diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx index c63852caa..9c1b18578 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx @@ -1,9 +1,10 @@ import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Badge, Card, Center, Divider, Group, Loader, Select, SimpleGrid, Stack, Text, ThemeIcon } from '@mantine/core'; +import { Button, Card, Center, Group, Loader, Popover, Select, SimpleGrid, Stack, Text, ThemeIcon } from '@mantine/core'; import { DatePickerInput } from '@mantine/dates'; import { ClipboardList, + Filter, PackageCheck, PackageOpen, PackagePlus, @@ -17,7 +18,6 @@ import { } from 'lucide-react'; import { PageContainer, PageHeader } from '@/components/page'; -import { getDateRangePresets } from '@/components/common/dateRangePresets'; import { AccrualDashboard, CycleTimeCard, @@ -44,44 +44,42 @@ interface Metric { icon: React.ReactNode; /** Route to navigate to when the card is clicked. */ to: string; - theme: string; } -const ORANGE = 'rgb(241, 147, 23)'; -const GREEN = '#084b21'; - const METRICS: Metric[] = [ - { key: 'totalWarehouses', label: 'Total Warehouses', icon: , to: '/dashboard/warehouses', theme: ORANGE }, - { key: 'totalInventory', label: 'Total Inventory', icon: , to: '/dashboard/warehouse-inventory', theme: GREEN }, - { key: 'received', label: 'Received Today', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED', theme: ORANGE }, - { key: 'awaitingInspection', label: 'Awaiting Inspection', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED', theme: GREEN }, - { key: 'emptyContainers', label: 'Empty Containers', icon: , to: '/dashboard/containers', theme: ORANGE }, - { key: 'importTrains', label: 'Import Trains', icon: , to: '/dashboard/import-warehouse', theme: GREEN }, - { key: 'exportTrains', label: 'Export Trains', icon: , to: '/dashboard/export-warehouse', theme: ORANGE }, - { key: 'loaded', label: 'Loaded', icon: , to: '/dashboard/loaded-inventory', theme: GREEN }, - { key: 'dispatched', label: 'Dispatched', icon: , to: '/dashboard/dispatch-queue', theme: ORANGE }, - { key: 'readyForPickup', label: 'Ready For Pickup', icon: , to: '/dashboard/warehouse-inventory?status=READY_FOR_PICKUP', theme: GREEN }, - { key: 'readyForLoading', label: 'Ready For Loading', icon: , to: '/dashboard/loading-queue', theme: ORANGE }, - { key: 'delivered', label: 'Delivered', icon: , to: '/dashboard/warehouse-inventory?status=DELIVERED', theme: GREEN }, + { key: 'totalWarehouses', label: 'Total Warehouses', icon: , to: '/dashboard/warehouses' }, + { key: 'totalInventory', label: 'Total Inventory', icon: , to: '/dashboard/warehouse-inventory' }, + { key: 'received', label: 'Received Today', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED' }, + { key: 'awaitingInspection', label: 'Awaiting Inspection', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED' }, + { key: 'emptyContainers', label: 'Empty Containers', icon: , to: '/dashboard/containers' }, + { key: 'importTrains', label: 'Import Trains', icon: , to: '/dashboard/import-warehouse' }, + { key: 'exportTrains', label: 'Export Trains', icon: , to: '/dashboard/export-warehouse' }, + { key: 'loaded', label: 'Loaded', icon: , to: '/dashboard/loaded-inventory' }, + { key: 'dispatched', label: 'Dispatched', icon: , to: '/dashboard/dispatch-queue' }, + { key: 'readyForPickup', label: 'Ready For Pickup', icon: , to: '/dashboard/warehouse-inventory?status=READY_FOR_PICKUP' }, + { key: 'readyForLoading', label: 'Ready For Loading', icon: , to: '/dashboard/loading-queue' }, + { key: 'delivered', label: 'Delivered', icon: , to: '/dashboard/warehouse-inventory?status=DELIVERED' }, ]; export default function WarehouseDashboardPage() { const navigate = useNavigate(); - // Both null → the API defaults `received` to "today", matching the page's original behaviour. - const [dateRange, setDateRange] = useState<[string | null, string | null]>([null, null]); + // null → the API defaults `received` to "today", matching the page's original behaviour. + const [receivedDate, setReceivedDate] = useState(null); const [warehouseId, setWarehouseId] = useState(null); - const [dateFrom, dateTo] = dateRange; - const hasCustomRange = Boolean(dateFrom || dateTo); + const [filtersOpen, setFiltersOpen] = useState(false); + const hasCustomDate = Boolean(receivedDate); const warehousesQuery = useWarehouses(); const warehouseOptions = useMemo( () => (warehousesQuery.data ?? []).map((w) => ({ value: w.id, label: `${w.name} (${w.code})` })), [warehousesQuery.data], ); + const activeFilterCount = (warehouseId ? 1 : 0) + (hasCustomDate ? 1 : 0); const { data, isError, isLoading } = useWarehouseDashboard({ - dateFrom: dateFrom ?? undefined, - dateTo: dateTo ?? undefined, + // Same date both ends → the one day the picker selected, inclusive. + dateFrom: receivedDate ?? undefined, + dateTo: receivedDate ?? undefined, warehouseId: warehouseId ?? undefined, }); @@ -89,57 +87,64 @@ export default function WarehouseDashboardPage() { - + {activeFilterCount > 0 && ( + + )} + + + } /> - {(warehouseId || hasCustomRange) && ( + {(warehouseId || hasCustomDate) && ( Scoped to{' '} {warehouseId ? warehouseOptions.find((o) => o.value === warehouseId)?.label ?? 'selected warehouse' : 'all warehouses'} - {hasCustomRange - ? ` · Received counts ${dateFrom ?? '…'} to ${dateTo ?? '…'}` - : ' · Received counts: today'} - . Status-backlog and fleet counters are always current regardless of the date range. + {hasCustomDate ? ` · Received counts for ${receivedDate}` : ' · Received counts: today'} + . Status-backlog and fleet counters are always current regardless of the date filter. )} @@ -152,41 +157,33 @@ export default function WarehouseDashboardPage() { Failed to load warehouse dashboard. ) : ( - + {/* Needs attention — live ops counters (received today, pending inspection, trucks on-site, items aging > 7 days). */} - - Needs attention - - - - + {METRICS.map((metric) => ( navigate(metric.to)} className="cursor-pointer transition-[transform,border-color] duration-150 hover:-translate-y-0.5 hover:border-edr-primary!" > - -
- - {metric.key === 'received' && hasCustomRange ? 'Received' : metric.label} - - - {data ? data[metric.key] : 0} - -
- + + {metric.icon} + + + {metric.key === 'received' && hasCustomDate ? 'Received' : metric.label} + + + {data ? data[metric.key] : 0} + +
))}