import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Badge, Button, Card, Group, Tabs, Text } from '@mantine/core'; import { CreditCard, Eye, Truck, TrainFront } from 'lucide-react'; import { DataTable, type ColumnDef } from '@edr/ui-common'; import { PageContainer, PageHeader } from '@/components/page'; import { InventoryWorkbench, VisualEmptyState, formatNumber, } from '@/components/warehouses'; import { LoadToTrainPanel } from '@/components/warehouses/LoadToTrainPanel'; import { useMutation, useQuery } from '@tanstack/react-query'; import { api } from '@/services/api'; import { useToast } from '@/hooks/use-toast'; import type { WarehouseInventoryItem } from '@/types/warehouse'; const isPaid = (item: WarehouseInventoryItem) => item.booking?.status === 'PAID'; /** * Loading Queue — manage inventory through the loading workflow. * Tabs: * - Ready to Load: READY_FOR_LOADING + booking PAID (can Mark as Loaded) * - Pending Payment: READY_FOR_LOADING + booking not PAID (no Load action) * - Loaded Inventory: LOADED (can Dispatch) * - Dispatch Queue: LOADED (can Dispatch) */ export default function LoadingQueuePage() { const navigate = useNavigate(); const { toast } = useToast(); const autoLoad = useMutation(api.warehouses.autoLoadReady.mutationOptions()); const { data: readyData, isLoading: readyLoading } = useQuery( api.warehouses.listInventory.queryOptions({ input: { filter: { status: 'READY_FOR_LOADING' } }, }), ); const { data: loadedData, isLoading: loadedLoading } = useQuery( api.warehouses.listInventory.queryOptions({ input: { filter: { status: 'LOADED' } } }), ); const handleAutoLoad = async () => { try { const r = await autoLoad.mutateAsync(); toast({ title: 'Auto-load complete', description: `Loaded ${r.loadedCount} PAID item(s); skipped ${r.skippedCount} (unpaid stay pending).`, }); } catch { toast({ variant: 'destructive', title: 'Auto-load failed' }); } }; const readyItems = readyData ?? []; const loadedItems = loadedData ?? []; const paidItems = useMemo(() => readyItems.filter(isPaid), [readyItems]); const unpaidItems = useMemo(() => readyItems.filter((i) => !isPaid(i)), [readyItems]); return ( } loading={autoLoad.isPending} onClick={handleAutoLoad} > Auto Load Ready Items } /> {paidItems.length} } > Ready to Load {unpaidItems.length} } > Pending Payment {loadedItems.length} } > Loaded Inventory {loadedItems.length} } > Dispatch Queue }> Load to Train {/* Ready to Load — PAID bookings, can be marked Loaded */} {!readyLoading && paidItems.length === 0 ? ( ) : ( )} {/* Pending Payment — unpaid bookings, read-only (no Load action) */} {!readyLoading && unpaidItems.length === 0 ? ( ) : ( )} {/* Loaded Inventory — LOADED items, can Dispatch */} {!loadedLoading && loadedItems.length === 0 ? ( ) : ( )} {/* Dispatch Queue — LOADED items awaiting departure */} {!loadedLoading && loadedItems.length === 0 ? ( ) : ( )} {/* Load to Train — per-train arrived containers/cargoes, multiselect → load onto wagons */} ); } interface PendingPaymentTableProps { items: WarehouseInventoryItem[]; onNavigate: (path: string) => void; } /** Read-only view of unpaid ready-for-loading items. No Mark-as-Loaded action. */ function PendingPaymentTable({ items, onNavigate }: PendingPaymentTableProps) { const columns: ColumnDef[] = [ { id: 'booking', header: 'Booking', cell: ({ row }) => ( {row.original.booking?.reference ?? row.original.bookingId?.slice(0, 8) ?? '—'} ), }, { id: 'warehouse', header: 'Warehouse', cell: ({ row }) => row.original.warehouse?.code ?? '—' }, { id: 'zone', header: 'Zone', cell: ({ row }) => row.original.zone?.code ?? '—' }, { id: 'weight', header: 'Weight (kg)', cell: ({ row }) => formatNumber(row.original.weight) }, { id: 'payment', header: 'Payment', cell: ({ row }) => ( {row.original.booking?.status ?? row.original.booking?.paymentStatus ?? 'UNPAID'} ), }, { id: 'actions', header: '', cell: ({ row }) => { const item = row.original; return ( e.stopPropagation()}> ); }, }, ]; return ( ); }