import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useMemo, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { z, ZodSchema } from "zod";
const useFormHandler =<T extends ZodSchema> (formSchema:T,defaultValues:z.infer<T>) => {
type SchemaType = z.infer<T>
const [isInputChanged,setIsInputChanged]=useState(false)
const [addValues,setAddValues]=useState<Partial<z.infer<T>>>({})
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues
});
const dirtyValues = form.formState.dirtyFields
const isValuesSet=useRef(false)
const getChangedFields=(values:Partial<SchemaType>)=>{
const changedFields = Object.keys(dirtyValues).reduce<Partial<SchemaType>>(
(acc, key) => {
const typedKey = key as keyof SchemaType;
const selectedValue = values[typedKey];
if (selectedValue !== undefined) {
acc[typedKey] = selectedValue as any;
}
return acc;
},
{}
);
return changedFields
}
useEffect(()=>{
if(isValuesSet.current)return
const valuesToSet=Object.entries(addValues)
if(!valuesToSet.length)return
valuesToSet.map(([key,value])=>{
form.setValue(key as any,value )
})
isValuesSet.current=true
},[addValues,form])
useEffect(() => {
const subscription = form.watch((value, { name, type }) =>{
if(type === 'change' && !isInputChanged){
setIsInputChanged(true)
}
}
)
return () => subscription.unsubscribe()
}, [form.watch,form,isInputChanged])
const setFormValues = (values:Partial<z.infer<T>>)=>{
setAddValues(values)
}
const isChanged = useMemo(()=>{
return Object.values(getChangedFields(form.getValues()))?.length ? true : false
},[form.getValues(),getChangedFields])
return {
form,
isInputChanged:isChanged,
setIsInputChanged,
getChangedFields,
setFormValues
}
}
export default useFormHandler