@burdenoff/microfe-movethewheels 2026.626.2 → 2026.703.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 (120) hide show
  1. package/dist/{AIAssistantPage-AvsMbunM.js → AIAssistantPage-C3ovZ0Fh.js} +100 -73
  2. package/dist/AnalyticsPage-O8SpY-V4.js +215 -0
  3. package/dist/{CreateOrderPage-CjlnEtk3.js → CreateOrderPage-CB1_-_mN.js} +33 -35
  4. package/dist/{CustomerDetailsPage-I6cdDHUi.js → CustomerDetailsPage-BaeKEI1D.js} +42 -44
  5. package/dist/{CustomersPage-CGGfD4ki.js → CustomersPage-DRaLuHMC.js} +26 -28
  6. package/dist/{DashboardPage-D2HRqwg9.js → DashboardPage-DPjhNfKB.js} +85 -83
  7. package/dist/{DataTable-CD9ZhpLB.js → DataTable-DmciIKKM.js} +3 -3
  8. package/dist/{DriverDetailsPage-rg_pGNuP.js → DriverDetailsPage-CSSQTOzn.js} +52 -54
  9. package/dist/{DriversPage-DKiynISH.js → DriversPage-C2Bk0w4Q.js} +24 -26
  10. package/dist/{FinancePage-Vg8WPs38.js → FinancePage-lmp0Sdsw.js} +9 -9
  11. package/dist/FleetPage-DZn5pIqd.js +365 -0
  12. package/dist/ImportExportPage-BIUJZc7O.js +290 -0
  13. package/dist/InventoryPage-Cxh1zYJd.js +253 -0
  14. package/dist/{LiveTrackingPage-DQ1q4Id3.js → LiveTrackingPage-BY1yAkIt.js} +60 -56
  15. package/dist/MarketplacePage-RMuL17EA.js +247 -0
  16. package/dist/{MetricCard-B7yMyvMX.js → MetricCard-7aYgzZHK.js} +1 -1
  17. package/dist/{OrderDetailsPage-CFASgsYX.js → OrderDetailsPage-C2Mf4KSy.js} +83 -85
  18. package/dist/{OrdersListPage-BHeT8S5o.js → OrdersListPage-BrPBtnhp.js} +31 -33
  19. package/dist/{PageLayout-D3N8MCTm.js → PageLayout-D4LDHJJq.js} +483 -422
  20. package/dist/{ProductDetailsPage-CFGcbaHo.js → ProductDetailsPage-CezzzZcj.js} +27 -29
  21. package/dist/{ProductsPage--xEpbQ8A.js → ProductsPage-I5DilIoY.js} +21 -23
  22. package/dist/ReportsPage-BDXNmUng.js +284 -0
  23. package/dist/RouteDetailsPage-BcomL20M.js +263 -0
  24. package/dist/RoutesPage-lqX9ylHP.js +144 -0
  25. package/dist/SettingsPage-CQVIOaNs.js +421 -0
  26. package/dist/StatusBadge-NpTeHVlw.js +152 -0
  27. package/dist/{TrackingPage-CcRc_dva.js → TrackingPage-BXrjz7V8.js} +59 -61
  28. package/dist/{VehicleDetailsPage-3YDMPsPs.js → VehicleDetailsPage-DZjLcJgr.js} +40 -42
  29. package/dist/{VehiclesPage-UlxPWP9K.js → VehiclesPage-6W39XT5W.js} +19 -21
  30. package/dist/{WarehouseDetailsPage-Db7KeN-d.js → WarehouseDetailsPage-C10pgRGW.js} +38 -40
  31. package/dist/{WarehousesPage-CuTO-OPp.js → WarehousesPage-CHvBqNaQ.js} +15 -17
  32. package/dist/{arrow-left-CBpZKkpq.js → arrow-left-n48Y-Wis.js} +1 -1
  33. package/dist/{box-CAaiElsb.js → box-D9Pal4HM.js} +1 -1
  34. package/dist/{chart-column-D1Ym15-S.js → chart-column-BFIJysDR.js} +1 -1
  35. package/dist/{chevron-right-BIFGi0UA.js → chevron-right-EMIIyyJ1.js} +1 -1
  36. package/dist/{circle-alert-DjmNo5_L.js → circle-alert-iY24lSlp.js} +1 -1
  37. package/dist/{circle-check-big-CjuPVo3_.js → circle-check-big-w0TrLKMF.js} +1 -1
  38. package/dist/{clock-BjkdnddD.js → clock-DJZtdl8u.js} +1 -1
  39. package/dist/{dollar-sign-IB4O0wuQ.js → dollar-sign-CgKQRz_e.js} +1 -1
  40. package/dist/{download-Dpa9vqoG.js → download-DRXxoiQR.js} +1 -1
  41. package/dist/{file-text-C8Uioy11.js → file-text-DWWY6_f5.js} +1 -1
  42. package/dist/{filter-Da5OZaHI.js → filter-DloLC2eE.js} +1 -1
  43. package/dist/index.js +119 -111
  44. package/dist/{map-_Per4sT9.js → map-CkJaULb2.js} +1 -1
  45. package/dist/{map-pin-BSaf5IDL.js → map-pin-BGiCvyCs.js} +1 -1
  46. package/dist/{navigation-DaTbrhw2.js → navigation-D36prnAn.js} +1 -1
  47. package/dist/{package-BE7U0wQE.js → package-BChUzpJS.js} +1 -1
  48. package/dist/{phone-DV4StZiA.js → phone-Ac9s3mo_.js} +1 -1
  49. package/dist/{plus-Dl1rLeJR.js → plus-Z76q-FZm.js} +1 -1
  50. package/dist/{refresh-cw-CWfERAit.js → refresh-cw-DKt6f5T6.js} +1 -1
  51. package/dist/{save-XH8vydOn.js → save-CojywNhG.js} +1 -1
  52. package/dist/{search-OxoIiL_C.js → search-CDGefqb3.js} +1 -1
  53. package/dist/{square-pen-hLIbFQFV.js → square-pen-CopE9GmB.js} +1 -1
  54. package/dist/{star-YsVV3MNQ.js → star-nHlLjDKR.js} +1 -1
  55. package/dist/{store-RCBl7HB-.js → store-BR9Voi5E.js} +1 -1
  56. package/dist/{trending-up-C-85AwGT.js → trending-up-B7W-GL6P.js} +1 -1
  57. package/dist/{triangle-alert-BOhfGgmh.js → triangle-alert-BonHFFNz.js} +1 -1
  58. package/dist/{truck-CtDjNFbi.js → truck-DrlfSpRC.js} +1 -1
  59. package/dist/{useAnalytics-ph7eTIK6.js → useAnalytics-CgdzUfY_.js} +40 -40
  60. package/dist/useAssistant-D4v3oxD3.js +84 -0
  61. package/dist/{useCustomers-bS3a4ytk.js → useCustomers-QrlozybF.js} +24 -24
  62. package/dist/{useFleet-BdETplNE.js → useFleet-DiAC-IiH.js} +70 -67
  63. package/dist/useImportExport-BLMnAKCC.js +55 -0
  64. package/dist/{useInventory-Dwn18FPz.js → useInventory-DKoks37x.js} +33 -33
  65. package/dist/{useOrders-D_3_hGMp.js → useOrders-D3UZVy8Y.js} +42 -42
  66. package/dist/useReports-Puq4DCH9.js +78 -0
  67. package/dist/{useRoutes-v4aBaS-E.js → useRoutes-Do57LvRb.js} +31 -31
  68. package/dist/useSettings-CkDH_-gM.js +81 -0
  69. package/dist/{useTracking-De2KIUNu.js → useTracking-GJify4HN.js} +22 -22
  70. package/dist/{user-Dz5TJZFs.js → user-CjSoudeu.js} +1 -1
  71. package/dist/{users-g2N0eL-Z.js → users-BAM4gHTn.js} +1 -1
  72. package/dist/{warehouse-D3WWDeTX.js → warehouse-C7MSr47B.js} +1 -1
  73. package/dist/{wrench-CmxY1n4I.js → wrench-CANXWxF-.js} +1 -1
  74. package/package.json +1 -1
  75. package/src/movethewheels/MoveTheWheelsRoutes.tsx +27 -3
  76. package/src/movethewheels/components/StatusBadge.tsx +18 -37
  77. package/src/movethewheels/constants/index.ts +67 -26
  78. package/src/movethewheels/hooks/index.ts +12 -0
  79. package/src/movethewheels/hooks/useAnalytics.ts +20 -6
  80. package/src/movethewheels/hooks/useAssistant.ts +74 -0
  81. package/src/movethewheels/hooks/useFleet.ts +63 -59
  82. package/src/movethewheels/hooks/useImportExport.ts +101 -0
  83. package/src/movethewheels/hooks/useReports.ts +158 -0
  84. package/src/movethewheels/hooks/useSettings.ts +120 -0
  85. package/src/movethewheels/pages/AIAssistantPage.tsx +53 -15
  86. package/src/movethewheels/pages/AnalyticsPage.tsx +67 -64
  87. package/src/movethewheels/pages/CustomerDetailsPage.tsx +1 -1
  88. package/src/movethewheels/pages/CustomersPage.tsx +1 -1
  89. package/src/movethewheels/pages/DashboardPage.tsx +42 -22
  90. package/src/movethewheels/pages/DriverDetailsPage.tsx +1 -1
  91. package/src/movethewheels/pages/DriversPage.tsx +1 -1
  92. package/src/movethewheels/pages/FleetPage.tsx +96 -38
  93. package/src/movethewheels/pages/ImportExportPage.tsx +174 -68
  94. package/src/movethewheels/pages/InventoryPage.tsx +66 -28
  95. package/src/movethewheels/pages/LiveTrackingPage.tsx +12 -3
  96. package/src/movethewheels/pages/MarketplacePage.tsx +87 -45
  97. package/src/movethewheels/pages/OrderDetailsPage.tsx +2 -2
  98. package/src/movethewheels/pages/ReportsPage.tsx +194 -90
  99. package/src/movethewheels/pages/RouteDetailsPage.tsx +5 -11
  100. package/src/movethewheels/pages/RoutesPage.tsx +4 -9
  101. package/src/movethewheels/pages/SettingsPage.tsx +234 -56
  102. package/src/movethewheels/pages/TrackingPage.tsx +6 -6
  103. package/src/movethewheels/providers/MoveTheWheelsProvider.tsx +7 -6
  104. package/src/movethewheels/store/movethewheelsStore.ts +1 -1
  105. package/dist/AnalyticsPage-CCLfHgQZ.js +0 -212
  106. package/dist/FleetPage-DddXt8r8.js +0 -332
  107. package/dist/ImportExportPage-BW6qO3kc.js +0 -248
  108. package/dist/InventoryPage-rMGuaJN-.js +0 -222
  109. package/dist/MarketplacePage-DKrXAv62.js +0 -219
  110. package/dist/ReportsPage-Bb7_90rK.js +0 -235
  111. package/dist/RouteDetailsPage-CVtDVb1N.js +0 -282
  112. package/dist/RoutesPage-s57PtgcQ.js +0 -163
  113. package/dist/SettingsPage-BYNCBOpN.js +0 -298
  114. package/dist/StatusBadge-CijYQXtb.js +0 -209
  115. package/dist/graphqlClient-CdJyR_ed.js +0 -55
  116. package/dist/navigation-BgnOfsVd.js +0 -6
  117. package/dist/route-Dp9JiN_E.js +0 -51
  118. package/dist/settings-3Rw5NwFF.js +0 -28
  119. package/src/movethewheels/constants/mockData.ts +0 -1342
  120. /package/dist/{formatters-_vJlC-47.js → formatters-DhKZ-eA1.js} +0 -0
