'use client'; import { useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Loader2 } from 'lucide-react'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Sheet, SheetContent, SheetFooter, SheetHeader, SheetTitle } from '@/components/ui/sheet'; import { Separator } from '@/components/ui/separator'; import { TagPicker } from '@/components/shared/tag-picker'; import { apiFetch } from '@/lib/api/client'; import { createCompanySchema, type CreateCompanyInput } from '@/lib/validators/companies'; type CompanyStatus = 'active' | 'dissolved'; type CompanyFormValues = z.input; interface CompanyFormProps { open: boolean; onOpenChange: (open: boolean) => void; /** If provided, form is in edit mode */ company?: { id: string; name: string; legalName: string | null; taxId: string | null; registrationNumber: string | null; incorporationCountry: string | null; incorporationDate: string | null; status: string; billingEmail: string | null; notes: string | null; }; } export function CompanyForm({ open, onOpenChange, company }: CompanyFormProps) { const queryClient = useQueryClient(); const isEdit = !!company; const [formError, setFormError] = useState(null); const { register, handleSubmit, watch, setValue, reset, formState: { errors, isSubmitting }, } = useForm({ resolver: zodResolver(createCompanySchema), defaultValues: { name: '', status: 'active', tagIds: [], }, }); const tagIds = watch('tagIds') ?? []; const status = watch('status') ?? 'active'; // Populate form when editing, or reset to defaults in create mode. useEffect(() => { if (company && open) { reset({ name: company.name, legalName: company.legalName ?? undefined, taxId: company.taxId ?? undefined, registrationNumber: company.registrationNumber ?? undefined, incorporationCountry: company.incorporationCountry ?? undefined, incorporationDate: company.incorporationDate ? new Date(company.incorporationDate) : undefined, status: (company.status as CompanyStatus) ?? 'active', billingEmail: company.billingEmail ?? undefined, notes: company.notes ?? undefined, tagIds: [], }); } else if (!company && open) { reset({ name: '', status: 'active', tagIds: [] }); } setFormError(null); }, [company, open, reset]); const mutation = useMutation({ mutationFn: async (data: CreateCompanyInput) => { if (isEdit) { // updateCompanySchema omits tagIds — strip them from PATCH body. const { tagIds: _tIds, ...rest } = data; void _tIds; await apiFetch(`/api/v1/companies/${company!.id}`, { method: 'PATCH', body: rest, }); } else { await apiFetch('/api/v1/companies', { method: 'POST', body: data }); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['companies'] }); onOpenChange(false); }, onError: (err: unknown) => { const msg = err instanceof Error ? err.message : 'Failed to save company'; setFormError(msg); }, }); return ( {isEdit ? 'Edit Company' : 'New Company'}
{ setFormError(null); mutation.mutate(data as CreateCompanyInput); })} className="space-y-6 py-6" > {/* Basics */}

Basics

{errors.name &&

{errors.name.message}

}
{/* Registration */}

Registration

{errors.incorporationDate && (

{errors.incorporationDate.message}

)}
{/* Contact & Status */}

Contact & Status

{errors.billingEmail && (

{errors.billingEmail.message}

)}
{/* Notes */}