|
|
|
@ -21,6 +21,7 @@ import {
|
|
|
|
|
} from '~/utils/offers/currency/CurrencyEnum';
|
|
|
|
|
|
|
|
|
|
import FormRadioList from '../../forms/FormRadioList';
|
|
|
|
|
import FormSection from '../../forms/FormSection';
|
|
|
|
|
import FormSelect from '../../forms/FormSelect';
|
|
|
|
|
import FormTextInput from '../../forms/FormTextInput';
|
|
|
|
|
|
|
|
|
@ -29,29 +30,26 @@ function YoeSection() {
|
|
|
|
|
background: BackgroundPostData;
|
|
|
|
|
}>();
|
|
|
|
|
const backgroundFields = formState.errors.background;
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
|
|
|
|
|
Years of Experience (YOE)
|
|
|
|
|
</h6>
|
|
|
|
|
|
|
|
|
|
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
|
|
|
|
|
<div className="mb-2 grid grid-cols-3 space-x-3">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
errorMessage={backgroundFields?.totalYoe?.message}
|
|
|
|
|
label="Total YOE"
|
|
|
|
|
placeholder="0"
|
|
|
|
|
required={true}
|
|
|
|
|
type="number"
|
|
|
|
|
{...register(`background.totalYoe`, {
|
|
|
|
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
|
|
|
|
required: FieldError.REQUIRED,
|
|
|
|
|
valueAsNumber: true,
|
|
|
|
|
})}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Collapsible label="Add specific YOEs by domain">
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
return (
|
|
|
|
|
<FormSection title="Years of Experience (YOE)">
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
errorMessage={backgroundFields?.totalYoe?.message}
|
|
|
|
|
label="Total YOE"
|
|
|
|
|
placeholder="0"
|
|
|
|
|
required={true}
|
|
|
|
|
type="number"
|
|
|
|
|
{...register(`background.totalYoe`, {
|
|
|
|
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
|
|
|
|
required: FieldError.REQUIRED,
|
|
|
|
|
valueAsNumber: true,
|
|
|
|
|
})}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Collapsible label="Add specific YOEs by domain">
|
|
|
|
|
<div className="space-y-4 sm:space-y-6">
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
errorMessage={backgroundFields?.specificYoes?.[0]?.yoe?.message}
|
|
|
|
|
label="Specific YOE 1"
|
|
|
|
@ -63,11 +61,11 @@ function YoeSection() {
|
|
|
|
|
/>
|
|
|
|
|
<FormTextInput
|
|
|
|
|
label="Specific Domain 1"
|
|
|
|
|
placeholder="e.g. Frontend"
|
|
|
|
|
placeholder="e.g. Front End"
|
|
|
|
|
{...register(`background.specificYoes.0.domain`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
errorMessage={backgroundFields?.specificYoes?.[1]?.yoe?.message}
|
|
|
|
|
label="Specific YOE 2"
|
|
|
|
@ -79,13 +77,13 @@ function YoeSection() {
|
|
|
|
|
/>
|
|
|
|
|
<FormTextInput
|
|
|
|
|
label="Specific Domain 2"
|
|
|
|
|
placeholder="e.g. Backend"
|
|
|
|
|
placeholder="e.g. Back End"
|
|
|
|
|
{...register(`background.specificYoes.1.domain`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Collapsible>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
</div>
|
|
|
|
|
</Collapsible>
|
|
|
|
|
</FormSection>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -107,38 +105,34 @@ function FullTimeJobFields() {
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<div>
|
|
|
|
|
<JobTitlesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchJobTitle,
|
|
|
|
|
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
|
|
|
|
|
value: watchJobTitle,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.title', option.value);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<CompaniesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchCompanyId,
|
|
|
|
|
label: watchCompanyName,
|
|
|
|
|
value: watchCompanyId,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.companyId', option.value);
|
|
|
|
|
setValue('background.experiences.0.companyName', option.label);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<JobTitlesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchJobTitle,
|
|
|
|
|
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
|
|
|
|
|
value: watchJobTitle,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.title', option.value);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<CompaniesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchCompanyId,
|
|
|
|
|
label: watchCompanyName,
|
|
|
|
|
value: watchCompanyId,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.companyId', option.value);
|
|
|
|
|
setValue('background.experiences.0.companyName', option.label);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-5 grid grid-cols-1 space-x-3">
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
endAddOn={
|
|
|
|
|
<FormSelect
|
|
|
|
@ -166,7 +160,7 @@ function FullTimeJobFields() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Collapsible label="Add more details">
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-3">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
label="Level"
|
|
|
|
|
placeholder="e.g. L4, Junior"
|
|
|
|
@ -178,8 +172,6 @@ function FullTimeJobFields() {
|
|
|
|
|
options={locationOptions}
|
|
|
|
|
{...register(`background.experiences.0.location`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
errorMessage={experiencesField?.durationInMonths?.message}
|
|
|
|
|
label="Duration (months)"
|
|
|
|
@ -213,72 +205,64 @@ function InternshipJobFields() {
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<div>
|
|
|
|
|
<JobTitlesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchJobTitle,
|
|
|
|
|
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
|
|
|
|
|
value: watchJobTitle,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.title', option.value);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<CompaniesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchCompanyId,
|
|
|
|
|
label: watchCompanyName,
|
|
|
|
|
value: watchCompanyId,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.companyId', option.value);
|
|
|
|
|
setValue('background.experiences.0.companyName', option.label);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-5 grid grid-cols-1 space-x-3">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
endAddOn={
|
|
|
|
|
<FormSelect
|
|
|
|
|
borderStyle="borderless"
|
|
|
|
|
defaultValue={Currency.SGD}
|
|
|
|
|
isLabelHidden={true}
|
|
|
|
|
label="Currency"
|
|
|
|
|
options={CURRENCY_OPTIONS}
|
|
|
|
|
{...register(`background.experiences.0.monthlySalary.currency`)}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
endAddOnType="element"
|
|
|
|
|
errorMessage={experiencesField?.monthlySalary?.value?.message}
|
|
|
|
|
label="Salary (Monthly)"
|
|
|
|
|
placeholder="0.00"
|
|
|
|
|
startAddOn="$"
|
|
|
|
|
startAddOnType="label"
|
|
|
|
|
type="number"
|
|
|
|
|
{...register(`background.experiences.0.monthlySalary.value`, {
|
|
|
|
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
|
|
|
|
valueAsNumber: true,
|
|
|
|
|
})}
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<JobTitlesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchJobTitle,
|
|
|
|
|
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
|
|
|
|
|
value: watchJobTitle,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.title', option.value);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<CompaniesTypeahead
|
|
|
|
|
value={{
|
|
|
|
|
id: watchCompanyId,
|
|
|
|
|
label: watchCompanyName,
|
|
|
|
|
value: watchCompanyId,
|
|
|
|
|
}}
|
|
|
|
|
onSelect={(option) => {
|
|
|
|
|
if (option) {
|
|
|
|
|
setValue('background.experiences.0.companyId', option.value);
|
|
|
|
|
setValue('background.experiences.0.companyName', option.label);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Collapsible label="Add more details">
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
endAddOn={
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Location"
|
|
|
|
|
options={locationOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.experiences.0.location`)}
|
|
|
|
|
borderStyle="borderless"
|
|
|
|
|
defaultValue={Currency.SGD}
|
|
|
|
|
isLabelHidden={true}
|
|
|
|
|
label="Currency"
|
|
|
|
|
options={CURRENCY_OPTIONS}
|
|
|
|
|
{...register(`background.experiences.0.monthlySalary.currency`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
endAddOnType="element"
|
|
|
|
|
errorMessage={experiencesField?.monthlySalary?.value?.message}
|
|
|
|
|
label="Salary (Monthly)"
|
|
|
|
|
placeholder="0.00"
|
|
|
|
|
startAddOn="$"
|
|
|
|
|
startAddOnType="label"
|
|
|
|
|
type="number"
|
|
|
|
|
{...register(`background.experiences.0.monthlySalary.value`, {
|
|
|
|
|
min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 },
|
|
|
|
|
valueAsNumber: true,
|
|
|
|
|
})}
|
|
|
|
|
/>
|
|
|
|
|
<Collapsible label="Add more details">
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Location"
|
|
|
|
|
options={locationOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.experiences.0.location`)}
|
|
|
|
|
/>
|
|
|
|
|
</Collapsible>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
@ -291,85 +275,71 @@ function CurrentJobSection() {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
|
|
|
|
|
Current / Previous Job
|
|
|
|
|
</h6>
|
|
|
|
|
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
|
|
|
|
|
<div className="mb-5">
|
|
|
|
|
<FormRadioList
|
|
|
|
|
defaultValue={watchJobType}
|
|
|
|
|
isLabelHidden={true}
|
|
|
|
|
label="Job Type"
|
|
|
|
|
orientation="horizontal"
|
|
|
|
|
{...register('background.experiences.0.jobType')}>
|
|
|
|
|
<RadioList.Item
|
|
|
|
|
key="Full-time"
|
|
|
|
|
label="Full-time"
|
|
|
|
|
value={JobType.FULLTIME}
|
|
|
|
|
/>
|
|
|
|
|
<RadioList.Item
|
|
|
|
|
key="Internship"
|
|
|
|
|
label="Internship"
|
|
|
|
|
value={JobType.INTERN}
|
|
|
|
|
/>
|
|
|
|
|
</FormRadioList>
|
|
|
|
|
</div>
|
|
|
|
|
{watchJobType === JobType.FULLTIME ? (
|
|
|
|
|
<FullTimeJobFields />
|
|
|
|
|
) : (
|
|
|
|
|
<InternshipJobFields />
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
<FormSection title="Current / Previous Job">
|
|
|
|
|
<FormRadioList
|
|
|
|
|
defaultValue={watchJobType}
|
|
|
|
|
isLabelHidden={true}
|
|
|
|
|
label="Job Type"
|
|
|
|
|
orientation="horizontal"
|
|
|
|
|
{...register('background.experiences.0.jobType')}>
|
|
|
|
|
<RadioList.Item
|
|
|
|
|
key="Full-time"
|
|
|
|
|
label="Full-time"
|
|
|
|
|
value={JobType.FULLTIME}
|
|
|
|
|
/>
|
|
|
|
|
<RadioList.Item
|
|
|
|
|
key="Internship"
|
|
|
|
|
label="Internship"
|
|
|
|
|
value={JobType.INTERN}
|
|
|
|
|
/>
|
|
|
|
|
</FormRadioList>
|
|
|
|
|
{watchJobType === JobType.FULLTIME ? (
|
|
|
|
|
<FullTimeJobFields />
|
|
|
|
|
) : (
|
|
|
|
|
<InternshipJobFields />
|
|
|
|
|
)}
|
|
|
|
|
</FormSection>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function EducationSection() {
|
|
|
|
|
const { register } = useFormContext();
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<h6 className="mb-2 text-left text-xl font-medium text-slate-400">
|
|
|
|
|
Education
|
|
|
|
|
</h6>
|
|
|
|
|
<div className="mb-5 rounded-lg border border-slate-200 px-10 py-5">
|
|
|
|
|
<div className="mb-5 grid grid-cols-2 space-x-3">
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Education Level"
|
|
|
|
|
options={educationLevelOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.educations.0.type`)}
|
|
|
|
|
/>
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Field"
|
|
|
|
|
options={educationFieldOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.educations.0.field`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Collapsible label="Add more details">
|
|
|
|
|
<div className="mb-5">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
label="School"
|
|
|
|
|
placeholder="e.g. National University of Singapore"
|
|
|
|
|
{...register(`background.educations.0.school`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Collapsible>
|
|
|
|
|
<FormSection title="Education">
|
|
|
|
|
<div className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-6">
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Education Level"
|
|
|
|
|
options={educationLevelOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.educations.0.type`)}
|
|
|
|
|
/>
|
|
|
|
|
<FormSelect
|
|
|
|
|
display="block"
|
|
|
|
|
label="Field"
|
|
|
|
|
options={educationFieldOptions}
|
|
|
|
|
placeholder={emptyOption}
|
|
|
|
|
{...register(`background.educations.0.field`)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
<Collapsible label="Add more details">
|
|
|
|
|
<FormTextInput
|
|
|
|
|
label="School"
|
|
|
|
|
placeholder="e.g. National University of Singapore"
|
|
|
|
|
{...register(`background.educations.0.school`)}
|
|
|
|
|
/>
|
|
|
|
|
</Collapsible>
|
|
|
|
|
</FormSection>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function BackgroundForm() {
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<h5 className="mb-8 text-center text-4xl font-bold text-slate-900">
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<h2 className="mb-8 text-2xl font-bold text-slate-900 sm:text-center sm:text-4xl">
|
|
|
|
|
Help us better gauge your offers
|
|
|
|
|
</h5>
|
|
|
|
|
<div>
|
|
|
|
|
</h2>
|
|
|
|
|
<div className="space-y-8 rounded-lg border border-slate-200 p-6 sm:space-y-16 sm:p-8">
|
|
|
|
|
<YoeSection />
|
|
|
|
|
<CurrentJobSection />
|
|
|
|
|
<EducationSection />
|
|
|
|
|