'use client'; import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { DndContext, closestCenter, type DragEndEvent, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core'; import { SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import { GripVertical, Plus, Loader2, Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { apiFetch } from '@/lib/api/client'; interface WaitingListEntry { id: string; clientId: string; position: number; priority: string; notifyPref: string; notes: string | null; createdAt: string; } interface WaitingListManagerProps { berthId: string; } function SortableEntry({ entry, onRemove, }: { entry: WaitingListEntry; onRemove: (id: string) => void; }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: entry.id, }); const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, }; return (
{entry.position}

{entry.clientId}

{entry.notes &&

{entry.notes}

}
{entry.priority}
); } export function WaitingListManager({ berthId }: WaitingListManagerProps) { const queryClient = useQueryClient(); const sensors = useSensors(useSensor(PointerSensor)); const [showAddForm, setShowAddForm] = useState(false); const [newClientId, setNewClientId] = useState(''); const [newPriority, setNewPriority] = useState<'normal' | 'high'>('normal'); const [newNotes, setNewNotes] = useState(''); const { data, isLoading } = useQuery<{ data: WaitingListEntry[] }>({ queryKey: ['berth-waiting-list', berthId], queryFn: () => apiFetch(`/api/v1/berths/${berthId}/waiting-list`), }); const reorderMutation = useMutation({ mutationFn: (body: { entryId: string; newPosition: number }) => apiFetch(`/api/v1/berths/${berthId}/waiting-list`, { method: 'PATCH', body, }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['berth-waiting-list', berthId] }); }, }); const addMutation = useMutation({ mutationFn: (entries: WaitingListEntry[]) => apiFetch(`/api/v1/berths/${berthId}/waiting-list`, { method: 'PUT', body: { entries }, }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['berth-waiting-list', berthId] }); setShowAddForm(false); setNewClientId(''); setNewNotes(''); }, }); const entries = data?.data ?? []; function handleDragEnd(event: DragEndEvent) { const { active, over } = event; if (!over || active.id === over.id) return; const overId = over.id as string; const overEntry = entries.find((e) => e.id === overId); if (!overEntry) return; reorderMutation.mutate({ entryId: active.id as string, newPosition: overEntry.position, }); } function handleAdd() { if (!newClientId.trim()) return; const newEntry = { clientId: newClientId.trim(), position: entries.length + 1, priority: newPriority, notifyPref: 'email' as const, notes: newNotes || undefined, }; addMutation.mutate([ ...entries.map((e) => ({ ...e, notifyPref: e.notifyPref as 'email' | 'in_app' | 'both', priority: e.priority as 'normal' | 'high', })), newEntry as WaitingListEntry, ]); } function handleRemove(entryId: string) { const remaining = entries .filter((e) => e.id !== entryId) .map((e, i) => ({ ...e, position: i + 1, notifyPref: e.notifyPref as 'email' | 'in_app' | 'both', priority: e.priority as 'normal' | 'high', })); addMutation.mutate(remaining); } if (isLoading) { return
; } return (
Waiting List ({entries.length})
{showAddForm && (
setNewClientId(e.target.value)} /> setNewNotes(e.target.value)} />
)} {entries.length === 0 ? (

No entries on waiting list.

) : ( e.id)} strategy={verticalListSortingStrategy}>
{entries.map((entry) => ( ))}
)}
); }