@burdenoff/microfe-movethewheels 2026.1031.3 → 2026.1031.5
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 +143 -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 +18 -5
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +19 -4
- 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
- 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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { VehicleHoldRefusal as e } from "../utils/orderVehicleHold.js";
|
|
2
|
+
import { useTr as t } from "../shared/hooks/useTr.js";
|
|
3
3
|
import { useEffect as n, useRef as r, useState as i } from "react";
|
|
4
4
|
//#region src/movethewheels/hooks/useOrderDispatch.ts
|
|
5
5
|
function a(a) {
|
|
6
|
-
let o =
|
|
6
|
+
let o = t(), { order: s, contextKey: c, updateOrder: l, updateOrderStatus: u, refresh: d } = a, f = `movethewheels.order-dispatch.unconfirmed.v1:${c}`, [p, m] = i(() => {
|
|
7
7
|
try {
|
|
8
8
|
return sessionStorage.getItem(f) !== null;
|
|
9
9
|
} catch {
|
|
@@ -28,56 +28,56 @@ function a(a) {
|
|
|
28
28
|
x.current = !1, S.current && g(!1);
|
|
29
29
|
};
|
|
30
30
|
return {
|
|
31
|
-
assign: async (
|
|
32
|
-
if (!
|
|
31
|
+
assign: async (t, n) => {
|
|
32
|
+
if (!t || !n || !s || s.vehicleId === t && s.driverId === n || !E(a.assignmentReady)) return;
|
|
33
33
|
let r = !1;
|
|
34
34
|
try {
|
|
35
35
|
if (await l(s.id, {
|
|
36
|
-
vehicleId:
|
|
36
|
+
vehicleId: t,
|
|
37
37
|
driverId: n
|
|
38
38
|
}, "SINGLE_ATTEMPT"), r = !0, S.current && b({
|
|
39
39
|
orderId: s.id,
|
|
40
|
-
vehicleId:
|
|
40
|
+
vehicleId: t,
|
|
41
41
|
driverId: n
|
|
42
42
|
}), T(), !S.current || (!(s.vehicleId && s.driverId) && s.status === "confirmed" && (w(), await u(s.id, "assigned"), T()), !S.current)) return;
|
|
43
43
|
v(o("movethewheels.order.assignmentSaved", "Assignment saved.")), d();
|
|
44
|
-
} catch (
|
|
45
|
-
if (
|
|
44
|
+
} catch (t) {
|
|
45
|
+
if (t instanceof e && t.operation === (r ? "updateDeliveryJobStatus" : "updateDeliveryJob")) {
|
|
46
46
|
try {
|
|
47
47
|
T();
|
|
48
48
|
} catch {
|
|
49
49
|
S.current && m(!0);
|
|
50
50
|
}
|
|
51
51
|
if (!S.current) return;
|
|
52
|
-
v(o(
|
|
52
|
+
v(o(t.kind === "driver" ? r ? "movethewheels.order.driverMovementBlocked" : "movethewheels.order.driverAssignmentBlocked" : r ? "movethewheels.order.movementBlocked" : "movethewheels.order.assignmentBlocked", t.kind === "driver" ? r ? "Assignment saved. Driver eligibility blocked movement." : "Assignment blocked by driver eligibility. Choose another driver." : r ? "Assignment saved. Movement blocked." : "Assignment blocked by the recorded vehicle status. Choose another vehicle.")), d();
|
|
53
53
|
} else S.current && (m(!0), v(C(r)));
|
|
54
54
|
} finally {
|
|
55
55
|
D();
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
changeStatus: async (
|
|
58
|
+
changeStatus: async (t) => {
|
|
59
59
|
if (!(!s || [
|
|
60
60
|
"delivered",
|
|
61
61
|
"returned",
|
|
62
62
|
"cancelled",
|
|
63
63
|
"failed"
|
|
64
|
-
].includes(s.status)) && !(
|
|
64
|
+
].includes(s.status)) && !(t === "assigned" && (!s.vehicleId || !s.driverId)) && !(!E(![
|
|
65
65
|
"assigned",
|
|
66
66
|
"picked_up",
|
|
67
67
|
"in_transit",
|
|
68
68
|
"out_for_delivery"
|
|
69
|
-
].includes(
|
|
70
|
-
if (await u(s.id,
|
|
69
|
+
].includes(t) || a.movementReady) || !s)) try {
|
|
70
|
+
if (await u(s.id, t), T(), !S.current) return;
|
|
71
71
|
v(o("movethewheels.order.statusSaved", "Order status updated.")), d();
|
|
72
|
-
} catch (
|
|
73
|
-
if (
|
|
72
|
+
} catch (t) {
|
|
73
|
+
if (t instanceof e && t.operation === "updateDeliveryJobStatus") {
|
|
74
74
|
try {
|
|
75
75
|
T();
|
|
76
76
|
} catch {
|
|
77
77
|
S.current && m(!0);
|
|
78
78
|
}
|
|
79
79
|
if (!S.current) return;
|
|
80
|
-
v(o(
|
|
80
|
+
v(o(t.kind === "driver" ? "movethewheels.order.driverStatusBlocked" : "movethewheels.order.statusBlocked", t.kind === "driver" ? "Movement blocked by driver eligibility. Choose another driver." : "Movement blocked by the recorded vehicle status. Choose another vehicle.")), d();
|
|
81
81
|
} else S.current && (m(!0), v(o("movethewheels.order.statusUnknown", "Order status could not be confirmed. Further changes are blocked.")));
|
|
82
82
|
} finally {
|
|
83
83
|
D();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function SettingsPage(): import('react').JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
|
2
|
+
import { MtwModuleSettings, MtwModuleSettingsInput } from '../utils/moduleSettings';
|
|
3
|
+
interface ModuleSettingsContextValue {
|
|
4
|
+
settings: MtwModuleSettings;
|
|
5
|
+
/** True once the workspace's settings were read (or the read failed). */
|
|
6
|
+
isLoaded: boolean;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
save: (input: MtwModuleSettingsInput) => Promise<MtwModuleSettings>;
|
|
9
|
+
reload: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const ModuleSettingsProvider: FC<PropsWithChildren>;
|
|
12
|
+
/**
|
|
13
|
+
* The workspace's MoveTheWheels defaults. Outside the provider (stories,
|
|
14
|
+
* isolated component tests) it returns the platform defaults read-only.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useModuleSettings(): ModuleSettingsContextValue;
|
|
17
|
+
export {};
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { Address } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Workspace display preferences (BOFF-10488). The module settings provider
|
|
4
|
+
* applies the workspace's saved MoveTheWheels defaults here once they load,
|
|
5
|
+
* so every formatter below honours them without each call site passing them.
|
|
6
|
+
* Until then the platform defaults apply.
|
|
7
|
+
*/
|
|
8
|
+
export interface FormatPreferences {
|
|
9
|
+
/** ISO 4217 code for amounts that carry no currency of their own. */
|
|
10
|
+
currency: string;
|
|
11
|
+
distanceUnit: 'KM' | 'MI';
|
|
12
|
+
weightUnit: 'KG' | 'LB';
|
|
13
|
+
/** IANA zone; null formats in the viewer's own local time. */
|
|
14
|
+
timeZone: string | null;
|
|
15
|
+
}
|
|
16
|
+
export declare const DEFAULT_FORMAT_PREFERENCES: Readonly<FormatPreferences>;
|
|
17
|
+
export declare function setFormatPreferences(next: FormatPreferences): void;
|
|
18
|
+
export declare function getFormatPreferences(): Readonly<FormatPreferences>;
|
|
2
19
|
/**
|
|
3
20
|
* Format an address object into a readable string.
|
|
4
21
|
*/
|
|
5
22
|
export declare function formatAddress(address: Partial<Address>): string;
|
|
6
23
|
/**
|
|
7
|
-
* Format a number as currency.
|
|
24
|
+
* Format a number as currency. Amounts without their own currency use the
|
|
25
|
+
* workspace default currency.
|
|
8
26
|
*/
|
|
9
27
|
export declare function formatCurrency(amount: number, currency?: string): string;
|
|
10
28
|
/**
|
|
@@ -34,11 +52,13 @@ export declare function formatNumber(num: number): string;
|
|
|
34
52
|
*/
|
|
35
53
|
export declare function formatPercentage(value: number, decimals?: number): string;
|
|
36
54
|
/**
|
|
37
|
-
* Format weight
|
|
55
|
+
* Format a weight given in kilograms, in the workspace weight unit: kg (and
|
|
56
|
+
* tonnes from 1,000 kg) or lb.
|
|
38
57
|
*/
|
|
39
58
|
export declare function formatWeight(kg: number): string;
|
|
40
59
|
/**
|
|
41
|
-
* Format distance
|
|
60
|
+
* Format a distance given in kilometres, in the workspace distance unit: km
|
|
61
|
+
* (metres below 1 km) or mi (feet below 0.1 mi).
|
|
42
62
|
*/
|
|
43
63
|
export declare function formatDistance(km: number): string;
|
|
44
64
|
/**
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FormatPreferences } from './formatters';
|
|
2
|
+
export type MtwDistanceUnit = 'KM' | 'MI';
|
|
3
|
+
export type MtwWeightUnit = 'KG' | 'LB';
|
|
4
|
+
export type MtwOrderPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' | 'CRITICAL';
|
|
5
|
+
export interface MtwModuleSettings {
|
|
6
|
+
workspaceId: string;
|
|
7
|
+
defaultCurrency: string;
|
|
8
|
+
distanceUnit: MtwDistanceUnit;
|
|
9
|
+
weightUnit: MtwWeightUnit;
|
|
10
|
+
/** IANA zone; null shows each viewer their own local time. */
|
|
11
|
+
timezone: string | null;
|
|
12
|
+
defaultOrderPriority: MtwOrderPriority;
|
|
13
|
+
defaultDeliveryWindowHours: number;
|
|
14
|
+
isCustomized: boolean;
|
|
15
|
+
updatedAt: string | null;
|
|
16
|
+
updatedBy: string | null;
|
|
17
|
+
}
|
|
18
|
+
export type MtwModuleSettingsInput = Partial<Pick<MtwModuleSettings, 'defaultCurrency' | 'distanceUnit' | 'weightUnit' | 'timezone' | 'defaultOrderPriority' | 'defaultDeliveryWindowHours'>>;
|
|
19
|
+
/** Mirrors the service range for the default delivery window. */
|
|
20
|
+
export declare const DELIVERY_WINDOW_MIN_HOURS = 1;
|
|
21
|
+
export declare const DELIVERY_WINDOW_MAX_HOURS = 720;
|
|
22
|
+
/** The service's platform defaults, shown until the workspace's settings load. */
|
|
23
|
+
export declare function platformDefaults(workspaceId?: string): MtwModuleSettings;
|
|
24
|
+
export declare const MTW_MODULE_SETTINGS_QUERY = "\n query MtwModuleSettings {\n mtwModuleSettings {\n \n workspaceId\n defaultCurrency\n distanceUnit\n weightUnit\n timezone\n defaultOrderPriority\n defaultDeliveryWindowHours\n isCustomized\n updatedAt\n updatedBy\n\n }\n }\n";
|
|
25
|
+
export declare const UPDATE_MTW_MODULE_SETTINGS_MUTATION = "\n mutation UpdateMtwModuleSettings($input: UpdateMtwModuleSettingsInput!) {\n updateMtwModuleSettings(input: $input) {\n \n workspaceId\n defaultCurrency\n distanceUnit\n weightUnit\n timezone\n defaultOrderPriority\n defaultDeliveryWindowHours\n isCustomized\n updatedAt\n updatedBy\n\n }\n }\n";
|
|
26
|
+
/** What the formatters need from the settings. */
|
|
27
|
+
export declare function toFormatPreferences(settings: MtwModuleSettings): FormatPreferences;
|
|
28
|
+
export declare const DISTANCE_UNIT_OPTIONS: ReadonlyArray<{
|
|
29
|
+
value: MtwDistanceUnit;
|
|
30
|
+
label: string;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const WEIGHT_UNIT_OPTIONS: ReadonlyArray<{
|
|
33
|
+
value: MtwWeightUnit;
|
|
34
|
+
label: string;
|
|
35
|
+
}>;
|
|
36
|
+
export declare const ORDER_PRIORITY_OPTIONS: ReadonlyArray<{
|
|
37
|
+
value: MtwOrderPriority;
|
|
38
|
+
label: string;
|
|
39
|
+
}>;
|
|
40
|
+
/** The order form's four priorities for a service priority (CRITICAL shows as urgent). */
|
|
41
|
+
export declare function orderFormPriority(priority: MtwOrderPriority): 'low' | 'normal' | 'high' | 'urgent';
|
|
42
|
+
export declare function currencyOptions(current?: string): string[];
|
|
43
|
+
export declare function currencyLabel(code: string): string;
|
|
44
|
+
export declare function timeZoneOptions(current?: string | null): string[];
|
|
45
|
+
/** The browser's own zone, for the "viewer's local time" option label. */
|
|
46
|
+
export declare function browserTimeZone(): string;
|
|
47
|
+
/** Client-side check of the delivery window before it is sent. */
|
|
48
|
+
export declare function deliveryWindowError(value: string): string | null;
|
|
49
|
+
/** Only the fields that differ from the saved settings. */
|
|
50
|
+
export declare function changedSettings(saved: MtwModuleSettings, draft: MtwModuleSettingsInput): MtwModuleSettingsInput;
|
|
51
|
+
/** A `datetime-local` value `hours` from `from`, in the viewer's clock. */
|
|
52
|
+
export declare function deliveryWindowValue(hours: number, from?: Date): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/bell.js
|
|
3
|
+
var t = e("Bell", [["path", {
|
|
4
|
+
d: "M10.268 21a2 2 0 0 0 3.464 0",
|
|
5
|
+
key: "vwvbt9"
|
|
6
|
+
}], ["path", {
|
|
7
|
+
d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",
|
|
8
|
+
key: "11g9vi"
|
|
9
|
+
}]]);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as Bell };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/key-round.js
|
|
3
|
+
var t = e("KeyRound", [["path", {
|
|
4
|
+
d: "M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",
|
|
5
|
+
key: "1s6t7t"
|
|
6
|
+
}], ["circle", {
|
|
7
|
+
cx: "16.5",
|
|
8
|
+
cy: "7.5",
|
|
9
|
+
r: ".5",
|
|
10
|
+
fill: "currentColor",
|
|
11
|
+
key: "w0ekpg"
|
|
12
|
+
}]]);
|
|
13
|
+
//#endregion
|
|
14
|
+
export { t as KeyRound };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/plug.js
|
|
3
|
+
var t = e("Plug", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M12 22v-5",
|
|
6
|
+
key: "1ega77"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M9 8V2",
|
|
10
|
+
key: "14iosj"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M15 8V2",
|
|
14
|
+
key: "18g5xt"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z",
|
|
18
|
+
key: "osxo6l"
|
|
19
|
+
}]
|
|
20
|
+
]);
|
|
21
|
+
//#endregion
|
|
22
|
+
export { t as Plug };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/rotate-ccw.js
|
|
3
|
+
var t = e("RotateCcw", [["path", {
|
|
4
|
+
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
|
|
5
|
+
key: "1357e3"
|
|
6
|
+
}], ["path", {
|
|
7
|
+
d: "M3 3v5h5",
|
|
8
|
+
key: "1xhq8a"
|
|
9
|
+
}]]);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as RotateCcw };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/settings.js
|
|
3
|
+
var t = e("Settings", [["path", {
|
|
4
|
+
d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",
|
|
5
|
+
key: "1qme2f"
|
|
6
|
+
}], ["circle", {
|
|
7
|
+
cx: "12",
|
|
8
|
+
cy: "12",
|
|
9
|
+
r: "3",
|
|
10
|
+
key: "1v7zrd"
|
|
11
|
+
}]]);
|
|
12
|
+
//#endregion
|
|
13
|
+
export { t as Settings };
|
|
@@ -4,15 +4,15 @@ import { Package as n } from "../node_modules/lucide-react/dist/esm/icons/packag
|
|
|
4
4
|
import { Star as r } from "../node_modules/lucide-react/dist/esm/icons/star.js";
|
|
5
5
|
import { TrendingUp as i } from "../node_modules/lucide-react/dist/esm/icons/trending-up.js";
|
|
6
6
|
import { Users as a } from "../node_modules/lucide-react/dist/esm/icons/users.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
7
|
+
import { formatCurrency as o } from "../utils/formatters.js";
|
|
8
|
+
import { useAnalytics as s, useFleetAnalytics as c, useOrderAnalytics as l } from "../hooks/useAnalytics.js";
|
|
9
|
+
import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Progress as h } from "../components/ui.js";
|
|
10
|
+
import { PageLayout as g } from "../components/PageLayout.js";
|
|
11
|
+
import { MetricCard as _, MetricCardSkeleton as v, MetricGrid as y } from "../components/MetricCard.js";
|
|
12
|
+
import { TrendChart as b } from "../components/charts/TrendChart.js";
|
|
13
|
+
import { VolumeBar as x } from "../components/charts/VolumeBar.js";
|
|
14
|
+
import { StatusDonut as S } from "../components/charts/StatusDonut.js";
|
|
14
15
|
import "../components/charts/index.js";
|
|
15
|
-
import { formatCurrency as S } from "../utils/formatters.js";
|
|
16
16
|
import { CarbonFootprintPanel as C } from "../components/CarbonFootprintPanel.js";
|
|
17
17
|
import { UpcomingDemandPanel as w } from "../components/UpcomingDemandPanel.js";
|
|
18
18
|
import { useDemandForecast as T } from "../hooks/useDemandForecast.js";
|
|
@@ -22,14 +22,14 @@ import { EmphasisPanel as k, PagePurpose as A } from "@burdenoff/fe-libs/ui";
|
|
|
22
22
|
//#region src/movethewheels/pages/AnalyticsPage.tsx
|
|
23
23
|
var j = (e) => e.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
|
|
24
24
|
function M() {
|
|
25
|
-
let { analytics: M, isLoading: N, error: P, refetch: F } =
|
|
25
|
+
let { analytics: M, isLoading: N, error: P, refetch: F } = s(), { orderData: I } = l(), { fleetData: L } = c(), { laneForecast: R, customerForecast: z, laneVariance: B, customerVariance: V, isLoading: H, error: U, refetch: W } = T(4, 8), G = E(() => M.trends.dailyOrders.map((e) => e.orders), [M.trends.dailyOrders]), K = E(() => M.trends.revenue.map((e) => ({
|
|
26
26
|
month: e.month,
|
|
27
27
|
revenue: e.revenue
|
|
28
28
|
})), [M.trends.revenue]), q = E(() => I.byStatus.filter((e) => e.count > 0).map((e) => ({
|
|
29
29
|
name: j(e.status),
|
|
30
30
|
value: e.count
|
|
31
31
|
})), [I.byStatus]), J = q.reduce((e, t) => e + t.value, 0);
|
|
32
|
-
return /* @__PURE__ */ O(
|
|
32
|
+
return /* @__PURE__ */ O(g, {
|
|
33
33
|
title: "Analytics",
|
|
34
34
|
subtitle: "Business performance and insights",
|
|
35
35
|
icon: /* @__PURE__ */ D(e, { size: 24 }),
|
|
@@ -38,9 +38,9 @@ function M() {
|
|
|
38
38
|
icon: /* @__PURE__ */ D(e, { size: 18 }),
|
|
39
39
|
children: "See how the operation is really performing. Track order volume, revenue, on-time rate and customer satisfaction over time so you can spot trends, find bottlenecks, and decide where to invest — whether that's more vehicles, better routes, or new customers."
|
|
40
40
|
}),
|
|
41
|
-
P && !N ? /* @__PURE__ */ D(
|
|
41
|
+
P && !N ? /* @__PURE__ */ D(d, {
|
|
42
42
|
className: "border-status-error-border",
|
|
43
|
-
children: /* @__PURE__ */ O(
|
|
43
|
+
children: /* @__PURE__ */ O(f, {
|
|
44
44
|
className: "p-6 text-center space-y-3",
|
|
45
45
|
children: [
|
|
46
46
|
/* @__PURE__ */ D("p", {
|
|
@@ -51,35 +51,35 @@ function M() {
|
|
|
51
51
|
className: "text-sm text-text-secondary",
|
|
52
52
|
children: P.message
|
|
53
53
|
}),
|
|
54
|
-
/* @__PURE__ */ D(
|
|
54
|
+
/* @__PURE__ */ D(u, {
|
|
55
55
|
variant: "outline",
|
|
56
56
|
onClick: F,
|
|
57
57
|
children: "Retry"
|
|
58
58
|
})
|
|
59
59
|
]
|
|
60
60
|
})
|
|
61
|
-
}) : N ? /* @__PURE__ */ D(
|
|
61
|
+
}) : N ? /* @__PURE__ */ D(y, {
|
|
62
62
|
columns: 4,
|
|
63
|
-
children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ D(
|
|
64
|
-
}) : /* @__PURE__ */ O(
|
|
63
|
+
children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ D(v, {}, t))
|
|
64
|
+
}) : /* @__PURE__ */ O(y, {
|
|
65
65
|
columns: 4,
|
|
66
66
|
children: [
|
|
67
|
-
/* @__PURE__ */ D(
|
|
67
|
+
/* @__PURE__ */ D(_, {
|
|
68
68
|
label: "Order Volume",
|
|
69
69
|
value: M.overview.totalOrders.toLocaleString(),
|
|
70
70
|
icon: /* @__PURE__ */ D(n, { size: 20 }),
|
|
71
71
|
accent: "brand",
|
|
72
72
|
sparklineData: G.length >= 2 ? G : void 0
|
|
73
73
|
}),
|
|
74
|
-
/* @__PURE__ */ D(
|
|
74
|
+
/* @__PURE__ */ D(_, {
|
|
75
75
|
treatment: "glass",
|
|
76
76
|
glow: !0,
|
|
77
77
|
label: "Revenue",
|
|
78
|
-
value:
|
|
78
|
+
value: o(M.overview.totalRevenue),
|
|
79
79
|
icon: /* @__PURE__ */ D(t, { size: 20 }),
|
|
80
80
|
accent: "success"
|
|
81
81
|
}),
|
|
82
|
-
/* @__PURE__ */ D(
|
|
82
|
+
/* @__PURE__ */ D(_, {
|
|
83
83
|
label: "On-Time Delivery",
|
|
84
84
|
value: `${M.overview.onTimeDeliveryRate.toFixed(1)}%`,
|
|
85
85
|
icon: /* @__PURE__ */ D(i, { size: 20 }),
|
|
@@ -92,7 +92,7 @@ function M() {
|
|
|
92
92
|
direction: "down"
|
|
93
93
|
}
|
|
94
94
|
}),
|
|
95
|
-
/* @__PURE__ */ D(
|
|
95
|
+
/* @__PURE__ */ D(_, {
|
|
96
96
|
label: "Customer Satisfaction",
|
|
97
97
|
value: M.overview.customerSatisfaction.toFixed(1),
|
|
98
98
|
icon: /* @__PURE__ */ D(r, { size: 20 }),
|
|
@@ -101,7 +101,7 @@ function M() {
|
|
|
101
101
|
})
|
|
102
102
|
]
|
|
103
103
|
}),
|
|
104
|
-
/* @__PURE__ */ O(
|
|
104
|
+
/* @__PURE__ */ O(d, { children: [/* @__PURE__ */ D(p, { children: /* @__PURE__ */ D(m, { children: "Order & delivery trend" }) }), /* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(b, {
|
|
105
105
|
xKey: "date",
|
|
106
106
|
height: 300,
|
|
107
107
|
data: M.trends.dailyOrders,
|
|
@@ -125,7 +125,7 @@ function M() {
|
|
|
125
125
|
}),
|
|
126
126
|
/* @__PURE__ */ O("div", {
|
|
127
127
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
128
|
-
children: [/* @__PURE__ */ O(
|
|
128
|
+
children: [/* @__PURE__ */ O(d, { children: [/* @__PURE__ */ D(p, { children: /* @__PURE__ */ D(m, { children: "Revenue by month" }) }), /* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(x, {
|
|
129
129
|
xKey: "month",
|
|
130
130
|
height: 280,
|
|
131
131
|
showLegend: !1,
|
|
@@ -134,9 +134,9 @@ function M() {
|
|
|
134
134
|
dataKey: "revenue",
|
|
135
135
|
name: "Revenue"
|
|
136
136
|
}],
|
|
137
|
-
valueFormatter: (e) =>
|
|
137
|
+
valueFormatter: (e) => o(Number(e)),
|
|
138
138
|
emptyMessage: "No revenue recorded yet"
|
|
139
|
-
}) })] }), /* @__PURE__ */ O(
|
|
139
|
+
}) })] }), /* @__PURE__ */ O(d, { children: [/* @__PURE__ */ D(p, { children: /* @__PURE__ */ D(m, { children: "Orders by status" }) }), /* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(S, {
|
|
140
140
|
data: q,
|
|
141
141
|
height: 240,
|
|
142
142
|
centerLabel: J.toLocaleString(),
|
|
@@ -146,12 +146,12 @@ function M() {
|
|
|
146
146
|
}),
|
|
147
147
|
/* @__PURE__ */ O("div", {
|
|
148
148
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
149
|
-
children: [/* @__PURE__ */ O(
|
|
149
|
+
children: [/* @__PURE__ */ O(d, { children: [/* @__PURE__ */ D(p, { children: /* @__PURE__ */ D(m, { children: "Fleet Performance" }) }), /* @__PURE__ */ O(f, {
|
|
150
150
|
className: "space-y-4",
|
|
151
151
|
children: [/* @__PURE__ */ O("div", { children: [/* @__PURE__ */ O("div", {
|
|
152
152
|
className: "flex justify-between text-sm mb-1",
|
|
153
153
|
children: [/* @__PURE__ */ D("span", { children: "Vehicle Utilization" }), /* @__PURE__ */ O("span", { children: [L.vehicleUtilization.toFixed(0), "%"] })]
|
|
154
|
-
}), /* @__PURE__ */ D(
|
|
154
|
+
}), /* @__PURE__ */ D(h, { value: L.vehicleUtilization })] }), L.vehiclesByType.length > 0 && /* @__PURE__ */ O("div", {
|
|
155
155
|
className: "pt-2",
|
|
156
156
|
children: [/* @__PURE__ */ D("p", {
|
|
157
157
|
className: "text-sm text-text-secondary mb-2",
|