@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
@@ -5,7 +5,8 @@
5
5
  import { Package, Plus, RefreshCw, Download } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
- import { Button, Badge } from '../components/ui';
8
+ import { Badge } from '../components/ui';
9
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
9
10
  import { useProducts } from '../hooks/useInventory';
10
11
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
11
12
  import { formatCurrency } from '../utils/formatters';
@@ -96,19 +97,44 @@ export default function ProductsPage() {
96
97
  subtitle={`${totalProducts} products`}
97
98
  icon={<Package size={24} />}
98
99
  headerActions={
99
- <div className="flex gap-2">
100
- <Button variant="outline" onClick={refetch}>
101
- <RefreshCw size={16} /> Refresh
102
- </Button>
103
- <Button variant="outline">
104
- <Download size={16} /> Export
105
- </Button>
106
- <Button>
107
- <Plus size={16} /> Add Product
108
- </Button>
109
- </div>
100
+ <CTAOverflowMenu
101
+ primary={{ label: 'Add Product', icon: <Plus size={16} />, onSelect: () => {} }}
102
+ actions={[
103
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
104
+ { label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
105
+ ]}
106
+ />
110
107
  }
111
108
  >
109
+ <PagePurpose icon={<Package size={18} />}>
110
+ The catalog of items you ship. Each product&apos;s dimensions, weight, value and handling
111
+ flags (fragile, hazardous, temperature-controlled) drive how it&apos;s packed, priced and
112
+ routed — keep them accurate so shipments are quoted and handled correctly.
113
+ </PagePurpose>
114
+
115
+ {/* Catalog at a glance — the page's single emphasis zone */}
116
+ <EmphasisPanel>
117
+ <p className="text-sm font-medium text-text-secondary">Catalog at a glance</p>
118
+ <div className="mt-3 grid grid-cols-3 gap-4">
119
+ <div>
120
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalProducts}</p>
121
+ <p className="text-xs text-text-secondary">Total products</p>
122
+ </div>
123
+ <div>
124
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
125
+ {products.filter((p) => p.fragile || p.hazardous).length}
126
+ </p>
127
+ <p className="text-xs text-text-secondary">Special handling</p>
128
+ </div>
129
+ <div>
130
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
131
+ {products.filter((p) => p.temperatureControlled).length}
132
+ </p>
133
+ <p className="text-xs text-text-secondary">Temp-controlled</p>
134
+ </div>
135
+ </div>
136
+ </EmphasisPanel>
137
+
112
138
  <DataTable
113
139
  columns={columns}
114
140
  data={products}
@@ -118,6 +144,9 @@ export default function ProductsPage() {
118
144
  searchFields={['name', 'sku', 'category'] as (keyof Product)[]}
119
145
  onRowClick={(row) => goTo(`inventory/products/${row.id}`)}
120
146
  getRowId={(row) => row.id}
147
+ emptyIllustration="empty-files"
148
+ emptyTitle="No products yet"
149
+ emptyDescription="Add products to your catalog so they can be added to orders and stocked in warehouses."
121
150
  />
122
151
  </PageLayout>
123
152
  );
@@ -17,6 +17,7 @@ import {
17
17
  SelectTrigger,
18
18
  SelectValue,
19
19
  } from '../components/ui';
20
+ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
20
21
 
21
22
  export default function ReportsPage() {
22
23
  const reports = [
@@ -87,6 +88,12 @@ export default function ReportsPage() {
87
88
  </div>
88
89
  }
89
90
  >
91
+ <PagePurpose icon={<FileBarChart size={18} />}>
92
+ Turn your operational data into shareable summaries. Generate one-off reports on orders,
93
+ finance, fleet, customers or inventory, or schedule them to land in inboxes automatically —
94
+ so stakeholders always have the latest numbers without logging in.
95
+ </PagePurpose>
96
+
90
97
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
91
98
  <div className="lg:col-span-2 space-y-4">
92
99
  <h3 className="font-semibold">Available Reports</h3>
@@ -121,25 +128,22 @@ export default function ReportsPage() {
121
128
  </div>
122
129
 
123
130
  <div className="space-y-6">
124
- <Card>
125
- <CardHeader>
126
- <CardTitle className="flex items-center gap-2">
127
- <Clock size={18} /> Scheduled Reports
128
- </CardTitle>
129
- </CardHeader>
130
- <CardContent className="space-y-3">
131
- {scheduledReports.map((report) => (
132
- <div key={report.name} className="p-3 border rounded-lg">
133
- <p className="font-medium">{report.name}</p>
134
- <p className="text-sm text-text-secondary">Next: {report.nextRun}</p>
135
- <p className="text-xs text-text-secondary">{report.recipients} recipients</p>
136
- </div>
137
- ))}
138
- <Button variant="outline" className="w-full">
139
- Schedule New Report
140
- </Button>
141
- </CardContent>
142
- </Card>
131
+ {/* Scheduled Reports — the page's single emphasis zone */}
132
+ <EmphasisPanel className="space-y-3">
133
+ <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
134
+ <Clock size={18} /> Scheduled Reports
135
+ </h2>
136
+ {scheduledReports.map((report) => (
137
+ <div key={report.name} className="p-3 border border-border-seam rounded-lg">
138
+ <p className="font-medium">{report.name}</p>
139
+ <p className="text-sm text-text-secondary">Next: {report.nextRun}</p>
140
+ <p className="text-xs text-text-secondary">{report.recipients} recipients</p>
141
+ </div>
142
+ ))}
143
+ <Button variant="outline" className="w-full">
144
+ Schedule New Report
145
+ </Button>
146
+ </EmphasisPanel>
143
147
 
144
148
  <Card>
145
149
  <CardHeader>
@@ -4,9 +4,10 @@
4
4
 
5
5
  import { useParams } from 'react-router-dom';
6
6
  import { Navigation, ArrowLeft, Edit, MapPin, Clock, Zap, CheckCircle } from 'lucide-react';
7
- import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
7
+ import { PageLayout, LoadingState, ErrorState, EmptyState } from '../components/PageLayout';
8
8
  import { StatusBadge } from '../components/StatusBadge';
9
9
  import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
10
+ import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
10
11
  import { useRoute, useRoutes } from '../hooks/useRoutes';
11
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
13
  import { formatDate, formatAddress } from '../utils/formatters';
@@ -19,6 +20,7 @@ export default function RouteDetailsPage() {
19
20
  const { optimizeRoute } = useRoutes();
20
21
 
21
22
  const goBack = () => navigate?.(joinPath(basePath, 'routes'));
23
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
22
24
 
23
25
  // Handle new route form
24
26
  if (!routeId) {
@@ -33,11 +35,15 @@ export default function RouteDetailsPage() {
33
35
  </Button>
34
36
  }
35
37
  >
36
- <Card>
37
- <CardContent className="p-8 text-center">
38
- <p className="text-text-secondary">Route creation form would go here</p>
39
- </CardContent>
40
- </Card>
38
+ <PagePurpose icon={<Navigation size={18} />}>
39
+ Plan a new delivery route — pick the stops to visit, and the optimizer will sequence them
40
+ into the shortest driving plan so one driver can cover them in a single run.
41
+ </PagePurpose>
42
+ <EmptyState
43
+ illustration="onboarding"
44
+ title="Build your route"
45
+ description="The route planner lets you add stops, set the running order, and optimize for distance and time."
46
+ />
41
47
  </PageLayout>
42
48
  );
43
49
  }
@@ -90,6 +96,43 @@ export default function RouteDetailsPage() {
90
96
  </div>
91
97
  }
92
98
  >
99
+ <PagePurpose icon={<Navigation size={18} />}>
100
+ A single optimized driving plan that chains together this route&apos;s stops. Review the
101
+ sequence, distance and timing here, re-optimize if traffic or stops change, then hand the
102
+ itinerary to a driver.
103
+ </PagePurpose>
104
+
105
+ <NextSteps
106
+ storageKey="movethewheels-route-details"
107
+ steps={[
108
+ ...(!route.optimized
109
+ ? [
110
+ {
111
+ id: 'optimize',
112
+ label: 'Optimize this route',
113
+ description: 'Reorder stops to cut distance and driving time.',
114
+ icon: <Zap size={16} />,
115
+ onClick: handleOptimize,
116
+ },
117
+ ]
118
+ : []),
119
+ {
120
+ id: 'edit',
121
+ label: 'Adjust stops',
122
+ description: 'Add, remove or reorder the delivery stops.',
123
+ icon: <Edit size={16} />,
124
+ onClick: () => {},
125
+ },
126
+ {
127
+ id: 'orders',
128
+ label: 'Review the orders on this route',
129
+ description: 'Check the deliveries bundled into this run.',
130
+ icon: <MapPin size={16} />,
131
+ onClick: () => goTo('orders'),
132
+ },
133
+ ]}
134
+ />
135
+
93
136
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
94
137
  <div className="lg:col-span-2 space-y-6">
95
138
  <Card>
@@ -161,36 +204,33 @@ export default function RouteDetailsPage() {
161
204
  </div>
162
205
 
163
206
  <div className="space-y-6">
164
- <Card>
165
- <CardHeader>
166
- <CardTitle>Route Info</CardTitle>
167
- </CardHeader>
168
- <CardContent className="space-y-4">
169
- <div>
170
- <p className="text-sm text-text-secondary">Total Distance</p>
171
- <p className="text-2xl font-bold">
172
- {route.distance.toFixed(1)}
173
- <span className="text-sm font-normal"> km</span>
174
- </p>
175
- </div>
207
+ {/* Route Info — the page's single emphasis zone */}
208
+ <EmphasisPanel className="space-y-4">
209
+ <h2 className="text-base font-semibold text-text-primary">Route Info</h2>
210
+ <div>
211
+ <p className="text-sm text-text-secondary">Total Distance</p>
212
+ <p className="text-2xl font-bold">
213
+ {route.distance.toFixed(1)}
214
+ <span className="text-sm font-normal"> km</span>
215
+ </p>
216
+ </div>
217
+ <div>
218
+ <p className="text-sm text-text-secondary">Est. Duration</p>
219
+ <p className="text-2xl font-bold">
220
+ {route.estimatedDuration}
221
+ <span className="text-sm font-normal"> min</span>
222
+ </p>
223
+ </div>
224
+ {route.actualDuration && (
176
225
  <div>
177
- <p className="text-sm text-text-secondary">Est. Duration</p>
226
+ <p className="text-sm text-text-secondary">Actual Duration</p>
178
227
  <p className="text-2xl font-bold">
179
- {route.estimatedDuration}
228
+ {route.actualDuration}
180
229
  <span className="text-sm font-normal"> min</span>
181
230
  </p>
182
231
  </div>
183
- {route.actualDuration && (
184
- <div>
185
- <p className="text-sm text-text-secondary">Actual Duration</p>
186
- <p className="text-2xl font-bold">
187
- {route.actualDuration}
188
- <span className="text-sm font-normal"> min</span>
189
- </p>
190
- </div>
191
- )}
192
- </CardContent>
193
- </Card>
232
+ )}
233
+ </EmphasisPanel>
194
234
 
195
235
  <Card>
196
236
  <CardHeader>
@@ -6,7 +6,8 @@ import { Plus, RefreshCw, Navigation } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
8
  import { StatusBadge } from '../components/StatusBadge';
9
- import { Button, Badge } from '../components/ui';
9
+ import { Badge, Button } from '../components/ui';
10
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
10
11
  import { useRoutes } from '../hooks/useRoutes';
11
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
13
  import { formatDate } from '../utils/formatters';
@@ -79,16 +80,45 @@ export default function RoutesPage() {
79
80
  subtitle={`${totalRoutes} routes`}
80
81
  icon={<Navigation size={24} />}
81
82
  headerActions={
82
- <div className="flex gap-2">
83
- <Button variant="outline" onClick={refetch}>
84
- <RefreshCw size={16} /> Refresh
85
- </Button>
86
- <Button onClick={() => goTo('routes/new')}>
87
- <Plus size={16} /> Create Route
88
- </Button>
89
- </div>
83
+ <CTAOverflowMenu
84
+ primary={{
85
+ label: 'Create Route',
86
+ icon: <Plus size={16} />,
87
+ onSelect: () => goTo('routes/new'),
88
+ }}
89
+ actions={[{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() }]}
90
+ />
90
91
  }
91
92
  >
93
+ <PagePurpose icon={<Navigation size={18} />}>
94
+ Routes group multiple delivery stops into an optimized driving plan. Build a route to batch
95
+ nearby drop-offs, cut distance and fuel, and give drivers a single ordered itinerary — then
96
+ open one to review stops, distance and optimization status.
97
+ </PagePurpose>
98
+
99
+ {/* Routes at a glance — the page's single emphasis zone */}
100
+ <EmphasisPanel>
101
+ <p className="text-sm font-medium text-text-secondary">Routes at a glance</p>
102
+ <div className="mt-3 grid grid-cols-3 gap-4">
103
+ <div>
104
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalRoutes}</p>
105
+ <p className="text-xs text-text-secondary">Total routes</p>
106
+ </div>
107
+ <div>
108
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
109
+ {routes.filter((r) => r.status === 'in_progress').length}
110
+ </p>
111
+ <p className="text-xs text-text-secondary">In progress</p>
112
+ </div>
113
+ <div>
114
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
115
+ {routes.filter((r) => r.optimized).length}
116
+ </p>
117
+ <p className="text-xs text-text-secondary">Optimized</p>
118
+ </div>
119
+ </div>
120
+ </EmphasisPanel>
121
+
92
122
  <DataTable
93
123
  columns={columns}
94
124
  data={routes}
@@ -98,6 +128,15 @@ export default function RoutesPage() {
98
128
  searchFields={['name'] as (keyof Route)[]}
99
129
  onRowClick={(row) => goTo(`routes/${row.id}`)}
100
130
  getRowId={(row) => row.id}
131
+ emptyIllustration="empty-data"
132
+ emptyTitle="No routes yet"
133
+ emptyDescription="Create a route to batch deliveries into an optimized driving plan."
134
+ emptyAction={
135
+ <Button onClick={() => goTo('routes/new')}>
136
+ <Plus size={16} className="mr-1.5" />
137
+ Create Route
138
+ </Button>
139
+ }
101
140
  />
102
141
  </PageLayout>
103
142
  );
@@ -2,6 +2,7 @@
2
2
  * Settings Page
3
3
  */
4
4
 
5
+ import { useState } from 'react';
5
6
  import { Settings, User, Bell, Shield, Globe, Webhook, Save } from 'lucide-react';
6
7
  import { PageLayout } from '../components/PageLayout';
7
8
  import {
@@ -24,15 +25,59 @@ import {
24
25
  TabsTrigger,
25
26
  TabsContent,
26
27
  } from '../components/ui';
28
+ import { EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';
27
29
 
28
30
  export default function SettingsPage() {
31
+ const [tab, setTab] = useState('general');
32
+
29
33
  return (
30
34
  <PageLayout
31
35
  title="Settings"
32
36
  subtitle="Manage your account and preferences"
33
37
  icon={<Settings size={24} />}
34
38
  >
35
- <Tabs defaultValue="general">
39
+ <PagePurpose icon={<Settings size={18} />}>
40
+ Configure how MoveTheWheels works for your business — company details and localization,
41
+ which notifications you receive, account security, and the integrations (maps, payments,
42
+ messaging) that power deliveries. Set these once so the rest of the app behaves the way you
43
+ expect.
44
+ </PagePurpose>
45
+
46
+ <NextSteps
47
+ storageKey="movethewheels-settings"
48
+ steps={[
49
+ {
50
+ id: 'company',
51
+ label: 'Confirm company details & localization',
52
+ description: 'Set your name, contact info, timezone, currency and language.',
53
+ icon: <User size={16} />,
54
+ onClick: () => setTab('general'),
55
+ },
56
+ {
57
+ id: 'notifications',
58
+ label: 'Choose your notifications',
59
+ description: 'Decide which order, delivery and report emails you receive.',
60
+ icon: <Bell size={16} />,
61
+ onClick: () => setTab('notifications'),
62
+ },
63
+ {
64
+ id: 'security',
65
+ label: 'Secure your account',
66
+ description: 'Update your password and enable two-factor authentication.',
67
+ icon: <Shield size={16} />,
68
+ onClick: () => setTab('security'),
69
+ },
70
+ {
71
+ id: 'integrations',
72
+ label: 'Connect your tools',
73
+ description: 'Link maps, payments and messaging providers.',
74
+ icon: <Webhook size={16} />,
75
+ onClick: () => setTab('integrations'),
76
+ },
77
+ ]}
78
+ />
79
+
80
+ <Tabs value={tab} onValueChange={setTab}>
36
81
  <TabsList className="mb-6">
37
82
  <TabsTrigger value="general">
38
83
  <User size={16} /> General
@@ -49,32 +94,29 @@ export default function SettingsPage() {
49
94
  </TabsList>
50
95
 
51
96
  <TabsContent value="general" className="space-y-6">
52
- <Card>
53
- <CardHeader>
54
- <CardTitle>Company Information</CardTitle>
55
- <CardDescription>Basic company details</CardDescription>
56
- </CardHeader>
57
- <CardContent className="space-y-4">
58
- <div className="grid grid-cols-2 gap-4">
59
- <div>
60
- <Label>Company Name</Label>
61
- <Input defaultValue="QuickLogistics Pro" />
62
- </div>
63
- <div>
64
- <Label>Contact Email</Label>
65
- <Input defaultValue="contact@quicklogistics.com" />
66
- </div>
67
- <div>
68
- <Label>Phone</Label>
69
- <Input defaultValue="+1-555-QUICK" />
70
- </div>
71
- <div>
72
- <Label>Website</Label>
73
- <Input defaultValue="https://quicklogistics.com" />
74
- </div>
97
+ {/* Company Information — the page's single emphasis zone */}
98
+ <EmphasisPanel>
99
+ <h2 className="text-base font-semibold text-text-primary">Company Information</h2>
100
+ <p className="text-sm text-text-secondary mb-4">Basic company details</p>
101
+ <div className="grid grid-cols-2 gap-4">
102
+ <div>
103
+ <Label>Company Name</Label>
104
+ <Input defaultValue="QuickLogistics Pro" />
75
105
  </div>
76
- </CardContent>
77
- </Card>
106
+ <div>
107
+ <Label>Contact Email</Label>
108
+ <Input defaultValue="contact@quicklogistics.com" />
109
+ </div>
110
+ <div>
111
+ <Label>Phone</Label>
112
+ <Input defaultValue="+1-555-QUICK" />
113
+ </div>
114
+ <div>
115
+ <Label>Website</Label>
116
+ <Input defaultValue="https://quicklogistics.com" />
117
+ </div>
118
+ </div>
119
+ </EmphasisPanel>
78
120
 
79
121
  <Card>
80
122
  <CardHeader>
@@ -10,6 +10,7 @@ import { MapPin, Search, Package, Truck, Clock, CheckCircle, AlertCircle } from
10
10
  import { PageLayout, EmptyState } from '../components/PageLayout';
11
11
  import { StatusBadge } from '../components/StatusBadge';
12
12
  import { Card, CardContent, CardHeader, CardTitle, Button, Input } from '../components/ui';
13
+ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
13
14
  import { useOrderTracking } from '../hooks/useTracking';
14
15
  import { formatDate, formatAddress } from '../utils/formatters';
15
16
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
@@ -56,6 +57,13 @@ export default function TrackingPage() {
56
57
  </Button>
57
58
  }
58
59
  >
60
+ <PagePurpose icon={<MapPin size={18} />}>
61
+ {t(
62
+ 'movethewheels.tracking.purpose',
63
+ 'Look up any single shipment by its tracking number or order ID to see exactly where it is, its progress through pickup and delivery, the current location and any alerts — the same view you can share with a customer.'
64
+ )}
65
+ </PagePurpose>
66
+
59
67
  {/* Search Form */}
60
68
  <Card>
61
69
  <CardContent className="p-6">
@@ -106,7 +114,7 @@ export default function TrackingPage() {
106
114
  {/* No Search Yet */}
107
115
  {!searchedOrderId && !error && (
108
116
  <EmptyState
109
- icon={<Package size={48} />}
117
+ illustration="onboarding"
110
118
  title={t('movethewheels.tracking.empty.title', 'Enter a tracking number')}
111
119
  description={t(
112
120
  'movethewheels.tracking.empty.description',
@@ -120,55 +128,50 @@ export default function TrackingPage() {
120
128
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
121
129
  {/* Main Tracking Info */}
122
130
  <div className="lg:col-span-2 space-y-6">
123
- {/* Status Card */}
124
- <Card>
125
- <CardHeader>
126
- <div className="flex items-center justify-between">
127
- <CardTitle className="flex items-center gap-2">
128
- <Package size={20} />
129
- {t('movethewheels.tracking.orderLabel', 'Order')} {order.orderNumber}
130
- </CardTitle>
131
- <StatusBadge status={order.status} type="order" />
131
+ {/* Status Card — the page's single emphasis zone */}
132
+ <EmphasisPanel>
133
+ <div className="flex items-center justify-between mb-4">
134
+ <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
135
+ <Package size={20} />
136
+ {t('movethewheels.tracking.orderLabel', 'Order')} {order.orderNumber}
137
+ </h2>
138
+ <StatusBadge status={order.status} type="order" />
139
+ </div>
140
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
141
+ <div>
142
+ <p className="text-sm text-text-secondary">
143
+ {t('movethewheels.tracking.details.trackingNumber', 'Tracking Number')}
144
+ </p>
145
+ <p className="font-mono font-medium">{order.trackingNumber}</p>
132
146
  </div>
133
- </CardHeader>
134
- <CardContent>
135
- <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
136
- <div>
137
- <p className="text-sm text-text-secondary">
138
- {t('movethewheels.tracking.details.trackingNumber', 'Tracking Number')}
139
- </p>
140
- <p className="font-mono font-medium">{order.trackingNumber}</p>
141
- </div>
142
- <div>
143
- <p className="text-sm text-text-secondary">
144
- {t('movethewheels.tracking.details.estimatedDelivery', 'Estimated Delivery')}
145
- </p>
146
- <p className="font-medium">
147
- {tracking.estimatedArrival
148
- ? formatDate(tracking.estimatedArrival, 'full')
149
- : order.scheduledDelivery
150
- ? formatDate(order.scheduledDelivery, 'full')
151
- : t('movethewheels.tracking.details.tbd', 'TBD')}
152
- </p>
153
- </div>
154
- <div>
155
- <p className="text-sm text-text-secondary">
156
- {t('movethewheels.tracking.details.items', 'Items')}
157
- </p>
158
- <p className="font-medium">
159
- {order.items.length}{' '}
160
- {t('movethewheels.tracking.details.itemsSuffix', 'items')}
161
- </p>
162
- </div>
163
- <div>
164
- <p className="text-sm text-text-secondary">
165
- {t('movethewheels.tracking.details.lastUpdated', 'Last Updated')}
166
- </p>
167
- <p className="font-medium">{formatDate(tracking.lastUpdated, 'relative')}</p>
168
- </div>
147
+ <div>
148
+ <p className="text-sm text-text-secondary">
149
+ {t('movethewheels.tracking.details.estimatedDelivery', 'Estimated Delivery')}
150
+ </p>
151
+ <p className="font-medium">
152
+ {tracking.estimatedArrival
153
+ ? formatDate(tracking.estimatedArrival, 'full')
154
+ : order.scheduledDelivery
155
+ ? formatDate(order.scheduledDelivery, 'full')
156
+ : t('movethewheels.tracking.details.tbd', 'TBD')}
157
+ </p>
169
158
  </div>
170
- </CardContent>
171
- </Card>
159
+ <div>
160
+ <p className="text-sm text-text-secondary">
161
+ {t('movethewheels.tracking.details.items', 'Items')}
162
+ </p>
163
+ <p className="font-medium">
164
+ {order.items.length} {t('movethewheels.tracking.details.itemsSuffix', 'items')}
165
+ </p>
166
+ </div>
167
+ <div>
168
+ <p className="text-sm text-text-secondary">
169
+ {t('movethewheels.tracking.details.lastUpdated', 'Last Updated')}
170
+ </p>
171
+ <p className="font-medium">{formatDate(tracking.lastUpdated, 'relative')}</p>
172
+ </div>
173
+ </div>
174
+ </EmphasisPanel>
172
175
 
173
176
  {/* Progress Timeline */}
174
177
  <Card>
@@ -404,7 +407,7 @@ export default function TrackingPage() {
404
407
  {/* No Results */}
405
408
  {searchedOrderId && !order && !isLoading && !error && (
406
409
  <EmptyState
407
- icon={<Search size={48} />}
410
+ illustration="empty-search"
408
411
  title={t('movethewheels.tracking.notFound.title', 'Shipment not found')}
409
412
  description={`${t('movethewheels.tracking.notFound.descriptionPrefix', 'No shipment found with tracking number')} "${searchedOrderId}"`}
410
413
  action={