Files
road-monitoring-ui/src/app/(modules)/clients/hooks/useClientForm.ts

143 lines
3.9 KiB
TypeScript

'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useCallback } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
import type { Client } from '@/types';
import { useSaveClientMutation } from './useClientMutations';
const phoneSchema = z
.string()
.trim()
.min(1, 'Phone number is required')
.regex(/^\+(?:[0-9] ?|-){6,18}[0-9]$/, 'Please enter a valid phone number');
const optionalTaxIdSchema = z.string().trim();
const clientFormSchema = z.object({
id: z.number().optional(),
name: z.string().trim().min(1, 'Client name is required'),
email: z.string().trim().min(1, 'Email is required').email('Invalid email'),
landline_number: phoneSchema,
address: z.string().trim().min(1, 'Address is required'),
gst: optionalTaxIdSchema,
pan: optionalTaxIdSchema,
tan: optionalTaxIdSchema,
contact_name: z.string().trim().min(1, 'Contact name is required'),
contact_phone_number: phoneSchema,
contact_email: z
.string()
.trim()
.min(1, 'Contact email is required')
.email('Invalid contact email'),
is_active: z.boolean(),
});
export type ClientFormValues = z.infer<typeof clientFormSchema>;
const defaultValues: ClientFormValues = {
name: '',
email: '',
landline_number: '',
address: '',
gst: '',
pan: '',
tan: '',
contact_name: '',
contact_phone_number: '',
contact_email: '',
is_active: true,
};
export function useClientForm({ onSaved }: { onSaved: () => void }) {
const {
register,
handleSubmit: submitForm,
reset,
control,
formState: { isSubmitting, errors, isSubmitted },
} = useForm<ClientFormValues>({
defaultValues,
mode: 'onSubmit',
reValidateMode: 'onChange',
resolver: zodResolver(clientFormSchema),
});
const saveMutation = useSaveClientMutation({
onSaved: () => {
reset(defaultValues);
onSaved();
},
});
const clientId = useWatch({ control, name: 'id' });
const name = useWatch({ control, name: 'name' }) || '';
const email = useWatch({ control, name: 'email' }) || '';
const landlineNumber = useWatch({ control, name: 'landline_number' }) || '';
const address = useWatch({ control, name: 'address' }) || '';
const contactName = useWatch({ control, name: 'contact_name' }) || '';
const contactPhoneNumber =
useWatch({ control, name: 'contact_phone_number' }) || '';
const contactEmail = useWatch({ control, name: 'contact_email' }) || '';
const canSubmit =
name.trim().length > 0 &&
email.trim().length > 0 &&
landlineNumber.trim().length > 0 &&
address.trim().length > 0 &&
contactName.trim().length > 0 &&
contactPhoneNumber.trim().length > 0 &&
contactEmail.trim().length > 0;
const handleSubmit = submitForm(
(values) => saveMutation.mutate(values),
(formErrors) => {
const firstError = Object.values(formErrors).find(
(error) => error?.message,
);
if (firstError?.message) {
toast.error(firstError.message);
}
},
);
const openCreate = useCallback(() => {
reset(defaultValues);
}, [reset]);
const openEdit = useCallback(
(client: Client) => {
reset({
id: client.id,
name: client.name || '',
email: client.email || '',
landline_number: client.landline_number || '',
address: client.address || '',
gst: client.gst || '',
pan: client.pan || '',
tan: client.tan || '',
contact_name: client.contact_name || '',
contact_phone_number: client.contact_phone_number || '',
contact_email: client.contact_email || '',
is_active: client.is_active,
});
},
[reset],
);
return {
register,
handleSubmit,
reset,
openCreate,
openEdit,
clientId,
errors,
isSubmitted,
canSubmit,
isSaving: isSubmitting || saveMutation.isPending,
};
}