From fec915cffa30f791833cab5069bfb2fa13d6fc08 Mon Sep 17 00:00:00 2001 From: Ai Ling <50992674+ailing35@users.noreply.github.com> Date: Sat, 5 Nov 2022 00:57:09 +0800 Subject: [PATCH] [offers][feat] Tweak UI and add View More button to OEA (#507) * [offers][feat] Tweak UI and minor refactoring * [offers][feat] Add view more button to OEA --- .../offers/dashboard/DashboardProfileCard.tsx | 2 +- .../offers/offerAnalysis/OfferAnalysis.tsx | 30 +++- .../offers/offerAnalysis/OfferProfileCard.tsx | 146 +++++++++++++----- .../offersSubmission/OffersSubmissionForm.tsx | 36 +++-- .../submissionForm/OfferDetailsForm.tsx | 4 +- .../offers/profile/ProfileDetails.tsx | 5 +- apps/portal/src/components/offers/types.ts | 134 ++++++++++++---- .../offers/profile/edit/[offerProfileId].tsx | 15 +- 8 files changed, 266 insertions(+), 106 deletions(-) diff --git a/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx b/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx index 854686eb..a4e82b69 100644 --- a/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx +++ b/apps/portal/src/components/offers/dashboard/DashboardProfileCard.tsx @@ -63,7 +63,7 @@ export default function DashboardProfileCard({ {profileName}

- Created at {formatDate(createdAt)} + Created in {formatDate(createdAt)}

diff --git a/apps/portal/src/components/offers/offerAnalysis/OfferAnalysis.tsx b/apps/portal/src/components/offers/offerAnalysis/OfferAnalysis.tsx index ab80bb48..1d8aa2ae 100644 --- a/apps/portal/src/components/offers/offerAnalysis/OfferAnalysis.tsx +++ b/apps/portal/src/components/offers/offerAnalysis/OfferAnalysis.tsx @@ -1,10 +1,13 @@ import { useEffect } from 'react'; import { useState } from 'react'; -import { Alert, HorizontalDivider, Spinner, Tabs } from '@tih/ui'; +import { ArrowUpRightIcon } from '@heroicons/react/24/outline'; +import { JobType } from '@prisma/client'; +import { Alert, Button, HorizontalDivider, Spinner, Tabs } from '@tih/ui'; import OfferPercentileAnalysisText from './OfferPercentileAnalysisText'; import OfferProfileCard from './OfferProfileCard'; import { OVERALL_TAB } from '../constants'; +import { YOE_CATEGORY } from '../table/types'; import type { AnalysisUnit, ProfileAnalysis } from '~/types/offers'; @@ -19,6 +22,16 @@ function OfferAnalysisContent({ tab, isSubmission, }: OfferAnalysisContentProps) { + const { companyId, companyName, title, totalYoe, jobType } = analysis; + const yoeCategory = + jobType === JobType.INTERN + ? '' + : totalYoe <= 2 + ? YOE_CATEGORY.ENTRY + : totalYoe <= 5 + ? YOE_CATEGORY.MID + : YOE_CATEGORY.SENIOR; + if (!analysis || analysis.noOfOffers === 0) { if (tab === OVERALL_TAB) { return ( @@ -55,15 +68,22 @@ function OfferAnalysisContent({ offerProfile={topPercentileOffer} /> ))} - {/* {offerAnalysis.topPercentileOffers.length > 0 && ( + {analysis.topPercentileOffers.length > 0 && (
- )} */} + )} ); } @@ -133,4 +153,4 @@ export default function OfferAnalysis({ )} ); -} \ No newline at end of file +} diff --git a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx index 37f85f8d..ae0d678b 100644 --- a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx +++ b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx @@ -1,4 +1,10 @@ import { + ArrowTrendingUpIcon, + BuildingOfficeIcon, + MapPinIcon, +} from '@heroicons/react/20/solid'; +import { + ArrowTopRightOnSquareIcon, BuildingOffice2Icon, CalendarDaysIcon, } from '@heroicons/react/24/outline'; @@ -7,9 +13,8 @@ import { JobType } from '@prisma/client'; import type { JobTitleType } from '~/components/shared/JobTitles'; import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; -import { HorizontalDivider } from '~/../../../packages/ui/dist'; +import { Button } from '~/../../../packages/ui/dist'; import { convertMoneyToString } from '~/utils/offers/currency'; -import { getCompanyDisplayText } from '~/utils/offers/string'; import { formatDate } from '~/utils/offers/time'; import { JobTypeLabel } from '../constants'; @@ -36,52 +41,109 @@ export default function OfferProfileCard({ profileId, }, }: OfferProfileCardProps) { - return ( - -
-
- -
-
-

{profileName}

- {previousCompanies.length > 0 && ( -
- - Current: - {previousCompanies[0]} + function UpperSection() { + return ( +
+
+
+
+
+ +
+
+

+ {profileName} +

+

+ + YOE: + {totalYoe} + {previousCompanies.length > 0 && ( + <> + + Previous: + {previousCompanies[0]} + + )} +

+
- )} -
- - YOE: - {totalYoe} +
+
+
+ ); + } - -
-
-

- {getLabelForJobTitleType(title as JobTitleType)}{' '} - {`(${JobTypeLabel[jobType]})`} -

-

{`Company: ${getCompanyDisplayText(company.name, location)}`}

- {level &&

Level: {level}

} -
-
-

{formatDate(monthYearReceived)}

-

- {jobType === JobType.FULLTIME - ? `${convertMoneyToString(income)} / year` - : `${convertMoneyToString(income)} / month`} -

+ function BottomSection() { + return ( +
+
+
+

+ {getLabelForJobTitleType(title as JobTitleType)}{' '} + {jobType && <>({JobTypeLabel[jobType]})} +

+
+ {company?.name && ( +
+
+ )} + {location && ( +
+
+ )} + {level && ( +
+
+ )} +
+
+
+

+ {jobType === JobType.FULLTIME + ? `${convertMoneyToString(income)} / year` + : `${convertMoneyToString(income)} / month`} +

+

+ {formatDate(monthYearReceived)} +

+
-
+ ); + } + + return ( +
+ + +
); } diff --git a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx index bef36c36..f27e7cce 100644 --- a/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx @@ -13,10 +13,12 @@ import BackgroundForm from '~/components/offers/offersSubmission/submissionForm/ import OfferDetailsForm from '~/components/offers/offersSubmission/submissionForm/OfferDetailsForm'; import type { OfferFormData, + OfferPostData, OffersProfileFormData, } from '~/components/offers/types'; import type { Month } from '~/components/shared/MonthYearPicker'; +import { Currency } from '~/utils/offers/currency/CurrencyEnum'; import { cleanObject, removeEmptyObjects, @@ -25,6 +27,8 @@ import { import { getCurrentMonth, getCurrentYear } from '~/utils/offers/time'; import { trpc } from '~/utils/trpc'; +export const DEFAULT_CURRENCY = Currency.SGD; + const defaultOfferValues = { cityId: '', comments: '', @@ -43,21 +47,17 @@ export const defaultFullTimeOfferValues = { jobType: JobType.FULLTIME, offersFullTime: { baseSalary: { - currency: 'SGD', - value: null, + currency: DEFAULT_CURRENCY, }, bonus: { - currency: 'SGD', - value: null, + currency: DEFAULT_CURRENCY, }, level: '', stocks: { - currency: 'SGD', - value: null, + currency: DEFAULT_CURRENCY, }, totalCompensation: { - currency: 'SGD', - value: null, + currency: DEFAULT_CURRENCY, }, }, }; @@ -66,16 +66,15 @@ export const defaultInternshipOfferValues = { ...defaultOfferValues, jobType: JobType.INTERN, offersIntern: { - internshipCycle: null, + internshipCycle: '', monthlySalary: { - currency: 'SGD', - value: null, + currency: DEFAULT_CURRENCY, }, startYear: null, }, }; -const defaultOfferProfileValues = { +const defaultOfferProfileValues: OffersProfileFormData = { background: { educations: [], experiences: [{ jobType: JobType.FULLTIME }], @@ -116,7 +115,7 @@ export default function OffersSubmissionForm({ const { handleSubmit, trigger, - formState: { isSubmitting }, + formState: { isSubmitting, isDirty }, } = formMethods; const generateAnalysisMutation = trpc.useMutation( @@ -218,7 +217,7 @@ export default function OffersSubmissionForm({ offer.monthYearReceived.year, offer.monthYearReceived.month - 1, // Convert month to monthIndex ), - })); + })) as Array; if (params.profileId && params.token) { createOrUpdateMutation.mutate({ @@ -254,11 +253,14 @@ export default function OffersSubmissionForm({ const warningText = 'Leave this page? Changes that you made will not be saved.'; const handleWindowClose = (e: BeforeUnloadEvent) => { + if (!isDirty) { + return; + } e.preventDefault(); return (e.returnValue = warningText); }; const handleRouteChange = (url: string) => { - if (url.includes('/offers/submit/result')) { + if (url.includes('/offers/submit/result') || !isDirty) { return; } if (window.confirm(warningText)) { @@ -274,7 +276,7 @@ export default function OffersSubmissionForm({ router.events.off('routeChangeStart', handleRouteChange); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [isDirty]); return generateAnalysisMutation.isLoading ? ( @@ -353,4 +355,4 @@ export default function OffersSubmissionForm({
); -} \ No newline at end of file +} diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx index 5bd4307b..e0b1828e 100644 --- a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx @@ -117,6 +117,7 @@ function FullTimeOfferDetailsForm({ onSelect={(option) => { if (option) { setValue(`offers.${index}.companyId`, option.value); + setValue(`offers.${index}.companyName`, option.label); } }} /> @@ -550,7 +551,6 @@ export default function OfferDetailsForm() { if (newJobType === jobType) { return; } - setDialogOpen(true); }} /> @@ -586,4 +586,4 @@ export default function OfferDetailsForm() {
); -} \ No newline at end of file +} diff --git a/apps/portal/src/components/offers/profile/ProfileDetails.tsx b/apps/portal/src/components/offers/profile/ProfileDetails.tsx index 9a6ccaef..3be4ae3c 100644 --- a/apps/portal/src/components/offers/profile/ProfileDetails.tsx +++ b/apps/portal/src/components/offers/profile/ProfileDetails.tsx @@ -131,9 +131,8 @@ function ProfileAnalysis({ {isEditable && (