@burdenoff/microfe-movethewheels 2026.625.1 → 2026.626.2

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 (80) hide show
  1. package/dist/{AIAssistantPage-CNyoKtID.js → AIAssistantPage-AvsMbunM.js} +35 -29
  2. package/dist/{AnalyticsPage-Ck615ox7.js → AnalyticsPage-CCLfHgQZ.js} +36 -25
  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-DTmyuC11.js → DashboardPage-D2HRqwg9.js} +93 -89
  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-DCfOmBa2.js → FleetPage-DddXt8r8.js} +109 -71
  12. package/dist/ImportExportPage-BW6qO3kc.js +248 -0
  13. package/dist/{InventoryPage-BW0QXWuf.js → InventoryPage-rMGuaJN-.js} +74 -70
  14. package/dist/LiveTrackingPage-DQ1q4Id3.js +375 -0
  15. package/dist/MarketplacePage-DKrXAv62.js +219 -0
  16. package/dist/OrderDetailsPage-CFASgsYX.js +431 -0
  17. package/dist/OrdersListPage-BHeT8S5o.js +309 -0
  18. package/dist/ProductDetailsPage-CFGcbaHo.js +195 -0
  19. package/dist/ProductsPage--xEpbQ8A.js +171 -0
  20. package/dist/{ReportsPage-Df3hciPy.js → ReportsPage-Bb7_90rK.js} +53 -45
  21. package/dist/RouteDetailsPage-CVtDVb1N.js +282 -0
  22. package/dist/RoutesPage-s57PtgcQ.js +163 -0
  23. package/dist/SettingsPage-BYNCBOpN.js +298 -0
  24. package/dist/{TrackingPage-CU0Vk4mx.js → TrackingPage-CcRc_dva.js} +77 -72
  25. package/dist/VehicleDetailsPage-3YDMPsPs.js +220 -0
  26. package/dist/VehiclesPage-UlxPWP9K.js +167 -0
  27. package/dist/WarehouseDetailsPage-Db7KeN-d.js +238 -0
  28. package/dist/WarehousesPage-CuTO-OPp.js +164 -0
  29. package/dist/index.js +2 -2
  30. package/package.json +2 -2
  31. package/src/movethewheels/components/DataTable.tsx +37 -2
  32. package/src/movethewheels/components/MetricCard.tsx +3 -1
  33. package/src/movethewheels/pages/AIAssistantPage.tsx +11 -3
  34. package/src/movethewheels/pages/AnalyticsPage.tsx +31 -25
  35. package/src/movethewheels/pages/CreateOrderPage.tsx +56 -17
  36. package/src/movethewheels/pages/CustomerDetailsPage.tsx +63 -38
  37. package/src/movethewheels/pages/CustomersPage.tsx +40 -2
  38. package/src/movethewheels/pages/DashboardPage.tsx +8 -1
  39. package/src/movethewheels/pages/DriverDetailsPage.tsx +57 -26
  40. package/src/movethewheels/pages/DriversPage.tsx +37 -1
  41. package/src/movethewheels/pages/FinancePage.tsx +45 -41
  42. package/src/movethewheels/pages/FleetPage.tsx +68 -25
  43. package/src/movethewheels/pages/ImportExportPage.tsx +46 -29
  44. package/src/movethewheels/pages/InventoryPage.tsx +20 -23
  45. package/src/movethewheels/pages/LiveTrackingPage.tsx +58 -20
  46. package/src/movethewheels/pages/MarketplacePage.tsx +37 -3
  47. package/src/movethewheels/pages/OrderDetailsPage.tsx +74 -46
  48. package/src/movethewheels/pages/OrdersListPage.tsx +62 -1
  49. package/src/movethewheels/pages/ProductDetailsPage.tsx +36 -11
  50. package/src/movethewheels/pages/ProductsPage.tsx +33 -1
  51. package/src/movethewheels/pages/ReportsPage.tsx +23 -19
  52. package/src/movethewheels/pages/RouteDetailsPage.tsx +71 -31
  53. package/src/movethewheels/pages/RoutesPage.tsx +41 -5
  54. package/src/movethewheels/pages/SettingsPage.tsx +68 -26
  55. package/src/movethewheels/pages/TrackingPage.tsx +50 -47
  56. package/src/movethewheels/pages/VehicleDetailsPage.tsx +49 -24
  57. package/src/movethewheels/pages/VehiclesPage.tsx +33 -1
  58. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +55 -30
  59. package/src/movethewheels/pages/WarehousesPage.tsx +42 -4
  60. package/dist/CreateOrderPage-C9Vb57Yn.js +0 -471
  61. package/dist/CustomerDetailsPage-BVkHRZvi.js +0 -239
  62. package/dist/CustomersPage-DhQg-6h_.js +0 -118
  63. package/dist/DataTable-CfWvFw5B.js +0 -239
  64. package/dist/DriverDetailsPage-DaaCQ-2O.js +0 -297
  65. package/dist/DriversPage-D0RMBB_t.js +0 -129
  66. package/dist/FinancePage-BUXqW1IM.js +0 -154
  67. package/dist/ImportExportPage-BM1BoRcE.js +0 -232
  68. package/dist/LiveTrackingPage-DqcGXdkw.js +0 -332
  69. package/dist/MarketplacePage-DFqsxNYU.js +0 -192
  70. package/dist/OrderDetailsPage-Dx1m3cVA.js +0 -398
  71. package/dist/OrdersListPage-DHYBGrWf.js +0 -256
  72. package/dist/ProductDetailsPage-DOXO90kb.js +0 -168
  73. package/dist/ProductsPage-RLMTwWN0.js +0 -133
  74. package/dist/RouteDetailsPage-xzFDeR-X.js +0 -240
  75. package/dist/RoutesPage-DDFy1QVi.js +0 -118
  76. package/dist/SettingsPage-JH_-UPbf.js +0 -247
  77. package/dist/VehicleDetailsPage-P4xDttKw.js +0 -194
  78. package/dist/VehiclesPage-tJZ64QKV.js +0 -129
  79. package/dist/WarehouseDetailsPage-Bt_w2Yf7.js +0 -215
  80. package/dist/WarehousesPage-HsPpEFeG.js +0 -126
