@@ -12,6 +12,7 @@ import {
1212} from 'react'
1313import { useLocation , useNavigate , useParams } from 'react-router-dom'
1414import { mutate } from 'swr'
15+ import { toast } from 'react-toastify'
1516import moment from 'moment'
1617
1718import {
@@ -28,13 +29,15 @@ import { textFormatDateLocaleShortString } from '~/libs/shared'
2829
2930import { CopilotApplication } from '../../models/CopilotApplication'
3031import {
32+ cancelCopilotOpportunity ,
3133 copilotBaseUrl ,
3234 CopilotOpportunityResponse ,
3335 useCopilotApplications ,
3436 useCopilotOpportunity ,
3537} from '../../services/copilot-opportunities'
3638import { FormattedMembers , useMembers } from '../../services/members'
3739import { copilotRoutesMap } from '../../copilots.routes'
40+ import { ProjectType } from '../../constants'
3841
3942import { ApplyOpportunityModal } from './apply-opportunity-modal'
4043import {
@@ -103,7 +106,7 @@ const CopilotOpportunityDetails: FC<{}> = () => {
103106
104107 const onApplied : ( ) => void = useCallback ( ( ) => {
105108 mutate ( `${ copilotBaseUrl } /copilots/opportunity/${ opportunityId } /applications` )
106- mutate ( `${ copilotBaseUrl } /copilots /opportunity/${ opportunityId } ` )
109+ mutate ( `${ copilotBaseUrl } /copilot /opportunity/${ opportunityId } ` )
107110 } , [ ] )
108111
109112 const onCloseApplyModal : ( ) => void = useCallback ( ( ) => {
@@ -119,13 +122,42 @@ const CopilotOpportunityDetails: FC<{}> = () => {
119122 )
120123 }
121124
125+ async function cancelCopilotOpportunityHandler ( ) : Promise < void > {
126+ if ( opportunityId ) {
127+ await cancelCopilotOpportunity ( opportunityId )
128+ mutate ( `${ copilotBaseUrl } /copilots/opportunity/${ opportunityId } /applications` )
129+ mutate ( `${ copilotBaseUrl } /copilot/opportunity/${ opportunityId } ` )
130+ toast . success ( 'Canceled copilot opportunity successfully' )
131+ }
132+
133+ }
134+
122135 const applyCopilotOpportunityButton : ButtonProps = {
123136 label : 'Apply as Copilot' ,
124137 onClick : ( ) => setShowApplyOpportunityModal ( true ) ,
125138 }
126139
140+ const cancelCopilotOpportunityButton : ButtonProps = {
141+ label : 'Cancel opportunity' ,
142+ onClick : cancelCopilotOpportunityHandler ,
143+ }
144+
127145 const application = copilotApplications && copilotApplications [ 0 ]
128- const isAlreadyMemberOfTheProject = profile && opportunity ?. members ?. includes ( profile . userId )
146+
147+ const getOpportunityType = ( type : string ) : ProjectType => {
148+ switch ( type ) {
149+ case 'ai' :
150+ return ProjectType . ai
151+ case 'datascience' :
152+ return ProjectType . datascience
153+ case 'dev' :
154+ return ProjectType . developement
155+ case 'design' :
156+ return ProjectType . design
157+ default :
158+ return ProjectType . qa
159+ }
160+ }
129161
130162 return (
131163 < ContentLayout
@@ -135,7 +167,11 @@ const CopilotOpportunityDetails: FC<{}> = () => {
135167 && copilotApplications
136168 && copilotApplications . length === 0
137169 && opportunity ?. status === 'active'
138- && ! isAlreadyMemberOfTheProject ? applyCopilotOpportunityButton : undefined
170+ && opportunity ?. canApplyAsCopilot ? applyCopilotOpportunityButton : undefined
171+ }
172+ secondaryButtonConfig = {
173+ opportunity ?. status === 'active'
174+ && isAdminOrPM ? cancelCopilotOpportunityButton : undefined
139175 }
140176 infoComponent = { ( isCopilot && ! ( copilotApplications
141177 && copilotApplications . length === 0
@@ -156,94 +192,101 @@ const CopilotOpportunityDetails: FC<{}> = () => {
156192 { isValidating && ! showNotFound && (
157193 < LoadingSpinner />
158194 ) }
159- < h1 className = { styles . header } >
160- { opportunity ?. projectName }
161- </ h1 >
162- < div className = { styles . infoRow } >
163- < div className = { styles . infoColumn } >
164- < IconOutline . ClipboardCheckIcon className = { styles . icon } />
165- < div className = { styles . infoText } >
166- < span className = { styles . infoHeading } > Status</ span >
167- < span className = { styles . infoValue } > { opportunity ?. status } </ span >
195+ < div className = { styles . wrapper } >
196+ < h1 className = { styles . header } >
197+ { opportunity ?. projectName }
198+ </ h1 >
199+ < div className = { styles . infoRow } >
200+ < div className = { styles . infoColumn } >
201+ < IconOutline . ClipboardCheckIcon className = { styles . icon } />
202+ < div className = { styles . infoText } >
203+ < span className = { styles . infoHeading } > Status</ span >
204+ < span className = { styles . infoValue } > { opportunity ?. status } </ span >
205+ </ div >
168206 </ div >
169- </ div >
170- < div className = { styles . infoColumn } >
171- < IconOutline . PlayIcon className = { styles . icon } / >
172- < div className = { styles . infoText } >
173- < span className = { styles . infoHeading } > Start Date </ span >
174- < span className = { styles . infoValue } >
175- { moment ( opportunity ?. startDate )
176- . format ( 'MMM D, YYYY' ) }
177-
178- </ span >
207+ < div className = { styles . infoColumn } >
208+ < IconOutline . PlayIcon className = { styles . icon } / >
209+ < div className = { styles . infoText } >
210+ < span className = { styles . infoHeading } > Start Date </ span >
211+ < span className = { styles . infoValue } >
212+ { moment ( opportunity ?. startDate )
213+ . format ( 'MMM D, YYYY' ) }
214+
215+ </ span >
216+ </ div >
179217 </ div >
180- </ div >
181- < div className = { styles . infoColumn } >
182- < IconOutline . CalendarIcon className = { styles . icon } / >
183- < div className = { styles . infoText } >
184- < span className = { styles . infoHeading } > Duration </ span >
185- < span className = { styles . infoValue } >
186- { opportunity ?. numWeeks }
187- { ' ' }
188- weeks
189- </ span >
218+ < div className = { styles . infoColumn } >
219+ < IconOutline . CalendarIcon className = { styles . icon } / >
220+ < div className = { styles . infoText } >
221+ < span className = { styles . infoHeading } > Duration </ span >
222+ < span className = { styles . infoValue } >
223+ { opportunity ?. numWeeks }
224+ { ' ' }
225+ weeks
226+ </ span >
227+ </ div >
190228 </ div >
191- </ div >
192- < div className = { styles . infoColumn } >
193- < IconOutline . ClockIcon className = { styles . icon } / >
194- < div className = { styles . infoText } >
195- < span className = { styles . infoHeading } > Hours </ span >
196- < span className = { styles . infoValue } >
197- { opportunity ?. numHoursPerWeek }
198- { ' ' }
199- hours/week
200- </ span >
229+ < div className = { styles . infoColumn } >
230+ < IconOutline . ClockIcon className = { styles . icon } / >
231+ < div className = { styles . infoText } >
232+ < span className = { styles . infoHeading } > Hours </ span >
233+ < span className = { styles . infoValue } >
234+ { opportunity ?. numHoursPerWeek }
235+ { ' ' }
236+ hours/week
237+ </ span >
238+ </ div >
201239 </ div >
202- </ div >
203- < div className = { styles . infoColumn } >
204- < IconOutline . CogIcon className = { styles . icon } />
205- < div className = { styles . infoText } >
206- < span className = { styles . infoHeading } > Type</ span >
207- < span className = { styles . infoValue } > { opportunity ?. type } </ span >
240+ < div className = { styles . infoColumn } >
241+ < IconOutline . CogIcon className = { styles . icon } />
242+ < div className = { styles . infoText } >
243+ < span className = { styles . infoHeading } > Type</ span >
244+ < span
245+ className = { styles . infoValue }
246+ >
247+ { opportunity ?. type && getOpportunityType ( opportunity ?. type ) }
248+ </ span >
249+ </ div >
208250 </ div >
209- </ div >
210- < div className = { styles . infoColumn } >
211- < IconOutline . GlobeAltIcon className = { styles . icon } / >
212- < div className = { styles . infoText } >
213- < span className = { styles . infoHeading } > Working Hours </ span >
214- < span className = { styles . infoValue } > { opportunity ?. tzRestrictions } </ span >
251+ < div className = { styles . infoColumn } >
252+ < IconOutline . GlobeAltIcon className = { styles . icon } / >
253+ < div className = { styles . infoText } >
254+ < span className = { styles . infoHeading } > Working Hours </ span >
255+ < span className = { styles . infoValue } > { opportunity ?. tzRestrictions } </ span >
256+ </ div >
215257 </ div >
216258 </ div >
217- </ div >
218- {
219- initialized && (
220- < TabsNavbar
221- defaultActive = { activeTab }
222- onChange = { handleTabChange }
223- tabs = { getCopilotDetailsTabsConfig ( isAdminOrPM ) }
259+ {
260+ initialized && (
261+ < TabsNavbar
262+ defaultActive = { activeTab }
263+ onChange = { handleTabChange }
264+ tabs = { getCopilotDetailsTabsConfig ( isAdminOrPM ) }
265+ />
266+ )
267+ }
268+ { activeTab === CopilotDetailsTabViews . details && < OpportunityDetails opportunity = { opportunity } /> }
269+ { activeTab === CopilotDetailsTabViews . applications && isAdminOrPM && opportunity && (
270+ < CopilotApplications
271+ copilotApplications = { copilotApplications }
272+ opportunity = { opportunity }
273+ members = { members }
224274 />
225- )
226- }
227- { activeTab === CopilotDetailsTabViews . details && < OpportunityDetails opportunity = { opportunity } /> }
228- { activeTab === CopilotDetailsTabViews . applications && isAdminOrPM && opportunity && (
229- < CopilotApplications
230- copilotApplications = { copilotApplications }
231- opportunity = { opportunity }
232- members = { members }
233- />
234- ) }
275+ ) }
276+
277+ {
278+ showApplyOpportunityModal
279+ && opportunity && (
280+ < ApplyOpportunityModal
281+ copilotOpportunityId = { opportunity ?. id }
282+ onClose = { onCloseApplyModal }
283+ projectName = { opportunity ?. projectName }
284+ onApplied = { onApplied }
285+ />
286+ )
287+ }
288+ </ div >
235289
236- {
237- showApplyOpportunityModal
238- && opportunity && (
239- < ApplyOpportunityModal
240- copilotOpportunityId = { opportunity ?. id }
241- onClose = { onCloseApplyModal }
242- projectName = { opportunity ?. projectName }
243- onApplied = { onApplied }
244- />
245- )
246- }
247290 </ ContentLayout >
248291 )
249292}
0 commit comments