updates on the active section and the dispatch page section regarding the active order details
This commit is contained in:
@@ -26,9 +26,7 @@ const ActiveSection = ({
|
|||||||
}) => {
|
}) => {
|
||||||
// Sort by live distance ascending (closest drop-off first; null/unknown last)
|
// Sort by live distance ascending (closest drop-off first; null/unknown last)
|
||||||
const activeDeliveries = visibleRiders
|
const activeDeliveries = visibleRiders
|
||||||
.map((r) => getActiveOrder(r.orders))
|
.flatMap((r) => (r.orders || []).filter((o) => String(o.orderstatus || '').toLowerCase() === 'active'))
|
||||||
.filter(Boolean)
|
|
||||||
.filter((o) => String(o.orderstatus || '').toLowerCase() === 'active')
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const mA = calculateEstMeters(a.rider_id || a.userid, a) ?? Infinity;
|
const mA = calculateEstMeters(a.rider_id || a.userid, a) ?? Infinity;
|
||||||
const mB = calculateEstMeters(b.rider_id || b.userid, b) ?? Infinity;
|
const mB = calculateEstMeters(b.rider_id || b.userid, b) ?? Infinity;
|
||||||
|
|||||||
@@ -1304,7 +1304,7 @@ const Dispatch = ({
|
|||||||
hasNextPage: liveHasNextPage,
|
hasNextPage: liveHasNextPage,
|
||||||
isFetchingNextPage: liveIsFetchingNextPage
|
isFetchingNextPage: liveIsFetchingNextPage
|
||||||
} = useInfiniteQuery({
|
} = useInfiniteQuery({
|
||||||
queryKey: ['dispatchDeliveries', selectedAppLocationId, liveUserid, 'all', selectedDate, selectedDate, 50, '', 0, 0, 0],
|
queryKey: ['dispatchDeliveries', selectedAppLocationId, liveUserid, 'all', selectedDate, selectedDate, 1000, '', 0, 0, 0],
|
||||||
queryFn: fetchDeliveries,
|
queryFn: fetchDeliveries,
|
||||||
getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
|
getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
|
||||||
enabled: shouldFetchLive,
|
enabled: shouldFetchLive,
|
||||||
@@ -1578,10 +1578,8 @@ const Dispatch = ({
|
|||||||
// excluded here. Every other view (By Location / By Zone / By Rider) is
|
// excluded here. Every other view (By Location / By Zone / By Rider) is
|
||||||
// unchanged.
|
// unchanged.
|
||||||
const isAllActiveView = viewMode === 'all';
|
const isAllActiveView = viewMode === 'all';
|
||||||
// Orders belonging to GPS-active riders — the candidate pool for this view's
|
|
||||||
// list, drop set and auto-fit. Narrowed to in-progress orders below.
|
|
||||||
const allViewOrders = useMemo(
|
const allViewOrders = useMemo(
|
||||||
() => (isAllActiveView ? allOrders.filter((o) => activeRiderIdSet.has(String(o.rider_id))) : allOrders),
|
() => (isAllActiveView ? allOrders.filter((o) => activeRiderIdSet.has(String(o.rider_id || o.userid || ''))) : allOrders),
|
||||||
[isAllActiveView, allOrders, activeRiderIdSet]
|
[isAllActiveView, allOrders, activeRiderIdSet]
|
||||||
);
|
);
|
||||||
// The single gate for the whole Active view: rider ids that are GPS-active AND
|
// The single gate for the whole Active view: rider ids that are GPS-active AND
|
||||||
@@ -1592,8 +1590,8 @@ const Dispatch = ({
|
|||||||
() =>
|
() =>
|
||||||
new Set(
|
new Set(
|
||||||
(isAllActiveView ? allViewOrders : [])
|
(isAllActiveView ? allViewOrders : [])
|
||||||
.filter(isActiveDelivery)
|
.filter((o) => String(o?.orderstatus || '').toLowerCase() === 'active')
|
||||||
.map((o) => String(o.rider_id))
|
.map((o) => String(o.rider_id || o.userid || ''))
|
||||||
),
|
),
|
||||||
[isAllActiveView, allViewOrders]
|
[isAllActiveView, allViewOrders]
|
||||||
);
|
);
|
||||||
@@ -2305,8 +2303,12 @@ const Dispatch = ({
|
|||||||
if (focusedRider && focusedRider.id !== r.id) return;
|
if (focusedRider && focusedRider.id !== r.id) return;
|
||||||
if (focusedKitchen && !focusedKitchen.riders.has(r.id)) return;
|
if (focusedKitchen && !focusedKitchen.riders.has(r.id)) return;
|
||||||
|
|
||||||
|
const activeOrder = isAllActiveView ? getActiveOrder(r.orders) : null;
|
||||||
|
const isActiveAndShown = activeOrder && String(activeOrder.orderstatus || '').toLowerCase() === 'active';
|
||||||
|
const rOrders = isAllActiveView ? (isActiveAndShown ? [activeOrder] : []) : r.orders;
|
||||||
|
|
||||||
const trips = {};
|
const trips = {};
|
||||||
r.orders.forEach(o => {
|
rOrders.forEach(o => {
|
||||||
const t = o.trip_number || 1;
|
const t = o.trip_number || 1;
|
||||||
if (!trips[t]) trips[t] = [];
|
if (!trips[t]) trips[t] = [];
|
||||||
trips[t].push(o);
|
trips[t].push(o);
|
||||||
@@ -2320,12 +2322,27 @@ const Dispatch = ({
|
|||||||
|
|
||||||
if (filteredTOrders.length === 0) return;
|
if (filteredTOrders.length === 0) return;
|
||||||
|
|
||||||
const cacheKey = `${r.id}-${tNum}`;
|
const cacheKey = isAllActiveView ? `${r.id}-active-${filteredTOrders[0].orderid}` : `${r.id}-${tNum}`;
|
||||||
const roadPath = osrmRoutes[cacheKey];
|
const roadPath = osrmRoutes[cacheKey];
|
||||||
const sorted = [...filteredTOrders].sort((a, b) => (a.step || 0) - (b.step || 0));
|
const sorted = [...filteredTOrders].sort((a, b) => (a.step || 0) - (b.step || 0));
|
||||||
|
|
||||||
// Aerial fallback — NaN-safe build
|
// Aerial fallback
|
||||||
const aerialPath = buildTripPoints(sorted);
|
let activeStraightLeg = null;
|
||||||
|
if (isAllActiveView && filteredTOrders[0]) {
|
||||||
|
const o = filteredTOrders[0];
|
||||||
|
const lp = liveRiderLocations.find((l) => String(l.id) === String(r.id));
|
||||||
|
const start = (lp && Number.isFinite(lp.lat) && Number.isFinite(lp.lon))
|
||||||
|
? [lp.lat, lp.lon]
|
||||||
|
: (hasValidPickup(o)
|
||||||
|
? [toNum(pickupLat(o)), toNum(pickupLon(o))]
|
||||||
|
: null);
|
||||||
|
const dLat = toNum(o.droplat || o.deliverylat);
|
||||||
|
const dLon = toNum(o.droplon || o.deliverylong);
|
||||||
|
if (start && Number.isFinite(dLat) && Number.isFinite(dLon)) {
|
||||||
|
activeStraightLeg = [start, [dLat, dLon]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const aerialPath = isAllActiveView ? (activeStraightLeg || []) : buildTripPoints(sorted);
|
||||||
|
|
||||||
const isKitchenAerial = (viewMode === 'kitchens' || focusedKitchen);
|
const isKitchenAerial = (viewMode === 'kitchens' || focusedKitchen);
|
||||||
const path = roadPath || aerialPath;
|
const path = roadPath || aerialPath;
|
||||||
@@ -3997,177 +4014,177 @@ const Dispatch = ({
|
|||||||
})
|
})
|
||||||
: tOrders;
|
: tOrders;
|
||||||
return (
|
return (
|
||||||
<div key={tNum} className="trip-block">
|
<div key={tNum} className="trip-block">
|
||||||
<div className="trip-header" style={{ background: `${focusedRider.color}12`, borderColor: `${focusedRider.color}30` }}>
|
<div className="trip-header" style={{ background: `${focusedRider.color}12`, borderColor: `${focusedRider.color}30` }}>
|
||||||
<span className="th-badge" style={{ background: focusedRider.color }}>Trip {tNum}</span>
|
<span className="th-badge" style={{ background: focusedRider.color }}>Trip {tNum}</span>
|
||||||
<span className="trip-stats">
|
<span className="trip-stats">
|
||||||
<span><Ico><MdLocationOn /></Ico>{tOrders.length} stops</span>
|
<span><Ico><MdLocationOn /></Ico>{tOrders.length} stops</span>
|
||||||
<span><Ico><MdStraighten /></Ico>{tOrders.reduce((s, o) => s + parseFloat(o.actualkms || o.kms || 0), 0).toFixed(1)} km</span>
|
<span><Ico><MdStraighten /></Ico>{tOrders.reduce((s, o) => s + parseFloat(o.actualkms || o.kms || 0), 0).toFixed(1)} km</span>
|
||||||
</span>
|
</span>
|
||||||
{/* iOS-style segmented control: Planned (dispatched step
|
{/* iOS-style segmented control: Planned (dispatched step
|
||||||
order) vs By time (completion order). The active item is
|
order) vs By time (completion order). The active item is
|
||||||
a white "thumb"; the rider color stays on the Trip badge
|
a white "thumb"; the rider color stays on the Trip badge
|
||||||
so the pills don't compete with it. */}
|
so the pills don't compete with it. */}
|
||||||
<div
|
<div
|
||||||
className="trip-sort-toggle"
|
className="trip-sort-toggle"
|
||||||
role="group"
|
role="group"
|
||||||
aria-label="Sort stops by"
|
aria-label="Sort stops by"
|
||||||
data-mode={isTimeMode ? 'time' : 'planned'}
|
data-mode={isTimeMode ? 'time' : 'planned'}
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`trip-sort-pill ${!isTimeMode ? 'is-active' : ''}`}
|
|
||||||
aria-pressed={!isTimeMode}
|
|
||||||
onClick={() => setTripSortMode('planned')}
|
|
||||||
title="Sort stops by planned step (dispatched order)"
|
|
||||||
>
|
>
|
||||||
<MdFormatListBulleted aria-hidden="true" />
|
<button
|
||||||
<span>Planned</span>
|
type="button"
|
||||||
</button>
|
className={`trip-sort-pill ${!isTimeMode ? 'is-active' : ''}`}
|
||||||
<button
|
aria-pressed={!isTimeMode}
|
||||||
type="button"
|
onClick={() => setTripSortMode('planned')}
|
||||||
className={`trip-sort-pill ${isTimeMode ? 'is-active' : ''}`}
|
title="Sort stops by planned step (dispatched order)"
|
||||||
aria-pressed={isTimeMode}
|
>
|
||||||
onClick={() => setTripSortMode('time')}
|
<MdFormatListBulleted aria-hidden="true" />
|
||||||
title="Sort stops by completion time (which delivery was done first)"
|
<span>Planned</span>
|
||||||
>
|
</button>
|
||||||
<MdAccessTime aria-hidden="true" />
|
<button
|
||||||
<span>By time</span>
|
type="button"
|
||||||
</button>
|
className={`trip-sort-pill ${isTimeMode ? 'is-active' : ''}`}
|
||||||
|
aria-pressed={isTimeMode}
|
||||||
|
onClick={() => setTripSortMode('time')}
|
||||||
|
title="Sort stops by completion time (which delivery was done first)"
|
||||||
|
>
|
||||||
|
<MdAccessTime aria-hidden="true" />
|
||||||
|
<span>By time</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="zone-order-grid">
|
||||||
|
{displayOrders.map((o, idx) => {
|
||||||
|
const kitchenKey = (o.kitchen_key || o.pickupcustomer || 'Unknown').toLowerCase().trim();
|
||||||
|
const showTransition = prevKitchenKey !== null && kitchenKey !== prevKitchenKey;
|
||||||
|
prevKitchenKey = kitchenKey;
|
||||||
|
const isStopActive = focusedStop && focusedStop.orderid === o.orderid;
|
||||||
|
const isGoingOn = activeOrderId && o.orderid === activeOrderId;
|
||||||
|
const lat = parseFloat(o.droplat || o.deliverylat);
|
||||||
|
const lon = parseFloat(o.droplon || o.deliverylong);
|
||||||
|
const canFocus = Number.isFinite(lat) && Number.isFinite(lon);
|
||||||
|
const statusStyle = getStatusStyle(o.orderstatus);
|
||||||
|
const estMeters = calculateEstMeters(focusedRider.id, o);
|
||||||
|
// In "By time" mode, stops with no actual delivery time
|
||||||
|
// were sunk to the bottom — dim them so it's obvious
|
||||||
|
// they're not yet delivered without reading the status.
|
||||||
|
const isUndeliveredInTimeMode = isTimeMode && !o.deliverytime;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={o.orderid}>
|
||||||
|
{showTransition && (
|
||||||
|
<div className="kitchen-transition"><span className="kt-ico"><MdSwapHoriz /></span> Switch to <strong>{o.pickupcustomer}</strong></div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={`zone-order-card ${canFocus ? 'clickable' : ''} ${isStopActive ? 'active' : ''} ${isGoingOn ? 'going-on' : ''} ${isUndeliveredInTimeMode ? 'is-pending-time' : ''}`}
|
||||||
|
role={canFocus ? 'button' : undefined}
|
||||||
|
tabIndex={canFocus ? 0 : undefined}
|
||||||
|
onClick={canFocus ? () => setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon }) : undefined}
|
||||||
|
onKeyDown={canFocus ? (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon });
|
||||||
|
}
|
||||||
|
} : undefined}
|
||||||
|
title={canFocus ? (isStopActive ? 'Click to show full trip' : `Show ${o.deliverycustomer || `order #${o.orderid}`} on map`) : undefined}
|
||||||
|
>
|
||||||
|
<div className="zone-order-card-head">
|
||||||
|
<div className="zone-order-num">{o.step || idx + 1}</div>
|
||||||
|
<div className="zone-order-id-block">
|
||||||
|
<div className="zone-order-id">Order #{o.orderid}</div>
|
||||||
|
</div>
|
||||||
|
{(() => {
|
||||||
|
// Stack the status pill and delivery time vertically on
|
||||||
|
// the right of the header so the operator sees the order
|
||||||
|
// outcome and the wall-clock time it landed at a glance.
|
||||||
|
const actual = formatTimeOnly(o.deliverytime);
|
||||||
|
const expected = formatTimeOnly(o.expecteddeliverytime);
|
||||||
|
const isDelivered = FINAL_STATUSES.has(String(o.orderstatus || '').toLowerCase());
|
||||||
|
const showEstDrop = !isDelivered && estMeters !== null;
|
||||||
|
if (!o.orderstatus && !actual && !expected && !showEstDrop) return null;
|
||||||
|
return (
|
||||||
|
<div className="zone-order-status-stack">
|
||||||
|
{o.orderstatus && (
|
||||||
|
<span
|
||||||
|
className="zone-order-status"
|
||||||
|
style={{ background: statusStyle.bg, color: statusStyle.fg }}
|
||||||
|
>
|
||||||
|
{statusStyle.label}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{(actual || expected) && (
|
||||||
|
<span
|
||||||
|
className={`zone-order-time ${actual ? '' : 'is-expected'}`}
|
||||||
|
title={actual ? `Delivered at ${actual}` : `Expected at ${expected}`}
|
||||||
|
>
|
||||||
|
<MdAccessTime />{actual || expected}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{showEstDrop && (
|
||||||
|
<span
|
||||||
|
className="zone-order-est-drop"
|
||||||
|
title="Estimated distance to drop location"
|
||||||
|
>
|
||||||
|
<MdMyLocation />{formatMeters(estMeters)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
{onChangeRider && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="zone-order-change-rider"
|
||||||
|
title="Change rider"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onChangeRider(o, focusedRider);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdSwapHoriz />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="zone-order-customer">
|
||||||
|
<Ico><MdMarkunreadMailbox /></Ico>{o.deliverycustomer || '—'}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{o.pickupcustomer && (
|
||||||
|
<div className="zone-order-line" title={`Kitchen: ${o.pickupcustomer}`}>
|
||||||
|
<Ico><MdRestaurant /></Ico>{o.pickupcustomer}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(o.deliverysuburb || o.deliveryaddress) && (
|
||||||
|
<div className="zone-order-line" title={o.deliveryaddress || o.deliverysuburb}>
|
||||||
|
<Ico><MdLocationOn /></Ico>{o.deliverysuburb || extractArea(o.deliveryaddress)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{o.ordernotes && (
|
||||||
|
<div className="zone-order-line zone-order-notes" title={o.ordernotes}>
|
||||||
|
<Ico><MdNotes /></Ico>{o.ordernotes}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="zone-order-stats">
|
||||||
|
<span className="zone-order-chip" title="Distance">
|
||||||
|
<Ico><MdStraighten /></Ico>{o.actualkms || o.kms || 0} km
|
||||||
|
</span>
|
||||||
|
{o.ordertype && (
|
||||||
|
<span className={`zone-order-chip zone-order-type type-${String(o.ordertype).toLowerCase()}`}>
|
||||||
|
{o.ordertype}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className="zone-order-chip zone-order-trip">
|
||||||
|
T{o.trip_number || tNum} · S{o.step || idx + 1}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="zone-order-grid">
|
|
||||||
{displayOrders.map((o, idx) => {
|
|
||||||
const kitchenKey = (o.kitchen_key || o.pickupcustomer || 'Unknown').toLowerCase().trim();
|
|
||||||
const showTransition = prevKitchenKey !== null && kitchenKey !== prevKitchenKey;
|
|
||||||
prevKitchenKey = kitchenKey;
|
|
||||||
const isStopActive = focusedStop && focusedStop.orderid === o.orderid;
|
|
||||||
const isGoingOn = activeOrderId && o.orderid === activeOrderId;
|
|
||||||
const lat = parseFloat(o.droplat || o.deliverylat);
|
|
||||||
const lon = parseFloat(o.droplon || o.deliverylong);
|
|
||||||
const canFocus = Number.isFinite(lat) && Number.isFinite(lon);
|
|
||||||
const statusStyle = getStatusStyle(o.orderstatus);
|
|
||||||
const estMeters = calculateEstMeters(focusedRider.id, o);
|
|
||||||
// In "By time" mode, stops with no actual delivery time
|
|
||||||
// were sunk to the bottom — dim them so it's obvious
|
|
||||||
// they're not yet delivered without reading the status.
|
|
||||||
const isUndeliveredInTimeMode = isTimeMode && !o.deliverytime;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment key={o.orderid}>
|
|
||||||
{showTransition && (
|
|
||||||
<div className="kitchen-transition"><span className="kt-ico"><MdSwapHoriz /></span> Switch to <strong>{o.pickupcustomer}</strong></div>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className={`zone-order-card ${canFocus ? 'clickable' : ''} ${isStopActive ? 'active' : ''} ${isGoingOn ? 'going-on' : ''} ${isUndeliveredInTimeMode ? 'is-pending-time' : ''}`}
|
|
||||||
role={canFocus ? 'button' : undefined}
|
|
||||||
tabIndex={canFocus ? 0 : undefined}
|
|
||||||
onClick={canFocus ? () => setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon }) : undefined}
|
|
||||||
onKeyDown={canFocus ? (e) => {
|
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
|
||||||
e.preventDefault();
|
|
||||||
setFocusedStop(isStopActive ? null : { orderid: o.orderid, lat, lon });
|
|
||||||
}
|
|
||||||
} : undefined}
|
|
||||||
title={canFocus ? (isStopActive ? 'Click to show full trip' : `Show ${o.deliverycustomer || `order #${o.orderid}`} on map`) : undefined}
|
|
||||||
>
|
|
||||||
<div className="zone-order-card-head">
|
|
||||||
<div className="zone-order-num">{o.step || idx + 1}</div>
|
|
||||||
<div className="zone-order-id-block">
|
|
||||||
<div className="zone-order-id">Order #{o.orderid}</div>
|
|
||||||
</div>
|
|
||||||
{(() => {
|
|
||||||
// Stack the status pill and delivery time vertically on
|
|
||||||
// the right of the header so the operator sees the order
|
|
||||||
// outcome and the wall-clock time it landed at a glance.
|
|
||||||
const actual = formatTimeOnly(o.deliverytime);
|
|
||||||
const expected = formatTimeOnly(o.expecteddeliverytime);
|
|
||||||
const isDelivered = FINAL_STATUSES.has(String(o.orderstatus || '').toLowerCase());
|
|
||||||
const showEstDrop = !isDelivered && estMeters !== null;
|
|
||||||
if (!o.orderstatus && !actual && !expected && !showEstDrop) return null;
|
|
||||||
return (
|
|
||||||
<div className="zone-order-status-stack">
|
|
||||||
{o.orderstatus && (
|
|
||||||
<span
|
|
||||||
className="zone-order-status"
|
|
||||||
style={{ background: statusStyle.bg, color: statusStyle.fg }}
|
|
||||||
>
|
|
||||||
{statusStyle.label}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{(actual || expected) && (
|
|
||||||
<span
|
|
||||||
className={`zone-order-time ${actual ? '' : 'is-expected'}`}
|
|
||||||
title={actual ? `Delivered at ${actual}` : `Expected at ${expected}`}
|
|
||||||
>
|
|
||||||
<MdAccessTime />{actual || expected}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{showEstDrop && (
|
|
||||||
<span
|
|
||||||
className="zone-order-est-drop"
|
|
||||||
title="Estimated distance to drop location"
|
|
||||||
>
|
|
||||||
<MdMyLocation />{formatMeters(estMeters)}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
{onChangeRider && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="zone-order-change-rider"
|
|
||||||
title="Change rider"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
onChangeRider(o, focusedRider);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdSwapHoriz />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="zone-order-customer">
|
|
||||||
<Ico><MdMarkunreadMailbox /></Ico>{o.deliverycustomer || '—'}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{o.pickupcustomer && (
|
|
||||||
<div className="zone-order-line" title={`Kitchen: ${o.pickupcustomer}`}>
|
|
||||||
<Ico><MdRestaurant /></Ico>{o.pickupcustomer}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{(o.deliverysuburb || o.deliveryaddress) && (
|
|
||||||
<div className="zone-order-line" title={o.deliveryaddress || o.deliverysuburb}>
|
|
||||||
<Ico><MdLocationOn /></Ico>{o.deliverysuburb || extractArea(o.deliveryaddress)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{o.ordernotes && (
|
|
||||||
<div className="zone-order-line zone-order-notes" title={o.ordernotes}>
|
|
||||||
<Ico><MdNotes /></Ico>{o.ordernotes}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="zone-order-stats">
|
|
||||||
<span className="zone-order-chip" title="Distance">
|
|
||||||
<Ico><MdStraighten /></Ico>{o.actualkms || o.kms || 0} km
|
|
||||||
</span>
|
|
||||||
{o.ordertype && (
|
|
||||||
<span className={`zone-order-chip zone-order-type type-${String(o.ordertype).toLowerCase()}`}>
|
|
||||||
{o.ordertype}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span className="zone-order-chip zone-order-trip">
|
|
||||||
T{o.trip_number || tNum} · S{o.step || idx + 1}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
Reference in New Issue
Block a user