@burdenoff/microfe-movethewheels 2026.624.1 → 2026.626.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/{AIAssistantPage-BrHX2lQn.js → AIAssistantPage-AvsMbunM.js} +39 -33
  2. package/dist/{AnalyticsPage-DI6Wcaw5.js → AnalyticsPage-CCLfHgQZ.js} +44 -33
  3. package/dist/CreateOrderPage-CjlnEtk3.js +510 -0
  4. package/dist/CustomerDetailsPage-I6cdDHUi.js +265 -0
  5. package/dist/CustomersPage-CGGfD4ki.js +163 -0
  6. package/dist/{DashboardPage-3ZOnwg1a.js → DashboardPage-D2HRqwg9.js} +122 -111
  7. package/dist/DataTable-CD9ZhpLB.js +249 -0
  8. package/dist/DriverDetailsPage-rg_pGNuP.js +330 -0
  9. package/dist/DriversPage-DKiynISH.js +167 -0
  10. package/dist/FinancePage-Vg8WPs38.js +158 -0
  11. package/dist/{FleetPage-CPS7r4J3.js → FleetPage-DddXt8r8.js} +124 -85
  12. package/dist/ImportExportPage-BW6qO3kc.js +248 -0
  13. package/dist/InventoryPage-rMGuaJN-.js +222 -0
  14. package/dist/LiveTrackingPage-DQ1q4Id3.js +375 -0
  15. package/dist/MarketplacePage-DKrXAv62.js +219 -0
  16. package/dist/MetricCard-B7yMyvMX.js +146 -0
  17. package/dist/OrderDetailsPage-CFASgsYX.js +431 -0
  18. package/dist/OrdersListPage-BHeT8S5o.js +309 -0
  19. package/dist/{PageLayout-xDTiBTDS.js → PageLayout-D3N8MCTm.js} +213 -195
  20. package/dist/ProductDetailsPage-CFGcbaHo.js +195 -0
  21. package/dist/ProductsPage--xEpbQ8A.js +171 -0
  22. package/dist/{ReportsPage-B8OyWGzl.js → ReportsPage-Bb7_90rK.js} +57 -49
  23. package/dist/RouteDetailsPage-CVtDVb1N.js +282 -0
  24. package/dist/RoutesPage-s57PtgcQ.js +163 -0
  25. package/dist/SettingsPage-BYNCBOpN.js +298 -0
  26. package/dist/{StatusBadge-C--7NhoW.js → StatusBadge-CijYQXtb.js} +5 -2
  27. package/dist/{TrackingPage-BldUm_g7.js → TrackingPage-CcRc_dva.js} +88 -83
  28. package/dist/VehicleDetailsPage-3YDMPsPs.js +220 -0
  29. package/dist/VehiclesPage-UlxPWP9K.js +167 -0
  30. package/dist/WarehouseDetailsPage-Db7KeN-d.js +238 -0
  31. package/dist/WarehousesPage-CuTO-OPp.js +164 -0
  32. package/dist/{arrow-left-Bk5GsGNk.js → arrow-left-CBpZKkpq.js} +1 -1
  33. package/dist/{box-BAMv2-7M.js → box-CAaiElsb.js} +1 -1
  34. package/dist/{chart-column-CAfkf4o6.js → chart-column-D1Ym15-S.js} +1 -1
  35. package/dist/{chevron-right-Czrt_Qew.js → chevron-right-BIFGi0UA.js} +1 -1
  36. package/dist/{circle-alert-CEuV9Pij.js → circle-alert-DjmNo5_L.js} +1 -1
  37. package/dist/{circle-check-big-Cx8aO6B-.js → circle-check-big-CjuPVo3_.js} +1 -1
  38. package/dist/{clock-Be95bq7_.js → clock-BjkdnddD.js} +1 -1
  39. package/dist/{dollar-sign-kJqItPli.js → dollar-sign-IB4O0wuQ.js} +1 -1
  40. package/dist/{download-caab0D3V.js → download-Dpa9vqoG.js} +1 -1
  41. package/dist/{file-text-b1qhrJn1.js → file-text-C8Uioy11.js} +1 -1
  42. package/dist/{filter-BWmLTZB-.js → filter-Da5OZaHI.js} +1 -1
  43. package/dist/index.js +16 -16
  44. package/dist/{map-CS2aFgyO.js → map-_Per4sT9.js} +1 -1
  45. package/dist/{map-pin-96FeqL7H.js → map-pin-BSaf5IDL.js} +1 -1
  46. package/dist/{navigation-i6UXEjTC.js → navigation-DaTbrhw2.js} +1 -1
  47. package/dist/{package-KhSi3xaT.js → package-BE7U0wQE.js} +1 -1
  48. package/dist/{phone-B-h3tbsr.js → phone-DV4StZiA.js} +1 -1
  49. package/dist/{plus-D2BYAzMn.js → plus-Dl1rLeJR.js} +1 -1
  50. package/dist/{refresh-cw-D5Sy01s-.js → refresh-cw-CWfERAit.js} +1 -1
  51. package/dist/{route-CBDXuwH9.js → route-Dp9JiN_E.js} +1 -1
  52. package/dist/{save-CMc7h-Vi.js → save-XH8vydOn.js} +1 -1
  53. package/dist/{search-DVrUQbOg.js → search-OxoIiL_C.js} +1 -1
  54. package/dist/{settings-BwzIRYv3.js → settings-3Rw5NwFF.js} +1 -1
  55. package/dist/{square-pen-DmW36Bau.js → square-pen-hLIbFQFV.js} +1 -1
  56. package/dist/{star-Cv2MzxZL.js → star-YsVV3MNQ.js} +1 -1
  57. package/dist/{store-CLH957vl.js → store-RCBl7HB-.js} +1 -1
  58. package/dist/{trending-up-l8M0BO_w.js → trending-up-C-85AwGT.js} +1 -1
  59. package/dist/{triangle-alert-BI45s6bH.js → triangle-alert-BOhfGgmh.js} +1 -1
  60. package/dist/{truck-DX3lNQkz.js → truck-CtDjNFbi.js} +1 -1
  61. package/dist/{user-D8EY1uvt.js → user-Dz5TJZFs.js} +1 -1
  62. package/dist/{users-CfG0J8wP.js → users-g2N0eL-Z.js} +1 -1
  63. package/dist/{warehouse-Dt_bAr82.js → warehouse-D3WWDeTX.js} +1 -1
  64. package/dist/{wrench-C50eI_Iy.js → wrench-CmxY1n4I.js} +1 -1
  65. package/package.json +2 -2
  66. package/src/movethewheels/components/DataTable.tsx +41 -6
  67. package/src/movethewheels/components/MetricCard.tsx +51 -20
  68. package/src/movethewheels/components/PageLayout.tsx +60 -5
  69. package/src/movethewheels/components/StatusBadge.tsx +2 -1
  70. package/src/movethewheels/pages/AIAssistantPage.tsx +11 -3
  71. package/src/movethewheels/pages/AnalyticsPage.tsx +31 -25
  72. package/src/movethewheels/pages/CreateOrderPage.tsx +56 -17
  73. package/src/movethewheels/pages/CustomerDetailsPage.tsx +63 -38
  74. package/src/movethewheels/pages/CustomersPage.tsx +51 -12
  75. package/src/movethewheels/pages/DashboardPage.tsx +62 -48
  76. package/src/movethewheels/pages/DriverDetailsPage.tsx +57 -26
  77. package/src/movethewheels/pages/DriversPage.tsx +45 -12
  78. package/src/movethewheels/pages/FinancePage.tsx +45 -41
  79. package/src/movethewheels/pages/FleetPage.tsx +82 -34
  80. package/src/movethewheels/pages/ImportExportPage.tsx +46 -29
  81. package/src/movethewheels/pages/InventoryPage.tsx +37 -33
  82. package/src/movethewheels/pages/LiveTrackingPage.tsx +58 -20
  83. package/src/movethewheels/pages/MarketplacePage.tsx +37 -3
  84. package/src/movethewheels/pages/OrderDetailsPage.tsx +74 -46
  85. package/src/movethewheels/pages/OrdersListPage.tsx +81 -14
  86. package/src/movethewheels/pages/ProductDetailsPage.tsx +36 -11
  87. package/src/movethewheels/pages/ProductsPage.tsx +41 -12
  88. package/src/movethewheels/pages/ReportsPage.tsx +23 -19
  89. package/src/movethewheels/pages/RouteDetailsPage.tsx +71 -31
  90. package/src/movethewheels/pages/RoutesPage.tsx +48 -9
  91. package/src/movethewheels/pages/SettingsPage.tsx +68 -26
  92. package/src/movethewheels/pages/TrackingPage.tsx +52 -49
  93. package/src/movethewheels/pages/VehicleDetailsPage.tsx +49 -24
  94. package/src/movethewheels/pages/VehiclesPage.tsx +41 -15
  95. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +55 -30
  96. package/src/movethewheels/pages/WarehousesPage.tsx +46 -9
  97. package/dist/CreateOrderPage-DfkSi6JF.js +0 -471
  98. package/dist/CustomerDetailsPage-DzAIu_tH.js +0 -239
  99. package/dist/CustomersPage-d21ixOYa.js +0 -119
  100. package/dist/DataTable-CZGz3SJu.js +0 -239
  101. package/dist/DriverDetailsPage-YuZSlPSV.js +0 -297
  102. package/dist/DriversPage-BOhqEBTv.js +0 -127
  103. package/dist/FinancePage-CnjUNXOb.js +0 -154
  104. package/dist/ImportExportPage-zNjs7xsV.js +0 -232
  105. package/dist/InventoryPage-C9g5d3SW.js +0 -223
  106. package/dist/LiveTrackingPage-DoBvtdBG.js +0 -332
  107. package/dist/MarketplacePage-BEj5hcBF.js +0 -192
  108. package/dist/MetricCard-DeHVeVwl.js +0 -135
  109. package/dist/OrderDetailsPage-D-9lDZYU.js +0 -398
  110. package/dist/OrdersListPage-CJzHbgY3.js +0 -257
  111. package/dist/ProductDetailsPage-3rKtzXpy.js +0 -168
  112. package/dist/ProductsPage-B0P_wjBJ.js +0 -131
  113. package/dist/RouteDetailsPage-DGjKTUMj.js +0 -240
  114. package/dist/RoutesPage-CpopY8xN.js +0 -116
  115. package/dist/SettingsPage-BvXSa3gi.js +0 -247
  116. package/dist/VehicleDetailsPage-Dqv--MVW.js +0 -194
  117. package/dist/VehiclesPage-CCBHRDHu.js +0 -127
  118. package/dist/WarehouseDetailsPage-ZObC_c7W.js +0 -215
  119. package/dist/WarehousesPage-CpgZEVW9.js +0 -121
