Skip to content

Commit 82920dc

Browse files
authored
Merge pull request #1165 from topcoder-platform/pm-1506_1
feat(PM-1506): show already member modal
2 parents 39685e5 + 4282776 commit 82920dc

File tree

5 files changed

+90
-2
lines changed

5 files changed

+90
-2
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ workflows:
222222
- LVT-256
223223
- CORE-635
224224
- feat/system-admin
225-
- pm-1448_1
225+
- pm-1506_1
226226

227227
- deployQa:
228228
context: org-global

src/apps/copilots/src/models/CopilotApplication.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ export enum CopilotApplicationStatus {
44
PENDING = 'pending',
55
}
66

7+
export interface ExistingMembership {
8+
role: string,
9+
id: number,
10+
}
11+
712
export interface CopilotApplication {
813
id: number,
914
notes?: string,
@@ -13,4 +18,6 @@ export interface CopilotApplication {
1318
userId: number,
1419
status: CopilotApplicationStatus,
1520
opportunityStatus: string,
21+
existingMembership?: ExistingMembership,
22+
projectName: string,
1623
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* eslint-disable react/jsx-no-bind */
2+
import { FC } from 'react'
3+
4+
import { BaseModal, Button } from '~/libs/ui'
5+
import { CopilotApplication } from '~/apps/copilots/src/models/CopilotApplication'
6+
7+
import styles from './styles.module.scss'
8+
9+
interface AlreadyMemberModalProps {
10+
onClose: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
11+
copilotApplication: CopilotApplication
12+
handle?: string
13+
onApply: () => void
14+
projectName: string
15+
}
16+
17+
const AlreadyMemberModal: FC<AlreadyMemberModalProps> = props => (
18+
<BaseModal
19+
onClose={props.onClose as () => void}
20+
open
21+
size='lg'
22+
title='User already member of the project'
23+
buttons={(
24+
<>
25+
<Button primary onClick={props.onApply} label='Confirm' />
26+
<Button secondary onClick={props.onClose} label='Cancel' />
27+
</>
28+
)}
29+
>
30+
<div className={styles.applyCopilotModal}>
31+
<div className={styles.info}>
32+
{`The copilot ${props.handle} is part of ${props.projectName}
33+
project with ${props.copilotApplication.existingMembership?.role} role.`}
34+
<div>Click &apos;Confirm&apos; to accept and complete this opportunity.</div>
35+
</div>
36+
</div>
37+
</BaseModal>
38+
)
39+
40+
export default AlreadyMemberModal

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import { useParams } from 'react-router-dom'
22
import { toast } from 'react-toastify'
33
import { mutate } from 'swr'
4-
import { useCallback, useMemo } from 'react'
4+
import { useCallback, useMemo, useState } from 'react'
55

66
import { assignCopilotOpportunity, copilotBaseUrl } from '~/apps/copilots/src/services/copilot-opportunities'
77
import { CopilotApplication, CopilotApplicationStatus } from '~/apps/copilots/src/models/CopilotApplication'
88
import { IconSolid, Tooltip } from '~/libs/ui'
99

10+
import AlreadyMemberModal from './AlreadyMemberModal'
1011
import styles from './styles.module.scss'
1112

1213
const CopilotApplicationAction = (
1314
copilotApplication: CopilotApplication,
1415
allCopilotApplications: CopilotApplication[],
1516
): JSX.Element => {
1617
const { opportunityId }: {opportunityId?: string} = useParams<{ opportunityId?: string }>()
18+
const [showAlreadyMemberModal, setShowAlreadyMemberModal] = useState(false)
1719
const isInvited = useMemo(
1820
() => allCopilotApplications
1921
&& allCopilotApplications.findIndex(item => item.status === CopilotApplicationStatus.INVITED) > -1,
@@ -28,6 +30,11 @@ const CopilotApplicationAction = (
2830
return
2931
}
3032

33+
if (copilotApplication.existingMembership) {
34+
setShowAlreadyMemberModal(true)
35+
return
36+
}
37+
3138
if (opportunityId) {
3239
try {
3340
await assignCopilotOpportunity(opportunityId, copilotApplication.id)
@@ -40,6 +47,29 @@ const CopilotApplicationAction = (
4047

4148
}
4249
}, [opportunityId, copilotApplication])
50+
51+
const onApply = useCallback(async () => {
52+
try {
53+
if (!opportunityId) {
54+
return
55+
}
56+
57+
await assignCopilotOpportunity(opportunityId, copilotApplication.id)
58+
toast.success('Accepted as copilot')
59+
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}/applications`)
60+
setShowAlreadyMemberModal(false)
61+
} catch (e) {
62+
const error = e as Error
63+
toast.error(error.message)
64+
}
65+
}, [opportunityId, copilotApplication])
66+
67+
const onCloseModal = useCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
68+
e.preventDefault()
69+
e.stopPropagation()
70+
setShowAlreadyMemberModal(false)
71+
}, [showAlreadyMemberModal])
72+
4373
return (
4474
<div onClick={onClick} className={styles.actionWrapper}>
4575
{
@@ -67,6 +97,16 @@ const CopilotApplicationAction = (
6797
</Tooltip>
6898
)
6999
}
100+
101+
{showAlreadyMemberModal && (
102+
<AlreadyMemberModal
103+
projectName={copilotApplication.projectName}
104+
handle={copilotApplication.handle}
105+
onClose={onCloseModal}
106+
onApply={onApply}
107+
copilotApplication={copilotApplication}
108+
/>
109+
)}
70110
</div>
71111
)
72112
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ const CopilotApplications: FC<{
8787
handle: member?.handle,
8888
opportunityStatus: props.opportunity.status,
8989
pastProjects: member?.pastProjects || 0,
90+
projectName: props.opportunity.projectName,
9091
}
9192
})
9293
.sort((a, b) => (b.fulfilment || 0) - (a.fulfilment || 0)) : [])

0 commit comments

Comments
 (0)