mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[offers][fix] Use title typeahead, add default currency and remove specialization field (#423)
This commit is contained in:
@ -2,26 +2,6 @@ import { EducationBackgroundType } from './types';
|
|||||||
|
|
||||||
export const emptyOption = '----';
|
export const emptyOption = '----';
|
||||||
|
|
||||||
// TODO: use enums
|
|
||||||
export const titleOptions = [
|
|
||||||
{
|
|
||||||
label: 'Software Engineer',
|
|
||||||
value: 'Software Engineer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Frontend Engineer',
|
|
||||||
value: 'Frontend Engineer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Backend Engineer',
|
|
||||||
value: 'Backend Engineer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Full-stack Engineer',
|
|
||||||
value: 'Full-stack Engineer',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const locationOptions = [
|
export const locationOptions = [
|
||||||
{
|
{
|
||||||
label: 'Singapore, Singapore',
|
label: 'Singapore, Singapore',
|
||||||
|
@ -115,7 +115,7 @@ export default function OffersSubmissionForm({
|
|||||||
),
|
),
|
||||||
hasNext: true,
|
hasNext: true,
|
||||||
hasPrevious: false,
|
hasPrevious: false,
|
||||||
label: 'Offer details',
|
label: 'Offers',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: <BackgroundForm key={1} />,
|
component: <BackgroundForm key={1} />,
|
||||||
@ -123,30 +123,35 @@ export default function OffersSubmissionForm({
|
|||||||
hasPrevious: true,
|
hasPrevious: true,
|
||||||
label: 'Background',
|
label: 'Background',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
component: (
|
|
||||||
<OfferAnalysis
|
|
||||||
key={2}
|
|
||||||
allAnalysis={analysis}
|
|
||||||
isError={generateAnalysisMutation.isError}
|
|
||||||
isLoading={generateAnalysisMutation.isLoading}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
hasNext: true,
|
|
||||||
hasPrevious: false,
|
|
||||||
label: 'Analysis',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
component: (
|
component: (
|
||||||
<OffersProfileSave
|
<OffersProfileSave
|
||||||
key={3}
|
key={2}
|
||||||
profileId={createProfileResponse.id || ''}
|
profileId={createProfileResponse.id || ''}
|
||||||
token={createProfileResponse.token}
|
token={createProfileResponse.token}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
hasNext: false,
|
hasNext: true,
|
||||||
hasPrevious: false,
|
hasPrevious: false,
|
||||||
label: 'Save',
|
label: 'Save profile',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: (
|
||||||
|
<div>
|
||||||
|
<h5 className="mb-8 text-center text-4xl font-bold text-slate-900">
|
||||||
|
Result
|
||||||
|
</h5>
|
||||||
|
<OfferAnalysis
|
||||||
|
key={3}
|
||||||
|
allAnalysis={analysis}
|
||||||
|
isError={generateAnalysisMutation.isError}
|
||||||
|
isLoading={generateAnalysisMutation.isLoading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
hasNext: false,
|
||||||
|
hasPrevious: true,
|
||||||
|
label: 'Analysis',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -231,7 +236,7 @@ export default function OffersSubmissionForm({
|
|||||||
<FormProvider {...formMethods}>
|
<FormProvider {...formMethods}>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
{formSteps[formStep].component}
|
{formSteps[formStep].component}
|
||||||
{/* <pre>{JSON.stringify(formMethods.watch(), null, 2)}</pre> */}
|
<pre>{JSON.stringify(formMethods.watch(), null, 2)}</pre>
|
||||||
{formSteps[formStep].hasNext && (
|
{formSteps[formStep].hasNext && (
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
|
@ -8,13 +8,17 @@ import {
|
|||||||
emptyOption,
|
emptyOption,
|
||||||
FieldError,
|
FieldError,
|
||||||
locationOptions,
|
locationOptions,
|
||||||
titleOptions,
|
|
||||||
} from '~/components/offers/constants';
|
} from '~/components/offers/constants';
|
||||||
import type { BackgroundPostData } from '~/components/offers/types';
|
import type { BackgroundPostData } from '~/components/offers/types';
|
||||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||||
|
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
|
||||||
|
|
||||||
import { CURRENCY_OPTIONS } from '~/utils/offers/currency/CurrencyEnum';
|
import {
|
||||||
|
Currency,
|
||||||
|
CURRENCY_OPTIONS,
|
||||||
|
} from '~/utils/offers/currency/CurrencyEnum';
|
||||||
|
|
||||||
|
import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
|
||||||
import FormRadioList from '../../forms/FormRadioList';
|
import FormRadioList from '../../forms/FormRadioList';
|
||||||
import FormSelect from '../../forms/FormSelect';
|
import FormSelect from '../../forms/FormSelect';
|
||||||
import FormTextInput from '../../forms/FormTextInput';
|
import FormTextInput from '../../forms/FormTextInput';
|
||||||
@ -92,13 +96,13 @@ function FullTimeJobFields() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-5 grid grid-cols-2 space-x-3">
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
||||||
<FormSelect
|
<div>
|
||||||
display="block"
|
<JobTitlesTypeahead
|
||||||
label="Title"
|
onSelect={({ value }) =>
|
||||||
options={titleOptions}
|
setValue(`background.experiences.0.title`, value)
|
||||||
placeholder={emptyOption}
|
}
|
||||||
{...register(`background.experiences.0.title`)}
|
/>
|
||||||
/>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CompaniesTypeahead
|
<CompaniesTypeahead
|
||||||
onSelect={({ value }) =>
|
onSelect={({ value }) =>
|
||||||
@ -112,6 +116,7 @@ function FullTimeJobFields() {
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
@ -177,13 +182,13 @@ function InternshipJobFields() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-5 grid grid-cols-2 space-x-3">
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
||||||
<FormSelect
|
<div>
|
||||||
display="block"
|
<JobTitlesTypeahead
|
||||||
label="Title"
|
onSelect={({ value }) =>
|
||||||
options={titleOptions}
|
setValue(`background.experiences.0.title`, value)
|
||||||
placeholder={emptyOption}
|
}
|
||||||
{...register(`background.experiences.0.title`)}
|
/>
|
||||||
/>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CompaniesTypeahead
|
<CompaniesTypeahead
|
||||||
onSelect={({ value }) =>
|
onSelect={({ value }) =>
|
||||||
@ -197,6 +202,7 @@ function InternshipJobFields() {
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
@ -310,6 +316,22 @@ function EducationSection() {
|
|||||||
{...register(`background.educations.0.school`)}
|
{...register(`background.educations.0.school`)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="grid grid-cols-2 space-x-3">
|
||||||
|
<FormMonthYearPicker
|
||||||
|
monthLabel="Candidature Start"
|
||||||
|
yearLabel=""
|
||||||
|
{...register(`background.educations.0.startDate`, {
|
||||||
|
required: FieldError.REQUIRED,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<FormMonthYearPicker
|
||||||
|
monthLabel="Candidature End"
|
||||||
|
yearLabel=""
|
||||||
|
{...register(`background.educations.0.endDate`, {
|
||||||
|
required: FieldError.REQUIRED,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -319,13 +341,9 @@ function EducationSection() {
|
|||||||
export default function BackgroundForm() {
|
export default function BackgroundForm() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h5 className="mb-2 text-center text-4xl font-bold text-slate-900">
|
<h5 className="mb-8 text-center text-4xl font-bold text-slate-900">
|
||||||
Help us better gauge your offers
|
Help us better gauge your offers
|
||||||
</h5>
|
</h5>
|
||||||
<h6 className="text-md mx-10 mb-8 text-center font-light text-slate-600">
|
|
||||||
This section is mostly optional, but your background information helps
|
|
||||||
us benchmark your offers.
|
|
||||||
</h6>
|
|
||||||
<div>
|
<div>
|
||||||
<YoeSection />
|
<YoeSection />
|
||||||
<CurrentJobSection />
|
<CurrentJobSection />
|
||||||
|
@ -13,6 +13,7 @@ import { JobType } from '@prisma/client';
|
|||||||
import { Button, Dialog } from '@tih/ui';
|
import { Button, Dialog } from '@tih/ui';
|
||||||
|
|
||||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||||
|
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defaultFullTimeOfferValues,
|
defaultFullTimeOfferValues,
|
||||||
@ -23,7 +24,6 @@ import {
|
|||||||
FieldError,
|
FieldError,
|
||||||
internshipCycleOptions,
|
internshipCycleOptions,
|
||||||
locationOptions,
|
locationOptions,
|
||||||
titleOptions,
|
|
||||||
yearOptions,
|
yearOptions,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
|
import FormMonthYearPicker from '../../forms/FormMonthYearPicker';
|
||||||
@ -32,7 +32,10 @@ import FormTextArea from '../../forms/FormTextArea';
|
|||||||
import FormTextInput from '../../forms/FormTextInput';
|
import FormTextInput from '../../forms/FormTextInput';
|
||||||
import type { OfferFormData } from '../../types';
|
import type { OfferFormData } from '../../types';
|
||||||
import { JobTypeLabel } from '../../types';
|
import { JobTypeLabel } from '../../types';
|
||||||
import { CURRENCY_OPTIONS } from '../../../../utils/offers/currency/CurrencyEnum';
|
import {
|
||||||
|
Currency,
|
||||||
|
CURRENCY_OPTIONS,
|
||||||
|
} from '../../../../utils/offers/currency/CurrencyEnum';
|
||||||
|
|
||||||
type FullTimeOfferDetailsFormProps = Readonly<{
|
type FullTimeOfferDetailsFormProps = Readonly<{
|
||||||
index: number;
|
index: number;
|
||||||
@ -64,32 +67,11 @@ function FullTimeOfferDetailsForm({
|
|||||||
return (
|
return (
|
||||||
<div className="my-5 rounded-lg border border-slate-200 px-10 py-5">
|
<div className="my-5 rounded-lg border border-slate-200 px-10 py-5">
|
||||||
<div className="mb-5 grid grid-cols-2 space-x-3">
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
||||||
<FormSelect
|
|
||||||
display="block"
|
|
||||||
errorMessage={offerFields?.offersFullTime?.title?.message}
|
|
||||||
label="Title"
|
|
||||||
options={titleOptions}
|
|
||||||
placeholder={emptyOption}
|
|
||||||
required={true}
|
|
||||||
{...register(`offers.${index}.offersFullTime.title`, {
|
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormTextInput
|
|
||||||
errorMessage={offerFields?.offersFullTime?.specialization?.message}
|
|
||||||
label="Focus / Specialization"
|
|
||||||
placeholder="e.g. Front End"
|
|
||||||
required={true}
|
|
||||||
{...register(`offers.${index}.offersFullTime.specialization`, {
|
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-5 flex grid grid-cols-2 space-x-3">
|
|
||||||
<div>
|
<div>
|
||||||
<CompaniesTypeahead
|
<JobTitlesTypeahead
|
||||||
|
required={true}
|
||||||
onSelect={({ value }) =>
|
onSelect={({ value }) =>
|
||||||
setValue(`offers.${index}.companyId`, value)
|
setValue(`offers.${index}.offersFullTime.title`, value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -103,7 +85,15 @@ function FullTimeOfferDetailsForm({
|
|||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-5 flex grid grid-cols-2 items-start space-x-3">
|
<div className="mb-5 flex grid grid-cols-2 space-x-3">
|
||||||
|
<div>
|
||||||
|
<CompaniesTypeahead
|
||||||
|
required={true}
|
||||||
|
onSelect={({ value }) =>
|
||||||
|
setValue(`offers.${index}.companyId`, value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<FormSelect
|
<FormSelect
|
||||||
display="block"
|
display="block"
|
||||||
errorMessage={offerFields?.location?.message}
|
errorMessage={offerFields?.location?.message}
|
||||||
@ -115,6 +105,8 @@ function FullTimeOfferDetailsForm({
|
|||||||
required: FieldError.REQUIRED,
|
required: FieldError.REQUIRED,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-5 flex grid grid-cols-2 items-start space-x-3">
|
||||||
<FormMonthYearPicker
|
<FormMonthYearPicker
|
||||||
monthLabel="Date Received"
|
monthLabel="Date Received"
|
||||||
monthRequired={true}
|
monthRequired={true}
|
||||||
@ -129,6 +121,7 @@ function FullTimeOfferDetailsForm({
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
@ -165,14 +158,12 @@ function FullTimeOfferDetailsForm({
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
{...register(
|
{...register(
|
||||||
`offers.${index}.offersFullTime.baseSalary.currency`,
|
`offers.${index}.offersFullTime.baseSalary.currency`,
|
||||||
{
|
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
},
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -180,13 +171,11 @@ function FullTimeOfferDetailsForm({
|
|||||||
errorMessage={offerFields?.offersFullTime?.baseSalary?.value?.message}
|
errorMessage={offerFields?.offersFullTime?.baseSalary?.value?.message}
|
||||||
label="Base Salary (Annual)"
|
label="Base Salary (Annual)"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
required={true}
|
|
||||||
startAddOn="$"
|
startAddOn="$"
|
||||||
startAddOnType="label"
|
startAddOnType="label"
|
||||||
type="number"
|
type="number"
|
||||||
{...register(`offers.${index}.offersFullTime.baseSalary.value`, {
|
{...register(`offers.${index}.offersFullTime.baseSalary.value`, {
|
||||||
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@ -194,25 +183,22 @@ function FullTimeOfferDetailsForm({
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
{...register(`offers.${index}.offersFullTime.bonus.currency`, {
|
{...register(`offers.${index}.offersFullTime.bonus.currency`)}
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
endAddOnType="element"
|
endAddOnType="element"
|
||||||
errorMessage={offerFields?.offersFullTime?.bonus?.value?.message}
|
errorMessage={offerFields?.offersFullTime?.bonus?.value?.message}
|
||||||
label="Bonus (Annual)"
|
label="Bonus (Annual)"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
required={true}
|
|
||||||
startAddOn="$"
|
startAddOn="$"
|
||||||
startAddOnType="label"
|
startAddOnType="label"
|
||||||
type="number"
|
type="number"
|
||||||
{...register(`offers.${index}.offersFullTime.bonus.value`, {
|
{...register(`offers.${index}.offersFullTime.bonus.value`, {
|
||||||
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@ -222,25 +208,22 @@ function FullTimeOfferDetailsForm({
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
{...register(`offers.${index}.offersFullTime.stocks.currency`, {
|
{...register(`offers.${index}.offersFullTime.stocks.currency`)}
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
endAddOnType="element"
|
endAddOnType="element"
|
||||||
errorMessage={offerFields?.offersFullTime?.stocks?.value?.message}
|
errorMessage={offerFields?.offersFullTime?.stocks?.value?.message}
|
||||||
label="Stocks (Annual)"
|
label="Stocks (Annual)"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
required={true}
|
|
||||||
startAddOn="$"
|
startAddOn="$"
|
||||||
startAddOnType="label"
|
startAddOnType="label"
|
||||||
type="number"
|
type="number"
|
||||||
{...register(`offers.${index}.offersFullTime.stocks.value`, {
|
{...register(`offers.${index}.offersFullTime.stocks.value`, {
|
||||||
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@ -291,32 +274,19 @@ function InternshipOfferDetailsForm({
|
|||||||
return (
|
return (
|
||||||
<div className="my-5 rounded-lg border border-slate-200 px-10 py-5">
|
<div className="my-5 rounded-lg border border-slate-200 px-10 py-5">
|
||||||
<div className="mb-5 grid grid-cols-2 space-x-3">
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
||||||
<FormSelect
|
<div>
|
||||||
display="block"
|
<JobTitlesTypeahead
|
||||||
errorMessage={offerFields?.offersIntern?.title?.message}
|
required={true}
|
||||||
label="Title"
|
onSelect={({ value }) =>
|
||||||
options={titleOptions}
|
setValue(`offers.${index}.offersIntern.title`, value)
|
||||||
placeholder={emptyOption}
|
}
|
||||||
required={true}
|
/>
|
||||||
{...register(`offers.${index}.offersIntern.title`, {
|
</div>
|
||||||
minLength: 1,
|
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormTextInput
|
|
||||||
errorMessage={offerFields?.offersIntern?.specialization?.message}
|
|
||||||
label="Focus / Specialization"
|
|
||||||
placeholder="e.g. Front End"
|
|
||||||
required={true}
|
|
||||||
{...register(`offers.${index}.offersIntern.specialization`, {
|
|
||||||
minLength: 1,
|
|
||||||
required: FieldError.REQUIRED,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-5 grid grid-cols-2 space-x-3">
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
||||||
<div>
|
<div>
|
||||||
<CompaniesTypeahead
|
<CompaniesTypeahead
|
||||||
|
required={true}
|
||||||
onSelect={({ value }) =>
|
onSelect={({ value }) =>
|
||||||
setValue(`offers.${index}.companyId`, value)
|
setValue(`offers.${index}.companyId`, value)
|
||||||
}
|
}
|
||||||
@ -374,6 +344,7 @@ function InternshipOfferDetailsForm({
|
|||||||
endAddOn={
|
endAddOn={
|
||||||
<FormSelect
|
<FormSelect
|
||||||
borderStyle="borderless"
|
borderStyle="borderless"
|
||||||
|
defaultValue={Currency.SGD}
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Currency"
|
label="Currency"
|
||||||
options={CURRENCY_OPTIONS}
|
options={CURRENCY_OPTIONS}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
import type { JobTitleType } from '~/components/shared/JobTitles';
|
||||||
|
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
|
||||||
|
|
||||||
import { convertMoneyToString } from '~/utils/offers/currency';
|
import { convertMoneyToString } from '~/utils/offers/currency';
|
||||||
import { formatDate } from '~/utils/offers/time';
|
import { formatDate } from '~/utils/offers/time';
|
||||||
|
|
||||||
@ -19,7 +22,9 @@ export default function OfferTableRow({
|
|||||||
scope="row">
|
scope="row">
|
||||||
{company.name}
|
{company.name}
|
||||||
</th>
|
</th>
|
||||||
<td className="py-4 px-6">{title}</td>
|
<td className="py-4 px-6">
|
||||||
|
{getLabelForJobTitleType(title as JobTitleType)}
|
||||||
|
</td>
|
||||||
<td className="py-4 px-6">{totalYoe}</td>
|
<td className="py-4 px-6">{totalYoe}</td>
|
||||||
<td className="py-4 px-6">{convertMoneyToString(income)}</td>
|
<td className="py-4 px-6">{convertMoneyToString(income)}</td>
|
||||||
<td className="py-4 px-6">{formatDate(monthYearReceived)}</td>
|
<td className="py-4 px-6">{formatDate(monthYearReceived)}</td>
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Select } from '@tih/ui';
|
|
||||||
|
|
||||||
import { titleOptions } from '~/components/offers/constants';
|
|
||||||
import OffersTitle from '~/components/offers/OffersTitle';
|
import OffersTitle from '~/components/offers/OffersTitle';
|
||||||
import OffersTable from '~/components/offers/table/OffersTable';
|
import OffersTable from '~/components/offers/table/OffersTable';
|
||||||
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
|
||||||
|
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
|
||||||
|
|
||||||
export default function OffersHomePage() {
|
export default function OffersHomePage() {
|
||||||
const [jobTitleFilter, setjobTitleFilter] = useState('Software Engineer');
|
const [jobTitleFilter, setjobTitleFilter] = useState('software-engineer');
|
||||||
const [companyFilter, setCompanyFilter] = useState('');
|
const [companyFilter, setCompanyFilter] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,19 +17,17 @@ export default function OffersHomePage() {
|
|||||||
<div className="mt-4 flex items-center">
|
<div className="mt-4 flex items-center">
|
||||||
Viewing offers for
|
Viewing offers for
|
||||||
<div className="mx-4">
|
<div className="mx-4">
|
||||||
<Select
|
<JobTitlesTypeahead
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Select a job title"
|
placeHolder="Software Engineer"
|
||||||
options={titleOptions}
|
onSelect={({ value }) => setjobTitleFilter(value)}
|
||||||
value={jobTitleFilter}
|
|
||||||
onChange={setjobTitleFilter}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
in
|
in
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<CompaniesTypeahead
|
<CompaniesTypeahead
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
placeHolder="All companies"
|
placeHolder="All Companies"
|
||||||
onSelect={({ value }) => setCompanyFilter(value)}
|
onSelect={({ value }) => setCompanyFilter(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,8 @@ import type {
|
|||||||
BackgroundDisplayData,
|
BackgroundDisplayData,
|
||||||
OfferDisplayData,
|
OfferDisplayData,
|
||||||
} from '~/components/offers/types';
|
} from '~/components/offers/types';
|
||||||
|
import type { JobTitleType } from '~/components/shared/JobTitles';
|
||||||
|
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
|
||||||
|
|
||||||
import { useToast } from '~/../../../packages/ui/dist';
|
import { useToast } from '~/../../../packages/ui/dist';
|
||||||
import { convertMoneyToString } from '~/utils/offers/currency';
|
import { convertMoneyToString } from '~/utils/offers/currency';
|
||||||
@ -62,7 +64,9 @@ export default function OfferProfile() {
|
|||||||
companyName: res.company.name,
|
companyName: res.company.name,
|
||||||
id: res.offersFullTime.id,
|
id: res.offersFullTime.id,
|
||||||
jobLevel: res.offersFullTime.level,
|
jobLevel: res.offersFullTime.level,
|
||||||
jobTitle: res.offersFullTime.title,
|
jobTitle: getLabelForJobTitleType(
|
||||||
|
res.offersFullTime.title as JobTitleType,
|
||||||
|
),
|
||||||
location: res.location,
|
location: res.location,
|
||||||
negotiationStrategy: res.negotiationStrategy,
|
negotiationStrategy: res.negotiationStrategy,
|
||||||
otherComment: res.comments,
|
otherComment: res.comments,
|
||||||
@ -77,7 +81,9 @@ export default function OfferProfile() {
|
|||||||
const filteredOffer: OfferDisplayData = {
|
const filteredOffer: OfferDisplayData = {
|
||||||
companyName: res.company.name,
|
companyName: res.company.name,
|
||||||
id: res.offersIntern!.id,
|
id: res.offersIntern!.id,
|
||||||
jobTitle: res.offersIntern!.title,
|
jobTitle: getLabelForJobTitleType(
|
||||||
|
res.offersIntern!.title as JobTitleType,
|
||||||
|
),
|
||||||
location: res.location,
|
location: res.location,
|
||||||
monthlySalary: convertMoneyToString(
|
monthlySalary: convertMoneyToString(
|
||||||
res.offersIntern!.monthlySalary,
|
res.offersIntern!.monthlySalary,
|
||||||
@ -107,7 +113,9 @@ export default function OfferProfile() {
|
|||||||
companyName: experience.company?.name,
|
companyName: experience.company?.name,
|
||||||
duration: experience.durationInMonths,
|
duration: experience.durationInMonths,
|
||||||
jobLevel: experience.level,
|
jobLevel: experience.level,
|
||||||
jobTitle: experience.title,
|
jobTitle: experience.title
|
||||||
|
? getLabelForJobTitleType(experience.title as JobTitleType)
|
||||||
|
: null,
|
||||||
monthlySalary: experience.monthlySalary
|
monthlySalary: experience.monthlySalary
|
||||||
? convertMoneyToString(experience.monthlySalary)
|
? convertMoneyToString(experience.monthlySalary)
|
||||||
: null,
|
: null,
|
||||||
|
Reference in New Issue
Block a user