@burdenoff/microfe-movethewheels 2026.805.1 → 2026.827.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CarbonFootprintPanel.js +108 -0
- package/dist/components/index.js +1 -0
- package/dist/generated/wspace-operations.d.ts +168 -912
- package/dist/generated/wspace-types.d.ts +78432 -35831
- package/dist/hooks/useAnalytics.js +45 -4
- package/dist/hooks/useFleet.js +142 -74
- package/dist/hooks/useInventory.js +163 -70
- package/dist/hooks/useOrders.js +2 -2
- package/dist/hooks/useTracking.js +5 -5
- package/dist/index.js +33 -32
- package/dist/movethewheels/components/CarbonFootprintPanel.d.ts +7 -0
- package/dist/movethewheels/components/index.d.ts +1 -0
- package/dist/movethewheels/hooks/index.d.ts +3 -3
- package/dist/movethewheels/hooks/useAnalytics.d.ts +22 -0
- package/dist/movethewheels/hooks/useFleet.d.ts +32 -1
- package/dist/movethewheels/hooks/useInventory.d.ts +67 -12
- package/dist/movethewheels/hooks/useOrders.d.ts +25 -2
- package/dist/movethewheels/types/index.d.ts +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/arrow-down-right.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/arrow-left-right.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/arrow-up-right.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/calendar-clock.js +32 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/history.js +18 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/leaf.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/lock.js +16 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/user-round.js +13 -0
- package/dist/pages/AnalyticsPage.js +81 -79
- package/dist/pages/CreateOrderPage.js +246 -195
- package/dist/pages/DeliveryCapturePage.js +91 -78
- package/dist/pages/DriversPage.js +202 -108
- package/dist/pages/InventoryPage.js +356 -131
- package/dist/pages/ProductDetailsPage.js +212 -156
- package/dist/pages/VehicleDetailsPage.js +257 -193
- package/dist/utils/formatters.js +4 -1
- package/package.json +1 -1
- package/src/generated/wspace-operations.ts +134 -929
- package/src/generated/wspace-types.ts +91730 -40059
- package/src/movethewheels/components/CarbonFootprintPanel.tsx +133 -0
- package/src/movethewheels/components/UpcomingDemandPanel.tsx +20 -11
- package/src/movethewheels/components/index.ts +3 -0
- package/src/movethewheels/hooks/index.ts +11 -0
- package/src/movethewheels/hooks/useAnalytics.ts +86 -0
- package/src/movethewheels/hooks/useDemandForecast.ts +10 -4
- package/src/movethewheels/hooks/useFleet.ts +133 -3
- package/src/movethewheels/hooks/useInventory.ts +311 -53
- package/src/movethewheels/hooks/useOrders.ts +31 -7
- package/src/movethewheels/hooks/useTracking.ts +14 -14
- package/src/movethewheels/pages/AnalyticsPage.tsx +5 -5
- package/src/movethewheels/pages/CreateOrderPage.tsx +67 -10
- package/src/movethewheels/pages/DeliveryCapturePage.tsx +8 -0
- package/src/movethewheels/pages/DriversPage.tsx +181 -31
- package/src/movethewheels/pages/InventoryPage.tsx +299 -19
- package/src/movethewheels/pages/ProductDetailsPage.tsx +68 -3
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +86 -27
- package/src/movethewheels/types/index.ts +2 -0
- package/src/operations/wspace/movethewheels/fragments/core.graphql +23 -53
- package/src/operations/wspace/movethewheels/fragments/core.withdrawn.graphql +59 -0
- package/src/operations/wspace/movethewheels/mutations/entities.graphql +5 -5
- package/src/operations/wspace/movethewheels/mutations/marketplace-reports.graphql +18 -78
- package/src/operations/wspace/movethewheels/mutations/marketplace-reports.withdrawn.graphql +93 -0
- package/src/operations/wspace/movethewheels/mutations/orders.graphql +7 -7
- package/src/operations/wspace/movethewheels/queries/dashboard.graphql +3 -3
- package/src/operations/wspace/movethewheels/queries/entities.graphql +3 -3
- package/src/operations/wspace/movethewheels/queries/logistics.graphql +3 -3
- package/src/operations/wspace/movethewheels/queries/marketplace-reports.withdrawn.graphql +58 -0
- package/src/operations/wspace/movethewheels/queries/orders.graphql +3 -3
- package/src/operations/wspace/movethewheels/queries/marketplace-reports.graphql +0 -40
|
@@ -133,4 +133,26 @@ export declare function usePerformanceAnalytics(): {
|
|
|
133
133
|
isLoading: boolean;
|
|
134
134
|
error: Error | null;
|
|
135
135
|
};
|
|
136
|
+
export interface EmissionsSummary {
|
|
137
|
+
totalCo2eKg: number;
|
|
138
|
+
totalDistanceKm: number;
|
|
139
|
+
averageCo2eKgPerKm: number;
|
|
140
|
+
byVehicle: Array<{
|
|
141
|
+
vehicleId: string | null;
|
|
142
|
+
vehicleNumber: string | null;
|
|
143
|
+
totalDistanceKm: number;
|
|
144
|
+
co2eKg: number;
|
|
145
|
+
}>;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Real emissions figures straight from Query.emissionsSummary (BOFF-4391).
|
|
149
|
+
* Returns totals, per-km intensity, and a per-vehicle breakdown sourced from
|
|
150
|
+
* cached route CO2e values and actual/estimated distances.
|
|
151
|
+
*/
|
|
152
|
+
export declare function useEmissionsSummary(): {
|
|
153
|
+
summary: EmissionsSummary;
|
|
154
|
+
isLoading: boolean;
|
|
155
|
+
error: Error | null;
|
|
156
|
+
refetch: () => void;
|
|
157
|
+
};
|
|
136
158
|
export {};
|
|
@@ -66,13 +66,44 @@ interface UseDriversResult {
|
|
|
66
66
|
updateDriverStatus: (id: string, status: DriverStatus) => Promise<Driver>;
|
|
67
67
|
assignVehicle: (driverId: string, vehicleId: string) => Promise<Driver>;
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
interface UseDriversOptions extends UseListOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Narrows the roster server-side via `DriverFilterInput.status` so the pager
|
|
72
|
+
* still counts whole result sets rather than filtering one fetched page.
|
|
73
|
+
*/
|
|
74
|
+
status?: DriverStatus;
|
|
75
|
+
}
|
|
76
|
+
export declare function useDrivers(options?: UseDriversOptions): UseDriversResult;
|
|
70
77
|
export declare function useDriver(driverId: string | undefined): {
|
|
71
78
|
driver: Driver | null;
|
|
72
79
|
isLoading: boolean;
|
|
73
80
|
error: Error | null;
|
|
74
81
|
refetch: () => void;
|
|
75
82
|
};
|
|
83
|
+
export interface DriverStatusCounts {
|
|
84
|
+
onBreak: number;
|
|
85
|
+
offDuty: number;
|
|
86
|
+
inactive: number;
|
|
87
|
+
}
|
|
88
|
+
/** Exact per-status driver counts for the roster tiles (see DRIVER_STATUS_COUNTS_QUERY). */
|
|
89
|
+
export declare function useDriverStatusCounts(): {
|
|
90
|
+
counts: DriverStatusCounts;
|
|
91
|
+
isLoading: boolean;
|
|
92
|
+
error: Error | null;
|
|
93
|
+
refetch: () => void;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* The driver(s) currently assigned to a vehicle, resolved server-side through
|
|
97
|
+
* `DriverFilterInput.vehicleId` (the same link `assignDriverVehicle` writes).
|
|
98
|
+
* A vehicle normally has one driver, but the filter returns a list, so the
|
|
99
|
+
* caller gets every assignment rather than a silently-picked first row.
|
|
100
|
+
*/
|
|
101
|
+
export declare function useVehicleDrivers(vehicleId: string | undefined): {
|
|
102
|
+
drivers: Driver[];
|
|
103
|
+
isLoading: boolean;
|
|
104
|
+
error: Error | null;
|
|
105
|
+
refetch: () => void;
|
|
106
|
+
};
|
|
76
107
|
export declare function useFleetStats(): {
|
|
77
108
|
stats: {
|
|
78
109
|
totalVehicles: number;
|
|
@@ -102,20 +102,75 @@ export declare function useWarehouse(warehouseId: string | undefined): {
|
|
|
102
102
|
error: Error | null;
|
|
103
103
|
refetch: () => undefined;
|
|
104
104
|
};
|
|
105
|
+
export interface InventoryStats {
|
|
106
|
+
/** Units physically in the warehouses. */
|
|
107
|
+
totalOnHand: number;
|
|
108
|
+
/** Units free to promise on a new order. */
|
|
109
|
+
totalAvailable: number;
|
|
110
|
+
/** Units already committed to open orders. */
|
|
111
|
+
totalAllocated: number;
|
|
112
|
+
/** Units written off as damaged. */
|
|
113
|
+
totalDamaged: number;
|
|
114
|
+
/** Stock lines at or under their reorder point. */
|
|
115
|
+
lowStockCount: number;
|
|
116
|
+
/** Catalog size (`cargoItemsCount`), workspace-wide — not a page length. */
|
|
117
|
+
totalProducts: number;
|
|
118
|
+
/** Warehouse count (`warehousesCount`), workspace-wide. */
|
|
119
|
+
totalWarehouses: number;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Workspace-wide inventory aggregates, every figure served by the module:
|
|
123
|
+
* `inventoryStats` for the stock position, `cargoItemsCount`/`warehousesCount`
|
|
124
|
+
* for catalog and network size. There is no aggregate stock-value field on the
|
|
125
|
+
* subgraph, so no monetary total is reported here.
|
|
126
|
+
*/
|
|
105
127
|
export declare function useInventoryStats(): {
|
|
106
|
-
stats:
|
|
107
|
-
totalItems: number;
|
|
108
|
-
lowStockItems: number;
|
|
109
|
-
totalValue: number;
|
|
110
|
-
totalProducts: number;
|
|
111
|
-
totalWarehouses: number;
|
|
112
|
-
warehouseUtilization: Array<{
|
|
113
|
-
id: string;
|
|
114
|
-
name: string;
|
|
115
|
-
utilization: number;
|
|
116
|
-
}>;
|
|
117
|
-
};
|
|
128
|
+
stats: InventoryStats;
|
|
118
129
|
isLoading: boolean;
|
|
119
130
|
error: Error | null;
|
|
120
131
|
};
|
|
132
|
+
export interface ProductStockLevel {
|
|
133
|
+
inventoryItemId: string;
|
|
134
|
+
warehouseId: string;
|
|
135
|
+
warehouseName: string;
|
|
136
|
+
warehouseCode: string;
|
|
137
|
+
onHand: number;
|
|
138
|
+
available: number;
|
|
139
|
+
allocated: number;
|
|
140
|
+
damaged: number;
|
|
141
|
+
reorderPoint?: number;
|
|
142
|
+
}
|
|
143
|
+
/** Where a catalog item is stocked, and how much of it is free to promise. */
|
|
144
|
+
export declare function useProductStockLevels(productId: string | undefined): {
|
|
145
|
+
levels: ProductStockLevel[];
|
|
146
|
+
isLoading: boolean;
|
|
147
|
+
error: Error | null;
|
|
148
|
+
refetch: () => void;
|
|
149
|
+
};
|
|
150
|
+
export type InventoryTransactionType = 'RECEIPT' | 'ISSUE' | 'TRANSFER' | 'ADJUSTMENT' | 'RETURN';
|
|
151
|
+
export interface InventoryTransaction {
|
|
152
|
+
id: string;
|
|
153
|
+
transactionNumber: string;
|
|
154
|
+
type: InventoryTransactionType;
|
|
155
|
+
/** Signed by `type`: receipts/returns add stock, issues remove it. */
|
|
156
|
+
quantity: number;
|
|
157
|
+
productId: string;
|
|
158
|
+
warehouseId: string;
|
|
159
|
+
notes?: string;
|
|
160
|
+
referenceType?: string;
|
|
161
|
+
referenceId?: string;
|
|
162
|
+
createdAt: Date;
|
|
163
|
+
}
|
|
164
|
+
interface UseInventoryTransactionsOptions {
|
|
165
|
+
limit?: number;
|
|
166
|
+
productId?: string;
|
|
167
|
+
warehouseId?: string;
|
|
168
|
+
}
|
|
169
|
+
/** Recent stock movements from `Query.inventoryTransactions` (newest first). */
|
|
170
|
+
export declare function useInventoryTransactions(options?: UseInventoryTransactionsOptions): {
|
|
171
|
+
transactions: InventoryTransaction[];
|
|
172
|
+
isLoading: boolean;
|
|
173
|
+
error: Error | null;
|
|
174
|
+
refetch: () => void;
|
|
175
|
+
};
|
|
121
176
|
export {};
|
|
@@ -5,6 +5,16 @@ interface UseOrdersOptions {
|
|
|
5
5
|
limit?: number;
|
|
6
6
|
offset?: number;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Write shape for create/update. Identical to `Partial<Order>` except that
|
|
10
|
+
* `scheduledDelivery` also accepts `null`: `UpdateDeliveryJobInput.scheduledDelivery`
|
|
11
|
+
* is nullable on the service, so an explicit `null` clears a previously booked
|
|
12
|
+
* slot, while `undefined` leaves it untouched. Without the distinction, clearing
|
|
13
|
+
* the field in the form would silently keep the old date.
|
|
14
|
+
*/
|
|
15
|
+
export type OrderWriteInput = Omit<Partial<Order>, 'scheduledDelivery'> & {
|
|
16
|
+
scheduledDelivery?: Date | null;
|
|
17
|
+
};
|
|
8
18
|
interface UseOrdersResult {
|
|
9
19
|
orders: Order[];
|
|
10
20
|
totalOrders: number;
|
|
@@ -17,11 +27,24 @@ interface UseOrdersResult {
|
|
|
17
27
|
isLoading: boolean;
|
|
18
28
|
error: Error | null;
|
|
19
29
|
refetch: () => void;
|
|
20
|
-
createOrder: (order:
|
|
21
|
-
updateOrder: (id: string, updates:
|
|
30
|
+
createOrder: (order: OrderWriteInput) => Promise<Order>;
|
|
31
|
+
updateOrder: (id: string, updates: OrderWriteInput) => Promise<Order>;
|
|
22
32
|
deleteOrder: (id: string) => Promise<void>;
|
|
23
33
|
updateOrderStatus: (id: string, status: OrderStatus) => Promise<Order>;
|
|
24
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Normalises a service `DeliveryJobStatus` into the MFE's OrderStatus union.
|
|
37
|
+
* Exported so any surface rendering a raw job status badge normalises it the
|
|
38
|
+
* same way — the service casing is upper snake case and would miss the badge
|
|
39
|
+
* colour map otherwise.
|
|
40
|
+
*/
|
|
41
|
+
export declare function mapOrderStatus(status: string): OrderStatus;
|
|
42
|
+
/**
|
|
43
|
+
* Normalises a service `DeliveryPriority` (LOW/MEDIUM/HIGH/URGENT/CRITICAL)
|
|
44
|
+
* into the four-level union PriorityBadge understands. MEDIUM and CRITICAL have
|
|
45
|
+
* no direct badge entry, so rendering the raw value would break the colour map.
|
|
46
|
+
*/
|
|
47
|
+
export declare function mapOrderPriority(priority: string): 'low' | 'normal' | 'high' | 'urgent';
|
|
25
48
|
export declare function useOrders(options?: UseOrdersOptions): UseOrdersResult;
|
|
26
49
|
export declare function useOrder(orderId: string | undefined): {
|
|
27
50
|
order: Order | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/arrow-down-right.js
|
|
3
|
+
var t = e("ArrowDownRight", [["path", {
|
|
4
|
+
d: "m7 7 10 10",
|
|
5
|
+
key: "1fmybs"
|
|
6
|
+
}], ["path", {
|
|
7
|
+
d: "M17 7v10H7",
|
|
8
|
+
key: "6fjiku"
|
|
9
|
+
}]]);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as ArrowDownRight };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/arrow-left-right.js
|
|
3
|
+
var t = e("ArrowLeftRight", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M8 3 4 7l4 4",
|
|
6
|
+
key: "9rb6wj"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M4 7h16",
|
|
10
|
+
key: "6tx8e3"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "m16 21 4-4-4-4",
|
|
14
|
+
key: "siv7j2"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "M20 17H4",
|
|
18
|
+
key: "h6l3hr"
|
|
19
|
+
}]
|
|
20
|
+
]);
|
|
21
|
+
//#endregion
|
|
22
|
+
export { t as ArrowLeftRight };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/arrow-up-right.js
|
|
3
|
+
var t = e("ArrowUpRight", [["path", {
|
|
4
|
+
d: "M7 7h10v10",
|
|
5
|
+
key: "1tivn9"
|
|
6
|
+
}], ["path", {
|
|
7
|
+
d: "M7 17 17 7",
|
|
8
|
+
key: "1vkiza"
|
|
9
|
+
}]]);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as ArrowUpRight };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/calendar-clock.js
|
|
3
|
+
var t = e("CalendarClock", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5",
|
|
6
|
+
key: "1osxxc"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M16 2v4",
|
|
10
|
+
key: "4m81vk"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M8 2v4",
|
|
14
|
+
key: "1cmpym"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "M3 10h5",
|
|
18
|
+
key: "r794hk"
|
|
19
|
+
}],
|
|
20
|
+
["path", {
|
|
21
|
+
d: "M17.5 17.5 16 16.3V14",
|
|
22
|
+
key: "akvzfd"
|
|
23
|
+
}],
|
|
24
|
+
["circle", {
|
|
25
|
+
cx: "16",
|
|
26
|
+
cy: "16",
|
|
27
|
+
r: "6",
|
|
28
|
+
key: "qoo3c4"
|
|
29
|
+
}]
|
|
30
|
+
]);
|
|
31
|
+
//#endregion
|
|
32
|
+
export { t as CalendarClock };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/history.js
|
|
3
|
+
var t = e("History", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
|
|
6
|
+
key: "1357e3"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M3 3v5h5",
|
|
10
|
+
key: "1xhq8a"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M12 7v5l4 2",
|
|
14
|
+
key: "1fdv2h"
|
|
15
|
+
}]
|
|
16
|
+
]);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as History };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/leaf.js
|
|
3
|
+
var t = e("Leaf", [["path", {
|
|
4
|
+
d: "M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z",
|
|
5
|
+
key: "nnexq3"
|
|
6
|
+
}], ["path", {
|
|
7
|
+
d: "M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12",
|
|
8
|
+
key: "mt58a7"
|
|
9
|
+
}]]);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as Leaf };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/lock.js
|
|
3
|
+
var t = e("Lock", [["rect", {
|
|
4
|
+
width: "18",
|
|
5
|
+
height: "11",
|
|
6
|
+
x: "3",
|
|
7
|
+
y: "11",
|
|
8
|
+
rx: "2",
|
|
9
|
+
ry: "2",
|
|
10
|
+
key: "1w4ew1"
|
|
11
|
+
}], ["path", {
|
|
12
|
+
d: "M7 11V7a5 5 0 0 1 10 0v4",
|
|
13
|
+
key: "fwvmzm"
|
|
14
|
+
}]]);
|
|
15
|
+
//#endregion
|
|
16
|
+
export { t as Lock };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/user-round.js
|
|
3
|
+
var t = e("UserRound", [["circle", {
|
|
4
|
+
cx: "12",
|
|
5
|
+
cy: "8",
|
|
6
|
+
r: "5",
|
|
7
|
+
key: "1hypcn"
|
|
8
|
+
}], ["path", {
|
|
9
|
+
d: "M20 21a8 8 0 0 0-16 0",
|
|
10
|
+
key: "rfgkzh"
|
|
11
|
+
}]]);
|
|
12
|
+
//#endregion
|
|
13
|
+
export { t as UserRound };
|
|
@@ -13,77 +13,78 @@ import { VolumeBar as b } from "../components/charts/VolumeBar.js";
|
|
|
13
13
|
import { StatusDonut as x } from "../components/charts/StatusDonut.js";
|
|
14
14
|
import "../components/charts/index.js";
|
|
15
15
|
import { formatCurrency as S } from "../utils/formatters.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
16
|
+
import { CarbonFootprintPanel as C } from "../components/CarbonFootprintPanel.js";
|
|
17
|
+
import { UpcomingDemandPanel as w } from "../components/UpcomingDemandPanel.js";
|
|
18
|
+
import { useDemandForecast as T } from "../hooks/useDemandForecast.js";
|
|
19
|
+
import { useMemo as E } from "react";
|
|
20
|
+
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
21
|
+
import { EmphasisPanel as k, PagePurpose as A } from "@burdenoff/fe-libs/ui";
|
|
21
22
|
//#region src/movethewheels/pages/AnalyticsPage.tsx
|
|
22
|
-
var
|
|
23
|
-
function
|
|
24
|
-
let { analytics:
|
|
23
|
+
var j = (e) => e.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
|
|
24
|
+
function M() {
|
|
25
|
+
let { analytics: M, isLoading: N, error: P, refetch: F } = o(), { orderData: I } = c(), { fleetData: L } = s(), { 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) => ({
|
|
25
26
|
month: e.month,
|
|
26
27
|
revenue: e.revenue
|
|
27
|
-
})), [
|
|
28
|
-
name:
|
|
28
|
+
})), [M.trends.revenue]), q = E(() => I.byStatus.filter((e) => e.count > 0).map((e) => ({
|
|
29
|
+
name: j(e.status),
|
|
29
30
|
value: e.count
|
|
30
|
-
})), [
|
|
31
|
-
return /* @__PURE__ */
|
|
31
|
+
})), [I.byStatus]), J = q.reduce((e, t) => e + t.value, 0);
|
|
32
|
+
return /* @__PURE__ */ O(h, {
|
|
32
33
|
title: "Analytics",
|
|
33
34
|
subtitle: "Business performance and insights",
|
|
34
|
-
icon: /* @__PURE__ */
|
|
35
|
+
icon: /* @__PURE__ */ D(e, { size: 24 }),
|
|
35
36
|
children: [
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
-
icon: /* @__PURE__ */
|
|
37
|
+
/* @__PURE__ */ D(A, {
|
|
38
|
+
icon: /* @__PURE__ */ D(e, { size: 18 }),
|
|
38
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."
|
|
39
40
|
}),
|
|
40
|
-
|
|
41
|
+
P && !N ? /* @__PURE__ */ D(u, {
|
|
41
42
|
className: "border-status-error-border",
|
|
42
|
-
children: /* @__PURE__ */
|
|
43
|
+
children: /* @__PURE__ */ O(d, {
|
|
43
44
|
className: "p-6 text-center space-y-3",
|
|
44
45
|
children: [
|
|
45
|
-
/* @__PURE__ */
|
|
46
|
+
/* @__PURE__ */ D("p", {
|
|
46
47
|
className: "text-status-error-text font-medium",
|
|
47
48
|
children: "Couldn't load analytics"
|
|
48
49
|
}),
|
|
49
|
-
/* @__PURE__ */
|
|
50
|
+
/* @__PURE__ */ D("p", {
|
|
50
51
|
className: "text-sm text-text-secondary",
|
|
51
|
-
children:
|
|
52
|
+
children: P.message
|
|
52
53
|
}),
|
|
53
|
-
/* @__PURE__ */
|
|
54
|
+
/* @__PURE__ */ D(l, {
|
|
54
55
|
variant: "outline",
|
|
55
|
-
onClick:
|
|
56
|
+
onClick: F,
|
|
56
57
|
children: "Retry"
|
|
57
58
|
})
|
|
58
59
|
]
|
|
59
60
|
})
|
|
60
|
-
}) :
|
|
61
|
+
}) : N ? /* @__PURE__ */ D(v, {
|
|
61
62
|
columns: 4,
|
|
62
|
-
children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */
|
|
63
|
-
}) : /* @__PURE__ */
|
|
63
|
+
children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ D(_, {}, t))
|
|
64
|
+
}) : /* @__PURE__ */ O(v, {
|
|
64
65
|
columns: 4,
|
|
65
66
|
children: [
|
|
66
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ D(g, {
|
|
67
68
|
label: "Order Volume",
|
|
68
|
-
value:
|
|
69
|
-
icon: /* @__PURE__ */
|
|
69
|
+
value: M.overview.totalOrders.toLocaleString(),
|
|
70
|
+
icon: /* @__PURE__ */ D(n, { size: 20 }),
|
|
70
71
|
accent: "brand",
|
|
71
|
-
sparklineData:
|
|
72
|
+
sparklineData: G.length >= 2 ? G : void 0
|
|
72
73
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ D(g, {
|
|
74
75
|
treatment: "glass",
|
|
75
76
|
glow: !0,
|
|
76
77
|
label: "Revenue",
|
|
77
|
-
value: S(
|
|
78
|
-
icon: /* @__PURE__ */
|
|
78
|
+
value: S(M.overview.totalRevenue),
|
|
79
|
+
icon: /* @__PURE__ */ D(t, { size: 20 }),
|
|
79
80
|
accent: "success"
|
|
80
81
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ D(g, {
|
|
82
83
|
label: "On-Time Delivery",
|
|
83
|
-
value: `${
|
|
84
|
-
icon: /* @__PURE__ */
|
|
84
|
+
value: `${M.overview.onTimeDeliveryRate.toFixed(1)}%`,
|
|
85
|
+
icon: /* @__PURE__ */ D(i, { size: 20 }),
|
|
85
86
|
accent: "blue",
|
|
86
|
-
delta:
|
|
87
|
+
delta: M.overview.onTimeDeliveryRate >= 90 ? {
|
|
87
88
|
value: "On target",
|
|
88
89
|
direction: "up"
|
|
89
90
|
} : {
|
|
@@ -91,19 +92,19 @@ function j() {
|
|
|
91
92
|
direction: "down"
|
|
92
93
|
}
|
|
93
94
|
}),
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ D(g, {
|
|
95
96
|
label: "Customer Satisfaction",
|
|
96
|
-
value:
|
|
97
|
-
icon: /* @__PURE__ */
|
|
97
|
+
value: M.overview.customerSatisfaction.toFixed(1),
|
|
98
|
+
icon: /* @__PURE__ */ D(r, { size: 20 }),
|
|
98
99
|
accent: "warning",
|
|
99
100
|
subtitle: "out of 5"
|
|
100
101
|
})
|
|
101
102
|
]
|
|
102
103
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ O(u, { children: [/* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(p, { children: "Order & delivery trend" }) }), /* @__PURE__ */ D(d, { children: /* @__PURE__ */ D(y, {
|
|
104
105
|
xKey: "date",
|
|
105
106
|
height: 300,
|
|
106
|
-
data:
|
|
107
|
+
data: M.trends.dailyOrders,
|
|
107
108
|
series: [{
|
|
108
109
|
dataKey: "orders",
|
|
109
110
|
name: "Orders"
|
|
@@ -113,98 +114,99 @@ function j() {
|
|
|
113
114
|
}],
|
|
114
115
|
emptyMessage: "No order trend recorded yet"
|
|
115
116
|
}) })] }),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
laneForecast:
|
|
118
|
-
customerForecast:
|
|
119
|
-
laneVariance:
|
|
120
|
-
customerVariance:
|
|
121
|
-
isLoading:
|
|
122
|
-
error:
|
|
123
|
-
onRetry:
|
|
117
|
+
/* @__PURE__ */ D(w, {
|
|
118
|
+
laneForecast: R,
|
|
119
|
+
customerForecast: z,
|
|
120
|
+
laneVariance: B,
|
|
121
|
+
customerVariance: V,
|
|
122
|
+
isLoading: H,
|
|
123
|
+
error: U,
|
|
124
|
+
onRetry: W
|
|
124
125
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
+
/* @__PURE__ */ O("div", {
|
|
126
127
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
127
|
-
children: [/* @__PURE__ */
|
|
128
|
+
children: [/* @__PURE__ */ O(u, { children: [/* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(p, { children: "Revenue by month" }) }), /* @__PURE__ */ D(d, { children: /* @__PURE__ */ D(b, {
|
|
128
129
|
xKey: "month",
|
|
129
130
|
height: 280,
|
|
130
131
|
showLegend: !1,
|
|
131
|
-
data:
|
|
132
|
+
data: K,
|
|
132
133
|
series: [{
|
|
133
134
|
dataKey: "revenue",
|
|
134
135
|
name: "Revenue"
|
|
135
136
|
}],
|
|
136
137
|
valueFormatter: (e) => S(Number(e)),
|
|
137
138
|
emptyMessage: "No revenue recorded yet"
|
|
138
|
-
}) })] }), /* @__PURE__ */
|
|
139
|
-
data:
|
|
139
|
+
}) })] }), /* @__PURE__ */ O(u, { children: [/* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(p, { children: "Orders by status" }) }), /* @__PURE__ */ D(d, { children: /* @__PURE__ */ D(x, {
|
|
140
|
+
data: q,
|
|
140
141
|
height: 240,
|
|
141
|
-
centerLabel:
|
|
142
|
+
centerLabel: J.toLocaleString(),
|
|
142
143
|
centerSubLabel: "orders",
|
|
143
144
|
emptyMessage: "No orders to break down yet"
|
|
144
145
|
}) })] })]
|
|
145
146
|
}),
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ O("div", {
|
|
147
148
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
148
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ O(u, { children: [/* @__PURE__ */ D(f, { children: /* @__PURE__ */ D(p, { children: "Fleet Performance" }) }), /* @__PURE__ */ O(d, {
|
|
149
150
|
className: "space-y-4",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
151
|
+
children: [/* @__PURE__ */ O("div", { children: [/* @__PURE__ */ O("div", {
|
|
151
152
|
className: "flex justify-between text-sm mb-1",
|
|
152
|
-
children: [/* @__PURE__ */
|
|
153
|
-
}), /* @__PURE__ */
|
|
153
|
+
children: [/* @__PURE__ */ D("span", { children: "Vehicle Utilization" }), /* @__PURE__ */ O("span", { children: [L.vehicleUtilization.toFixed(0), "%"] })]
|
|
154
|
+
}), /* @__PURE__ */ D(m, { value: L.vehicleUtilization })] }), L.vehiclesByType.length > 0 && /* @__PURE__ */ O("div", {
|
|
154
155
|
className: "pt-2",
|
|
155
|
-
children: [/* @__PURE__ */
|
|
156
|
+
children: [/* @__PURE__ */ D("p", {
|
|
156
157
|
className: "text-sm text-text-secondary mb-2",
|
|
157
158
|
children: "Vehicles by Type"
|
|
158
|
-
}),
|
|
159
|
+
}), L.vehiclesByType.map(({ type: e, count: t }) => /* @__PURE__ */ O("div", {
|
|
159
160
|
className: "flex justify-between text-sm py-1",
|
|
160
|
-
children: [/* @__PURE__ */
|
|
161
|
+
children: [/* @__PURE__ */ D("span", {
|
|
161
162
|
className: "capitalize",
|
|
162
163
|
children: e
|
|
163
|
-
}), /* @__PURE__ */
|
|
164
|
+
}), /* @__PURE__ */ D("span", {
|
|
164
165
|
className: "font-medium",
|
|
165
166
|
children: t
|
|
166
167
|
})]
|
|
167
168
|
}, e))]
|
|
168
169
|
})]
|
|
169
|
-
})] }), /* @__PURE__ */
|
|
170
|
+
})] }), /* @__PURE__ */ O(k, {
|
|
170
171
|
className: "space-y-4",
|
|
171
172
|
children: [
|
|
172
|
-
/* @__PURE__ */
|
|
173
|
+
/* @__PURE__ */ D("h2", {
|
|
173
174
|
className: "text-base font-semibold text-text-primary",
|
|
174
175
|
children: "Performance Metrics"
|
|
175
176
|
}),
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("p", {
|
|
177
178
|
className: "text-sm text-text-secondary",
|
|
178
179
|
children: "On-Time Delivery"
|
|
179
|
-
}), /* @__PURE__ */
|
|
180
|
+
}), /* @__PURE__ */ O("p", {
|
|
180
181
|
className: "text-2xl font-bold",
|
|
181
|
-
children: [
|
|
182
|
+
children: [M.performance.onTimeDelivery.toFixed(1), "%"]
|
|
182
183
|
})] }),
|
|
183
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("p", {
|
|
184
185
|
className: "text-sm text-text-secondary",
|
|
185
186
|
children: "Customer Satisfaction"
|
|
186
|
-
}), /* @__PURE__ */
|
|
187
|
+
}), /* @__PURE__ */ O("p", {
|
|
187
188
|
className: "text-2xl font-bold",
|
|
188
|
-
children: [
|
|
189
|
+
children: [M.overview.customerSatisfaction.toFixed(1), "/5"]
|
|
189
190
|
})] }),
|
|
190
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ O("div", {
|
|
191
192
|
className: "flex items-center gap-2",
|
|
192
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ D(a, {
|
|
193
194
|
size: 16,
|
|
194
195
|
className: "text-text-secondary"
|
|
195
|
-
}), /* @__PURE__ */
|
|
196
|
+
}), /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("p", {
|
|
196
197
|
className: "text-sm text-text-secondary",
|
|
197
198
|
children: "Driver Ratings"
|
|
198
|
-
}), /* @__PURE__ */
|
|
199
|
+
}), /* @__PURE__ */ O("p", {
|
|
199
200
|
className: "text-2xl font-bold",
|
|
200
|
-
children: [
|
|
201
|
+
children: [M.performance.driverRatings.toFixed(1), "/5"]
|
|
201
202
|
})] })]
|
|
202
203
|
})
|
|
203
204
|
]
|
|
204
205
|
})]
|
|
205
|
-
})
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ D(C, {})
|
|
206
208
|
]
|
|
207
209
|
});
|
|
208
210
|
}
|
|
209
211
|
//#endregion
|
|
210
|
-
export {
|
|
212
|
+
export { M as default };
|