@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.
- package/dist/{AIAssistantPage-AvsMbunM.js → AIAssistantPage-C3ovZ0Fh.js} +100 -73
- package/dist/AnalyticsPage-O8SpY-V4.js +215 -0
- package/dist/{CreateOrderPage-CjlnEtk3.js → CreateOrderPage-CB1_-_mN.js} +33 -35
- package/dist/{CustomerDetailsPage-I6cdDHUi.js → CustomerDetailsPage-BaeKEI1D.js} +42 -44
- package/dist/{CustomersPage-CGGfD4ki.js → CustomersPage-DRaLuHMC.js} +26 -28
- package/dist/{DashboardPage-D2HRqwg9.js → DashboardPage-DPjhNfKB.js} +85 -83
- package/dist/{DataTable-CD9ZhpLB.js → DataTable-DmciIKKM.js} +3 -3
- package/dist/{DriverDetailsPage-rg_pGNuP.js → DriverDetailsPage-CSSQTOzn.js} +52 -54
- package/dist/{DriversPage-DKiynISH.js → DriversPage-C2Bk0w4Q.js} +24 -26
- package/dist/{FinancePage-Vg8WPs38.js → FinancePage-lmp0Sdsw.js} +9 -9
- package/dist/FleetPage-DZn5pIqd.js +365 -0
- package/dist/ImportExportPage-BIUJZc7O.js +290 -0
- package/dist/InventoryPage-Cxh1zYJd.js +253 -0
- package/dist/{LiveTrackingPage-DQ1q4Id3.js → LiveTrackingPage-BY1yAkIt.js} +60 -56
- package/dist/MarketplacePage-RMuL17EA.js +247 -0
- package/dist/{MetricCard-B7yMyvMX.js → MetricCard-7aYgzZHK.js} +1 -1
- package/dist/{OrderDetailsPage-CFASgsYX.js → OrderDetailsPage-C2Mf4KSy.js} +83 -85
- package/dist/{OrdersListPage-BHeT8S5o.js → OrdersListPage-BrPBtnhp.js} +31 -33
- package/dist/{PageLayout-D3N8MCTm.js → PageLayout-D4LDHJJq.js} +483 -422
- package/dist/{ProductDetailsPage-CFGcbaHo.js → ProductDetailsPage-CezzzZcj.js} +27 -29
- package/dist/{ProductsPage--xEpbQ8A.js → ProductsPage-I5DilIoY.js} +21 -23
- package/dist/ReportsPage-BDXNmUng.js +284 -0
- package/dist/RouteDetailsPage-BcomL20M.js +263 -0
- package/dist/RoutesPage-lqX9ylHP.js +144 -0
- package/dist/SettingsPage-CQVIOaNs.js +421 -0
- package/dist/StatusBadge-NpTeHVlw.js +152 -0
- package/dist/{TrackingPage-CcRc_dva.js → TrackingPage-BXrjz7V8.js} +59 -61
- package/dist/{VehicleDetailsPage-3YDMPsPs.js → VehicleDetailsPage-DZjLcJgr.js} +40 -42
- package/dist/{VehiclesPage-UlxPWP9K.js → VehiclesPage-6W39XT5W.js} +19 -21
- package/dist/{WarehouseDetailsPage-Db7KeN-d.js → WarehouseDetailsPage-C10pgRGW.js} +38 -40
- package/dist/{WarehousesPage-CuTO-OPp.js → WarehousesPage-CHvBqNaQ.js} +15 -17
- package/dist/{arrow-left-CBpZKkpq.js → arrow-left-n48Y-Wis.js} +1 -1
- package/dist/{box-CAaiElsb.js → box-D9Pal4HM.js} +1 -1
- package/dist/{chart-column-D1Ym15-S.js → chart-column-BFIJysDR.js} +1 -1
- package/dist/{chevron-right-BIFGi0UA.js → chevron-right-EMIIyyJ1.js} +1 -1
- package/dist/{circle-alert-DjmNo5_L.js → circle-alert-iY24lSlp.js} +1 -1
- package/dist/{circle-check-big-CjuPVo3_.js → circle-check-big-w0TrLKMF.js} +1 -1
- package/dist/{clock-BjkdnddD.js → clock-DJZtdl8u.js} +1 -1
- package/dist/{dollar-sign-IB4O0wuQ.js → dollar-sign-CgKQRz_e.js} +1 -1
- package/dist/{download-Dpa9vqoG.js → download-DRXxoiQR.js} +1 -1
- package/dist/{file-text-C8Uioy11.js → file-text-DWWY6_f5.js} +1 -1
- package/dist/{filter-Da5OZaHI.js → filter-DloLC2eE.js} +1 -1
- package/dist/index.js +119 -111
- package/dist/{map-_Per4sT9.js → map-CkJaULb2.js} +1 -1
- package/dist/{map-pin-BSaf5IDL.js → map-pin-BGiCvyCs.js} +1 -1
- package/dist/{navigation-DaTbrhw2.js → navigation-D36prnAn.js} +1 -1
- package/dist/{package-BE7U0wQE.js → package-BChUzpJS.js} +1 -1
- package/dist/{phone-DV4StZiA.js → phone-Ac9s3mo_.js} +1 -1
- package/dist/{plus-Dl1rLeJR.js → plus-Z76q-FZm.js} +1 -1
- package/dist/{refresh-cw-CWfERAit.js → refresh-cw-DKt6f5T6.js} +1 -1
- package/dist/{save-XH8vydOn.js → save-CojywNhG.js} +1 -1
- package/dist/{search-OxoIiL_C.js → search-CDGefqb3.js} +1 -1
- package/dist/{square-pen-hLIbFQFV.js → square-pen-CopE9GmB.js} +1 -1
- package/dist/{star-YsVV3MNQ.js → star-nHlLjDKR.js} +1 -1
- package/dist/{store-RCBl7HB-.js → store-BR9Voi5E.js} +1 -1
- package/dist/{trending-up-C-85AwGT.js → trending-up-B7W-GL6P.js} +1 -1
- package/dist/{triangle-alert-BOhfGgmh.js → triangle-alert-BonHFFNz.js} +1 -1
- package/dist/{truck-CtDjNFbi.js → truck-DrlfSpRC.js} +1 -1
- package/dist/{useAnalytics-ph7eTIK6.js → useAnalytics-CgdzUfY_.js} +40 -40
- package/dist/useAssistant-D4v3oxD3.js +84 -0
- package/dist/{useCustomers-bS3a4ytk.js → useCustomers-QrlozybF.js} +24 -24
- package/dist/{useFleet-BdETplNE.js → useFleet-DiAC-IiH.js} +70 -67
- package/dist/useImportExport-BLMnAKCC.js +55 -0
- package/dist/{useInventory-Dwn18FPz.js → useInventory-DKoks37x.js} +33 -33
- package/dist/{useOrders-D_3_hGMp.js → useOrders-D3UZVy8Y.js} +42 -42
- package/dist/useReports-Puq4DCH9.js +78 -0
- package/dist/{useRoutes-v4aBaS-E.js → useRoutes-Do57LvRb.js} +31 -31
- package/dist/useSettings-CkDH_-gM.js +81 -0
- package/dist/{useTracking-De2KIUNu.js → useTracking-GJify4HN.js} +22 -22
- package/dist/{user-Dz5TJZFs.js → user-CjSoudeu.js} +1 -1
- package/dist/{users-g2N0eL-Z.js → users-BAM4gHTn.js} +1 -1
- package/dist/{warehouse-D3WWDeTX.js → warehouse-C7MSr47B.js} +1 -1
- package/dist/{wrench-CmxY1n4I.js → wrench-CANXWxF-.js} +1 -1
- package/package.json +1 -1
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +27 -3
- package/src/movethewheels/components/StatusBadge.tsx +18 -37
- package/src/movethewheels/constants/index.ts +67 -26
- package/src/movethewheels/hooks/index.ts +12 -0
- package/src/movethewheels/hooks/useAnalytics.ts +20 -6
- package/src/movethewheels/hooks/useAssistant.ts +74 -0
- package/src/movethewheels/hooks/useFleet.ts +63 -59
- package/src/movethewheels/hooks/useImportExport.ts +101 -0
- package/src/movethewheels/hooks/useReports.ts +158 -0
- package/src/movethewheels/hooks/useSettings.ts +120 -0
- package/src/movethewheels/pages/AIAssistantPage.tsx +53 -15
- package/src/movethewheels/pages/AnalyticsPage.tsx +67 -64
- package/src/movethewheels/pages/CustomerDetailsPage.tsx +1 -1
- package/src/movethewheels/pages/CustomersPage.tsx +1 -1
- package/src/movethewheels/pages/DashboardPage.tsx +42 -22
- package/src/movethewheels/pages/DriverDetailsPage.tsx +1 -1
- package/src/movethewheels/pages/DriversPage.tsx +1 -1
- package/src/movethewheels/pages/FleetPage.tsx +96 -38
- package/src/movethewheels/pages/ImportExportPage.tsx +174 -68
- package/src/movethewheels/pages/InventoryPage.tsx +66 -28
- package/src/movethewheels/pages/LiveTrackingPage.tsx +12 -3
- package/src/movethewheels/pages/MarketplacePage.tsx +87 -45
- package/src/movethewheels/pages/OrderDetailsPage.tsx +2 -2
- package/src/movethewheels/pages/ReportsPage.tsx +194 -90
- package/src/movethewheels/pages/RouteDetailsPage.tsx +5 -11
- package/src/movethewheels/pages/RoutesPage.tsx +4 -9
- package/src/movethewheels/pages/SettingsPage.tsx +234 -56
- package/src/movethewheels/pages/TrackingPage.tsx +6 -6
- package/src/movethewheels/providers/MoveTheWheelsProvider.tsx +7 -6
- package/src/movethewheels/store/movethewheelsStore.ts +1 -1
- package/dist/AnalyticsPage-CCLfHgQZ.js +0 -212
- package/dist/FleetPage-DddXt8r8.js +0 -332
- package/dist/ImportExportPage-BW6qO3kc.js +0 -248
- package/dist/InventoryPage-rMGuaJN-.js +0 -222
- package/dist/MarketplacePage-DKrXAv62.js +0 -219
- package/dist/ReportsPage-Bb7_90rK.js +0 -235
- package/dist/RouteDetailsPage-CVtDVb1N.js +0 -282
- package/dist/RoutesPage-s57PtgcQ.js +0 -163
- package/dist/SettingsPage-BYNCBOpN.js +0 -298
- package/dist/StatusBadge-CijYQXtb.js +0 -209
- package/dist/graphqlClient-CdJyR_ed.js +0 -55
- package/dist/navigation-BgnOfsVd.js +0 -6
- package/dist/route-Dp9JiN_E.js +0 -51
- package/dist/settings-3Rw5NwFF.js +0 -28
- package/src/movethewheels/constants/mockData.ts +0 -1342
- /package/dist/{formatters-_vJlC-47.js → formatters-DhKZ-eA1.js} +0 -0
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { cn } from '../utils/cn';
|
|
2
2
|
import { Badge } from './ui';
|
|
3
3
|
import type { OrderStatus, VehicleStatus, DriverStatus } from '../types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ORDER_STATUS_COLORS,
|
|
6
|
+
VEHICLE_STATUS_COLORS,
|
|
7
|
+
DRIVER_STATUS_COLORS,
|
|
8
|
+
PRIORITY_COLORS,
|
|
9
|
+
} from '../constants';
|
|
5
10
|
|
|
6
11
|
type StatusType = 'order' | 'vehicle' | 'driver' | 'custom';
|
|
7
12
|
|
|
@@ -37,28 +42,20 @@ export function StatusBadge({
|
|
|
37
42
|
// Get colors based on type
|
|
38
43
|
let colors = customColors;
|
|
39
44
|
|
|
45
|
+
const neutral = { bg: 'bg-bg-sunken', text: 'text-text-secondary' };
|
|
40
46
|
if (!colors) {
|
|
41
47
|
switch (type) {
|
|
42
48
|
case 'order':
|
|
43
|
-
colors = ORDER_STATUS_COLORS[status as OrderStatus] ||
|
|
44
|
-
bg: 'bg-gray-100',
|
|
45
|
-
text: 'text-gray-700',
|
|
46
|
-
};
|
|
49
|
+
colors = ORDER_STATUS_COLORS[status as OrderStatus] || neutral;
|
|
47
50
|
break;
|
|
48
51
|
case 'vehicle':
|
|
49
|
-
colors = VEHICLE_STATUS_COLORS[status as VehicleStatus] ||
|
|
50
|
-
bg: 'bg-gray-100',
|
|
51
|
-
text: 'text-gray-700',
|
|
52
|
-
};
|
|
52
|
+
colors = VEHICLE_STATUS_COLORS[status as VehicleStatus] || neutral;
|
|
53
53
|
break;
|
|
54
54
|
case 'driver':
|
|
55
|
-
colors = DRIVER_STATUS_COLORS[status as DriverStatus] ||
|
|
56
|
-
bg: 'bg-gray-100',
|
|
57
|
-
text: 'text-gray-700',
|
|
58
|
-
};
|
|
55
|
+
colors = DRIVER_STATUS_COLORS[status as DriverStatus] || neutral;
|
|
59
56
|
break;
|
|
60
57
|
default:
|
|
61
|
-
colors =
|
|
58
|
+
colors = neutral;
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
61
|
|
|
@@ -102,17 +99,7 @@ export function PriorityBadge({
|
|
|
102
99
|
size?: 'sm' | 'md' | 'lg';
|
|
103
100
|
className?: string;
|
|
104
101
|
}) {
|
|
105
|
-
const
|
|
106
|
-
low: { bg: 'bg-gray-100 dark:bg-gray-800', text: 'text-gray-600 dark:text-gray-400' },
|
|
107
|
-
normal: { bg: 'bg-blue-100 dark:bg-blue-900/30', text: 'text-blue-700 dark:text-blue-400' },
|
|
108
|
-
high: {
|
|
109
|
-
bg: 'bg-orange-100 dark:bg-orange-900/30',
|
|
110
|
-
text: 'text-orange-700 dark:text-orange-400',
|
|
111
|
-
},
|
|
112
|
-
urgent: { bg: 'bg-red-100 dark:bg-red-900/30', text: 'text-red-700 dark:text-red-400' },
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const colors = priorityColors[priority];
|
|
102
|
+
const colors = PRIORITY_COLORS[priority];
|
|
116
103
|
|
|
117
104
|
return (
|
|
118
105
|
<Badge
|
|
@@ -143,11 +130,8 @@ export function TypeBadge({
|
|
|
143
130
|
className?: string;
|
|
144
131
|
}) {
|
|
145
132
|
const typeColors = {
|
|
146
|
-
b2b: {
|
|
147
|
-
|
|
148
|
-
text: 'text-purple-700 dark:text-purple-400',
|
|
149
|
-
},
|
|
150
|
-
b2c: { bg: 'bg-teal-100 dark:bg-teal-900/30', text: 'text-teal-700 dark:text-teal-400' },
|
|
133
|
+
b2b: { bg: 'bg-status-info-bg-subtle', text: 'text-status-info-text' },
|
|
134
|
+
b2c: { bg: 'bg-status-success-bg-subtle', text: 'text-status-success-text' },
|
|
151
135
|
};
|
|
152
136
|
|
|
153
137
|
const colors = typeColors[type];
|
|
@@ -181,13 +165,10 @@ export function PaymentStatusBadge({
|
|
|
181
165
|
className?: string;
|
|
182
166
|
}) {
|
|
183
167
|
const statusColors = {
|
|
184
|
-
pending: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
},
|
|
188
|
-
paid: { bg: 'bg-green-100 dark:bg-green-900/30', text: 'text-green-700 dark:text-green-400' },
|
|
189
|
-
failed: { bg: 'bg-red-100 dark:bg-red-900/30', text: 'text-red-700 dark:text-red-400' },
|
|
190
|
-
refunded: { bg: 'bg-gray-100 dark:bg-gray-800', text: 'text-gray-700 dark:text-gray-400' },
|
|
168
|
+
pending: { bg: 'bg-status-warning-bg-subtle', text: 'text-status-warning-text' },
|
|
169
|
+
paid: { bg: 'bg-status-success-bg-subtle', text: 'text-status-success-text' },
|
|
170
|
+
failed: { bg: 'bg-status-error-bg-subtle', text: 'text-status-error-text' },
|
|
171
|
+
refunded: { bg: 'bg-bg-sunken', text: 'text-text-secondary' },
|
|
191
172
|
};
|
|
192
173
|
|
|
193
174
|
const colors = statusColors[status];
|
|
@@ -1,44 +1,85 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Constants barrel export
|
|
3
|
+
*
|
|
4
|
+
* Status color maps use fe-libs semantic status tokens (never raw palette
|
|
5
|
+
* classes) so they adapt automatically across light/dark and product themes.
|
|
6
|
+
* Definitions live in fe-libs/src/shared/styles/app-shell.css.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
|
-
export
|
|
9
|
+
export interface StatusColor {
|
|
10
|
+
bg: string;
|
|
11
|
+
text: string;
|
|
12
|
+
border?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const SUCCESS: StatusColor = {
|
|
16
|
+
bg: 'bg-status-success-bg-subtle',
|
|
17
|
+
text: 'text-status-success-text',
|
|
18
|
+
border: 'border-status-success-border',
|
|
19
|
+
};
|
|
20
|
+
const WARNING: StatusColor = {
|
|
21
|
+
bg: 'bg-status-warning-bg-subtle',
|
|
22
|
+
text: 'text-status-warning-text',
|
|
23
|
+
border: 'border-status-warning-border',
|
|
24
|
+
};
|
|
25
|
+
const ERROR: StatusColor = {
|
|
26
|
+
bg: 'bg-status-error-bg-subtle',
|
|
27
|
+
text: 'text-status-error-text',
|
|
28
|
+
border: 'border-status-error-border',
|
|
29
|
+
};
|
|
30
|
+
const INFO: StatusColor = {
|
|
31
|
+
bg: 'bg-status-info-bg-subtle',
|
|
32
|
+
text: 'text-status-info-text',
|
|
33
|
+
border: 'border-status-info-border',
|
|
34
|
+
};
|
|
35
|
+
const NEUTRAL: StatusColor = {
|
|
36
|
+
bg: 'bg-bg-sunken',
|
|
37
|
+
text: 'text-text-secondary',
|
|
38
|
+
};
|
|
6
39
|
|
|
7
40
|
// Order status colors
|
|
8
|
-
export const ORDER_STATUS_COLORS: Record<string,
|
|
9
|
-
pending:
|
|
10
|
-
confirmed:
|
|
11
|
-
assigned:
|
|
12
|
-
picked_up:
|
|
13
|
-
in_transit:
|
|
14
|
-
out_for_delivery:
|
|
15
|
-
delivered:
|
|
16
|
-
cancelled:
|
|
17
|
-
failed:
|
|
41
|
+
export const ORDER_STATUS_COLORS: Record<string, StatusColor> = {
|
|
42
|
+
pending: WARNING,
|
|
43
|
+
confirmed: INFO,
|
|
44
|
+
assigned: INFO,
|
|
45
|
+
picked_up: INFO,
|
|
46
|
+
in_transit: INFO,
|
|
47
|
+
out_for_delivery: WARNING,
|
|
48
|
+
delivered: SUCCESS,
|
|
49
|
+
cancelled: ERROR,
|
|
50
|
+
failed: ERROR,
|
|
18
51
|
};
|
|
19
52
|
|
|
20
53
|
// Vehicle status colors
|
|
21
|
-
export const VEHICLE_STATUS_COLORS: Record<string,
|
|
22
|
-
available:
|
|
23
|
-
assigned:
|
|
24
|
-
maintenance:
|
|
25
|
-
out_of_service:
|
|
54
|
+
export const VEHICLE_STATUS_COLORS: Record<string, StatusColor> = {
|
|
55
|
+
available: SUCCESS,
|
|
56
|
+
assigned: INFO,
|
|
57
|
+
maintenance: WARNING,
|
|
58
|
+
out_of_service: ERROR,
|
|
26
59
|
};
|
|
27
60
|
|
|
28
61
|
// Driver status colors
|
|
29
|
-
export const DRIVER_STATUS_COLORS: Record<string,
|
|
30
|
-
available:
|
|
31
|
-
busy:
|
|
32
|
-
offline:
|
|
33
|
-
on_break:
|
|
62
|
+
export const DRIVER_STATUS_COLORS: Record<string, StatusColor> = {
|
|
63
|
+
available: SUCCESS,
|
|
64
|
+
busy: INFO,
|
|
65
|
+
offline: NEUTRAL,
|
|
66
|
+
on_break: WARNING,
|
|
34
67
|
};
|
|
35
68
|
|
|
36
69
|
// Priority colors
|
|
37
|
-
export const PRIORITY_COLORS: Record<string,
|
|
38
|
-
low:
|
|
39
|
-
normal:
|
|
40
|
-
high:
|
|
41
|
-
urgent:
|
|
70
|
+
export const PRIORITY_COLORS: Record<string, StatusColor> = {
|
|
71
|
+
low: NEUTRAL,
|
|
72
|
+
normal: INFO,
|
|
73
|
+
high: WARNING,
|
|
74
|
+
urgent: ERROR,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Route status colors (shared by RoutesPage + RouteDetailsPage)
|
|
78
|
+
export const ROUTE_STATUS_COLORS: Record<string, StatusColor> = {
|
|
79
|
+
planned: INFO,
|
|
80
|
+
in_progress: WARNING,
|
|
81
|
+
completed: SUCCESS,
|
|
82
|
+
cancelled: ERROR,
|
|
42
83
|
};
|
|
43
84
|
|
|
44
85
|
// Customer type labels
|
|
@@ -53,3 +53,15 @@ export {
|
|
|
53
53
|
useTrackingAlerts,
|
|
54
54
|
useGeofence,
|
|
55
55
|
} from './useTracking';
|
|
56
|
+
|
|
57
|
+
// Assistant
|
|
58
|
+
export { useAssistant } from './useAssistant';
|
|
59
|
+
|
|
60
|
+
// Reports
|
|
61
|
+
export { useReports } from './useReports';
|
|
62
|
+
|
|
63
|
+
// Import / Export
|
|
64
|
+
export { useImportExport } from './useImportExport';
|
|
65
|
+
|
|
66
|
+
// Module settings
|
|
67
|
+
export { useModuleSettings } from './useSettings';
|
|
@@ -40,11 +40,14 @@ const ANALYTICS_QUERY = `
|
|
|
40
40
|
activeVehicles
|
|
41
41
|
lowStockItems
|
|
42
42
|
totalRevenue
|
|
43
|
+
onTimeDeliveryRate
|
|
44
|
+
customerSatisfaction
|
|
43
45
|
}
|
|
44
46
|
fleetStats {
|
|
45
47
|
totalVehicles
|
|
46
48
|
activeVehicles
|
|
47
49
|
maintenanceVehicles
|
|
50
|
+
avgDriverRating
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
`;
|
|
@@ -58,6 +61,8 @@ const DASHBOARD_QUERY = `
|
|
|
58
61
|
activeVehicles
|
|
59
62
|
lowStockItems
|
|
60
63
|
totalRevenue
|
|
64
|
+
onTimeDeliveryRate
|
|
65
|
+
customerSatisfaction
|
|
61
66
|
}
|
|
62
67
|
orderStats {
|
|
63
68
|
total
|
|
@@ -74,6 +79,7 @@ const DASHBOARD_QUERY = `
|
|
|
74
79
|
totalDrivers
|
|
75
80
|
availableDrivers
|
|
76
81
|
onDeliveryDrivers
|
|
82
|
+
avgDriverRating
|
|
77
83
|
}
|
|
78
84
|
financeMetrics {
|
|
79
85
|
revenue {
|
|
@@ -165,11 +171,14 @@ export function useAnalytics(_options: UseAnalyticsOptions = {}): UseAnalyticsRe
|
|
|
165
171
|
totalOrders: number;
|
|
166
172
|
totalRevenue: number;
|
|
167
173
|
activeVehicles: number;
|
|
174
|
+
onTimeDeliveryRate: number;
|
|
175
|
+
customerSatisfaction: number;
|
|
168
176
|
};
|
|
169
177
|
fleetStats: {
|
|
170
178
|
totalVehicles: number;
|
|
171
179
|
activeVehicles: number;
|
|
172
180
|
maintenanceVehicles: number;
|
|
181
|
+
avgDriverRating: number;
|
|
173
182
|
};
|
|
174
183
|
}>(graphQLOptions, ANALYTICS_QUERY);
|
|
175
184
|
|
|
@@ -178,8 +187,8 @@ export function useAnalytics(_options: UseAnalyticsOptions = {}): UseAnalyticsRe
|
|
|
178
187
|
totalOrders: data.dashboardMetrics.totalOrders,
|
|
179
188
|
totalRevenue: data.dashboardMetrics.totalRevenue,
|
|
180
189
|
activeVehicles: data.dashboardMetrics.activeVehicles,
|
|
181
|
-
onTimeDeliveryRate:
|
|
182
|
-
customerSatisfaction:
|
|
190
|
+
onTimeDeliveryRate: data.dashboardMetrics.onTimeDeliveryRate,
|
|
191
|
+
customerSatisfaction: data.dashboardMetrics.customerSatisfaction,
|
|
183
192
|
},
|
|
184
193
|
trends: {
|
|
185
194
|
dailyOrders: data.analytics.orderTrend.map((item) => ({
|
|
@@ -209,10 +218,10 @@ export function useAnalytics(_options: UseAnalyticsOptions = {}): UseAnalyticsRe
|
|
|
209
218
|
},
|
|
210
219
|
performance: {
|
|
211
220
|
onTimePickup: 0,
|
|
212
|
-
onTimeDelivery:
|
|
221
|
+
onTimeDelivery: data.dashboardMetrics.onTimeDeliveryRate,
|
|
213
222
|
damagedItems: 0,
|
|
214
223
|
customerComplaints: 0,
|
|
215
|
-
driverRatings:
|
|
224
|
+
driverRatings: data.fleetStats.avgDriverRating,
|
|
216
225
|
},
|
|
217
226
|
});
|
|
218
227
|
} catch (fetchError) {
|
|
@@ -281,6 +290,10 @@ export function useDashboardMetrics() {
|
|
|
281
290
|
setError(null);
|
|
282
291
|
try {
|
|
283
292
|
const data = await executeGraphQL<{
|
|
293
|
+
dashboardMetrics: {
|
|
294
|
+
onTimeDeliveryRate: number;
|
|
295
|
+
customerSatisfaction: number;
|
|
296
|
+
};
|
|
284
297
|
orderStats: {
|
|
285
298
|
total: number;
|
|
286
299
|
pending: number;
|
|
@@ -292,6 +305,7 @@ export function useDashboardMetrics() {
|
|
|
292
305
|
activeVehicles: number;
|
|
293
306
|
totalDrivers: number;
|
|
294
307
|
availableDrivers: number;
|
|
308
|
+
avgDriverRating: number;
|
|
295
309
|
};
|
|
296
310
|
financeMetrics: {
|
|
297
311
|
revenue: {
|
|
@@ -321,8 +335,8 @@ export function useDashboardMetrics() {
|
|
|
321
335
|
currency: 'USD',
|
|
322
336
|
},
|
|
323
337
|
performance: {
|
|
324
|
-
onTimeDeliveryRate:
|
|
325
|
-
avgDriverRating:
|
|
338
|
+
onTimeDeliveryRate: data.dashboardMetrics.onTimeDeliveryRate,
|
|
339
|
+
avgDriverRating: data.fleetStats.avgDriverRating,
|
|
326
340
|
},
|
|
327
341
|
});
|
|
328
342
|
} catch (fetchError) {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
3
|
+
import { executeGraphQL } from '../utils/graphqlClient';
|
|
4
|
+
|
|
5
|
+
export interface AssistantAnswer {
|
|
6
|
+
answer: string;
|
|
7
|
+
generatedAt: string;
|
|
8
|
+
question: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ASSISTANT_INSIGHTS_QUERY = `
|
|
12
|
+
query MovethewheelsAssistantInsights($question: String!) {
|
|
13
|
+
assistantInsights(question: $question) {
|
|
14
|
+
answer
|
|
15
|
+
generatedAt
|
|
16
|
+
question
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
interface UseAssistantResult {
|
|
22
|
+
ask: (question: string) => Promise<AssistantAnswer>;
|
|
23
|
+
isLoading: boolean;
|
|
24
|
+
error: Error | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* useAssistant — queries the real logistics assistant (Query.assistantInsights).
|
|
29
|
+
* The backend answers from the caller's own operational data; there is no
|
|
30
|
+
* client-side canned response.
|
|
31
|
+
*/
|
|
32
|
+
export function useAssistant(): UseAssistantResult {
|
|
33
|
+
const { apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser } =
|
|
34
|
+
useMoveTheWheels();
|
|
35
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
36
|
+
const [error, setError] = useState<Error | null>(null);
|
|
37
|
+
|
|
38
|
+
const graphQLOptions = useMemo(
|
|
39
|
+
() => ({
|
|
40
|
+
apiGatewayUrl,
|
|
41
|
+
authToken,
|
|
42
|
+
workspaceToken,
|
|
43
|
+
workspaceId,
|
|
44
|
+
tenantId,
|
|
45
|
+
actorId: currentUser?.id,
|
|
46
|
+
}),
|
|
47
|
+
[apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser?.id]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const ask = useCallback(
|
|
51
|
+
async (question: string): Promise<AssistantAnswer> => {
|
|
52
|
+
setIsLoading(true);
|
|
53
|
+
setError(null);
|
|
54
|
+
try {
|
|
55
|
+
const data = await executeGraphQL<{ assistantInsights: AssistantAnswer }>(
|
|
56
|
+
graphQLOptions,
|
|
57
|
+
ASSISTANT_INSIGHTS_QUERY,
|
|
58
|
+
{ question }
|
|
59
|
+
);
|
|
60
|
+
return data.assistantInsights;
|
|
61
|
+
} catch (fetchError) {
|
|
62
|
+
const normalized =
|
|
63
|
+
fetchError instanceof Error ? fetchError : new Error('Failed to get assistant response');
|
|
64
|
+
setError(normalized);
|
|
65
|
+
throw normalized;
|
|
66
|
+
} finally {
|
|
67
|
+
setIsLoading(false);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
[graphQLOptions]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return { ask, isLoading, error };
|
|
74
|
+
}
|
|
@@ -199,6 +199,7 @@ const FLEET_STATS_QUERY = `
|
|
|
199
199
|
totalDrivers
|
|
200
200
|
availableDrivers
|
|
201
201
|
onDeliveryDrivers
|
|
202
|
+
avgDriverRating
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
`;
|
|
@@ -712,67 +713,70 @@ export function useFleetStats() {
|
|
|
712
713
|
const [isLoading, setIsLoading] = useState(false);
|
|
713
714
|
const [error, setError] = useState<Error | null>(null);
|
|
714
715
|
|
|
716
|
+
const load = useCallback(async () => {
|
|
717
|
+
setIsLoading(true);
|
|
718
|
+
setError(null);
|
|
719
|
+
try {
|
|
720
|
+
const data = await executeGraphQL<{
|
|
721
|
+
fleetStats: {
|
|
722
|
+
totalVehicles: number;
|
|
723
|
+
activeVehicles: number;
|
|
724
|
+
inTransitVehicles: number;
|
|
725
|
+
maintenanceVehicles: number;
|
|
726
|
+
totalDrivers: number;
|
|
727
|
+
availableDrivers: number;
|
|
728
|
+
onDeliveryDrivers: number;
|
|
729
|
+
avgDriverRating: number;
|
|
730
|
+
};
|
|
731
|
+
}>(graphQLOptions, FLEET_STATS_QUERY);
|
|
732
|
+
|
|
733
|
+
setStats({
|
|
734
|
+
totalVehicles: data.fleetStats.totalVehicles,
|
|
735
|
+
totalDrivers: data.fleetStats.totalDrivers,
|
|
736
|
+
vehiclesByStatus: {
|
|
737
|
+
available: data.fleetStats.activeVehicles,
|
|
738
|
+
assigned: data.fleetStats.inTransitVehicles,
|
|
739
|
+
maintenance: data.fleetStats.maintenanceVehicles,
|
|
740
|
+
out_of_service: Math.max(
|
|
741
|
+
data.fleetStats.totalVehicles -
|
|
742
|
+
data.fleetStats.activeVehicles -
|
|
743
|
+
data.fleetStats.inTransitVehicles -
|
|
744
|
+
data.fleetStats.maintenanceVehicles,
|
|
745
|
+
0
|
|
746
|
+
),
|
|
747
|
+
},
|
|
748
|
+
driversByStatus: {
|
|
749
|
+
available: data.fleetStats.availableDrivers,
|
|
750
|
+
busy: data.fleetStats.onDeliveryDrivers,
|
|
751
|
+
offline: Math.max(
|
|
752
|
+
data.fleetStats.totalDrivers -
|
|
753
|
+
data.fleetStats.availableDrivers -
|
|
754
|
+
data.fleetStats.onDeliveryDrivers,
|
|
755
|
+
0
|
|
756
|
+
),
|
|
757
|
+
on_break: 0,
|
|
758
|
+
},
|
|
759
|
+
avgFuelLevel: 0,
|
|
760
|
+
avgDriverRating: data.fleetStats.avgDriverRating,
|
|
761
|
+
utilization:
|
|
762
|
+
data.fleetStats.totalVehicles > 0
|
|
763
|
+
? (data.fleetStats.activeVehicles / data.fleetStats.totalVehicles) * 100
|
|
764
|
+
: 0,
|
|
765
|
+
});
|
|
766
|
+
} catch (fetchError) {
|
|
767
|
+
setError(fetchError instanceof Error ? fetchError : new Error('Failed to load fleet stats'));
|
|
768
|
+
} finally {
|
|
769
|
+
setIsLoading(false);
|
|
770
|
+
}
|
|
771
|
+
}, [graphQLOptions]);
|
|
772
|
+
|
|
715
773
|
useEffect(() => {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
setError(null);
|
|
719
|
-
try {
|
|
720
|
-
const data = await executeGraphQL<{
|
|
721
|
-
fleetStats: {
|
|
722
|
-
totalVehicles: number;
|
|
723
|
-
activeVehicles: number;
|
|
724
|
-
inTransitVehicles: number;
|
|
725
|
-
maintenanceVehicles: number;
|
|
726
|
-
totalDrivers: number;
|
|
727
|
-
availableDrivers: number;
|
|
728
|
-
onDeliveryDrivers: number;
|
|
729
|
-
};
|
|
730
|
-
}>(graphQLOptions, FLEET_STATS_QUERY);
|
|
731
|
-
|
|
732
|
-
setStats({
|
|
733
|
-
totalVehicles: data.fleetStats.totalVehicles,
|
|
734
|
-
totalDrivers: data.fleetStats.totalDrivers,
|
|
735
|
-
vehiclesByStatus: {
|
|
736
|
-
available: data.fleetStats.activeVehicles,
|
|
737
|
-
assigned: data.fleetStats.inTransitVehicles,
|
|
738
|
-
maintenance: data.fleetStats.maintenanceVehicles,
|
|
739
|
-
out_of_service: Math.max(
|
|
740
|
-
data.fleetStats.totalVehicles -
|
|
741
|
-
data.fleetStats.activeVehicles -
|
|
742
|
-
data.fleetStats.inTransitVehicles -
|
|
743
|
-
data.fleetStats.maintenanceVehicles,
|
|
744
|
-
0
|
|
745
|
-
),
|
|
746
|
-
},
|
|
747
|
-
driversByStatus: {
|
|
748
|
-
available: data.fleetStats.availableDrivers,
|
|
749
|
-
busy: data.fleetStats.onDeliveryDrivers,
|
|
750
|
-
offline: Math.max(
|
|
751
|
-
data.fleetStats.totalDrivers -
|
|
752
|
-
data.fleetStats.availableDrivers -
|
|
753
|
-
data.fleetStats.onDeliveryDrivers,
|
|
754
|
-
0
|
|
755
|
-
),
|
|
756
|
-
on_break: 0,
|
|
757
|
-
},
|
|
758
|
-
avgFuelLevel: 0,
|
|
759
|
-
avgDriverRating: 0,
|
|
760
|
-
utilization:
|
|
761
|
-
data.fleetStats.totalVehicles > 0
|
|
762
|
-
? (data.fleetStats.activeVehicles / data.fleetStats.totalVehicles) * 100
|
|
763
|
-
: 0,
|
|
764
|
-
});
|
|
765
|
-
} catch (fetchError) {
|
|
766
|
-
setError(
|
|
767
|
-
fetchError instanceof Error ? fetchError : new Error('Failed to load fleet stats')
|
|
768
|
-
);
|
|
769
|
-
} finally {
|
|
770
|
-
setIsLoading(false);
|
|
771
|
-
}
|
|
772
|
-
};
|
|
774
|
+
void load();
|
|
775
|
+
}, [load]);
|
|
773
776
|
|
|
777
|
+
const refetch = useCallback(() => {
|
|
774
778
|
void load();
|
|
775
|
-
}, [
|
|
779
|
+
}, [load]);
|
|
776
780
|
|
|
777
|
-
return { stats, isLoading, error };
|
|
781
|
+
return { stats, isLoading, error, refetch };
|
|
778
782
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
3
|
+
import { executeGraphQL } from '../utils/graphqlClient';
|
|
4
|
+
|
|
5
|
+
export interface ImportExportResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
message: string;
|
|
8
|
+
payload?: Record<string, unknown> | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const EXPORT_DATA_MUTATION = `
|
|
12
|
+
mutation MovethewheelsExportData($input: MovethewheelsExportDataInput!) {
|
|
13
|
+
exportData(input: $input) {
|
|
14
|
+
success
|
|
15
|
+
message
|
|
16
|
+
payload
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const IMPORT_DATA_MUTATION = `
|
|
22
|
+
mutation MovethewheelsImportData($input: MovethewheelsImportDataInput!) {
|
|
23
|
+
importData(input: $input) {
|
|
24
|
+
success
|
|
25
|
+
message
|
|
26
|
+
payload
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
interface UseImportExportResult {
|
|
32
|
+
exportData: (resource: string, format?: string) => Promise<ImportExportResult>;
|
|
33
|
+
importData: (resource: string, payload: Record<string, unknown>) => Promise<ImportExportResult>;
|
|
34
|
+
isBusy: boolean;
|
|
35
|
+
error: Error | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useImportExport(): UseImportExportResult {
|
|
39
|
+
const { apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser } =
|
|
40
|
+
useMoveTheWheels();
|
|
41
|
+
const [isBusy, setIsBusy] = useState(false);
|
|
42
|
+
const [error, setError] = useState<Error | null>(null);
|
|
43
|
+
|
|
44
|
+
const graphQLOptions = useMemo(
|
|
45
|
+
() => ({
|
|
46
|
+
apiGatewayUrl,
|
|
47
|
+
authToken,
|
|
48
|
+
workspaceToken,
|
|
49
|
+
workspaceId,
|
|
50
|
+
tenantId,
|
|
51
|
+
actorId: currentUser?.id,
|
|
52
|
+
}),
|
|
53
|
+
[apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser?.id]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const exportData = useCallback(
|
|
57
|
+
async (resource: string, format?: string): Promise<ImportExportResult> => {
|
|
58
|
+
setIsBusy(true);
|
|
59
|
+
setError(null);
|
|
60
|
+
try {
|
|
61
|
+
const data = await executeGraphQL<{ exportData: ImportExportResult }>(
|
|
62
|
+
graphQLOptions,
|
|
63
|
+
EXPORT_DATA_MUTATION,
|
|
64
|
+
{ input: { resource, format } }
|
|
65
|
+
);
|
|
66
|
+
return data.exportData;
|
|
67
|
+
} catch (fetchError) {
|
|
68
|
+
const normalized = fetchError instanceof Error ? fetchError : new Error('Export failed');
|
|
69
|
+
setError(normalized);
|
|
70
|
+
throw normalized;
|
|
71
|
+
} finally {
|
|
72
|
+
setIsBusy(false);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
[graphQLOptions]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const importData = useCallback(
|
|
79
|
+
async (resource: string, payload: Record<string, unknown>): Promise<ImportExportResult> => {
|
|
80
|
+
setIsBusy(true);
|
|
81
|
+
setError(null);
|
|
82
|
+
try {
|
|
83
|
+
const data = await executeGraphQL<{ importData: ImportExportResult }>(
|
|
84
|
+
graphQLOptions,
|
|
85
|
+
IMPORT_DATA_MUTATION,
|
|
86
|
+
{ input: { resource, payload } }
|
|
87
|
+
);
|
|
88
|
+
return data.importData;
|
|
89
|
+
} catch (fetchError) {
|
|
90
|
+
const normalized = fetchError instanceof Error ? fetchError : new Error('Import failed');
|
|
91
|
+
setError(normalized);
|
|
92
|
+
throw normalized;
|
|
93
|
+
} finally {
|
|
94
|
+
setIsBusy(false);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[graphQLOptions]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return { exportData, importData, isBusy, error };
|
|
101
|
+
}
|