@@ -6,8 +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 { Badge, Avatar, AvatarFallback } from '../components/ui';
10
- import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
9
+ import { Badge, Avatar, AvatarFallback, Button } from '../components/ui';
10
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
11
11
  import { useCustomers } from '../hooks/useCustomers';
12
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
13
13
  import { formatDate } from '../utils/formatters';
@@ -101,6 +101,35 @@ export default function CustomersPage() {
101
101
  />
102
102
  }
103
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
+
104
133
  <DataTable
105
134
  columns={columns}
106
135
  data={customers}
@@ -110,6 +139,15 @@ export default function CustomersPage() {
110
139
  searchFields={['name', 'email', 'company'] as (keyof Customer)[]}
111
140
  onRowClick={(row) => goTo(`customers/${row.id}`)}
112
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
+ }
113
151
  />
114
152
  </PageLayout>
115
153
  );
@@ -27,7 +27,7 @@ import {
27
27
  Badge,
28
28
  Progress,
29
29
  } from '../components/ui';
30
- import { CTAOverflowMenu, EmphasisPanel } from '@burdenoff/fe-libs/ui';
30
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
31
31
  import { useDashboardMetrics } from '../hooks/useAnalytics';
32
32
  import { useOrders, useOrderStats } from '../hooks/useOrders';
33
33
  import { useFleetStats } from '../hooks/useFleet';
@@ -80,6 +80,13 @@ export default function DashboardPage() {
80
80
  />
81
81
  }
82
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
+
83
90
  {/* Key Metrics */}
