updates
This commit is contained in:
@@ -5669,6 +5669,47 @@
|
|||||||
letter-spacing: 0.04em;
|
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 ---
|
/* --- Body sections ---
|
||||||
No scroll: the popup expands to fit its content. Width is the dimension
|
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
|
we constrain (via leaflet's maxWidth prop) so the body grows downward as
|
||||||
|
|||||||
@@ -1987,12 +1987,19 @@ const Dispatch = ({
|
|||||||
: riders,
|
: riders,
|
||||||
[isAllActiveView, riders, activeOrderRiderIdSet]
|
[isAllActiveView, riders, activeOrderRiderIdSet]
|
||||||
);
|
);
|
||||||
// Active section sidebar riders — built from the FULL day's unfiltered rows
|
// Active section sidebar riders — built from filteredLiveRows (the SAME
|
||||||
// (liveRows, all batches, no GPS-status gate). Uses a sticky cache so cards
|
// batch-filtered rows that drive activeStats' "Orders/Riders" header tiles
|
||||||
// only disappear when the API returns an explicit terminal status (delivered /
|
// and every other view), not the raw unfiltered liveRows. Building this off
|
||||||
// cancelled / skipped). Temporary row omissions during the 15-second poll
|
// liveRows previously showed active orders from every batch regardless of
|
||||||
// cycle (single-page refetch, brief API inconsistency) no longer cause cards
|
// the selected Morning/Afternoon/Evening pill, while the header tiles above
|
||||||
// to flash away and reappear.
|
// 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(() => {
|
const activeViewRiders = useMemo(() => {
|
||||||
if (!isAllActiveView) {
|
if (!isAllActiveView) {
|
||||||
stickyActiveRef.current = {};
|
stickyActiveRef.current = {};
|
||||||
@@ -2001,7 +2008,7 @@ const Dispatch = ({
|
|||||||
|
|
||||||
const TERMINAL = new Set(['delivered', 'cancelled', 'skipped', 'complete', 'completed']);
|
const TERMINAL = new Set(['delivered', 'cancelled', 'skipped', 'complete', 'completed']);
|
||||||
|
|
||||||
liveRows.forEach((o) => {
|
filteredLiveRows.forEach((o) => {
|
||||||
const id = String(o.orderid);
|
const id = String(o.orderid);
|
||||||
const s = String(o.orderstatus || '').toLowerCase();
|
const s = String(o.orderstatus || '').toLowerCase();
|
||||||
if (s === 'active') {
|
if (s === 'active') {
|
||||||
@@ -2035,7 +2042,7 @@ const Dispatch = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Object.values(byRider);
|
return Object.values(byRider);
|
||||||
}, [isAllActiveView, liveRows, riders]);
|
}, [isAllActiveView, filteredLiveRows, riders]);
|
||||||
|
|
||||||
// Live GPS coordinates of exactly the riders this view shows (active + has an
|
// 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.
|
// 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
|
// 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
|
// different date, zone, or batch slot — stale cards from the previous filter
|
||||||
// into the new view.
|
// must not leak into the new view.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
stickyActiveRef.current = {};
|
stickyActiveRef.current = {};
|
||||||
}, [selectedDate, selectedAppLocationId]);
|
}, [selectedDate, selectedAppLocationId, selectedBatch]);
|
||||||
|
|
||||||
// Count of in-progress deliveries shown in the Active view list. Derives from
|
// 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.
|
// the sticky cache (via activeViewRiders) so header and card list always agree.
|
||||||
@@ -2979,18 +2986,30 @@ const Dispatch = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="pu-rider">
|
<div className="pu-header-main">
|
||||||
<MdTwoWheeler /> <span>{o.rider_name || o.ridername || 'Unassigned'}</span>
|
<div className="pu-header-left">
|
||||||
</div>
|
<div className="pu-rider">
|
||||||
{(o.deliverycustomer || o.customername) && (
|
<MdTwoWheeler /> <span>{o.rider_name || o.ridername || 'Unassigned'}</span>
|
||||||
<div className="pu-customer" title={o.deliverycustomer || o.customername}>
|
</div>
|
||||||
<MdMarkunreadMailbox />
|
{(o.deliverycustomer || o.customername) && (
|
||||||
<span>{o.deliverycustomer || o.customername}</span>
|
<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>
|
</div>
|
||||||
)}
|
{o.step != null && (
|
||||||
{o.deliveryid != null && (
|
<div className="pu-header-step">
|
||||||
<div className="pu-delivery-id">Delivery #{o.deliveryid}</div>
|
<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>
|
||||||
|
|
||||||
<div className="pu-body">
|
<div className="pu-body">
|
||||||
@@ -5019,6 +5038,15 @@ const Dispatch = ({
|
|||||||
))
|
))
|
||||||
) : isAllActiveView ? (
|
) : isAllActiveView ? (
|
||||||
<ActiveSection
|
<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}
|
visibleRiders={activeViewRiders}
|
||||||
riders={riders}
|
riders={riders}
|
||||||
focusedStop={focusedStop}
|
focusedStop={focusedStop}
|
||||||
|
|||||||
Reference in New Issue
Block a user