mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2026-04-24 10:32:01 +08:00
[offers][fix] Refactor and fix offer analysis (#413)
This commit is contained in:
@@ -84,7 +84,7 @@ export default function OfferProfileSave({
|
||||
onClick={saveProfile}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-10">
|
||||
<div>
|
||||
<Button
|
||||
icon={EyeIcon}
|
||||
label="View your profile"
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useRef, useState } from 'react';
|
||||
import type { SubmitHandler } from 'react-hook-form';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
|
||||
import { JobType } from '@prisma/client';
|
||||
import { Button } from '@tih/ui';
|
||||
|
||||
import { Breadcrumbs } from '~/components/offers/Breadcrumb';
|
||||
@@ -13,7 +14,6 @@ import type {
|
||||
OfferFormData,
|
||||
OffersProfileFormData,
|
||||
} from '~/components/offers/types';
|
||||
import { JobType } from '~/components/offers/types';
|
||||
import type { Month } from '~/components/shared/MonthYearPicker';
|
||||
|
||||
import { cleanObject, removeInvalidMoneyData } from '~/utils/offers/form';
|
||||
@@ -25,7 +25,7 @@ import type { CreateOfferProfileResponse } from '~/types/offers';
|
||||
const defaultOfferValues = {
|
||||
comments: '',
|
||||
companyId: '',
|
||||
jobType: JobType.FullTime,
|
||||
jobType: JobType.FULLTIME,
|
||||
location: '',
|
||||
monthYearReceived: {
|
||||
month: getCurrentMonth() as Month,
|
||||
@@ -36,18 +36,18 @@ const defaultOfferValues = {
|
||||
|
||||
export const defaultFullTimeOfferValues = {
|
||||
...defaultOfferValues,
|
||||
jobType: JobType.FullTime,
|
||||
jobType: JobType.FULLTIME,
|
||||
};
|
||||
|
||||
export const defaultInternshipOfferValues = {
|
||||
...defaultOfferValues,
|
||||
jobType: JobType.Intern,
|
||||
jobType: JobType.INTERN,
|
||||
};
|
||||
|
||||
const defaultOfferProfileValues = {
|
||||
background: {
|
||||
educations: [],
|
||||
experiences: [{ jobType: JobType.FullTime }],
|
||||
experiences: [{ jobType: JobType.FULLTIME }],
|
||||
specificYoes: [],
|
||||
totalYoe: 0,
|
||||
},
|
||||
@@ -90,7 +90,12 @@ export default function OffersSubmissionForm({
|
||||
|
||||
const formSteps: Array<FormStep> = [
|
||||
{
|
||||
component: <OfferDetailsForm key={0} />,
|
||||
component: (
|
||||
<OfferDetailsForm
|
||||
key={0}
|
||||
defaultJobType={initialOfferProfileValues.offers[0].jobType}
|
||||
/>
|
||||
),
|
||||
hasNext: true,
|
||||
hasPrevious: false,
|
||||
label: 'Offer details',
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HorizontalDivider, Spinner, Tabs } from '@tih/ui';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
import OfferPercentileAnalysis from './OfferPercentileAnalysis';
|
||||
import OfferPercentileAnalysisText from './OfferPercentileAnalysisText';
|
||||
import OfferProfileCard from './OfferProfileCard';
|
||||
import { OVERALL_TAB } from '../../constants';
|
||||
|
||||
@@ -38,11 +38,12 @@ function OfferAnalysisContent({
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<OfferPercentileAnalysis
|
||||
<OfferPercentileAnalysisText
|
||||
companyName={offer.company.name}
|
||||
offerAnalysis={offerAnalysis}
|
||||
tab={tab}
|
||||
/>
|
||||
<p className="mt-5">Here are some of the top offers relevant to you:</p>
|
||||
{offerAnalysis.topPercentileOffers.map((topPercentileOffer) => (
|
||||
<OfferProfileCard
|
||||
key={topPercentileOffer.id}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { Analysis } from '~/types/offers';
|
||||
|
||||
type OfferPercentileAnalysisProps = Readonly<{
|
||||
companyName: string;
|
||||
offerAnalysis: Analysis;
|
||||
tab: string;
|
||||
}>;
|
||||
|
||||
export default function OfferPercentileAnalysis({
|
||||
tab,
|
||||
companyName,
|
||||
offerAnalysis: { noOfOffers, percentile },
|
||||
}: OfferPercentileAnalysisProps) {
|
||||
return tab === 'Overall' ? (
|
||||
<p>
|
||||
Your highest offer is from {companyName}, which is {percentile} percentile
|
||||
out of {noOfOffers} offers received for the same job type, same level, and
|
||||
same YOE(+/-1) in the last year.
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
Your offer from {companyName} is {percentile} percentile out of{' '}
|
||||
{noOfOffers} offers received in {companyName} for the same job type, same
|
||||
level, and same YOE(+/-1) in the last year.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { Analysis } from '~/types/offers';
|
||||
|
||||
type OfferPercentileAnalysisTextProps = Readonly<{
|
||||
companyName: string;
|
||||
offerAnalysis: Analysis;
|
||||
tab: string;
|
||||
}>;
|
||||
|
||||
export default function OfferPercentileAnalysisText({
|
||||
tab,
|
||||
companyName,
|
||||
offerAnalysis: { noOfOffers, percentile },
|
||||
}: OfferPercentileAnalysisTextProps) {
|
||||
return tab === 'Overall' ? (
|
||||
<p>
|
||||
Your highest offer is from <b>{companyName}</b>, which is{' '}
|
||||
<b>{percentile}</b> percentile out of <b>{noOfOffers}</b> offers received
|
||||
for the same job title and YOE(+/-1) in the last year.
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
Your offer from <b>{companyName}</b> is <b>{percentile}</b> percentile out
|
||||
of <b>{noOfOffers}</b> offers received in {companyName} for the same job
|
||||
title and YOE(+/-1) in the last year.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { UserCircleIcon } from '@heroicons/react/24/outline';
|
||||
import { JobType } from '@prisma/client';
|
||||
|
||||
import { HorizontalDivider } from '~/../../../packages/ui/dist';
|
||||
import { convertMoneyToString } from '~/utils/offers/currency';
|
||||
import { formatDate } from '~/utils/offers/time';
|
||||
|
||||
import { JobType } from '../../types';
|
||||
import ProfilePhotoHolder from '../../profile/ProfilePhotoHolder';
|
||||
|
||||
import type { AnalysisOffer } from '~/types/offers';
|
||||
|
||||
@@ -29,7 +30,7 @@ export default function OfferProfileCard({
|
||||
<div className="my-5 block rounded-lg border p-4">
|
||||
<div className="grid grid-flow-col grid-cols-12 gap-x-10">
|
||||
<div className="col-span-1">
|
||||
<UserCircleIcon width={50} />
|
||||
<ProfilePhotoHolder size="sm" />
|
||||
</div>
|
||||
<div className="col-span-10">
|
||||
<p className="text-sm font-semibold">{profileName}</p>
|
||||
@@ -50,9 +51,9 @@ export default function OfferProfileCard({
|
||||
<div className="col-span-1 row-span-3">
|
||||
<p className="text-end text-sm">{formatDate(monthYearReceived)}</p>
|
||||
<p className="text-end text-xl">
|
||||
{jobType === JobType.FullTime
|
||||
? `$${income} / year`
|
||||
: `$${income} / month`}
|
||||
{jobType === JobType.FULLTIME
|
||||
? `${convertMoneyToString(income)} / year`
|
||||
: `${convertMoneyToString(income)} / month`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import { JobType } from '@prisma/client';
|
||||
import { Collapsible, RadioList } from '@tih/ui';
|
||||
|
||||
import {
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
titleOptions,
|
||||
} from '~/components/offers/constants';
|
||||
import type { BackgroundPostData } from '~/components/offers/types';
|
||||
import { JobType } from '~/components/offers/types';
|
||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||
|
||||
import { CURRENCY_OPTIONS } from '~/utils/offers/currency/CurrencyEnum';
|
||||
@@ -239,7 +239,7 @@ function InternshipJobFields() {
|
||||
function CurrentJobSection() {
|
||||
const { register } = useFormContext();
|
||||
const watchJobType = useWatch({
|
||||
defaultValue: JobType.FullTime,
|
||||
defaultValue: JobType.FULLTIME,
|
||||
name: 'background.experiences.0.jobType',
|
||||
});
|
||||
|
||||
@@ -251,7 +251,7 @@ function CurrentJobSection() {
|
||||
<div className="mb-5 rounded-lg border border-gray-200 px-10 py-5">
|
||||
<div className="mb-5">
|
||||
<FormRadioList
|
||||
defaultValue={JobType.FullTime}
|
||||
defaultValue={JobType.FULLTIME}
|
||||
isLabelHidden={true}
|
||||
label="Job Type"
|
||||
orientation="horizontal"
|
||||
@@ -259,16 +259,16 @@ function CurrentJobSection() {
|
||||
<RadioList.Item
|
||||
key="Full-time"
|
||||
label="Full-time"
|
||||
value={JobType.FullTime}
|
||||
value={JobType.FULLTIME}
|
||||
/>
|
||||
<RadioList.Item
|
||||
key="Internship"
|
||||
label="Internship"
|
||||
value={JobType.Intern}
|
||||
value={JobType.INTERN}
|
||||
/>
|
||||
</FormRadioList>
|
||||
</div>
|
||||
{watchJobType === JobType.FullTime ? (
|
||||
{watchJobType === JobType.FULLTIME ? (
|
||||
<FullTimeJobFields />
|
||||
) : (
|
||||
<InternshipJobFields />
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useFormContext } from 'react-hook-form';
|
||||
import { useFieldArray } from 'react-hook-form';
|
||||
import { PlusIcon } from '@heroicons/react/20/solid';
|
||||
import { TrashIcon } from '@heroicons/react/24/outline';
|
||||
import { JobType } from '@prisma/client';
|
||||
import { Button, Dialog } from '@tih/ui';
|
||||
|
||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||
@@ -31,7 +32,6 @@ import FormTextArea from '../../forms/FormTextArea';
|
||||
import FormTextInput from '../../forms/FormTextInput';
|
||||
import type { OfferFormData } from '../../types';
|
||||
import { JobTypeLabel } from '../../types';
|
||||
import { JobType } from '../../types';
|
||||
import { CURRENCY_OPTIONS } from '../../../../utils/offers/currency/CurrencyEnum';
|
||||
|
||||
type FullTimeOfferDetailsFormProps = Readonly<{
|
||||
@@ -448,7 +448,7 @@ function OfferDetailsFormArray({
|
||||
{fields.map((item, index) => {
|
||||
return (
|
||||
<div key={item.id}>
|
||||
{jobType === JobType.FullTime ? (
|
||||
{jobType === JobType.FULLTIME ? (
|
||||
<FullTimeOfferDetailsForm index={index} remove={remove} />
|
||||
) : (
|
||||
<InternshipOfferDetailsForm index={index} remove={remove} />
|
||||
@@ -464,7 +464,7 @@ function OfferDetailsFormArray({
|
||||
variant="tertiary"
|
||||
onClick={() =>
|
||||
append(
|
||||
jobType === JobType.FullTime
|
||||
jobType === JobType.FULLTIME
|
||||
? defaultFullTimeOfferValues
|
||||
: defaultInternshipOfferValues,
|
||||
)
|
||||
@@ -474,8 +474,14 @@ function OfferDetailsFormArray({
|
||||
);
|
||||
}
|
||||
|
||||
export default function OfferDetailsForm() {
|
||||
const [jobType, setJobType] = useState(JobType.FullTime);
|
||||
type OfferDetailsFormProps = Readonly<{
|
||||
defaultJobType?: JobType;
|
||||
}>;
|
||||
|
||||
export default function OfferDetailsForm({
|
||||
defaultJobType = JobType.FULLTIME,
|
||||
}: OfferDetailsFormProps) {
|
||||
const [jobType, setJobType] = useState(defaultJobType);
|
||||
const [isDialogOpen, setDialogOpen] = useState(false);
|
||||
const { control } = useFormContext();
|
||||
const fieldArrayValues = useFieldArray({ control, name: 'offers' });
|
||||
@@ -483,17 +489,17 @@ export default function OfferDetailsForm() {
|
||||
|
||||
const toggleJobType = () => {
|
||||
remove();
|
||||
if (jobType === JobType.FullTime) {
|
||||
setJobType(JobType.Intern);
|
||||
if (jobType === JobType.FULLTIME) {
|
||||
setJobType(JobType.INTERN);
|
||||
append(defaultInternshipOfferValues);
|
||||
} else {
|
||||
setJobType(JobType.FullTime);
|
||||
setJobType(JobType.FULLTIME);
|
||||
append(defaultFullTimeOfferValues);
|
||||
}
|
||||
};
|
||||
|
||||
const switchJobTypeLabel = () =>
|
||||
jobType === JobType.FullTime ? JobTypeLabel.INTERN : JobTypeLabel.FULLTIME;
|
||||
jobType === JobType.FULLTIME ? JobTypeLabel.INTERN : JobTypeLabel.FULLTIME;
|
||||
|
||||
return (
|
||||
<div className="mb-5">
|
||||
@@ -506,9 +512,9 @@ export default function OfferDetailsForm() {
|
||||
display="block"
|
||||
label={JobTypeLabel.FULLTIME}
|
||||
size="md"
|
||||
variant={jobType === JobType.FullTime ? 'secondary' : 'tertiary'}
|
||||
variant={jobType === JobType.FULLTIME ? 'secondary' : 'tertiary'}
|
||||
onClick={() => {
|
||||
if (jobType === JobType.FullTime) {
|
||||
if (jobType === JobType.FULLTIME) {
|
||||
return;
|
||||
}
|
||||
setDialogOpen(true);
|
||||
@@ -520,9 +526,9 @@ export default function OfferDetailsForm() {
|
||||
display="block"
|
||||
label={JobTypeLabel.INTERN}
|
||||
size="md"
|
||||
variant={jobType === JobType.Intern ? 'secondary' : 'tertiary'}
|
||||
variant={jobType === JobType.INTERN ? 'secondary' : 'tertiary'}
|
||||
onClick={() => {
|
||||
if (jobType === JobType.Intern) {
|
||||
if (jobType === JobType.INTERN) {
|
||||
return;
|
||||
}
|
||||
setDialogOpen(true);
|
||||
|
||||
@@ -3,18 +3,10 @@ import {
|
||||
LightBulbIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
|
||||
import type { EducationBackgroundType } from '~/components/offers/types';
|
||||
|
||||
type EducationEntity = {
|
||||
endDate?: string;
|
||||
field?: string;
|
||||
school?: string;
|
||||
startDate?: string;
|
||||
type?: EducationBackgroundType;
|
||||
};
|
||||
import type { EducationDisplayData } from '~/components/offers/types';
|
||||
|
||||
type Props = Readonly<{
|
||||
education: EducationEntity;
|
||||
education: EducationDisplayData;
|
||||
}>;
|
||||
|
||||
export default function EducationCard({
|
||||
@@ -39,9 +31,7 @@ export default function EducationCard({
|
||||
</div>
|
||||
{(startDate || endDate) && (
|
||||
<div className="font-light text-gray-400">
|
||||
<p>{`${startDate ? startDate : 'N/A'} - ${
|
||||
endDate ? endDate : 'N/A'
|
||||
}`}</p>
|
||||
<p>{`${startDate || 'N/A'} - ${endDate || 'N/A'}`}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { HorizontalDivider } from '@tih/ui';
|
||||
|
||||
import type { OfferEntity } from '~/components/offers/types';
|
||||
import type { OfferDisplayData } from '~/components/offers/types';
|
||||
|
||||
type Props = Readonly<{
|
||||
offer: OfferEntity;
|
||||
offer: OfferDisplayData;
|
||||
}>;
|
||||
|
||||
export default function OfferCard({
|
||||
|
||||
@@ -3,13 +3,18 @@ import { Spinner } from '@tih/ui';
|
||||
|
||||
import EducationCard from '~/components/offers/profile/EducationCard';
|
||||
import OfferCard from '~/components/offers/profile/OfferCard';
|
||||
import type { BackgroundCard, OfferEntity } from '~/components/offers/types';
|
||||
import { EducationBackgroundType } from '~/components/offers/types';
|
||||
import type {
|
||||
BackgroundDisplayData,
|
||||
OfferDisplayData,
|
||||
} from '~/components/offers/types';
|
||||
|
||||
import type { ProfileAnalysis } from '~/types/offers';
|
||||
|
||||
type ProfileHeaderProps = Readonly<{
|
||||
background?: BackgroundCard;
|
||||
analysis?: ProfileAnalysis;
|
||||
background?: BackgroundDisplayData;
|
||||
isLoading: boolean;
|
||||
offers: Array<OfferEntity>;
|
||||
offers: Array<OfferDisplayData>;
|
||||
selectedTab: string;
|
||||
}>;
|
||||
|
||||
@@ -52,7 +57,7 @@ export default function ProfileDetails({
|
||||
<BriefcaseIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Work Experience</span>
|
||||
</div>
|
||||
<OfferCard offer={background?.experiences[0]} />
|
||||
<OfferCard offer={background.experiences[0]} />
|
||||
</>
|
||||
)}
|
||||
{background?.educations && background?.educations.length > 0 && (
|
||||
@@ -61,15 +66,7 @@ export default function ProfileDetails({
|
||||
<AcademicCapIcon className="mr-1 h-5" />
|
||||
<span className="font-bold">Education</span>
|
||||
</div>
|
||||
<EducationCard
|
||||
education={{
|
||||
endDate: background.educations[0].endDate,
|
||||
field: background.educations[0].field,
|
||||
school: background.educations[0].school,
|
||||
startDate: background.educations[0].startDate,
|
||||
type: EducationBackgroundType.Bachelor,
|
||||
}}
|
||||
/>
|
||||
<EducationCard education={background.educations[0]} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
BookmarkSquareIcon,
|
||||
BuildingOffice2Icon,
|
||||
CalendarDaysIcon,
|
||||
PencilSquareIcon,
|
||||
@@ -10,12 +9,12 @@ import {
|
||||
import { Button, Dialog, Spinner, Tabs } from '@tih/ui';
|
||||
|
||||
import ProfilePhotoHolder from '~/components/offers/profile/ProfilePhotoHolder';
|
||||
import type { BackgroundCard } from '~/components/offers/types';
|
||||
import type { BackgroundDisplayData } from '~/components/offers/types';
|
||||
|
||||
import { getProfileEditPath } from '~/utils/offers/link';
|
||||
|
||||
type ProfileHeaderProps = Readonly<{
|
||||
background?: BackgroundCard;
|
||||
background?: BackgroundDisplayData;
|
||||
handleDelete: () => void;
|
||||
isEditable: boolean;
|
||||
isLoading: boolean;
|
||||
@@ -42,14 +41,14 @@ export default function ProfileHeader({
|
||||
function renderActionList() {
|
||||
return (
|
||||
<div className="space-x-2">
|
||||
<Button
|
||||
{/* <Button
|
||||
disabled={isLoading}
|
||||
icon={BookmarkSquareIcon}
|
||||
isLabelHidden={true}
|
||||
label="Save to user account"
|
||||
size="md"
|
||||
variant="tertiary"
|
||||
/>
|
||||
/> */}
|
||||
<Button
|
||||
disabled={isLoading}
|
||||
icon={PencilSquareIcon}
|
||||
@@ -109,6 +108,13 @@ export default function ProfileHeader({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!background) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { experiences, totalYoe, specificYoes, profileName } = background;
|
||||
|
||||
return (
|
||||
<div className="h-40 bg-white p-4">
|
||||
<div className="justify-left flex h-1/2">
|
||||
@@ -118,7 +124,7 @@ export default function ProfileHeader({
|
||||
<div className="w-full">
|
||||
<div className="justify-left flex flex-1">
|
||||
<h2 className="flex w-4/5 text-2xl font-bold">
|
||||
{background?.profileName ?? 'anonymous'}
|
||||
{profileName ?? 'anonymous'}
|
||||
</h2>
|
||||
{isEditable && (
|
||||
<div className="flex h-8 w-1/5 justify-end">
|
||||
@@ -126,22 +132,26 @@ export default function ProfileHeader({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<BuildingOffice2Icon className="mr-2.5 h-5" />
|
||||
<span className="mr-2 font-bold">Current:</span>
|
||||
<span>
|
||||
{`${background?.experiences[0]?.companyName ?? '-'} ${
|
||||
background?.experiences[0]?.jobLevel || ''
|
||||
} ${background?.experiences[0]?.jobTitle || ''}`}
|
||||
</span>
|
||||
</div>
|
||||
{(experiences[0]?.companyName ||
|
||||
experiences[0]?.jobLevel ||
|
||||
experiences[0]?.jobTitle) && (
|
||||
<div className="flex flex-row">
|
||||
<BuildingOffice2Icon className="mr-2.5 h-5" />
|
||||
<span className="mr-2 font-bold">Current:</span>
|
||||
<span>
|
||||
{`${experiences[0]?.companyName || ''} ${
|
||||
experiences[0]?.jobLevel || ''
|
||||
} ${experiences[0]?.jobTitle || ''}`}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-row">
|
||||
<CalendarDaysIcon className="mr-2.5 h-5" />
|
||||
<span className="mr-2 font-bold">YOE:</span>
|
||||
<span className="mr-4">{background?.totalYoe}</span>
|
||||
{background?.specificYoes &&
|
||||
background?.specificYoes.length > 0 &&
|
||||
background?.specificYoes.map(({ domain, yoe }) => {
|
||||
<span className="mr-4">{totalYoe}</span>
|
||||
{specificYoes &&
|
||||
specificYoes.length > 0 &&
|
||||
specificYoes.map(({ domain, yoe }) => {
|
||||
return (
|
||||
<span
|
||||
key={domain}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export default function ProfilePhotoHolder() {
|
||||
type ProfilePhotoHolderProps = {
|
||||
size?: 'lg' | 'sm';
|
||||
};
|
||||
|
||||
export default function ProfilePhotoHolder({
|
||||
size = 'lg',
|
||||
}: ProfilePhotoHolderProps) {
|
||||
const sizeMap = { lg: '16', sm: '12' };
|
||||
return (
|
||||
<span className="inline-block h-16 w-16 overflow-hidden rounded-full bg-gray-100">
|
||||
<span
|
||||
className={`inline-block h-${sizeMap[size]} w-${sizeMap[size]} overflow-hidden rounded-full bg-gray-100`}>
|
||||
<svg
|
||||
className="h-full w-full text-gray-300"
|
||||
fill="currentColor"
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import type { JobType } from '@prisma/client';
|
||||
|
||||
import type { MonthYear } from '~/components/shared/MonthYearPicker';
|
||||
|
||||
/*
|
||||
* Offer Profile
|
||||
*/
|
||||
|
||||
export enum JobType {
|
||||
FullTime = 'FULLTIME',
|
||||
Intern = 'INTERN',
|
||||
}
|
||||
|
||||
export const JobTypeLabel = {
|
||||
FULLTIME: 'Full-time',
|
||||
INTERN: 'Internship',
|
||||
@@ -26,17 +23,20 @@ export enum EducationBackgroundType {
|
||||
|
||||
export type OffersProfilePostData = {
|
||||
background: BackgroundPostData;
|
||||
id?: string;
|
||||
offers: Array<OfferPostData>;
|
||||
};
|
||||
|
||||
export type OffersProfileFormData = {
|
||||
background: BackgroundPostData;
|
||||
id?: string;
|
||||
offers: Array<OfferFormData>;
|
||||
};
|
||||
|
||||
export type BackgroundPostData = {
|
||||
educations: Array<EducationPostData>;
|
||||
experiences: Array<ExperiencePostData>;
|
||||
id?: string;
|
||||
specificYoes: Array<SpecificYoePostData>;
|
||||
totalYoe: number;
|
||||
};
|
||||
@@ -44,6 +44,7 @@ export type BackgroundPostData = {
|
||||
type ExperiencePostData = {
|
||||
companyId?: string | null;
|
||||
durationInMonths?: number | null;
|
||||
id?: string;
|
||||
jobType?: string | null;
|
||||
level?: string | null;
|
||||
location?: string | null;
|
||||
@@ -57,6 +58,7 @@ type ExperiencePostData = {
|
||||
type EducationPostData = {
|
||||
endDate?: Date | null;
|
||||
field?: string | null;
|
||||
id?: string;
|
||||
school?: string | null;
|
||||
startDate?: Date | null;
|
||||
type?: string | null;
|
||||
@@ -64,6 +66,7 @@ type EducationPostData = {
|
||||
|
||||
type SpecificYoePostData = {
|
||||
domain: string;
|
||||
id?: string;
|
||||
yoe: number;
|
||||
};
|
||||
|
||||
@@ -72,7 +75,8 @@ type SpecificYoe = SpecificYoePostData;
|
||||
export type OfferPostData = {
|
||||
comments: string;
|
||||
companyId: string;
|
||||
jobType: string;
|
||||
id?: string;
|
||||
jobType: JobType;
|
||||
location: string;
|
||||
monthYearReceived: Date;
|
||||
negotiationStrategy: string;
|
||||
@@ -87,6 +91,7 @@ export type OfferFormData = Omit<OfferPostData, 'monthYearReceived'> & {
|
||||
export type OfferFullTimePostData = {
|
||||
baseSalary: Money;
|
||||
bonus: Money;
|
||||
id?: string;
|
||||
level: string;
|
||||
specialization: string;
|
||||
stocks: Money;
|
||||
@@ -95,6 +100,7 @@ export type OfferFullTimePostData = {
|
||||
};
|
||||
|
||||
export type OfferInternPostData = {
|
||||
id?: string;
|
||||
internshipCycle: string;
|
||||
monthlySalary: Money;
|
||||
specialization: string;
|
||||
@@ -104,40 +110,41 @@ export type OfferInternPostData = {
|
||||
|
||||
export type Money = {
|
||||
currency: string;
|
||||
id?: string;
|
||||
value: number;
|
||||
};
|
||||
|
||||
type EducationDisplay = {
|
||||
endDate?: string;
|
||||
field: string;
|
||||
school: string;
|
||||
startDate?: string;
|
||||
type: string;
|
||||
export type EducationDisplayData = {
|
||||
endDate?: string | null;
|
||||
field?: string | null;
|
||||
school?: string | null;
|
||||
startDate?: string | null;
|
||||
type?: string | null;
|
||||
};
|
||||
|
||||
export type OfferEntity = {
|
||||
base?: string;
|
||||
bonus?: string;
|
||||
companyName?: string;
|
||||
duration?: string;
|
||||
export type OfferDisplayData = {
|
||||
base?: string | null;
|
||||
bonus?: string | null;
|
||||
companyName?: string | null;
|
||||
duration?: number | null;
|
||||
id?: string;
|
||||
jobLevel?: string;
|
||||
jobTitle?: string;
|
||||
location?: string;
|
||||
monthlySalary?: string;
|
||||
negotiationStrategy?: string;
|
||||
otherComment?: string;
|
||||
receivedMonth?: string;
|
||||
stocks?: string;
|
||||
totalCompensation?: string;
|
||||
jobLevel?: string | null;
|
||||
jobTitle?: string | null;
|
||||
location?: string | null;
|
||||
monthlySalary?: string | null;
|
||||
negotiationStrategy?: string | null;
|
||||
otherComment?: string | null;
|
||||
receivedMonth?: string | null;
|
||||
stocks?: string | null;
|
||||
totalCompensation?: string | null;
|
||||
};
|
||||
|
||||
export type BackgroundCard = {
|
||||
educations: Array<EducationDisplay>;
|
||||
experiences: Array<OfferEntity>;
|
||||
export type BackgroundDisplayData = {
|
||||
educations: Array<EducationDisplayData>;
|
||||
experiences: Array<OfferDisplayData>;
|
||||
profileName: string;
|
||||
specificYoes: Array<SpecificYoe>;
|
||||
totalYoe: string;
|
||||
totalYoe: number;
|
||||
};
|
||||
|
||||
export type CommentEntity = {
|
||||
|
||||
Reference in New Issue
Block a user