From c86c77d1e00485247aff0b92d07255ce05f8d99f Mon Sep 17 00:00:00 2001 From: Zhang Ziqing <69516975+ziqing26@users.noreply.github.com> Date: Thu, 3 Nov 2022 12:20:51 +0800 Subject: [PATCH 01/11] [offers][style] fix dashboard layout (#496) * [offers][style] fix dashboard layout * [offers][fix] fix profile link layout --- apps/portal/src/components/offers/profile/ProfileComments.tsx | 2 +- apps/portal/src/components/offers/table/OffersTable.tsx | 3 --- apps/portal/src/pages/offers/dashboard.tsx | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/portal/src/components/offers/profile/ProfileComments.tsx b/apps/portal/src/components/offers/profile/ProfileComments.tsx index dc0ec114..5654ed5e 100644 --- a/apps/portal/src/components/offers/profile/ProfileComments.tsx +++ b/apps/portal/src/components/offers/profile/ProfileComments.tsx @@ -113,7 +113,7 @@ export default function ProfileComments({
-
+
{isEditable && ( diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx index 534cd783..5ca1d91b 100644 --- a/apps/portal/src/components/offers/table/OffersTable.tsx +++ b/apps/portal/src/components/offers/table/OffersTable.tsx @@ -247,9 +247,6 @@ export default function OffersTable({ (offers.length === 0 && (
No data yet🥺
-
- Please try another set of filters. -
))}
diff --git a/apps/portal/src/pages/offers/dashboard.tsx b/apps/portal/src/pages/offers/dashboard.tsx index 1ae9ea46..bb3f5dc8 100644 --- a/apps/portal/src/pages/offers/dashboard.tsx +++ b/apps/portal/src/pages/offers/dashboard.tsx @@ -46,8 +46,8 @@ export default function ProfilesDashboard() { if (userProfiles.length === 0) { return (
-
-
+
+

You have not saved any offer profiles yet.

From f7d1c8d2c4f094da9b1360e367944937cd4349f9 Mon Sep 17 00:00:00 2001 From: Wu Peirong Date: Thu, 3 Nov 2022 12:43:04 +0800 Subject: [PATCH 02/11] [resumes][chore] remove overflow on page components --- .../components/resumes/comments/ResumeCommentsList.tsx | 2 +- apps/portal/src/pages/resumes/[resumeId].tsx | 4 ++-- apps/portal/src/pages/resumes/index.tsx | 8 ++++---- apps/portal/src/pages/resumes/submit.tsx | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/portal/src/components/resumes/comments/ResumeCommentsList.tsx b/apps/portal/src/components/resumes/comments/ResumeCommentsList.tsx index 271fdd44..b4af9089 100644 --- a/apps/portal/src/components/resumes/comments/ResumeCommentsList.tsx +++ b/apps/portal/src/components/resumes/comments/ResumeCommentsList.tsx @@ -57,7 +57,7 @@ export default function ResumeCommentsList({ } return ( -
+
{RESUME_COMMENTS_SECTIONS.map(({ label, value }) => { const comments = commentsQuery.data ? commentsQuery.data.filter((comment: ResumeComment) => { diff --git a/apps/portal/src/pages/resumes/[resumeId].tsx b/apps/portal/src/pages/resumes/[resumeId].tsx index 4e6c9bea..2fea9d4f 100644 --- a/apps/portal/src/pages/resumes/[resumeId].tsx +++ b/apps/portal/src/pages/resumes/[resumeId].tsx @@ -236,8 +236,8 @@ export default function ResumeReviewPage() { {detailsQuery.data.title} -
-
+
+

{detailsQuery.data.title}

diff --git a/apps/portal/src/pages/resumes/index.tsx b/apps/portal/src/pages/resumes/index.tsx index 549a7849..7b601e40 100644 --- a/apps/portal/src/pages/resumes/index.tsx +++ b/apps/portal/src/pages/resumes/index.tsx @@ -395,7 +395,7 @@ export default function ResumeHomePage() { leave="transition ease-in-out duration-300 transform" leaveFrom="translate-x-0" leaveTo="translate-x-full"> - +

Quick access @@ -614,7 +614,7 @@ export default function ResumeHomePage() {

-
+
) : ( -
+
-
+
{getTabTotalPages() > 1 && (
)} {status === 'authenticated' && ( -
+
From 7e06e07df4f9c1231da8efa575bc0d717469ce2a Mon Sep 17 00:00:00 2001 From: Zhang Ziqing <69516975+ziqing26@users.noreply.github.com> Date: Thu, 3 Nov 2022 15:07:28 +0800 Subject: [PATCH 03/11] [offers][fix] fix profile location display (#497) --- apps/portal/src/components/offers/profile/ProfileHeader.tsx | 4 ++-- apps/portal/src/components/offers/table/OffersRow.tsx | 6 +++--- apps/portal/src/pages/offers/profile/[offerProfileId].tsx | 1 + apps/portal/src/utils/offers/currency/index.tsx | 6 +++++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/portal/src/components/offers/profile/ProfileHeader.tsx b/apps/portal/src/components/offers/profile/ProfileHeader.tsx index 9a2923be..625e2be7 100644 --- a/apps/portal/src/components/offers/profile/ProfileHeader.tsx +++ b/apps/portal/src/components/offers/profile/ProfileHeader.tsx @@ -246,7 +246,7 @@ export default function ProfileHeader({ {(experiences[0]?.companyName || experiences[0]?.jobLevel || experiences[0]?.jobTitle) && ( -
+
@@ -262,7 +262,7 @@ export default function ProfileHeader({

)} -
+

YOE: diff --git a/apps/portal/src/components/offers/table/OffersRow.tsx b/apps/portal/src/components/offers/table/OffersRow.tsx index 77c7ab44..f80802e4 100644 --- a/apps/portal/src/components/offers/table/OffersRow.tsx +++ b/apps/portal/src/components/offers/table/OffersRow.tsx @@ -42,9 +42,9 @@ export default function OfferTableRow({ {convertMoneyToString(income)} {jobType === JobType.FULLTIME && ( - {`${baseSalary && convertMoneyToString(baseSalary)} / ${ - bonus && convertMoneyToString(bonus) - } / ${stocks && convertMoneyToString(stocks)}`} + {`${convertMoneyToString(baseSalary)} / ${convertMoneyToString( + bonus, + )} / ${convertMoneyToString(stocks)}`} )} {formatDate(monthYearReceived)} diff --git a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx index 092cf8b9..73468325 100644 --- a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx +++ b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx @@ -132,6 +132,7 @@ export default function OfferProfile() { ? getLabelForJobTitleType(experience.title as JobTitleType) : null, jobType: experience.jobType || undefined, + location: experience.location, monthlySalary: experience.monthlySalary ? convertMoneyToString(experience.monthlySalary) : null, diff --git a/apps/portal/src/utils/offers/currency/index.tsx b/apps/portal/src/utils/offers/currency/index.tsx index 1e219c45..b8ab6932 100644 --- a/apps/portal/src/utils/offers/currency/index.tsx +++ b/apps/portal/src/utils/offers/currency/index.tsx @@ -4,7 +4,11 @@ import { Currency } from './CurrencyEnum'; export const baseCurrencyString = Currency.USD.toString(); -export function convertMoneyToString({ currency, value }: Money) { +export function convertMoneyToString(money: Money | undefined) { + if (!money) { + return '-'; + } + const { currency, value } = money; if (!value) { return '-'; } From b3eb2f6d6b1a201ad4a15aa684e4b06e2feec989 Mon Sep 17 00:00:00 2001 From: Bryann Yeap Kok Keong Date: Thu, 3 Nov 2022 16:13:32 +0800 Subject: [PATCH 04/11] [offers][chore] Add profileId to AnalysisOffer --- apps/portal/src/mappers/offers-mappers.ts | 14 ++++++-------- apps/portal/src/types/offers.d.ts | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/portal/src/mappers/offers-mappers.ts b/apps/portal/src/mappers/offers-mappers.ts index 07b37bb0..9ce90cc1 100644 --- a/apps/portal/src/mappers/offers-mappers.ts +++ b/apps/portal/src/mappers/offers-mappers.ts @@ -87,6 +87,7 @@ const analysisOfferDtoMapper = ( background?.experiences ?.filter((exp) => exp.company != null) .map((exp) => exp.company?.name ?? '') ?? [], + profileId: offer.profileId, profileName, title: offer.jobType === JobType.FULLTIME @@ -708,20 +709,17 @@ export const dashboardOfferDtoMapper = ( if (offer.offersFullTime.baseSalary) { dashboardOfferDto.baseSalary = valuationDtoMapper( - offer.offersFullTime.baseSalary + offer.offersFullTime.baseSalary, ); } if (offer.offersFullTime.bonus) { - dashboardOfferDto.bonus = valuationDtoMapper( - offer.offersFullTime.bonus - ); - + dashboardOfferDto.bonus = valuationDtoMapper(offer.offersFullTime.bonus); } if (offer.offersFullTime.stocks) { dashboardOfferDto.stocks = valuationDtoMapper( - offer.offersFullTime.stocks + offer.offersFullTime.stocks, ); } } else if (offer.offersIntern) { @@ -736,12 +734,12 @@ export const dashboardOfferDtoMapper = ( export const getOffersResponseMapper = ( data: Array, paging: Paging, - jobType: JobType + jobType: JobType, ) => { const getOffersResponse: GetOffersResponse = { data, jobType, - paging + paging, }; return getOffersResponse; }; diff --git a/apps/portal/src/types/offers.d.ts b/apps/portal/src/types/offers.d.ts index 425d654d..559c9f31 100644 --- a/apps/portal/src/types/offers.d.ts +++ b/apps/portal/src/types/offers.d.ts @@ -181,6 +181,7 @@ export type AnalysisOffer = { monthYearReceived: Date; negotiationStrategy: string; previousCompanies: Array; + profileId: string; profileName: string; title: string; totalYoe: number; From 230b32be34acca8d9ccbe9e3f7aa6cb32509f435 Mon Sep 17 00:00:00 2001 From: Ai Ling <50992674+ailing35@users.noreply.github.com> Date: Thu, 3 Nov 2022 16:24:48 +0800 Subject: [PATCH 05/11] [offers][feat] Add token check and refactor UI (#499) * [offers][fix] Fix and refactor UI * [offers][feat] Add token check in submission results page * [offers][refactor] Refactor text display --- .../{Breadcrumb.tsx => Breadcrumbs.tsx} | 0 .../src/components/offers/EducationFields.ts | 16 ++++ .../src/components/offers/EducationLevels.ts | 18 ++++ .../src/components/offers/InternshipCycles.ts | 18 ++++ .../src/components/offers/JobTypeTabs.tsx | 2 +- apps/portal/src/components/offers/Years.ts | 8 ++ .../portal/src/components/offers/constants.ts | 82 ++----------------- .../offers/features/LeftTextCard.tsx | 2 +- .../offers/features/RightTextCard.tsx | 2 +- .../offers/offerAnalysis/OfferProfileCard.tsx | 5 +- .../offersSubmission/OffersProfileSave.tsx | 1 - .../offersSubmission/OffersSubmissionForm.tsx | 41 ++++++---- .../submissionForm/BackgroundForm.tsx | 18 ++-- .../submissionForm/OfferDetailsForm.tsx | 31 +++---- .../components/offers/profile/OfferCard.tsx | 29 ++++--- .../offers/profile/ProfileHeader.tsx | 2 +- .../components/offers/table/OffersTable.tsx | 12 ++- .../offers/table/OffersTablePagination.tsx | 2 +- apps/portal/src/components/offers/types.ts | 21 ----- apps/portal/src/pages/offers/features.tsx | 2 +- .../pages/offers/profile/[offerProfileId].tsx | 2 +- .../offers/submit/result/[offerProfileId].tsx | 26 ++++-- .../offers/currency/CurrencySelector.tsx | 2 +- apps/portal/src/utils/offers/string.tsx | 37 +++++++++ 24 files changed, 206 insertions(+), 173 deletions(-) rename apps/portal/src/components/offers/{Breadcrumb.tsx => Breadcrumbs.tsx} (100%) create mode 100644 apps/portal/src/components/offers/EducationFields.ts create mode 100644 apps/portal/src/components/offers/EducationLevels.ts create mode 100644 apps/portal/src/components/offers/InternshipCycles.ts create mode 100644 apps/portal/src/components/offers/Years.ts create mode 100644 apps/portal/src/utils/offers/string.tsx diff --git a/apps/portal/src/components/offers/Breadcrumb.tsx b/apps/portal/src/components/offers/Breadcrumbs.tsx similarity index 100% rename from apps/portal/src/components/offers/Breadcrumb.tsx rename to apps/portal/src/components/offers/Breadcrumbs.tsx diff --git a/apps/portal/src/components/offers/EducationFields.ts b/apps/portal/src/components/offers/EducationFields.ts new file mode 100644 index 00000000..6818b9ab --- /dev/null +++ b/apps/portal/src/components/offers/EducationFields.ts @@ -0,0 +1,16 @@ +import { emptyOption } from './constants'; + +export const EducationFieldLabels = [ + 'Business Analytics', + 'Computer Science', + 'Data Science and Analytics', + 'Information Security', + 'Information Systems', +]; + +export const EducationFieldOptions = [emptyOption].concat( + EducationFieldLabels.map((label) => ({ + label, + value: label.replace(/\s+/g, '-').toLowerCase(), + })), +); diff --git a/apps/portal/src/components/offers/EducationLevels.ts b/apps/portal/src/components/offers/EducationLevels.ts new file mode 100644 index 00000000..176b2519 --- /dev/null +++ b/apps/portal/src/components/offers/EducationLevels.ts @@ -0,0 +1,18 @@ +import { emptyOption } from './constants'; + +export const EducationLevelLabels = [ + 'Bachelor', + 'Diploma', + 'Masters', + 'PhD', + 'Professional', + 'Secondary', + 'Self-taught', +]; + +export const EducationLevelOptions = [emptyOption].concat( + EducationLevelLabels.map((label) => ({ + label, + value: label.replace(/\s+/g, '-').toLowerCase(), + })), +); diff --git a/apps/portal/src/components/offers/InternshipCycles.ts b/apps/portal/src/components/offers/InternshipCycles.ts new file mode 100644 index 00000000..1f90539f --- /dev/null +++ b/apps/portal/src/components/offers/InternshipCycles.ts @@ -0,0 +1,18 @@ +import { emptyOption } from './constants'; + +export const InternshipCycleLabels = [ + 'Spring', + 'Summer', + 'Fall', + 'Winter', + 'Half year', + 'Full year', + 'Others', +]; + +export const InternshipCycleOptions = [emptyOption].concat( + InternshipCycleLabels.map((label) => ({ + label, + value: label.replace(/\s+/g, '-').toLowerCase(), + })), +); diff --git a/apps/portal/src/components/offers/JobTypeTabs.tsx b/apps/portal/src/components/offers/JobTypeTabs.tsx index 8ea87bc6..22d70ea7 100644 --- a/apps/portal/src/components/offers/JobTypeTabs.tsx +++ b/apps/portal/src/components/offers/JobTypeTabs.tsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import { JobType } from '@prisma/client'; -import { JobTypeLabel } from './types'; +import { JobTypeLabel } from '~/components/offers/constants'; type Props = Readonly<{ onChange: (jobType: JobType) => void; diff --git a/apps/portal/src/components/offers/Years.ts b/apps/portal/src/components/offers/Years.ts new file mode 100644 index 00000000..da9ab8e3 --- /dev/null +++ b/apps/portal/src/components/offers/Years.ts @@ -0,0 +1,8 @@ +const NUM_YEARS = 5; +export const FutureYearsOptions = Array.from({ length: NUM_YEARS }, (_, i) => { + const year = new Date().getFullYear() + i; + return { + label: String(year), + value: year, + }; +}); diff --git a/apps/portal/src/components/offers/constants.ts b/apps/portal/src/components/offers/constants.ts index d49dca1a..e84dfd4e 100644 --- a/apps/portal/src/components/offers/constants.ts +++ b/apps/portal/src/components/offers/constants.ts @@ -1,78 +1,14 @@ -import { EducationBackgroundType } from './types'; +export const HOME_URL = '/offers'; -export const emptyOption = '----'; +export const JobTypeLabel = { + FULLTIME: 'Full-time', + INTERN: 'Internship', +}; -export const internshipCycleOptions = [ - { - label: 'Summer', - value: 'Summer', - }, - { - label: 'Winter', - value: 'Winter', - }, - { - label: 'Spring', - value: 'Spring', - }, - { - label: 'Fall', - value: 'Fall', - }, - { - label: 'Full year', - value: 'Full year', - }, -]; - -export const yearOptions = [ - { - label: '2021', - value: 2021, - }, - { - label: '2022', - value: 2022, - }, - { - label: '2023', - value: 2023, - }, - { - label: '2024', - value: 2024, - }, -]; - -export const educationLevelOptions = Object.entries( - EducationBackgroundType, -).map(([, value]) => ({ - label: value, - value, -})); - -export const educationFieldOptions = [ - { - label: 'Computer Science', - value: 'Computer Science', - }, - { - label: 'Information Security', - value: 'Information Security', - }, - { - label: 'Information Systems', - value: 'Information Systems', - }, - { - label: 'Business Analytics', - value: 'Business Analytics', - }, - { - label: 'Data Science and Analytics', - value: 'Data Science and Analytics', - }, -]; +export const emptyOption = { + label: '', + value: '', +}; export enum FieldError { NON_NEGATIVE_NUMBER = 'Please fill in a non-negative number in this field.', diff --git a/apps/portal/src/components/offers/features/LeftTextCard.tsx b/apps/portal/src/components/offers/features/LeftTextCard.tsx index b4fac765..867b24b7 100644 --- a/apps/portal/src/components/offers/features/LeftTextCard.tsx +++ b/apps/portal/src/components/offers/features/LeftTextCard.tsx @@ -2,7 +2,7 @@ import type { StaticImageData } from 'next/image'; import Image from 'next/image'; import type { ReactNode } from 'react'; -import { HOME_URL } from '~/components/offers/types'; +import { HOME_URL } from '../constants'; type LeftTextCardProps = Readonly<{ description: string; diff --git a/apps/portal/src/components/offers/features/RightTextCard.tsx b/apps/portal/src/components/offers/features/RightTextCard.tsx index 9ca0f949..028dc57b 100644 --- a/apps/portal/src/components/offers/features/RightTextCard.tsx +++ b/apps/portal/src/components/offers/features/RightTextCard.tsx @@ -2,7 +2,7 @@ import type { StaticImageData } from 'next/image'; import Image from 'next/image'; import type { ReactNode } from 'react'; -import { HOME_URL } from '~/components/offers/types'; +import { HOME_URL } from '../constants'; type RightTextCarddProps = Readonly<{ description: string; diff --git a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx index bdf9a1b3..4c7ecca3 100644 --- a/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx +++ b/apps/portal/src/components/offers/offerAnalysis/OfferProfileCard.tsx @@ -9,10 +9,11 @@ import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; import { HorizontalDivider } 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'; import ProfilePhotoHolder from '../profile/ProfilePhotoHolder'; -import { JobTypeLabel } from '../types'; import type { AnalysisOffer } from '~/types/offers'; @@ -69,7 +70,7 @@ export default function OfferProfileCard({ {getLabelForJobTitleType(title as JobTitleType)}{' '} {`(${JobTypeLabel[jobType]})`}

-

{`Company: ${company.name}, ${location}`}

+

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

{level &&

Level: {level}

}
diff --git a/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx b/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx index b72641d8..d494912e 100644 --- a/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx +++ b/apps/portal/src/components/offers/offersSubmission/OffersProfileSave.tsx @@ -93,7 +93,6 @@ export default function OffersProfileSave({
(null); const scrollToTop = () => @@ -132,13 +133,7 @@ export default function OffersSubmissionForm({ }, ); - const steps = [ - , - , - ]; + const steps = [, ]; const breadcrumbSteps: Array = [ { @@ -157,14 +152,14 @@ export default function OffersSubmissionForm({ }, ]; - const goToNextStep = async (currStep: number) => { - if (currStep === 0) { + const setStepWithValidation = async (nextStep: number) => { + if (nextStep === 1) { const result = await trigger('offers'); if (!result) { return; } } - setStep(step + 1); + setStep(nextStep); }; const mutationpath = @@ -175,10 +170,24 @@ export default function OffersSubmissionForm({ const createOrUpdateMutation = trpc.useMutation([mutationpath], { onError(error) { console.error(error.message); + showToast({ + title: + editProfileId && editToken + ? 'Error updating offer profile.' + : 'Error creating offer profile', + variant: 'failure', + }); }, onSuccess(data) { setParams({ profileId: data.id, token: data.token }); setIsSubmitted(true); + showToast({ + title: + editProfileId && editToken + ? 'Offer profile updated successfully!' + : 'Offer profile created successfully!', + variant: 'success', + }); }, }); @@ -270,7 +279,7 @@ export default function OffersSubmissionForm({
@@ -288,7 +297,7 @@ export default function OffersSubmissionForm({ label="Next" variant="primary" onClick={() => { - goToNextStep(step); + setStepWithValidation(step + 1); gaEvent({ action: 'offers.profile_submission_navigate_next', category: 'submission', diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx index bfe5ee5f..d951f088 100644 --- a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx @@ -2,12 +2,7 @@ import { useFormContext, useWatch } from 'react-hook-form'; import { JobType } from '@prisma/client'; import { Collapsible, RadioList } from '@tih/ui'; -import { - educationFieldOptions, - educationLevelOptions, - emptyOption, - FieldError, -} from '~/components/offers/constants'; +import { FieldError } from '~/components/offers/constants'; import type { BackgroundPostData } from '~/components/offers/types'; import CitiesTypeahead from '~/components/shared/CitiesTypeahead'; import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead'; @@ -20,6 +15,8 @@ import { CURRENCY_OPTIONS, } from '~/utils/offers/currency/CurrencyEnum'; +import { EducationFieldOptions } from '../../EducationFields'; +import { EducationLevelOptions } from '../../EducationLevels'; import FormRadioList from '../../forms/FormRadioList'; import FormSection from '../../forms/FormSection'; import FormSelect from '../../forms/FormSelect'; @@ -134,6 +131,9 @@ function FullTimeJobFields() { if (option) { setValue('background.experiences.0.companyId', option.value); setValue('background.experiences.0.companyName', option.label); + } else { + setValue('background.experiences.0.companyId', ''); + setValue('background.experiences.0.companyName', ''); } }} /> @@ -343,15 +343,13 @@ function EducationSection() {
diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx index 7c9e52e6..1fc38fe2 100644 --- a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx @@ -22,20 +22,16 @@ import { defaultFullTimeOfferValues, defaultInternshipOfferValues, } from '../OffersSubmissionForm'; -import { - emptyOption, - FieldError, - internshipCycleOptions, - yearOptions, -} from '../../constants'; +import { FieldError, JobTypeLabel } from '../../constants'; import FormMonthYearPicker from '../../forms/FormMonthYearPicker'; import FormSection from '../../forms/FormSection'; import FormSelect from '../../forms/FormSelect'; import FormTextArea from '../../forms/FormTextArea'; import FormTextInput from '../../forms/FormTextInput'; +import { InternshipCycleOptions } from '../../InternshipCycles'; import JobTypeTabs from '../../JobTypeTabs'; import type { OfferFormData } from '../../types'; -import { JobTypeLabel } from '../../types'; +import { FutureYearsOptions } from '../../Years'; import { Currency, CURRENCY_OPTIONS, @@ -384,8 +380,7 @@ function InternshipOfferDetailsForm({ display="block" errorMessage={offerFields?.offersIntern?.internshipCycle?.message} label="Internship Cycle" - options={internshipCycleOptions} - placeholder={emptyOption} + options={InternshipCycleOptions} required={true} {...register(`offers.${index}.offersIntern.internshipCycle`, { required: FieldError.REQUIRED, @@ -395,8 +390,7 @@ function InternshipOfferDetailsForm({ display="block" errorMessage={offerFields?.offersIntern?.startYear?.message} label="Internship Year" - options={yearOptions} - placeholder={emptyOption} + options={FutureYearsOptions} required={true} {...register(`offers.${index}.offersIntern.startYear`, { required: FieldError.REQUIRED, @@ -522,14 +516,11 @@ function OfferDetailsFormArray({ ); } -type OfferDetailsFormProps = Readonly<{ - defaultJobType?: JobType; -}>; - -export default function OfferDetailsForm({ - defaultJobType = JobType.FULLTIME, -}: OfferDetailsFormProps) { - const [jobType, setJobType] = useState(defaultJobType); +export default function OfferDetailsForm() { + const watchJobType = useWatch({ + name: `offers.0.jobType`, + }); + const [jobType, setJobType] = useState(watchJobType as JobType); const [isDialogOpen, setDialogOpen] = useState(false); const { control } = useFormContext(); const fieldArrayValues = useFieldArray({ control, name: 'offers' }); @@ -576,8 +567,8 @@ export default function OfferDetailsForm({ label="Switch" variant="primary" onClick={() => { - toggleJobType(); setDialogOpen(false); + toggleJobType(); }} /> } diff --git a/apps/portal/src/components/offers/profile/OfferCard.tsx b/apps/portal/src/components/offers/profile/OfferCard.tsx index 3d03e1ef..75e5735e 100644 --- a/apps/portal/src/components/offers/profile/OfferCard.tsx +++ b/apps/portal/src/components/offers/profile/OfferCard.tsx @@ -7,7 +7,11 @@ import { import { HorizontalDivider } from '@tih/ui'; import type { OfferDisplayData } from '~/components/offers/types'; -import { JobTypeLabel } from '~/components/offers/types'; + +import { + getCompanyDisplayText, + getJobDisplayText, +} from '~/utils/offers/string'; type Props = Readonly<{ offer: OfferDisplayData; @@ -35,19 +39,18 @@ export default function OfferCard({ return (
-
- - - - - {location ? `${companyName}, ${location.cityName}` : companyName} - -
+ {(companyName || location) && ( +
+ + + + + {getCompanyDisplayText(companyName, location)} + +
+ )}
-

- {jobLevel ? `${jobTitle}, ${jobLevel}` : jobTitle}{' '} - {jobType && `(${JobTypeLabel[jobType]})`} -

+

{getJobDisplayText(jobTitle, jobLevel, jobType)}

{!duration && receivedMonth && ( diff --git a/apps/portal/src/components/offers/profile/ProfileHeader.tsx b/apps/portal/src/components/offers/profile/ProfileHeader.tsx index 625e2be7..bb96a295 100644 --- a/apps/portal/src/components/offers/profile/ProfileHeader.tsx +++ b/apps/portal/src/components/offers/profile/ProfileHeader.tsx @@ -13,10 +13,10 @@ import { Button, Dialog, Spinner, Tabs, useToast } from '@tih/ui'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import type { ProfileDetailTab } from '~/components/offers/constants'; +import { JobTypeLabel } from '~/components/offers/constants'; import { profileDetailTabs } from '~/components/offers/constants'; import ProfilePhotoHolder from '~/components/offers/profile/ProfilePhotoHolder'; import type { BackgroundDisplayData } from '~/components/offers/types'; -import { JobTypeLabel } from '~/components/offers/types'; import Tooltip from '~/components/offers/util/Tooltip'; import { getProfileEditPath } from '~/utils/offers/link'; diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx index 5ca1d91b..9022297d 100644 --- a/apps/portal/src/components/offers/table/OffersTable.tsx +++ b/apps/portal/src/components/offers/table/OffersTable.tsx @@ -2,7 +2,7 @@ import clsx from 'clsx'; import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import { JobType } from '@prisma/client'; -import { DropdownMenu, Spinner } from '@tih/ui'; +import { DropdownMenu, Spinner, useToast } from '@tih/ui'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import OffersTablePagination from '~/components/offers/table/OffersTablePagination'; @@ -66,6 +66,7 @@ export default function OffersTable({ event?.preventDefault(); }, [yoeCategory]); + const { showToast } = useToast(); trpc.useQuery( [ 'offers.list', @@ -81,8 +82,11 @@ export default function OffersTable({ }, ], { - onError: (err) => { - alert(err); + onError: () => { + showToast({ + title: 'Error loading the page.', + variant: 'failure', + }); }, onSuccess: (response: GetOffersResponse) => { setOffers(response.data); @@ -246,7 +250,7 @@ export default function OffersTable({ {!offers || (offers.length === 0 && (
-
No data yet🥺
+
No data yet 🥺
))}
diff --git a/apps/portal/src/components/offers/table/OffersTablePagination.tsx b/apps/portal/src/components/offers/table/OffersTablePagination.tsx index 9a235901..45dd7831 100644 --- a/apps/portal/src/components/offers/table/OffersTablePagination.tsx +++ b/apps/portal/src/components/offers/table/OffersTablePagination.tsx @@ -26,7 +26,7 @@ export default function OffersTablePagination({
Showing - {` ${startNumber} - ${endNumber} `} + {` ${endNumber > 0 ? startNumber : 0} - ${endNumber} `} {`of `} diff --git a/apps/portal/src/components/offers/types.ts b/apps/portal/src/components/offers/types.ts index 0e963a17..b38d1540 100644 --- a/apps/portal/src/components/offers/types.ts +++ b/apps/portal/src/components/offers/types.ts @@ -4,27 +4,6 @@ import type { MonthYear } from '~/components/shared/MonthYearPicker'; import type { Location } from '~/types/offers'; -export const HOME_URL = '/offers'; - -/* - * Offer Profile - */ - -export const JobTypeLabel = { - FULLTIME: 'Full-time', - INTERN: 'Internship', -}; - -export enum EducationBackgroundType { - Bachelor = 'Bachelor', - Diploma = 'Diploma', - Masters = 'Masters', - PhD = 'PhD', - Professional = 'Professional', - Secondary = 'Secondary', - SelfTaught = 'Self-taught', -} - export type OffersProfilePostData = { background: BackgroundPostData; id?: string; diff --git a/apps/portal/src/pages/offers/features.tsx b/apps/portal/src/pages/offers/features.tsx index 77ca380c..da0cc28d 100644 --- a/apps/portal/src/pages/offers/features.tsx +++ b/apps/portal/src/pages/offers/features.tsx @@ -8,12 +8,12 @@ import { UsersIcon, } from '@heroicons/react/24/outline'; +import { HOME_URL } from '~/components/offers/constants'; import offersAnalysis from '~/components/offers/features/images/offers-analysis.png'; import offersBrowse from '~/components/offers/features/images/offers-browse.png'; import offersProfile from '~/components/offers/features/images/offers-profile.png'; import LeftTextCard from '~/components/offers/features/LeftTextCard'; import RightTextCard from '~/components/offers/features/RightTextCard'; -import { HOME_URL } from '~/components/offers/types'; const features = [ { diff --git a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx index 73468325..fe39a45b 100644 --- a/apps/portal/src/pages/offers/profile/[offerProfileId].tsx +++ b/apps/portal/src/pages/offers/profile/[offerProfileId].tsx @@ -6,6 +6,7 @@ import { Spinner, useToast } from '@tih/ui'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import { ProfileDetailTab } from '~/components/offers/constants'; +import { HOME_URL } from '~/components/offers/constants'; import ProfileComments from '~/components/offers/profile/ProfileComments'; import ProfileDetails from '~/components/offers/profile/ProfileDetails'; import ProfileHeader from '~/components/offers/profile/ProfileHeader'; @@ -13,7 +14,6 @@ import type { BackgroundDisplayData, OfferDisplayData, } from '~/components/offers/types'; -import { HOME_URL } from '~/components/offers/types'; import type { JobTitleType } from '~/components/shared/JobTitles'; import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; diff --git a/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx b/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx index 35c72796..f507283d 100644 --- a/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx +++ b/apps/portal/src/pages/offers/submit/result/[offerProfileId].tsx @@ -1,11 +1,12 @@ +import Error from 'next/error'; import { useRouter } from 'next/router'; import { useEffect, useRef, useState } from 'react'; import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid'; import { EyeIcon } from '@heroicons/react/24/outline'; import { Button, Spinner } from '@tih/ui'; -import type { BreadcrumbStep } from '~/components/offers/Breadcrumb'; -import { Breadcrumbs } from '~/components/offers/Breadcrumb'; +import type { BreadcrumbStep } from '~/components/offers/Breadcrumbs'; +import { Breadcrumbs } from '~/components/offers/Breadcrumbs'; import OffersProfileSave from '~/components/offers/offersSubmission/OffersProfileSave'; import OffersSubmissionAnalysis from '~/components/offers/offersSubmission/OffersSubmissionAnalysis'; @@ -21,12 +22,21 @@ export default function OffersSubmissionResult() { token = token as string; const [step, setStep] = useState(0); const [analysis, setAnalysis] = useState(null); + const [isValidToken, setIsValidToken] = useState(false); const pageRef = useRef(null); const scrollToTop = () => pageRef.current?.scrollTo({ behavior: 'smooth', top: 0 }); - // TODO: Check if the token is valid before showing this page + const checkToken = trpc.useQuery( + ['offers.profile.isValidToken', { profileId: offerProfileId, token }], + { + onSuccess(data) { + setIsValidToken(data); + }, + }, + ); + const getAnalysis = trpc.useQuery( ['offers.analysis.get', { profileId: offerProfileId }], { @@ -69,7 +79,7 @@ export default function OffersSubmissionResult() { return ( <> - {getAnalysis.isLoading && ( + {(checkToken.isLoading || getAnalysis.isLoading) && (
@@ -77,7 +87,13 @@ export default function OffersSubmissionResult() {
)} - {!getAnalysis.isLoading && ( + {checkToken.isSuccess && !isValidToken && ( + + )} + {getAnalysis.isSuccess && (
diff --git a/apps/portal/src/utils/offers/currency/CurrencySelector.tsx b/apps/portal/src/utils/offers/currency/CurrencySelector.tsx index 2ba883b4..2b339933 100644 --- a/apps/portal/src/utils/offers/currency/CurrencySelector.tsx +++ b/apps/portal/src/utils/offers/currency/CurrencySelector.tsx @@ -20,7 +20,7 @@ export default function CurrencySelector({