'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, DialogHeader, DialogTitle, DialogFooter, DialogDescription, } 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 { ClientPicker } from '@/components/shared/client-picker'; import { YachtPicker } from '@/components/yachts/yacht-picker'; import { apiFetch } from '@/lib/api/client'; type TenureType = 'permanent' | 'fixed_term' | 'seasonal'; type FormValues = { clientId: string | null; yachtId: string | null; startDate: string; // YYYY-MM-DD tenureType: TenureType; notes?: string; }; interface BerthReserveDialogProps { open: boolean; onOpenChange: (open: boolean) => void; berthId: string; } export function BerthReserveDialog({ open, onOpenChange, berthId }: BerthReserveDialogProps) { const queryClient = useQueryClient(); const [formError, setFormError] = useState(null); const { register, handleSubmit, watch, setValue, reset, formState: { errors, isSubmitting }, } = useForm({ defaultValues: { clientId: null, yachtId: null, startDate: new Date().toISOString().slice(0, 10), tenureType: 'permanent', notes: '', }, }); useEffect(() => { if (open) { setFormError(null); reset({ clientId: null, yachtId: null, startDate: new Date().toISOString().slice(0, 10), tenureType: 'permanent', notes: '', }); } }, [open, reset]); const clientId = watch('clientId'); const yachtId = watch('yachtId'); const tenureType = watch('tenureType'); // When client changes, clear yacht (since yacht-picker is filtered to owner=client) useEffect(() => { setValue('yachtId', null); }, [clientId, setValue]); function validate(data: FormValues): string | null { if (!data.clientId) return 'Please select a client'; if (!data.yachtId) return 'Please select a yacht'; return null; } async function createPending(data: FormValues): Promise<{ id: string }> { const res = await apiFetch<{ data: { id: string } }>(`/api/v1/berths/${berthId}/reservations`, { method: 'POST', body: { clientId: data.clientId!, yachtId: data.yachtId!, startDate: data.startDate, tenureType: data.tenureType, notes: data.notes?.trim() || undefined, }, }); return res.data; } const createMutation = useMutation({ mutationFn: async (data: FormValues) => { const err = validate(data); if (err) throw new Error(err); await createPending(data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['berths', berthId, 'reservations'] }); queryClient.invalidateQueries({ queryKey: ['berth-reservations'] }); toast.success('Reservation created'); onOpenChange(false); }, onError: (err: unknown) => { const msg = err instanceof Error ? err.message : 'Failed to create reservation'; setFormError(msg); }, }); const createAndActivateMutation = useMutation({ mutationFn: async (data: FormValues) => { const err = validate(data); if (err) throw new Error(err); const pending = await createPending(data); // Immediately activate await apiFetch(`/api/v1/berth-reservations/${pending.id}`, { method: 'PATCH', body: { action: 'activate' }, }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['berths', berthId, 'reservations'] }); queryClient.invalidateQueries({ queryKey: ['berth-reservations'] }); toast.success('Reservation created and activated'); onOpenChange(false); }, onError: (err: unknown) => { const msg = err instanceof Error ? err.message : 'Failed to activate'; if (/active reservation|conflict|409/i.test(msg)) { setFormError( 'This berth already has an active reservation. The pending record was created — activate it manually once the other reservation ends.', ); } else { setFormError(msg); } }, }); const isPending = isSubmitting || createMutation.isPending || createAndActivateMutation.isPending; return ( Reserve this berth Create a pending reservation or activate it immediately.
setValue('clientId', id)} />
setValue('yachtId', id)} ownerFilter={clientId ? { type: 'client', id: clientId } : undefined} disabled={!clientId} placeholder={clientId ? 'Select yacht...' : 'Select a client first'} />
{errors.startDate &&

Required

}