diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx index 63e0148b..07696d77 100644 --- a/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/BackgroundForm.tsx @@ -9,6 +9,7 @@ import { Currency, CURRENCY_OPTIONS, } from '~/utils/offers/currency/CurrencyEnum'; +import { validateNumber } from '~/utils/offers/form'; import { EducationFieldOptions } from '../../EducationFields'; import { EducationLevelOptions } from '../../EducationLevels'; @@ -34,10 +35,11 @@ function YoeSection() { label="Total YOE" placeholder="0" required={true} - type="number" + type="text" {...register(`background.totalYoe`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, required: FieldError.REQUIRED, + validate: validateNumber, valueAsNumber: true, })} /> @@ -48,9 +50,10 @@ function YoeSection() { @@ -64,9 +67,10 @@ function YoeSection() { @@ -119,9 +123,10 @@ function FullTimeJobFields() { placeholder="0.00" startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`background.experiences.0.totalCompensation.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, + validate: validateNumber, valueAsNumber: true, })} /> @@ -142,9 +147,10 @@ function FullTimeJobFields() { @@ -188,9 +194,10 @@ function InternshipJobFields() { placeholder="0.00" startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`background.experiences.0.monthlySalary.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, + validate: validateNumber, valueAsNumber: true, })} /> @@ -205,9 +212,10 @@ function InternshipJobFields() { diff --git a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx index 9b24c5e6..c9a26670 100644 --- a/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx +++ b/apps/portal/src/components/offers/offersSubmission/submissionForm/OfferDetailsForm.tsx @@ -13,6 +13,8 @@ import { TrashIcon } from '@heroicons/react/24/outline'; import { JobType } from '@prisma/client'; import { Button, Dialog, HorizontalDivider } from '@tih/ui'; +import { validateNumber } from '~/utils/offers/form'; + import { defaultFullTimeOfferValues, defaultInternshipOfferValues, @@ -156,12 +158,13 @@ function FullTimeOfferDetailsForm({ required={true} startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register( `offers.${index}.offersFullTime.totalCompensation.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, required: FieldError.REQUIRED, + validate: validateNumber, valueAsNumber: true, }, )} @@ -189,9 +192,10 @@ function FullTimeOfferDetailsForm({ placeholder="0" startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`offers.${index}.offersFullTime.baseSalary.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, + validate: validateNumber, valueAsNumber: true, })} /> @@ -212,9 +216,10 @@ function FullTimeOfferDetailsForm({ placeholder="0" startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`offers.${index}.offersFullTime.bonus.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, + validate: validateNumber, valueAsNumber: true, })} /> @@ -235,9 +240,10 @@ function FullTimeOfferDetailsForm({ placeholder="0" startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`offers.${index}.offersFullTime.stocks.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, + validate: validateNumber, valueAsNumber: true, })} /> @@ -394,10 +400,11 @@ function InternshipOfferDetailsForm({ required={true} startAddOn="$" startAddOnType="label" - type="number" + type="text" {...register(`offers.${index}.offersIntern.monthlySalary.value`, { min: { message: FieldError.NON_NEGATIVE_NUMBER, value: 0 }, required: FieldError.REQUIRED, + validate: validateNumber, valueAsNumber: true, })} /> diff --git a/apps/portal/src/utils/offers/form.tsx b/apps/portal/src/utils/offers/form.tsx index ac03e281..52ee4deb 100644 --- a/apps/portal/src/utils/offers/form.tsx +++ b/apps/portal/src/utils/offers/form.tsx @@ -1,5 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { Validate } from 'react-hook-form'; + +import { FieldError } from '~/components/offers/constants'; + /** * Removes empty objects, empty strings, `null`, `undefined`, and `NaN` values from an object. * Does not remove empty arrays. @@ -85,3 +89,16 @@ export function removeInvalidMoneyData(object: any) { }); return object; } + +/** + * Validation rule for numbers. + * @param value + * @returns `true` if value is a number, otherwise error message. + */ +export const validateNumber: Validate = (value) => { + // Checks for NaN value, as the value passed in by the form is already converted to number pre-validation. + if (value !== value) { + return FieldError.NUMBER; + } + return true; +};