From 3bde09839c5c62ec0c2fee1a4da52e518608c9e2 Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Mon, 28 Sep 2026 12:41:08 +0530 Subject: [PATCH] updates on the queries page and dispatch page section --- src/api/doormile/queries.js | 28 ++++++++++++++- src/pages/doormile/dispatch/Dispatch.jsx | 46 ++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/api/doormile/queries.js b/src/api/doormile/queries.js index 340f070..c477cb1 100644 --- a/src/api/doormile/queries.js +++ b/src/api/doormile/queries.js @@ -305,10 +305,36 @@ export const fetchAppLocations = async () => { try { const hubs = await getHubs(); const seen = new Map(); + // Each city also carries a map centre, so Control X can move the map + // there when the operator switches city and there are no orders yet to + // zoom to. It is the MEDIAN of the city's hub coordinates, not the mean: + // one mis-filed hub (a Chennai hub tagged as Coimbatore, say) would drag a + // mean tens of km off, while the median ignores it. Hubs with no + // coordinates (0,0 / missing) are left out. + const points = new Map(); (hubs || []).forEach((hub) => { - if (hub.applocationid != null && !seen.has(hub.applocationid)) { + if (hub.applocationid == null) return; + if (!seen.has(hub.applocationid)) { seen.set(hub.applocationid, { applocationid: hub.applocationid, locationname: hub.city || hub.hubname }); } + const lat = Number(hub.latitude); + const lng = Number(hub.longitude); + if (Number.isFinite(lat) && Number.isFinite(lng) && lat !== 0 && lng !== 0) { + const list = points.get(hub.applocationid) || []; + list.push([lat, lng]); + points.set(hub.applocationid, list); + } + }); + const median = (values) => { + const v = [...values].sort((a, b) => a - b); + const mid = Math.floor(v.length / 2); + return v.length % 2 ? v[mid] : (v[mid - 1] + v[mid]) / 2; + }; + points.forEach((list, id) => { + const loc = seen.get(id); + if (loc && list.length) { + Object.assign(loc, { latitude: median(list.map((p) => p[0])), longitude: median(list.map((p) => p[1])) }); + } }); const allLocations = [...seen.values()]; diff --git a/src/pages/doormile/dispatch/Dispatch.jsx b/src/pages/doormile/dispatch/Dispatch.jsx index d75b895..ed26353 100644 --- a/src/pages/doormile/dispatch/Dispatch.jsx +++ b/src/pages/doormile/dispatch/Dispatch.jsx @@ -564,8 +564,10 @@ const getStableRiderColor = (id) => { // call sites in this file are Leaflet divIcon HTML strings, which need a raw // hex — normal JSX should render instead. -const MapController = ({ focusedItem, viewMode, orders, kitchens, locationKey }) => { +const MapController = ({ focusedItem, viewMode, orders, kitchens, locationKey, locationCenter }) => { const map = useMap(); + // Which city the map was last moved to by the no-data fallback below. + const lastCenteredLocRef = useRef(null); // Last fit signature. We only call fitBounds when this changes — otherwise // every parent render (data refetch, sidebar tick, etc.) would refit the // map and snap it back mid-drag, which felt like the map was un-draggable. @@ -620,7 +622,28 @@ const MapController = ({ focusedItem, viewMode, orders, kitchens, locationKey }) return `${loc}m|${viewMode || ''}|${kPairs.length}|${kSig}`; }, [focusedItem, viewMode, orders, kitchens, locationKey]); + // City the fit key last belonged to. Switching city must forget the last + // fit: otherwise Coimbatore → Bangalore → Coimbatore produces the SAME + // Coimbatore fit key as before, the early-return below treats it as + // "already fitted", and the map stays parked on Bangalore. + const lastFitLocRef = useRef(locationKey); + useEffect(() => { + if (lastFitLocRef.current !== locationKey) { + lastFitLocRef.current = locationKey; + lastFitKeyRef.current = ''; + // Move to the new city IMMEDIATELY. Waiting for its data meant the map + // sat on the previous city for the 5–8s the new orders took to load, + // which read as "the dropdown didn't do anything". Skip fitting on this + // pass — whatever orders/kitchens are on hand still belong to the OLD + // city — and let the new city's data refit onto its orders when it + // arrives (the fit key changes then). + if (!focusedItem && locationCenter) { + lastCenteredLocRef.current = locationKey; + map.flyTo(locationCenter, 12, { duration: 0.8 }); + return; + } + } if (lastFitKeyRef.current === fitKey) return; let pts = []; @@ -675,7 +698,17 @@ const MapController = ({ focusedItem, viewMode, orders, kitchens, locationKey }) // bug that left Nagercoil (and every non-Coimbatore hub) stuck on the // Coimbatore default during the brief window between picking the hub // and its data arriving. - }, [fitKey, focusedItem, viewMode, orders, kitchens, map]); + // + // But a city with NO orders for the day never produces data to fit to, + // so picking Bangalore left the map sitting on Coimbatore indefinitely. + // Fall back to the selected city's own centre (its hubs' average) — the + // selected city, never a hard-coded default — once per city switch. The + // fit key stays unlocked, so orders arriving later still refit onto them. + if (focusedItem || locationKey == null || !locationCenter) return; + if (lastCenteredLocRef.current === locationKey) return; + lastCenteredLocRef.current = locationKey; + map.flyTo(locationCenter, 12, { duration: 0.8 }); + }, [fitKey, focusedItem, viewMode, orders, kitchens, map, locationKey, locationCenter]); return null; }; @@ -1283,6 +1316,14 @@ const Dispatch = ({ return match?.locationname || null; }, [appLocations, selectedAppLocationId]); + // The selected city's map centre (average of its hubs), used by + // MapController when there's nothing on the map to zoom to. + const locationCenter = useMemo(() => { + if (!appLocations) return null; + const match = appLocations.find((l) => String(l.applocationid) === String(selectedAppLocationId)); + return Number.isFinite(match?.latitude) && Number.isFinite(match?.longitude) ? [match.latitude, match.longitude] : null; + }, [appLocations, selectedAppLocationId]); + const handleLocationPick = (id) => { logger.info('Switching hub/location ID:', id); setSelectedAppLocationId(Number(id)); @@ -5430,6 +5471,7 @@ const Dispatch = ({ orders={allViewOrders} kitchens={kitchens} locationKey={selectedAppLocationId} + locationCenter={locationCenter} extraPoints={allViewLivePoints} /> {kitchens