@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.
- package/dist/{AIAssistantPage-BrHX2lQn.js → AIAssistantPage-AvsMbunM.js} +39 -33
- package/dist/{AnalyticsPage-DI6Wcaw5.js → AnalyticsPage-CCLfHgQZ.js} +44 -33
- package/dist/CreateOrderPage-CjlnEtk3.js +510 -0
- package/dist/CustomerDetailsPage-I6cdDHUi.js +265 -0
- package/dist/CustomersPage-CGGfD4ki.js +163 -0
- package/dist/{DashboardPage-3ZOnwg1a.js → DashboardPage-D2HRqwg9.js} +122 -111
- package/dist/DataTable-CD9ZhpLB.js +249 -0
- package/dist/DriverDetailsPage-rg_pGNuP.js +330 -0
- package/dist/DriversPage-DKiynISH.js +167 -0
- package/dist/FinancePage-Vg8WPs38.js +158 -0
- package/dist/{FleetPage-CPS7r4J3.js → FleetPage-DddXt8r8.js} +124 -85
- package/dist/ImportExportPage-BW6qO3kc.js +248 -0
- package/dist/InventoryPage-rMGuaJN-.js +222 -0
- package/dist/LiveTrackingPage-DQ1q4Id3.js +375 -0
- package/dist/MarketplacePage-DKrXAv62.js +219 -0
- package/dist/MetricCard-B7yMyvMX.js +146 -0
- package/dist/OrderDetailsPage-CFASgsYX.js +431 -0
- package/dist/OrdersListPage-BHeT8S5o.js +309 -0
- package/dist/{PageLayout-xDTiBTDS.js → PageLayout-D3N8MCTm.js} +213 -195
- package/dist/ProductDetailsPage-CFGcbaHo.js +195 -0
- package/dist/ProductsPage--xEpbQ8A.js +171 -0
- package/dist/{ReportsPage-B8OyWGzl.js → ReportsPage-Bb7_90rK.js} +57 -49
- package/dist/RouteDetailsPage-CVtDVb1N.js +282 -0
- package/dist/RoutesPage-s57PtgcQ.js +163 -0
- package/dist/SettingsPage-BYNCBOpN.js +298 -0
- package/dist/{StatusBadge-C--7NhoW.js → StatusBadge-CijYQXtb.js} +5 -2
- package/dist/{TrackingPage-BldUm_g7.js → TrackingPage-CcRc_dva.js} +88 -83
- package/dist/VehicleDetailsPage-3YDMPsPs.js +220 -0
- package/dist/VehiclesPage-UlxPWP9K.js +167 -0
- package/dist/WarehouseDetailsPage-Db7KeN-d.js +238 -0
- package/dist/WarehousesPage-CuTO-OPp.js +164 -0
- package/dist/{arrow-left-Bk5GsGNk.js → arrow-left-CBpZKkpq.js} +1 -1
- package/dist/{box-BAMv2-7M.js → box-CAaiElsb.js} +1 -1
- package/dist/{chart-column-CAfkf4o6.js → chart-column-D1Ym15-S.js} +1 -1
- package/dist/{chevron-right-Czrt_Qew.js → chevron-right-BIFGi0UA.js} +1 -1
- package/dist/{circle-alert-CEuV9Pij.js → circle-alert-DjmNo5_L.js} +1 -1
- package/dist/{circle-check-big-Cx8aO6B-.js → circle-check-big-CjuPVo3_.js} +1 -1
- package/dist/{clock-Be95bq7_.js → clock-BjkdnddD.js} +1 -1
- package/dist/{dollar-sign-kJqItPli.js → dollar-sign-IB4O0wuQ.js} +1 -1
- package/dist/{download-caab0D3V.js → download-Dpa9vqoG.js} +1 -1
- package/dist/{file-text-b1qhrJn1.js → file-text-C8Uioy11.js} +1 -1
- package/dist/{filter-BWmLTZB-.js → filter-Da5OZaHI.js} +1 -1
- package/dist/index.js +16 -16
- package/dist/{map-CS2aFgyO.js → map-_Per4sT9.js} +1 -1
- package/dist/{map-pin-96FeqL7H.js → map-pin-BSaf5IDL.js} +1 -1
- package/dist/{navigation-i6UXEjTC.js → navigation-DaTbrhw2.js} +1 -1
- package/dist/{package-KhSi3xaT.js → package-BE7U0wQE.js} +1 -1
- package/dist/{phone-B-h3tbsr.js → phone-DV4StZiA.js} +1 -1
- package/dist/{plus-D2BYAzMn.js → plus-Dl1rLeJR.js} +1 -1
- package/dist/{refresh-cw-D5Sy01s-.js → refresh-cw-CWfERAit.js} +1 -1
- package/dist/{route-CBDXuwH9.js → route-Dp9JiN_E.js} +1 -1
- package/dist/{save-CMc7h-Vi.js → save-XH8vydOn.js} +1 -1
- package/dist/{search-DVrUQbOg.js → search-OxoIiL_C.js} +1 -1
- package/dist/{settings-BwzIRYv3.js → settings-3Rw5NwFF.js} +1 -1
- package/dist/{square-pen-DmW36Bau.js → square-pen-hLIbFQFV.js} +1 -1
- package/dist/{star-Cv2MzxZL.js → star-YsVV3MNQ.js} +1 -1
- package/dist/{store-CLH957vl.js → store-RCBl7HB-.js} +1 -1
- package/dist/{trending-up-l8M0BO_w.js → trending-up-C-85AwGT.js} +1 -1
- package/dist/{triangle-alert-BI45s6bH.js → triangle-alert-BOhfGgmh.js} +1 -1
- package/dist/{truck-DX3lNQkz.js → truck-CtDjNFbi.js} +1 -1
- package/dist/{user-D8EY1uvt.js → user-Dz5TJZFs.js} +1 -1
- package/dist/{users-CfG0J8wP.js → users-g2N0eL-Z.js} +1 -1
- package/dist/{warehouse-Dt_bAr82.js → warehouse-D3WWDeTX.js} +1 -1
- package/dist/{wrench-C50eI_Iy.js → wrench-CmxY1n4I.js} +1 -1
- package/package.json +2 -2
- package/src/movethewheels/components/DataTable.tsx +41 -6
- package/src/movethewheels/components/MetricCard.tsx +51 -20
- package/src/movethewheels/components/PageLayout.tsx +60 -5
- package/src/movethewheels/components/StatusBadge.tsx +2 -1
- package/src/movethewheels/pages/AIAssistantPage.tsx +11 -3
- package/src/movethewheels/pages/AnalyticsPage.tsx +31 -25
- package/src/movethewheels/pages/CreateOrderPage.tsx +56 -17
- package/src/movethewheels/pages/CustomerDetailsPage.tsx +63 -38
- package/src/movethewheels/pages/CustomersPage.tsx +51 -12
- package/src/movethewheels/pages/DashboardPage.tsx +62 -48
- package/src/movethewheels/pages/DriverDetailsPage.tsx +57 -26
- package/src/movethewheels/pages/DriversPage.tsx +45 -12
- package/src/movethewheels/pages/FinancePage.tsx +45 -41
- package/src/movethewheels/pages/FleetPage.tsx +82 -34
- package/src/movethewheels/pages/ImportExportPage.tsx +46 -29
- package/src/movethewheels/pages/InventoryPage.tsx +37 -33
- package/src/movethewheels/pages/LiveTrackingPage.tsx +58 -20
- package/src/movethewheels/pages/MarketplacePage.tsx +37 -3
- package/src/movethewheels/pages/OrderDetailsPage.tsx +74 -46
- package/src/movethewheels/pages/OrdersListPage.tsx +81 -14
- package/src/movethewheels/pages/ProductDetailsPage.tsx +36 -11
- package/src/movethewheels/pages/ProductsPage.tsx +41 -12
- package/src/movethewheels/pages/ReportsPage.tsx +23 -19
- package/src/movethewheels/pages/RouteDetailsPage.tsx +71 -31
- package/src/movethewheels/pages/RoutesPage.tsx +48 -9
- package/src/movethewheels/pages/SettingsPage.tsx +68 -26
- package/src/movethewheels/pages/TrackingPage.tsx +52 -49
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +49 -24
- package/src/movethewheels/pages/VehiclesPage.tsx +41 -15
- package/src/movethewheels/pages/WarehouseDetailsPage.tsx +55 -30
- package/src/movethewheels/pages/WarehousesPage.tsx +46 -9
- package/dist/CreateOrderPage-DfkSi6JF.js +0 -471
- package/dist/CustomerDetailsPage-DzAIu_tH.js +0 -239
- package/dist/CustomersPage-d21ixOYa.js +0 -119
- package/dist/DataTable-CZGz3SJu.js +0 -239
- package/dist/DriverDetailsPage-YuZSlPSV.js +0 -297
- package/dist/DriversPage-BOhqEBTv.js +0 -127
- package/dist/FinancePage-CnjUNXOb.js +0 -154
- package/dist/ImportExportPage-zNjs7xsV.js +0 -232
- package/dist/InventoryPage-C9g5d3SW.js +0 -223
- package/dist/LiveTrackingPage-DoBvtdBG.js +0 -332
- package/dist/MarketplacePage-BEj5hcBF.js +0 -192
- package/dist/MetricCard-DeHVeVwl.js +0 -135
- package/dist/OrderDetailsPage-D-9lDZYU.js +0 -398
- package/dist/OrdersListPage-CJzHbgY3.js +0 -257
- package/dist/ProductDetailsPage-3rKtzXpy.js +0 -168
- package/dist/ProductsPage-B0P_wjBJ.js +0 -131
- package/dist/RouteDetailsPage-DGjKTUMj.js +0 -240
- package/dist/RoutesPage-CpopY8xN.js +0 -116
- package/dist/SettingsPage-BvXSa3gi.js +0 -247
- package/dist/VehicleDetailsPage-Dqv--MVW.js +0 -194
- package/dist/VehiclesPage-CCBHRDHu.js +0 -127
- package/dist/WarehouseDetailsPage-ZObC_c7W.js +0 -215
- 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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
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
|
-
|
|
81
|
-
|
|
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 {
|
|
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
|
-
<
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
Refresh
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
</
|
|
95
|
-
</
|
|
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 {
|
|
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
|
-
<
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
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
|
);
|