import { useMemo } from "react"; import { ArrowRight, Package } from "lucide-react"; import { Accordion, Badge, Button, Checkbox, Group, Loader, Paper, Stack, Text, } from "@mantine/core"; import { BookingPriorityBadge } from "@/components/bookings/BookingPriorityBadge"; import type { EligibleContainerBooking, FreightType } from "@/types/trainScheduling"; import { groupBookingsByThreeHourWindow } from "@/utils/groupBookingsByThreeHourWindow"; function EligibleBookingRow({ booking, freightType, selected, onToggle, }: { booking: EligibleContainerBooking; freightType?: FreightType; selected: boolean; onToggle: () => void; }) { const resolvedFreightType = booking.freightType ?? freightType; const isBulk = resolvedFreightType === "BULK"; return ( {booking.reference} {resolvedFreightType ? ( {resolvedFreightType} ) : null} {booking.schedulingStatus ? ( {booking.schedulingStatus} ) : null} {booking.customer} {booking.origin} {booking.destination} {isBulk ? `${booking.weightTons}T` : `${booking.quantity} × ${booking.containerType}`} {booking.preferredDepartureDate ? ( {new Date(booking.preferredDepartureDate).toLocaleString("en-GB", { timeZone: "UTC", day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit", })}{" "} UTC ) : null} ); } export function EligibleBookingsPanel({ items, isLoading, selectedIds, onSelectionChange, assignedIds = [], freightType, }: { items: EligibleContainerBooking[]; isLoading?: boolean; selectedIds: string[]; onSelectionChange: (ids: string[]) => void; assignedIds?: string[]; freightType?: FreightType; }) { const assignedSet = useMemo(() => new Set(assignedIds), [assignedIds]); const availableItems = useMemo( () => items.filter((b) => !assignedSet.has(b.id)), [items, assignedSet], ); const buckets = useMemo( () => groupBookingsByThreeHourWindow(availableItems), [availableItems], ); const selectableIds = useMemo(() => { return [...assignedIds, ...availableItems.map((b) => b.id)]; }, [availableItems, assignedIds]); const toggle = (id: string) => { if (selectedIds.includes(id)) { onSelectionChange(selectedIds.filter((x) => x !== id)); } else { onSelectionChange([...selectedIds, id]); } }; const toggleBucket = (bucketIds: string[], select: boolean) => { if (select) { const merged = new Set([...selectedIds, ...bucketIds]); onSelectionChange([...merged]); } else { onSelectionChange(selectedIds.filter((id) => !bucketIds.includes(id))); } }; if (isLoading) { return ( Loading eligible bookings… ); } if (!items.length && !assignedIds.length) { return ( No eligible bookings for this corridor ); } return ( Eligible bookings ({availableItems.length}) {buckets.length > 0 ? ( {buckets.map((bucket) => { const bucketIds = bucket.bookings.map((b) => b.id); const selectedInBucket = bucketIds.filter((id) => selectedIds.includes(id)); const allSelected = bucketIds.length > 0 && selectedInBucket.length === bucketIds.length; return ( {bucket.label} {bucket.bookings.length} booking {bucket.bookings.length === 1 ? "" : "s"} · priority sorted e.stopPropagation()}> {selectedInBucket.length} selected {bucket.bookings.map((booking) => ( toggle(booking.id)} /> ))} ); })} ) : ( No additional eligible bookings in this corridor. )} ); }