'use client'; import { useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Loader2 } from 'lucide-react'; import { toast } from 'sonner'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { OwnerPicker, type OwnerRef } from '@/components/shared/owner-picker'; import { apiFetch } from '@/lib/api/client'; type TransferReason = 'sale' | 'inheritance' | 'gift' | 'company_restructure' | 'other'; type FormValues = { newOwner: OwnerRef | undefined; effectiveDate: string; // ISO date string from transferReason?: TransferReason; transferNotes?: string; }; interface YachtTransferDialogProps { open: boolean; onOpenChange: (open: boolean) => void; yachtId: string; /** Current owner shown for reference; used to guard against selecting the same owner. */ currentOwner?: OwnerRef; } const todayIso = (): string => new Date().toISOString().slice(0, 10); export function YachtTransferDialog({ open, onOpenChange, yachtId, currentOwner, }: YachtTransferDialogProps) { const queryClient = useQueryClient(); const [formError, setFormError] = useState(null); const { register, handleSubmit, watch, setValue, reset, formState: { errors, isSubmitting }, } = useForm({ defaultValues: { newOwner: undefined, effectiveDate: todayIso(), transferReason: undefined, transferNotes: '', }, }); useEffect(() => { if (open) { setFormError(null); reset({ newOwner: undefined, effectiveDate: todayIso(), transferReason: undefined, transferNotes: '', }); } }, [open, reset]); const newOwner = watch('newOwner'); const transferReason = watch('transferReason'); const mutation = useMutation({ mutationFn: async (data: FormValues) => { if (!data.newOwner) { throw new Error('Please select a new owner'); } if ( currentOwner && data.newOwner.type === currentOwner.type && data.newOwner.id === currentOwner.id ) { throw new Error('New owner must be different from the current owner'); } await apiFetch(`/api/v1/yachts/${yachtId}/transfer`, { method: 'POST', body: { newOwner: data.newOwner, effectiveDate: data.effectiveDate, transferReason: data.transferReason, transferNotes: data.transferNotes?.trim() || undefined, }, }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['yachts', yachtId] }); queryClient.invalidateQueries({ queryKey: ['yachts', yachtId, 'ownership-history'] }); queryClient.invalidateQueries({ queryKey: ['yachts'] }); toast.success('Ownership transferred'); onOpenChange(false); }, onError: (err: unknown) => { const msg = err instanceof Error ? err.message : 'Failed to transfer ownership'; setFormError(msg); }, }); return ( Transfer ownership This will close the current ownership record and open a new one. The change is auditable and atomic.
{ setFormError(null); mutation.mutate(data); })} className="space-y-4" >
setValue('newOwner', v ?? undefined)} />
{errors.effectiveDate &&

Required

}