Skip to content

Commit 77d0714

Browse files
authored
[offers][fix] Refactor and fix offer analysis (yangshun#413)
1 parent 6bf1a60 commit 77d0714

20 files changed

+255
-209
lines changed

apps/portal/src/components/offers/offersSubmission/OfferProfileSave.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default function OfferProfileSave({
8484
onClick={saveProfile}
8585
/>
8686
</div>
87-
<div className="mb-10">
87+
<div>
8888
<Button
8989
icon={EyeIcon}
9090
label="View your profile"

apps/portal/src/components/offers/offersSubmission/OffersSubmissionForm.tsx

+11-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useRef, useState } from 'react';
22
import type { SubmitHandler } from 'react-hook-form';
33
import { FormProvider, useForm } from 'react-hook-form';
44
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
5+
import { JobType } from '@prisma/client';
56
import { Button } from '@tih/ui';
67

78
import { Breadcrumbs } from '~/components/offers/Breadcrumb';
@@ -13,7 +14,6 @@ import type {
1314
OfferFormData,
1415
OffersProfileFormData,
1516
} from '~/components/offers/types';
16-
import { JobType } from '~/components/offers/types';
1717
import type { Month } from '~/components/shared/MonthYearPicker';
1818

1919
import { cleanObject, removeInvalidMoneyData } from '~/utils/offers/form';
@@ -25,7 +25,7 @@ import type { CreateOfferProfileResponse } from '~/types/offers';
2525
const defaultOfferValues = {
2626
comments: '',
2727
companyId: '',
28-
jobType: JobType.FullTime,
28+
jobType: JobType.FULLTIME,
2929
location: '',
3030
monthYearReceived: {
3131
month: getCurrentMonth() as Month,
@@ -36,18 +36,18 @@ const defaultOfferValues = {
3636

3737
export const defaultFullTimeOfferValues = {
3838
...defaultOfferValues,
39-
jobType: JobType.FullTime,
39+
jobType: JobType.FULLTIME,
4040
};
4141

4242
export const defaultInternshipOfferValues = {
4343
...defaultOfferValues,
44-
jobType: JobType.Intern,
44+
jobType: JobType.INTERN,
4545
};
4646

4747
const defaultOfferProfileValues = {
4848
background: {
4949
educations: [],
50-
experiences: [{ jobType: JobType.FullTime }],
50+
experiences: [{ jobType: JobType.FULLTIME }],
5151
specificYoes: [],
5252
totalYoe: 0,
5353
},
@@ -90,7 +90,12 @@ export default function OffersSubmissionForm({
9090

9191
const formSteps: Array<FormStep> = [
9292
{
93-
component: <OfferDetailsForm key={0} />,
93+
component: (
94+
<OfferDetailsForm
95+
key={0}
96+
defaultJobType={initialOfferProfileValues.offers[0].jobType}
97+
/>
98+
),
9499
hasNext: true,
95100
hasPrevious: false,
96101
label: 'Offer details',

apps/portal/src/components/offers/offersSubmission/analysis/OfferAnalysis.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { HorizontalDivider, Spinner, Tabs } from '@tih/ui';
44

55
import { trpc } from '~/utils/trpc';
66

7-
import OfferPercentileAnalysis from './OfferPercentileAnalysis';
7+
import OfferPercentileAnalysisText from './OfferPercentileAnalysisText';
88
import OfferProfileCard from './OfferProfileCard';
99
import { OVERALL_TAB } from '../../constants';
1010

@@ -38,11 +38,12 @@ function OfferAnalysisContent({
3838
}
3939
return (
4040
<>
41-
<OfferPercentileAnalysis
41+
<OfferPercentileAnalysisText
4242
companyName={offer.company.name}
4343
offerAnalysis={offerAnalysis}
4444
tab={tab}
4545
/>
46+
<p className="mt-5">Here are some of the top offers relevant to you:</p>
4647
{offerAnalysis.topPercentileOffers.map((topPercentileOffer) => (
4748
<OfferProfileCard
4849
key={topPercentileOffer.id}

apps/portal/src/components/offers/offersSubmission/analysis/OfferPercentileAnalysis.tsx

-27
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { Analysis } from '~/types/offers';
2+
3+
type OfferPercentileAnalysisTextProps = Readonly<{
4+
companyName: string;
5+
offerAnalysis: Analysis;
6+
tab: string;
7+
}>;
8+
9+
export default function OfferPercentileAnalysisText({
10+
tab,
11+
companyName,
12+
offerAnalysis: { noOfOffers, percentile },
13+
}: OfferPercentileAnalysisTextProps) {
14+
return tab === 'Overall' ? (
15+
<p>
16+
Your highest offer is from <b>{companyName}</b>, which is{' '}
17+
<b>{percentile}</b> percentile out of <b>{noOfOffers}</b> offers received
18+
for the same job title and YOE(+/-1) in the last year.
19+
</p>
20+
) : (
21+
<p>
22+
Your offer from <b>{companyName}</b> is <b>{percentile}</b> percentile out
23+
of <b>{noOfOffers}</b> offers received in {companyName} for the same job
24+
title and YOE(+/-1) in the last year.
25+
</p>
26+
);
27+
}

apps/portal/src/components/offers/offersSubmission/analysis/OfferProfileCard.tsx

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { UserCircleIcon } from '@heroicons/react/24/outline';
1+
import { JobType } from '@prisma/client';
22

33
import { HorizontalDivider } from '~/../../../packages/ui/dist';
4+
import { convertMoneyToString } from '~/utils/offers/currency';
45
import { formatDate } from '~/utils/offers/time';
56

6-
import { JobType } from '../../types';
7+
import ProfilePhotoHolder from '../../profile/ProfilePhotoHolder';
78

89
import type { AnalysisOffer } from '~/types/offers';
910

@@ -29,7 +30,7 @@ export default function OfferProfileCard({
2930
<div className="my-5 block rounded-lg border p-4">
3031
<div className="grid grid-flow-col grid-cols-12 gap-x-10">
3132
<div className="col-span-1">
32-
<UserCircleIcon width={50} />
33+
<ProfilePhotoHolder size="sm" />
3334
</div>
3435
<div className="col-span-10">
3536
<p className="text-sm font-semibold">{profileName}</p>
@@ -50,9 +51,9 @@ export default function OfferProfileCard({
5051
<div className="col-span-1 row-span-3">
5152
<p className="text-end text-sm">{formatDate(monthYearReceived)}</p>
5253
<p className="text-end text-xl">
53-
{jobType === JobType.FullTime
54-
? `$${income} / year`
55-
: `$${income} / month`}
54+
{jobType === JobType.FULLTIME
55+
? `${convertMoneyToString(income)} / year`
56+
: `${convertMoneyToString(income)} / month`}
5657
</p>
5758
</div>
5859
</div>

apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useFormContext, useWatch } from 'react-hook-form';
2+
import { JobType } from '@prisma/client';
23
import { Collapsible, RadioList } from '@tih/ui';
34

45
import {
@@ -10,7 +11,6 @@ import {
1011
titleOptions,
1112
} from '~/components/offers/constants';
1213
import type { BackgroundPostData } from '~/components/offers/types';
13-
import { JobType } from '~/components/offers/types';
1414
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
1515

1616
import { CURRENCY_OPTIONS } from '~/utils/offers/currency/CurrencyEnum';
@@ -239,7 +239,7 @@ function InternshipJobFields() {
239239
function CurrentJobSection() {
240240
const { register } = useFormContext();
241241
const watchJobType = useWatch({
242-
defaultValue: JobType.FullTime,
242+
defaultValue: JobType.FULLTIME,
243243
name: 'background.experiences.0.jobType',
244244
});
245245

@@ -251,24 +251,24 @@ function CurrentJobSection() {
251251
<div className="mb-5 rounded-lg border border-gray-200 px-10 py-5">
252252
<div className="mb-5">
253253
<FormRadioList
254-
defaultValue={JobType.FullTime}
254+
defaultValue={JobType.FULLTIME}
255255
isLabelHidden={true}
256256
label="Job Type"
257257
orientation="horizontal"
258258
{...register('background.experiences.0.jobType')}>
259259
<RadioList.Item
260260
key="Full-time"
261261
label="Full-time"
262-
value={JobType.FullTime}
262+
value={JobType.FULLTIME}
263263
/>
264264
<RadioList.Item
265265
key="Internship"
266266
label="Internship"
267-
value={JobType.Intern}
267+
value={JobType.INTERN}
268268
/>
269269
</FormRadioList>
270270
</div>
271-
{watchJobType === JobType.FullTime ? (
271+
{watchJobType === JobType.FULLTIME ? (
272272
<FullTimeJobFields />
273273
) : (
274274
<InternshipJobFields />

apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx

+19-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useFormContext } from 'react-hook-form';
99
import { useFieldArray } from 'react-hook-form';
1010
import { PlusIcon } from '@heroicons/react/20/solid';
1111
import { TrashIcon } from '@heroicons/react/24/outline';
12+
import { JobType } from '@prisma/client';
1213
import { Button, Dialog } from '@tih/ui';
1314

1415
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
@@ -31,7 +32,6 @@ import FormTextArea from '../../forms/FormTextArea';
3132
import FormTextInput from '../../forms/FormTextInput';
3233
import type { OfferFormData } from '../../types';
3334
import { JobTypeLabel } from '../../types';
34-
import { JobType } from '../../types';
3535
import { CURRENCY_OPTIONS } from '../../../../utils/offers/currency/CurrencyEnum';
3636

3737
type FullTimeOfferDetailsFormProps = Readonly<{
@@ -448,7 +448,7 @@ function OfferDetailsFormArray({
448448
{fields.map((item, index) => {
449449
return (
450450
<div key={item.id}>
451-
{jobType === JobType.FullTime ? (
451+
{jobType === JobType.FULLTIME ? (
452452
<FullTimeOfferDetailsForm index={index} remove={remove} />
453453
) : (
454454
<InternshipOfferDetailsForm index={index} remove={remove} />
@@ -464,7 +464,7 @@ function OfferDetailsFormArray({
464464
variant="tertiary"
465465
onClick={() =>
466466
append(
467-
jobType === JobType.FullTime
467+
jobType === JobType.FULLTIME
468468
? defaultFullTimeOfferValues
469469
: defaultInternshipOfferValues,
470470
)
@@ -474,26 +474,32 @@ function OfferDetailsFormArray({
474474
);
475475
}
476476

477-
export default function OfferDetailsForm() {
478-
const [jobType, setJobType] = useState(JobType.FullTime);
477+
type OfferDetailsFormProps = Readonly<{
478+
defaultJobType?: JobType;
479+
}>;
480+
481+
export default function OfferDetailsForm({
482+
defaultJobType = JobType.FULLTIME,
483+
}: OfferDetailsFormProps) {
484+
const [jobType, setJobType] = useState(defaultJobType);
479485
const [isDialogOpen, setDialogOpen] = useState(false);
480486
const { control } = useFormContext();
481487
const fieldArrayValues = useFieldArray({ control, name: 'offers' });
482488
const { append, remove } = fieldArrayValues;
483489

484490
const toggleJobType = () => {
485491
remove();
486-
if (jobType === JobType.FullTime) {
487-
setJobType(JobType.Intern);
492+
if (jobType === JobType.FULLTIME) {
493+
setJobType(JobType.INTERN);
488494
append(defaultInternshipOfferValues);
489495
} else {
490-
setJobType(JobType.FullTime);
496+
setJobType(JobType.FULLTIME);
491497
append(defaultFullTimeOfferValues);
492498
}
493499
};
494500

495501
const switchJobTypeLabel = () =>
496-
jobType === JobType.FullTime ? JobTypeLabel.INTERN : JobTypeLabel.FULLTIME;
502+
jobType === JobType.FULLTIME ? JobTypeLabel.INTERN : JobTypeLabel.FULLTIME;
497503

498504
return (
499505
<div className="mb-5">
@@ -506,9 +512,9 @@ export default function OfferDetailsForm() {
506512
display="block"
507513
label={JobTypeLabel.FULLTIME}
508514
size="md"
509-
variant={jobType === JobType.FullTime ? 'secondary' : 'tertiary'}
515+
variant={jobType === JobType.FULLTIME ? 'secondary' : 'tertiary'}
510516
onClick={() => {
511-
if (jobType === JobType.FullTime) {
517+
if (jobType === JobType.FULLTIME) {
512518
return;
513519
}
514520
setDialogOpen(true);
@@ -520,9 +526,9 @@ export default function OfferDetailsForm() {
520526
display="block"
521527
label={JobTypeLabel.INTERN}
522528
size="md"
523-
variant={jobType === JobType.Intern ? 'secondary' : 'tertiary'}
529+
variant={jobType === JobType.INTERN ? 'secondary' : 'tertiary'}
524530
onClick={() => {
525-
if (jobType === JobType.Intern) {
531+
if (jobType === JobType.INTERN) {
526532
return;
527533
}
528534
setDialogOpen(true);

apps/portal/src/components/offers/profile/EducationCard.tsx

+3-13
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,10 @@ import {
33
LightBulbIcon,
44
} from '@heroicons/react/24/outline';
55

6-
import type { EducationBackgroundType } from '~/components/offers/types';
7-
8-
type EducationEntity = {
9-
endDate?: string;
10-
field?: string;
11-
school?: string;
12-
startDate?: string;
13-
type?: EducationBackgroundType;
14-
};
6+
import type { EducationDisplayData } from '~/components/offers/types';
157

168
type Props = Readonly<{
17-
education: EducationEntity;
9+
education: EducationDisplayData;
1810
}>;
1911

2012
export default function EducationCard({
@@ -39,9 +31,7 @@ export default function EducationCard({
3931
</div>
4032
{(startDate || endDate) && (
4133
<div className="font-light text-gray-400">
42-
<p>{`${startDate ? startDate : 'N/A'} - ${
43-
endDate ? endDate : 'N/A'
44-
}`}</p>
34+
<p>{`${startDate || 'N/A'} - ${endDate || 'N/A'}`}</p>
4535
</div>
4636
)}
4737
</div>

apps/portal/src/components/offers/profile/OfferCard.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import {
66
} from '@heroicons/react/24/outline';
77
import { HorizontalDivider } from '@tih/ui';
88

9-
import type { OfferEntity } from '~/components/offers/types';
9+
import type { OfferDisplayData } from '~/components/offers/types';
1010

1111
type Props = Readonly<{
12-
offer: OfferEntity;
12+
offer: OfferDisplayData;
1313
}>;
1414

1515
export default function OfferCard({

0 commit comments

Comments
 (0)