updates on the deliveries page and status updates as well
This commit is contained in:
@@ -33,6 +33,7 @@ import { currency, exportRows, km as formatKm, matchesQuery, orDash, useDebounce
|
||||
/* `other` is not declared here — it is appended only when rows actually land
|
||||
in it, so the strip never carries a permanently empty tab. */
|
||||
const STATUS_TABS = [
|
||||
{ value: 'all', label: 'All', countKey: 'total' },
|
||||
{ value: 'pending', label: 'Pending', countKey: 'uncoveredLength' },
|
||||
{ value: 'accepted', label: 'Accepted', countKey: 'assignedLength' },
|
||||
{ value: 'arrived', label: 'Arrived', countKey: 'arrivedLength' },
|
||||
@@ -60,26 +61,8 @@ const SETTABLE_STATUSES = [
|
||||
];
|
||||
|
||||
export default function Deliveries() {
|
||||
// Unscoped by default. `fetchDeliveries` treats a blank from/to as "no
|
||||
// bound" (see queries.js — `if (!startdate && !enddate) return true`), and
|
||||
// it filters on `orderdate` (the booking's creation day), never on when a
|
||||
// row was last touched. Defaulting this range to today meant the Pending/
|
||||
// Accepted/Arrived/Picked/Active tabs — an outstanding-work QUEUE, not a
|
||||
// day's log — only showed a booking that was also *created* today.
|
||||
// Reassign an order that came in yesterday and it's still correctly
|
||||
// "Pending" work, but it dropped off the board the moment you did it,
|
||||
// reading as "I just assigned it and it's not there." Same "state vs
|
||||
// flow" distinction this app already draws elsewhere for orders. Delivered/
|
||||
// Cancelled stay meaningful to scope by date — the operator narrows via
|
||||
// the date inputs same as before.
|
||||
const [range, setRange] = useState({ from: '', to: '' });
|
||||
const [tab, setTab] = useState('pending');
|
||||
// 'all' rather than the wave matching the current clock hour: a batch is a
|
||||
// slice of ONE day, so "jump to the slot matching right now" only means
|
||||
// something once the date range above is scoped to a single day. With the
|
||||
// range unscoped by default, defaulting the batch too would silently hide
|
||||
// almost everything — a booking created three days ago at 11am has no
|
||||
// relationship to "the slot matching right now" on a different day.
|
||||
const [tab, setTab] = useState('all');
|
||||
const [batch, setBatch] = useState('all');
|
||||
const [search, setSearch] = useState('');
|
||||
const debouncedSearch = useDebouncedValue(search);
|
||||
@@ -144,7 +127,10 @@ export default function Deliveries() {
|
||||
const base = STATUS_TABS.map((entry) => ({
|
||||
value: entry.value,
|
||||
label: entry.label,
|
||||
count: batchRows.filter((row) => String(row.orderstatus || '').toLowerCase() === entry.value).length,
|
||||
count:
|
||||
entry.value === 'all'
|
||||
? batchRows.length
|
||||
: batchRows.filter((row) => String(row.orderstatus || '').toLowerCase() === entry.value).length,
|
||||
}));
|
||||
/* A row whose status matches no tab used to be counted nowhere and shown
|
||||
nowhere. It gets its own tab, but only when one actually exists. */
|
||||
@@ -154,7 +140,9 @@ export default function Deliveries() {
|
||||
|
||||
const rows = useMemo(() => {
|
||||
const scoped =
|
||||
tab === 'other'
|
||||
tab === 'all'
|
||||
? batchRows
|
||||
: tab === 'other'
|
||||
? unmapped
|
||||
: batchRows.filter((row) => {
|
||||
const status = String(row.orderstatus || '').toLowerCase();
|
||||
@@ -164,7 +152,17 @@ export default function Deliveries() {
|
||||
return scoped.filter((row) =>
|
||||
matchesQuery(
|
||||
row,
|
||||
['orderid', 'deliverycustomer', 'ridername', 'pickupaddress', 'deliveryaddress', 'tenantname'],
|
||||
[
|
||||
'orderid',
|
||||
'bookingno',
|
||||
'bookingid',
|
||||
'consignmentid',
|
||||
'deliverycustomer',
|
||||
'ridername',
|
||||
'pickupaddress',
|
||||
'deliveryaddress',
|
||||
'tenantname',
|
||||
],
|
||||
debouncedSearch
|
||||
)
|
||||
);
|
||||
@@ -252,7 +250,7 @@ export default function Deliveries() {
|
||||
sortable: true,
|
||||
cell: (row) => (
|
||||
<div className="flex flex-col items-start gap-0.5">
|
||||
<StatusBadge status={row.orderstatus} dot size="sm" />
|
||||
<StatusBadge status={row.consignmentstatus || row.orderstatus} dot size="sm" />
|
||||
{/* Where the value came from. Without this, a row reading "Active"
|
||||
while the booking still says Converted_To_Consignment looks
|
||||
exactly like a bug. */}
|
||||
@@ -643,7 +641,7 @@ function OrderDetailDrawer({ row, onClose }) {
|
||||
<Surface variant="subtle" padding="sm" radius="lg">
|
||||
<dl className="grid grid-cols-2 gap-3">
|
||||
{[
|
||||
['Status', row?.orderstatus ? <StatusBadge status={row.orderstatus} size="sm" /> : '—'],
|
||||
['Status', row ? <StatusBadge status={row.consignmentstatus || row.orderstatus} size="sm" /> : '—'],
|
||||
['Rider', orDash(row?.ridername)],
|
||||
['Customer', orDash(row?.deliverycustomer)],
|
||||
['Contact', orDash(row?.deliverycontactno)],
|
||||
|
||||
@@ -54,13 +54,15 @@ An opt-in "activity" date basis was added so an order booked yesterday and still
|
||||
|
||||
The filter field and the bucket field have to be the same field. If carried-over work needs to be visible on the board, it needs its own bucket ("Carried over") — not a time-of-day wave it does not belong to. Decide that before reaching for the date filter again.
|
||||
|
||||
### Picked is empty for hyperlocal traffic, and that is correct
|
||||
### Picked vs Out for Delivery & Converted_To_Consignment
|
||||
|
||||
`doormile-flow.md` §5: at `pickup-complete` the booking becomes a consignment, and **matching 3-digit pickup/delivery pincode prefixes go straight to `Out_for_Delivery`** (hyperlocal); everything else routes via a hub.
|
||||
`doormile-flow.md` §5: at `pickup-complete` the booking becomes a consignment, and **matching 3-digit pickup/delivery pincode prefixes go straight to `Out_for_Delivery`** (hyperlocal) when the pickup collection flag is off; everything else sits at `Collected_By_Miler` (Picked) or routes via a hub (`Inwarded_At_Hub`).
|
||||
|
||||
So a Coimbatore-to-Coimbatore order (641xxx → 641xxx) is picked up and is *immediately* out for delivery. It never rests in a "picked" state. The Picked tab reading 0 while orders are plainly moving is expected behaviour on hyperlocal traffic, not a missing mapping.
|
||||
|
||||
The confusing part is downstream of that: the booking's own `status` **freezes at `Converted_To_Consignment`** the moment it is picked up. The Deliveries page joins `GET /admin/consignments` and lets the consignment's status win, so a row correctly reads **Active** while `GET /admin/bookings` still says `Converted_To_Consignment`. That looks like a bug on inspection, which is why the status badge carries a tooltip naming the consignment and its status whenever the value came from there (`statusfromconsignment` on the row).
|
||||
The booking's own `status` **freezes at `Converted_To_Consignment`** the moment pickup is complete. `Converted_To_Consignment` is a handoff marker, not a display state, and is never displayed literally to the user. The Deliveries page joins `GET /admin/consignments` (and reads `consignmentstatus` attached to the booking row) to derive the live state:
|
||||
- `Collected_By_Miler` → **Picked** (under Picked tab)
|
||||
- `Out_for_Delivery` → **Active / Out for Delivery** (under Active tab)
|
||||
- `Inwarded_At_Hub` / `At_Hub` / `Outwarded_From_Hub` → **Active** (with dedicated Inwarded/Hub badge)
|
||||
- `Delivered` → **Delivered** (under Delivered tab)
|
||||
|
||||
### ⛔ Never bucket on `assigntime`
|
||||
It is **not** an assignment time. The Doormile bookings feed has no assignment timestamp, so `api.js` maps `assigntime` to the booking's `updatedat` — its last-modified column. Any status change, parcel scan, payment or pickup-complete re-stamps it.
|
||||
|
||||
@@ -275,11 +275,18 @@ export default function Orders() {
|
||||
header: 'Status',
|
||||
sortable: true,
|
||||
cell: (row) => {
|
||||
const rawStatus = String(row.status || '').trim().toLowerCase();
|
||||
const isArrived =
|
||||
String(row.status || '').toLowerCase() === 'pickup_scheduled' &&
|
||||
rawStatus === 'pickup_scheduled' &&
|
||||
Boolean(row.reachedat ?? row.reached_at ?? row.reachedAt ?? row.reachedtime ?? row.reached_time);
|
||||
const displayStatus = isArrived ? 'arrived' : row.status;
|
||||
return <StatusBadge status={displayStatus} dot size="sm" />;
|
||||
if (isArrived) {
|
||||
return <StatusBadge status="arrived" dot size="sm" />;
|
||||
}
|
||||
if (rawStatus === 'converted_to_consignment') {
|
||||
const cStatus = row.consignmentstatus ?? row.consignment_status;
|
||||
return <StatusBadge status={cStatus || 'picked'} dot size="sm" />;
|
||||
}
|
||||
return <StatusBadge status={row.status} dot size="sm" />;
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user