Skip to content

Commit 296bbcf

Browse files
authored
Merge pull request #1116 from topcoder-platform/pm-1373
fix(PM-1373, PM-1375, PM-1376, PM-1383, PM-1380, PM-1378): demo feedbacks implementation
2 parents 86575bb + cca9941 commit 296bbcf

File tree

8 files changed

+144
-176
lines changed

8 files changed

+144
-176
lines changed

src/apps/copilots/src/pages/copilot-opportunity-details/apply-opportunity-modal/ApplyOpportunityModal.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
4444
size='lg'
4545
title={
4646
success
47-
? `Your Application for ${props.projectName} Has Been Received!`
48-
: `Confirm Your Copilot Application for ${props.projectName}`
47+
? 'Your Application Has Been Received!'
48+
: 'Confirm Your Copilot Application'
4949
}
5050
buttons={
5151
!success ? (
@@ -62,21 +62,21 @@ const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
6262
<div className={styles.info}>
6363
{
6464
success
65-
? `We appreciate the time and effort you've taken to apply
66-
for this exciting opportunity. Our team is committed
67-
to providing a seamless and efficient process to ensure a
68-
great experience for all copilots. We will review your application
69-
within short time.`
65+
? `Thank you for taking the time to apply for this exciting opportunity.
66+
We truly value your interest and effort.
67+
Your application will be reviewed promptly.`
7068
: `We're excited to see your interest in joining our team as a copilot
71-
for the ${props.projectName} project! Before we proceed, we want to
69+
for the "${props.projectName}" project! Before we proceed, we want to
7270
ensure that you have carefully reviewed the project requirements and
73-
are committed to meeting them.`
71+
are committed to meeting them. Please write below the reason(s)
72+
why you believe you're a good fit for this project
73+
(e.g., previous experience, availability, etc.).`
7474
}
7575
</div>
7676
{
7777
!success && (
7878
<InputTextarea
79-
name='Notes'
79+
name='Reason'
8080
onChange={onChange}
8181
value={notes}
8282
error={error}

src/apps/copilots/src/pages/copilot-opportunity-details/index.tsx

Lines changed: 107 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from 'react'
1313
import { useLocation, useNavigate, useParams } from 'react-router-dom'
1414
import { mutate } from 'swr'
15+
import { toast } from 'react-toastify'
1516
import moment from 'moment'
1617

1718
import {
@@ -28,6 +29,7 @@ import { textFormatDateLocaleShortString } from '~/libs/shared'
2829

2930
import { CopilotApplication } from '../../models/CopilotApplication'
3031
import {
32+
cancelCopilotOpportunity,
3133
copilotBaseUrl,
3234
CopilotOpportunityResponse,
3335
useCopilotApplications,
@@ -104,7 +106,7 @@ const CopilotOpportunityDetails: FC<{}> = () => {
104106

105107
const onApplied: () => void = useCallback(() => {
106108
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}/applications`)
107-
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}`)
109+
mutate(`${copilotBaseUrl}/copilot/opportunity/${opportunityId}`)
108110
}, [])
109111

110112
const onCloseApplyModal: () => void = useCallback(() => {
@@ -120,11 +122,26 @@ const CopilotOpportunityDetails: FC<{}> = () => {
120122
)
121123
}
122124

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+
123135
const applyCopilotOpportunityButton: ButtonProps = {
124136
label: 'Apply as Copilot',
125137
onClick: () => setShowApplyOpportunityModal(true),
126138
}
127139

140+
const cancelCopilotOpportunityButton: ButtonProps = {
141+
label: 'Cancel opportunity',
142+
onClick: cancelCopilotOpportunityHandler,
143+
}
144+
128145
const application = copilotApplications && copilotApplications[0]
129146

130147
const getOpportunityType = (type: string): ProjectType => {
@@ -152,6 +169,10 @@ const CopilotOpportunityDetails: FC<{}> = () => {
152169
&& opportunity?.status === 'active'
153170
&& opportunity?.canApplyAsCopilot ? applyCopilotOpportunityButton : undefined
154171
}
172+
secondaryButtonConfig={
173+
opportunity?.status === 'active'
174+
&& isAdminOrPM ? cancelCopilotOpportunityButton : undefined
175+
}
155176
infoComponent={(isCopilot && !(copilotApplications
156177
&& copilotApplications.length === 0
157178
) && opportunity?.status === 'active' && !!application) && (
@@ -171,98 +192,101 @@ const CopilotOpportunityDetails: FC<{}> = () => {
171192
{isValidating && !showNotFound && (
172193
<LoadingSpinner />
173194
) }
174-
<h1 className={styles.header}>
175-
{opportunity?.projectName}
176-
</h1>
177-
<div className={styles.infoRow}>
178-
<div className={styles.infoColumn}>
179-
<IconOutline.ClipboardCheckIcon className={styles.icon} />
180-
<div className={styles.infoText}>
181-
<span className={styles.infoHeading}>Status</span>
182-
<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>
183206
</div>
184-
</div>
185-
<div className={styles.infoColumn}>
186-
<IconOutline.PlayIcon className={styles.icon} />
187-
<div className={styles.infoText}>
188-
<span className={styles.infoHeading}>Start Date</span>
189-
<span className={styles.infoValue}>
190-
{moment(opportunity?.startDate)
191-
.format('MMM D, YYYY')}
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')}
192214

193-
</span>
215+
</span>
216+
</div>
194217
</div>
195-
</div>
196-
<div className={styles.infoColumn}>
197-
<IconOutline.CalendarIcon className={styles.icon} />
198-
<div className={styles.infoText}>
199-
<span className={styles.infoHeading}>Duration</span>
200-
<span className={styles.infoValue}>
201-
{opportunity?.numWeeks}
202-
{' '}
203-
weeks
204-
</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>
205228
</div>
206-
</div>
207-
<div className={styles.infoColumn}>
208-
<IconOutline.ClockIcon className={styles.icon} />
209-
<div className={styles.infoText}>
210-
<span className={styles.infoHeading}>Hours</span>
211-
<span className={styles.infoValue}>
212-
{opportunity?.numHoursPerWeek}
213-
{' '}
214-
hours/week
215-
</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>
216239
</div>
217-
</div>
218-
<div className={styles.infoColumn}>
219-
<IconOutline.CogIcon className={styles.icon} />
220-
<div className={styles.infoText}>
221-
<span className={styles.infoHeading}>Type</span>
222-
<span
223-
className={styles.infoValue}
224-
>
225-
{opportunity?.type && getOpportunityType(opportunity?.type)}
226-
</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>
227250
</div>
228-
</div>
229-
<div className={styles.infoColumn}>
230-
<IconOutline.GlobeAltIcon className={styles.icon} />
231-
<div className={styles.infoText}>
232-
<span className={styles.infoHeading}>Working Hours</span>
233-
<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>
234257
</div>
235258
</div>
236-
</div>
237-
{
238-
initialized && (
239-
<TabsNavbar
240-
defaultActive={activeTab}
241-
onChange={handleTabChange}
242-
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}
243274
/>
244-
)
245-
}
246-
{activeTab === CopilotDetailsTabViews.details && <OpportunityDetails opportunity={opportunity} />}
247-
{activeTab === CopilotDetailsTabViews.applications && isAdminOrPM && opportunity && (
248-
<CopilotApplications
249-
copilotApplications={copilotApplications}
250-
opportunity={opportunity}
251-
members={members}
252-
/>
253-
)}
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>
254289

255-
{
256-
showApplyOpportunityModal
257-
&& opportunity && (
258-
<ApplyOpportunityModal
259-
copilotOpportunityId={opportunity?.id}
260-
onClose={onCloseApplyModal}
261-
projectName={opportunity?.projectName}
262-
onApplied={onApplied}
263-
/>
264-
)
265-
}
266290
</ContentLayout>
267291
)
268292
}

src/apps/copilots/src/pages/copilot-opportunity-details/styles.module.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
@import '@libs/ui/styles/includes';
22

3+
.wrapper {
4+
min-height: 800px;
5+
}
6+
37
.header {
48
display: flex;
59
align-items: center;

src/apps/copilots/src/pages/copilot-opportunity-details/tabs/copilot-applications/CopilotApplicationAction.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const CopilotApplicationAction = (
1515
): JSX.Element => {
1616
const { opportunityId }: {opportunityId?: string} = useParams<{ opportunityId?: string }>()
1717
const isInvited = useMemo(
18-
() => allCopilotApplications.findIndex(item => item.status === CopilotApplicationStatus.INVITED) > -1,
18+
() => allCopilotApplications
19+
&& allCopilotApplications.findIndex(item => item.status === CopilotApplicationStatus.INVITED) > -1,
1920
[allCopilotApplications],
2021
)
2122
const onClick = useCallback(async () => {

src/apps/copilots/src/pages/copilot-opportunity-details/tabs/opportunity-details/OpportunityDetails.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ const OpportunityDetails: FC<{
1111
<div>
1212
<h2 className={styles.subHeading}> Required skills </h2>
1313
<div className={styles.skillsContainer}>
14-
{props.opportunity?.skills.map((skill: any) => (
15-
<div key={skill.id} className={styles.skillPill}>
16-
{skill.name}
17-
</div>
18-
))}
14+
{props.opportunity?.skills.map(item => item.name)
15+
.join(',')}
1916
</div>
2017
<h2 className={styles.subHeading}> Description </h2>
2118
<p>

src/apps/copilots/src/pages/copilot-opportunity-list/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ const tableColumns: TableColumn<CopilotOpportunity>[] = [
8484
propertyName: 'startDate',
8585
type: 'date',
8686
},
87+
{
88+
label: 'Duration(Weeks)',
89+
propertyName: 'numWeeks',
90+
type: 'text',
91+
},
8792
{
8893
label: 'Complexity',
8994
propertyName: 'complexity',

0 commit comments

Comments
 (0)