diff --git a/src/pages/nearle/dispatch/Dispatch.js b/src/pages/nearle/dispatch/Dispatch.js index 791f9ec..774b763 100644 --- a/src/pages/nearle/dispatch/Dispatch.js +++ b/src/pages/nearle/dispatch/Dispatch.js @@ -785,11 +785,7 @@ const Dispatch = ({ selectedRiderId, onRiderSelect, // Highlight a single marker (e.g. on table-row hover). Adds a `.pulse` class to that cmark. - pulseOrderId, - // Optional. When provided, focused-rider order cards render a small "change rider" - // icon in their header. Receiving callsite owns the rider-picker dialog. Standalone - // /dispatch usage leaves this undefined so the icon never appears there. - onChangeRider + pulseOrderId }) => { // Default to "By Zone" when the caller passes pre-zoned data (AI preview); fall back to // "By Rider" for the standalone live page where zones are synthesized but riders are primary. @@ -4131,19 +4127,6 @@ const Dispatch = ({ ); })()} - {onChangeRider && ( - - )}
diff --git a/src/pages/nearle/dispatch/Preview.js b/src/pages/nearle/dispatch/Preview.js index 0f3999a..c372f8f 100644 --- a/src/pages/nearle/dispatch/Preview.js +++ b/src/pages/nearle/dispatch/Preview.js @@ -1,35 +1,28 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { - Autocomplete, Backdrop, Box, Button, Card, Chip, - Dialog, - DialogActions, - DialogContent, - DialogTitle, IconButton, Stack, Tab, Tabs, - TextField, Tooltip, Typography } from '@mui/material'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; import dayjs from 'dayjs'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { HiOutlineArrowLeft } from 'react-icons/hi'; import { IoReload } from 'react-icons/io5'; -import { MdTwoWheeler, MdSwapHoriz } from 'react-icons/md'; +import { MdTwoWheeler } from 'react-icons/md'; import { createAutomationDeliveries, createOptimisationDeliveries, - fetchRidersList, finalCreatedeliveries, notifyRider, reconcileSteps @@ -117,78 +110,6 @@ const flattenRiders = (riders) => { return out; }; -// Move one order from oldRiderId -> newRiderId inside dispatchPreviewData. -// Mutates both the zones[].riders[].orders[] tree (so the Dispatch tab -// renders the change) AND the flat details[] list (so Assign Orders picks -// it up). Returns a NEW preview object (immutable update). -const moveOrderInPreviewData = (preview, { orderId, newRiderId, newRiderName }) => { - if (!preview) return preview; - const next = JSON.parse(JSON.stringify(preview)); - - // 1) Update flat details list - if (Array.isArray(next.details)) { - next.details = next.details.map((o) => - String(o.orderid) === String(orderId) - ? { ...o, rider_id: newRiderId, userid: newRiderId, rider_name: newRiderName, rider: newRiderName } - : o - ); - } - - // 2) Move within zones[].riders[].orders[] - if (Array.isArray(next.zones)) { - let movedOrder = null; - let homeZoneIdx = -1; - - for (let zi = 0; zi < next.zones.length && !movedOrder; zi++) { - const zone = next.zones[zi]; - if (!Array.isArray(zone.riders)) continue; - for (let ri = 0; ri < zone.riders.length && !movedOrder; ri++) { - const r = zone.riders[ri]; - if (!Array.isArray(r.orders)) continue; - const oi = r.orders.findIndex((o) => String(o.orderid) === String(orderId)); - if (oi !== -1) { - movedOrder = r.orders[oi]; - r.orders.splice(oi, 1); - homeZoneIdx = zi; - } - } - } - - if (movedOrder) { - const updated = { - ...movedOrder, - rider_id: newRiderId, - userid: newRiderId, - rider_name: newRiderName, - rider: newRiderName - }; - let placed = false; - for (const zone of next.zones) { - if (!Array.isArray(zone.riders)) continue; - const target = zone.riders.find( - (r) => String(r.rider_id ?? r.userid) === String(newRiderId) - ); - if (target) { - target.orders = target.orders || []; - target.orders.push(updated); - placed = true; - break; - } - } - if (!placed && homeZoneIdx >= 0) { - next.zones[homeZoneIdx].riders.push({ - rider_id: newRiderId, - userid: newRiderId, - rider_name: newRiderName, - orders: [updated] - }); - } - } - } - - return next; -}; - // Merge a reconcile-API response { riders:[{rider_id, orders}] } back into // dispatchPreviewData. Replaces each rider's orders[] in zones (preserving // zone containment), then rebuilds the flat details list from the new tree. @@ -319,12 +240,6 @@ const Preview = () => { // server-side step re-ordering only needs to see what actually changed. const [dirtyRiderIds, setDirtyRiderIds] = useState(() => new Set()); - // Change-rider dialog state - const [changeDialogOpen, setChangeDialogOpen] = useState(false); - const [selectedOrder, setSelectedOrder] = useState(null); - const [selectedOldRiderId, setSelectedOldRiderId] = useState(null); - const [selectedNewRider, setSelectedNewRider] = useState(null); - const aiMode = stateData.aiMode ?? 1; const selectedMode = stateData.selectedMode || null; const deliveryData = stateData.deliveryData || []; @@ -341,16 +256,8 @@ const Preview = () => { return 0; }, [stateData.appId]); - const { data: ridersList } = useQuery({ - queryKey: ['ridersList', appId], - queryFn: fetchRidersList, - enabled: !!appId, - staleTime: 5 * 60 * 1000 - }); - // Derived: rider list for the Reconcile tab. Recomputes whenever the cache - // (dispatchPreviewData) changes — so Change Rider / Reconcile both reflect - // here without a separate state. + // (dispatchPreviewData) changes — so Reconcile reflects here without a separate state. const reconcileRiders = useMemo(() => extractRiders(dispatchPreviewData), [dispatchPreviewData]); // Derived: flat orders list used for the Assign Orders payload + CSV export. @@ -508,47 +415,6 @@ const Preview = () => { }); }; - const openChangeRider = (oldRider, order) => { - const oldId = - oldRider?.rider_id ?? oldRider?.id ?? order?.rider_id ?? order?.userid ?? null; - setSelectedOldRiderId(oldId); - setSelectedOrder(order); - setSelectedNewRider(null); - setChangeDialogOpen(true); - }; - - const confirmChangeRider = () => { - if (!selectedNewRider || !selectedOrder) return; - // Backend expects an int — coerce at the boundary so a string from the - // riders API doesn't propagate into the Assign Orders payload. - const newRiderId = Number(selectedNewRider.userid); - const newRiderName = - selectedNewRider.label || - `${selectedNewRider.firstname || ''} ${selectedNewRider.lastname || ''}`.trim() || - `Rider ${newRiderId}`; - - setDispatchPreviewData((prev) => - moveOrderInPreviewData(prev, { - orderId: selectedOrder.orderid, - oldRiderId: selectedOldRiderId, - newRiderId, - newRiderName - }) - ); - // Both riders' step sequences are now potentially stale: the old rider - // lost a stop, the new rider gained one. Mark both as dirty so the next - // Reconcile sends exactly these two. - setDirtyRiderIds((prev) => { - const next = new Set(prev); - if (selectedOldRiderId != null) next.add(String(selectedOldRiderId)); - if (newRiderId != null && Number.isFinite(newRiderId)) next.add(String(newRiderId)); - return next; - }); - setHasReconciled(false); - setChangeDialogOpen(false); - OpenToast('Rider changed — click Reconcile to verify steps', 'info', 2500); - }; - return ( { {dispatchPreviewData && ( openChangeRider(focusedRider, order)} /> )} - setChangeDialogOpen(false)} maxWidth="xs" fullWidth> - Change Rider - - - Move order #{selectedOrder?.orderid} (step {selectedOrder?.step ?? '—'}) to: - - - o?.label || `${o?.firstname || ''} ${o?.lastname || ''}`.trim() || '' - } - value={selectedNewRider} - onChange={(e, val) => setSelectedNewRider(val)} - renderInput={(params) => } - /> - - - - - - ); };