Skip to content

Commit b9cf19e

Browse files
authored
Merge pull request #1086 from topcoder-platform/pm-580
feat(PM-580): added assign action to applications list
2 parents b5bc422 + c120616 commit b9cf19e

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
export enum CopilotApplicationStatus {
2+
INVITED = 'invited',
3+
ACCEPTED = 'accepted',
4+
PENDING = 'pending',
5+
}
6+
17
export interface CopilotApplication {
28
id: number,
39
notes?: string,
410
createdAt: Date,
511
opportunityId: string,
612
handle?: string,
713
userId: number,
14+
status: CopilotApplicationStatus,
815
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ const CopilotOpportunityDetails: FC<{}> = () => {
137137
}
138138
infoComponent={(isCopilot && !(copilotApplications
139139
&& copilotApplications.length === 0
140-
&& opportunity?.status === 'active'
141-
) && !!application) && (
140+
) && opportunity?.status === 'active' && !!application) && (
142141
<div className={styles.applied}>
143142
<IconSolid.CheckCircleIcon className={styles.appliedIcon} />
144143
<span
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useParams } from 'react-router-dom'
2+
import { toast } from 'react-toastify'
3+
import { mutate } from 'swr'
4+
import { useCallback } from 'react'
5+
6+
import { assignCopilotOpportunity, copilotBaseUrl } from '~/apps/copilots/src/services/copilot-opportunities'
7+
import { CopilotApplication, CopilotApplicationStatus } from '~/apps/copilots/src/models/CopilotApplication'
8+
import { IconSolid, Tooltip } from '~/libs/ui'
9+
10+
import styles from './styles.module.scss'
11+
12+
const CopilotApplicationAction = (copilotApplication: CopilotApplication): JSX.Element => {
13+
const { opportunityId }: {opportunityId?: string} = useParams<{ opportunityId?: string }>()
14+
const onClick = useCallback(async () => {
15+
if (copilotApplication.status !== CopilotApplicationStatus.PENDING) {
16+
return
17+
}
18+
19+
if (opportunityId) {
20+
try {
21+
await assignCopilotOpportunity(opportunityId, copilotApplication.id)
22+
toast.success('Invited a copilot')
23+
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}/applications`)
24+
} catch (e) {
25+
const error = e as Error
26+
toast.error(error.message)
27+
}
28+
29+
}
30+
}, [opportunityId, copilotApplication])
31+
return (
32+
<div onClick={onClick} className={styles.actionWrapper}>
33+
{
34+
copilotApplication.status === CopilotApplicationStatus.INVITED && (
35+
<Tooltip content='User already invited'>
36+
<IconSolid.MailOpenIcon />
37+
</Tooltip>
38+
)
39+
}
40+
41+
{
42+
copilotApplication.status === CopilotApplicationStatus.PENDING && (
43+
<IconSolid.UserAddIcon />
44+
)
45+
}
46+
47+
{
48+
copilotApplication.status === CopilotApplicationStatus.ACCEPTED && (
49+
<IconSolid.BadgeCheckIcon />
50+
)
51+
}
52+
</div>
53+
)
54+
}
55+
56+
export default CopilotApplicationAction

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { USER_PROFILE_URL } from '~/config/environments/default.env'
66
import { CopilotApplication } from '../../../../models/CopilotApplication'
77
import { FormattedMembers } from '../../../../services/members'
88

9+
import CopilotApplicationAction from './CopilotApplicationAction'
910
import styles from './styles.module.scss'
1011

1112
const tableColumns: TableColumn<CopilotApplication>[] = [
@@ -33,6 +34,16 @@ const tableColumns: TableColumn<CopilotApplication>[] = [
3334
propertyName: 'activeProjects',
3435
type: 'text',
3536
},
37+
{
38+
label: 'Status',
39+
propertyName: 'status',
40+
renderer: (copilotApplication: CopilotApplication) => (
41+
<div className={styles.status}>
42+
{copilotApplication.status}
43+
</div>
44+
),
45+
type: 'element',
46+
},
3647
{
3748
label: 'Applied Date',
3849
propertyName: 'createdAt',
@@ -48,6 +59,12 @@ const tableColumns: TableColumn<CopilotApplication>[] = [
4859
),
4960
type: 'element',
5061
},
62+
{
63+
label: 'Actions',
64+
propertyName: '',
65+
renderer: CopilotApplicationAction,
66+
type: 'element',
67+
},
5168
]
5269

5370
const CopilotApplications: FC<{
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.status {
4+
text-transform: capitalize;
5+
}
6+
7+
.actionWrapper {
8+
width: 24px;
9+
height: 24px;
10+
cursor: pointer;
11+
svg {
12+
color: $teal-100;
13+
}
14+
}

src/apps/copilots/src/services/copilot-opportunities.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ export const applyCopilotOpportunity = async (opportunityId: number, request?: {
105105
return xhrPostAsync(url, request, {})
106106
}
107107

108+
/**
109+
* apply copilot opportunity
110+
* @param opportunityId
111+
* @param applicationId
112+
* @returns
113+
*/
114+
export const assignCopilotOpportunity = async (
115+
opportunityId: string,
116+
applicationId: number,
117+
): Promise<{applicationId: number}> => {
118+
const url = `${copilotBaseUrl}/copilots/opportunity/${opportunityId}/assign`
119+
120+
return xhrPostAsync(url, { applicationId: applicationId.toString() }, {})
121+
}
122+
108123
/**
109124
* Custom hook to fetch copilot applications by opportunity id.
110125
*

0 commit comments

Comments
 (0)