@@ -15,6 +15,7 @@ import {
15
15
  Badge,
16
16
  Progress,
17
17
  } from '../components/ui';
18
+ import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
18
19
  import { useVehicle } from '../hooks/useFleet';
19
20
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
20
21
  import { formatDate } from '../utils/formatters';
@@ -26,6 +27,7 @@ export default function VehicleDetailsPage() {
26
27
  const { vehicle, isLoading, error, refetch } = useVehicle(vehicleId);
27
28
 
28
29
  const goBack = () => navigate?.(joinPath(basePath, 'fleet/vehicles'));
30
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
29
31
 
30
32
  if (isLoading) return <LoadingState message="Loading vehicle details..." />;
31
33
  if (error || !vehicle) return <ErrorState title="Vehicle not found" onRetry={refetch} />;
@@ -52,33 +54,56 @@ export default function VehicleDetailsPage() {
52
54
  </div>
53
55
  }
54
56
  >
57
+ <PagePurpose icon={<Truck size={18} />}>
58
+ The full record for this vehicle — specs, capacity, fuel and mileage, maintenance schedule
59
+ and current location. Use it to confirm a vehicle is fuelled, serviced and the right size
60
+ before dispatching it on a delivery.
61
+ </PagePurpose>
62
+
63
+ <NextSteps
64
+ storageKey="movethewheels-vehicle-details"
65
+ steps={[
66
+ {
67
+ id: 'assign',
68
+ label: 'Assign to a delivery',
69
+ description: 'Put this vehicle on an order that fits its capacity.',
70
+ icon: <MapPin size={16} />,
71
+ onClick: () => goTo('orders'),
72
+ },
73
+ {
74
+ id: 'maintenance',
75
+ label: 'Schedule maintenance',
76
+ description: 'Keep it road-ready and compliant.',
77
+ icon: <Wrench size={16} />,
78
+ onClick: () => {},
79
+ },
80
+ ]}
81
+ />
82
+
55
83
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
56
84
  <div className="lg:col-span-2 space-y-6">
57
- <Card>
58
- <CardHeader>
59
- <CardTitle>Vehicle Information</CardTitle>
60
- </CardHeader>
61
- <CardContent>
62
- <div className="grid grid-cols-2 md:grid-cols-4 gap-6">
63
- <div>
64
- <p className="text-sm text-text-secondary">Type</p>
65
- <p className="font-medium capitalize">{vehicle.type}</p>
66
- </div>
67
- <div>
68
- <p className="text-sm text-text-secondary">Make</p>
69
- <p className="font-medium">{vehicle.make}</p>
70
- </div>
71
- <div>
72
- <p className="text-sm text-text-secondary">Model</p>
73
- <p className="font-medium">{vehicle.model}</p>
74
- </div>
75
- <div>
76
- <p className="text-sm text-text-secondary">Year</p>
77
- <p className="font-medium">{vehicle.year}</p>
78
- </div>
85
+ {/* Vehicle Information — the page's single emphasis zone */}
86
+ <EmphasisPanel>
87
+ <h2 className="text-base font-semibold text-text-primary mb-4">Vehicle Information</h2>
88
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-6">
89
+ <div>
90
+ <p className="text-sm text-text-secondary">Type</p>
91
+ <p className="font-medium capitalize">{vehicle.type}</p>
79
92
  </div>
80
- </CardContent>
81
- </Card>
93
+ <div>
94
+ <p className="text-sm text-text-secondary">Make</p>
95
+ <p className="font-medium">{vehicle.make}</p>
96
+ </div>
97
+ <div>
98
+ <p className="text-sm text-text-secondary">Model</p>
99
+ <p className="font-medium">{vehicle.model}</p>
100
+ </div>
101
+ <div>
102
+ <p className="text-sm text-text-secondary">Year</p>
103
+ <p className="font-medium">{vehicle.year}</p>
104
+ </div>
105
+ </div>
106
+ </EmphasisPanel>
82
107
 
83
108
  <Card>
84
109
  <CardHeader>
@@ -6,7 +6,8 @@ import { Truck, Plus, RefreshCw, Download } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
8
  import { StatusBadge, VehicleTypeBadge } from '../components/StatusBadge';
9
- import { Button, Progress } from '../components/ui';
9
+ import { Progress } from '../components/ui';
10
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
10
11
  import { useVehicles } from '../hooks/useFleet';
11
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
13
  import { joinPath } from '../utils/navigation';
@@ -93,22 +94,44 @@ export default function VehiclesPage() {
93
94
  subtitle={`${totalVehicles} vehicles in fleet`}
94
95
  icon={<Truck size={24} />}
95
96
  headerActions={
96
- <div className="flex gap-2">
97
- <Button variant="outline" onClick={refetch}>
98
- <RefreshCw size={16} />
99
- Refresh
100
- </Button>
101
- <Button variant="outline">
102
- <Download size={16} />
103
- Export
104
- </Button>
105
- <Button>
106
- <Plus size={16} />
107
- Add Vehicle
108
- </Button>
109
- </div>
97
+ <CTAOverflowMenu
98
+ primary={{ label: 'Add Vehicle', icon: <Plus size={16} />, onSelect: () => {} }}
99
+ actions={[
100
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
101
+ { label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
102
+ ]}
103
+ />
110
104
  }
111
105
  >
106
+ <PagePurpose icon={<Truck size={18} />}>
107
+ Every truck, van and bike in your fleet. Monitor capacity, fuel level, mileage and
108
+ maintenance status here so you always know which vehicles are road-ready before dispatching
109
+ an order.
110
+ </PagePurpose>
111
+
112
+ {/* Fleet at a glance — the page's single emphasis zone */}
113
+ <EmphasisPanel>
114
+ <p className="text-sm font-medium text-text-secondary">Fleet at a glance</p>
115
+ <div className="mt-3 grid grid-cols-3 gap-4">
116
+ <div>
117
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalVehicles}</p>
118
+ <p className="text-xs text-text-secondary">Total vehicles</p>
119
+ </div>
120
+ <div>
121
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
122
+ {vehicles.filter((v) => v.status === 'available').length}
123
+ </p>
124
+ <p className="text-xs text-text-secondary">Available now</p>
125
+ </div>
126
+ <div>
127
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
128
+ {vehicles.filter((v) => v.status === 'maintenance').length}
129
+ </p>
130
+ <p className="text-xs text-text-secondary">In maintenance</p>
131
+ </div>
132
+ </div>
133
+ </EmphasisPanel>
134
+
112
135
  <DataTable
113
136
  columns={columns}
114
137
  data={vehicles}
@@ -118,6 +141,9 @@ export default function VehiclesPage() {
118
141
  searchFields={['vehicleNumber', 'make', 'model'] as (keyof Vehicle)[]}
119
142
  onRowClick={(row) => goTo(`fleet/vehicles/${row.id}`)}
120
143
  getRowId={(row) => row.id}
144
+ emptyIllustration="empty-data"
145
+ emptyTitle="No vehicles yet"
146
+ emptyDescription="Add vehicles to your fleet to start assigning them to deliveries."
121
147
  />
122
148
  </PageLayout>
123
149
  );
@@ -14,6 +14,7 @@ import {
14
14
  Badge,
15
15
  Progress,
16
16
  } from '../components/ui';
17
+ import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
17
18
  import { useWarehouse } from '../hooks/useInventory';
18
19
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
19
20
  import { formatAddress } from '../utils/formatters';
@@ -25,6 +26,7 @@ export default function WarehouseDetailsPage() {
25
26
  const { warehouse, isLoading, error, refetch } = useWarehouse(warehouseId);
26
27
 
27
28
  const goBack = () => navigate?.(joinPath(basePath, 'inventory/warehouses'));
29
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
28
30
 
29
31
  if (isLoading) return <LoadingState message="Loading warehouse details..." />;
30
32
  if (error || !warehouse) return <ErrorState title="Warehouse not found" onRetry={refetch} />;
@@ -57,42 +59,65 @@ export default function WarehouseDetailsPage() {
57
59
  </div>
58
60
  }
59
61
  >
62
+ <PagePurpose icon={<Warehouse size={18} />}>
63
+ A storage and fulfilment site at a glance — how full it is, its zones, operating hours,
64
+ throughput and staff. Use it to decide whether this warehouse has the space and hours to
65
+ fulfil an order, and where stock is running tight.
66
+ </PagePurpose>
67
+
68
+ <NextSteps
69
+ storageKey="movethewheels-warehouse-details"
70
+ steps={[
71
+ {
72
+ id: 'inventory',
73
+ label: 'Review stock here',
74
+ description: 'See which products are stored at this site.',
75
+ icon: <Box size={16} />,
76
+ onClick: () => goTo('inventory/products'),
77
+ },
78
+ {
79
+ id: 'fulfil',
80
+ label: 'Fulfil an order from this site',
81
+ description: 'Pick a pending order to ship out of this warehouse.',
82
+ icon: <MapPin size={16} />,
83
+ onClick: () => goTo('orders'),
84
+ },
85
+ ]}
86
+ />
87
+
60
88
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
61
89
  <div className="lg:col-span-2 space-y-6">
62
- <Card>
63
- <CardHeader>
64
- <CardTitle className="flex items-center gap-2">
65
- <Box size={18} /> Capacity
66
- </CardTitle>
67
- </CardHeader>
68
- <CardContent>
69
- <div className="space-y-4">
90
+ {/* Capacity — the page's single emphasis zone */}
91
+ <EmphasisPanel>
92
+ <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary mb-4">
93
+ <Box size={18} /> Capacity
94
+ </h2>
95
+ <div className="space-y-4">
96
+ <div>
97
+ <div className="flex justify-between text-sm mb-2">
98
+ <span>Space Utilization</span>
99
+ <span>{utilization.toFixed(0)}%</span>
100
+ </div>
101
+ <Progress value={utilization} />
102
+ <p className="text-sm text-text-secondary mt-1">
103
+ {warehouse.capacity.usedSpace.toLocaleString()} /{' '}
104
+ {warehouse.capacity.totalSpace.toLocaleString()} sq ft
105
+ </p>
106
+ </div>
107
+ <div className="grid grid-cols-2 gap-4">
70
108
  <div>
71
- <div className="flex justify-between text-sm mb-2">
72
- <span>Space Utilization</span>
73
- <span>{utilization.toFixed(0)}%</span>
74
- </div>
75
- <Progress value={utilization} />
76
- <p className="text-sm text-text-secondary mt-1">
77
- {warehouse.capacity.usedSpace.toLocaleString()} /{' '}
78
- {warehouse.capacity.totalSpace.toLocaleString()} sq ft
109
+ <p className="text-sm text-text-secondary">Pallets Used</p>
110
+ <p className="text-2xl font-bold">
111
+ {warehouse.capacity.usedPallets}
112
+ <span className="text-sm font-normal text-text-secondary">
113
+ {' '}
114
+ / {warehouse.capacity.totalPallets}
115
+ </span>
79
116
  </p>
80
117
  </div>
81
- <div className="grid grid-cols-2 gap-4">
82
- <div>
83
- <p className="text-sm text-text-secondary">Pallets Used</p>
84
- <p className="text-2xl font-bold">
85
- {warehouse.capacity.usedPallets}
86
- <span className="text-sm font-normal text-text-secondary">
87
- {' '}
88
- / {warehouse.capacity.totalPallets}
89
- </span>
90
- </p>
91
- </div>
92
- </div>
93
118
  </div>
94
- </CardContent>
95
- </Card>
119
+ </div>
120
+ </EmphasisPanel>
96
121
 
97
122
  <Card>
98
123
  <CardHeader>
@@ -5,7 +5,8 @@
5
5
  import { Warehouse, Plus, RefreshCw } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
- import { Button, Badge, Progress } from '../components/ui';
8
+ import { Badge, Progress } from '../components/ui';
9
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
9
10
  import { useWarehouses } from '../hooks/useInventory';
10
11
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
11
12
  import { joinPath } from '../utils/navigation';
@@ -97,16 +98,49 @@ export default function WarehousesPage() {
97
98
  subtitle={`${totalWarehouses} warehouses`}
98
99
  icon={<Warehouse size={24} />}
99
100
  headerActions={
100
- <div className="flex gap-2">
101
- <Button variant="outline" onClick={refetch}>
102
- <RefreshCw size={16} /> Refresh
103
- </Button>
104
- <Button>
105
- <Plus size={16} /> Add Warehouse
106
- </Button>
107
- </div>
101
+ <CTAOverflowMenu
102
+ primary={{ label: 'Add Warehouse', icon: <Plus size={16} />, onSelect: () => {} }}
103
+ actions={[{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() }]}
104
+ />
108
105
  }
109
106
  >
107
+ <PagePurpose icon={<Warehouse size={18} />}>
108
+ Your storage and fulfilment sites. Watch space and pallet utilization across each warehouse
109
+ to balance stock, spot capacity crunches, and decide where to fulfil an order from.
110
+ </PagePurpose>
111
+
112
+ {/* Network at a glance — the page's single emphasis zone */}
113
+ <EmphasisPanel>
114
+ <p className="text-sm font-medium text-text-secondary">Network at a glance</p>
115
+ <div className="mt-3 grid grid-cols-3 gap-4">
116
+ <div>
117
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalWarehouses}</p>
118
+ <p className="text-xs text-text-secondary">Total sites</p>
119
+ </div>
120
+ <div>
121
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
122
+ {warehouses.filter((w) => w.isActive).length}
123
+ </p>
124
+ <p className="text-xs text-text-secondary">Active</p>
125
+ </div>
126
+ <div>
127
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
128
+ {warehouses.length > 0
129
+ ? `${Math.round(
130
+ (warehouses.reduce(
131
+ (sum, w) => sum + w.capacity.usedSpace / w.capacity.totalSpace,
132
+ 0
133
+ ) /
134
+ warehouses.length) *
135
+ 100
136
+ )}%`
137
+ : '—'}
138
+ </p>
139
+ <p className="text-xs text-text-secondary">Avg utilization</p>
140
+ </div>
141
+ </div>
142
+ </EmphasisPanel>
143
+
110
144
  <DataTable
111
145
  columns={columns}
112
146
  data={warehouses}
@@ -116,6 +150,9 @@ export default function WarehousesPage() {
116
150
  searchFields={['name', 'code'] as (keyof WarehouseType)[]}
117
151
  onRowClick={(row) => goTo(`inventory/warehouses/${row.id}`)}
118
152
  getRowId={(row) => row.id}
153
+ emptyIllustration="empty-data"
154
+ emptyTitle="No warehouses yet"
155
+ emptyDescription="Add a warehouse to store inventory and fulfil orders from it."
119
156
  />
120
157
  </PageLayout>
121
158
  );