@@ -56,6 +56,13 @@ export default function DashboardPage() {
56
56
  }
57
57
  };
58
58
 
59
+ const onRowKeyDown = (e: React.KeyboardEvent, action: () => void) => {
60
+ if (e.key === 'Enter' || e.key === ' ') {
61
+ e.preventDefault();
62
+ action();
63
+ }
64
+ };
65
+
59
66
  return (
60
67
  <PageLayout
61
68
  hero
@@ -93,9 +100,6 @@ export default function DashboardPage() {
93
100
  label={t('movethewheels.dashboard.metrics.totalOrders', 'Total Orders')}
94
101
  value={metrics.orders.total}
95
102
  icon={<Package size={20} />}
96
- change={`+${metrics.orders.today} ${t('movethewheels.dashboard.metrics.today', 'today')}`}
97
- changeType="positive"
98
- trend="up"
99
103
  onClick={() => goTo('orders')}
100
104
  />
101
105
  <MetricCard
@@ -118,9 +122,6 @@ export default function DashboardPage() {
118
122
  label={t('movethewheels.dashboard.metrics.revenue', 'Revenue')}
119
123
  value={formatCurrency(metrics.revenue.total)}
120
124
  icon={<DollarSign size={20} />}
121
- change="+12.5%"
122
- changeType="positive"
123
- trend="up"
124
125
  onClick={() => goTo('analytics')}
125
126
  />
126
127
  </MetricGrid>
@@ -167,8 +168,12 @@ export default function DashboardPage() {
167
168
  {orders.slice(0, 5).map((order) => (
168
169
  <div
169
170
  key={order.id}
170
- className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors"
171
+ role="button"
172
+ tabIndex={0}
173
+ aria-label={`View order ${order.orderNumber}`}
174
+ className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg"
171
175
  onClick={() => goTo(`orders/${order.id}`)}
176
+ onKeyDown={(e) => onRowKeyDown(e, () => goTo(`orders/${order.id}`))}
172
177
  >
173
178
  <div className="flex items-center justify-between">
174
179
  <div>
@@ -211,8 +216,15 @@ export default function DashboardPage() {
211
216
  delivery.order ? (
212
217
  <div
213
218
  key={delivery.order.id}
214
- className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors"
219
+ role="button"
220
+ tabIndex={0}
221
+ aria-label={`Track order ${delivery.order.orderNumber}`}
222
+ className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg"
215
223
  onClick={() => goTo(`tracking?order=${delivery.order.id}`)}
224
+ onKeyDown={(e) =>
225
+ delivery.order &&
226
+ onRowKeyDown(e, () => goTo(`tracking?order=${delivery.order.id}`))
227
+ }
216
228
  >
217
229
  <div className="flex items-center justify-between">
218
230
  <div>
@@ -257,18 +269,26 @@ export default function DashboardPage() {
257
269
  </h2>
258
270
  <div className="space-y-3">
259
271
  {[
260
- { status: 'pending', count: orderStats.byStatus.pending, color: 'bg-yellow-500' },
272
+ {
273
+ status: 'pending',
274
+ count: orderStats.byStatus.pending,
275
+ color: 'bg-status-warning-text',
276
+ },
261
277
  {
262
278
  status: 'in_transit',
263
279
  count: orderStats.byStatus.in_transit,
264
- color: 'bg-blue-500',
280
+ color: 'bg-status-info-text',
265
281
  },
266
282
  {
267
283
  status: 'delivered',
268
284
  count: orderStats.byStatus.delivered,
269
- color: 'bg-green-500',
285
+ color: 'bg-status-success-text',
286
+ },
287
+ {
288
+ status: 'cancelled',
289
+ count: orderStats.byStatus.cancelled,
290
+ color: 'bg-status-error-text',
270
291
  },
271
- { status: 'cancelled', count: orderStats.byStatus.cancelled, color: 'bg-red-500' },
272
292
  ].map(({ status, count, color }) => (
273
293
  <div key={status} className="flex items-center justify-between">
274
294
  <div className="flex items-center gap-2">
@@ -313,7 +333,7 @@ export default function DashboardPage() {
313
333
  <p className="text-text-secondary">
314
334
  {t('movethewheels.dashboard.fleetStatus.available', 'Available')}
315
335
  </p>
316
- <p className="text-lg font-semibold text-green-600">
336
+ <p className="text-lg font-semibold text-status-success-text">
317
337
  {fleetStats.vehiclesByStatus.available}
318
338
  </p>
319
339
  </div>
@@ -321,7 +341,7 @@ export default function DashboardPage() {
321
341
  <p className="text-text-secondary">
322
342
  {t('movethewheels.dashboard.fleetStatus.inUse', 'In Use')}
323
343
  </p>
324
- <p className="text-lg font-semibold text-blue-600">
344
+ <p className="text-lg font-semibold text-status-info-text">
325
345
  {fleetStats.vehiclesByStatus.assigned}
326
346
  </p>
327
347
  </div>
@@ -329,7 +349,7 @@ export default function DashboardPage() {
329
349
  <p className="text-text-secondary">
330
350
  {t('movethewheels.dashboard.fleetStatus.maintenance', 'Maintenance')}
331
351
  </p>
332
- <p className="text-lg font-semibold text-yellow-600">
352
+ <p className="text-lg font-semibold text-status-warning-text">
333
353
  {fleetStats.vehiclesByStatus.maintenance}
334
354
  </p>
335
355
  </div>
@@ -347,15 +367,15 @@ export default function DashboardPage() {
347
367
  <Card>
348
368
  <CardHeader>
349
369
  <CardTitle className="text-base flex items-center gap-2">
350
- <AlertTriangle size={16} className="text-yellow-500" />
370
+ <AlertTriangle size={16} className="text-status-warning-text" />
351
371
  {t('movethewheels.dashboard.alerts.title', 'Alerts')}
352
372
  </CardTitle>
353
373
  </CardHeader>
354
374
  <CardContent>
355
375
  <div className="space-y-3">
356
376
  {orderStats.byStatus.pending > 5 && (
357
- <div className="flex items-start gap-3 p-2 rounded bg-yellow-50 dark:bg-yellow-900/20">
358
- <Clock size={16} className="text-yellow-600 mt-0.5" />
377
+ <div className="flex items-start gap-3 p-2 rounded bg-status-warning-bg-subtle">
378
+ <Clock size={16} className="text-status-warning-text mt-0.5" />
359
379
  <div>
360
380
  <p className="text-sm font-medium">
361
381
  {t('movethewheels.dashboard.alerts.pendingOrders.title', 'Pending Orders')}
@@ -371,8 +391,8 @@ export default function DashboardPage() {
371
391
  </div>
372
392
  )}
373
393
  {fleetStats.vehiclesByStatus.maintenance > 0 && (
374
- <div className="flex items-start gap-3 p-2 rounded bg-orange-50 dark:bg-orange-900/20">
375
- <Truck size={16} className="text-orange-600 mt-0.5" />
394
+ <div className="flex items-start gap-3 p-2 rounded bg-status-warning-bg-subtle">
395
+ <Truck size={16} className="text-status-warning-text mt-0.5" />
376
396
  <div>
377
397
  <p className="text-sm font-medium">
378
398
  {t(
@@ -391,8 +411,8 @@ export default function DashboardPage() {
391
411
  </div>
392
412
  )}
393
413
  {fleetStats.driversByStatus.offline > 0 && (
394
- <div className="flex items-start gap-3 p-2 rounded bg-gray-50 dark:bg-gray-800">
395
- <Users size={16} className="text-gray-600 mt-0.5" />
414
+ <div className="flex items-start gap-3 p-2 rounded bg-bg-sunken">
415
+ <Users size={16} className="text-text-secondary mt-0.5" />
396
416
  <div>
397
417
  <p className="text-sm font-medium">
398
418
  {t('movethewheels.dashboard.alerts.offlineDrivers.title', 'Offline Drivers')}
@@ -51,7 +51,7 @@ export default function DriverDetailsPage() {
51
51
  <div className="flex items-center gap-4">
52
52
  <StatusBadge status={driver.status} type="driver" />
53
53
  <div className="flex items-center gap-1">
54
- <Star size={16} className="text-yellow-500 fill-yellow-500" />
54
+ <Star size={16} className="text-status-warning-text fill-current" />
55
55
  <span className="font-medium">{driver.ratings.overall.toFixed(1)}</span>
56
56
  <span className="text-text-secondary">({driver.ratings.totalRatings} ratings)</span>
57
57
  </div>
@@ -53,7 +53,7 @@ export default function DriversPage() {
53
53
  header: 'Rating',
54
54
  cell: (row) => (
55
55
  <div className="flex items-center gap-1">
56
- <Star size={14} className="text-yellow-500 fill-yellow-500" />
56
+ <Star size={14} className="text-status-warning-text fill-current" />
57
57
  <span className="font-medium">{row.ratings.overall.toFixed(1)}</span>
58
58
  <span className="text-text-secondary text-sm">({row.ratings.totalRatings})</span>
59
59
  </div>
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { Truck, Users, Wrench, Fuel, Star, ChevronRight } from 'lucide-react';
8
8
  import { PageLayout, PageSection } from '../components/PageLayout';
9
- import { MetricCard, MetricGrid } from '../components/MetricCard';
9
+ import { MetricCard, MetricGrid, MetricCardSkeleton } from '../components/MetricCard';
10
10
  import { StatusBadge, VehicleTypeBadge } from '../components/StatusBadge';
11
11
  import {
12
12
  Card,
@@ -31,9 +31,32 @@ export default function FleetPage() {
31
31
  return value === key ? fallback : value;
32
32
  };
33
33
  const { basePath, navigate } = useMoveTheWheels();
34
- const { stats } = useFleetStats();
35
- const { vehicles } = useVehicles();
36
- const { drivers } = useDrivers();
34
+ const {
35
+ stats,
36
+ isLoading: statsLoading,
37
+ error: statsError,
38
+ refetch: refetchStats,
39
+ } = useFleetStats();
40
+ const {
41
+ vehicles,
42
+ isLoading: vehiclesLoading,
43
+ error: vehiclesError,
44
+ refetch: refetchVehicles,
45
+ } = useVehicles();
46
+ const {
47
+ drivers,
48
+ isLoading: driversLoading,
49
+ error: driversError,
50
+ refetch: refetchDrivers,
51
+ } = useDrivers();
52
+
53
+ const isLoading = statsLoading || vehiclesLoading || driversLoading;
54
+ const error = statsError ?? vehiclesError ?? driversError;
55
+ const refetchAll = () => {
56
+ refetchStats();
57
+ refetchVehicles();
58
+ refetchDrivers();
59
+ };
37
60
 
38
61
  const goTo = (path: string) => {
39
62
  if (navigate) {
@@ -41,6 +64,13 @@ export default function FleetPage() {
41
64
  }
42
65
  };
43
66
 
67
+ const onRowKeyDown = (e: React.KeyboardEvent, action: () => void) => {
68
+ if (e.key === 'Enter' || e.key === ' ') {
69
+ e.preventDefault();
70
+ action();
71
+ }
72
+ };
73
+
44
74
  return (
45
75
  <PageLayout
46
76
  title={t('movethewheels.fleet.title', 'Fleet Management')}
@@ -107,37 +137,57 @@ export default function FleetPage() {
107
137
  />
108
138
 
109
139
  {/* Key Metrics */}
110
- <MetricGrid columns={4}>
111
- <MetricCard
112
- label={t('movethewheels.fleet.metrics.totalVehicles', 'Total Vehicles')}
113
- value={stats.totalVehicles}
114
- icon={<Truck size={20} />}
115
- subtitle={`${stats.vehiclesByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
116
- onClick={() => goTo('fleet/vehicles')}
117
- />
118
- <MetricCard
119
- label={t('movethewheels.fleet.metrics.totalDrivers', 'Total Drivers')}
120
- value={stats.totalDrivers}
121
- icon={<Users size={20} />}
122
- subtitle={`${stats.driversByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
123
- onClick={() => goTo('fleet/drivers')}
124
- />
125
- <MetricCard
126
- treatment="glass"
127
- glow
128
- label={t('movethewheels.fleet.metrics.utilization', 'Fleet Utilization')}
129
- value={`${stats.utilization.toFixed(0)}%`}
130
- icon={<Truck size={20} />}
131
- changeType={stats.utilization >= 70 ? 'positive' : 'neutral'}
132
- />
133
- <MetricCard
134
- label={t('movethewheels.fleet.metrics.avgDriverRating', 'Avg Driver Rating')}
135
- value={stats.avgDriverRating.toFixed(1)}
136
- icon={<Star size={20} />}
137
- subtitle={t('movethewheels.fleet.metrics.outOfFive', 'out of 5')}
138
- changeType={stats.avgDriverRating >= 4.5 ? 'positive' : 'neutral'}
139
- />
140
- </MetricGrid>
140
+ {error && !isLoading ? (
141
+ <Card className="border-status-error-border">
142
+ <CardContent className="p-6 text-center space-y-3">
143
+ <p className="text-status-error-text font-medium">
144
+ {t('movethewheels.fleet.error.title', "Couldn't load fleet data")}
145
+ </p>
146
+ <p className="text-sm text-text-secondary">{error.message}</p>
147
+ <Button variant="outline" onClick={refetchAll}>
148
+ {t('movethewheels.fleet.error.retry', 'Retry')}
149
+ </Button>
150
+ </CardContent>
151
+ </Card>
152
+ ) : isLoading ? (
153
+ <MetricGrid columns={4}>
154
+ {Array.from({ length: 4 }).map((_, i) => (
155
+ <MetricCardSkeleton key={i} />
156
+ ))}
157
+ </MetricGrid>
158
+ ) : (
159
+ <MetricGrid columns={4}>
160
+ <MetricCard
161
+ label={t('movethewheels.fleet.metrics.totalVehicles', 'Total Vehicles')}
162
+ value={stats.totalVehicles}
163
+ icon={<Truck size={20} />}
164
+ subtitle={`${stats.vehiclesByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
165
+ onClick={() => goTo('fleet/vehicles')}
166
+ />
167
+ <MetricCard
168
+ label={t('movethewheels.fleet.metrics.totalDrivers', 'Total Drivers')}
169
+ value={stats.totalDrivers}
170
+ icon={<Users size={20} />}
171
+ subtitle={`${stats.driversByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
172
+ onClick={() => goTo('fleet/drivers')}
173
+ />
174
+ <MetricCard
175
+ treatment="glass"
176
+ glow
177
+ label={t('movethewheels.fleet.metrics.utilization', 'Fleet Utilization')}
178
+ value={`${stats.utilization.toFixed(0)}%`}
179
+ icon={<Truck size={20} />}
180
+ changeType={stats.utilization >= 70 ? 'positive' : 'neutral'}
181
+ />
182
+ <MetricCard
183
+ label={t('movethewheels.fleet.metrics.avgDriverRating', 'Avg Driver Rating')}
184
+ value={stats.avgDriverRating.toFixed(1)}
185
+ icon={<Star size={20} />}
186
+ subtitle={t('movethewheels.fleet.metrics.outOfFive', 'out of 5')}
187
+ changeType={stats.avgDriverRating >= 4.5 ? 'positive' : 'neutral'}
188
+ />
189
+ </MetricGrid>
190
+ )}
141
191
 
142
192
  <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
143
193
  {/* Vehicles Overview */}
@@ -155,8 +205,12 @@ export default function FleetPage() {
155
205
  {vehicles.slice(0, 5).map((vehicle) => (
156
206
  <div
157
207
  key={vehicle.id}
158
- className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors"
208
+ role="button"
209
+ tabIndex={0}
210
+ aria-label={`View vehicle ${vehicle.vehicleNumber}`}
211
+ className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg"
159
212
  onClick={() => goTo(`fleet/vehicles/${vehicle.id}`)}
213
+ onKeyDown={(e) => onRowKeyDown(e, () => goTo(`fleet/vehicles/${vehicle.id}`))}
160
214
  >
161
215
  <div className="flex items-center justify-between">
162
216
  <div className="flex items-center gap-3">
@@ -208,8 +262,12 @@ export default function FleetPage() {
208
262
  {drivers.slice(0, 5).map((driver) => (
209
263
  <div
210
264
  key={driver.id}
211
- className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors"
265
+ role="button"
266
+ tabIndex={0}
267
+ aria-label={`View driver ${driver.fullName}`}
268
+ className="p-4 hover:bg-bg-sunken/50 cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg"
212
269
  onClick={() => goTo(`fleet/drivers/${driver.id}`)}
270
+ onKeyDown={(e) => onRowKeyDown(e, () => goTo(`fleet/drivers/${driver.id}`))}
213
271
  >
214
272
  <div className="flex items-center justify-between">
215
273
  <div className="flex items-center gap-3">
@@ -232,7 +290,7 @@ export default function FleetPage() {
232
290
  <div className="text-right">
233
291
  <StatusBadge status={driver.status} type="driver" size="sm" />
234
292
  <div className="mt-1 flex items-center gap-1 justify-end">
235
- <Star size={12} className="text-yellow-500 fill-yellow-500" />
293
+ <Star size={12} className="text-status-warning-text fill-current" />
236
294
  <span className="text-sm font-medium">
237
295
  {driver.ratings.overall.toFixed(1)}
238
296
  </span>