@burdenoff/microfe-movethewheels 2026.924.2 → 2026.925.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/OrderItemRow.js +195 -109
- package/dist/constants/index.js +1 -0
- package/dist/generated/wspace-operations.d.ts +7 -0
- package/dist/hooks/useOrders.js +8 -4
- package/dist/hooks/useTracking.js +127 -66
- package/dist/movethewheels/components/OrderItemRow.d.ts +1 -2
- package/dist/movethewheels/hooks/useOrders.d.ts +1 -0
- package/dist/movethewheels/hooks/useTracking.d.ts +2 -2
- package/dist/movethewheels/types/index.d.ts +1 -1
- package/dist/pages/CreateOrderPage.js +597 -420
- package/dist/pages/OrderDetailsPage.js +289 -266
- package/dist/pages/OrdersListPage.js +4 -0
- package/dist/pages/TrackingPage.js +205 -195
- package/dist/utils/mapMarkers.js +2 -1
- package/package.json +1 -1
- package/src/generated/wspace-operations.ts +10 -3
- package/src/movethewheels/components/OrderItemRow.tsx +162 -99
- package/src/movethewheels/constants/index.ts +1 -0
- package/src/movethewheels/hooks/useOrders.ts +17 -3
- package/src/movethewheels/hooks/useTracking.ts +208 -27
- package/src/movethewheels/pages/CreateOrderPage.tsx +372 -263
- package/src/movethewheels/pages/OrderDetailsPage.tsx +55 -23
- package/src/movethewheels/pages/OrdersListPage.tsx +1 -0
- package/src/movethewheels/pages/TrackingPage.tsx +44 -14
- package/src/movethewheels/types/index.ts +1 -0
- package/src/movethewheels/utils/mapMarkers.ts +1 -0
- package/src/operations/wspace/movethewheels/queries/dashboard.graphql +5 -0
- package/src/operations/wspace/movethewheels/queries/logistics.graphql +2 -2
|
@@ -79,10 +79,13 @@ const STATUS_LABELS: Record<OrderStatus, string> = {
|
|
|
79
79
|
in_transit: 'In Transit',
|
|
80
80
|
out_for_delivery: 'Out for Delivery',
|
|
81
81
|
delivered: 'Delivered',
|
|
82
|
+
returned: 'Returned',
|
|
82
83
|
cancelled: 'Cancelled',
|
|
83
84
|
failed: 'Failed',
|
|
84
85
|
};
|
|
85
86
|
|
|
87
|
+
const TERMINAL_STATUSES = new Set<OrderStatus>(['delivered', 'returned', 'cancelled', 'failed']);
|
|
88
|
+
|
|
86
89
|
function nextStatus(current: OrderStatus): OrderStatus | null {
|
|
87
90
|
const index = STATUS_FLOW.indexOf(current);
|
|
88
91
|
if (index === -1 || index >= STATUS_FLOW.length - 1) return null;
|
|
@@ -149,18 +152,31 @@ export default function OrderDetailsPage() {
|
|
|
149
152
|
}, [selectedVehicle, vehicles, vehiclesLoading]);
|
|
150
153
|
|
|
151
154
|
const handleAssign = async () => {
|
|
152
|
-
if (!orderId ||
|
|
153
|
-
setActionError('
|
|
155
|
+
if (!orderId || !order) {
|
|
156
|
+
setActionError('This order is no longer available. Refresh and try again.');
|
|
154
157
|
return;
|
|
155
158
|
}
|
|
159
|
+
|
|
160
|
+
const vehicleId = selectedVehicle || order.vehicleId;
|
|
161
|
+
const driverId = selectedDriver || order.driverId;
|
|
162
|
+
if (!vehicleId || !driverId) {
|
|
163
|
+
setActionError('Select both a compatible vehicle and driver before dispatching.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const wasFullyAssigned = Boolean(order.vehicleId && order.driverId);
|
|
156
168
|
setAssigning(true);
|
|
157
169
|
setActionError(null);
|
|
158
170
|
try {
|
|
159
|
-
await updateOrder(orderId, {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
notify(
|
|
171
|
+
await updateOrder(orderId, { vehicleId, driverId });
|
|
172
|
+
if (!wasFullyAssigned && order.status === 'confirmed') {
|
|
173
|
+
await updateOrderStatus(orderId, 'assigned');
|
|
174
|
+
}
|
|
175
|
+
notify(
|
|
176
|
+
!wasFullyAssigned && order.status === 'confirmed'
|
|
177
|
+
? 'Fleet assigned and order advanced to Assigned.'
|
|
178
|
+
: 'Assignment updated.'
|
|
179
|
+
);
|
|
164
180
|
setSelectedVehicle('');
|
|
165
181
|
setSelectedDriver('');
|
|
166
182
|
refetch();
|
|
@@ -172,7 +188,13 @@ export default function OrderDetailsPage() {
|
|
|
172
188
|
};
|
|
173
189
|
|
|
174
190
|
const handleStatusChange = async (status: OrderStatus, successMessage: string) => {
|
|
175
|
-
if (!orderId) return;
|
|
191
|
+
if (!orderId || !order) return;
|
|
192
|
+
if (status === 'assigned' && (!order.vehicleId || !order.driverId)) {
|
|
193
|
+
setActionError('Assign both a compatible vehicle and driver before advancing to Assigned.');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (TERMINAL_STATUSES.has(order.status)) return;
|
|
197
|
+
|
|
176
198
|
setAdvancing(true);
|
|
177
199
|
setActionError(null);
|
|
178
200
|
try {
|
|
@@ -635,24 +657,34 @@ export default function OrderDetailsPage() {
|
|
|
635
657
|
{(() => {
|
|
636
658
|
const upcoming = nextStatus(order.status);
|
|
637
659
|
if (!upcoming) return null;
|
|
660
|
+
const missingDispatchPair =
|
|
661
|
+
upcoming === 'assigned' && (!order.vehicleId || !order.driverId);
|
|
638
662
|
return (
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
663
|
+
<>
|
|
664
|
+
<Button
|
|
665
|
+
variant="outline"
|
|
666
|
+
className="w-full"
|
|
667
|
+
onClick={() =>
|
|
668
|
+
handleStatusChange(
|
|
669
|
+
upcoming,
|
|
670
|
+
`Order advanced to ${STATUS_LABELS[upcoming]}.`
|
|
671
|
+
)
|
|
672
|
+
}
|
|
673
|
+
disabled={advancing || missingDispatchPair}
|
|
674
|
+
>
|
|
675
|
+
<ArrowRight size={16} />
|
|
676
|
+
{advancing ? 'Updating…' : `Advance to ${STATUS_LABELS[upcoming]}`}
|
|
677
|
+
</Button>
|
|
678
|
+
{missingDispatchPair && (
|
|
679
|
+
<p className="text-xs text-text-secondary">
|
|
680
|
+
Assign both a compatible vehicle and driver before dispatching this
|
|
681
|
+
order.
|
|
682
|
+
</p>
|
|
683
|
+
)}
|
|
684
|
+
</>
|
|
653
685
|
);
|
|
654
686
|
})()}
|
|
655
|
-
{order.status !== 'cancelled' && order.status
|
|
687
|
+
{order.status !== 'cancelled' && !TERMINAL_STATUSES.has(order.status) && (
|
|
656
688
|
<Button
|
|
657
689
|
variant="outline"
|
|
658
690
|
className="w-full text-status-error-text"
|
|
@@ -195,6 +195,7 @@ export default function OrdersListPage() {
|
|
|
195
195
|
label: t('movethewheels.orders.status.outForDelivery', 'Out for Delivery'),
|
|
196
196
|
},
|
|
197
197
|
{ value: 'delivered', label: t('movethewheels.orders.status.delivered', 'Delivered') },
|
|
198
|
+
{ value: 'returned', label: t('movethewheels.orders.status.returned', 'Returned') },
|
|
198
199
|
{ value: 'cancelled', label: t('movethewheels.orders.status.cancelled', 'Cancelled') },
|
|
199
200
|
{ value: 'failed', label: t('movethewheels.orders.status.failed', 'Failed') },
|
|
200
201
|
];
|
|
@@ -60,7 +60,20 @@ export default function TrackingPage() {
|
|
|
60
60
|
? { ...destCoord, label: `Delivery · ${order.deliveryAddress.city || 'Destination'}` }
|
|
61
61
|
: null;
|
|
62
62
|
|
|
63
|
-
const
|
|
63
|
+
const trackingTrail: TrackPoint[] = (tracking?.locationHistory ?? [])
|
|
64
|
+
.map((location): TrackPoint | null => {
|
|
65
|
+
const coord = firstRealLatLng(location);
|
|
66
|
+
return coord
|
|
67
|
+
? {
|
|
68
|
+
lat: coord.lat,
|
|
69
|
+
lng: coord.lng,
|
|
70
|
+
timestamp: location.timestamp?.toISOString() ?? new Date().toISOString(),
|
|
71
|
+
}
|
|
72
|
+
: null;
|
|
73
|
+
})
|
|
74
|
+
.filter((point): point is TrackPoint => point !== null);
|
|
75
|
+
|
|
76
|
+
const statusTrail: TrackPoint[] = order.timeline
|
|
64
77
|
.map((event): TrackPoint | null => {
|
|
65
78
|
const coord = event.location ? firstRealLatLng(event.location) : null;
|
|
66
79
|
return coord
|
|
@@ -69,6 +82,7 @@ export default function TrackingPage() {
|
|
|
69
82
|
})
|
|
70
83
|
.filter((point): point is TrackPoint => point !== null);
|
|
71
84
|
|
|
85
|
+
const trail = trackingTrail.length > 0 ? trackingTrail : statusTrail;
|
|
72
86
|
const currentCoord = tracking ? firstRealLatLng(tracking.currentLocation) : null;
|
|
73
87
|
const current: TrackEndpoint | null = currentCoord
|
|
74
88
|
? {
|
|
@@ -163,7 +177,7 @@ export default function TrackingPage() {
|
|
|
163
177
|
)}
|
|
164
178
|
|
|
165
179
|
{/* Tracking Results */}
|
|
166
|
-
{order &&
|
|
180
|
+
{order && (
|
|
167
181
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
168
182
|
{/* Main Tracking Info */}
|
|
169
183
|
<div className="lg:col-span-2 space-y-6">
|
|
@@ -181,14 +195,14 @@ export default function TrackingPage() {
|
|
|
181
195
|
<p className="text-sm text-text-secondary">
|
|
182
196
|
{t('movethewheels.tracking.details.trackingNumber', 'Tracking Number')}
|
|
183
197
|
</p>
|
|
184
|
-
<p className="font-mono font-medium">{order.trackingNumber}</p>
|
|
198
|
+
<p className="font-mono font-medium">{order.trackingNumber || '—'}</p>
|
|
185
199
|
</div>
|
|
186
200
|
<div>
|
|
187
201
|
<p className="text-sm text-text-secondary">
|
|
188
202
|
{t('movethewheels.tracking.details.estimatedDelivery', 'Estimated Delivery')}
|
|
189
203
|
</p>
|
|
190
204
|
<p className="font-medium">
|
|
191
|
-
{tracking
|
|
205
|
+
{tracking?.estimatedArrival
|
|
192
206
|
? formatDate(tracking.estimatedArrival, 'full')
|
|
193
207
|
: order.scheduledDelivery
|
|
194
208
|
? formatDate(order.scheduledDelivery, 'full')
|
|
@@ -207,9 +221,21 @@ export default function TrackingPage() {
|
|
|
207
221
|
<p className="text-sm text-text-secondary">
|
|
208
222
|
{t('movethewheels.tracking.details.lastUpdated', 'Last Updated')}
|
|
209
223
|
</p>
|
|
210
|
-
<p className="font-medium">
|
|
224
|
+
<p className="font-medium">
|
|
225
|
+
{tracking
|
|
226
|
+
? formatDate(tracking.lastUpdated, 'relative')
|
|
227
|
+
: t('movethewheels.tracking.details.noUpdates', 'No tracking updates yet')}
|
|
228
|
+
</p>
|
|
211
229
|
</div>
|
|
212
230
|
</div>
|
|
231
|
+
{!tracking && (
|
|
232
|
+
<p className="mt-4 rounded-card border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary">
|
|
233
|
+
{t(
|
|
234
|
+
'movethewheels.tracking.details.noUpdatesDescription',
|
|
235
|
+
'The delivery was found, but no tracking updates have been recorded yet.'
|
|
236
|
+
)}
|
|
237
|
+
</p>
|
|
238
|
+
)}
|
|
213
239
|
</EmphasisPanel>
|
|
214
240
|
|
|
215
241
|
{/* Route Map — real origin/destination + tracking trail + live position */}
|
|
@@ -356,7 +382,7 @@ export default function TrackingPage() {
|
|
|
356
382
|
</Card>
|
|
357
383
|
|
|
358
384
|
{/* Alerts */}
|
|
359
|
-
{tracking
|
|
385
|
+
{tracking?.alerts && tracking.alerts.length > 0 && (
|
|
360
386
|
<Card>
|
|
361
387
|
<CardHeader>
|
|
362
388
|
<CardTitle className="flex items-center gap-2">
|
|
@@ -430,14 +456,18 @@ export default function TrackingPage() {
|
|
|
430
456
|
</p>
|
|
431
457
|
</div>
|
|
432
458
|
)}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
459
|
+
{tracking && (
|
|
460
|
+
<>
|
|
461
|
+
<p className="text-sm">
|
|
462
|
+
{tracking.currentLocation.address ||
|
|
463
|
+
t('movethewheels.tracking.location.updating', 'Location updating...')}
|
|
464
|
+
</p>
|
|
465
|
+
<p className="text-xs text-text-secondary mt-1">
|
|
466
|
+
{t('movethewheels.tracking.location.updated', 'Updated')}{' '}
|
|
467
|
+
{formatDate(tracking.currentLocation.timestamp || new Date(), 'relative')}
|
|
468
|
+
</p>
|
|
469
|
+
</>
|
|
470
|
+
)}
|
|
441
471
|
</CardContent>
|
|
442
472
|
</Card>
|
|
443
473
|
|
|
@@ -57,8 +57,8 @@ query GetShipment($id: ID!) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
query GetDeliveryJobTracking($deliveryJobId: ID
|
|
61
|
-
deliveryJobTracking(deliveryJobId: $deliveryJobId) {
|
|
60
|
+
query GetDeliveryJobTracking($deliveryJobId: ID!, $pagination: PaginationInput) {
|
|
61
|
+
deliveryJobTracking(deliveryJobId: $deliveryJobId, pagination: $pagination) {
|
|
62
62
|
id
|
|
63
63
|
shipmentId
|
|
64
64
|
eventType
|