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;
+};