'use client'; import { useEffect } from 'react'; import { useForm, useFieldArray } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Plus, Trash2, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter, } from '@/components/ui/sheet'; import { Checkbox } from '@/components/ui/checkbox'; import { Separator } from '@/components/ui/separator'; import { TagPicker } from '@/components/shared/tag-picker'; import { apiFetch } from '@/lib/api/client'; import { createClientSchema, type CreateClientInput } from '@/lib/validators/clients'; interface ClientFormProps { open: boolean; onOpenChange: (open: boolean) => void; /** If provided, form is in edit mode */ client?: { id: string; fullName: string; companyName?: string | null; nationality?: string | null; isProxy?: boolean; proxyType?: string | null; actualOwnerName?: string | null; yachtName?: string | null; berthSizeDesired?: string | null; preferredContactMethod?: string | null; preferredLanguage?: string | null; timezone?: string | null; source?: string | null; sourceDetails?: string | null; contacts?: Array<{ channel: string; value: string; label?: string | null; isPrimary?: boolean; }>; tags?: Array<{ id: string }>; }; } export function ClientForm({ open, onOpenChange, client }: ClientFormProps) { const queryClient = useQueryClient(); const isEdit = !!client; const { register, handleSubmit, control, watch, setValue, reset, formState: { errors, isSubmitting }, } = useForm({ resolver: zodResolver(createClientSchema), defaultValues: { fullName: '', contacts: [{ channel: 'email', value: '', isPrimary: true }], isProxy: false, tagIds: [], }, }); const { fields, append, remove } = useFieldArray({ control, name: 'contacts' }); const isProxy = watch('isProxy'); const tagIds = watch('tagIds') ?? []; // Populate form when editing useEffect(() => { if (client && open) { reset({ fullName: client.fullName, companyName: client.companyName ?? undefined, nationality: client.nationality ?? undefined, isProxy: client.isProxy ?? false, proxyType: client.proxyType ?? undefined, actualOwnerName: client.actualOwnerName ?? undefined, yachtName: client.yachtName ?? undefined, berthSizeDesired: client.berthSizeDesired ?? undefined, preferredContactMethod: (client.preferredContactMethod as any) ?? undefined, preferredLanguage: client.preferredLanguage ?? undefined, timezone: client.timezone ?? undefined, source: (client.source as any) ?? undefined, sourceDetails: client.sourceDetails ?? undefined, contacts: client.contacts && client.contacts.length > 0 ? client.contacts.map((c) => ({ channel: c.channel as any, value: c.value, label: c.label ?? undefined, isPrimary: c.isPrimary ?? false, })) : [{ channel: 'email', value: '', isPrimary: true }], tagIds: client.tags?.map((t) => t.id) ?? [], }); } else if (!client && open) { reset({ fullName: '', contacts: [{ channel: 'email', value: '', isPrimary: true }], isProxy: false, tagIds: [], }); } }, [client, open, reset]); const mutation = useMutation({ mutationFn: async (data: CreateClientInput) => { if (isEdit) { const { contacts, tagIds: tIds, ...rest } = data; await apiFetch(`/api/v1/clients/${client!.id}`, { method: 'PATCH', body: rest }); if (tIds) { await apiFetch(`/api/v1/clients/${client!.id}/tags`, { method: 'PUT', body: { tagIds: tIds }, }); } } else { await apiFetch('/api/v1/clients', { method: 'POST', body: data }); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['clients'] }); onOpenChange(false); }, }); return ( {isEdit ? 'Edit Client' : 'New Client'}
mutation.mutate(data))} className="space-y-6 py-6" > {/* Basic Info */}

Basic Information

{errors.fullName && (

{errors.fullName.message}

)}
{/* Contacts */}

Contacts

{errors.contacts?.root && (

{errors.contacts.root.message}

)}
{fields.map((field, index) => (
setValue(`contacts.${index}.isPrimary`, !!v) } />
{fields.length > 1 && ( )}
))}
{/* Proxy */}

Proxy Information

setValue('isProxy', !!v)} />
{isProxy && (
)}
{/* Yacht Details */}

Yacht Details

{/* Source & Preferences */}

Source & Preferences

{/* Tags */}
setValue('tagIds', ids)} />
); }