updates on the bookings page and updated ai and more thngs

This commit is contained in:
2026-09-11 11:20:38 +05:30
parent 1caa7b71a9
commit 49ee0c5076
40 changed files with 5796 additions and 359 deletions

View File

@@ -16,6 +16,8 @@ import { useZone } from '@/lib/ZoneContext';
import { BATCHES, batchRangeLabel, getRowBatchId } from '@/lib/batchBucket';
import { formatDoormileTimestamp, parseDoormileTimestamp } from '@/lib/doormileTimestamp';
import { currency, exportRows, km as formatKm, matchesQuery, orDash, useDebouncedValue } from '@/lib/doormileFormat';
import { pickupSourceTypeLabel } from '@/lib/orderFlow';
import { summariseRouting } from '@/lib/routingSummary';
/**
* Deliveries — orders that have moved past merely being created.
@@ -640,6 +642,59 @@ export default function Deliveries() {
);
}
/**
* How this booking was routed, and on what.
*
* Backend decides the route; this only reports the decision and the inputs it
* was made from, so support can answer "why does the rider's screen say hand
* over at a base instead of deliver?" without reconstructing a pincode rule by
* hand.
*
* Before pickup the decision has not been taken — `decided` is false and what is
* shown is a projection from the captured from/to, labelled as such. A number
* presented as a decision when it is only a forecast is worse than no number.
*
* Wording note: the wire says hub, operators and riders say base. The
* translation happens here, at the edge, and never travels back up.
*/
function RoutingSummary({ routing }) {
const s = summariseRouting(routing);
if (!s) return null;
return (
<div>
<p className="mb-2 text-overline uppercase text-ink-4">Routing</p>
<Surface variant="subtle" padding="sm" radius="lg">
<Stack space="xs">
<p className="text-body-sm text-ink-1">{s.reason}</p>
<p className="text-caption text-ink-3">{s.route}</p>
<dl className="grid grid-cols-2 gap-3 pt-1">
{[
['Collected from', pickupSourceTypeLabel(routing.pickup_source_type)],
['Parcel state', s.consignmentState],
['Next step', s.nextAction],
['Base', s.base || '—'],
].map(([label, value]) => (
<div key={label}>
<dt className="text-caption uppercase tracking-wide text-ink-3">{label}</dt>
<dd className="text-body-sm text-ink-1">{value}</dd>
</div>
))}
</dl>
{s.baseAddress ? <p className="text-caption text-ink-3">{s.baseAddress}</p> : null}
{s.inwardedAt ? (
<p className="text-caption text-ink-3">
Received at the base {formatDoormileTimestamp(s.inwardedAt)}
</p>
) : null}
</Stack>
</Surface>
</div>
);
}
/**
* What is actually in the parcel.
*
@@ -687,14 +742,40 @@ function OrderDetailDrawer({ row, onClose }) {
<div>
<p className="mb-2 text-overline uppercase text-ink-4">Pickup</p>
<p className="text-body-sm text-ink-2">{orDash(row?.pickupaddress)}</p>
<p className="text-body-sm text-ink-2">
{orDash(booking?.routing?.from_address || row?.pickupaddress)}
</p>
{booking?.routing ? (
<p className="text-caption text-ink-3">
{[
pickupSourceTypeLabel(booking.routing.pickup_source_type),
booking.routing.pickup_source_name,
booking.routing.from_pincode
]
.filter(Boolean)
.join(' · ')}
</p>
) : null}
</div>
<div>
<p className="mb-2 text-overline uppercase text-ink-4">Drop</p>
<p className="text-body-sm text-ink-2">{orDash(row?.deliveryaddress)}</p>
<p className="text-body-sm text-ink-2">
{orDash(booking?.routing?.to_address || row?.deliveryaddress)}
</p>
{booking?.routing?.destination_pincode ? (
<p className="text-caption text-ink-3">{booking.routing.destination_pincode}</p>
) : null}
</div>
{/* Why this parcel is going where it is going.
A rider rings asking why his screen says hand over at a base
instead of deliver to the customer; without this, answering meant
reconstructing the routing rule from two pincodes by hand. The
backend decides the route and reports it here with the inputs it
used, so the answer is a lookup. */}
{booking?.routing ? <RoutingSummary routing={booking.routing} /> : null}
<div>
<p className="mb-2 text-overline uppercase text-ink-4">
Parcels {parcels.length ? `· ${parcels.length}` : ''}