[offers][feat] Add error messages for text input fields

pull/366/head
Ai Ling 3 years ago
parent e531899571
commit 1eed5227c4

@ -1,7 +1,6 @@
import type { ProductNavigationItems } from '~/components/global/ProductNavigation'; import type { ProductNavigationItems } from '~/components/global/ProductNavigation';
const navigation: ProductNavigationItems = [ const navigation: ProductNavigationItems = [
{ href: '/offers', name: 'Home' },
{ href: '/offers/submit', name: 'Benchmark your offer' }, { href: '/offers/submit', name: 'Benchmark your offer' },
]; ];

@ -134,3 +134,7 @@ export const educationFieldOptions = [
value: 'Business Analytics', value: 'Business Analytics',
}, },
]; ];
export enum FieldError {
required = 'Please fill in this field.',
}

@ -16,12 +16,16 @@ import FormTextArea from './components/FormTextArea';
import FormTextInput from './components/FormTextInput'; import FormTextInput from './components/FormTextInput';
import { import {
companyOptions, companyOptions,
FieldError,
internshipCycleOptions, internshipCycleOptions,
locationOptions, locationOptions,
titleOptions, titleOptions,
yearOptions, yearOptions,
} from '../constants'; } from '../constants';
import type { OfferDetailsFormData } from '../types'; import type {
FullTimeOfferDetailsFormData,
InternshipOfferDetailsFormData,
} from '../types';
import { JobType } from '../types'; import { JobType } from '../types';
import { CURRENCY_OPTIONS } from '../../../utils/offers/currency/CurrencyEnum'; import { CURRENCY_OPTIONS } from '../../../utils/offers/currency/CurrencyEnum';
@ -34,10 +38,12 @@ function FullTimeOfferDetailsForm({
index, index,
remove, remove,
}: FullTimeOfferDetailsFormProps) { }: FullTimeOfferDetailsFormProps) {
const { register } = useFormContext<{ const { register, formState } = useFormContext<{
offers: Array<OfferDetailsFormData>; offers: Array<FullTimeOfferDetailsFormData>;
}>(); }>();
const jobFields = formState.errors.offers?.[index]?.job;
return ( return (
<div className="my-5 rounded-lg border border-gray-200 px-10 py-5"> <div className="my-5 rounded-lg border border-gray-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">
@ -47,15 +53,16 @@ function FullTimeOfferDetailsForm({
options={titleOptions} options={titleOptions}
required={true} required={true}
{...register(`offers.${index}.job.title`, { {...register(`offers.${index}.job.title`, {
required: true, required: FieldError.required,
})} })}
/> />
<FormTextInput <FormTextInput
errorMessage={jobFields?.specialization?.message}
label="Focus / Specialization" label="Focus / Specialization"
placeholder="e.g. Front End" placeholder="e.g. Front End"
required={true} required={true}
{...register(`offers.${index}.job.specialization`, { {...register(`offers.${index}.job.specialization`, {
required: true, required: FieldError.required,
})} })}
/> />
</div> </div>
@ -65,13 +72,18 @@ function FullTimeOfferDetailsForm({
label="Company" label="Company"
options={companyOptions} options={companyOptions}
required={true} required={true}
{...register(`offers.${index}.companyId`, { required: true })} {...register(`offers.${index}.companyId`, {
required: FieldError.required,
})}
/> />
<FormTextInput <FormTextInput
errorMessage={jobFields?.level?.message}
label="Level" label="Level"
placeholder="e.g. L4, Junior" placeholder="e.g. L4, Junior"
required={true} required={true}
{...register(`offers.${index}.job.level`, { required: true })} {...register(`offers.${index}.job.level`, {
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">
@ -80,10 +92,14 @@ function FullTimeOfferDetailsForm({
label="Location" label="Location"
options={locationOptions} options={locationOptions}
required={true} required={true}
{...register(`offers.${index}.location`, { required: true })} {...register(`offers.${index}.location`, {
required: FieldError.required,
})}
/> />
<FormMonthYearPicker <FormMonthYearPicker
{...register(`offers.${index}.monthYearReceived`, { required: true })} {...register(`offers.${index}.monthYearReceived`, {
required: FieldError.required,
})}
/> />
</div> </div>
<div className="mb-5"> <div className="mb-5">
@ -95,11 +111,12 @@ function FullTimeOfferDetailsForm({
label="Currency" label="Currency"
options={CURRENCY_OPTIONS} options={CURRENCY_OPTIONS}
{...register(`offers.${index}.job.totalCompensation.currency`, { {...register(`offers.${index}.job.totalCompensation.currency`, {
required: true, required: FieldError.required,
})} })}
/> />
} }
endAddOnType="element" endAddOnType="element"
errorMessage={jobFields?.totalCompensation?.value?.message}
label="Total Compensation (Annual)" label="Total Compensation (Annual)"
placeholder="0.00" placeholder="0.00"
required={true} required={true}
@ -107,7 +124,7 @@ function FullTimeOfferDetailsForm({
startAddOnType="label" startAddOnType="label"
type="number" type="number"
{...register(`offers.${index}.job.totalCompensation.value`, { {...register(`offers.${index}.job.totalCompensation.value`, {
required: true, required: FieldError.required,
valueAsNumber: true, valueAsNumber: true,
})} })}
/> />
@ -121,11 +138,12 @@ function FullTimeOfferDetailsForm({
label="Currency" label="Currency"
options={CURRENCY_OPTIONS} options={CURRENCY_OPTIONS}
{...register(`offers.${index}.job.base.currency`, { {...register(`offers.${index}.job.base.currency`, {
required: true, required: FieldError.required,
})} })}
/> />
} }
endAddOnType="element" endAddOnType="element"
errorMessage={jobFields?.base?.value?.message}
label="Base Salary (Annual)" label="Base Salary (Annual)"
placeholder="0.00" placeholder="0.00"
required={true} required={true}
@ -133,7 +151,7 @@ function FullTimeOfferDetailsForm({
startAddOnType="label" startAddOnType="label"
type="number" type="number"
{...register(`offers.${index}.job.base.value`, { {...register(`offers.${index}.job.base.value`, {
required: true, required: FieldError.required,
valueAsNumber: true, valueAsNumber: true,
})} })}
/> />
@ -145,11 +163,12 @@ function FullTimeOfferDetailsForm({
label="Currency" label="Currency"
options={CURRENCY_OPTIONS} options={CURRENCY_OPTIONS}
{...register(`offers.${index}.job.bonus.currency`, { {...register(`offers.${index}.job.bonus.currency`, {
required: true, required: FieldError.required,
})} })}
/> />
} }
endAddOnType="element" endAddOnType="element"
errorMessage={jobFields?.bonus?.value?.message}
label="Bonus (Annual)" label="Bonus (Annual)"
placeholder="0.00" placeholder="0.00"
required={true} required={true}
@ -157,7 +176,7 @@ function FullTimeOfferDetailsForm({
startAddOnType="label" startAddOnType="label"
type="number" type="number"
{...register(`offers.${index}.job.bonus.value`, { {...register(`offers.${index}.job.bonus.value`, {
required: true, required: FieldError.required,
valueAsNumber: true, valueAsNumber: true,
})} })}
/> />
@ -171,11 +190,12 @@ function FullTimeOfferDetailsForm({
label="Currency" label="Currency"
options={CURRENCY_OPTIONS} options={CURRENCY_OPTIONS}
{...register(`offers.${index}.job.stocks.currency`, { {...register(`offers.${index}.job.stocks.currency`, {
required: true, required: FieldError.required,
})} })}
/> />
} }
endAddOnType="element" endAddOnType="element"
errorMessage={jobFields?.stocks?.value?.message}
label="Stocks (Annual)" label="Stocks (Annual)"
placeholder="0.00" placeholder="0.00"
required={true} required={true}
@ -183,7 +203,7 @@ function FullTimeOfferDetailsForm({
startAddOnType="label" startAddOnType="label"
type="number" type="number"
{...register(`offers.${index}.job.stocks.value`, { {...register(`offers.${index}.job.stocks.value`, {
required: true, required: FieldError.required,
valueAsNumber: true, valueAsNumber: true,
})} })}
/> />
@ -264,10 +284,12 @@ function InternshipOfferDetailsForm({
index, index,
remove, remove,
}: InternshipOfferDetailsFormProps) { }: InternshipOfferDetailsFormProps) {
const { register } = useFormContext<{ const { register, formState } = useFormContext<{
offers: Array<OfferDetailsFormData>; offers: Array<InternshipOfferDetailsFormData>;
}>(); }>();
const jobFields = formState.errors.offers?.[index]?.job;
return ( return (
<div className="my-5 rounded-lg border border-gray-200 px-10 py-5"> <div className="my-5 rounded-lg border border-gray-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">
@ -278,16 +300,17 @@ function InternshipOfferDetailsForm({
required={true} required={true}
{...register(`offers.${index}.job.title`, { {...register(`offers.${index}.job.title`, {
minLength: 1, minLength: 1,
required: true, required: FieldError.required,
})} })}
/> />
<FormTextInput <FormTextInput
errorMessage={jobFields?.specialization?.message}
label="Focus / Specialization" label="Focus / Specialization"
placeholder="e.g. Front End" placeholder="e.g. Front End"
required={true} required={true}
{...register(`offers.${index}.job.specialization`, { {...register(`offers.${index}.job.specialization`, {
minLength: 1, minLength: 1,
required: true, required: FieldError.required,
})} })}
/> />
</div> </div>
@ -298,7 +321,7 @@ function InternshipOfferDetailsForm({
options={companyOptions} options={companyOptions}
required={true} required={true}
{...register(`offers.${index}.companyId`, { {...register(`offers.${index}.companyId`, {
required: true, required: FieldError.required,
})} })}
/> />
<FormSelect <FormSelect
@ -307,7 +330,7 @@ function InternshipOfferDetailsForm({
options={locationOptions} options={locationOptions}
required={true} required={true}
{...register(`offers.${index}.location`, { {...register(`offers.${index}.location`, {
required: true, required: FieldError.required,
})} })}
/> />
</div> </div>
@ -318,7 +341,7 @@ function InternshipOfferDetailsForm({
options={internshipCycleOptions} options={internshipCycleOptions}
required={true} required={true}
{...register(`offers.${index}.job.internshipCycle`, { {...register(`offers.${index}.job.internshipCycle`, {
required: true, required: FieldError.required,
})} })}
/> />
<FormSelect <FormSelect
@ -327,14 +350,16 @@ function InternshipOfferDetailsForm({
options={yearOptions} options={yearOptions}
required={true} required={true}
{...register(`offers.${index}.job.startYear`, { {...register(`offers.${index}.job.startYear`, {
required: true, required: FieldError.required,
})} })}
/> />
</div> </div>
<div className="mb-5 flex items-center space-x-9"> <div className="mb-5 flex items-center space-x-9">
<p className="text-sm">Date received:</p> <p className="text-sm">Date received:</p>
<FormMonthYearPicker <FormMonthYearPicker
{...register(`offers.${index}.monthYearReceived`, { required: true })} {...register(`offers.${index}.monthYearReceived`, {
required: FieldError.required,
})}
/> />
</div> </div>
<div className="mb-5"> <div className="mb-5">
@ -346,11 +371,12 @@ function InternshipOfferDetailsForm({
label="Currency" label="Currency"
options={CURRENCY_OPTIONS} options={CURRENCY_OPTIONS}
{...register(`offers.${index}.job.monthlySalary.currency`, { {...register(`offers.${index}.job.monthlySalary.currency`, {
required: true, required: FieldError.required,
})} })}
/> />
} }
endAddOnType="element" endAddOnType="element"
errorMessage={jobFields?.monthlySalary?.value?.message}
label="Salary (Monthly)" label="Salary (Monthly)"
placeholder="0.00" placeholder="0.00"
required={true} required={true}
@ -358,7 +384,7 @@ function InternshipOfferDetailsForm({
startAddOnType="label" startAddOnType="label"
type="number" type="number"
{...register(`offers.${index}.job.monthlySalary.value`, { {...register(`offers.${index}.job.monthlySalary.value`, {
required: true, required: FieldError.required,
valueAsNumber: true, valueAsNumber: true,
})} })}
/> />

@ -43,16 +43,27 @@ type InternshipJobData = {
title: string; title: string;
}; };
export type OfferDetailsFormData = { type OfferDetailsGeneralData = {
comments: string; comments: string;
companyId: string; companyId: string;
job: FullTimeJobData | InternshipJobData;
jobType: string; jobType: string;
location: string; location: string;
monthYearReceived: MonthYear; monthYearReceived: MonthYear;
negotiationStrategy: string; negotiationStrategy: string;
}; };
export type FullTimeOfferDetailsFormData = OfferDetailsGeneralData & {
job: FullTimeJobData;
};
export type InternshipOfferDetailsFormData = OfferDetailsGeneralData & {
job: InternshipJobData;
};
export type OfferDetailsFormData =
| FullTimeOfferDetailsFormData
| InternshipOfferDetailsFormData;
export type OfferDetailsPostData = Omit< export type OfferDetailsPostData = Omit<
OfferDetailsFormData, OfferDetailsFormData,
'monthYearReceived' 'monthYearReceived'

Loading…
Cancel
Save