@burdenoff/microfe-movethewheels 2026.1031.3 → 2026.1031.4
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 +136 -127
- package/dist/MoveTheWheelsRoutes.js +140 -135
- package/dist/components/DocumentsCard.js +11 -11
- package/dist/components/ProofOfDeliveryCard.js +13 -13
- package/dist/components/ShipmentRiskDialog.js +24 -24
- package/dist/components/ShippingQuoteResults.js +46 -46
- package/dist/components/TrackingAlertList.js +17 -17
- package/dist/generated/tracking-quality-operations.d.ts +56 -0
- package/dist/hooks/useOrderDispatch.js +17 -17
- package/dist/movethewheels/pages/SettingsPage.d.ts +1 -0
- package/dist/movethewheels/providers/ModuleSettingsProvider.d.ts +17 -0
- package/dist/movethewheels/utils/formatters.d.ts +23 -3
- package/dist/movethewheels/utils/moduleSettings.d.ts +52 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/bell.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/key-round.js +14 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/plug.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/rotate-ccw.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/settings.js +13 -0
- package/dist/pages/AnalyticsPage.js +27 -27
- package/dist/pages/CreateOrderPage.js +340 -317
- package/dist/pages/CustomerDetailsPage.js +246 -246
- package/dist/pages/CustomersPage.js +19 -19
- package/dist/pages/DashboardPage.js +24 -24
- package/dist/pages/DeliveryCapturePage.js +74 -74
- package/dist/pages/DriverDetailsPage.js +337 -337
- package/dist/pages/DriversPage.js +26 -26
- package/dist/pages/FinancePage.js +26 -26
- package/dist/pages/InventoryPage.js +28 -28
- package/dist/pages/LiveTrackingPage.js +108 -108
- package/dist/pages/MarketplacePage.js +44 -44
- package/dist/pages/OrderDetailsPage.js +306 -306
- package/dist/pages/OrdersListPage.js +27 -27
- package/dist/pages/ProductDetailsPage.js +89 -89
- package/dist/pages/ProductsPage.js +73 -73
- package/dist/pages/RouteDetailsPage.js +282 -285
- package/dist/pages/RoutesPage.js +78 -78
- package/dist/pages/SettingsPage.js +459 -0
- package/dist/pages/TrackingPage.js +41 -41
- package/dist/pages/VehicleDetailsPage.js +207 -207
- package/dist/pages/VehiclesPage.js +17 -16
- package/dist/pages/WarehouseDetailsPage.js +132 -132
- package/dist/providers/ModuleSettingsProvider.js +74 -0
- package/dist/utils/formatters.js +53 -26
- package/dist/utils/moduleSettings.js +132 -0
- package/package.json +3 -2
- package/src/generated/tracking-quality-operations.ts +62 -0
- package/src/movethewheels/MoveTheWheelsRoot.tsx +14 -3
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +9 -0
- package/src/movethewheels/pages/CreateOrderPage.tsx +38 -6
- package/src/movethewheels/pages/ProductsPage.tsx +2 -2
- package/src/movethewheels/pages/RouteDetailsPage.tsx +3 -6
- package/src/movethewheels/pages/RoutesPage.tsx +2 -2
- package/src/movethewheels/pages/SettingsPage.tsx +516 -0
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +4 -2
- package/src/movethewheels/pages/VehiclesPage.tsx +2 -1
- package/src/movethewheels/providers/ModuleSettingsProvider.tsx +133 -0
- package/src/movethewheels/utils/formatters.ts +69 -10
- package/src/movethewheels/utils/moduleSettings.ts +224 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useMoveTheWheels as e } from "./MoveTheWheelsProvider.js";
|
|
2
|
+
import { executeGraphQL as t } from "../utils/graphqlClient.js";
|
|
3
|
+
import { setFormatPreferences as n } from "../utils/formatters.js";
|
|
4
|
+
import { MTW_MODULE_SETTINGS_QUERY as r, UPDATE_MTW_MODULE_SETTINGS_MUTATION as i, platformDefaults as a, toFormatPreferences as o } from "../utils/moduleSettings.js";
|
|
5
|
+
import { createContext as s, useCallback as c, useContext as l, useEffect as u, useMemo as d, useState as f } from "react";
|
|
6
|
+
import { jsx as p } from "react/jsx-runtime";
|
|
7
|
+
//#region src/movethewheels/providers/ModuleSettingsProvider.tsx
|
|
8
|
+
var m = s(null), h = ({ children: s }) => {
|
|
9
|
+
let { apiGatewayUrl: l, authToken: h, workspaceToken: g, workspaceId: _, tenantId: v, currentUser: y } = e(), b = d(() => ({
|
|
10
|
+
apiGatewayUrl: l,
|
|
11
|
+
authToken: h,
|
|
12
|
+
workspaceToken: g,
|
|
13
|
+
workspaceId: _,
|
|
14
|
+
tenantId: v,
|
|
15
|
+
actorId: y?.id
|
|
16
|
+
}), [
|
|
17
|
+
l,
|
|
18
|
+
h,
|
|
19
|
+
g,
|
|
20
|
+
_,
|
|
21
|
+
v,
|
|
22
|
+
y?.id
|
|
23
|
+
]), [x, S] = f(() => a(_ ?? "")), [C, w] = f(!1), [T, E] = f(null), [D, O] = f(0), k = c((e) => {
|
|
24
|
+
n(o(e)), S(e);
|
|
25
|
+
}, []);
|
|
26
|
+
u(() => {
|
|
27
|
+
if (!b.workspaceId) return;
|
|
28
|
+
let e = !1;
|
|
29
|
+
return t(b, r).then((t) => {
|
|
30
|
+
e || (k(t.mtwModuleSettings), E(null));
|
|
31
|
+
}).catch((t) => {
|
|
32
|
+
e || (k(a(b.workspaceId ?? "")), E(t instanceof Error ? t : /* @__PURE__ */ Error("Could not load settings")));
|
|
33
|
+
}).finally(() => {
|
|
34
|
+
e || w(!0);
|
|
35
|
+
}), () => {
|
|
36
|
+
e = !0;
|
|
37
|
+
};
|
|
38
|
+
}, [
|
|
39
|
+
b,
|
|
40
|
+
D,
|
|
41
|
+
k
|
|
42
|
+
]);
|
|
43
|
+
let A = c(async (e) => {
|
|
44
|
+
let n = await t(b, i, { input: e });
|
|
45
|
+
return k(n.updateMtwModuleSettings), E(null), n.updateMtwModuleSettings;
|
|
46
|
+
}, [b, k]), j = c(() => O((e) => e + 1), []), M = d(() => ({
|
|
47
|
+
settings: x,
|
|
48
|
+
isLoaded: C,
|
|
49
|
+
error: T,
|
|
50
|
+
save: A,
|
|
51
|
+
reload: j
|
|
52
|
+
}), [
|
|
53
|
+
x,
|
|
54
|
+
C,
|
|
55
|
+
T,
|
|
56
|
+
A,
|
|
57
|
+
j
|
|
58
|
+
]);
|
|
59
|
+
return /* @__PURE__ */ p(m.Provider, {
|
|
60
|
+
value: M,
|
|
61
|
+
children: s
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
function g() {
|
|
65
|
+
return l(m) || {
|
|
66
|
+
settings: a(),
|
|
67
|
+
isLoaded: !0,
|
|
68
|
+
error: null,
|
|
69
|
+
save: () => Promise.reject(/* @__PURE__ */ Error("Module settings are not available here")),
|
|
70
|
+
reload: () => void 0
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { h as ModuleSettingsProvider, g as useModuleSettings };
|
package/dist/utils/formatters.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var e = {
|
|
2
|
+
currency: "USD",
|
|
3
|
+
distanceUnit: "KM",
|
|
4
|
+
weightUnit: "KG",
|
|
5
|
+
timeZone: null
|
|
6
|
+
};
|
|
7
|
+
function t(t) {
|
|
8
|
+
e = { ...t };
|
|
9
|
+
}
|
|
10
|
+
function n() {
|
|
11
|
+
return e.timeZone ? { timeZone: e.timeZone } : {};
|
|
12
|
+
}
|
|
13
|
+
var r = 1.609344, i = .45359237;
|
|
14
|
+
function a(e) {
|
|
3
15
|
return [
|
|
4
16
|
e.street,
|
|
5
17
|
e.city,
|
|
@@ -8,35 +20,38 @@ function e(e) {
|
|
|
8
20
|
e.country
|
|
9
21
|
].filter(Boolean).join(", ");
|
|
10
22
|
}
|
|
11
|
-
function t
|
|
23
|
+
function o(t, n) {
|
|
12
24
|
return new Intl.NumberFormat("en-US", {
|
|
13
25
|
style: "currency",
|
|
14
|
-
currency:
|
|
26
|
+
currency: n || e.currency,
|
|
15
27
|
minimumFractionDigits: 2,
|
|
16
28
|
maximumFractionDigits: 2
|
|
17
|
-
}).format(
|
|
29
|
+
}).format(t);
|
|
18
30
|
}
|
|
19
|
-
function
|
|
20
|
-
let
|
|
21
|
-
return t === "relative" ?
|
|
31
|
+
function s(e, t = "short") {
|
|
32
|
+
let r = typeof e == "string" ? new Date(e) : e;
|
|
33
|
+
return t === "relative" ? l(r) : t === "time" ? new Intl.DateTimeFormat("en-US", {
|
|
22
34
|
hour: "numeric",
|
|
23
35
|
minute: "2-digit",
|
|
24
|
-
hour12: !0
|
|
25
|
-
|
|
36
|
+
hour12: !0,
|
|
37
|
+
...n()
|
|
38
|
+
}).format(r) : t === "full" ? new Intl.DateTimeFormat("en-US", {
|
|
26
39
|
weekday: "long",
|
|
27
40
|
year: "numeric",
|
|
28
41
|
month: "long",
|
|
29
42
|
day: "numeric",
|
|
30
43
|
hour: "numeric",
|
|
31
44
|
minute: "2-digit",
|
|
32
|
-
hour12: !0
|
|
33
|
-
|
|
45
|
+
hour12: !0,
|
|
46
|
+
...n()
|
|
47
|
+
}).format(r) : new Intl.DateTimeFormat("en-US", {
|
|
34
48
|
year: "numeric",
|
|
35
49
|
month: "short",
|
|
36
|
-
day: "numeric"
|
|
37
|
-
|
|
50
|
+
day: "numeric",
|
|
51
|
+
...n()
|
|
52
|
+
}).format(r);
|
|
38
53
|
}
|
|
39
|
-
function
|
|
54
|
+
function c(e) {
|
|
40
55
|
let t = typeof e == "string" ? new Date(e) : e;
|
|
41
56
|
return new Intl.DateTimeFormat("en-US", {
|
|
42
57
|
year: "numeric",
|
|
@@ -44,21 +59,33 @@ function r(e) {
|
|
|
44
59
|
day: "numeric",
|
|
45
60
|
hour: "numeric",
|
|
46
61
|
minute: "2-digit",
|
|
47
|
-
hour12: !0
|
|
62
|
+
hour12: !0,
|
|
63
|
+
...n()
|
|
48
64
|
}).format(t);
|
|
49
65
|
}
|
|
50
|
-
function
|
|
51
|
-
let t = typeof e == "string" ? new Date(e) : e,
|
|
52
|
-
if (
|
|
66
|
+
function l(e) {
|
|
67
|
+
let t = typeof e == "string" ? new Date(e) : e, n = Math.floor(((/* @__PURE__ */ new Date()).getTime() - t.getTime()) / 1e3);
|
|
68
|
+
if (n < 60) return "Just now";
|
|
69
|
+
let r = Math.floor(n / 60);
|
|
70
|
+
if (r < 60) return `${r} ${r === 1 ? "minute" : "minutes"} ago`;
|
|
53
71
|
let i = Math.floor(r / 60);
|
|
54
|
-
if (i <
|
|
55
|
-
let a = Math.floor(i /
|
|
56
|
-
|
|
57
|
-
let o = Math.floor(a / 24);
|
|
58
|
-
return o < 7 ? `${o} ${o === 1 ? "day" : "days"} ago` : n(t);
|
|
72
|
+
if (i < 24) return `${i} ${i === 1 ? "hour" : "hours"} ago`;
|
|
73
|
+
let a = Math.floor(i / 24);
|
|
74
|
+
return a < 7 ? `${a} ${a === 1 ? "day" : "days"} ago` : s(t);
|
|
59
75
|
}
|
|
60
|
-
|
|
76
|
+
var u = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 }), d = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
|
|
77
|
+
function f(t) {
|
|
78
|
+
return e.weightUnit === "LB" ? `${u.format(t / i)} lb` : Math.abs(t) >= 1e3 ? `${u.format(t / 1e3)} tonnes` : `${u.format(t)} kg`;
|
|
79
|
+
}
|
|
80
|
+
function p(t) {
|
|
81
|
+
if (e.distanceUnit === "MI") {
|
|
82
|
+
let e = t / r;
|
|
83
|
+
return Math.abs(e) < .1 ? `${Math.round(e * 5280)} ft` : `${d.format(e)} mi`;
|
|
84
|
+
}
|
|
85
|
+
return Math.abs(t) < 1 ? `${Math.round(t * 1e3)} m` : `${d.format(t)} km`;
|
|
86
|
+
}
|
|
87
|
+
function m(e) {
|
|
61
88
|
return e.split(" ").map((e) => e[0]).join("").toUpperCase().slice(0, 2);
|
|
62
89
|
}
|
|
63
90
|
//#endregion
|
|
64
|
-
export {
|
|
91
|
+
export { a as formatAddress, o as formatCurrency, s as formatDate, c as formatDateTime, p as formatDistance, f as formatWeight, m as getInitials, t as setFormatPreferences };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
function e(e = "") {
|
|
2
|
+
return {
|
|
3
|
+
workspaceId: e,
|
|
4
|
+
defaultCurrency: "USD",
|
|
5
|
+
distanceUnit: "KM",
|
|
6
|
+
weightUnit: "KG",
|
|
7
|
+
timezone: null,
|
|
8
|
+
defaultOrderPriority: "MEDIUM",
|
|
9
|
+
defaultDeliveryWindowHours: 24,
|
|
10
|
+
isCustomized: !1,
|
|
11
|
+
updatedAt: null,
|
|
12
|
+
updatedBy: null
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var t = "\n workspaceId\n defaultCurrency\n distanceUnit\n weightUnit\n timezone\n defaultOrderPriority\n defaultDeliveryWindowHours\n isCustomized\n updatedAt\n updatedBy\n", n = `
|
|
16
|
+
query MtwModuleSettings {
|
|
17
|
+
mtwModuleSettings {
|
|
18
|
+
${t}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`, r = `
|
|
22
|
+
mutation UpdateMtwModuleSettings($input: UpdateMtwModuleSettingsInput!) {
|
|
23
|
+
updateMtwModuleSettings(input: $input) {
|
|
24
|
+
${t}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
function i(e) {
|
|
29
|
+
return {
|
|
30
|
+
currency: e.defaultCurrency,
|
|
31
|
+
distanceUnit: e.distanceUnit,
|
|
32
|
+
weightUnit: e.weightUnit,
|
|
33
|
+
timeZone: e.timezone
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
var a = [{
|
|
37
|
+
value: "KM",
|
|
38
|
+
label: "Kilometres (km)"
|
|
39
|
+
}, {
|
|
40
|
+
value: "MI",
|
|
41
|
+
label: "Miles (mi)"
|
|
42
|
+
}], o = [{
|
|
43
|
+
value: "KG",
|
|
44
|
+
label: "Kilograms (kg)"
|
|
45
|
+
}, {
|
|
46
|
+
value: "LB",
|
|
47
|
+
label: "Pounds (lb)"
|
|
48
|
+
}], s = [
|
|
49
|
+
{
|
|
50
|
+
value: "LOW",
|
|
51
|
+
label: "Low"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: "MEDIUM",
|
|
55
|
+
label: "Normal"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: "HIGH",
|
|
59
|
+
label: "High"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: "URGENT",
|
|
63
|
+
label: "Urgent"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: "CRITICAL",
|
|
67
|
+
label: "Critical"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
function c(e) {
|
|
71
|
+
switch (e) {
|
|
72
|
+
case "LOW": return "low";
|
|
73
|
+
case "HIGH": return "high";
|
|
74
|
+
case "URGENT":
|
|
75
|
+
case "CRITICAL": return "urgent";
|
|
76
|
+
default: return "normal";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
var l = [
|
|
80
|
+
"USD",
|
|
81
|
+
"EUR",
|
|
82
|
+
"GBP",
|
|
83
|
+
"INR",
|
|
84
|
+
"AED",
|
|
85
|
+
"SGD",
|
|
86
|
+
"AUD",
|
|
87
|
+
"CAD",
|
|
88
|
+
"JPY",
|
|
89
|
+
"CNY"
|
|
90
|
+
];
|
|
91
|
+
function u(e) {
|
|
92
|
+
return typeof Intl.supportedValuesOf == "function" ? Intl.supportedValuesOf(e) : [];
|
|
93
|
+
}
|
|
94
|
+
function d(e) {
|
|
95
|
+
let t = new Set([...l, ...u("currency")]);
|
|
96
|
+
e && t.add(e);
|
|
97
|
+
let n = [...t].filter((e) => !l.includes(e)).sort();
|
|
98
|
+
return [...l, ...n];
|
|
99
|
+
}
|
|
100
|
+
function f(e) {
|
|
101
|
+
try {
|
|
102
|
+
let t = new Intl.DisplayNames(["en"], { type: "currency" }).of(e);
|
|
103
|
+
return t && t !== e ? `${e} — ${t}` : e;
|
|
104
|
+
} catch {
|
|
105
|
+
return e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function p(e) {
|
|
109
|
+
let t = new Set(["UTC", ...u("timeZone")]);
|
|
110
|
+
return e && t.add(e), [...t].sort((e, t) => e === "UTC" ? -1 : t === "UTC" ? 1 : e.localeCompare(t));
|
|
111
|
+
}
|
|
112
|
+
function m() {
|
|
113
|
+
try {
|
|
114
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
115
|
+
} catch {
|
|
116
|
+
return "UTC";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function h(e) {
|
|
120
|
+
let t = Number(e);
|
|
121
|
+
return !e.trim() || !Number.isInteger(t) || t < 1 || t > 720 ? "Enter a whole number of hours between 1 and 720." : null;
|
|
122
|
+
}
|
|
123
|
+
function g(e, t) {
|
|
124
|
+
let n = {};
|
|
125
|
+
return t.defaultCurrency !== void 0 && t.defaultCurrency !== e.defaultCurrency && (n.defaultCurrency = t.defaultCurrency), t.distanceUnit !== void 0 && t.distanceUnit !== e.distanceUnit && (n.distanceUnit = t.distanceUnit), t.weightUnit !== void 0 && t.weightUnit !== e.weightUnit && (n.weightUnit = t.weightUnit), t.timezone !== void 0 && t.timezone !== e.timezone && (n.timezone = t.timezone), t.defaultOrderPriority !== void 0 && t.defaultOrderPriority !== e.defaultOrderPriority && (n.defaultOrderPriority = t.defaultOrderPriority), t.defaultDeliveryWindowHours !== void 0 && t.defaultDeliveryWindowHours !== e.defaultDeliveryWindowHours && (n.defaultDeliveryWindowHours = t.defaultDeliveryWindowHours), n;
|
|
126
|
+
}
|
|
127
|
+
function _(e, t = /* @__PURE__ */ new Date()) {
|
|
128
|
+
let n = new Date(t.getTime() + e * 3600 * 1e3), r = (e) => String(e).padStart(2, "0");
|
|
129
|
+
return `${n.getFullYear()}-${r(n.getMonth() + 1)}-${r(n.getDate())}T${r(n.getHours())}:${r(n.getMinutes())}`;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { a as DISTANCE_UNIT_OPTIONS, n as MTW_MODULE_SETTINGS_QUERY, s as ORDER_PRIORITY_OPTIONS, r as UPDATE_MTW_MODULE_SETTINGS_MUTATION, o as WEIGHT_UNIT_OPTIONS, m as browserTimeZone, g as changedSettings, f as currencyLabel, d as currencyOptions, h as deliveryWindowError, _ as deliveryWindowValue, c as orderFormPriority, e as platformDefaults, p as timeZoneOptions, i as toFormatPreferences };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-movethewheels",
|
|
3
|
-
"version": "2026.1031.
|
|
3
|
+
"version": "2026.1031.4",
|
|
4
4
|
"description": "Burdenoff MoveTheWheels Microfrontend - Logistics & Supply Chain Management Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
38
38
|
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
39
39
|
"validate:schema-drift": "graphql-schema-drift",
|
|
40
|
-
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:entity-import && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
40
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:entity-import && bun run verify:module-settings && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
41
41
|
"storybook": "storybook dev -p 6006",
|
|
42
42
|
"build-storybook": "storybook build",
|
|
43
43
|
"test:storybook": "vitest run --project=storybook",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"verify:core-codegen": "bun test scripts/codegen.test.ts && node --test scripts/check-package-types.test.mjs",
|
|
75
75
|
"verify:entity-export": "bun test scripts/check-entity-export.test.ts",
|
|
76
76
|
"verify:entity-import": "bun test scripts/check-entity-import.test.ts",
|
|
77
|
+
"verify:module-settings": "bun test scripts/check-module-settings.test.ts",
|
|
77
78
|
"verify:pallet-preview": "bun test scripts/check-pallet-preview.test.ts && bun scripts/verify-pallet-preview-hook.mjs",
|
|
78
79
|
"verify:consumed-fuel-preview": "bun test scripts/check-consumed-fuel-preview.test.ts && bun scripts/verify-consumed-fuel-preview-hook.mjs && bun scripts/verify-consumed-fuel-preview-component.mjs"
|
|
79
80
|
},
|
|
@@ -1259,6 +1259,13 @@ export type MtwDemandForecastVariance = {
|
|
|
1259
1259
|
volumeVariance: Scalars['Int']['output'];
|
|
1260
1260
|
};
|
|
1261
1261
|
|
|
1262
|
+
/** Unit MoveTheWheels shows distances in. */
|
|
1263
|
+
export type MtwDistanceUnit =
|
|
1264
|
+
/** Kilometres */
|
|
1265
|
+
| 'KM'
|
|
1266
|
+
/** Miles */
|
|
1267
|
+
| 'MI';
|
|
1268
|
+
|
|
1262
1269
|
export type MtwDriver = {
|
|
1263
1270
|
__typename?: 'MtwDriver';
|
|
1264
1271
|
baseSalary?: Maybe<Scalars['Float']['output']>;
|
|
@@ -2700,6 +2707,31 @@ export type MtwMarketplaceStats = {
|
|
|
2700
2707
|
verifiedProviders: Scalars['Int']['output'];
|
|
2701
2708
|
};
|
|
2702
2709
|
|
|
2710
|
+
/**
|
|
2711
|
+
* Workspace operational defaults for MoveTheWheels (BOFF-10488): how amounts,
|
|
2712
|
+
* distances, weights and times are shown, and what new orders start from.
|
|
2713
|
+
* Company profile, notifications, two-factor authentication and integrations
|
|
2714
|
+
* are platform settings and are not part of this type.
|
|
2715
|
+
*/
|
|
2716
|
+
export type MtwModuleSettings = {
|
|
2717
|
+
__typename?: 'MtwModuleSettings';
|
|
2718
|
+
/** ISO 4217 code amounts without their own currency are shown in. */
|
|
2719
|
+
defaultCurrency: Scalars['String']['output'];
|
|
2720
|
+
/** Hours from now a new order's suggested delivery time falls (1 to 720). */
|
|
2721
|
+
defaultDeliveryWindowHours: Scalars['Int']['output'];
|
|
2722
|
+
/** Priority a new order starts with. */
|
|
2723
|
+
defaultOrderPriority: DeliveryPriority;
|
|
2724
|
+
distanceUnit: MtwDistanceUnit;
|
|
2725
|
+
/** False until the workspace saves its settings; the values are then the platform defaults. */
|
|
2726
|
+
isCustomized: Scalars['Boolean']['output'];
|
|
2727
|
+
/** IANA time zone dates and times are shown in. Null shows each viewer their own local time. */
|
|
2728
|
+
timezone?: Maybe<Scalars['String']['output']>;
|
|
2729
|
+
updatedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
2730
|
+
updatedBy?: Maybe<Scalars['ID']['output']>;
|
|
2731
|
+
weightUnit: MtwWeightUnit;
|
|
2732
|
+
workspaceId: Scalars['ID']['output'];
|
|
2733
|
+
};
|
|
2734
|
+
|
|
2703
2735
|
export type MtwMoveReviewSource = {
|
|
2704
2736
|
__typename?: 'MtwMoveReviewSource';
|
|
2705
2737
|
reference: Scalars['String']['output'];
|
|
@@ -4552,6 +4584,13 @@ export type MtwWarehouseStats = {
|
|
|
4552
4584
|
total: Scalars['Int']['output'];
|
|
4553
4585
|
};
|
|
4554
4586
|
|
|
4587
|
+
/** Unit MoveTheWheels shows weights in. */
|
|
4588
|
+
export type MtwWeightUnit =
|
|
4589
|
+
/** Kilograms */
|
|
4590
|
+
| 'KG'
|
|
4591
|
+
/** Pounds */
|
|
4592
|
+
| 'LB';
|
|
4593
|
+
|
|
4555
4594
|
export type Mutation = {
|
|
4556
4595
|
__typename?: 'Mutation';
|
|
4557
4596
|
_empty?: Maybe<Scalars['String']['output']>;
|
|
@@ -4658,6 +4697,8 @@ export type Mutation = {
|
|
|
4658
4697
|
updateDriverStatus: MtwDriver;
|
|
4659
4698
|
updateIntegration: MtwIntegration;
|
|
4660
4699
|
updateInventoryItem: MtwInventoryItem;
|
|
4700
|
+
/** Save the workspace's MoveTheWheels operational defaults. Every field is validated. */
|
|
4701
|
+
updateMtwModuleSettings: MtwModuleSettings;
|
|
4661
4702
|
updateRoute: MtwRoute;
|
|
4662
4703
|
updateServiceOffering: MtwServiceOffering;
|
|
4663
4704
|
updateServiceProvider: MtwServiceProvider;
|
|
@@ -5141,6 +5182,11 @@ export type MutationUpdateInventoryItemArgs = {
|
|
|
5141
5182
|
};
|
|
5142
5183
|
|
|
5143
5184
|
|
|
5185
|
+
export type MutationUpdateMtwModuleSettingsArgs = {
|
|
5186
|
+
input: UpdateMtwModuleSettingsInput;
|
|
5187
|
+
};
|
|
5188
|
+
|
|
5189
|
+
|
|
5144
5190
|
export type MutationUpdateRouteArgs = {
|
|
5145
5191
|
id: Scalars['ID']['input'];
|
|
5146
5192
|
input: UpdateRouteInput;
|
|
@@ -5375,6 +5421,8 @@ export type Query = {
|
|
|
5375
5421
|
* entity create permission.
|
|
5376
5422
|
*/
|
|
5377
5423
|
mtwImportSpec: Array<MtwImportEntitySpec>;
|
|
5424
|
+
/** The workspace's MoveTheWheels operational defaults; platform defaults when none were saved. */
|
|
5425
|
+
mtwModuleSettings: MtwModuleSettings;
|
|
5378
5426
|
mtwPalletGeometryPreview: MtwPalletGeometryPreview;
|
|
5379
5427
|
mtwPickPreparation: MtwPickPreparation;
|
|
5380
5428
|
mtwPickReview: MtwPickReview;
|
|
@@ -6647,6 +6695,20 @@ export type UpdateInventoryItemInput = {
|
|
|
6647
6695
|
unitCost?: InputMaybe<Scalars['Float']['input']>;
|
|
6648
6696
|
};
|
|
6649
6697
|
|
|
6698
|
+
/**
|
|
6699
|
+
* Changes to the workspace's MoveTheWheels defaults. Omitted fields keep their
|
|
6700
|
+
* current value. `timezone: null` (or an empty string) clears the time zone so
|
|
6701
|
+
* each viewer sees their own local time.
|
|
6702
|
+
*/
|
|
6703
|
+
export type UpdateMtwModuleSettingsInput = {
|
|
6704
|
+
defaultCurrency?: InputMaybe<Scalars['String']['input']>;
|
|
6705
|
+
defaultDeliveryWindowHours?: InputMaybe<Scalars['Int']['input']>;
|
|
6706
|
+
defaultOrderPriority?: InputMaybe<DeliveryPriority>;
|
|
6707
|
+
distanceUnit?: InputMaybe<MtwDistanceUnit>;
|
|
6708
|
+
timezone?: InputMaybe<Scalars['String']['input']>;
|
|
6709
|
+
weightUnit?: InputMaybe<MtwWeightUnit>;
|
|
6710
|
+
};
|
|
6711
|
+
|
|
6650
6712
|
export type UpdateRouteInput = {
|
|
6651
6713
|
actualDistance?: InputMaybe<Scalars['Float']['input']>;
|
|
6652
6714
|
actualDuration?: InputMaybe<Scalars['Float']['input']>;
|
|
@@ -24,8 +24,10 @@ import {
|
|
|
24
24
|
Bot,
|
|
25
25
|
Store,
|
|
26
26
|
ArrowDownUp,
|
|
27
|
+
Settings,
|
|
27
28
|
} from 'lucide-react';
|
|
28
29
|
import { MoveTheWheelsProvider } from './providers/MoveTheWheelsProvider';
|
|
30
|
+
import { ModuleSettingsProvider } from './providers/ModuleSettingsProvider';
|
|
29
31
|
import { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
30
32
|
import type { NavItem, MoveTheWheelsRootProps } from './types';
|
|
31
33
|
import { MoveTheWheelsRoutes } from './MoveTheWheelsRoutes';
|
|
@@ -305,6 +307,13 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
|
|
|
305
307
|
icon: <Bot size={16} />,
|
|
306
308
|
order: 13,
|
|
307
309
|
},
|
|
310
|
+
{
|
|
311
|
+
id: 'mtw-settings',
|
|
312
|
+
label: tr('movethewheels.root.nav.settings', 'Settings'),
|
|
313
|
+
path: joinPath(basePath, 'settings'),
|
|
314
|
+
icon: <Settings size={16} />,
|
|
315
|
+
order: 99,
|
|
316
|
+
},
|
|
308
317
|
],
|
|
309
318
|
};
|
|
310
319
|
|
|
@@ -365,9 +374,11 @@ export const MoveTheWheelsRoot: FC<MoveTheWheelsRootProps> = (props) => {
|
|
|
365
374
|
<FeatureFlagProvider workspaceId={null} gateway="global" defaultEnabled={true}>
|
|
366
375
|
<NavRegistrar registerNavItems={registerNavItems} basePath={basePath} />
|
|
367
376
|
<MoveTheWheelsProvider {...props}>
|
|
368
|
-
<
|
|
369
|
-
<
|
|
370
|
-
|
|
377
|
+
<ModuleSettingsProvider>
|
|
378
|
+
<div className="movethewheels-root h-full">
|
|
379
|
+
<MoveTheWheelsRoutes />
|
|
380
|
+
</div>
|
|
381
|
+
</ModuleSettingsProvider>
|
|
371
382
|
</MoveTheWheelsProvider>
|
|
372
383
|
</FeatureFlagProvider>
|
|
373
384
|
);
|
|
@@ -9,6 +9,7 @@ import { Routes, Route, 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';
|
|
12
|
+
import { useModuleSettings } from './providers/ModuleSettingsProvider';
|
|
12
13
|
import { useTr } from './hooks';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -73,6 +74,7 @@ const CustomersPage = lazy(() => import('./pages/CustomersPage'));
|
|
|
73
74
|
const CustomerDetailsPage = lazy(() => import('./pages/CustomerDetailsPage'));
|
|
74
75
|
const MarketplacePage = lazy(() => import('./pages/MarketplacePage'));
|
|
75
76
|
const ImportExportPage = lazy(() => import('./pages/ImportExportPage'));
|
|
77
|
+
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
|
|
76
78
|
const RoutesPage = lazy(() => import('./pages/RoutesPage'));
|
|
77
79
|
const RouteDetailsPage = lazy(() => import('./pages/RouteDetailsPage'));
|
|
78
80
|
const AnalyticsPage = lazy(() => import('./pages/AnalyticsPage'));
|
|
@@ -96,6 +98,10 @@ const ConsumedFuelPreviewPage = lazy(() => import('./pages/ConsumedFuelPreviewPa
|
|
|
96
98
|
const EmptyReusePage = lazy(() => import('./pages/EmptyReusePage'));
|
|
97
99
|
|
|
98
100
|
export function MoveTheWheelsRoutes() {
|
|
101
|
+
// Subscribing here re-renders every page when the workspace's display
|
|
102
|
+
// defaults load or change, so amounts, units and dates follow them
|
|
103
|
+
// (BOFF-10488). The value itself is read through the shared formatters.
|
|
104
|
+
useModuleSettings();
|
|
99
105
|
return (
|
|
100
106
|
<Suspense fallback={<PageLoader />}>
|
|
101
107
|
<Routes>
|
|
@@ -164,6 +170,9 @@ export function MoveTheWheelsRoutes() {
|
|
|
164
170
|
{/* Bulk CSV/JSON import and dataset export (BOFF-3990) */}
|
|
165
171
|
<Route path="import-export" element={<ImportExportPage />} />
|
|
166
172
|
|
|
173
|
+
{/* Workspace operational defaults: currency, units, time zone (BOFF-10488) */}
|
|
174
|
+
<Route path="settings" element={<SettingsPage />} />
|
|
175
|
+
|
|
167
176
|
{/* Routes */}
|
|
168
177
|
<Route path="routes" element={<RoutesPage />} />
|
|
169
178
|
<Route path="routes/trip-utilization" element={<TripUtilizationPage />} />
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Form for creating or editing orders.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { useEffect, useState, type ChangeEvent } from 'react';
|
|
7
|
+
import { useEffect, useRef, useState, type ChangeEvent } from 'react';
|
|
8
8
|
import { useParams, useSearchParams } from 'react-router';
|
|
9
9
|
import {
|
|
10
10
|
Package,
|
|
@@ -43,6 +43,8 @@ import { useCustomer, useCustomers } from '../hooks/useCustomers';
|
|
|
43
43
|
import { useRoute, useRoutes } from '../hooks/useRoutes';
|
|
44
44
|
import { useProducts } from '../hooks/useInventory';
|
|
45
45
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
46
|
+
import { useModuleSettings } from '../providers/ModuleSettingsProvider';
|
|
47
|
+
import { deliveryWindowValue, orderFormPriority } from '../utils/moduleSettings';
|
|
46
48
|
import { joinPath, buildCustomerCreatePath } from '../utils/navigation';
|
|
47
49
|
import { CustomerPicker } from '../components/CustomerPicker';
|
|
48
50
|
import { EntityCombobox } from '../components/EntityCombobox';
|
|
@@ -118,11 +120,16 @@ export default function CreateOrderPage() {
|
|
|
118
120
|
});
|
|
119
121
|
|
|
120
122
|
const isEditing = !!orderId && !!order;
|
|
123
|
+
// Workspace defaults for new orders (BOFF-10488).
|
|
124
|
+
const { settings: moduleSettings } = useModuleSettings();
|
|
125
|
+
const defaultPriority = orderFormPriority(moduleSettings.defaultOrderPriority);
|
|
126
|
+
const deliveryWindowHours = moduleSettings.defaultDeliveryWindowHours;
|
|
127
|
+
const priorityTouched = useRef(false);
|
|
121
128
|
|
|
122
129
|
const [selectedCustomer, setSelectedCustomer] = useState<Customer | null>(null);
|
|
123
130
|
const [formData, setFormData] = useState({
|
|
124
131
|
customerId: prefilledCustomerId || order?.customerId || '',
|
|
125
|
-
priority: order?.priority ||
|
|
132
|
+
priority: order?.priority || defaultPriority,
|
|
126
133
|
routeId: order?.routeId || '',
|
|
127
134
|
pickupAddress: {
|
|
128
135
|
street: order?.pickupAddress.street || '',
|
|
@@ -308,9 +315,19 @@ export default function CreateOrderPage() {
|
|
|
308
315
|
};
|
|
309
316
|
|
|
310
317
|
const updateField = (field: string, value: unknown) => {
|
|
318
|
+
if (field === 'priority') priorityTouched.current = true;
|
|
311
319
|
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
312
320
|
};
|
|
313
321
|
|
|
322
|
+
// The workspace defaults usually arrive after the first render; a new order
|
|
323
|
+
// picks up the default priority unless the user already chose one.
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (orderId || priorityTouched.current) return;
|
|
326
|
+
setFormData((prev) =>
|
|
327
|
+
prev.priority === defaultPriority ? prev : { ...prev, priority: defaultPriority }
|
|
328
|
+
);
|
|
329
|
+
}, [orderId, defaultPriority]);
|
|
330
|
+
|
|
314
331
|
const updateAddress = (
|
|
315
332
|
type: 'pickupAddress' | 'deliveryAddress',
|
|
316
333
|
field: string,
|
|
@@ -551,7 +568,9 @@ export default function CreateOrderPage() {
|
|
|
551
568
|
<SelectItem value="urgent">Urgent</SelectItem>
|
|
552
569
|
</SelectContent>
|
|
553
570
|
</Select>
|
|
554
|
-
<p className="text-xs text-text-secondary">
|
|
571
|
+
<p className="text-xs text-text-secondary">
|
|
572
|
+
New orders start with this workspace's default priority.
|
|
573
|
+
</p>
|
|
555
574
|
</div>
|
|
556
575
|
</div>
|
|
557
576
|
</EmphasisPanel>
|
|
@@ -879,9 +898,22 @@ export default function CreateOrderPage() {
|
|
|
879
898
|
updateField('scheduledDelivery', e.target.value)
|
|
880
899
|
}
|
|
881
900
|
/>
|
|
882
|
-
<
|
|
883
|
-
|
|
884
|
-
|
|
901
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
902
|
+
<p className="text-xs text-text-secondary">
|
|
903
|
+
Leave blank to dispatch as soon as a driver is available.
|
|
904
|
+
</p>
|
|
905
|
+
<Button
|
|
906
|
+
type="button"
|
|
907
|
+
variant="link"
|
|
908
|
+
size="sm"
|
|
909
|
+
className="h-auto p-0 text-xs"
|
|
910
|
+
onClick={() =>
|
|
911
|
+
updateField('scheduledDelivery', deliveryWindowValue(deliveryWindowHours))
|
|
912
|
+
}
|
|
913
|
+
>
|
|
914
|
+
Use the default window ({deliveryWindowHours} h from now)
|
|
915
|
+
</Button>
|
|
916
|
+
</div>
|
|
885
917
|
</div>
|
|
886
918
|
<div className="space-y-2 lg:col-span-1">
|
|
887
919
|
<Label htmlFor="specialInstructions">Special instructions</Label>
|
|
@@ -20,7 +20,7 @@ import { CTAOverflowMenu, PagePurpose } from '@burdenoff/fe-libs/ui';
|
|
|
20
20
|
import { useProducts, useProductStats } from '../hooks/useInventory';
|
|
21
21
|
import { useDebouncedValue } from '../hooks/useDebouncedValue';
|
|
22
22
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
23
|
-
import { formatCurrency } from '../utils/formatters';
|
|
23
|
+
import { formatCurrency, formatWeight } from '../utils/formatters';
|
|
24
24
|
import { joinPath } from '../utils/navigation';
|
|
25
25
|
import { useEntityExport } from '../hooks/useEntityExport';
|
|
26
26
|
import { ExportStatusBanner } from '../components/ExportStatusBanner';
|
|
@@ -90,7 +90,7 @@ export default function ProductsPage() {
|
|
|
90
90
|
header: 'Weight',
|
|
91
91
|
accessorKey: 'weight',
|
|
92
92
|
sortable: true,
|
|
93
|
-
cell: (row) => (row.weight !== undefined ?
|
|
93
|
+
cell: (row) => (row.weight !== undefined ? formatWeight(row.weight) : 'Not provided'),
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
id: 'value',
|