updates on the queries page and dispatch page section

This commit is contained in:
2026-09-28 12:41:08 +05:30
parent 912f3cbcd4
commit 3bde09839c
2 changed files with 71 additions and 3 deletions

View File

@@ -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()];

View File

@@ -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 <StatusBadge> 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