@burdenoff/microfe-movethewheels 2026.1031.4 → 2026.1031.6
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/MoveTheWheelsRoot.js +2 -2
- package/dist/MoveTheWheelsRoutes.js +133 -130
- package/dist/movethewheels/pages/FinancePage.d.ts +3 -1
- package/dist/node_modules/lucide-react/dist/esm/icons/file-check.js +18 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/receipt.js +18 -0
- package/dist/pages/FinancePage.js +99 -71
- package/package.json +1 -1
- package/src/movethewheels/MoveTheWheelsRoot.tsx +4 -2
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +10 -4
- package/src/movethewheels/components/UpcomingDemandPanel.tsx +1 -3
- package/src/movethewheels/pages/FinancePage.tsx +33 -3
- package/dist/movethewheels/pages/AIAssistantPage.d.ts +0 -22
- package/dist/node_modules/lucide-react/dist/esm/icons/message-circle.js +0 -8
- package/dist/node_modules/lucide-react/dist/esm/icons/wallet.js +0 -11
- package/dist/pages/AIAssistantPage.js +0 -81
- package/src/movethewheels/pages/AIAssistantPage.tsx +0 -123
|
@@ -262,8 +262,8 @@ var T = ({ registerNavItems: _, basePath: v = "/" }) => {
|
|
|
262
262
|
},
|
|
263
263
|
{
|
|
264
264
|
id: "mtw-ai-assistant",
|
|
265
|
-
label: b("movethewheels.root.nav.
|
|
266
|
-
path:
|
|
265
|
+
label: b("movethewheels.root.nav.aiOperations", "AI Operations"),
|
|
266
|
+
path: "/ai",
|
|
267
267
|
icon: /* @__PURE__ */ S(t, { size: 16 }),
|
|
268
268
|
order: 13
|
|
269
269
|
},
|
|
@@ -3,268 +3,271 @@ import { useModuleSettings as t } from "./providers/ModuleSettingsProvider.js";
|
|
|
3
3
|
import { useTr as n } from "./shared/hooks/useTr.js";
|
|
4
4
|
import "./hooks/index.js";
|
|
5
5
|
import { Suspense as r, lazy as i } from "react";
|
|
6
|
-
import {
|
|
7
|
-
import { jsx as
|
|
8
|
-
import { NotFoundPage as
|
|
6
|
+
import { Navigate as a, Route as o, Routes as s, useNavigate as c } from "react-router";
|
|
7
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
8
|
+
import { NotFoundPage as d } from "@burdenoff/fe-libs/shared/pages";
|
|
9
9
|
//#region src/movethewheels/MoveTheWheelsRoutes.tsx
|
|
10
|
-
function
|
|
11
|
-
let { navigate: t, basePath: r } = e(), i =
|
|
12
|
-
return /* @__PURE__ */
|
|
10
|
+
function f() {
|
|
11
|
+
let { navigate: t, basePath: r } = e(), i = c();
|
|
12
|
+
return /* @__PURE__ */ l(d, {
|
|
13
13
|
homeLabel: n()("movethewheels.root.notFound.homeLabel", "Back to MoveTheWheels"),
|
|
14
14
|
onGoHome: () => {
|
|
15
15
|
t ? t(r || "/") : i("/");
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
function
|
|
19
|
+
function p() {
|
|
20
20
|
let e = n();
|
|
21
|
-
return /* @__PURE__ */
|
|
21
|
+
return /* @__PURE__ */ l("div", {
|
|
22
22
|
className: "flex items-center justify-center min-h-[400px]",
|
|
23
|
-
children: /* @__PURE__ */
|
|
23
|
+
children: /* @__PURE__ */ u("div", {
|
|
24
24
|
className: "flex flex-col items-center gap-3",
|
|
25
|
-
children: [/* @__PURE__ */
|
|
25
|
+
children: [/* @__PURE__ */ l("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" }), /* @__PURE__ */ l("p", {
|
|
26
26
|
className: "text-sm text-text-secondary",
|
|
27
27
|
children: e("movethewheels.root.loading", "Loading...")
|
|
28
28
|
})]
|
|
29
29
|
})
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
var
|
|
32
|
+
var m = i(() => import("./pages/DashboardPage.js")), h = i(() => import("./pages/OrdersListPage.js")), g = i(() => import("./pages/OrderDetailsPage.js")), _ = i(() => import("./pages/CreateOrderPage.js")), v = i(() => import("./pages/TrackingPage.js")), y = i(() => import("./pages/TrackingEventQualityPage.js")), b = i(() => import("./pages/ShipmentStatusAuthorityPage.js")), x = i(() => import("./pages/LiveTrackingPage.js")), S = i(() => import("./pages/FleetPage.js")), C = i(() => import("./pages/VehiclesPage.js")), w = i(() => import("./pages/VehicleDetailsPage.js")), T = i(() => import("./pages/DriversPage.js")), E = i(() => import("./pages/DriverDetailsPage.js")), D = i(() => import("./pages/InventoryPage.js")), O = i(() => import("./pages/ProductsPage.js")), k = i(() => import("./pages/ProductDetailsPage.js")), A = i(() => import("./pages/PalletPreviewPage.js")), j = i(() => import("./pages/WarehousesPage.js")), M = i(() => import("./pages/WarehouseDetailsPage.js")), N = i(() => import("./pages/CustomersPage.js")), P = i(() => import("./pages/CustomerDetailsPage.js")), F = i(() => import("./pages/MarketplacePage.js")), ee = i(() => import("./pages/ImportExportPage.js")), I = i(() => import("./pages/SettingsPage.js")), L = i(() => import("./pages/RoutesPage.js")), R = i(() => import("./pages/RouteDetailsPage.js")), z = i(() => import("./pages/AnalyticsPage.js")), B = i(() => import("./pages/FinancePage.js")), V = i(() => import("./pages/FreightEstimatePage.js")), H = i(() => import("./pages/FreightInvoicePage.js")), U = i(() => import("./pages/ConsolidationPage.js")), W = i(() => import("./pages/LogisticsProceduresPage.js")), G = i(() => import("./pages/DeliveryCapturePage.js")), K = i(() => import("./pages/MultiModalShipmentPage.js")), q = i(() => import("./pages/ShippingRatesPage.js")), J = i(() => import("./pages/ContainersPage.js")), Y = i(() => import("./pages/ContainerConditionPage.js")), X = i(() => import("./pages/FreeTimePage.js")), Z = i(() => import("./pages/PendingPickPage.js")), Q = i(() => import("./pages/StockObservationsPage.js")), $ = i(() => import("./pages/StockBindingPage.js")), te = i(() => import("./pages/TripUtilizationPage.js")), ne = i(() => import("./pages/ConsumedFuelPreviewPage.js")), re = i(() => import("./pages/EmptyReusePage.js"));
|
|
33
33
|
function ie() {
|
|
34
|
-
return t(), /* @__PURE__ */
|
|
35
|
-
fallback: /* @__PURE__ */
|
|
36
|
-
children: /* @__PURE__ */
|
|
37
|
-
/* @__PURE__ */
|
|
34
|
+
return t(), /* @__PURE__ */ l(r, {
|
|
35
|
+
fallback: /* @__PURE__ */ l(p, {}),
|
|
36
|
+
children: /* @__PURE__ */ u(s, { children: [
|
|
37
|
+
/* @__PURE__ */ l(o, {
|
|
38
38
|
index: !0,
|
|
39
|
-
element: /* @__PURE__ */
|
|
39
|
+
element: /* @__PURE__ */ l(m, {})
|
|
40
40
|
}),
|
|
41
|
-
/* @__PURE__ */
|
|
41
|
+
/* @__PURE__ */ l(o, {
|
|
42
42
|
path: "orders",
|
|
43
|
-
element: /* @__PURE__ */
|
|
43
|
+
element: /* @__PURE__ */ l(h, {})
|
|
44
44
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
45
|
+
/* @__PURE__ */ l(o, {
|
|
46
46
|
path: "orders/new",
|
|
47
|
-
element: /* @__PURE__ */
|
|
47
|
+
element: /* @__PURE__ */ l(_, {})
|
|
48
48
|
}),
|
|
49
|
-
/* @__PURE__ */
|
|
49
|
+
/* @__PURE__ */ l(o, {
|
|
50
50
|
path: "orders/:orderId",
|
|
51
|
-
element: /* @__PURE__ */
|
|
51
|
+
element: /* @__PURE__ */ l(g, {})
|
|
52
52
|
}),
|
|
53
|
-
/* @__PURE__ */
|
|
53
|
+
/* @__PURE__ */ l(o, {
|
|
54
54
|
path: "orders/:orderId/edit",
|
|
55
|
-
element: /* @__PURE__ */
|
|
55
|
+
element: /* @__PURE__ */ l(_, {})
|
|
56
56
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
57
|
+
/* @__PURE__ */ l(o, {
|
|
58
58
|
path: "tracking",
|
|
59
|
-
element: /* @__PURE__ */
|
|
59
|
+
element: /* @__PURE__ */ l(v, {})
|
|
60
60
|
}),
|
|
61
|
-
/* @__PURE__ */
|
|
61
|
+
/* @__PURE__ */ l(o, {
|
|
62
62
|
path: "tracking/live",
|
|
63
|
-
element: /* @__PURE__ */
|
|
63
|
+
element: /* @__PURE__ */ l(x, {})
|
|
64
64
|
}),
|
|
65
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ l(o, {
|
|
66
66
|
path: "tracking/event-quality",
|
|
67
|
-
element: /* @__PURE__ */
|
|
67
|
+
element: /* @__PURE__ */ l(y, {})
|
|
68
68
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ l(o, {
|
|
70
70
|
path: "shipments/status-authority",
|
|
71
|
-
element: /* @__PURE__ */
|
|
71
|
+
element: /* @__PURE__ */ l(b, {})
|
|
72
72
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
73
|
+
/* @__PURE__ */ l(o, {
|
|
74
74
|
path: "deliveries/mine",
|
|
75
|
-
element: /* @__PURE__ */
|
|
75
|
+
element: /* @__PURE__ */ l(G, {})
|
|
76
76
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ l(o, {
|
|
78
78
|
path: "shipments/multi-modal",
|
|
79
|
-
element: /* @__PURE__ */
|
|
79
|
+
element: /* @__PURE__ */ l(K, {})
|
|
80
80
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ l(o, {
|
|
82
82
|
path: "shipments/rates",
|
|
83
|
-
element: /* @__PURE__ */
|
|
83
|
+
element: /* @__PURE__ */ l(q, {})
|
|
84
84
|
}),
|
|
85
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ l(o, {
|
|
86
86
|
path: "containers",
|
|
87
|
-
element: /* @__PURE__ */
|
|
87
|
+
element: /* @__PURE__ */ l(J, {})
|
|
88
88
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ l(o, {
|
|
90
90
|
path: "containers/condition",
|
|
91
|
-
element: /* @__PURE__ */
|
|
91
|
+
element: /* @__PURE__ */ l(Y, {})
|
|
92
92
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ l(o, {
|
|
94
94
|
path: "containers/free-time",
|
|
95
|
-
element: /* @__PURE__ */
|
|
95
|
+
element: /* @__PURE__ */ l(X, {})
|
|
96
96
|
}),
|
|
97
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ l(o, {
|
|
98
98
|
path: "containers/empty-reuse",
|
|
99
|
-
element: /* @__PURE__ */
|
|
99
|
+
element: /* @__PURE__ */ l(re, {})
|
|
100
100
|
}),
|
|
101
|
-
/* @__PURE__ */
|
|
101
|
+
/* @__PURE__ */ l(o, {
|
|
102
102
|
path: "containers/consolidation",
|
|
103
|
-
element: /* @__PURE__ */
|
|
103
|
+
element: /* @__PURE__ */ l(U, {})
|
|
104
104
|
}),
|
|
105
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ l(o, {
|
|
106
106
|
path: "containers/procedures",
|
|
107
|
-
element: /* @__PURE__ */
|
|
107
|
+
element: /* @__PURE__ */ l(W, {})
|
|
108
108
|
}),
|
|
109
|
-
/* @__PURE__ */
|
|
109
|
+
/* @__PURE__ */ l(o, {
|
|
110
110
|
path: "fleet",
|
|
111
|
-
element: /* @__PURE__ */
|
|
111
|
+
element: /* @__PURE__ */ l(S, {})
|
|
112
112
|
}),
|
|
113
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ l(o, {
|
|
114
114
|
path: "fleet/vehicles",
|
|
115
|
-
element: /* @__PURE__ */
|
|
115
|
+
element: /* @__PURE__ */ l(C, {})
|
|
116
116
|
}),
|
|
117
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ l(o, {
|
|
118
118
|
path: "fleet/vehicles/new",
|
|
119
|
-
element: /* @__PURE__ */
|
|
119
|
+
element: /* @__PURE__ */ l(w, {})
|
|
120
120
|
}),
|
|
121
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ l(o, {
|
|
122
122
|
path: "fleet/vehicles/:vehicleId",
|
|
123
|
-
element: /* @__PURE__ */
|
|
123
|
+
element: /* @__PURE__ */ l(w, {})
|
|
124
124
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ l(o, {
|
|
126
126
|
path: "fleet/vehicles/:vehicleId/edit",
|
|
127
|
-
element: /* @__PURE__ */
|
|
127
|
+
element: /* @__PURE__ */ l(w, {})
|
|
128
128
|
}),
|
|
129
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ l(o, {
|
|
130
130
|
path: "fleet/drivers",
|
|
131
|
-
element: /* @__PURE__ */
|
|
131
|
+
element: /* @__PURE__ */ l(T, {})
|
|
132
132
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ l(o, {
|
|
134
134
|
path: "fleet/drivers/new",
|
|
135
|
-
element: /* @__PURE__ */
|
|
135
|
+
element: /* @__PURE__ */ l(E, {})
|
|
136
136
|
}),
|
|
137
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ l(o, {
|
|
138
138
|
path: "fleet/drivers/:driverId",
|
|
139
|
-
element: /* @__PURE__ */
|
|
139
|
+
element: /* @__PURE__ */ l(E, {})
|
|
140
140
|
}),
|
|
141
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ l(o, {
|
|
142
142
|
path: "fleet/drivers/:driverId/edit",
|
|
143
|
-
element: /* @__PURE__ */
|
|
143
|
+
element: /* @__PURE__ */ l(E, {})
|
|
144
144
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ l(o, {
|
|
146
146
|
path: "inventory",
|
|
147
|
-
element: /* @__PURE__ */
|
|
147
|
+
element: /* @__PURE__ */ l(D, {})
|
|
148
148
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ l(o, {
|
|
150
150
|
path: "inventory/source-assessments",
|
|
151
|
-
element: /* @__PURE__ */
|
|
151
|
+
element: /* @__PURE__ */ l($, {})
|
|
152
152
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ l(o, {
|
|
154
154
|
path: "inventory/reported-issues",
|
|
155
|
-
element: /* @__PURE__ */
|
|
155
|
+
element: /* @__PURE__ */ l(Q, {})
|
|
156
156
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ l(o, {
|
|
158
158
|
path: "inventory/pending-picks",
|
|
159
|
-
element: /* @__PURE__ */
|
|
159
|
+
element: /* @__PURE__ */ l(Z, {})
|
|
160
160
|
}),
|
|
161
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ l(o, {
|
|
162
162
|
path: "inventory/products",
|
|
163
|
-
element: /* @__PURE__ */
|
|
163
|
+
element: /* @__PURE__ */ l(O, {})
|
|
164
164
|
}),
|
|
165
|
-
/* @__PURE__ */
|
|
165
|
+
/* @__PURE__ */ l(o, {
|
|
166
166
|
path: "inventory/products/new",
|
|
167
|
-
element: /* @__PURE__ */
|
|
167
|
+
element: /* @__PURE__ */ l(k, {})
|
|
168
168
|
}),
|
|
169
|
-
/* @__PURE__ */
|
|
169
|
+
/* @__PURE__ */ l(o, {
|
|
170
170
|
path: "inventory/products/:productId",
|
|
171
|
-
element: /* @__PURE__ */
|
|
171
|
+
element: /* @__PURE__ */ l(k, {})
|
|
172
172
|
}),
|
|
173
|
-
/* @__PURE__ */
|
|
173
|
+
/* @__PURE__ */ l(o, {
|
|
174
174
|
path: "inventory/products/:productId/edit",
|
|
175
|
-
element: /* @__PURE__ */
|
|
175
|
+
element: /* @__PURE__ */ l(k, {})
|
|
176
176
|
}),
|
|
177
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ l(o, {
|
|
178
178
|
path: "inventory/warehouses",
|
|
179
|
-
element: /* @__PURE__ */
|
|
179
|
+
element: /* @__PURE__ */ l(j, {})
|
|
180
180
|
}),
|
|
181
|
-
/* @__PURE__ */
|
|
181
|
+
/* @__PURE__ */ l(o, {
|
|
182
182
|
path: "inventory/warehouses/pallet-preview",
|
|
183
|
-
element: /* @__PURE__ */
|
|
183
|
+
element: /* @__PURE__ */ l(A, {})
|
|
184
184
|
}),
|
|
185
|
-
/* @__PURE__ */
|
|
185
|
+
/* @__PURE__ */ l(o, {
|
|
186
186
|
path: "inventory/warehouses/new",
|
|
187
|
-
element: /* @__PURE__ */
|
|
187
|
+
element: /* @__PURE__ */ l(M, {})
|
|
188
188
|
}),
|
|
189
|
-
/* @__PURE__ */
|
|
189
|
+
/* @__PURE__ */ l(o, {
|
|
190
190
|
path: "inventory/warehouses/:warehouseId",
|
|
191
|
-
element: /* @__PURE__ */
|
|
191
|
+
element: /* @__PURE__ */ l(M, {})
|
|
192
192
|
}),
|
|
193
|
-
/* @__PURE__ */
|
|
193
|
+
/* @__PURE__ */ l(o, {
|
|
194
194
|
path: "inventory/warehouses/:warehouseId/edit",
|
|
195
|
-
element: /* @__PURE__ */
|
|
195
|
+
element: /* @__PURE__ */ l(M, {})
|
|
196
196
|
}),
|
|
197
|
-
/* @__PURE__ */
|
|
197
|
+
/* @__PURE__ */ l(o, {
|
|
198
198
|
path: "customers",
|
|
199
|
-
element: /* @__PURE__ */
|
|
199
|
+
element: /* @__PURE__ */ l(N, {})
|
|
200
200
|
}),
|
|
201
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ l(o, {
|
|
202
202
|
path: "customers/new",
|
|
203
|
-
element: /* @__PURE__ */
|
|
203
|
+
element: /* @__PURE__ */ l(P, {})
|
|
204
204
|
}),
|
|
205
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ l(o, {
|
|
206
206
|
path: "customers/:customerId",
|
|
207
|
-
element: /* @__PURE__ */
|
|
207
|
+
element: /* @__PURE__ */ l(P, {})
|
|
208
208
|
}),
|
|
209
|
-
/* @__PURE__ */
|
|
209
|
+
/* @__PURE__ */ l(o, {
|
|
210
210
|
path: "marketplace",
|
|
211
|
-
element: /* @__PURE__ */
|
|
211
|
+
element: /* @__PURE__ */ l(F, {})
|
|
212
212
|
}),
|
|
213
|
-
/* @__PURE__ */
|
|
213
|
+
/* @__PURE__ */ l(o, {
|
|
214
214
|
path: "import-export",
|
|
215
|
-
element: /* @__PURE__ */
|
|
215
|
+
element: /* @__PURE__ */ l(ee, {})
|
|
216
216
|
}),
|
|
217
|
-
/* @__PURE__ */
|
|
217
|
+
/* @__PURE__ */ l(o, {
|
|
218
218
|
path: "settings",
|
|
219
|
-
element: /* @__PURE__ */
|
|
219
|
+
element: /* @__PURE__ */ l(I, {})
|
|
220
220
|
}),
|
|
221
|
-
/* @__PURE__ */
|
|
221
|
+
/* @__PURE__ */ l(o, {
|
|
222
222
|
path: "routes",
|
|
223
|
-
element: /* @__PURE__ */
|
|
223
|
+
element: /* @__PURE__ */ l(L, {})
|
|
224
224
|
}),
|
|
225
|
-
/* @__PURE__ */
|
|
225
|
+
/* @__PURE__ */ l(o, {
|
|
226
226
|
path: "routes/trip-utilization",
|
|
227
|
-
element: /* @__PURE__ */
|
|
227
|
+
element: /* @__PURE__ */ l(te, {})
|
|
228
228
|
}),
|
|
229
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ l(o, {
|
|
230
230
|
path: "fuel-preview",
|
|
231
|
-
element: /* @__PURE__ */
|
|
231
|
+
element: /* @__PURE__ */ l(ne, {})
|
|
232
232
|
}),
|
|
233
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ l(o, {
|
|
234
234
|
path: "routes/new",
|
|
235
|
-
element: /* @__PURE__ */
|
|
235
|
+
element: /* @__PURE__ */ l(R, {})
|
|
236
236
|
}),
|
|
237
|
-
/* @__PURE__ */
|
|
237
|
+
/* @__PURE__ */ l(o, {
|
|
238
238
|
path: "routes/:routeId",
|
|
239
|
-
element: /* @__PURE__ */
|
|
239
|
+
element: /* @__PURE__ */ l(R, {})
|
|
240
240
|
}),
|
|
241
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ l(o, {
|
|
242
242
|
path: "routes/:routeId/edit",
|
|
243
|
-
element: /* @__PURE__ */
|
|
243
|
+
element: /* @__PURE__ */ l(R, {})
|
|
244
244
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
245
|
+
/* @__PURE__ */ l(o, {
|
|
246
246
|
path: "analytics",
|
|
247
|
-
element: /* @__PURE__ */
|
|
247
|
+
element: /* @__PURE__ */ l(z, {})
|
|
248
248
|
}),
|
|
249
|
-
/* @__PURE__ */
|
|
249
|
+
/* @__PURE__ */ l(o, {
|
|
250
250
|
path: "finance",
|
|
251
|
-
element: /* @__PURE__ */
|
|
251
|
+
element: /* @__PURE__ */ l(B, {})
|
|
252
252
|
}),
|
|
253
|
-
/* @__PURE__ */
|
|
253
|
+
/* @__PURE__ */ l(o, {
|
|
254
254
|
path: "finance/freight-estimates",
|
|
255
|
-
element: /* @__PURE__ */
|
|
255
|
+
element: /* @__PURE__ */ l(V, {})
|
|
256
256
|
}),
|
|
257
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ l(o, {
|
|
258
258
|
path: "finance/freight-invoice-comparisons",
|
|
259
|
-
element: /* @__PURE__ */
|
|
259
|
+
element: /* @__PURE__ */ l(H, {})
|
|
260
260
|
}),
|
|
261
|
-
/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ l(o, {
|
|
262
262
|
path: "ai-assistant",
|
|
263
|
-
element: /* @__PURE__ */
|
|
263
|
+
element: /* @__PURE__ */ l(a, {
|
|
264
|
+
to: "/ai",
|
|
265
|
+
replace: !0
|
|
266
|
+
})
|
|
264
267
|
}),
|
|
265
|
-
/* @__PURE__ */
|
|
268
|
+
/* @__PURE__ */ l(o, {
|
|
266
269
|
path: "*",
|
|
267
|
-
element: /* @__PURE__ */
|
|
270
|
+
element: /* @__PURE__ */ l(f, {})
|
|
268
271
|
})
|
|
269
272
|
] })
|
|
270
273
|
});
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* revenue, fuel cost, open invoices) plus the real revenue trend series — no
|
|
6
6
|
* simulated paid/pending splits and no fabricated cost categories. Invoicing and
|
|
7
7
|
* settlement are handled by the platform Billing module, which this page
|
|
8
|
-
* deep-links to rather than re-implementing an Invoice ledger here.
|
|
8
|
+
* deep-links to rather than re-implementing an Invoice ledger here. Carrier
|
|
9
|
+
* invoices are checked against the agreed freight estimate on the freight
|
|
10
|
+
* invoice comparison page, which this page links to (BOFF-4395).
|
|
9
11
|
*/
|
|
10
12
|
export default function FinancePage(): import('react').JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/file-check.js
|
|
3
|
+
var t = e("FileCheck", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",
|
|
6
|
+
key: "1rqfz7"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M14 2v4a2 2 0 0 0 2 2h4",
|
|
10
|
+
key: "tnqrlb"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "m9 15 2 2 4-4",
|
|
14
|
+
key: "1grp1n"
|
|
15
|
+
}]
|
|
16
|
+
]);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as FileCheck };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/receipt.js
|
|
3
|
+
var t = e("Receipt", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z",
|
|
6
|
+
key: "q3az6g"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8",
|
|
10
|
+
key: "1h4pet"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M12 17.5v-11",
|
|
14
|
+
key: "1jc1ny"
|
|
15
|
+
}]
|
|
16
|
+
]);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Receipt };
|
|
@@ -1,160 +1,188 @@
|
|
|
1
1
|
import { ArrowRight as e } from "../node_modules/lucide-react/dist/esm/icons/arrow-right.js";
|
|
2
2
|
import { CreditCard as t } from "../node_modules/lucide-react/dist/esm/icons/credit-card.js";
|
|
3
3
|
import { DollarSign as n } from "../node_modules/lucide-react/dist/esm/icons/dollar-sign.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
4
|
+
import { FileCheck as r } from "../node_modules/lucide-react/dist/esm/icons/file-check.js";
|
|
5
|
+
import { FileText as i } from "../node_modules/lucide-react/dist/esm/icons/file-text.js";
|
|
6
|
+
import { Fuel as a } from "../node_modules/lucide-react/dist/esm/icons/fuel.js";
|
|
7
|
+
import { Receipt as o } from "../node_modules/lucide-react/dist/esm/icons/receipt.js";
|
|
8
|
+
import { TrendingUp as s } from "../node_modules/lucide-react/dist/esm/icons/trending-up.js";
|
|
9
|
+
import { joinPath as c } from "../utils/navigation.js";
|
|
10
|
+
import { useMoveTheWheels as l } from "../providers/MoveTheWheelsProvider.js";
|
|
11
|
+
import { formatCurrency as u } from "../utils/formatters.js";
|
|
12
|
+
import { useAnalytics as d, useFinanceMetrics as f } from "../hooks/useAnalytics.js";
|
|
13
|
+
import { Button as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "../components/ui.js";
|
|
14
|
+
import { PageLayout as v } from "../components/PageLayout.js";
|
|
15
|
+
import { chartTokens as y } from "../components/charts/chartTokens.js";
|
|
16
|
+
import { MetricCard as b, MetricGrid as x } from "../components/MetricCard.js";
|
|
17
|
+
import { TrendChart as S } from "../components/charts/TrendChart.js";
|
|
18
|
+
import { VolumeBar as C } from "../components/charts/VolumeBar.js";
|
|
16
19
|
import "../components/charts/index.js";
|
|
17
|
-
import { useMemo as
|
|
18
|
-
import { jsx as
|
|
19
|
-
import { EmphasisPanel as
|
|
20
|
+
import { useMemo as w } from "react";
|
|
21
|
+
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
22
|
+
import { EmphasisPanel as D, PagePurpose as O } from "@burdenoff/fe-libs/ui";
|
|
20
23
|
//#region src/movethewheels/pages/FinancePage.tsx
|
|
21
|
-
function
|
|
22
|
-
let { analytics:
|
|
24
|
+
function k() {
|
|
25
|
+
let { analytics: k } = d(), { metrics: A } = f(), { navigate: j, basePath: M } = l(), N = () => j("/billing"), P = () => j(c(M, "finance/freight-estimates")), F = () => j(c(M, "finance/freight-invoice-comparisons")), I = w(() => k.trends.revenue.map((e) => ({
|
|
23
26
|
month: e.month,
|
|
24
27
|
revenue: e.revenue
|
|
25
|
-
})), [
|
|
28
|
+
})), [k.trends.revenue]), L = w(() => [
|
|
26
29
|
{
|
|
27
30
|
label: "Total revenue",
|
|
28
|
-
amount:
|
|
31
|
+
amount: A.totalRevenue
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
label: "Collected",
|
|
32
|
-
amount:
|
|
35
|
+
amount: A.deliveredRevenue
|
|
33
36
|
},
|
|
34
37
|
{
|
|
35
38
|
label: "Fuel cost",
|
|
36
|
-
amount:
|
|
39
|
+
amount: A.fuelCost
|
|
37
40
|
}
|
|
38
41
|
], [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
]),
|
|
43
|
-
return /* @__PURE__ */
|
|
42
|
+
A.totalRevenue,
|
|
43
|
+
A.deliveredRevenue,
|
|
44
|
+
A.fuelCost
|
|
45
|
+
]), R = L.some((e) => e.amount > 0);
|
|
46
|
+
return /* @__PURE__ */ E(v, {
|
|
44
47
|
title: "Finance",
|
|
45
48
|
subtitle: "Financial overview and reports",
|
|
46
|
-
icon: /* @__PURE__ */
|
|
47
|
-
headerActions: /* @__PURE__ */
|
|
49
|
+
icon: /* @__PURE__ */ T(n, { size: 24 }),
|
|
50
|
+
headerActions: /* @__PURE__ */ E(p, {
|
|
48
51
|
variant: "outline",
|
|
49
|
-
onClick:
|
|
50
|
-
children: [/* @__PURE__ */
|
|
52
|
+
onClick: N,
|
|
53
|
+
children: [/* @__PURE__ */ T(i, { size: 16 }), " Invoices & Billing"]
|
|
51
54
|
}),
|
|
52
55
|
children: [
|
|
53
|
-
/* @__PURE__ */
|
|
54
|
-
icon: /* @__PURE__ */
|
|
56
|
+
/* @__PURE__ */ T(O, {
|
|
57
|
+
icon: /* @__PURE__ */ T(n, { size: 18 }),
|
|
55
58
|
children: "Follow the money behind your deliveries. See total revenue, how much has already been collected on delivered orders, fuel cost and how many invoices are still open — then head to Billing to raise and settle invoices."
|
|
56
59
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
60
|
+
/* @__PURE__ */ E(x, {
|
|
58
61
|
columns: 4,
|
|
59
62
|
children: [
|
|
60
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ T(b, {
|
|
61
64
|
treatment: "glass",
|
|
62
65
|
glow: !0,
|
|
63
66
|
label: "Total Revenue",
|
|
64
|
-
value:
|
|
65
|
-
icon: /* @__PURE__ */
|
|
67
|
+
value: u(A.totalRevenue),
|
|
68
|
+
icon: /* @__PURE__ */ T(n, { size: 20 }),
|
|
66
69
|
accent: "success"
|
|
67
70
|
}),
|
|
68
|
-
/* @__PURE__ */
|
|
71
|
+
/* @__PURE__ */ T(b, {
|
|
69
72
|
label: "Collected (Delivered)",
|
|
70
|
-
value:
|
|
71
|
-
icon: /* @__PURE__ */
|
|
73
|
+
value: u(A.deliveredRevenue),
|
|
74
|
+
icon: /* @__PURE__ */ T(s, { size: 20 }),
|
|
72
75
|
accent: "brand"
|
|
73
76
|
}),
|
|
74
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ T(b, {
|
|
75
78
|
label: "Fuel Cost",
|
|
76
|
-
value:
|
|
77
|
-
icon: /* @__PURE__ */
|
|
79
|
+
value: u(A.fuelCost),
|
|
80
|
+
icon: /* @__PURE__ */ T(a, { size: 20 }),
|
|
78
81
|
accent: "warning"
|
|
79
82
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
83
|
+
/* @__PURE__ */ T(b, {
|
|
81
84
|
label: "Open Invoices",
|
|
82
|
-
value: String(
|
|
83
|
-
icon: /* @__PURE__ */
|
|
85
|
+
value: String(A.openInvoices),
|
|
86
|
+
icon: /* @__PURE__ */ T(t, { size: 20 }),
|
|
84
87
|
accent: "blue"
|
|
85
88
|
})
|
|
86
89
|
]
|
|
87
90
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
91
|
+
/* @__PURE__ */ E("div", {
|
|
89
92
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
90
|
-
children: [/* @__PURE__ */
|
|
93
|
+
children: [/* @__PURE__ */ E(m, {
|
|
91
94
|
className: "lg:col-span-2",
|
|
92
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue trend" }) }), /* @__PURE__ */ T(h, { children: /* @__PURE__ */ T(S, {
|
|
93
96
|
xKey: "month",
|
|
94
97
|
variant: "area",
|
|
95
98
|
height: 280,
|
|
96
99
|
showLegend: !1,
|
|
97
|
-
data:
|
|
100
|
+
data: I,
|
|
98
101
|
series: [{
|
|
99
102
|
dataKey: "revenue",
|
|
100
103
|
name: "Revenue",
|
|
101
|
-
color:
|
|
104
|
+
color: y.brandBlue
|
|
102
105
|
}],
|
|
103
|
-
valueFormatter: (e) =>
|
|
106
|
+
valueFormatter: (e) => u(Number(e)),
|
|
104
107
|
emptyMessage: "No revenue recorded yet. Revenue appears here as orders are delivered."
|
|
105
108
|
}) })]
|
|
106
|
-
}), /* @__PURE__ */
|
|
109
|
+
}), /* @__PURE__ */ E(D, {
|
|
107
110
|
className: "space-y-4",
|
|
108
111
|
children: [
|
|
109
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ T("h2", {
|
|
110
113
|
className: "text-base font-semibold text-text-primary",
|
|
111
114
|
children: "Invoices & Settlement"
|
|
112
115
|
}),
|
|
113
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ T("p", {
|
|
114
117
|
className: "text-sm text-text-secondary",
|
|
115
118
|
children: "Invoicing, payments and settlement run through the platform Billing module — the single source of truth for what's been billed and paid. MoveTheWheels doesn't keep its own invoice ledger."
|
|
116
119
|
}),
|
|
117
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ E("div", {
|
|
118
121
|
className: "flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
122
|
+
children: [/* @__PURE__ */ E("div", {
|
|
120
123
|
className: "flex items-center gap-3",
|
|
121
|
-
children: [/* @__PURE__ */
|
|
124
|
+
children: [/* @__PURE__ */ T("div", {
|
|
122
125
|
className: "w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center",
|
|
123
|
-
children: /* @__PURE__ */
|
|
126
|
+
children: /* @__PURE__ */ T(t, {
|
|
124
127
|
size: 20,
|
|
125
128
|
className: "text-status-warning-text"
|
|
126
129
|
})
|
|
127
|
-
}), /* @__PURE__ */
|
|
130
|
+
}), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
|
|
128
131
|
className: "font-medium",
|
|
129
132
|
children: "Open invoices"
|
|
130
|
-
}), /* @__PURE__ */
|
|
133
|
+
}), /* @__PURE__ */ E("p", {
|
|
131
134
|
className: "text-sm text-text-secondary",
|
|
132
|
-
children: [
|
|
135
|
+
children: [A.openInvoices, " awaiting settlement"]
|
|
133
136
|
})] })]
|
|
134
|
-
}), /* @__PURE__ */
|
|
137
|
+
}), /* @__PURE__ */ T("span", {
|
|
135
138
|
className: "text-xl font-bold text-status-warning-text",
|
|
136
|
-
children:
|
|
139
|
+
children: A.openInvoices
|
|
137
140
|
})]
|
|
138
141
|
}),
|
|
139
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ E(p, {
|
|
140
143
|
className: "w-full",
|
|
141
|
-
onClick:
|
|
142
|
-
children: ["Open Billing ", /* @__PURE__ */
|
|
144
|
+
onClick: N,
|
|
145
|
+
children: ["Open Billing ", /* @__PURE__ */ T(e, { size: 16 })]
|
|
146
|
+
}),
|
|
147
|
+
/* @__PURE__ */ E("div", {
|
|
148
|
+
className: "space-y-2 border-t border-border-default pt-4",
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ T("h3", {
|
|
151
|
+
className: "text-sm font-semibold text-text-primary",
|
|
152
|
+
children: "Freight cost control"
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ T("p", {
|
|
155
|
+
className: "text-sm text-text-secondary",
|
|
156
|
+
children: "Record the agreed freight estimate for a shipment, then check the carrier's invoice against it line by line before it is settled in Billing."
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ E("div", {
|
|
159
|
+
className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
|
|
160
|
+
children: [/* @__PURE__ */ E(p, {
|
|
161
|
+
variant: "outline",
|
|
162
|
+
onClick: P,
|
|
163
|
+
children: [/* @__PURE__ */ T(o, { size: 16 }), " Freight estimates"]
|
|
164
|
+
}), /* @__PURE__ */ E(p, {
|
|
165
|
+
variant: "outline",
|
|
166
|
+
onClick: F,
|
|
167
|
+
children: [/* @__PURE__ */ T(r, { size: 16 }), " Invoice comparisons"]
|
|
168
|
+
})]
|
|
169
|
+
})
|
|
170
|
+
]
|
|
143
171
|
})
|
|
144
172
|
]
|
|
145
173
|
})]
|
|
146
174
|
}),
|
|
147
|
-
/* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ E(m, { children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue vs cost" }) }), /* @__PURE__ */ T(h, { children: R ? /* @__PURE__ */ T(C, {
|
|
148
176
|
xKey: "label",
|
|
149
177
|
height: 260,
|
|
150
178
|
showLegend: !1,
|
|
151
|
-
data:
|
|
179
|
+
data: L,
|
|
152
180
|
series: [{
|
|
153
181
|
dataKey: "amount",
|
|
154
182
|
name: "Amount"
|
|
155
183
|
}],
|
|
156
|
-
valueFormatter: (e) =>
|
|
157
|
-
}) : /* @__PURE__ */
|
|
184
|
+
valueFormatter: (e) => u(Number(e))
|
|
185
|
+
}) : /* @__PURE__ */ T("p", {
|
|
158
186
|
className: "py-8 text-center text-sm text-text-secondary",
|
|
159
187
|
children: "Revenue and cost figures appear here as orders are delivered."
|
|
160
188
|
}) })] })
|
|
@@ -162,4 +190,4 @@ function E() {
|
|
|
162
190
|
});
|
|
163
191
|
}
|
|
164
192
|
//#endregion
|
|
165
|
-
export {
|
|
193
|
+
export { k as default };
|
package/package.json
CHANGED
|
@@ -302,8 +302,10 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
|
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
id: 'mtw-ai-assistant',
|
|
305
|
-
label: tr('movethewheels.root.nav.
|
|
306
|
-
|
|
305
|
+
label: tr('movethewheels.root.nav.aiOperations', 'AI Operations'),
|
|
306
|
+
// Shell-level shared AI operations page (fe-libs AiPage), not an
|
|
307
|
+
// MFE route — see BOFF-3897.
|
|
308
|
+
path: '/ai',
|
|
307
309
|
icon: <Bot size={16} />,
|
|
308
310
|
order: 13,
|
|
309
311
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Uses lazy loading for code splitting.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Routes, Route, useNavigate } from 'react-router';
|
|
8
|
+
import { Routes, Route, Navigate, useNavigate } from 'react-router';
|
|
9
9
|
import { lazy, Suspense } from 'react';
|
|
10
10
|
import { NotFoundPage } from '@burdenoff/fe-libs/shared/pages';
|
|
11
11
|
import { useMoveTheWheels } from './providers/MoveTheWheelsProvider';
|
|
@@ -83,7 +83,6 @@ const FreightEstimatePage = lazy(() => import('./pages/FreightEstimatePage'));
|
|
|
83
83
|
const FreightInvoicePage = lazy(() => import('./pages/FreightInvoicePage'));
|
|
84
84
|
const ConsolidationPage = lazy(() => import('./pages/ConsolidationPage'));
|
|
85
85
|
const LogisticsProceduresPage = lazy(() => import('./pages/LogisticsProceduresPage'));
|
|
86
|
-
const AIAssistantPage = lazy(() => import('./pages/AIAssistantPage'));
|
|
87
86
|
const DeliveryCapturePage = lazy(() => import('./pages/DeliveryCapturePage'));
|
|
88
87
|
const MultiModalShipmentPage = lazy(() => import('./pages/MultiModalShipmentPage'));
|
|
89
88
|
const ShippingRatesPage = lazy(() => import('./pages/ShippingRatesPage'));
|
|
@@ -189,8 +188,15 @@ export function MoveTheWheelsRoutes() {
|
|
|
189
188
|
<Route path="finance/freight-estimates" element={<FreightEstimatePage />} />
|
|
190
189
|
<Route path="finance/freight-invoice-comparisons" element={<FreightInvoicePage />} />
|
|
191
190
|
|
|
192
|
-
{/*
|
|
193
|
-
|
|
191
|
+
{/*
|
|
192
|
+
AI Operations lives on the shell's shared /ai page (fe-libs AiPage:
|
|
193
|
+
per-product AI credits, recorded usage by model / surface / trigger,
|
|
194
|
+
and the workspace model + provider catalog). The old ai-assistant
|
|
195
|
+
page advertised capabilities the backend never had (BOFF-3897), so
|
|
196
|
+
this path only redirects existing links and bookmarks there. Chat
|
|
197
|
+
stays on the shell's AssistantWidget.
|
|
198
|
+
*/}
|
|
199
|
+
<Route path="ai-assistant" element={<Navigate to="/ai" replace />} />
|
|
194
200
|
|
|
195
201
|
{/* Catch-all - friendly 404 */}
|
|
196
202
|
<Route path="*" element={<MoveTheWheelsNotFound />} />
|
|
@@ -211,9 +211,7 @@ function VarianceList({ rows }: VarianceListProps) {
|
|
|
211
211
|
{rows.map((row) => {
|
|
212
212
|
const isOvershoot = row.volumeVariance > 0;
|
|
213
213
|
const Icon = isOvershoot ? TrendingUp : TrendingDown;
|
|
214
|
-
const tone = isOvershoot
|
|
215
|
-
? 'text-status-success-text'
|
|
216
|
-
: 'text-status-error-text';
|
|
214
|
+
const tone = isOvershoot ? 'text-status-success-text' : 'text-status-error-text';
|
|
217
215
|
return (
|
|
218
216
|
<li
|
|
219
217
|
key={`${row.scopeType}-${row.scopeKey}-${row.periodStart}`}
|
|
@@ -5,11 +5,22 @@
|
|
|
5
5
|
* revenue, fuel cost, open invoices) plus the real revenue trend series — no
|
|
6
6
|
* simulated paid/pending splits and no fabricated cost categories. Invoicing and
|
|
7
7
|
* settlement are handled by the platform Billing module, which this page
|
|
8
|
-
* deep-links to rather than re-implementing an Invoice ledger here.
|
|
8
|
+
* deep-links to rather than re-implementing an Invoice ledger here. Carrier
|
|
9
|
+
* invoices are checked against the agreed freight estimate on the freight
|
|
10
|
+
* invoice comparison page, which this page links to (BOFF-4395).
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { useMemo } from 'react';
|
|
12
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
DollarSign,
|
|
16
|
+
TrendingUp,
|
|
17
|
+
CreditCard,
|
|
18
|
+
FileText,
|
|
19
|
+
Fuel,
|
|
20
|
+
ArrowRight,
|
|
21
|
+
Receipt,
|
|
22
|
+
FileCheck,
|
|
23
|
+
} from 'lucide-react';
|
|
13
24
|
import { PageLayout } from '../components/PageLayout';
|
|
14
25
|
import { MetricCard, MetricGrid } from '../components/MetricCard';
|
|
15
26
|
import { Card, CardContent, CardHeader, CardTitle, Button } from '../components/ui';
|
|
@@ -18,14 +29,18 @@ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
|
|
|
18
29
|
import { useAnalytics, useFinanceMetrics } from '../hooks/useAnalytics';
|
|
19
30
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
20
31
|
import { formatCurrency } from '../utils/formatters';
|
|
32
|
+
import { joinPath } from '../utils/navigation';
|
|
21
33
|
|
|
22
34
|
export default function FinancePage() {
|
|
23
35
|
const { analytics } = useAnalytics();
|
|
24
36
|
const { metrics } = useFinanceMetrics();
|
|
25
|
-
const { navigate } = useMoveTheWheels();
|
|
37
|
+
const { navigate, basePath } = useMoveTheWheels();
|
|
26
38
|
|
|
27
39
|
// Deep-link to the host Billing module (mounted at /billing in the app shell).
|
|
28
40
|
const openBilling = () => navigate('/billing');
|
|
41
|
+
const openFreightEstimates = () => navigate(joinPath(basePath, 'finance/freight-estimates'));
|
|
42
|
+
const openInvoiceComparisons = () =>
|
|
43
|
+
navigate(joinPath(basePath, 'finance/freight-invoice-comparisons'));
|
|
29
44
|
|
|
30
45
|
const revenueSeries = useMemo(
|
|
31
46
|
() => analytics.trends.revenue.map((r) => ({ month: r.month, revenue: r.revenue })),
|
|
@@ -137,6 +152,21 @@ export default function FinancePage() {
|
|
|
137
152
|
<Button className="w-full" onClick={openBilling}>
|
|
138
153
|
Open Billing <ArrowRight size={16} />
|
|
139
154
|
</Button>
|
|
155
|
+
<div className="space-y-2 border-t border-border-default pt-4">
|
|
156
|
+
<h3 className="text-sm font-semibold text-text-primary">Freight cost control</h3>
|
|
157
|
+
<p className="text-sm text-text-secondary">
|
|
158
|
+
Record the agreed freight estimate for a shipment, then check the carrier's
|
|
159
|
+
invoice against it line by line before it is settled in Billing.
|
|
160
|
+
</p>
|
|
161
|
+
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
|
162
|
+
<Button variant="outline" onClick={openFreightEstimates}>
|
|
163
|
+
<Receipt size={16} /> Freight estimates
|
|
164
|
+
</Button>
|
|
165
|
+
<Button variant="outline" onClick={openInvoiceComparisons}>
|
|
166
|
+
<FileCheck size={16} /> Invoice comparisons
|
|
167
|
+
</Button>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
140
170
|
</EmphasisPanel>
|
|
141
171
|
</div>
|
|
142
172
|
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AI Operations Page
|
|
3
|
-
*
|
|
4
|
-
* This page previously shipped a second, fabricated chat surface
|
|
5
|
-
* (`useAssistant` → `Query.assistantInsights`) whose "capabilities" list
|
|
6
|
-
* advertised route optimization, demand forecasting, fleet analysis, cost
|
|
7
|
-
* optimization and natural-language queries — none of which the backend
|
|
8
|
-
* implemented; every question routed to a fixed template built from four
|
|
9
|
-
* Prisma counts. See BOFF-3897.
|
|
10
|
-
*
|
|
11
|
-
* The real conversational assistant is the shared `AssistantWidget`, already
|
|
12
|
-
* mounted globally in the app shell (`AppShell.tsx`) on the sandbox
|
|
13
|
-
* transport — this page must never contain a second chat box.
|
|
14
|
-
*
|
|
15
|
-
* The full "AI Operations" surface this page is meant to become — a model
|
|
16
|
-
* picker, an agent-activity feed reading the shared AgentRun ledger,
|
|
17
|
-
* accept/reject decision cards for AI dispatch proposals, and per-workspace
|
|
18
|
-
* AI credit visibility — depends on the shared multi-model AI gateway
|
|
19
|
-
* (BOFF-3601), which has not landed yet. Until it does, this page shows an
|
|
20
|
-
* honest roadmap state instead of fabricating any of that content.
|
|
21
|
-
*/
|
|
22
|
-
export default function AIAssistantPage(): import('react').JSX.Element;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
-
//#region node_modules/lucide-react/dist/esm/icons/message-circle.js
|
|
3
|
-
var t = e("MessageCircle", [["path", {
|
|
4
|
-
d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z",
|
|
5
|
-
key: "vv11sd"
|
|
6
|
-
}]]);
|
|
7
|
-
//#endregion
|
|
8
|
-
export { t as MessageCircle };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
-
//#region node_modules/lucide-react/dist/esm/icons/wallet.js
|
|
3
|
-
var t = e("Wallet", [["path", {
|
|
4
|
-
d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1",
|
|
5
|
-
key: "18etb6"
|
|
6
|
-
}], ["path", {
|
|
7
|
-
d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4",
|
|
8
|
-
key: "xoc0q4"
|
|
9
|
-
}]]);
|
|
10
|
-
//#endregion
|
|
11
|
-
export { t as Wallet };
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { Activity as e } from "../node_modules/lucide-react/dist/esm/icons/activity.js";
|
|
2
|
-
import { Bot as t } from "../node_modules/lucide-react/dist/esm/icons/bot.js";
|
|
3
|
-
import { MessageCircle as n } from "../node_modules/lucide-react/dist/esm/icons/message-circle.js";
|
|
4
|
-
import { ShieldCheck as r } from "../node_modules/lucide-react/dist/esm/icons/shield-check.js";
|
|
5
|
-
import { Wallet as i } from "../node_modules/lucide-react/dist/esm/icons/wallet.js";
|
|
6
|
-
import { useTr as a } from "../shared/hooks/useTr.js";
|
|
7
|
-
import "../hooks/index.js";
|
|
8
|
-
import { Card as o, CardContent as s, CardHeader as c, CardTitle as l } from "../components/ui.js";
|
|
9
|
-
import { EmptyState as u, PageLayout as d } from "../components/PageLayout.js";
|
|
10
|
-
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
11
|
-
import { GlassCard as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
|
|
12
|
-
//#region src/movethewheels/pages/AIAssistantPage.tsx
|
|
13
|
-
function g() {
|
|
14
|
-
let g = a(), _ = [
|
|
15
|
-
{
|
|
16
|
-
icon: e,
|
|
17
|
-
title: g("movethewheels.ai.roadmap.agentActivity.title", "Agent activity feed"),
|
|
18
|
-
description: g("movethewheels.ai.roadmap.agentActivity.description", "A live log of what the AI decided, on which shipments, with trigger, model, latency and cost — so an autonomous run is never a black box.")
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
icon: r,
|
|
22
|
-
title: g("movethewheels.ai.roadmap.dispatchDecisionCards.title", "Dispatch decision cards"),
|
|
23
|
-
description: g("movethewheels.ai.roadmap.dispatchDecisionCards.description", "Proposed driver/vehicle assignments and carrier recommendations with rationale and confidence, requiring an explicit accept or reject before anything is written.")
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
icon: i,
|
|
27
|
-
title: g("movethewheels.ai.roadmap.aiCreditVisibility.title", "AI credit visibility"),
|
|
28
|
-
description: g("movethewheels.ai.roadmap.aiCreditVisibility.description", "Per-workspace AI spend for admins, so cost is visible before the invoice.")
|
|
29
|
-
}
|
|
30
|
-
];
|
|
31
|
-
return /* @__PURE__ */ p(d, {
|
|
32
|
-
title: g("movethewheels.ai.title", "AI Operations"),
|
|
33
|
-
subtitle: g("movethewheels.ai.subtitle", "What the AI is doing on your workspace, and why"),
|
|
34
|
-
icon: /* @__PURE__ */ f(t, { size: 24 }),
|
|
35
|
-
children: [
|
|
36
|
-
/* @__PURE__ */ f(h, {
|
|
37
|
-
icon: /* @__PURE__ */ f(t, { size: 18 }),
|
|
38
|
-
children: g("movethewheels.ai.purpose", "This page will surface AI-driven dispatch decisions and their outcomes once the shared AI runtime lands. It does not host a chat box — chat with your live operational data is always available from the assistant icon anywhere in the app.")
|
|
39
|
-
}),
|
|
40
|
-
/* @__PURE__ */ f(m, {
|
|
41
|
-
treatment: "glass",
|
|
42
|
-
className: "p-4",
|
|
43
|
-
children: /* @__PURE__ */ p("div", {
|
|
44
|
-
className: "flex items-start gap-3",
|
|
45
|
-
children: [/* @__PURE__ */ f(n, {
|
|
46
|
-
size: 20,
|
|
47
|
-
className: "text-primary flex-shrink-0 mt-0.5"
|
|
48
|
-
}), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
|
|
49
|
-
className: "text-sm font-medium text-text-primary",
|
|
50
|
-
children: g("movethewheels.ai.callout.title", "Looking to ask a question about your operations?")
|
|
51
|
-
}), /* @__PURE__ */ f("p", {
|
|
52
|
-
className: "text-sm text-text-secondary mt-1",
|
|
53
|
-
children: g("movethewheels.ai.callout.description", "Open the assistant from its icon in the corner of the screen — it answers from your live orders, shipments, fleet and inventory data, and it is the only chat surface in this product.")
|
|
54
|
-
})] })]
|
|
55
|
-
})
|
|
56
|
-
}),
|
|
57
|
-
/* @__PURE__ */ p(o, { children: [/* @__PURE__ */ f(c, { children: /* @__PURE__ */ f(l, { children: g("movethewheels.ai.roadmap.title", "On the roadmap") }) }), /* @__PURE__ */ p(s, { children: [/* @__PURE__ */ f(u, {
|
|
58
|
-
illustration: "empty-agents",
|
|
59
|
-
title: g("movethewheels.ai.emptyState.title", "Autonomous dispatch operations aren't live yet"),
|
|
60
|
-
description: g("movethewheels.ai.emptyState.description", "Autonomous dispatch isn't available yet — these capabilities are still in development. Nothing below is available today.")
|
|
61
|
-
}), /* @__PURE__ */ f("ul", {
|
|
62
|
-
className: "mt-4 space-y-4",
|
|
63
|
-
children: _.map((e) => /* @__PURE__ */ p("li", {
|
|
64
|
-
className: "flex items-start gap-3",
|
|
65
|
-
children: [/* @__PURE__ */ f(e.icon, {
|
|
66
|
-
size: 18,
|
|
67
|
-
className: "text-text-secondary flex-shrink-0 mt-0.5"
|
|
68
|
-
}), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
|
|
69
|
-
className: "text-sm font-medium text-text-primary",
|
|
70
|
-
children: e.title
|
|
71
|
-
}), /* @__PURE__ */ f("p", {
|
|
72
|
-
className: "text-xs text-text-secondary",
|
|
73
|
-
children: e.description
|
|
74
|
-
})] })]
|
|
75
|
-
}, e.title))
|
|
76
|
-
})] })] })
|
|
77
|
-
]
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
export { g as default };
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AI Operations Page
|
|
3
|
-
*
|
|
4
|
-
* This page previously shipped a second, fabricated chat surface
|
|
5
|
-
* (`useAssistant` → `Query.assistantInsights`) whose "capabilities" list
|
|
6
|
-
* advertised route optimization, demand forecasting, fleet analysis, cost
|
|
7
|
-
* optimization and natural-language queries — none of which the backend
|
|
8
|
-
* implemented; every question routed to a fixed template built from four
|
|
9
|
-
* Prisma counts. See BOFF-3897.
|
|
10
|
-
*
|
|
11
|
-
* The real conversational assistant is the shared `AssistantWidget`, already
|
|
12
|
-
* mounted globally in the app shell (`AppShell.tsx`) on the sandbox
|
|
13
|
-
* transport — this page must never contain a second chat box.
|
|
14
|
-
*
|
|
15
|
-
* The full "AI Operations" surface this page is meant to become — a model
|
|
16
|
-
* picker, an agent-activity feed reading the shared AgentRun ledger,
|
|
17
|
-
* accept/reject decision cards for AI dispatch proposals, and per-workspace
|
|
18
|
-
* AI credit visibility — depends on the shared multi-model AI gateway
|
|
19
|
-
* (BOFF-3601), which has not landed yet. Until it does, this page shows an
|
|
20
|
-
* honest roadmap state instead of fabricating any of that content.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { Bot, MessageCircle, Activity, ShieldCheck, Wallet } from 'lucide-react';
|
|
24
|
-
import { PageLayout, EmptyState } from '../components/PageLayout';
|
|
25
|
-
import { Card, CardContent, CardHeader, CardTitle } from '../components/ui';
|
|
26
|
-
import { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';
|
|
27
|
-
import { useTr } from '../hooks';
|
|
28
|
-
|
|
29
|
-
export default function AIAssistantPage() {
|
|
30
|
-
const tr = useTr();
|
|
31
|
-
|
|
32
|
-
const roadmapItems = [
|
|
33
|
-
{
|
|
34
|
-
icon: Activity,
|
|
35
|
-
title: tr('movethewheels.ai.roadmap.agentActivity.title', 'Agent activity feed'),
|
|
36
|
-
description: tr(
|
|
37
|
-
'movethewheels.ai.roadmap.agentActivity.description',
|
|
38
|
-
'A live log of what the AI decided, on which shipments, with trigger, model, latency and cost — so an autonomous run is never a black box.'
|
|
39
|
-
),
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
icon: ShieldCheck,
|
|
43
|
-
title: tr('movethewheels.ai.roadmap.dispatchDecisionCards.title', 'Dispatch decision cards'),
|
|
44
|
-
description: tr(
|
|
45
|
-
'movethewheels.ai.roadmap.dispatchDecisionCards.description',
|
|
46
|
-
'Proposed driver/vehicle assignments and carrier recommendations with rationale and confidence, requiring an explicit accept or reject before anything is written.'
|
|
47
|
-
),
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
icon: Wallet,
|
|
51
|
-
title: tr('movethewheels.ai.roadmap.aiCreditVisibility.title', 'AI credit visibility'),
|
|
52
|
-
description: tr(
|
|
53
|
-
'movethewheels.ai.roadmap.aiCreditVisibility.description',
|
|
54
|
-
'Per-workspace AI spend for admins, so cost is visible before the invoice.'
|
|
55
|
-
),
|
|
56
|
-
},
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<PageLayout
|
|
61
|
-
title={tr('movethewheels.ai.title', 'AI Operations')}
|
|
62
|
-
subtitle={tr('movethewheels.ai.subtitle', 'What the AI is doing on your workspace, and why')}
|
|
63
|
-
icon={<Bot size={24} />}
|
|
64
|
-
>
|
|
65
|
-
<PagePurpose icon={<Bot size={18} />}>
|
|
66
|
-
{tr(
|
|
67
|
-
'movethewheels.ai.purpose',
|
|
68
|
-
'This page will surface AI-driven dispatch decisions and their outcomes once the shared AI runtime lands. It does not host a chat box — chat with your live operational data is always available from the assistant icon anywhere in the app.'
|
|
69
|
-
)}
|
|
70
|
-
</PagePurpose>
|
|
71
|
-
|
|
72
|
-
<GlassCard treatment="glass" className="p-4">
|
|
73
|
-
<div className="flex items-start gap-3">
|
|
74
|
-
<MessageCircle size={20} className="text-primary flex-shrink-0 mt-0.5" />
|
|
75
|
-
<div>
|
|
76
|
-
<p className="text-sm font-medium text-text-primary">
|
|
77
|
-
{tr(
|
|
78
|
-
'movethewheels.ai.callout.title',
|
|
79
|
-
'Looking to ask a question about your operations?'
|
|
80
|
-
)}
|
|
81
|
-
</p>
|
|
82
|
-
<p className="text-sm text-text-secondary mt-1">
|
|
83
|
-
{tr(
|
|
84
|
-
'movethewheels.ai.callout.description',
|
|
85
|
-
'Open the assistant from its icon in the corner of the screen — it answers from your live orders, shipments, fleet and inventory data, and it is the only chat surface in this product.'
|
|
86
|
-
)}
|
|
87
|
-
</p>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
</GlassCard>
|
|
91
|
-
|
|
92
|
-
<Card>
|
|
93
|
-
<CardHeader>
|
|
94
|
-
<CardTitle>{tr('movethewheels.ai.roadmap.title', 'On the roadmap')}</CardTitle>
|
|
95
|
-
</CardHeader>
|
|
96
|
-
<CardContent>
|
|
97
|
-
<EmptyState
|
|
98
|
-
illustration="empty-agents"
|
|
99
|
-
title={tr(
|
|
100
|
-
'movethewheels.ai.emptyState.title',
|
|
101
|
-
"Autonomous dispatch operations aren't live yet"
|
|
102
|
-
)}
|
|
103
|
-
description={tr(
|
|
104
|
-
'movethewheels.ai.emptyState.description',
|
|
105
|
-
"Autonomous dispatch isn't available yet — these capabilities are still in development. Nothing below is available today."
|
|
106
|
-
)}
|
|
107
|
-
/>
|
|
108
|
-
<ul className="mt-4 space-y-4">
|
|
109
|
-
{roadmapItems.map((item) => (
|
|
110
|
-
<li key={item.title} className="flex items-start gap-3">
|
|
111
|
-
<item.icon size={18} className="text-text-secondary flex-shrink-0 mt-0.5" />
|
|
112
|
-
<div>
|
|
113
|
-
<p className="text-sm font-medium text-text-primary">{item.title}</p>
|
|
114
|
-
<p className="text-xs text-text-secondary">{item.description}</p>
|
|
115
|
-
</div>
|
|
116
|
-
</li>
|
|
117
|
-
))}
|
|
118
|
-
</ul>
|
|
119
|
-
</CardContent>
|
|
120
|
-
</Card>
|
|
121
|
-
</PageLayout>
|
|
122
|
-
);
|
|
123
|
-
}
|