'use client'; import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; 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 { Separator } from '@/components/ui/separator'; import { Switch } from '@/components/ui/switch'; import { TagPicker } from '@/components/shared/tag-picker'; import { apiFetch } from '@/lib/api/client'; import { updateBerthSchema, type UpdateBerthInput } from '@/lib/validators/berths'; interface BerthFormProps { berth: { id: string; mooringNumber: string; area: string | null; status: string; lengthFt: string | null; lengthM: string | null; widthFt: string | null; widthM: string | null; draftFt: string | null; draftM: string | null; widthIsMinimum: boolean | null; price: string | null; priceCurrency: string; tenureType: string; tenureYears: number | null; tenureStartDate: string | null; tenureEndDate: string | null; powerCapacity: string | null; voltage: string | null; mooringType: string | null; access: string | null; berthApproved: boolean | null; tags: Array<{ id: string; name: string; color: string }>; }; open: boolean; onOpenChange: (open: boolean) => void; } export function BerthForm({ berth, open, onOpenChange }: BerthFormProps) { const queryClient = useQueryClient(); const [tagIds, setTagIds] = useState(berth.tags.map((t) => t.id)); const { register, handleSubmit, setValue, watch, formState: { isSubmitting }, } = useForm({ resolver: zodResolver(updateBerthSchema), defaultValues: { area: berth.area ?? undefined, lengthFt: berth.lengthFt ? Number(berth.lengthFt) : undefined, lengthM: berth.lengthM ? Number(berth.lengthM) : undefined, widthFt: berth.widthFt ? Number(berth.widthFt) : undefined, widthM: berth.widthM ? Number(berth.widthM) : undefined, draftFt: berth.draftFt ? Number(berth.draftFt) : undefined, draftM: berth.draftM ? Number(berth.draftM) : undefined, widthIsMinimum: berth.widthIsMinimum ?? false, price: berth.price ? Number(berth.price) : undefined, priceCurrency: berth.priceCurrency, tenureType: berth.tenureType as 'permanent' | 'fixed_term', tenureYears: berth.tenureYears ?? undefined, tenureStartDate: berth.tenureStartDate ?? undefined, tenureEndDate: berth.tenureEndDate ?? undefined, powerCapacity: berth.powerCapacity ?? undefined, voltage: berth.voltage ?? undefined, mooringType: berth.mooringType ?? undefined, access: berth.access ?? undefined, berthApproved: berth.berthApproved ?? false, }, }); const tagMutation = useMutation({ mutationFn: (ids: string[]) => apiFetch(`/api/v1/berths/${berth.id}/tags`, { method: 'PUT', body: { tagIds: ids }, }), }); async function onSubmit(data: UpdateBerthInput) { try { await apiFetch(`/api/v1/berths/${berth.id}`, { method: 'PATCH', body: data, }); await tagMutation.mutateAsync(tagIds); queryClient.invalidateQueries({ queryKey: ['berths'] }); queryClient.invalidateQueries({ queryKey: ['berth', berth.id] }); toast.success('Berth updated'); onOpenChange(false); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to update berth'; toast.error(message); } } const tenureType = watch('tenureType'); return ( Edit Berth {berth.mooringNumber}
{/* Basic Info */}

Basic Info

setValue('berthApproved', v)} />
{/* Dimensions */}

Dimensions

setValue('widthIsMinimum', v)} />
{/* Price */}

Price

{/* Tenure */}

Tenure

{tenureType === 'fixed_term' && (
)}
{/* Infrastructure */}

Infrastructure

{/* Tags */}

Tags

); }