@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
@@ -6,6 +6,7 @@ import { BarChart3, TrendingUp, Package, Truck, DollarSign, Users } from 'lucide
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { MetricCard, MetricGrid } from '../components/MetricCard';
8
8
  import { Card, CardContent, CardHeader, CardTitle, Progress } from '../components/ui';
9
+ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
9
10
  import { useAnalytics, useOrderAnalytics, useFleetAnalytics } from '../hooks/useAnalytics';
10
11
  import { formatCurrency } from '../utils/formatters';
11
12
 
@@ -20,6 +21,12 @@ export default function AnalyticsPage() {
20
21
  subtitle="Business performance and insights"
21
22
  icon={<BarChart3 size={24} />}
22
23
  >
24
+ <PagePurpose icon={<BarChart3 size={18} />}>
25
+ See how the operation is really performing. Track order volume, revenue, on-time rate and
26
+ customer satisfaction over time so you can spot trends, find bottlenecks, and decide where
27
+ to invest — whether that&apos;s more vehicles, better routes, or new customers.
28
+ </PagePurpose>
29
+
23
30
  <MetricGrid columns={5}>
24
31
  <MetricCard
25
32
  label="Total Orders"
@@ -30,6 +37,8 @@ export default function AnalyticsPage() {
30
37
  trend="up"
31
38
  />
32
39
  <MetricCard
40
+ treatment="glass"
41
+ glow
33
42
  label="Revenue"
34
43
  value={formatCurrency(analytics.overview.totalRevenue)}
35
44
  icon={<DollarSign size={20} />}
@@ -159,31 +168,28 @@ export default function AnalyticsPage() {
159
168
  </CardContent>
160
169
  </Card>
161
170
 
162
- <Card>
163
- <CardHeader>
164
- <CardTitle>Performance Metrics</CardTitle>
165
- </CardHeader>
166
- <CardContent className="space-y-4">
167
- <div>
168
- <p className="text-sm text-text-secondary">On-Time Pickup</p>
169
- <p className="text-2xl font-bold">{analytics.performance.onTimePickup}%</p>
170
- </div>
171
- <div>
172
- <p className="text-sm text-text-secondary">On-Time Delivery</p>
173
- <p className="text-2xl font-bold">{analytics.performance.onTimeDelivery}%</p>
174
- </div>
175
- <div>
176
- <p className="text-sm text-text-secondary">Damaged Items</p>
177
- <p className="text-2xl font-bold text-green-600">
178
- {analytics.performance.damagedItems}%
179
- </p>
180
- </div>
181
- <div>
182
- <p className="text-sm text-text-secondary">Driver Ratings</p>
183
- <p className="text-2xl font-bold">{analytics.performance.driverRatings}/5</p>
184
- </div>
185
- </CardContent>
186
- </Card>
171
+ {/* Performance Metrics — the page's single emphasis zone */}
172
+ <EmphasisPanel className="space-y-4">
173
+ <h2 className="text-base font-semibold text-text-primary">Performance Metrics</h2>
174
+ <div>
175
+ <p className="text-sm text-text-secondary">On-Time Pickup</p>
176
+ <p className="text-2xl font-bold">{analytics.performance.onTimePickup}%</p>
177
+ </div>
178
+ <div>
179
+ <p className="text-sm text-text-secondary">On-Time Delivery</p>
180
+ <p className="text-2xl font-bold">{analytics.performance.onTimeDelivery}%</p>
181
+ </div>
182
+ <div>
183
+ <p className="text-sm text-text-secondary">Damaged Items</p>
184
+ <p className="text-2xl font-bold text-status-success-text">
185
+ {analytics.performance.damagedItems}%
186
+ </p>
187
+ </div>
188
+ <div>
189
+ <p className="text-sm text-text-secondary">Driver Ratings</p>
190
+ <p className="text-2xl font-bold">{analytics.performance.driverRatings}/5</p>
191
+ </div>
192
+ </EmphasisPanel>
187
193
  </div>
188
194
  </PageLayout>
189
195
  );
@@ -6,8 +6,8 @@
6
6
 
7
7
  import { useState } from 'react';
8
8
  import { useParams } from 'react-router-dom';
9
- import { Package, ArrowLeft, Save, Plus, Trash2 } from 'lucide-react';
10
- import { PageLayout } from '../components/PageLayout';
9
+ import { Package, ArrowLeft, Save, Plus, Trash2, Users, MapPin } from 'lucide-react';
10
+ import { PageLayout, EmptyState } from '../components/PageLayout';
11
11
  import {
12
12
  Card,
13
13
  CardContent,
@@ -24,6 +24,7 @@ import {
24
24
  SelectValue,
25
25
  Separator,
26
26
  } from '../components/ui';
27
+ import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
27
28
  import { useOrder, useOrders } from '../hooks/useOrders';
28
29
  import { useCustomers } from '../hooks/useCustomers';
29
30
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
@@ -171,13 +172,47 @@ export default function CreateOrderPage() {
171
172
  </div>
172
173
  }
173
174
  >
175
+ <PagePurpose icon={<Package size={18} />}>
176
+ {isEditing
177
+ ? 'Update this delivery before it goes out — change the customer, addresses, items or handling notes, then save.'
178
+ : 'Book a new delivery in a few steps: choose who it’s for, set pickup and drop-off addresses, list what’s being shipped, and add any handling notes. Once created it joins the orders pipeline ready to assign and track.'}
179
+ </PagePurpose>
180
+
181
+ <NextSteps
182
+ storageKey="movethewheels-create-order"
183
+ steps={[
184
+ {
185
+ id: 'customer',
186
+ label: 'Pick the customer first',
187
+ description: 'Their saved contact details auto-fill the order.',
188
+ icon: <Users size={16} />,
189
+ done: !!formData.customerId,
190
+ onClick: () => document.getElementById('customer')?.focus(),
191
+ },
192
+ {
193
+ id: 'addresses',
194
+ label: 'Set pickup & delivery addresses',
195
+ description: 'Where the shipment is collected and dropped off.',
196
+ icon: <MapPin size={16} />,
197
+ done: !!formData.pickupAddress.street && !!formData.deliveryAddress.street,
198
+ onClick: () => document.getElementById('pickupStreet')?.focus(),
199
+ },
200
+ {
201
+ id: 'items',
202
+ label: 'Add the items to ship',
203
+ description: 'List each product with its quantity and value.',
204
+ icon: <Package size={16} />,
205
+ done: formData.items.length > 0,
206
+ onClick: addItem,
207
+ },
208
+ ]}
209
+ />
210
+
174
211
  <form onSubmit={handleSubmit} className="space-y-6">
175
- {/* Order Details */}
176
- <Card>
177
- <CardHeader>
178
- <CardTitle>Order Details</CardTitle>
179
- </CardHeader>
180
- <CardContent className="space-y-4">
212
+ {/* Order Details — the page's single emphasis zone (the form's starting point) */}
213
+ <EmphasisPanel>
214
+ <h2 className="text-base font-semibold text-text-primary mb-4">Order Details</h2>
215
+ <div className="space-y-4">
181
216
  <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
182
217
  <div className="space-y-2">
183
218
  <Label htmlFor="customer">Customer</Label>
@@ -230,8 +265,8 @@ export default function CreateOrderPage() {
230
265
  </Select>
231
266
  </div>
232
267
  </div>
233
- </CardContent>
234
- </Card>
268
+ </div>
269
+ </EmphasisPanel>
235
270
 
236
271
  {/* Addresses */}
237
272
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
@@ -363,13 +398,17 @@ export default function CreateOrderPage() {
363
398
  </CardHeader>
364
399
  <CardContent>
365
400
  {formData.items.length === 0 ? (
366
- <div className="text-center py-8 text-text-secondary">
367
- <Package size={48} className="mx-auto mb-4 opacity-50" />
368
- <p>No items added yet</p>
369
- <Button type="button" variant="link" onClick={addItem}>
370
- Add your first item
371
- </Button>
372
- </div>
401
+ <EmptyState
402
+ illustration="empty-files"
403
+ title="No items added yet"
404
+ description="Add the products this order will ship — each with a name, SKU, quantity and value."
405
+ action={
406
+ <Button type="button" variant="outline" onClick={addItem}>
407
+ <Plus size={16} className="mr-1.5" />
408
+ Add your first item
409
+ </Button>
410
+ }
411
+ />
373
412
  ) : (
374
413
  <div className="space-y-4">
375
414
  {formData.items.map((item, index) => (
@@ -17,6 +17,7 @@ import {
17
17
  import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
18
18
  import { TypeBadge } from '../components/StatusBadge';
19
19
  import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
20
+ import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
20
21
  import { useCustomer } from '../hooks/useCustomers';
21
22
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
22
23
  import { formatAddress, formatDate } from '../utils/formatters';
@@ -28,6 +29,7 @@ export default function CustomerDetailsPage() {
28
29
  const { customer, isLoading, error, refetch } = useCustomer(customerId);
29
30
 
30
31
  const goBack = () => navigate?.(joinPath(basePath, 'customers'));
32
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
31
33
 
32
34
  // Handle new customer form
33
35
  if (!customerId) {
@@ -82,52 +84,75 @@ export default function CustomerDetailsPage() {
82
84
  </div>
83
85
  }
84
86
  >
87
+ <PagePurpose icon={<Users size={18} />}>
88
+ Everything you know about this customer — how to reach them, where they are, and their
89
+ account standing. Use it to confirm contact details before a delivery, check their rating,
90
+ or book their next order.
91
+ </PagePurpose>
92
+
93
+ <NextSteps
94
+ storageKey="movethewheels-customer-details"
95
+ steps={[
96
+ {
97
+ id: 'new-order',
98
+ label: 'Book a delivery for this customer',
99
+ description: 'Start a new order pre-filled for this account.',
100
+ icon: <FileText size={16} />,
101
+ onClick: () => goTo('orders/new'),
102
+ },
103
+ {
104
+ id: 'edit',
105
+ label: 'Update contact details',
106
+ description: 'Keep email, phone and address current.',
107
+ icon: <Edit size={16} />,
108
+ onClick: () => {},
109
+ },
110
+ ]}
111
+ />
112
+
85
113
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
86
114
  <div className="lg:col-span-2 space-y-6">
87
- <Card>
88
- <CardHeader>
89
- <CardTitle>Contact Information</CardTitle>
90
- </CardHeader>
91
- <CardContent>
92
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
93
- <div className="space-y-4">
94
- <div className="flex items-center gap-3">
95
- <Mail size={18} className="text-text-secondary" />
96
- <div>
97
- <p className="text-sm text-text-secondary">Email</p>
98
- <p className="font-medium">{customer.email}</p>
99
- </div>
115
+ {/* Contact Information — the page's single emphasis zone */}
116
+ <EmphasisPanel>
117
+ <h2 className="text-base font-semibold text-text-primary mb-4">Contact Information</h2>
118
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
119
+ <div className="space-y-4">
120
+ <div className="flex items-center gap-3">
121
+ <Mail size={18} className="text-text-secondary" />
122
+ <div>
123
+ <p className="text-sm text-text-secondary">Email</p>
124
+ <p className="font-medium">{customer.email}</p>
100
125
  </div>
101
- <div className="flex items-center gap-3">
102
- <Phone size={18} className="text-text-secondary" />
103
- <div>
104
- <p className="text-sm text-text-secondary">Phone</p>
105
- <p className="font-medium">{customer.phone}</p>
106
- </div>
126
+ </div>
127
+ <div className="flex items-center gap-3">
128
+ <Phone size={18} className="text-text-secondary" />
129
+ <div>
130
+ <p className="text-sm text-text-secondary">Phone</p>
131
+ <p className="font-medium">{customer.phone}</p>
107
132
  </div>
108
133
  </div>
109
- <div className="space-y-4">
110
- {customer.company && (
111
- <div className="flex items-center gap-3">
112
- <Building size={18} className="text-text-secondary" />
113
- <div>
114
- <p className="text-sm text-text-secondary">Company</p>
115
- <p className="font-medium">{customer.company}</p>
116
- </div>
117
- </div>
118
- )}
119
- {customer.website && (
134
+ </div>
135
+ <div className="space-y-4">
136
+ {customer.company && (
137
+ <div className="flex items-center gap-3">
138
+ <Building size={18} className="text-text-secondary" />
120
139
  <div>
121
- <p className="text-sm text-text-secondary">Website</p>
122
- <a href={customer.website} className="text-primary hover:underline">
123
- {customer.website}
124
- </a>
140
+ <p className="text-sm text-text-secondary">Company</p>
141
+ <p className="font-medium">{customer.company}</p>
125
142
  </div>
126
- )}
127
- </div>
143
+ </div>
144
+ )}
145
+ {customer.website && (
146
+ <div>
147
+ <p className="text-sm text-text-secondary">Website</p>
148
+ <a href={customer.website} className="text-primary hover:underline">
149
+ {customer.website}
150
+ </a>
151
+ </div>
152
+ )}
128
153
  </div>
129
- </CardContent>
130
- </Card>
154
+ </div>
155
+ </EmphasisPanel>
131
156
 
132
157
  <Card>
133
158
  <CardHeader>
@@ -6,7 +6,8 @@ import { Users, Plus, RefreshCw, Download, Star } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
8
  import { TypeBadge } from '../components/StatusBadge';
9
- import { Button, Badge, Avatar, AvatarFallback } from '../components/ui';
9
+ import { Badge, Avatar, AvatarFallback, Button } from '../components/ui';
10
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
10
11
  import { useCustomers } from '../hooks/useCustomers';
11
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
13
  import { formatDate } from '../utils/formatters';
@@ -87,19 +88,48 @@ export default function CustomersPage() {
87
88
  subtitle={`${totalCustomers} customers`}
88
89
  icon={<Users size={24} />}
89
90
  headerActions={
90
- <div className="flex gap-2">
91
- <Button variant="outline" onClick={refetch}>
92
- <RefreshCw size={16} /> Refresh
93
- </Button>
94
- <Button variant="outline">
95
- <Download size={16} /> Export
96
- </Button>
97
- <Button onClick={() => goTo('customers/new')}>
98
- <Plus size={16} /> Add Customer
99
- </Button>
100
- </div>
91
+ <CTAOverflowMenu
92
+ primary={{
93
+ label: 'Add Customer',
94
+ icon: <Plus size={16} />,
95
+ onSelect: () => goTo('customers/new'),
96
+ }}
97
+ actions={[
98
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
99
+ { label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
100
+ ]}
101
+ />
101
102
  }
102
103
  >
104
+ <PagePurpose icon={<Users size={18} />}>
105
+ The businesses and individuals you deliver for. Keep contact details, locations and
106
+ satisfaction ratings here, and open a customer to see their order history before booking the
107
+ next shipment.
108
+ </PagePurpose>
109
+
110
+ {/* Customer base at a glance — the page's single emphasis zone */}
111
+ <EmphasisPanel>
112
+ <p className="text-sm font-medium text-text-secondary">Customer base at a glance</p>
113
+ <div className="mt-3 grid grid-cols-3 gap-4">
114
+ <div>
115
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalCustomers}</p>
116
+ <p className="text-xs text-text-secondary">Total customers</p>
117
+ </div>
118
+ <div>
119
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
120
+ {customers.filter((c) => c.isActive).length}
121
+ </p>
122
+ <p className="text-xs text-text-secondary">Active</p>
123
+ </div>
124
+ <div>
125
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
126
+ {customers.filter((c) => c.type === 'b2b').length}
127
+ </p>
128
+ <p className="text-xs text-text-secondary">Business accounts</p>
129
+ </div>
130
+ </div>
131
+ </EmphasisPanel>
132
+
103
133
  <DataTable
104
134
  columns={columns}
105
135
  data={customers}
@@ -109,6 +139,15 @@ export default function CustomersPage() {
109
139
  searchFields={['name', 'email', 'company'] as (keyof Customer)[]}
110
140
  onRowClick={(row) => goTo(`customers/${row.id}`)}
111
141
  getRowId={(row) => row.id}
142
+ emptyIllustration="empty-people"
143
+ emptyTitle="No customers yet"
144
+ emptyDescription="Add your first customer to start booking deliveries for them."
145
+ emptyAction={
146
+ <Button onClick={() => goTo('customers/new')}>
147
+ <Plus size={16} className="mr-1.5" />
148
+ Add Customer
149
+ </Button>
150
+ }
112
151
  />
113
152
  </PageLayout>
114
153
  );
@@ -27,6 +27,7 @@ import {
27
27
  Badge,
28
28
  Progress,
29
29
  } from '../components/ui';
30
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
30
31
  import { useDashboardMetrics } from '../hooks/useAnalytics';
31
32
  import { useOrders, useOrderStats } from '../hooks/useOrders';
32
33
  import { useFleetStats } from '../hooks/useFleet';
@@ -57,22 +58,35 @@ export default function DashboardPage() {
57
58
 
58
59
  return (
59
60
  <PageLayout
61
+ hero
62
+ titleAccent={t('movethewheels.dashboard.title', 'Dashboard')}
60
63
  title={t('movethewheels.dashboard.title', 'Dashboard')}
61
64
  subtitle={t('movethewheels.dashboard.subtitle', 'Overview of your logistics operations')}
62
65
  icon={<TrendingUp size={24} />}
63
66
  headerActions={
64
- <div className="flex gap-2">
65
- <Button variant="outline" onClick={() => goTo('tracking/live')}>
66
- <MapPin size={16} />
67
- {t('movethewheels.dashboard.actions.liveMap', 'Live Map')}
68
- </Button>
69
- <Button onClick={() => goTo('orders/new')}>
70
- <Package size={16} />
71
- {t('movethewheels.dashboard.actions.newOrder', 'New Order')}
72
- </Button>
73
- </div>
67
+ <CTAOverflowMenu
68
+ primary={{
69
+ label: t('movethewheels.dashboard.actions.newOrder', 'New Order'),
70
+ icon: <Package size={16} />,
71
+ onSelect: () => goTo('orders/new'),
72
+ }}
73
+ actions={[
74
+ {
75
+ label: t('movethewheels.dashboard.actions.liveMap', 'Live Map'),
76
+ icon: <MapPin size={16} />,
77
+ onSelect: () => goTo('tracking/live'),
78
+ },
79
+ ]}
80
+ />
74
81
  }
75
82
  >
83
+ <PagePurpose icon={<TrendingUp size={18} />}>
84
+ {t(
85
+ 'movethewheels.dashboard.purpose',
86
+ 'Your logistics command center — a live snapshot of orders, active deliveries, fleet health and revenue. Start here each day to spot what needs attention, then jump straight into an order, the live map or fleet status.'
87
+ )}
88
+ </PagePurpose>
89
+
76
90
  {/* Key Metrics */}
77
91
  <MetricGrid columns={4}>
78
92
  <MetricCard
@@ -99,6 +113,8 @@ export default function DashboardPage() {
99
113
  onClick={() => goTo('fleet')}
100
114
  />
101
115
  <MetricCard
116
+ treatment="glass"
117
+ glow
102
118
  label={t('movethewheels.dashboard.metrics.revenue', 'Revenue')}
103
119
  value={formatCurrency(metrics.revenue.total)}
104
120
  icon={<DollarSign size={20} />}
@@ -234,45 +250,43 @@ export default function DashboardPage() {
234
250
  </div>
235
251
 
236
252
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
237
- {/* Order Status Summary */}
238
- <Card>
239
- <CardHeader>
240
- <CardTitle className="text-base">
241
- {t('movethewheels.dashboard.orderStatus.title', 'Order Status')}
242
- </CardTitle>
243
- </CardHeader>
244
- <CardContent className="space-y-4">
245
- <div className="space-y-3">
246
- {[
247
- { status: 'pending', count: orderStats.byStatus.pending, color: 'bg-yellow-500' },
248
- {
249
- status: 'in_transit',
250
- count: orderStats.byStatus.in_transit,
251
- color: 'bg-blue-500',
252
- },
253
- {
254
- status: 'delivered',
255
- count: orderStats.byStatus.delivered,
256
- color: 'bg-green-500',
257
- },
258
- { status: 'cancelled', count: orderStats.byStatus.cancelled, color: 'bg-red-500' },
259
- ].map(({ status, count, color }) => (
260
- <div key={status} className="flex items-center justify-between">
261
- <div className="flex items-center gap-2">
262
- <div className={`w-2 h-2 rounded-full ${color}`} />
263
- <span className="text-sm capitalize">
264
- {t(
265
- `movethewheels.dashboard.orderStatus.status.${status}`,
266
- status.replace('_', ' ')
267
- )}
268
- </span>
269
- </div>
270
- <Badge variant="secondary">{count}</Badge>
253
+ {/* Order Status Summary — the page's single emphasis zone */}
254
+ <EmphasisPanel className="space-y-4">
255
+ <h2 className="text-base font-semibold text-text-primary">
256
+ {t('movethewheels.dashboard.orderStatus.title', 'Order Status')}
257
+ </h2>
258
+ <div className="space-y-3">
259
+ {[
260
+ { status: 'pending', count: orderStats.byStatus.pending, color: 'bg-yellow-500' },
261
+ {
262
+ status: 'in_transit',
263
+ count: orderStats.byStatus.in_transit,
264
+ color: 'bg-blue-500',
265
+ },
266
+ {
267
+ status: 'delivered',
268
+ count: orderStats.byStatus.delivered,
269
+ color: 'bg-green-500',
270
+ },
271
+ { status: 'cancelled', count: orderStats.byStatus.cancelled, color: 'bg-red-500' },
272
+ ].map(({ status, count, color }) => (
273
+ <div key={status} className="flex items-center justify-between">
274
+ <div className="flex items-center gap-2">
275
+ <div className={`w-2 h-2 rounded-full ${color}`} />
276
+ <span className="text-sm capitalize">
277
+ {t(
278
+ `movethewheels.dashboard.orderStatus.status.${status}`,
279
+ status.replace('_', ' ')
280
+ )}
281
+ </span>
271
282
  </div>
272
- ))}
273
- </div>
274
- </CardContent>
275
- </Card>
283
+ <Badge variant="secondary" className="tabular-nums">
284
+ {count}
285
+ </Badge>
286
+ </div>
287
+ ))}
288
+ </div>
289
+ </EmphasisPanel>
276
290
 
277
291
  {/* Fleet Status */}
278
292
  <Card>