updates on the dispatch page preview
This commit is contained in:
@@ -29,13 +29,17 @@ export const extractRiders = (previewData) => {
|
||||
map.set(key, { rider_id: riderId, rider_name: riderName, orders: [] });
|
||||
}
|
||||
const entry = map.get(key);
|
||||
(orders || []).forEach((o) => {
|
||||
const oid = o?.orderid != null ? String(o.orderid) : null;
|
||||
(orders || []).forEach((o, oIdx) => {
|
||||
const resolvedOrderId = o?.orderid || o?.bookingno || o?.bookingid || o?.order_id || o?.booking_id || o?.consignment_id || o?.id || `ord-${oIdx + 1}`;
|
||||
const oid = String(resolvedOrderId);
|
||||
if (oid) {
|
||||
if (seenOrderIds.has(oid)) return;
|
||||
seenOrderIds.add(oid);
|
||||
}
|
||||
entry.orders.push(o);
|
||||
entry.orders.push({
|
||||
...o,
|
||||
orderid: resolvedOrderId
|
||||
});
|
||||
});
|
||||
if (!entry.rider_name && riderName) entry.rider_name = riderName;
|
||||
};
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
MdTwoWheeler,
|
||||
MdLocationOn,
|
||||
MdRestaurant,
|
||||
MdMyLocation,
|
||||
MdAccessTime,
|
||||
MdInventory2,
|
||||
MdStraighten,
|
||||
MdMarkunreadMailbox,
|
||||
MdAccountBalanceWallet,
|
||||
MdNotes
|
||||
} from 'react-icons/md';
|
||||
|
||||
import { parseDoormileTimestamp } from '@/lib/doormileTimestamp';
|
||||
import { getActiveOrder } from './dispatchShared';
|
||||
import { getActiveOrder, getStatusStyle, onActivate } from './dispatchShared';
|
||||
import { OpenToast } from '@/components/third-party/OpenToast';
|
||||
|
||||
const Ico = ({ children }) => (
|
||||
<span className="ico-inline" style={{ display: 'inline-flex', alignItems: 'center', verticalAlign: '-2px', marginRight: 4 }}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
const formatTimeOnly = (t) => {
|
||||
if (!t) return null;
|
||||
const d = dayjs(t);
|
||||
if (!d.isValid()) return String(t);
|
||||
return d.format('hh:mm A');
|
||||
};
|
||||
|
||||
const ActiveSection = ({
|
||||
visibleRiders = [],
|
||||
riders = [],
|
||||
@@ -22,7 +36,6 @@ const ActiveSection = ({
|
||||
setFocusedStop,
|
||||
calculateEstMeters,
|
||||
getRiderColor,
|
||||
formatMeters,
|
||||
isLoading
|
||||
}) => {
|
||||
// Sort by live distance ascending (closest drop-off first; null/unknown last)
|
||||
@@ -64,7 +77,7 @@ const ActiveSection = ({
|
||||
OpenToast(`🛵 ${cur.riderName} is now delivering to ${cur.customer}`, 'success', 3000);
|
||||
}
|
||||
if (old.status === 'active' && cur.status === 'delivered') {
|
||||
OpenToast(`${cur.riderName} has reached ${cur.customer}'s location`, 'info', 3000);
|
||||
OpenToast(`✅ ${cur.riderName} delivered to ${cur.customer}`, 'success', 3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -96,140 +109,139 @@ const ActiveSection = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3.5 w-full pb-4">
|
||||
{activeDeliveries.map((o) => {
|
||||
<div className="zone-order-grid w-full pb-4">
|
||||
{activeDeliveries.map((o, idx) => {
|
||||
const rid = o.rider_id || o.userid;
|
||||
const rider = riders.find((r) => String(r.id) === String(rid));
|
||||
const color = getRiderColor(rid) || '#0284c7';
|
||||
const lat = parseFloat(o.droplat || o.deliverylat);
|
||||
const lon = parseFloat(o.droplon || o.deliverylong);
|
||||
const canFocus = Number.isFinite(lat) && Number.isFinite(lon);
|
||||
const estMeters = calculateEstMeters(rid, o);
|
||||
const customer = o.deliverycustomer || o.customername || `Order #${o.orderid}`;
|
||||
const dropArea = o.deliverysuburb || o.deliveryaddress || o.zone_name || '';
|
||||
const riderName = o.rider_name || o.ridername || 'Unassigned';
|
||||
const isSelected = canFocus && focusedStop && String(focusedStop.orderid) === String(o.orderid);
|
||||
const initials =
|
||||
riderName
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map((w) => w[0])
|
||||
.join('')
|
||||
.toUpperCase() || '•';
|
||||
const isStopActive = focusedStop && String(focusedStop.orderid) === String(o.orderid);
|
||||
const statusStyle = getStatusStyle(o.orderstatus);
|
||||
const profit = parseFloat(o.profit || 0);
|
||||
const isLoss = profit < 0;
|
||||
|
||||
const deliveredAt = o.deliverytime
|
||||
? parseDoormileTimestamp(o.deliverytime).isValid()
|
||||
? parseDoormileTimestamp(o.deliverytime).format('hh:mm A')
|
||||
: String(o.deliverytime)
|
||||
: null;
|
||||
|
||||
const etaMin = estMeters !== null ? (estMeters / 1000 / 20) * 60 : null;
|
||||
const totalDistanceKm = Number(o.actualkms || o.kms || 0);
|
||||
const actual = formatTimeOnly(o.deliverytime);
|
||||
const expected = formatTimeOnly(o.expecteddeliverytime);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={o.orderid}
|
||||
className={`zone-order-card going-on ${canFocus ? 'clickable' : ''} ${isStopActive ? 'active' : ''}`}
|
||||
role={canFocus ? 'button' : undefined}
|
||||
tabIndex={canFocus ? 0 : undefined}
|
||||
onClick={() => {
|
||||
if (rider) handleRiderFocus(rider);
|
||||
if (canFocus) setFocusedStop({ orderid: o.orderid, lat, lon });
|
||||
if (canFocus) setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon });
|
||||
}}
|
||||
className={`group bg-white rounded-xl border p-4 transition-all duration-150 cursor-pointer shadow-2xs select-none relative overflow-hidden ${
|
||||
isSelected
|
||||
? 'border-blue-600 ring-2 ring-blue-500/20 bg-blue-50/20 shadow-sm'
|
||||
: 'border-slate-200/90 hover:border-slate-300 hover:shadow-xs'
|
||||
}`}
|
||||
onKeyDown={
|
||||
canFocus
|
||||
? onActivate(() => {
|
||||
if (rider) handleRiderFocus(rider);
|
||||
setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon });
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
title={
|
||||
canFocus
|
||||
? isStopActive
|
||||
? 'Click to show full trip'
|
||||
: `Show ${o.deliverycustomer || o.customername || `order #${o.orderid}`} on map`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{/* Top Accent Strip */}
|
||||
<div
|
||||
className="absolute top-0 left-0 right-0 h-1"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
|
||||
{/* Header: Rider Avatar + Customer Name + Status Badge */}
|
||||
<div className="flex items-start justify-between gap-3 pt-1">
|
||||
<div className="flex items-center gap-2.5 min-w-0 flex-1">
|
||||
<div
|
||||
className="w-8 h-8 rounded-lg shrink-0 flex items-center justify-center font-black text-white text-xs shadow-xs"
|
||||
style={{ backgroundColor: color }}
|
||||
>
|
||||
{initials}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h4 className="font-bold text-slate-900 text-xs tracking-tight truncate" title={customer}>
|
||||
{customer}
|
||||
</h4>
|
||||
<div className="text-[10px] font-mono text-slate-400 mt-0.5">
|
||||
Order #{o.orderid} {o.trip_number ? `· Trip ${o.trip_number}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
{/* Header: Step Number Box + Order ID + Status Stack */}
|
||||
<div className="zone-order-card-head">
|
||||
<div
|
||||
className="zone-order-num"
|
||||
style={{ background: color, borderColor: color }}
|
||||
title={`Planned step ${o.step || idx + 1}`}
|
||||
>
|
||||
{o.step || idx + 1}
|
||||
</div>
|
||||
|
||||
<span className="inline-flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wider px-2.5 py-0.5 rounded-full bg-emerald-50 text-emerald-700 border border-emerald-200 shrink-0">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
|
||||
{o.orderstatus || 'Active'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Middle: Rider Info & Locations */}
|
||||
<div className="mt-3 pt-2.5 border-t border-slate-100 space-y-1.5 text-xs">
|
||||
<div className="flex items-center gap-2 text-slate-700 font-semibold truncate">
|
||||
<div className="w-5 h-5 rounded-md bg-slate-100 text-slate-600 flex items-center justify-center shrink-0">
|
||||
<MdTwoWheeler className="w-3.5 h-3.5" />
|
||||
</div>
|
||||
<span className="truncate">{riderName}</span>
|
||||
<div className="zone-order-id-block">
|
||||
<div className="zone-order-id">Order #{o.orderid}</div>
|
||||
</div>
|
||||
|
||||
{dropArea && (
|
||||
<div className="flex items-center gap-2 text-slate-500 text-[11px] truncate" title={dropArea}>
|
||||
<div className="w-5 h-5 rounded-md bg-slate-50 text-slate-400 flex items-center justify-center shrink-0">
|
||||
<MdLocationOn className="w-3.5 h-3.5 text-orange-500" />
|
||||
</div>
|
||||
<span className="truncate">{dropArea}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{o.pickupcustomer && (
|
||||
<div className="flex items-center gap-2 text-slate-500 text-[11px] truncate" title={o.pickupcustomer}>
|
||||
<div className="w-5 h-5 rounded-md bg-slate-50 text-slate-400 flex items-center justify-center shrink-0">
|
||||
<MdRestaurant className="w-3.5 h-3.5 text-amber-500" />
|
||||
</div>
|
||||
<span className="truncate">{o.pickupcustomer}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bottom Metrics Bar */}
|
||||
<div className="mt-3 pt-2.5 border-t border-slate-100 flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{totalDistanceKm > 0 && (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] font-mono font-medium text-slate-600 bg-slate-50 px-2 py-0.5 rounded border border-slate-200/60">
|
||||
<MdStraighten className="w-3 h-3 text-slate-400" />
|
||||
{totalDistanceKm.toFixed(1)} km
|
||||
</span>
|
||||
)}
|
||||
|
||||
{deliveredAt && (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] font-mono text-slate-500">
|
||||
<MdAccessTime className="w-3 h-3 text-slate-400" />
|
||||
{deliveredAt}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{estMeters !== null && (
|
||||
<div className="inline-flex items-center gap-1.5 text-[11px] font-mono font-bold text-sky-900 bg-sky-50 px-2.5 py-0.5 rounded-full border border-sky-200/80">
|
||||
<MdMyLocation className="w-3 h-3 text-sky-600 animate-spin-slow" />
|
||||
<span>{formatMeters(estMeters)}</span>
|
||||
{etaMin !== null && (
|
||||
<>
|
||||
<span className="text-sky-300">·</span>
|
||||
<span className="text-sky-700">{etaMin < 1 ? '< 1m' : `${Math.ceil(etaMin)}m`}</span>
|
||||
</>
|
||||
{(o.orderstatus || actual || expected) && (
|
||||
<div className="zone-order-status-stack">
|
||||
{o.orderstatus && (
|
||||
<span
|
||||
className="zone-order-status"
|
||||
style={{ background: statusStyle.bg, color: statusStyle.fg }}
|
||||
>
|
||||
{statusStyle.label}
|
||||
</span>
|
||||
)}
|
||||
{(actual || expected) && (
|
||||
<span
|
||||
className={`zone-order-time ${actual ? '' : 'is-expected'}`}
|
||||
title={actual ? `Delivered at ${actual}` : `Expected at ${expected}`}
|
||||
>
|
||||
<MdAccessTime />
|
||||
{actual || expected}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Customer */}
|
||||
<div className="zone-order-customer">
|
||||
<Ico>
|
||||
<MdMarkunreadMailbox />
|
||||
</Ico>
|
||||
{o.deliverycustomer || o.customername || '—'}
|
||||
</div>
|
||||
|
||||
{/* Kitchen */}
|
||||
{o.pickupcustomer && (
|
||||
<div className="zone-order-line" title={`Kitchen: ${o.pickupcustomer}`}>
|
||||
<Ico>
|
||||
<MdRestaurant />
|
||||
</Ico>
|
||||
{o.pickupcustomer}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Drop Location */}
|
||||
{(o.deliverysuburb || o.deliveryaddress) && (
|
||||
<div className="zone-order-line" title={o.deliveryaddress || o.deliverysuburb}>
|
||||
<Ico>
|
||||
<MdLocationOn />
|
||||
</Ico>
|
||||
{o.deliverysuburb || o.deliveryaddress}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Notes */}
|
||||
{o.ordernotes && (
|
||||
<div className="zone-order-line zone-order-notes" title={o.ordernotes}>
|
||||
<Ico>
|
||||
<MdNotes />
|
||||
</Ico>
|
||||
{o.ordernotes}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stats Chips */}
|
||||
<div className="zone-order-stats">
|
||||
<span className="zone-order-chip" title="Distance">
|
||||
<Ico>
|
||||
<MdStraighten />
|
||||
</Ico>
|
||||
{Number(o.actualkms || o.kms || 0).toFixed(2)} km
|
||||
</span>
|
||||
<span className={`zone-order-chip ${isLoss ? 'is-loss' : 'is-profit'}`} title="Profit">
|
||||
<Ico>
|
||||
<MdAccountBalanceWallet />
|
||||
</Ico>
|
||||
{isLoss ? '-' : ''}₹{Math.abs(profit).toFixed(0)}
|
||||
</span>
|
||||
<span className="zone-order-chip zone-order-trip">
|
||||
T{o.trip_number || 1} · S{o.step || idx + 1}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1663,7 +1663,19 @@ const Dispatch = ({
|
||||
// delivers to, which kitchens it picks up from, and the order-status breakdown.
|
||||
const zoneCards = useMemo(() => {
|
||||
const source = data || liveData || { zones: [], zone_summary: [] };
|
||||
const zonesArr = source.zones || [];
|
||||
const rawZones = source.zones || [];
|
||||
const zonesArr = rawZones.map((z, zIdx) => ({
|
||||
...z,
|
||||
riders: (z.riders || []).map((r, rIdx) => ({
|
||||
...r,
|
||||
orders: (r.orders || []).map((o, oIdx) => ({
|
||||
...o,
|
||||
orderid: o.orderid || o.bookingno || o.bookingid || o.order_id || o.booking_id || o.consignment_id || o.id || `ord-${zIdx}-${rIdx}-${oIdx + 1}`,
|
||||
trip_number: o.trip_number || 1,
|
||||
step: o.step || oIdx + 1
|
||||
}))
|
||||
}))
|
||||
}));
|
||||
const summaryByName = {};
|
||||
(source.zone_summary || []).forEach((s) => {
|
||||
summaryByName[s.zone_name] = s;
|
||||
@@ -1714,25 +1726,44 @@ const Dispatch = ({
|
||||
const { riders, kitchens, allOrders, stats } = useMemo(() => {
|
||||
const source = data || liveData || { zones: [], zone_summary: [] };
|
||||
const orders = [];
|
||||
(source.zones || []).forEach((z) => {
|
||||
(z.riders || []).forEach((r) => {
|
||||
r.orders.forEach((o) => {
|
||||
orders.push({ ...o, zone_name: z.zone_name, rider_name: r.rider_name, rider_id: r.rider_id });
|
||||
(source.zones || []).forEach((z, zIdx) => {
|
||||
(z.riders || []).forEach((r, rIdx) => {
|
||||
(r.orders || []).forEach((o, oIdx) => {
|
||||
const resolvedOrderId = o.orderid || o.bookingno || o.bookingid || o.order_id || o.booking_id || o.consignment_id || o.id || `ord-${zIdx}-${rIdx}-${oIdx + 1}`;
|
||||
orders.push({
|
||||
...o,
|
||||
orderid: resolvedOrderId,
|
||||
zone_name: z.zone_name,
|
||||
rider_name: r.rider_name || o.rider_name,
|
||||
rider_id: r.rider_id ?? o.rider_id ?? o.userid
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (orders.length === 0 && Array.isArray(source.details)) {
|
||||
source.details.forEach((o, oIdx) => {
|
||||
const resolvedOrderId = o.orderid || o.bookingno || o.bookingid || o.order_id || o.booking_id || o.consignment_id || o.id || `ord-${oIdx + 1}`;
|
||||
orders.push({
|
||||
...o,
|
||||
orderid: resolvedOrderId,
|
||||
rider_id: o.rider_id ?? o.userid,
|
||||
rider_name: o.rider_name || o.ridername || o.rider
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const riderMap = {};
|
||||
|
||||
// First, populate riderMap with all riders present in the zones to capture those with 0 orders
|
||||
(source.zones || []).forEach((z) => {
|
||||
(z.riders || []).forEach((r) => {
|
||||
const key = r.rider_id;
|
||||
if (!key || key === 'unassigned') return;
|
||||
const key = String(r.rider_id ?? r.userid ?? '');
|
||||
if (!key || key === 'unassigned' || key === '0') return;
|
||||
if (!riderMap[key]) {
|
||||
riderMap[key] = {
|
||||
id: key,
|
||||
riderName: r.rider_name || r.username || key,
|
||||
riderName: r.rider_name || r.username || `Rider ${key}`,
|
||||
orders: [],
|
||||
color: RIDER_COLORS[Object.keys(riderMap).length % RIDER_COLORS.length]
|
||||
};
|
||||
@@ -1742,17 +1773,18 @@ const Dispatch = ({
|
||||
|
||||
// Next, map the flat orders list to the riders
|
||||
orders.forEach((o) => {
|
||||
const key = o.rider_id || o.userid || 'unknown';
|
||||
if (key === 'unassigned') return;
|
||||
const key = String(o.rider_id ?? o.userid ?? '');
|
||||
if (!key || key === 'unassigned' || key === '0') return;
|
||||
if (!riderMap[key]) {
|
||||
riderMap[key] = {
|
||||
id: key,
|
||||
riderName: o.rider_name || o.username || o.rider || key,
|
||||
riderName: o.rider_name || o.username || o.rider || `Rider ${key}`,
|
||||
orders: [],
|
||||
color: RIDER_COLORS[Object.keys(riderMap).length % RIDER_COLORS.length]
|
||||
};
|
||||
}
|
||||
if (!riderMap[key].orders.some((existing) => existing.orderid === o.orderid)) {
|
||||
const orderIdStr = String(o.orderid);
|
||||
if (!riderMap[key].orders.some((existing) => String(existing.orderid) === orderIdStr)) {
|
||||
riderMap[key].orders.push(o);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,6 +79,38 @@ const tuningTypes = [
|
||||
{ tuneid: 4, type: 'Zone Strict', value: 'zone_strict' }
|
||||
];
|
||||
|
||||
// Normalise preview data so every order carries an explicit `orderid` (falling
|
||||
// back to bookingno/bookingid/id) and step/trip fields.
|
||||
export const normalizePreviewData = (previewData) => {
|
||||
if (!previewData) return null;
|
||||
const next = JSON.parse(JSON.stringify(previewData));
|
||||
if (Array.isArray(next.zones)) {
|
||||
next.zones.forEach((z, zIdx) => {
|
||||
if (Array.isArray(z.riders)) {
|
||||
z.riders.forEach((r, rIdx) => {
|
||||
if (Array.isArray(r.orders)) {
|
||||
r.orders = r.orders.map((o, oIdx) => ({
|
||||
...o,
|
||||
orderid: o.orderid || o.bookingno || o.bookingid || o.order_id || o.booking_id || o.consignment_id || o.id || `ord-${zIdx}-${rIdx}-${oIdx + 1}`,
|
||||
step: o.step || oIdx + 1,
|
||||
trip_number: o.trip_number || 1
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (Array.isArray(next.details)) {
|
||||
next.details = next.details.map((o, oIdx) => ({
|
||||
...o,
|
||||
orderid: o.orderid || o.bookingno || o.bookingid || o.order_id || o.booking_id || o.consignment_id || o.id || `ord-${oIdx + 1}`,
|
||||
step: o.step || oIdx + 1,
|
||||
trip_number: o.trip_number || 1
|
||||
}));
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
// Flatten the API's zoned shape into [{ rider_id, rider_name, orders }] for
|
||||
// the Reconcile tab UI and the reconcile-API payload.
|
||||
const extractRiders = (previewData) => {
|
||||
@@ -92,13 +124,17 @@ const extractRiders = (previewData) => {
|
||||
map.set(key, { rider_id: riderId, rider_name: riderName, orders: [] });
|
||||
}
|
||||
const entry = map.get(key);
|
||||
(orders || []).forEach((o) => {
|
||||
const oid = o?.orderid != null ? String(o.orderid) : null;
|
||||
(orders || []).forEach((o, oIdx) => {
|
||||
const resolvedOrderId = o?.orderid || o?.bookingno || o?.bookingid || o?.order_id || o?.booking_id || o?.consignment_id || o?.id || `ord-${oIdx + 1}`;
|
||||
const oid = String(resolvedOrderId);
|
||||
if (oid) {
|
||||
if (seenOrderIds.has(oid)) return;
|
||||
seenOrderIds.add(oid);
|
||||
}
|
||||
entry.orders.push(o);
|
||||
entry.orders.push({
|
||||
...o,
|
||||
orderid: resolvedOrderId
|
||||
});
|
||||
});
|
||||
if (!entry.rider_name && riderName) entry.rider_name = riderName;
|
||||
};
|
||||
@@ -297,7 +333,7 @@ const Preview = () => {
|
||||
const stateData = location.state || {};
|
||||
const isMobile = useIsNarrowViewport();
|
||||
|
||||
const [dispatchPreviewData, setDispatchPreviewData] = useState(stateData.dispatchPreviewData || null);
|
||||
const [dispatchPreviewData, setDispatchPreviewData] = useState(() => normalizePreviewData(stateData.dispatchPreviewData));
|
||||
|
||||
useEffect(() => {
|
||||
if (!stateData.dispatchPreviewData) {
|
||||
@@ -405,7 +441,7 @@ const Preview = () => {
|
||||
mutationFn: aiMode == 0 ? createOptimisationDeliveries : createAutomationDeliveries,
|
||||
onSuccess: (data) => {
|
||||
OpenToast('Orders Optimised Successfully', 'success', 2000);
|
||||
setDispatchPreviewData(data);
|
||||
setDispatchPreviewData(normalizePreviewData(data));
|
||||
setHasReconciled(false);
|
||||
setDirtyRiderIds(new Set());
|
||||
setIsLoading(false);
|
||||
@@ -443,7 +479,7 @@ const Preview = () => {
|
||||
onSuccess: (data) => {
|
||||
logger.debug('reconcile: response', data);
|
||||
if (Array.isArray(data?.riders)) {
|
||||
setDispatchPreviewData((prev) => applyReconcileResponse(prev, data));
|
||||
setDispatchPreviewData((prev) => normalizePreviewData(applyReconcileResponse(prev, data)));
|
||||
setHasReconciled(true);
|
||||
setDirtyRiderIds((prev) => {
|
||||
const next = new Set(prev);
|
||||
|
||||
Reference in New Issue
Block a user