@@ -31,6 +31,7 @@ import { HistorySidebar } from "../../Common/HistorySidebar";
3131import { useEntityChangeHistory } from "../../../../application/hooks/useEntityChangeHistory" ;
3232import { useQueryClient } from "@tanstack/react-query" ;
3333import { Suspense , useEffect , useMemo , useState } from "react" ;
34+ import { useFormValidation } from "../../../../application/hooks/useFormValidation" ;
3435import dayjs , { Dayjs } from "dayjs" ;
3536import Alert from "../../Alert" ;
3637import { 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