This commit is contained in:
2026-07-01 12:50:35 +05:30
parent 1d0d7c428c
commit 360b13a467
2 changed files with 91 additions and 22 deletions

View File

@@ -5669,6 +5669,47 @@
letter-spacing: 0.04em;
}
/* Rider/customer/delivery-id stack on the left, Step badge pinned to the
right so operators can read the sequence position without opening the
Details section. */
.dispatch-container .dispatch-popup .pu-header-main {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
}
.dispatch-container .dispatch-popup .pu-header-left {
min-width: 0;
flex: 1;
}
.dispatch-container .dispatch-popup .pu-header-step {
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
padding: 4px 10px;
border-radius: 10px;
background: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
}
.dispatch-container .dispatch-popup .pu-header-step-label {
font-size: 9px;
font-weight: 800;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #7b1fa2;
}
.dispatch-container .dispatch-popup .pu-header-step-value {
font-size: 15px;
font-weight: 800;
color: #7b1fa2;
white-space: nowrap;
}
/* --- Body sections ---
No scroll: the popup expands to fit its content. Width is the dimension
we constrain (via leaflet's maxWidth prop) so the body grows downward as

View File

@@ -1987,12 +1987,19 @@ const Dispatch = ({
: riders,
[isAllActiveView, riders, activeOrderRiderIdSet]
);
// Active section sidebar riders — built from the FULL day's unfiltered rows
// (liveRows, all batches, no GPS-status gate). Uses a sticky cache so cards
// only disappear when the API returns an explicit terminal status (delivered /
// cancelled / skipped). Temporary row omissions during the 15-second poll
// cycle (single-page refetch, brief API inconsistency) no longer cause cards
// to flash away and reappear.
// Active section sidebar riders — built from filteredLiveRows (the SAME
// batch-filtered rows that drive activeStats' "Orders/Riders" header tiles
// and every other view), not the raw unfiltered liveRows. Building this off
// liveRows previously showed active orders from every batch regardless of
// the selected Morning/Afternoon/Evening pill, while the header tiles above
// it (sourced from allOrders → filteredLiveRows) reported the batch-filtered
// count — e.g. tiles reading "0 Orders" while afternoon-batch cards still
// rendered underneath. Uses a sticky cache so cards only disappear when the
// API returns an explicit terminal status (delivered / cancelled / skipped).
// Temporary row omissions during the 15-second poll cycle (single-page
// refetch, brief API inconsistency) no longer cause cards to flash away and
// reappear. The cache is reset on batch change (see the effect below) so
// switching slots doesn't leak a previous batch's sticky cards forward.
const activeViewRiders = useMemo(() => {
if (!isAllActiveView) {
stickyActiveRef.current = {};
@@ -2001,7 +2008,7 @@ const Dispatch = ({
const TERMINAL = new Set(['delivered', 'cancelled', 'skipped', 'complete', 'completed']);
liveRows.forEach((o) => {
filteredLiveRows.forEach((o) => {
const id = String(o.orderid);
const s = String(o.orderstatus || '').toLowerCase();
if (s === 'active') {
@@ -2035,7 +2042,7 @@ const Dispatch = ({
}
});
return Object.values(byRider);
}, [isAllActiveView, liveRows, riders]);
}, [isAllActiveView, filteredLiveRows, riders]);
// Live GPS coordinates of exactly the riders this view shows (active + has an
// order), fed to MapController's auto-fit so the map frames what's rendered.
@@ -2050,11 +2057,11 @@ const Dispatch = ({
);
// Clear the sticky active-order cache whenever the operator switches to a
// different date or zone — stale cards from the previous filter must not leak
// into the new view.
// different date, zone, or batch slot — stale cards from the previous filter
// must not leak into the new view.
useEffect(() => {
stickyActiveRef.current = {};
}, [selectedDate, selectedAppLocationId]);
}, [selectedDate, selectedAppLocationId, selectedBatch]);
// Count of in-progress deliveries shown in the Active view list. Derives from
// the sticky cache (via activeViewRiders) so header and card list always agree.
@@ -2979,18 +2986,30 @@ const Dispatch = ({
</span>
)}
</div>
<div className="pu-rider">
<MdTwoWheeler /> <span>{o.rider_name || o.ridername || 'Unassigned'}</span>
</div>
{(o.deliverycustomer || o.customername) && (
<div className="pu-customer" title={o.deliverycustomer || o.customername}>
<MdMarkunreadMailbox />
<span>{o.deliverycustomer || o.customername}</span>
<div className="pu-header-main">
<div className="pu-header-left">
<div className="pu-rider">
<MdTwoWheeler /> <span>{o.rider_name || o.ridername || 'Unassigned'}</span>
</div>
{(o.deliverycustomer || o.customername) && (
<div className="pu-customer" title={o.deliverycustomer || o.customername}>
<MdMarkunreadMailbox />
<span>{o.deliverycustomer || o.customername}</span>
</div>
)}
{o.deliveryid != null && (
<div className="pu-delivery-id">Delivery #{o.deliveryid}</div>
)}
</div>
)}
{o.deliveryid != null && (
<div className="pu-delivery-id">Delivery #{o.deliveryid}</div>
)}
{o.step != null && (
<div className="pu-header-step">
<span className="pu-header-step-label">Step</span>
<span className="pu-header-step-value">
{o.trip_number != null && o.trip_number > 1 ? `T${o.trip_number}·` : ''}{o.step}
</span>
</div>
)}
</div>
</div>
<div className="pu-body">
@@ -5019,6 +5038,15 @@ const Dispatch = ({
))
) : isAllActiveView ? (
<ActiveSection
// Remount on batch/date/zone change so its internal
// prevStatusMapRef (used to detect real status
// transitions and fire the "now delivering" /
// "reached location" toasts) resets. Without this,
// switching e.g. Morning → Afternoon swaps in a new
// set of orders the ref has never seen, so every
// already-active order in the new batch looks like a
// fresh transition and fires a stale toast.
key={`${selectedDate}-${selectedAppLocationId}-${selectedBatch}`}
visibleRiders={activeViewRiders}
riders={riders}
focusedStop={focusedStop}