Skip to content

fix(PM-1373, PM-1375, PM-1376, PM-1383, PM-1380, PM-1378): demo feedbacks implementation #1116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
size='lg'
title={
success
? `Your Application for ${props.projectName} Has Been Received!`
: `Confirm Your Copilot Application for ${props.projectName}`
? 'Your Application Has Been Received!'
: 'Confirm Your Copilot Application'
}
buttons={
!success ? (
Expand All @@ -62,21 +62,21 @@ const ApplyOpportunityModal: FC<ApplyOpportunityModalProps> = props => {
<div className={styles.info}>
{
success
? `We appreciate the time and effort you've taken to apply
for this exciting opportunity. Our team is committed
to providing a seamless and efficient process to ensure a
great experience for all copilots. We will review your application
within short time.`
? `Thank you for taking the time to apply for this exciting opportunity.
We truly value your interest and effort.
Your application will be reviewed promptly.`
: `We're excited to see your interest in joining our team as a copilot
for the ${props.projectName} project! Before we proceed, we want to
for the "${props.projectName}" project! Before we proceed, we want to
ensure that you have carefully reviewed the project requirements and
are committed to meeting them.`
are committed to meeting them. Please write below the reason(s)
why you believe you're a good fit for this project
(e.g., previous experience, availability, etc.).`
}
</div>
{
!success && (
<InputTextarea
name='Notes'
name='Reason'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input field name has been changed from 'Notes' to 'Reason'. Ensure that this change is reflected consistently throughout the codebase, including any form handling logic or validation that may rely on the field name.

onChange={onChange}
value={notes}
error={error}
Expand Down
180 changes: 101 additions & 79 deletions src/apps/copilots/src/pages/copilot-opportunity-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { textFormatDateLocaleShortString } from '~/libs/shared'

import { CopilotApplication } from '../../models/CopilotApplication'
import {
cancelCopilotOpportunity,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function cancelCopilotOpportunity is imported but not used in this file. Consider removing it if it's not needed.

copilotBaseUrl,
CopilotOpportunityResponse,
useCopilotApplications,
Expand Down Expand Up @@ -119,11 +120,25 @@ const CopilotOpportunityDetails: FC<{}> = () => {
)
}

async function cancelCopilotOpportunityHandler(): Promise<void> {
if (opportunityId) {
await cancelCopilotOpportunity(opportunityId)
mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}/applications`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mutate function is called twice with similar URLs. Consider extracting the base URL and opportunity ID into a variable to avoid repetition and improve readability.

mutate(`${copilotBaseUrl}/copilots/opportunity/${opportunityId}`)
}

}

const applyCopilotOpportunityButton: ButtonProps = {
label: 'Apply as Copilot',
onClick: () => setShowApplyOpportunityModal(true),
}

const cancelCopilotOpportunityButton: ButtonProps = {
label: 'Cancel opportunity',
onClick: cancelCopilotOpportunityHandler,
}

const application = copilotApplications && copilotApplications[0]

return (
Expand All @@ -136,6 +151,10 @@ const CopilotOpportunityDetails: FC<{}> = () => {
&& opportunity?.status === 'active'
&& opportunity?.canApplyAsCopilot ? applyCopilotOpportunityButton : undefined
}
secondaryButtonConfig={
opportunity?.status === 'active'
&& isAdminOrPM ? cancelCopilotOpportunityButton : undefined
}
infoComponent={(isCopilot && !(copilotApplications
&& copilotApplications.length === 0
) && opportunity?.status === 'active' && !!application) && (
Expand All @@ -155,94 +174,97 @@ const CopilotOpportunityDetails: FC<{}> = () => {
{isValidating && !showNotFound && (
<LoadingSpinner />
) }
<h1 className={styles.header}>
{opportunity?.projectName}
</h1>
<div className={styles.infoRow}>
<div className={styles.infoColumn}>
<IconOutline.ClipboardCheckIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Status</span>
<span className={styles.infoValue}>{opportunity?.status}</span>
<div className={styles.wrapper}>
<h1 className={styles.header}>
{opportunity?.projectName}
</h1>
<div className={styles.infoRow}>
<div className={styles.infoColumn}>
<IconOutline.ClipboardCheckIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Status</span>
<span className={styles.infoValue}>{opportunity?.status}</span>
</div>
</div>
</div>
<div className={styles.infoColumn}>
<IconOutline.PlayIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Start Date</span>
<span className={styles.infoValue}>
{moment(opportunity?.startDate)
.format('MMM D, YYYY')}

</span>
<div className={styles.infoColumn}>
<IconOutline.PlayIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Start Date</span>
<span className={styles.infoValue}>
{moment(opportunity?.startDate)
.format('MMM D, YYYY')}

</span>
</div>
</div>
</div>
<div className={styles.infoColumn}>
<IconOutline.CalendarIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Duration</span>
<span className={styles.infoValue}>
{opportunity?.numWeeks}
{' '}
weeks
</span>
<div className={styles.infoColumn}>
<IconOutline.CalendarIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Duration</span>
<span className={styles.infoValue}>
{opportunity?.numWeeks}
{' '}
weeks
</span>
</div>
</div>
</div>
<div className={styles.infoColumn}>
<IconOutline.ClockIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Hours</span>
<span className={styles.infoValue}>
{opportunity?.numHoursPerWeek}
{' '}
hours/week
</span>
<div className={styles.infoColumn}>
<IconOutline.ClockIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Hours</span>
<span className={styles.infoValue}>
{opportunity?.numHoursPerWeek}
{' '}
hours/week
</span>
</div>
</div>
</div>
<div className={styles.infoColumn}>
<IconOutline.CogIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Type</span>
<span className={styles.infoValue}>{opportunity?.type}</span>
<div className={styles.infoColumn}>
<IconOutline.CogIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Type</span>
<span className={styles.infoValue}>{opportunity?.type}</span>
</div>
</div>
</div>
<div className={styles.infoColumn}>
<IconOutline.GlobeAltIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Working Hours</span>
<span className={styles.infoValue}>{opportunity?.tzRestrictions}</span>
<div className={styles.infoColumn}>
<IconOutline.GlobeAltIcon className={styles.icon} />
<div className={styles.infoText}>
<span className={styles.infoHeading}>Working Hours</span>
<span className={styles.infoValue}>{opportunity?.tzRestrictions}</span>
</div>
</div>
</div>
</div>
{
initialized && (
<TabsNavbar
defaultActive={activeTab}
onChange={handleTabChange}
tabs={getCopilotDetailsTabsConfig(isAdminOrPM)}
{
initialized && (
<TabsNavbar
defaultActive={activeTab}
onChange={handleTabChange}
tabs={getCopilotDetailsTabsConfig(isAdminOrPM)}
/>
)
}
{activeTab === CopilotDetailsTabViews.details && <OpportunityDetails opportunity={opportunity} />}
{activeTab === CopilotDetailsTabViews.applications && isAdminOrPM && opportunity && (
<CopilotApplications
copilotApplications={copilotApplications}
opportunity={opportunity}
members={members}
/>
)
}
{activeTab === CopilotDetailsTabViews.details && <OpportunityDetails opportunity={opportunity} />}
{activeTab === CopilotDetailsTabViews.applications && isAdminOrPM && opportunity && (
<CopilotApplications
copilotApplications={copilotApplications}
opportunity={opportunity}
members={members}
/>
)}
)}

{
showApplyOpportunityModal
&& opportunity && (
<ApplyOpportunityModal
copilotOpportunityId={opportunity?.id}
onClose={onCloseApplyModal}
projectName={opportunity?.projectName}
onApplied={onApplied}
/>
)
}
</div>

{
showApplyOpportunityModal
&& opportunity && (
<ApplyOpportunityModal
copilotOpportunityId={opportunity?.id}
onClose={onCloseApplyModal}
projectName={opportunity?.projectName}
onApplied={onApplied}
/>
)
}
</ContentLayout>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
@import '@libs/ui/styles/includes';

.wrapper {
min-height: 800px;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more flexible unit for min-height, such as vh or %, to ensure better responsiveness across different screen sizes.

}

.header {
display: flex;
align-items: center;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const CopilotApplicationAction = (
): JSX.Element => {
const { opportunityId }: {opportunityId?: string} = useParams<{ opportunityId?: string }>()
const isInvited = useMemo(
() => allCopilotApplications.findIndex(item => item.status === CopilotApplicationStatus.INVITED) > -1,
() => allCopilotApplications
&& allCopilotApplications.findIndex(item => item.status === CopilotApplicationStatus.INVITED) > -1,
[allCopilotApplications],
)
const onClick = useCallback(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ const OpportunityDetails: FC<{
<div>
<h2 className={styles.subHeading}> Required skills </h2>
<div className={styles.skillsContainer}>
{props.opportunity?.skills.map((skill: any) => (
<div key={skill.id} className={styles.skillPill}>
{skill.name}
</div>
))}
{props.opportunity?.skills.map(item => item.name)
.join(',')}
</div>
<h2 className={styles.subHeading}> Description </h2>
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ const tableColumns: TableColumn<CopilotOpportunity>[] = [
propertyName: 'startDate',
type: 'date',
},
{
label: 'Duration(Weeks)',
propertyName: 'numWeeks',
type: 'text',
},
{
label: 'Complexity',
propertyName: 'complexity',
Expand Down
Loading