Skip to content

Commit f72a801

Browse files
committed
Inline validation replaced with generic hook on New Vendor modal
1 parent 147c878 commit f72a801

File tree

1 file changed

+40
-78
lines changed
  • Clients/src/presentation/components/Modals/NewVendor

1 file changed

+40
-78
lines changed

Clients/src/presentation/components/Modals/NewVendor/index.tsx

Lines changed: 40 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { HistorySidebar } from "../../Common/HistorySidebar";
3131
import { useEntityChangeHistory } from "../../../../application/hooks/useEntityChangeHistory";
3232
import { useQueryClient } from "@tanstack/react-query";
3333
import { Suspense, useEffect, useMemo, useState } from "react";
34+
import { useFormValidation } from "../../../../application/hooks/useFormValidation";
3435
import dayjs, { Dayjs } from "dayjs";
3536
import Alert from "../../Alert";
3637
import { checkStringValidation } from "../../../../application/validations/stringValidation";
@@ -126,7 +127,40 @@ const AddNewVendor: React.FC<AddNewVendorProps> = ({
126127
}) => {
127128
const theme = useTheme();
128129
const [values, setValues] = useState(initialState);
129-
const [errors, setErrors] = useState<VendorFormErrors>({});
130+
const validators = useMemo(
131+
() => ({
132+
vendorName: (v: unknown) => {
133+
const r = checkStringValidation("Vendor Name", v as string, 1, 64);
134+
return r.accepted ? "" : r.message;
135+
},
136+
website: (v: unknown) => {
137+
const r = checkStringValidation("Vendor Website", v as string, 1, 64);
138+
return r.accepted ? "" : r.message;
139+
},
140+
reviewResult: (v: unknown) => {
141+
if (!v) return "";
142+
const r = checkStringValidation("Vendor review result", v as string, 1, 256);
143+
return r.accepted ? "" : r.message;
144+
},
145+
projectIds: (v: unknown) => {
146+
if (!v || !(Array.isArray(v)) || v.length === 0) {
147+
return "Please select a use case from the dropdown";
148+
}
149+
return "";
150+
},
151+
vendorProvides: (v: unknown) => {
152+
const r = checkStringValidation("Vendor Provides", v as string, 1, 256);
153+
return r.accepted ? "" : r.message;
154+
},
155+
vendorContactPerson: (v: unknown) => {
156+
const r = checkStringValidation("Vendor Contact Person", v as string, 1, 64, undefined, undefined, undefined, undefined, "contactPerson");
157+
return r.accepted ? "" : r.message;
158+
},
159+
assignee: (v: unknown) => (v === null ? "Please select an assignee from the dropdown" : ""),
160+
}),
161+
[]
162+
);
163+
const { errors, validateAll, validateField, clearFieldError, resetErrors } = useFormValidation<typeof initialState>(validators);
130164
const [isSubmitting, setIsSubmitting] = useState(false);
131165
const [projectsLoaded, setProjectsLoaded] = useState(false); // Track if projects are loaded
132166
const [alert, setAlert] = useState<{
@@ -173,9 +207,9 @@ const AddNewVendor: React.FC<AddNewVendorProps> = ({
173207
useEffect(() => {
174208
if (!isOpen) {
175209
setValues(initialState);
176-
setErrors({} as VendorFormErrors);
210+
resetErrors();
177211
}
178-
}, [isOpen]);
212+
}, [isOpen, resetErrors]);
179213

180214
useEffect(() => {
181215
if (isOpen && !projectsLoaded) {
@@ -229,7 +263,7 @@ const AddNewVendor: React.FC<AddNewVendorProps> = ({
229263
* Opens the confirmation modal if form validation passes
230264
*/
231265
const handleSave = () => {
232-
if (validateForm()) {
266+
if (validateAll(values)) {
233267
handleOnSave();
234268
}
235269
};
@@ -253,87 +287,15 @@ const AddNewVendor: React.FC<AddNewVendorProps> = ({
253287
* @param field - The field name to update
254288
* @param value - The new value
255289
*/
256-
const handleOnChange = (field: string, value: string | number | number[]) => {
290+
const handleOnChange = (field: keyof typeof initialState, value: string | number | number[]) => {
257291
setValues((prevValues) => ({
258292
...prevValues,
259293
[field]: value,
260294
}));
261-
setErrors({ ...errors, [field]: "" });
295+
clearFieldError(field);
262296
};
263297

264-
/**
265-
* Validates all required fields in the form
266-
* @returns boolean indicating if form is valid
267-
*/
268-
const validateForm = (): boolean => {
269-
const newErrors: VendorFormErrors = {};
270-
const vendorName = checkStringValidation(
271-
"Vendor Name",
272-
values.vendorName,
273-
1,
274-
64
275-
);
276-
if (!vendorName.accepted) {
277-
newErrors.vendorName = vendorName.message;
278-
}
279-
const vendorWebsite = checkStringValidation(
280-
"Vendor Website",
281-
values.website,
282-
1,
283-
64
284-
);
285-
if (!vendorWebsite.accepted) {
286-
newErrors.website = vendorWebsite.message;
287-
}
288-
// Review result is now optional
289-
if (values.reviewResult) {
290-
const vendorReviewResult = checkStringValidation(
291-
"Vendor review result",
292-
values.reviewResult,
293-
1,
294-
256
295-
);
296-
if (!vendorReviewResult.accepted) {
297-
newErrors.reviewResult = vendorReviewResult.message;
298-
}
299-
}
300-
if (
301-
!values.projectIds ||
302-
Number(values.projectIds.length) === 0
303-
) {
304-
newErrors.projectIds = "Please select a use case from the dropdown";
305-
}
306-
const vendorProvides = checkStringValidation(
307-
"Vendor Provides",
308-
values.vendorProvides,
309-
1,
310-
256
311-
);
312-
if (!vendorProvides.accepted) {
313-
newErrors.vendorProvides = vendorProvides.message;
314-
}
315-
const vendorContactPerson = checkStringValidation(
316-
"Vendor Contact Person",
317-
values.vendorContactPerson,
318-
1,
319-
64,
320-
undefined,
321-
undefined,
322-
undefined,
323-
undefined,
324-
"contactPerson" //
325-
);
326-
if (!vendorContactPerson.accepted) {
327-
newErrors.vendorContactPerson = vendorContactPerson.message;
328-
}
329-
// Review status, reviewer, and review date are now optional
330-
if (values.assignee === null) {
331-
newErrors.assignee = "Please select an assignee from the dropdown";
332-
}
333298

334-
setErrors(newErrors);
335-
return Object.keys(newErrors).length === 0;
336-
};
337299

338300
/**
339301
* Handles the final save operation after confirmation

0 commit comments

Comments
 (0)