@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
@@ -210,7 +210,7 @@ export default function OrderDetailsPage() {
210
210
  </p>
211
211
  )}
212
212
  {order.actualPickup && (
213
- <p className="text-sm text-green-600 mt-1">
213
+ <p className="text-sm text-status-success-text mt-1">
214
214
  <CheckCircle size={14} className="inline mr-1" />
215
215
  Picked up: {formatDate(order.actualPickup, 'full')}
216
216
  </p>
@@ -227,7 +227,7 @@ export default function OrderDetailsPage() {
227
227
  </p>
228
228
  )}
229
229
  {order.actualDelivery && (
230
- <p className="text-sm text-green-600 mt-1">
230
+ <p className="text-sm text-status-success-text mt-1">
231
231
  <CheckCircle size={14} className="inline mr-1" />
232
232
  Delivered: {formatDate(order.actualDelivery, 'full')}
233
233
  </p>
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * Reports Page
3
+ *
4
+ * Lists reports from the backend (movethewheelsReports) and lets operators
5
+ * create, schedule and generate them via the real mutations. Pre-launch
6
+ * workspaces start empty — no fabricated report history is shown.
3
7
  */
4
8
 
5
- import { FileBarChart, Download, Calendar, Filter, Clock } from 'lucide-react';
9
+ import { useState } from 'react';
10
+ import { FileBarChart, Download, Calendar, Filter, Clock, Plus } from 'lucide-react';
6
11
  import { PageLayout } from '../components/PageLayout';
7
12
  import {
8
13
  Card,
@@ -16,53 +21,77 @@ import {
16
21
  SelectItem,
17
22
  SelectTrigger,
18
23
  SelectValue,
24
+ Skeleton,
19
25
  } from '../components/ui';
20
- import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
26
+ import { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';
27
+ import { useReports, type CreateReportInput } from '../hooks/useReports';
28
+ import { formatDate } from '../utils/formatters';
29
+
30
+ const REPORT_TYPES: { value: string; label: string }[] = [
31
+ { value: 'operations', label: 'Operations Summary' },
32
+ { value: 'finance', label: 'Financial Report' },
33
+ { value: 'fleet', label: 'Fleet Utilization' },
34
+ { value: 'customers', label: 'Customer Analytics' },
35
+ { value: 'inventory', label: 'Inventory Status' },
36
+ ];
37
+
38
+ interface Feedback {
39
+ tone: 'success' | 'error';
40
+ text: string;
41
+ }
21
42
 
22
43
  export default function ReportsPage() {
23
- const reports = [
24
- {
25
- name: 'Daily Operations Summary',
26
- description: 'Overview of daily deliveries and performance',
27
- frequency: 'Daily',
28
- lastGenerated: '2024-01-15',
29
- },
30
- {
31
- name: 'Weekly Performance Report',
32
- description: 'KPIs and metrics for the week',
33
- frequency: 'Weekly',
34
- lastGenerated: '2024-01-14',
35
- },
36
- {
37
- name: 'Monthly Financial Report',
38
- description: 'Revenue, expenses, and profit analysis',
39
- frequency: 'Monthly',
40
- lastGenerated: '2024-01-01',
41
- },
42
- {
43
- name: 'Fleet Utilization Report',
44
- description: 'Vehicle and driver utilization metrics',
45
- frequency: 'Weekly',
46
- lastGenerated: '2024-01-14',
47
- },
48
- {
49
- name: 'Customer Analytics Report',
50
- description: 'Customer satisfaction and retention',
51
- frequency: 'Monthly',
52
- lastGenerated: '2024-01-01',
53
- },
54
- {
55
- name: 'Inventory Status Report',
56
- description: 'Stock levels and movement analysis',
57
- frequency: 'Daily',
58
- lastGenerated: '2024-01-15',
59
- },
60
- ];
44
+ const { reports, isLoading, error, refetch, createReport, generateReport } = useReports();
45
+ const [reportType, setReportType] = useState('operations');
46
+ const [busyId, setBusyId] = useState<string | null>(null);
47
+ const [creating, setCreating] = useState(false);
48
+ const [feedback, setFeedback] = useState<Feedback | null>(null);
49
+
50
+ const typeLabel = (value: string) =>
51
+ REPORT_TYPES.find((item) => item.value === value)?.label ?? value;
52
+
53
+ const handleCreate = async (schedule?: string) => {
54
+ setCreating(true);
55
+ setFeedback(null);
56
+ const input: CreateReportInput = {
57
+ name: `${typeLabel(reportType)}${schedule ? ' (Scheduled)' : ''}`,
58
+ type: reportType,
59
+ description: `${typeLabel(reportType)} generated from live operational data`,
60
+ ...(schedule ? { schedule } : {}),
61
+ };
62
+ try {
63
+ await createReport(input);
64
+ setFeedback({
65
+ tone: 'success',
66
+ text: schedule ? 'Scheduled report created.' : 'Report created.',
67
+ });
68
+ } catch (createError) {
69
+ setFeedback({
70
+ tone: 'error',
71
+ text: createError instanceof Error ? createError.message : 'Could not create report.',
72
+ });
73
+ } finally {
74
+ setCreating(false);
75
+ }
76
+ };
77
+
78
+ const handleGenerate = async (id: string) => {
79
+ setBusyId(id);
80
+ setFeedback(null);
81
+ try {
82
+ await generateReport(id);
83
+ setFeedback({ tone: 'success', text: 'Report generated.' });
84
+ } catch (genError) {
85
+ setFeedback({
86
+ tone: 'error',
87
+ text: genError instanceof Error ? genError.message : 'Could not generate report.',
88
+ });
89
+ } finally {
90
+ setBusyId(null);
91
+ }
92
+ };
61
93
 
62
- const scheduledReports = [
63
- { name: 'Daily Summary', nextRun: 'Tomorrow 6:00 AM', recipients: 3 },
64
- { name: 'Weekly Review', nextRun: 'Monday 9:00 AM', recipients: 5 },
65
- ];
94
+ const scheduledReports = reports.filter((report) => report.schedule);
66
95
 
67
96
  return (
68
97
  <PageLayout
@@ -71,19 +100,20 @@ export default function ReportsPage() {
71
100
  icon={<FileBarChart size={24} />}
72
101
  headerActions={
73
102
  <div className="flex gap-2">
74
- <Select defaultValue="30d">
75
- <SelectTrigger className="w-[150px]">
103
+ <Select value={reportType} onValueChange={setReportType}>
104
+ <SelectTrigger className="w-[190px]">
76
105
  <SelectValue />
77
106
  </SelectTrigger>
78
107
  <SelectContent>
79
- <SelectItem value="7d">Last 7 days</SelectItem>
80
- <SelectItem value="30d">Last 30 days</SelectItem>
81
- <SelectItem value="90d">Last 90 days</SelectItem>
82
- <SelectItem value="custom">Custom</SelectItem>
108
+ {REPORT_TYPES.map((item) => (
109
+ <SelectItem key={item.value} value={item.value}>
110
+ {item.label}
111
+ </SelectItem>
112
+ ))}
83
113
  </SelectContent>
84
114
  </Select>
85
- <Button>
86
- <FileBarChart size={16} /> Create Report
115
+ <Button onClick={() => void handleCreate()} disabled={creating}>
116
+ <Plus size={16} /> Create Report
87
117
  </Button>
88
118
  </div>
89
119
  }
@@ -94,37 +124,94 @@ export default function ReportsPage() {
94
124
  so stakeholders always have the latest numbers without logging in.
95
125
  </PagePurpose>
96
126
 
127
+ {feedback && (
128
+ <div
129
+ role="status"
130
+ className={`rounded-lg p-3 text-sm ${
131
+ feedback.tone === 'success'
132
+ ? 'bg-status-success-bg-subtle text-status-success-text'
133
+ : 'bg-status-error-bg-subtle text-status-error-text'
134
+ }`}
135
+ >
136
+ {feedback.text}
137
+ </div>
138
+ )}
139
+
97
140
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
98
141
  <div className="lg:col-span-2 space-y-4">
99
142
  <h3 className="font-semibold">Available Reports</h3>
100
- {reports.map((report) => (
101
- <Card key={report.name}>
102
- <CardContent className="p-4">
103
- <div className="flex items-center justify-between">
104
- <div className="flex items-center gap-3">
105
- <div className="w-10 h-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center">
106
- <FileBarChart size={20} className="text-primary" />
107
- </div>
108
- <div>
109
- <p className="font-medium">{report.name}</p>
110
- <p className="text-sm text-text-secondary">{report.description}</p>
111
- </div>
112
- </div>
113
- <div className="flex items-center gap-3">
114
- <div className="text-right">
115
- <Badge variant="outline">{report.frequency}</Badge>
116
- <p className="text-xs text-text-secondary mt-1">
117
- Last: {report.lastGenerated}
118
- </p>
119
- </div>
120
- <Button variant="outline" size="sm">
121
- <Download size={14} />
143
+
144
+ {isLoading ? (
145
+ <div className="space-y-3">
146
+ {Array.from({ length: 3 }).map((_, i) => (
147
+ <Skeleton key={i} className="h-20 w-full rounded-lg" />
148
+ ))}
149
+ </div>
150
+ ) : error ? (
151
+ <Card className="border-status-error-border">
152
+ <CardContent className="p-6 text-center space-y-3">
153
+ <p className="text-status-error-text font-medium">Couldn&apos;t load reports</p>
154
+ <p className="text-sm text-text-secondary">{error.message}</p>
155
+ <Button variant="outline" onClick={refetch}>
156
+ Retry
157
+ </Button>
158
+ </CardContent>
159
+ </Card>
160
+ ) : reports.length === 0 ? (
161
+ <Card>
162
+ <CardContent className="p-0">
163
+ <IllustratedEmptyState
164
+ illustration="empty-data"
165
+ title="No reports yet"
166
+ description="Create your first report to turn live operational data into a shareable summary."
167
+ action={
168
+ <Button onClick={() => void handleCreate()} disabled={creating}>
169
+ <Plus size={16} className="mr-1.5" /> Create Report
122
170
  </Button>
123
- </div>
124
- </div>
171
+ }
172
+ />
125
173
  </CardContent>
126
174
  </Card>
127
- ))}
175
+ ) : (
176
+ reports.map((report) => (
177
+ <Card key={report.id}>
178
+ <CardContent className="p-4">
179
+ <div className="flex items-center justify-between">
180
+ <div className="flex items-center gap-3">
181
+ <div className="w-10 h-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center">
182
+ <FileBarChart size={20} className="text-primary" />
183
+ </div>
184
+ <div>
185
+ <p className="font-medium">{report.name}</p>
186
+ <p className="text-sm text-text-secondary">
187
+ {report.description ?? typeLabel(report.type)}
188
+ </p>
189
+ </div>
190
+ </div>
191
+ <div className="flex items-center gap-3">
192
+ <div className="text-right">
193
+ <Badge variant="outline">{report.schedule ?? 'On demand'}</Badge>
194
+ {report.lastGenerated && (
195
+ <p className="text-xs text-text-secondary mt-1">
196
+ Last: {formatDate(new Date(report.lastGenerated), 'short')}
197
+ </p>
198
+ )}
199
+ </div>
200
+ <Button
201
+ variant="outline"
202
+ size="sm"
203
+ aria-label={`Generate ${report.name}`}
204
+ disabled={busyId === report.id}
205
+ onClick={() => void handleGenerate(report.id)}
206
+ >
207
+ <Download size={14} />
208
+ </Button>
209
+ </div>
210
+ </div>
211
+ </CardContent>
212
+ </Card>
213
+ ))
214
+ )}
128
215
  </div>
129
216
 
130
217
  <div className="space-y-6">
@@ -133,14 +220,24 @@ export default function ReportsPage() {
133
220
  <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
134
221
  <Clock size={18} /> Scheduled Reports
135
222
  </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">
223
+ {scheduledReports.length === 0 ? (
224
+ <p className="text-sm text-text-secondary">
225
+ No scheduled reports yet. Schedule one to have it generated automatically.
226
+ </p>
227
+ ) : (
228
+ scheduledReports.map((report) => (
229
+ <div key={report.id} className="p-3 border border-border-seam rounded-lg">
230
+ <p className="font-medium">{report.name}</p>
231
+ <p className="text-sm text-text-secondary">Schedule: {report.schedule}</p>
232
+ </div>
233
+ ))
234
+ )}
235
+ <Button
236
+ variant="outline"
237
+ className="w-full"
238
+ disabled={creating}
239
+ onClick={() => void handleCreate('daily')}
240
+ >
144
241
  Schedule New Report
145
242
  </Button>
146
243
  </EmphasisPanel>
@@ -150,15 +247,22 @@ export default function ReportsPage() {
150
247
  <CardTitle>Quick Actions</CardTitle>
151
248
  </CardHeader>
152
249
  <CardContent className="space-y-2">
153
- <Button variant="outline" className="w-full justify-start">
250
+ <Button
251
+ variant="outline"
252
+ className="w-full justify-start"
253
+ disabled={creating}
254
+ onClick={() => void handleCreate('weekly')}
255
+ >
154
256
  <Calendar size={16} /> Schedule Report
155
257
  </Button>
156
- <Button variant="outline" className="w-full justify-start">
258
+ <Button
259
+ variant="outline"
260
+ className="w-full justify-start"
261
+ disabled={creating}
262
+ onClick={() => void handleCreate()}
263
+ >
157
264
  <Filter size={16} /> Custom Report
158
265
  </Button>
159
- <Button variant="outline" className="w-full justify-start">
160
- <Download size={16} /> Export All
161
- </Button>
162
266
  </CardContent>
163
267
  </Card>
164
268
  </div>
@@ -12,6 +12,7 @@ import { useRoute, useRoutes } from '../hooks/useRoutes';
12
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
13
13
  import { formatDate, formatAddress } from '../utils/formatters';
14
14
  import { joinPath } from '../utils/navigation';
15
+ import { ROUTE_STATUS_COLORS } from '../constants';
15
16
 
16
17
  export default function RouteDetailsPage() {
17
18
  const { routeId } = useParams<{ routeId: string }>();
@@ -60,13 +61,6 @@ export default function RouteDetailsPage() {
60
61
  }
61
62
  };
62
63
 
63
- const statusColors = {
64
- planned: { bg: 'bg-blue-100', text: 'text-blue-700' },
65
- in_progress: { bg: 'bg-yellow-100', text: 'text-yellow-700' },
66
- completed: { bg: 'bg-green-100', text: 'text-green-700' },
67
- cancelled: { bg: 'bg-red-100', text: 'text-red-700' },
68
- };
69
-
70
64
  return (
71
65
  <PageLayout
72
66
  title={route.name}
@@ -89,7 +83,7 @@ export default function RouteDetailsPage() {
89
83
  }
90
84
  headerContent={
91
85
  <div className="flex gap-2">
92
- <StatusBadge status={route.status} customColors={statusColors[route.status]} />
86
+ <StatusBadge status={route.status} customColors={ROUTE_STATUS_COLORS[route.status]} />
93
87
  <Badge variant={route.optimized ? 'default' : 'secondary'}>
94
88
  {route.optimized ? 'Optimized' : 'Not Optimized'}
95
89
  </Badge>
@@ -159,7 +153,7 @@ export default function RouteDetailsPage() {
159
153
  <div key={stop.id} className="flex gap-4">
160
154
  <div className="relative">
161
155
  <div
162
- className={`w-8 h-8 rounded-full flex items-center justify-center ${stop.status === 'completed' ? 'bg-green-500 text-white' : 'bg-bg-sunken'}`}
156
+ className={`w-8 h-8 rounded-full flex items-center justify-center ${stop.status === 'completed' ? 'bg-status-success-text text-text-inverse' : 'bg-bg-sunken'}`}
163
157
  >
164
158
  {stop.status === 'completed' ? <CheckCircle size={16} /> : stop.sequence}
165
159
  </div>
@@ -188,7 +182,7 @@ export default function RouteDetailsPage() {
188
182
  Scheduled: {formatDate(stop.scheduledTime, 'time')}
189
183
  </p>
190
184
  {stop.actualTime && (
191
- <p className="text-sm text-green-600">
185
+ <p className="text-sm text-status-success-text">
192
186
  Actual: {formatDate(stop.actualTime, 'time')}
193
187
  </p>
194
188
  )}
@@ -267,7 +261,7 @@ export default function RouteDetailsPage() {
267
261
  {route.trafficConditions.map((tc, i) => (
268
262
  <div
269
263
  key={i}
270
- className={`p-2 rounded mb-2 ${tc.condition === 'severe' ? 'bg-red-50' : tc.condition === 'heavy' ? 'bg-orange-50' : 'bg-yellow-50'}`}
264
+ className={`p-2 rounded mb-2 ${tc.condition === 'severe' ? 'bg-status-error-bg-subtle' : tc.condition === 'heavy' ? 'bg-status-warning-bg-subtle' : 'bg-status-warning-bg-subtle'}`}
271
265
  >
272
266
  <p className="text-sm font-medium capitalize">{tc.condition} traffic</p>
273
267
  <p className="text-xs text-text-secondary">
@@ -12,6 +12,7 @@ import { useRoutes } from '../hooks/useRoutes';
12
12
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
13
13
  import { formatDate } from '../utils/formatters';
14
14
  import { joinPath } from '../utils/navigation';
15
+ import { ROUTE_STATUS_COLORS } from '../constants';
15
16
  import type { Route } from '../types';
16
17
 
17
18
  export default function RoutesPage() {
@@ -33,15 +34,9 @@ export default function RoutesPage() {
33
34
  header: 'Status',
34
35
  accessorKey: 'status',
35
36
  sortable: true,
36
- cell: (row) => {
37
- const colors = {
38
- planned: { bg: 'bg-blue-100', text: 'text-blue-700' },
39
- in_progress: { bg: 'bg-yellow-100', text: 'text-yellow-700' },
40
- completed: { bg: 'bg-green-100', text: 'text-green-700' },
41
- cancelled: { bg: 'bg-red-100', text: 'text-red-700' },
42
- };
43
- return <StatusBadge status={row.status} customColors={colors[row.status]} />;
44
- },
37
+ cell: (row) => (
38
+ <StatusBadge status={row.status} customColors={ROUTE_STATUS_COLORS[row.status]} />
39
+ ),
45
40
  },
46
41
  {
47
42
  id: 'stops',