Skip to content

Commit b5bc422

Browse files
authored
Merge pull request #1072 from topcoder-platform/pm-578_1
fix(PM-578): QA feedbacks on apply copilot opportunity functionality
2 parents b57e191 + 9e3d8ed commit b5bc422

File tree

6 files changed

+61
-10
lines changed

6 files changed

+61
-10
lines changed

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ interface ApplyOpportunityModalProps {
1717
const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
1818
const [notes, setNotes] = useState('')
1919
const [success, setSuccess] = useState(false)
20+
const [error, setError] = useState('')
2021

2122
const onApply = useCallback(async () => {
2223
try {
23-
await applyCopilotOpportunity(props.copilotOpportunityId, {
24+
await applyCopilotOpportunity(props.copilotOpportunityId, notes ? {
2425
notes,
25-
})
26+
} : undefined)
2627

2728
props.onApplied()
2829
setSuccess(true)
29-
} catch (e) {
30-
setSuccess(true)
30+
} catch (e: any) {
31+
setSuccess(false)
32+
setError(e.message)
3133
}
3234
}, [props.copilotOpportunityId, notes])
3335

@@ -77,6 +79,8 @@ const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
7779
name='Notes'
7880
onChange={onChange}
7981
value={notes}
82+
error={error}
83+
dirty={!!error}
8084
/>
8185
)
8286
}

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

+29-4
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import {
1818
ButtonProps,
1919
ContentLayout,
2020
IconOutline,
21+
IconSolid,
2122
LoadingSpinner,
2223
PageTitle,
2324
TabsNavbar,
2425
} from '~/libs/ui'
2526
import { profileContext, ProfileContextData, UserRole } from '~/libs/core'
27+
import { textFormatDateLocaleShortString } from '~/libs/shared'
2628

2729
import { CopilotApplication } from '../../models/CopilotApplication'
2830
import {
@@ -77,8 +79,12 @@ const CopilotOpportunityDetails: FC<{}> = () => {
7779
const [activeTab, setActiveTab]: [string, Dispatch<SetStateAction<string>>] = useState<string>(activeTabHash)
7880

7981
useEffect(() => {
80-
setActiveTab(activeTabHash)
81-
}, [activeTabHash])
82+
if (isAdminOrPM) {
83+
setActiveTab(activeTabHash)
84+
} else {
85+
setActiveTab('0')
86+
}
87+
}, [activeTabHash, isAdminOrPM])
8288

8389
const handleTabChange = useCallback((tabId: string): void => {
8490
setActiveTab(tabId)
@@ -97,6 +103,7 @@ const CopilotOpportunityDetails: FC<{}> = () => {
97103

98104
const onApplied: () => void = useCallback(() => {
99105
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}/applications`)
106+
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}`)
100107
}, [])
101108

102109
const onCloseApplyModal: () => void = useCallback(() => {
@@ -117,16 +124,34 @@ const CopilotOpportunityDetails: FC<{}> = () => {
117124
onClick: () => setShowApplyOpportunityModal(true),
118125
}
119126

127+
const application = copilotApplications && copilotApplications[0]
128+
120129
return (
121130
<ContentLayout
122131
title='Copilot Opportunity'
123132
buttonConfig={
124133
isCopilot
125134
&& copilotApplications
126-
&& copilotApplications.length === 0 ? applyCopilotOpportunityButton : undefined
135+
&& copilotApplications.length === 0
136+
&& opportunity?.status === 'active' ? applyCopilotOpportunityButton : undefined
127137
}
138+
infoComponent={(isCopilot && !(copilotApplications
139+
&& copilotApplications.length === 0
140+
&& opportunity?.status === 'active'
141+
) && !!application) && (
142+
<div className={styles.applied}>
143+
<IconSolid.CheckCircleIcon className={styles.appliedIcon} />
144+
<span
145+
className={styles.appliedText}
146+
>
147+
{`Applied on ${textFormatDateLocaleShortString(new Date(application.createdAt))}`}
148+
</span>
149+
</div>
150+
)}
128151
>
129-
<PageTitle>Copilot Opportunity</PageTitle>
152+
<PageTitle>
153+
Copilot Opportunity
154+
</PageTitle>
130155
{isValidating && !showNotFound && (
131156
<LoadingSpinner />
132157
) }

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

+16
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@
5454
color: $teal-100;
5555
}
5656

57+
.applied {
58+
display: flex;
59+
align-items: center;
60+
.appliedIcon {
61+
width: 30px;
62+
height: 30px;
63+
color: $green-1;
64+
}
65+
66+
.appliedText {
67+
font-size: 14px;
68+
font-weight: 600;
69+
color: #333;
70+
}
71+
}
72+
5773
.textCaps {
5874
text-transform: capitalize;
5975
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export const useCopilotOpportunity = (opportunityId?: string): CopilotOpportunit
9797
* @param request
9898
* @returns
9999
*/
100-
export const applyCopilotOpportunity = async (opportunityId: number, request: {
100+
export const applyCopilotOpportunity = async (opportunityId: number, request?: {
101101
notes?: string;
102102
}): Promise<CopilotApplication> => {
103103
const url = `${copilotBaseUrl}/copilots/opportunity/${opportunityId}/apply`

src/libs/ui/lib/components/content-layout/ContentLayout.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface ContentLayoutProps {
1414
outerClass?: string
1515
title?: string
1616
titleClass?: string
17+
infoComponent?: ReactNode
1718
}
1819

1920
const ContentLayout: FC<ContentLayoutProps> = (props: ContentLayoutProps) => (
@@ -50,6 +51,12 @@ const ContentLayout: FC<ContentLayoutProps> = (props: ContentLayoutProps) => (
5051
</div>
5152
)}
5253

54+
{!!props.infoComponent && (
55+
<div>
56+
{props.infoComponent}
57+
</div>
58+
)}
59+
5360
</div>
5461
)}
5562

src/libs/ui/lib/styles/_modals.scss

-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454

5555
.react-responsive-modal-closeButton {
5656
top: $sp-5;
57-
padding: $sp-1;
5857
border-radius: 50%;
5958

6059
svg {

0 commit comments

Comments
 (0)