84
91
  <MetricGrid columns={4}>
85
92
  <MetricCard
@@ -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 { useDriver } from '../hooks/useFleet';
19
20
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
20
21
  import { formatCurrency, formatDate } from '../utils/formatters';
@@ -26,6 +27,7 @@ export default function DriverDetailsPage() {
26
27
  const { driver, isLoading, error, refetch } = useDriver(driverId);
27
28
 
28
29
  const goBack = () => navigate?.(joinPath(basePath, 'fleet/drivers'));
30
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
29
31
 
30
32
  if (isLoading) return <LoadingState message="Loading driver details..." />;
31
33
  if (error || !driver) return <ErrorState title="Driver not found" onRetry={refetch} />;
@@ -56,35 +58,64 @@ export default function DriverDetailsPage() {
56
58
  </div>
57
59
  }
58
60
  >
61
+ <PagePurpose icon={<Users size={18} />}>
62
+ A driver&apos;s full profile — performance ratings, working hours, documents, earnings and
63
+ live location. Use it to confirm someone is road-ready and compliant before assigning them
64
+ an order or route.
65
+ </PagePurpose>
66
+
67
+ <NextSteps
68
+ storageKey="movethewheels-driver-details"
69
+ steps={[
70
+ {
71
+ id: 'assign',
72
+ label: 'Assign to an order',
73
+ description: 'Hand a pending delivery to this driver.',
74
+ icon: <MapPin size={16} />,
75
+ onClick: () => goTo('orders'),
76
+ },
77
+ {
78
+ id: 'routes',
79
+ label: 'Plan their route',
80
+ description: 'Batch nearby drop-offs into an optimized itinerary.',
81
+ icon: <Clock size={16} />,
82
+ onClick: () => goTo('routes'),
83
+ },
84
+ {
85
+ id: 'edit',
86
+ label: 'Update driver record',
87
+ description: 'Refresh documents, shift or compliance details.',
88
+ icon: <Edit size={16} />,
89
+ onClick: () => {},
90
+ },
91
+ ]}
92
+ />
93
+
59
94
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
60
95
  <div className="lg:col-span-2 space-y-6">
61
- {/* Ratings */}
62
- <Card>
63
- <CardHeader>
64
- <CardTitle className="flex items-center gap-2">
65
- <Star size={18} /> Ratings
66
- </CardTitle>
67
- </CardHeader>
68
- <CardContent>
69
- <div className="grid grid-cols-2 md:grid-cols-3 gap-4">
70
- {[
71
- { label: 'Punctuality', value: driver.ratings.punctuality },
72
- { label: 'Communication', value: driver.ratings.communication },
73
- { label: 'Handling', value: driver.ratings.carefulHandling },
74
- { label: 'Professionalism', value: driver.ratings.professionalism },
75
- { label: 'On-Time Delivery', value: driver.ratings.onTimeDelivery },
76
- ].map((rating) => (
77
- <div key={rating.label}>
78
- <p className="text-sm text-text-secondary">{rating.label}</p>
79
- <div className="flex items-center gap-2 mt-1">
80
- <Progress value={rating.value * 20} className="flex-1 h-2" />
81
- <span className="text-sm font-medium">{rating.value.toFixed(1)}</span>
82
- </div>
96
+ {/* Ratings — the page's single emphasis zone */}
97
+ <EmphasisPanel>
98
+ <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary mb-4">
99
+ <Star size={18} /> Ratings
100
+ </h2>
101
+ <div className="grid grid-cols-2 md:grid-cols-3 gap-4">
102
+ {[
103
+ { label: 'Punctuality', value: driver.ratings.punctuality },
104
+ { label: 'Communication', value: driver.ratings.communication },
105
+ { label: 'Handling', value: driver.ratings.carefulHandling },
106
+ { label: 'Professionalism', value: driver.ratings.professionalism },
107
+ { label: 'On-Time Delivery', value: driver.ratings.onTimeDelivery },
108
+ ].map((rating) => (
109
+ <div key={rating.label}>
110
+ <p className="text-sm text-text-secondary">{rating.label}</p>
111
+ <div className="flex items-center gap-2 mt-1">
112
+ <Progress value={rating.value * 20} className="flex-1 h-2" />
113
+ <span className="text-sm font-medium">{rating.value.toFixed(1)}</span>
83
114
  </div>
84
- ))}
85
- </div>
86
- </CardContent>
87
- </Card>
115
+ </div>
116
+ ))}
117
+ </div>
118
+ </EmphasisPanel>
88
119
 
89
120
  {/* Working Hours */}
90
121
  <Card>
@@ -7,7 +7,7 @@ import { PageLayout } from '../components/PageLayout';
7
7
  import { DataTable, type Column } from '../components/DataTable';
8
8
  import { StatusBadge } from '../components/StatusBadge';
9
9
  import { Avatar, AvatarFallback } from '../components/ui';
10
- import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
10
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
11
11
  import { useDrivers } from '../hooks/useFleet';
12
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
13
13
  import { formatDate } from '../utils/formatters';
@@ -100,6 +100,39 @@ export default function DriversPage() {
100
100
  />
101
101
  }
102
102
  >
103
+ <PagePurpose icon={<Users size={18} />}>
104
+ Your delivery workforce. Track each driver&apos;s availability, performance rating,
105
+ completed deliveries and license status here — open a driver to review their history before
106
+ assigning them to an order or route.
107
+ </PagePurpose>
108
+
109
+ {/* Workforce at a glance — the page's single emphasis zone */}
110
+ <EmphasisPanel>
111
+ <p className="text-sm font-medium text-text-secondary">Workforce at a glance</p>
112
+ <div className="mt-3 grid grid-cols-3 gap-4">
113
+ <div>
114
+ <p className="text-2xl font-bold text-text-primary tabular-nums">{totalDrivers}</p>
115
+ <p className="text-xs text-text-secondary">Total drivers</p>
116
+ </div>
117
+ <div>
118
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
119
+ {drivers.filter((d) => d.status === 'available' || d.status === 'busy').length}
120
+ </p>
121
+ <p className="text-xs text-text-secondary">On duty / available</p>
122
+ </div>
123
+ <div>
124
+ <p className="text-2xl font-bold text-text-primary tabular-nums">
125
+ {drivers.length > 0
126
+ ? (drivers.reduce((sum, d) => sum + d.ratings.overall, 0) / drivers.length).toFixed(
127
+ 1
128
+ )
129
+ : '—'}
130
+ </p>
131
+ <p className="text-xs text-text-secondary">Avg rating</p>
132
+ </div>
133
+ </div>
134
+ </EmphasisPanel>
135
+
103
136
  <DataTable
104
137
  columns={columns}
105
138
  data={drivers}
@@ -109,6 +142,9 @@ export default function DriversPage() {
109
142
  searchFields={['fullName', 'employeeId'] as (keyof Driver)[]}
110
143
  onRowClick={(row) => goTo(`fleet/drivers/${row.id}`)}
111
144
  getRowId={(row) => row.id}
145
+ emptyIllustration="empty-people"
146
+ emptyTitle="No drivers yet"
147
+ emptyDescription="Add drivers to start assigning deliveries and routes."
112
148
  />
113
149
  </PageLayout>
114
150
  );
@@ -6,6 +6,7 @@ import { DollarSign, TrendingUp, CreditCard, FileText, Download } from 'lucide-r
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { MetricCard, MetricGrid } from '../components/MetricCard';
8
8
  import { Card, CardContent, CardHeader, CardTitle, Button } from '../components/ui';
9
+ import { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';
9
10
  import { useAnalytics } from '../hooks/useAnalytics';
10
11
  import { useOrderStats } from '../hooks/useOrders';
11
12
  import { formatCurrency } from '../utils/formatters';
@@ -33,8 +34,16 @@ export default function FinancePage() {
33
34
  </div>
34
35
  }
35
36
  >
37
+ <PagePurpose icon={<DollarSign size={18} />}>
38
+ Follow the money behind your deliveries. See revenue earned, what&apos;s been collected
39
+ versus still owed, and average order value — use it to chase pending payments, forecast cash
40
+ flow, and confirm which shipments have actually been paid for.
41
+ </PagePurpose>
42
+
36
43
  <MetricGrid columns={4}>
37
44
  <MetricCard
45
+ treatment="glass"
46
+ glow
38
47
  label="Total Revenue"
39
48
  value={formatCurrency(analytics.overview.totalRevenue)}
40
49
  icon={<DollarSign size={20} />}
@@ -81,47 +90,42 @@ export default function FinancePage() {
81
90
  </CardContent>
82
91
  </Card>
83
92
 
84
- <Card>
85
- <CardHeader>
86
- <CardTitle>Payment Status</CardTitle>
87
- </CardHeader>
88
- <CardContent>
89
- <div className="space-y-4">
90
- <div className="flex items-center justify-between p-4 bg-green-50 dark:bg-green-900/20 rounded-lg">
91
- <div className="flex items-center gap-3">
92
- <div className="w-10 h-10 rounded-full bg-green-100 dark:bg-green-800 flex items-center justify-center">
93
- <TrendingUp size={20} className="text-green-600" />
94
- </div>
95
- <div>
96
- <p className="font-medium">Paid</p>
97
- <p className="text-sm text-text-secondary">
98
- {stats.byStatus.delivered} orders
99
- </p>
100
- </div>
93
+ {/* Payment Status — the page's single emphasis zone */}
94
+ <EmphasisPanel className="space-y-4">
95
+ <h2 className="text-base font-semibold text-text-primary">Payment Status</h2>
96
+ <div className="space-y-4">
97
+ <div className="flex items-center justify-between p-4 bg-status-success-bg/10 rounded-lg">
98
+ <div className="flex items-center gap-3">
99
+ <div className="w-10 h-10 rounded-full bg-status-success-bg/20 flex items-center justify-center">
100
+ <TrendingUp size={20} className="text-status-success-text" />
101
+ </div>
102
+ <div>
103
+ <p className="font-medium">Paid</p>
104
+ <p className="text-sm text-text-secondary">{stats.byStatus.delivered} orders</p>
101
105
  </div>
102
- <span className="text-xl font-bold text-green-600">
103
- {formatCurrency(completedPayments)}
104
- </span>
105
106
  </div>
106
- <div className="flex items-center justify-between p-4 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg">
107
- <div className="flex items-center gap-3">
108
- <div className="w-10 h-10 rounded-full bg-yellow-100 dark:bg-yellow-800 flex items-center justify-center">
109
- <CreditCard size={20} className="text-yellow-600" />
110
- </div>
111
- <div>
112
- <p className="font-medium">Pending</p>
113
- <p className="text-sm text-text-secondary">
114
- {stats.byStatus.pending + stats.byStatus.in_transit} orders
115
- </p>
116
- </div>
107
+ <span className="text-xl font-bold text-status-success-text">
108
+ {formatCurrency(completedPayments)}
109
+ </span>
110
+ </div>
111
+ <div className="flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg">
112
+ <div className="flex items-center gap-3">
113
+ <div className="w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center">
114
+ <CreditCard size={20} className="text-status-warning-text" />
115
+ </div>
116
+ <div>
117
+ <p className="font-medium">Pending</p>
118
+ <p className="text-sm text-text-secondary">
119
+ {stats.byStatus.pending + stats.byStatus.in_transit} orders
120
+ </p>
117
121
  </div>
118
- <span className="text-xl font-bold text-yellow-600">
119
- {formatCurrency(pendingPayments)}
120
- </span>
121
122
  </div>
123
+ <span className="text-xl font-bold text-status-warning-text">
124
+ {formatCurrency(pendingPayments)}
125
+ </span>
122
126
  </div>
123
- </CardContent>
124
- </Card>
127
+ </div>
128
+ </EmphasisPanel>
125
129
  </div>
126
130
 
127
131
  <Card>
@@ -129,11 +133,11 @@ export default function FinancePage() {
129
133
  <CardTitle>Recent Transactions</CardTitle>
130
134
  </CardHeader>
131
135
  <CardContent>
132
- <div className="text-center py-8 text-text-secondary">
133
- <FileText size={48} className="mx-auto mb-4 opacity-50" />
134
- <p>Transaction history would be displayed here</p>
135
- <p className="text-sm">Integration with payment gateway required</p>
136
- </div>
136
+ <IllustratedEmptyState
137
+ illustration="empty-data"
138
+ title="No transactions yet"
139
+ description="Once payments are processed, your transaction history will appear here. Connect a payment gateway to start recording transactions."
140
+ />
137
141
  </CardContent>
138
142
  </Card>
139
143
  </PageLayout>
@@ -18,7 +18,7 @@ import {
18
18
  Avatar,
19
19
  AvatarFallback,
20
20
  } from '../components/ui';
21
- import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
21
+ import { CTAOverflowMenu, EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';
22
22
  import { useFleetStats, useVehicles, useDrivers } from '../hooks/useFleet';
23
23
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
24
24
  import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
@@ -63,6 +63,49 @@ export default function FleetPage() {
63
63
  />
64
64
  }
65
65
  >
66
+ <PagePurpose icon={<Truck size={18} />}>
67
+ {t(
68
+ 'movethewheels.fleet.purpose',
69
+ 'Your command center for vehicles and drivers. See utilization at a glance, keep an eye on availability and ratings, and act on maintenance alerts so you always have road-ready capacity to fulfil orders.'
70
+ )}
71
+ </PagePurpose>
72
+
73
+ <NextSteps
74
+ storageKey="movethewheels-fleet"
75
+ steps={[
76
+ {
77
+ id: 'vehicles',
78
+ label: t('movethewheels.fleet.nextSteps.vehicles', 'Review your vehicles'),
79
+ description: t(
80
+ 'movethewheels.fleet.nextSteps.vehiclesDesc',
81
+ 'Check capacity, fuel and maintenance status across the fleet.'
82
+ ),
83
+ icon: <Truck size={16} />,
84
+ onClick: () => goTo('fleet/vehicles'),
85
+ },
86
+ {
87
+ id: 'drivers',
88
+ label: t('movethewheels.fleet.nextSteps.drivers', 'Review your drivers'),
89
+ description: t(
90
+ 'movethewheels.fleet.nextSteps.driversDesc',
91
+ 'See availability, ratings and delivery history before assigning work.'
92
+ ),
93
+ icon: <Users size={16} />,
94
+ onClick: () => goTo('fleet/drivers'),
95
+ },
96
+ {
97
+ id: 'assign',
98
+ label: t('movethewheels.fleet.nextSteps.assign', 'Assign capacity to orders'),
99
+ description: t(
100
+ 'movethewheels.fleet.nextSteps.assignDesc',
101
+ 'Open an order to assign an available vehicle and driver.'
102
+ ),
103
+ icon: <ChevronRight size={16} />,
104
+ onClick: () => goTo('orders'),
105
+ },
106
+ ]}
107
+ />
108
+
66
109
  {/* Key Metrics */}
67
110
  <MetricGrid columns={4}>
68
111
  <MetricCard
@@ -80,6 +123,8 @@ export default function FleetPage() {
80
123
  onClick={() => goTo('fleet/drivers')}
81
124
  />
82
125
  <MetricCard
126
+ treatment="glass"
127
+ glow
83
128
  label={t('movethewheels.fleet.metrics.utilization', 'Fleet Utilization')}
84
129
  value={`${stats.utilization.toFixed(0)}%`}
85
130
  icon={<Truck size={20} />}
@@ -202,29 +247,27 @@ export default function FleetPage() {
202
247
  </PageSection>
203
248
  </div>
204
249
 
205
- {/* Status Summary */}
250
+ {/* Status Summary — Vehicle Status is the page's single emphasis zone */}
206
251
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
207
252
  {/* Vehicle Status */}
208
- <Card>
209
- <CardHeader>
210
- <CardTitle>{t('movethewheels.fleet.status.vehicleTitle', 'Vehicle Status')}</CardTitle>
211
- </CardHeader>
212
- <CardContent>
213
- <div className="space-y-4">
214
- {Object.entries(stats.vehiclesByStatus).map(([status, count]) => (
215
- <div key={status} className="flex items-center justify-between">
216
- <div className="flex items-center gap-3">
217
- <StatusBadge status={status} type="vehicle" />
218
- </div>
219
- <div className="flex items-center gap-3">
220
- <span className="font-medium">{count}</span>
221
- <Progress value={(count / stats.totalVehicles) * 100} className="w-24 h-2" />
222
- </div>
253
+ <EmphasisPanel className="space-y-4">
254
+ <h2 className="text-base font-semibold text-text-primary">
255
+ {t('movethewheels.fleet.status.vehicleTitle', 'Vehicle Status')}
256
+ </h2>
257
+ <div className="space-y-4">
258
+ {Object.entries(stats.vehiclesByStatus).map(([status, count]) => (
259
+ <div key={status} className="flex items-center justify-between">
260
+ <div className="flex items-center gap-3">
261
+ <StatusBadge status={status} type="vehicle" />
223
262
  </div>
224
- ))}
225
- </div>
226
- </CardContent>
227
- </Card>
263
+ <div className="flex items-center gap-3">
264
+ <span className="font-medium">{count}</span>
265
+ <Progress value={(count / stats.totalVehicles) * 100} className="w-24 h-2" />
266
+ </div>
267
+ </div>
268
+ ))}
269
+ </div>
270
+ </EmphasisPanel>
228
271
 
229
272
  {/* Driver Status */}
230
273
  <Card>
@@ -251,9 +294,9 @@ export default function FleetPage() {
251
294
 
252
295
  {/* Maintenance Alerts */}
253
296
  {stats.vehiclesByStatus.maintenance > 0 && (
254
- <Card className="border-yellow-200 dark:border-yellow-800">
297
+ <Card className="border-status-warning-border">
255
298
  <CardHeader>
256
- <CardTitle className="flex items-center gap-2 text-yellow-600">
299
+ <CardTitle className="flex items-center gap-2 text-status-warning-text">
257
300
  <Wrench size={18} />
258
301
  {t('movethewheels.fleet.maintenance.title', 'Maintenance Required')}
259
302
  </CardTitle>
@@ -265,10 +308,10 @@ export default function FleetPage() {
265
308
  .map((vehicle) => (
266
309
  <div
267
310
  key={vehicle.id}
268
- className="flex items-center justify-between p-3 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg"
311
+ className="flex items-center justify-between p-3 bg-status-warning-bg/10 rounded-lg"
269
312
  >
270
313
  <div className="flex items-center gap-3">
271
- <Truck size={20} className="text-yellow-600" />
314
+ <Truck size={20} className="text-status-warning-text" />
272
315
  <div>
273
316
  <p className="font-medium">{vehicle.vehicleNumber}</p>
274
317
  <p className="text-sm text-text-secondary">
@@ -5,6 +5,7 @@
5
5
  import { Upload, Download, FileText, FileSpreadsheet, Check } from 'lucide-react';
6
6
  import { PageLayout } from '../components/PageLayout';
7
7
  import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
8
+ import { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';
8
9
 
9
10
  export default function ImportExportPage() {
10
11
  const importOptions = [
@@ -69,14 +70,19 @@ export default function ImportExportPage() {
69
70
  subtitle="Import and export your data"
70
71
  icon={<FileText size={24} />}
71
72
  >
73
+ <PagePurpose icon={<FileText size={18} />}>
74
+ Move data in and out in bulk. Import orders, customers, products or inventory from CSV/Excel
75
+ to onboard or migrate without re-keying, and export any dataset for accounting, BI tools or
76
+ backups — no manual copy-paste required.
77
+ </PagePurpose>
78
+
72
79
  <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
73
- <Card>
74
- <CardHeader>
75
- <CardTitle className="flex items-center gap-2">
76
- <Upload size={18} /> Import Data
77
- </CardTitle>
78
- </CardHeader>
79
- <CardContent className="space-y-4">
80
+ {/* Import Data — the page's single emphasis zone */}
81
+ <EmphasisPanel className="space-y-4">
82
+ <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
83
+ <Upload size={18} /> Import Data
84
+ </h2>
85
+ <div className="space-y-4">
80
86
  {importOptions.map((opt) => (
81
87
  <div
82
88
  key={opt.name}
@@ -99,8 +105,8 @@ export default function ImportExportPage() {
99
105
  </div>
100
106
  </div>
101
107
  ))}
102
- </CardContent>
103
- </Card>
108
+ </div>
109
+ </EmphasisPanel>
104
110
 
105
111
  <Card>
106
112
  <CardHeader>
@@ -136,28 +142,39 @@ export default function ImportExportPage() {
136
142
  <CardTitle>Recent Activity</CardTitle>
137
143
  </CardHeader>
138
144
  <CardContent>
139
- <div className="space-y-3">
140
- {recentActivity.map((activity, i) => (
141
- <div key={i} className="flex items-center justify-between p-3 bg-bg-sunken/50 rounded-lg">
142
- <div className="flex items-center gap-3">
143
- {activity.type === 'import' ? (
144
- <Upload size={16} className="text-primary" />
145
- ) : (
146
- <Download size={16} className="text-primary" />
147
- )}
148
- <div>
149
- <p className="font-medium">{activity.name}</p>
150
- <p className="text-sm text-text-secondary">
151
- {activity.type === 'import' ? 'Imported' : 'Exported'} on {activity.date}
152
- </p>
145
+ {recentActivity.length === 0 ? (
146
+ <IllustratedEmptyState
147
+ illustration="empty-data"
148
+ title="No import or export activity yet"
149
+ description="Your recent imports and exports will show up here once you run one."
150
+ />
151
+ ) : (
152
+ <div className="space-y-3">
153
+ {recentActivity.map((activity, i) => (
154
+ <div
155
+ key={i}
156
+ className="flex items-center justify-between p-3 bg-bg-sunken/50 rounded-lg"
157
+ >
158
+ <div className="flex items-center gap-3">
159
+ {activity.type === 'import' ? (
160
+ <Upload size={16} className="text-primary" />
161
+ ) : (
162
+ <Download size={16} className="text-primary" />
163
+ )}
164
+ <div>
165
+ <p className="font-medium">{activity.name}</p>
166
+ <p className="text-sm text-text-secondary">
167
+ {activity.type === 'import' ? 'Imported' : 'Exported'} on {activity.date}
168
+ </p>
169
+ </div>
153
170
  </div>
171
+ <Badge variant="default" className="gap-1">
172
+ <Check size={12} /> {activity.status}
173
+ </Badge>
154
174
  </div>
155
- <Badge variant="default" className="gap-1">
156
- <Check size={12} /> {activity.status}
157
- </Badge>
158
- </div>
159
- ))}
160
- </div>
175
+ ))}
176
+ </div>
177
+ )}
161
178
  </CardContent>
162
179
  </Card>
163
180
  </PageLayout>