@burdenoff/microfe-movethewheels 2026.624.1 → 2026.625.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 (83) hide show
  1. package/dist/{AIAssistantPage-BrHX2lQn.js → AIAssistantPage-CNyoKtID.js} +4 -4
  2. package/dist/{AnalyticsPage-DI6Wcaw5.js → AnalyticsPage-Ck615ox7.js} +8 -8
  3. package/dist/{CreateOrderPage-DfkSi6JF.js → CreateOrderPage-C9Vb57Yn.js} +5 -5
  4. package/dist/{CustomerDetailsPage-DzAIu_tH.js → CustomerDetailsPage-BVkHRZvi.js} +9 -9
  5. package/dist/CustomersPage-DhQg-6h_.js +118 -0
  6. package/dist/{DashboardPage-3ZOnwg1a.js → DashboardPage-DTmyuC11.js} +118 -111
  7. package/dist/{DataTable-CZGz3SJu.js → DataTable-CfWvFw5B.js} +6 -6
  8. package/dist/{DriverDetailsPage-YuZSlPSV.js → DriverDetailsPage-DaaCQ-2O.js} +10 -10
  9. package/dist/DriversPage-D0RMBB_t.js +129 -0
  10. package/dist/{FinancePage-CnjUNXOb.js → FinancePage-BUXqW1IM.js} +6 -6
  11. package/dist/{FleetPage-CPS7r4J3.js → FleetPage-DCfOmBa2.js} +66 -65
  12. package/dist/{ImportExportPage-zNjs7xsV.js → ImportExportPage-BM1BoRcE.js} +3 -3
  13. package/dist/{InventoryPage-C9g5d3SW.js → InventoryPage-BW0QXWuf.js} +61 -66
  14. package/dist/{LiveTrackingPage-DoBvtdBG.js → LiveTrackingPage-DqcGXdkw.js} +8 -8
  15. package/dist/{MarketplacePage-BEj5hcBF.js → MarketplacePage-DFqsxNYU.js} +7 -7
  16. package/dist/MetricCard-B7yMyvMX.js +146 -0
  17. package/dist/{OrderDetailsPage-D-9lDZYU.js → OrderDetailsPage-Dx1m3cVA.js} +13 -13
  18. package/dist/{OrdersListPage-CJzHbgY3.js → OrdersListPage-DHYBGrWf.js} +76 -77
  19. package/dist/{PageLayout-xDTiBTDS.js → PageLayout-D3N8MCTm.js} +213 -195
  20. package/dist/{ProductDetailsPage-3rKtzXpy.js → ProductDetailsPage-DOXO90kb.js} +6 -6
  21. package/dist/{ProductsPage-B0P_wjBJ.js → ProductsPage-RLMTwWN0.js} +41 -39
  22. package/dist/{ReportsPage-B8OyWGzl.js → ReportsPage-Df3hciPy.js} +4 -4
  23. package/dist/{RouteDetailsPage-DGjKTUMj.js → RouteDetailsPage-xzFDeR-X.js} +8 -8
  24. package/dist/{RoutesPage-CpopY8xN.js → RoutesPage-DDFy1QVi.js} +32 -30
  25. package/dist/{SettingsPage-BvXSa3gi.js → SettingsPage-JH_-UPbf.js} +4 -4
  26. package/dist/{StatusBadge-C--7NhoW.js → StatusBadge-CijYQXtb.js} +5 -2
  27. package/dist/{TrackingPage-BldUm_g7.js → TrackingPage-CU0Vk4mx.js} +11 -11
  28. package/dist/{VehicleDetailsPage-Dqv--MVW.js → VehicleDetailsPage-P4xDttKw.js} +8 -8
  29. package/dist/{VehiclesPage-CCBHRDHu.js → VehiclesPage-tJZ64QKV.js} +42 -40
  30. package/dist/{WarehouseDetailsPage-ZObC_c7W.js → WarehouseDetailsPage-Bt_w2Yf7.js} +8 -8
  31. package/dist/{WarehousesPage-CpgZEVW9.js → WarehousesPage-HsPpEFeG.js} +37 -32
  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 +4 -4
  67. package/src/movethewheels/components/MetricCard.tsx +49 -20
  68. package/src/movethewheels/components/PageLayout.tsx +60 -5
  69. package/src/movethewheels/components/StatusBadge.tsx +2 -1
  70. package/src/movethewheels/pages/CustomersPage.tsx +13 -12
  71. package/src/movethewheels/pages/DashboardPage.tsx +55 -48
  72. package/src/movethewheels/pages/DriversPage.tsx +9 -12
  73. package/src/movethewheels/pages/FleetPage.tsx +15 -10
  74. package/src/movethewheels/pages/InventoryPage.tsx +18 -11
  75. package/src/movethewheels/pages/OrdersListPage.tsx +20 -14
  76. package/src/movethewheels/pages/ProductsPage.tsx +9 -12
  77. package/src/movethewheels/pages/RoutesPage.tsx +12 -9
  78. package/src/movethewheels/pages/TrackingPage.tsx +2 -2
  79. package/src/movethewheels/pages/VehiclesPage.tsx +9 -15
  80. package/src/movethewheels/pages/WarehousesPage.tsx +8 -9
  81. package/dist/CustomersPage-d21ixOYa.js +0 -119
  82. package/dist/DriversPage-BOhqEBTv.js +0 -127
  83. package/dist/MetricCard-DeHVeVwl.js +0 -135
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
+ import { AuroraBackground, GradientText, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';
2
3
  import { cn } from '../utils/cn';
3
4
 
4
5
  interface PageLayoutProps {
@@ -21,6 +22,16 @@ interface PageLayoutProps {
21
22
  className?: string;
22
23
  /** Additional CSS classes for the content area */
23
24
  contentClassName?: string;
25
+ /**
26
+ * Boff UI 2.0 — render a subtle living aurora backdrop behind the page header.
27
+ * Reserved for the MFE's single primary page (the Dashboard). One per MFE.
28
+ */
29
+ hero?: boolean;
30
+ /**
31
+ * Boff UI 2.0 — the slice of the title to emphasise with a brand gradient.
32
+ * When provided, the title renders as `…<GradientText>{titleAccent}</GradientText>`.
33
+ */
34
+ titleAccent?: string;
24
35
  }
25
36
 
26
37
  const maxWidthClasses = {
@@ -53,7 +64,24 @@ export function PageLayout({
53
64
  showHeader = true,
54
65
  className,
55
66
  contentClassName,
67
+ hero = false,
68
+ titleAccent,
56
69
  }: PageLayoutProps) {
70
+ // Render the title, optionally clipping a gradient into the accent slice.
71
+ const renderTitle = (value: string) => {
72
+ if (!titleAccent || !value.includes(titleAccent)) {
73
+ return value;
74
+ }
75
+ const [before, after] = value.split(titleAccent);
76
+ return (
77
+ <>
78
+ {before}
79
+ <GradientText>{titleAccent}</GradientText>
80
+ {after}
81
+ </>
82
+ );
83
+ };
84
+
57
85
  return (
58
86
  <div
59
87
  className={cn(
@@ -72,20 +100,27 @@ export function PageLayout({
72
100
  <div className={cn('mx-auto w-full', maxWidthClasses[maxWidth], contentClassName)}>
73
101
  {/* Page Header */}
74
102
  {showHeader && (title || headerActions) && (
75
- <header className="mb-6 sm:mb-8">
103
+ <header
104
+ className={cn(
105
+ 'mb-6 sm:mb-8',
106
+ hero &&
107
+ 'relative overflow-hidden rounded-card border border-border-seam bg-hero-mesh px-5 py-6 sm:px-7 sm:py-8'
108
+ )}
109
+ >
110
+ {hero && <AuroraBackground intensity="subtle" />}
76
111
  <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
77
112
  {/* Title Section */}
78
113
  <div className="space-y-1">
79
114
  {(title || icon) && (
80
115
  <div className="flex items-center gap-3">
81
116
  {icon && (
82
- <div className="flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary">
117
+ <div className="flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-action-primary-bg">
83
118
  {icon}
84
119
  </div>
85
120
  )}
86
121
  {title && (
87
122
  <h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-text-primary">
88
- {title}
123
+ {renderTitle(title)}
89
124
  </h1>
90
125
  )}
91
126
  </div>
@@ -148,7 +183,13 @@ export function PageSection({
148
183
  }
149
184
 
150
185
  /**
151
- * EmptyState - A consistent empty state component
186
+ * EmptyState - A consistent empty/zero state component.
187
+ *
188
+ * Boff UI 2.0: when an `illustration` name is provided (one of the standard
189
+ * host-served names — empty-data, empty-search, empty-files, empty-people,
190
+ * empty-notifications, onboarding, empty-generic), it renders the on-brand
191
+ * IllustratedEmptyState. Otherwise it falls back to the legacy icon layout so
192
+ * existing callers keep working unchanged.
152
193
  */
153
194
  export function EmptyState({
154
195
  icon,
@@ -156,13 +197,27 @@ export function EmptyState({
156
197
  description,
157
198
  action,
158
199
  className,
200
+ illustration = 'empty-data',
159
201
  }: {
160
202
  icon?: ReactNode;
161
203
  title: string;
162
204
  description?: string;
163
205
  action?: ReactNode;
164
206
  className?: string;
207
+ /** Standard illustration name served by the host at /illustrations/<name>.webp. */
208
+ illustration?: string;
165
209
  }) {
210
+ if (!icon) {
211
+ return (
212
+ <IllustratedEmptyState
213
+ illustration={illustration}
214
+ title={title}
215
+ description={description}
216
+ action={action}
217
+ className={cn('animate-in fade-in-0 zoom-in-95 duration-300', className)}
218
+ />
219
+ );
220
+ }
166
221
  return (
167
222
  <div
168
223
  className={cn(
@@ -173,7 +228,7 @@ export function EmptyState({
173
228
  className
174
229
  )}
175
230
  >
176
- {icon && <div className="mb-4 p-4 rounded-2xl bg-bg-sunken/50 text-text-secondary">{icon}</div>}
231
+ <div className="mb-4 p-4 rounded-2xl bg-bg-sunken/50 text-text-secondary">{icon}</div>
177
232
  <h3 className="text-lg font-semibold text-text-primary mb-1">{title}</h3>
178
233
  {description && <p className="text-sm text-text-secondary max-w-sm mb-4">{description}</p>}
179
234
  {action}
@@ -78,8 +78,9 @@ export function StatusBadge({
78
78
  >
79
79
  {showDot && (
80
80
  <span
81
+ aria-hidden="true"
81
82
  className={cn(
82
- 'w-1.5 h-1.5 rounded-full mr-1.5 flex-shrink-0',
83
+ 'w-1.5 h-1.5 rounded-full mr-1.5 flex-shrink-0 motion-safe:animate-vc-glow-pulse',
83
84
  colors.text.replace('text-', 'bg-')
84
85
  )}
85
86
  />
@@ -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 } from '../components/ui';
10
+ import { CTAOverflowMenu } 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,17 +88,17 @@ 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
  >
103
104
  <DataTable
@@ -27,6 +27,7 @@ import {
27
27
  Badge,
28
28
  Progress,
29
29
  } from '../components/ui';
30
+ import { CTAOverflowMenu, EmphasisPanel } 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,20 +58,26 @@ 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
  >
76
83
  {/* Key Metrics */}
@@ -99,6 +106,8 @@ export default function DashboardPage() {
99
106
  onClick={() => goTo('fleet')}
100
107
  />
101
108
  <MetricCard
109
+ treatment="glass"
110
+ glow
102
111
  label={t('movethewheels.dashboard.metrics.revenue', 'Revenue')}
103
112
  value={formatCurrency(metrics.revenue.total)}
104
113
  icon={<DollarSign size={20} />}
@@ -234,45 +243,43 @@ export default function DashboardPage() {
234
243
  </div>
235
244
 
236
245
  <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>
246
+ {/* Order Status Summary — the page's single emphasis zone */}
247
+ <EmphasisPanel className="space-y-4">
248
+ <h2 className="text-base font-semibold text-text-primary">
249
+ {t('movethewheels.dashboard.orderStatus.title', 'Order Status')}
250
+ </h2>
251
+ <div className="space-y-3">
252
+ {[
253
+ { status: 'pending', count: orderStats.byStatus.pending, color: 'bg-yellow-500' },
254
+ {
255
+ status: 'in_transit',
256
+ count: orderStats.byStatus.in_transit,
257
+ color: 'bg-blue-500',
258
+ },
259
+ {
260
+ status: 'delivered',
261
+ count: orderStats.byStatus.delivered,
262
+ color: 'bg-green-500',
263
+ },
264
+ { status: 'cancelled', count: orderStats.byStatus.cancelled, color: 'bg-red-500' },
265
+ ].map(({ status, count, color }) => (
266
+ <div key={status} className="flex items-center justify-between">
267
+ <div className="flex items-center gap-2">
268
+ <div className={`w-2 h-2 rounded-full ${color}`} />
269
+ <span className="text-sm capitalize">
270
+ {t(
271
+ `movethewheels.dashboard.orderStatus.status.${status}`,
272
+ status.replace('_', ' ')
273
+ )}
274
+ </span>
271
275
  </div>
272
- ))}
273
- </div>
274
- </CardContent>
275
- </Card>
276
+ <Badge variant="secondary" className="tabular-nums">
277
+ {count}
278
+ </Badge>
279
+ </div>
280
+ ))}
281
+ </div>
282
+ </EmphasisPanel>
276
283
 
277
284
  {/* Fleet Status */}
278
285
  <Card>
@@ -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 { StatusBadge } from '../components/StatusBadge';
9
- import { Button, Avatar, AvatarFallback } from '../components/ui';
9
+ import { Avatar, AvatarFallback } from '../components/ui';
10
+ import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
10
11
  import { useDrivers } from '../hooks/useFleet';
11
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
13
  import { formatDate } from '../utils/formatters';
@@ -90,17 +91,13 @@ export default function DriversPage() {
90
91
  subtitle={`${totalDrivers} drivers`}
91
92
  icon={<Users size={24} />}
92
93
  headerActions={
93
- <div className="flex gap-2">
94
- <Button variant="outline" onClick={refetch}>
95
- <RefreshCw size={16} /> Refresh
96
- </Button>
97
- <Button variant="outline">
98
- <Download size={16} /> Export
99
- </Button>
100
- <Button>
101
- <Plus size={16} /> Add Driver
102
- </Button>
103
- </div>
94
+ <CTAOverflowMenu
95
+ primary={{ label: 'Add Driver', icon: <Plus size={16} />, onSelect: () => {} }}
96
+ actions={[
97
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
98
+ { label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
99
+ ]}
100
+ />
104
101
  }
105
102
  >
106
103
  <DataTable
@@ -18,6 +18,7 @@ import {
18
18
  Avatar,
19
19
  AvatarFallback,
20
20
  } from '../components/ui';
21
+ import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
21
22
  import { useFleetStats, useVehicles, useDrivers } from '../hooks/useFleet';
22
23
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
23
24
  import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
@@ -46,16 +47,20 @@ export default function FleetPage() {
46
47
  subtitle={t('movethewheels.fleet.subtitle', 'Manage your vehicles and drivers')}
47
48
  icon={<Truck size={24} />}
48
49
  headerActions={
49
- <div className="flex gap-2">
50
- <Button variant="outline" onClick={() => goTo('fleet/vehicles')}>
51
- <Truck size={16} />
52
- {t('movethewheels.fleet.actions.allVehicles', 'All Vehicles')}
53
- </Button>
54
- <Button variant="outline" onClick={() => goTo('fleet/drivers')}>
55
- <Users size={16} />
56
- {t('movethewheels.fleet.actions.allDrivers', 'All Drivers')}
57
- </Button>
58
- </div>
50
+ <CTAOverflowMenu
51
+ primary={{
52
+ label: t('movethewheels.fleet.actions.allVehicles', 'All Vehicles'),
53
+ icon: <Truck size={16} />,
54
+ onSelect: () => goTo('fleet/vehicles'),
55
+ }}
56
+ actions={[
57
+ {
58
+ label: t('movethewheels.fleet.actions.allDrivers', 'All Drivers'),
59
+ icon: <Users size={16} />,
60
+ onSelect: () => goTo('fleet/drivers'),
61
+ },
62
+ ]}
63
+ />
59
64
  }
60
65
  >
61
66
  {/* Key Metrics */}
@@ -14,6 +14,7 @@ import {
14
14
  Badge,
15
15
  Progress,
16
16
  } from '../components/ui';
17
+ import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
17
18
  import { useInventory, useInventoryStats } from '../hooks/useInventory';
18
19
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
19
20
  import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
@@ -39,17 +40,23 @@ export default function InventoryPage() {
39
40
  subtitle={t('movethewheels.inventory.subtitle', 'Manage your products and warehouses')}
40
41
  icon={<Package size={24} />}
41
42
  headerActions={
42
- <div className="flex gap-2">
43
- <Button variant="outline" onClick={() => goTo('inventory/products')}>
44
- {t('movethewheels.inventory.actions.products', 'Products')}
45
- </Button>
46
- <Button variant="outline" onClick={() => goTo('inventory/warehouses')}>
47
- {t('movethewheels.inventory.actions.warehouses', 'Warehouses')}
48
- </Button>
49
- <Button>
50
- <Plus size={16} /> {t('movethewheels.inventory.actions.addProduct', 'Add Product')}
51
- </Button>
52
- </div>
43
+ <CTAOverflowMenu
44
+ primary={{
45
+ label: t('movethewheels.inventory.actions.addProduct', 'Add Product'),
46
+ icon: <Plus size={16} />,
47
+ onSelect: () => {},
48
+ }}
49
+ actions={[
50
+ {
51
+ label: t('movethewheels.inventory.actions.products', 'Products'),
52
+ onSelect: () => goTo('inventory/products'),
53
+ },
54
+ {
55
+ label: t('movethewheels.inventory.actions.warehouses', 'Warehouses'),
56
+ onSelect: () => goTo('inventory/warehouses'),
57
+ },
58
+ ]}
59
+ />
53
60
  }
54
61
  >
55
62
  <MetricGrid columns={4}>
@@ -9,6 +9,7 @@ import { Package, Plus, Filter, Download, RefreshCw } from 'lucide-react';
9
9
  import { PageLayout } from '../components/PageLayout';
10
10
  import { DataTable, type Column } from '../components/DataTable';
11
11
  import { StatusBadge, PriorityBadge, TypeBadge } from '../components/StatusBadge';
12
+ import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
12
13
  import {
13
14
  Button,
14
15
  Card,
@@ -152,20 +153,25 @@ export default function OrdersListPage() {
152
153
  subtitle={`${totalOrders} ${t('movethewheels.orders.subtitle', 'total orders')}`}
153
154
  icon={<Package size={24} />}
154
155
  headerActions={
155
- <div className="flex gap-2">
156
- <Button variant="outline" onClick={refetch}>
157
- <RefreshCw size={16} />
158
- {t('movethewheels.orders.actions.refresh', 'Refresh')}
159
- </Button>
160
- <Button variant="outline">
161
- <Download size={16} />
162
- {t('movethewheels.orders.actions.export', 'Export')}
163
- </Button>
164
- <Button onClick={() => goTo('orders/new')}>
165
- <Plus size={16} />
166
- {t('movethewheels.orders.actions.newOrder', 'New Order')}
167
- </Button>
168
- </div>
156
+ <CTAOverflowMenu
157
+ primary={{
158
+ label: t('movethewheels.orders.actions.newOrder', 'New Order'),
159
+ icon: <Plus size={16} />,
160
+ onSelect: () => goTo('orders/new'),
161
+ }}
162
+ actions={[
163
+ {
164
+ label: t('movethewheels.orders.actions.refresh', 'Refresh'),
165
+ icon: <RefreshCw size={16} />,
166
+ onSelect: () => refetch(),
167
+ },
168
+ {
169
+ label: t('movethewheels.orders.actions.export', 'Export'),
170
+ icon: <Download size={16} />,
171
+ onSelect: () => {},
172
+ },
173
+ ]}
174
+ />
169
175
  }
170
176
  >
171
177
  {/* Filters */}
@@ -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 } 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,17 +97,13 @@ 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
  >
112
109
  <DataTable
@@ -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 } from '../components/ui';
10
+ import { CTAOverflowMenu } 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,14 +80,16 @@ 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={[
90
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
91
+ ]}
92
+ />
90
93
  }
91
94
  >
92
95
  <DataTable
@@ -106,7 +106,7 @@ export default function TrackingPage() {
106
106
  {/* No Search Yet */}
107
107
  {!searchedOrderId && !error && (
108
108
  <EmptyState
109
- icon={<Package size={48} />}
109
+ illustration="onboarding"
110
110
  title={t('movethewheels.tracking.empty.title', 'Enter a tracking number')}
111
111
  description={t(
112
112
  'movethewheels.tracking.empty.description',
@@ -404,7 +404,7 @@ export default function TrackingPage() {
404
404
  {/* No Results */}
405
405
  {searchedOrderId && !order && !isLoading && !error && (
406
406
  <EmptyState
407
- icon={<Search size={48} />}
407
+ illustration="empty-search"
408
408
  title={t('movethewheels.tracking.notFound.title', 'Shipment not found')}
409
409
  description={`${t('movethewheels.tracking.notFound.descriptionPrefix', 'No shipment found with tracking number')} "${searchedOrderId}"`}
410
410
  action={
@@ -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 } 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,20 +94,13 @@ 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
  >
112
106
  <DataTable
@@ -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 } 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,14 +98,12 @@ 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={[
104
+ { label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
105
+ ]}
106
+ />
108
107
  }
109
108
  >
110
109
  <DataTable