From b7b03db945b82f34a50595dd09959552924fd4ab Mon Sep 17 00:00:00 2001 From: Nathnael Date: Sat, 20 Jun 2026 10:30:31 +0000 Subject: [PATCH] style: warehouse revamp --- .../src/components/page/KpiStrip.tsx | 2 +- .../src/pages/warehouses/ArrivalQueuePage.tsx | 52 ++--- .../pages/warehouses/DispatchQueuePage.tsx | 46 ++-- .../pages/warehouses/InventoryInquiryPage.tsx | 210 +++++++++--------- .../pages/warehouses/LoadedInventoryPage.tsx | 140 ++++++------ .../src/pages/warehouses/LoadingQueuePage.tsx | 37 ++- .../warehouses/WarehouseInventoryPage.tsx | 132 ++++++----- .../warehouses/WarehouseInvoicesPage.tsx | 29 +-- .../pages/warehouses/WarehouseListPage.tsx | 62 +++--- .../pages/warehouses/WarehouseRulesPage.tsx | 57 +++-- 10 files changed, 353 insertions(+), 414 deletions(-) diff --git a/apps/edr-freight-web/backoffice/src/components/page/KpiStrip.tsx b/apps/edr-freight-web/backoffice/src/components/page/KpiStrip.tsx index 81b75966c..6c8167a33 100644 --- a/apps/edr-freight-web/backoffice/src/components/page/KpiStrip.tsx +++ b/apps/edr-freight-web/backoffice/src/components/page/KpiStrip.tsx @@ -37,7 +37,7 @@ export function KpiStrip({ items, loading = false }: KpiStripProps) { const cells = items.slice(0, 5); return ( - +
{cells.map((item, index) => { const Icon = item.icon; diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/ArrivalQueuePage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/ArrivalQueuePage.tsx index c05f2c626..55eed2699 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/ArrivalQueuePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/ArrivalQueuePage.tsx @@ -4,20 +4,17 @@ import { Badge, Button, Card, - Container, Group, Loader, - Stack, Table, Text, } from '@mantine/core'; import { ClipboardList, Eye, PackageOpen, Truck } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; +import { PageContainer, PageHeader } from '@/components/page'; import { InspectionReportModal, VisualEmptyState, - WarehouseHero, formatDate, } from '@/components/warehouses'; import { useArrivalQueue, useAutoUnloadArrived, useUnloadBooking } from '@/hooks/useWarehouses'; @@ -64,31 +61,27 @@ export default function ArrivalQueuePage() { }; return ( - - + + } + loading={autoUnload.isPending} + onClick={handleAutoUnload} + > + Auto Unload Arrived Bookings + + } + /> - - + + + {items.length} arrived booking(s) + - - - {items.length} arrived booking(s) - - - - {isLoading ? ( + {isLoading ? ( @@ -187,14 +180,13 @@ export default function ArrivalQueuePage() { )} - - + setInspectInventoryId(null)} inventoryId={inspectInventoryId} /> - + ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/DispatchQueuePage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/DispatchQueuePage.tsx index 58e630fbf..1776ac8e0 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/DispatchQueuePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/DispatchQueuePage.tsx @@ -1,7 +1,7 @@ -import { Card, Container, Stack } from '@mantine/core'; +import { Card } from '@mantine/core'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; -import { InventoryWorkbench, VisualEmptyState, WarehouseHero } from '@/components/warehouses'; +import { PageContainer, PageHeader } from '@/components/page'; +import { InventoryWorkbench, VisualEmptyState } from '@/components/warehouses'; import { useWarehouseInventory } from '@/hooks/useWarehouses'; /** Items that are LOADED and awaiting dispatch (train departure). */ @@ -10,29 +10,23 @@ export default function DispatchQueuePage() { const items = data ?? []; return ( - - + + - - - - - {!isLoading && items.length === 0 ? ( - - ) : ( - - )} - - - + + {!isLoading && items.length === 0 ? ( + + ) : ( + + )} + + ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/InventoryInquiryPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/InventoryInquiryPage.tsx index 0995796da..eeaaa8848 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/InventoryInquiryPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/InventoryInquiryPage.tsx @@ -1,8 +1,8 @@ import { useMemo, useState } from 'react'; -import { Button, Card, Center, Container, Group, Loader, Select, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Button, Card, Center, Group, Loader, Select, Stack, TextInput } from '@mantine/core'; import { Search } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; +import { PageContainer, PageHeader } from '@/components/page'; import { VisualEmptyState, WarehouseInquiryTable, inventoryStatusOptions } from '@/components/warehouses'; import { useInventoryInquiry, @@ -43,113 +43,107 @@ export default function InventoryInquiryPage() { }; return ( - - + + - -
- Inventory Inquiry - - Locate any cargo, container or goods inside the warehouse network. - -
- - - - - { const v = e.currentTarget.value; setDraft((f) => ({ ...f, bookingNumber: v || undefined })); }} - w={200} - /> - { const v = e.currentTarget.value; setDraft((f) => ({ ...f, containerNumber: v || undefined })); }} - w={200} - /> - { const v = e.currentTarget.value; setDraft((f) => ({ ...f, goodsName: v || undefined })); }} - w={180} - /> - setDraft((f) => ({ ...f, yardId: value ?? undefined, zoneId: undefined }))} - w={180} - /> - setDraft((f) => ({ ...f, status: (value as InventoryStatus) ?? undefined }))} - w={180} - /> - - - - - - - - - - - {isFetching ? ( -
- -
- ) : results.length === 0 ? ( - + + + { const v = e.currentTarget.value; setDraft((f) => ({ ...f, bookingNumber: v || undefined })); }} + w={200} /> - ) : ( - - )} -
-
-
+ { const v = e.currentTarget.value; setDraft((f) => ({ ...f, containerNumber: v || undefined })); }} + w={200} + /> + { const v = e.currentTarget.value; setDraft((f) => ({ ...f, goodsName: v || undefined })); }} + w={180} + /> + setDraft((f) => ({ ...f, yardId: value ?? undefined, zoneId: undefined }))} + w={180} + /> + setDraft((f) => ({ ...f, status: (value as InventoryStatus) ?? undefined }))} + w={180} + /> + + + + + + + + + + + {isFetching ? ( +
+ +
+ ) : results.length === 0 ? ( + + ) : ( + + )} +
+ ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx index 5cea3de20..99284f609 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadedInventoryPage.tsx @@ -1,7 +1,7 @@ -import { Badge, Card, Container, Group, Loader, Stack, Table, Text } from '@mantine/core'; +import { Badge, Card, Group, Loader, Table, Text } from '@mantine/core'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; -import { FreightVisual, VisualEmptyState, WarehouseHero, formatDate, formatNumber } from '@/components/warehouses'; +import { PageContainer, PageHeader } from '@/components/page'; +import { FreightVisual, VisualEmptyState, formatDate, formatNumber } from '@/components/warehouses'; import { useWarehouseLoadings } from '@/hooks/useWarehouses'; /** Record of every inventory item loaded onto a wagon. */ @@ -10,77 +10,71 @@ export default function LoadedInventoryPage() { const loadings = data ?? []; return ( - - + + - - - - - {isLoading ? ( - - - - ) : loadings.length === 0 ? ( - - ) : ( - - - - - Wagon - Warehouse - Zone - Loaded Weight (kg) - Loaded At - Status + + {isLoading ? ( + + + + ) : loadings.length === 0 ? ( + + ) : ( + +
+ + + Wagon + Warehouse + Zone + Loaded Weight (kg) + Loaded At + Status + + + + {loadings.map((l) => ( + + + + + + {l.wagonNumber ?? l.wagonId.slice(0, 8)} + + + + + {l.inventory?.warehouse + ? `${l.inventory.warehouse.name} (${l.inventory.warehouse.code})` + : '—'} + + {l.inventory?.zone ? l.inventory.zone.name : '—'} + {formatNumber(l.loadedWeight)} + {formatDate(l.loadedAt)} + + + {l.inventory?.status ?? 'LOADED'} + + - - - {loadings.map((l) => ( - - - - - - {l.wagonNumber ?? l.wagonId.slice(0, 8)} - - - - - {l.inventory?.warehouse - ? `${l.inventory.warehouse.name} (${l.inventory.warehouse.code})` - : '—'} - - {l.inventory?.zone ? l.inventory.zone.name : '—'} - {formatNumber(l.loadedWeight)} - {formatDate(l.loadedAt)} - - - {l.inventory?.status ?? 'LOADED'} - - - - ))} - -
-
- )} -
-
-
+ ))} + + + + )} + + ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx index 7bc363c09..9f8e6a64d 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/LoadingQueuePage.tsx @@ -1,13 +1,12 @@ import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Badge, Button, Card, Container, Group, Stack, Table, Tabs, Text } from '@mantine/core'; +import { Badge, Button, Card, Group, Table, Tabs, Text } from '@mantine/core'; import { CreditCard, Eye, Truck } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; +import { PageContainer, PageHeader } from '@/components/page'; import { InventoryWorkbench, VisualEmptyState, - WarehouseHero, formatNumber, } from '@/components/warehouses'; import { useAutoLoadReady, useWarehouseInventory } from '@/hooks/useWarehouses'; @@ -53,30 +52,23 @@ export default function LoadingQueuePage() { const unpaidItems = useMemo(() => readyItems.filter((i) => !isPaid(i)), [readyItems]); return ( - - - - - - - + + } loading={autoLoad.isPending} onClick={handleAutoLoad} > Auto Load Ready Items - + } + /> - - + + )} - - - - + + + ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInventoryPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInventoryPage.tsx index 8831037d1..234c37826 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInventoryPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInventoryPage.tsx @@ -1,10 +1,10 @@ import { useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { Button, Card, Container, Group, Select, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Button, Card, Group, Select, Stack, TextInput } from '@mantine/core'; import { useDebouncedValue } from '@mantine/hooks'; import { PackagePlus, Search } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; +import { PageContainer, PageHeader } from '@/components/page'; import { InventoryWorkbench, ReceiveInventoryModal, @@ -52,79 +52,73 @@ export default function WarehouseInventoryPage() { ); return ( - - - - - -
- Warehouse Inventory - - Track received items through the storage, reservation, loading and dispatch lifecycle. - -
+ + } onClick={() => setModalOpen(true)}> Receive Inventory -
+ } + /> - - - - } - value={search} - onChange={(e) => setSearch(e.currentTarget.value)} - w={220} - /> - setFilter((f) => ({ ...f, yardId: value ?? undefined, zoneId: undefined }))} - w={200} - /> - setFilter((f) => ({ ...f, status: (value as InventoryStatus) ?? undefined }))} - w={200} - /> - + + + + } + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} + w={220} + /> + setFilter((f) => ({ ...f, yardId: value ?? undefined, zoneId: undefined }))} + w={200} + /> + setFilter((f) => ({ ...f, status: (value as InventoryStatus) ?? undefined }))} + w={200} + /> + - - - - + +
+ setModalOpen(false)} /> -
+ ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInvoicesPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInvoicesPage.tsx index 3f680bf0f..ee1303a47 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInvoicesPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseInvoicesPage.tsx @@ -4,7 +4,6 @@ import { Badge, Button, Card, - Container, Divider, Group, Loader, @@ -18,8 +17,7 @@ import { } from '@mantine/core'; import { Ban, CreditCard, Eye, Search } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; -import { WarehouseHero } from '@/components/warehouses'; +import { PageContainer, PageHeader } from '@/components/page'; import { useToast } from '@/hooks/use-toast'; import { useCancelInvoice, @@ -59,18 +57,14 @@ export default function WarehouseInvoicesPage() { }, [invoices, search]); return ( - - - - + + - - + + } @@ -123,11 +117,10 @@ export default function WarehouseInvoicesPage() { )} - - + setDetailId(null)} /> - + ); } @@ -217,7 +210,7 @@ function InvoiceDetailModal({ id, onClose }: { id: string | null; onClose: () => onChange={(v) => setPayAmount(v === '' ? '' : Number(v))} style={{ flex: 1 }} /> - diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseListPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseListPage.tsx index b0d71834e..3f9df44f6 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseListPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseListPage.tsx @@ -1,10 +1,10 @@ import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Button, Card, Center, Container, Group, Loader, Stack, Text, Title } from '@mantine/core'; +import { Button, Card, Center, Loader, Stack, Text } from '@mantine/core'; import { useDebouncedValue } from '@mantine/hooks'; import { Plus } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; +import { PageContainer, PageHeader } from '@/components/page'; import { CreateWarehouseModal, WarehouseCardView, @@ -42,44 +42,38 @@ export default function WarehouseListPage() { const openDetail = (warehouse: Warehouse) => navigate(`/dashboard/warehouses/${warehouse.id}`); return ( - - - - - -
- Warehouses - - Manage warehouses, yards and zones. - -
+ + } onClick={openCreate}> Create Warehouse -
+ } + /> - - - + + + - {isLoading ? ( -
- -
- ) : isError ? ( - - Failed to load warehouses. - - ) : view === 'table' ? ( - - ) : ( - - )} -
-
-
+ {isLoading ? ( +
+ +
+ ) : isError ? ( + + Failed to load warehouses. + + ) : view === 'table' ? ( + + ) : ( + + )} +
+ setModalOpen(false)} warehouse={editing} /> -
+ ); } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseRulesPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseRulesPage.tsx index 1bfce1de1..9e9e5b522 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseRulesPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseRulesPage.tsx @@ -4,7 +4,6 @@ import { Badge, Button, Card, - Container, Group, Loader, Modal, @@ -18,8 +17,7 @@ import { } from '@mantine/core'; import { Plus, Trash2 } from 'lucide-react'; -import Breadcrumbs from '@/components/ui/Breadcrumbs'; -import { WarehouseHero } from '@/components/warehouses'; +import { PageContainer, PageHeader } from '@/components/page'; import { useToast } from '@/hooks/use-toast'; import { useAllocationRules, @@ -45,31 +43,26 @@ const clean = (s: string) => s.trim() || undefined; export default function WarehouseRulesPage() { return ( - - - - - - - - Allocation Rules - Storage / Demurrage Fees - - - - - - - - - - - + + + + + + Allocation Rules + Storage / Demurrage Fees + + + + + + + + + + ); } @@ -116,7 +109,7 @@ function AllocationRules() { <> {rules.length} rule(s) — matched by ascending priority - + {isLoading ? ( @@ -172,7 +165,7 @@ function AllocationRules() { - + @@ -222,7 +215,7 @@ function FeeRules() { <> {rules.length} rule(s) — most specific match applies - + {isLoading ? ( @@ -276,7 +269,7 @@ function FeeRules() { - +