updates on the activeSection and dispatch

This commit is contained in:
2026-06-18 15:05:29 +05:30
parent 892f8fbc5d
commit 3e0772ffb8
2 changed files with 93 additions and 18 deletions

View File

@@ -7,6 +7,7 @@ import {
MdMyLocation,
MdInventory2
} from 'react-icons/md';
import dayjs from 'dayjs';
import { getStatusStyle, getActiveOrder } from './dispatchShared';
const ActiveSection = ({
@@ -83,6 +84,7 @@ const ActiveSection = ({
<span className="adcard-tx">{riderName}</span>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: '4px' }}>
<span
className="adcard-status"
style={{ background: `${statusStyle.bg}1a`, color: statusStyle.bg }}
@@ -90,6 +92,12 @@ const ActiveSection = ({
>
{statusStyle.label}
</span>
{o.deliverytime && (
<span className="adcard-time" style={{ fontSize: '11px', color: '#64748b' }}>
{dayjs(o.deliverytime).isValid() ? dayjs(o.deliverytime).format('HH:mm:ss') : String(o.deliverytime)}
</span>
)}
</div>
</div>
{dropArea && (

View File

@@ -800,8 +800,46 @@ const MapController = ({ focusedItem, viewMode, orders, kitchens, locationKey })
// automatically. Either way motion is smooth and never freezes mid-trip.
// `duration` is only the seed used for the very first segment (no prior fix to
// measure against yet).
const MIN_GLIDE_MS = 800; // floor: don't animate faster than this even on rapid fixes
const MAX_GLIDE_MS = 32_000; // ceiling: cover the ~30s backend cadence + small buffer
const MIN_GLIDE_MS = 200; // floor: don't animate faster than this even on rapid fixes
const MAX_GLIDE_MS = 2500; // ceiling: tighter ceiling for 1s update cadence
const interpolatePath = (path, t) => {
if (!path || path.length === 0) return null;
if (path.length === 1) return path[0];
if (t <= 0) return path[0];
if (t >= 1) return path[path.length - 1];
const segmentDistances = [];
let totalDistance = 0;
for (let i = 0; i < path.length - 1; i++) {
const p1 = path[i];
const p2 = path[i + 1];
const dLat = p2[0] - p1[0];
const dLng = p2[1] - p1[1];
const dist = Math.sqrt(dLat * dLat + dLng * dLng);
segmentDistances.push(dist);
totalDistance += dist;
}
if (totalDistance === 0) return path[0];
const targetDistance = t * totalDistance;
let accumulatedDistance = 0;
for (let i = 0; i < segmentDistances.length; i++) {
const nextDistance = accumulatedDistance + segmentDistances[i];
if (nextDistance >= targetDistance) {
const segT = (targetDistance - accumulatedDistance) / segmentDistances[i];
const p1 = path[i];
const p2 = path[i + 1];
return [
p1[0] + (p2[0] - p1[0]) * segT,
p1[1] + (p2[1] - p1[1]) * segT
];
}
accumulatedDistance = nextDistance;
}
return path[path.length - 1];
};
const AnimatedRiderMarker = ({ target, icon, duration = 950, zIndexOffset, eventHandlers, children, markerRef: externalRef }) => {
const markerRef = useRef(null);
const rafRef = useRef(null);
@@ -861,17 +899,46 @@ const AnimatedRiderMarker = ({ target, icon, duration = 950, zIndexOffset, event
prevFixTsRef.current = startTs;
const startLat = from.lat;
const startLng = from.lng;
let active = true;
let osrmPath = null;
// Fetch OSRM route for this step so the bike follows the roads
const fetchOsrmPath = async () => {
const url = `https://router.project-osrm.org/route/v1/driving/${from.lng},${from.lat};${to.lng},${to.lat}?overview=full&geometries=geojson`;
try {
const res = await fetch(url);
const json = await res.json();
if (active && json.routes && json.routes[0]) {
osrmPath = json.routes[0].geometry.coordinates.map(c => [c[1], c[0]]);
}
} catch (e) {
console.error('OSRM animated rider marker fetch error:', e);
}
};
fetchOsrmPath();
const step = (now) => {
if (!active) return;
const t = Math.min(1, (now - startTs) / segMs);
// Linear interpolation → constant speed. Spanning the glide across the
// full inter-fix interval chains consecutive segments into one continuous
// motion (a vehicle moving down the road) rather than the accelerate/brake
// feel an easing curve gives, or the dart-then-freeze of a fixed duration.
if (osrmPath && osrmPath.length >= 2) {
const pos = interpolatePath(osrmPath, t);
if (pos) {
marker.setLatLng(pos);
} else {
marker.setLatLng([startLat + dLat * t, startLng + dLng * t]);
}
} else {
// Fallback to linear interpolation if OSRM route isn't available
marker.setLatLng([startLat + dLat * t, startLng + dLng * t]);
}
if (t < 1) rafRef.current = requestAnimationFrame(step);
};
rafRef.current = requestAnimationFrame(step);
return () => {
active = false;
if (rafRef.current) cancelAnimationFrame(rafRef.current);
};
}, [lat, lon, duration]);
@@ -1455,13 +1522,13 @@ const Dispatch = ({
// hub (latitude/longitude/logdate/status). We render those positions as
// markers on the main dispatch map so the operator sees where each rider
// actually is — matching the Reports → Riders Logs page.
const RIDER_LOG_POLL_MS = 15000;
const RIDER_LOG_POLL_MS = 1000;
const { data: ridersLocationLogs } = useQuery({
queryKey: [selectedAppLocationId, selectedDate, ''],
queryFn: fetchRidersLogs,
refetchInterval: RIDER_LOG_POLL_MS,
refetchIntervalInBackground: false,
staleTime: 5 * 1000,
staleTime: 0,
refetchOnWindowFocus: false
});
@@ -4143,7 +4210,7 @@ const Dispatch = ({
</div>
*/}
{(focusedRider || focusedKitchen) ? (
{((focusedRider && !isAllActiveView) || focusedKitchen) ? (
<div id="route-detail">
<button className="rd-back" onClick={() => { handleRiderFocus(null); setFocusedKitchen(null); }}> Back to {focusedZone ? focusedZone.name : 'list'}</button>
{focusedRider ? (
@@ -5028,7 +5095,7 @@ const Dispatch = ({
// existing views behave exactly as they did before.
const LiveMarker = isAllActiveView ? AnimatedRiderMarker : Marker;
const positionProps = isAllActiveView
? { target: [r.lat, r.lon], duration: 15000 }
? { target: [r.lat, r.lon], duration: 1000 }
: { position: [r.lat, r.lon] };
return (
<LiveMarker