import { Fragment, useState, type MouseEvent } from 'react'; import { ActionIcon, Badge, Button, Checkbox, Group, Table, Text, Tooltip } from '@mantine/core'; import { ArrowRightLeft, ChevronDown, ChevronRight, ClipboardList, Coins, Download, Eye, FileText, History, MapPin } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { warehouseService } from '@/services/warehouse.service'; import { getNextInventoryAction, type InventoryAction, type WarehouseInventoryItem, } from '@/types/warehouse'; import { InventoryStatusBadge } from './badges'; import { TruckBreakdownRow } from './TruckBreakdownRow'; import { extractDownloadErrorMessage, formatDate, formatNumber, humanizeEnum } from './options'; import { openPdfBlob } from './pdf'; interface WarehouseInventoryTableProps { items: WarehouseInventoryItem[]; busyId?: string | null; onAdvance: (item: WarehouseInventoryItem, action: InventoryAction) => void; onMove: (item: WarehouseInventoryItem) => void; onHistory: (item: WarehouseInventoryItem) => void; onView?: (item: WarehouseInventoryItem) => void; onInspect?: (item: WarehouseInventoryItem) => void; onFeePreview?: (item: WarehouseInventoryItem) => void; onReleaseDocument?: (item: WarehouseInventoryItem) => void; onHandoverDocument?: (item: WarehouseInventoryItem) => void; onDownloadBundle?: (item: WarehouseInventoryItem) => void; onLastMile?: (item: WarehouseInventoryItem) => void; selectedIds?: Set; onToggleSelect?: (id: string) => void; onToggleSelectAll?: () => void; allSelected?: boolean; someSelected?: boolean; } const itemKind = (item: WarehouseInventoryItem) => { if (item.containerId) return { label: 'Container', color: 'blue' }; if (item.cargoId) return { label: 'Cargo', color: 'grape' }; if (item.goodsId) return { label: 'Goods', color: 'orange' }; return { label: '-', color: 'gray' }; }; const actionColor: Record = { store: 'blue', 'ready-for-loading': 'cyan', load: 'teal', dispatch: 'edr-green', 'ready-for-pickup': 'orange', release: 'yellow', deliver: 'green', }; const releaseActionLabel = (item: WarehouseInventoryItem) => item.releaseOrderReference ? 'Truck Leaving' : 'Truck Arrival'; const noteLineValue = (notes: string | null | undefined, label: string) => { const match = notes?.match(new RegExp(`^${label}:\\s*(.+)$`, 'im')); return match?.[1]?.trim() ?? ''; }; const handoverDocumentReference = (item: WarehouseInventoryItem) => item.handoverDocumentReference ?? noteLineValue(item.notes, 'Handover Reference'); function GrnDocumentButton({ item }: { item: WarehouseInventoryItem }) { const { toast } = useToast(); const [loading, setLoading] = useState(false); const openDocument = async (event: MouseEvent) => { event.stopPropagation(); if (!item.grnNumber) { toast({ variant: 'destructive', title: 'GRN document unavailable', description: 'This item has no GRN number yet.' }); return; } setLoading(true); const pdfWindow = window.open('', '_blank'); try { const response = await warehouseService.downloadGrnDocument(item.id); const opened = openPdfBlob(response.data, `grn-${item.grnNumber}.pdf`, pdfWindow); toast({ title: opened ? 'GRN document opened' : 'GRN document downloaded' }); } catch (error) { pdfWindow?.close(); toast({ variant: 'destructive', title: 'GRN document failed', description: await extractDownloadErrorMessage(error) }); } finally { setLoading(false); } }; return ( ); } export function WarehouseInventoryTable({ items, busyId, onAdvance, onMove, onHistory, onView, onInspect, onFeePreview, onReleaseDocument, onHandoverDocument, onDownloadBundle, onLastMile, selectedIds, onToggleSelect, onToggleSelectAll, allSelected, someSelected, }: WarehouseInventoryTableProps) { const selectable = Boolean(onToggleSelect); // Bookings whose truck breakdown is open. Expanded rows fetch on demand, so a // closed table costs nothing extra. const [expanded, setExpanded] = useState>(new Set()); const toggleExpanded = (bookingId: string) => setExpanded((prev) => { const next = new Set(prev); if (next.has(bookingId)) next.delete(bookingId); else next.add(bookingId); return next; }); if (items.length === 0) { return ( No inventory items found. ); } return ( {selectable && ( )} {/* Expander for the per-truck breakdown. */} Booking GRN Facility Warehouse Yard Zone Item Qty Weight Status Arrived Actions {items.map((item) => { const kind = itemKind(item); const busy = busyId === item.id; // Per-booking Load and Dispatch are retired: wagon loading happens in // the train flow and dispatch at the train level (which already // advances inventory). Only the remaining lifecycle actions render. const rawNextAction = getNextInventoryAction(item); const nextAction = rawNextAction === 'load' || rawNextAction === 'dispatch' ? null : rawNextAction; const canGenerateHandover = item.inspectionStatus === 'PASSED' && Boolean(item.bookingId) && (!item.booking?.tradeDirection || item.booking.tradeDirection === 'IMPORT'); const handoverReference = handoverDocumentReference(item); // Only offer the breakdown where there is one: a plate means at // least one customer truck is on the booking. const hasCustomerTrucks = Boolean( item.bookingId && item.booking?.customerTruckPlateNumber?.trim(), ); const isExpanded = Boolean(item.bookingId && expanded.has(item.bookingId)); return ( {selectable && ( onToggleSelect?.(item.id)} /> )} {hasCustomerTrucks ? ( toggleExpanded(item.bookingId as string)} > {isExpanded ? : } ) : null} {item.bookingReference || item.booking?.reference || item.bookingId ? ( {item.bookingReference ?? item.booking?.reference ?? `${item.bookingId?.slice(0, 8)}...`} ) : ( - )} {item.warehouse?.facility?.name ?? '-'} {item.warehouse?.code ?? '-'} {item.yard?.code ?? '-'} {item.zone?.code ?? '-'} {kind.label} {formatNumber(item.quantity)} {formatNumber(item.weight)} {formatDate(item.arrivedAt)} {onView && ( onView(item)}> )} {nextAction && ( )} {item.status === 'READY_FOR_PICKUP' && ( )} {item.status !== 'DISPATCHED' && ( onMove(item)}> )} {onInspect && ( onInspect(item)}> )} {onFeePreview && ( onFeePreview(item)}> )} {onReleaseDocument && item.releaseDate && ( onReleaseDocument(item)}> )} {onHandoverDocument && canGenerateHandover && ( onHandoverDocument(item)}> )} {onDownloadBundle && item.grnNumber && ( onDownloadBundle(item)}> )} {onLastMile && item.booking?.lastMileDeliveryAddress && ( onLastMile(item)}> )} onHistory(item)}> {isExpanded && item.bookingId ? ( ) : null} ); })}
); }