This commit is contained in:
natib21
2026-07-04 02:07:31 +00:00
parent 00d4b729a2
commit cac6e4eaa1

View File

@@ -40,6 +40,7 @@ import {
} from "@mantine/core";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { LastMileStepper, type LastMileStepState } from "@/components/operations/LastMileSteps";
import { ReceiveInventoryModal } from "@/components/warehouses/ReceiveInventoryModal";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { useToast } from "@/hooks/use-toast";
@@ -121,6 +122,50 @@ const bookingContainerNumbers = (record: FirstMileRecord): string[] =>
.map((c) => c.containerNumber)
.filter((n): n is string => Boolean(n));
/** Progress stages of the first-mile pickup workflow, for the detail stepper. */
const computeFirstMileSteps = (record: FirstMileRecord): LastMileStepState[] => {
const exactKm = record.exactKm;
const inTransitOrPast =
record.status === "IN_TRANSIT" || record.status === "RECEIVED_TO_PORT";
const flags = [
record.status !== "PAYMENT_PENDING", // Ready to Transit
isAssigned(record), // Assign vehicle
inTransitOrPast, // In transit
exactKm != null, // Add distance
Boolean(record.invoice), // Generate Invoice
record.status === "RECEIVED_TO_PORT",// Received to port
];
// Current step = earliest incomplete one.
const activeIdx = flags.findIndex((f) => !f);
const labels = [
"Ready to Transit",
"Assign vehicle",
"In transit",
"Add distance",
"Generate Invoice",
"Received to port",
];
const vehCount = record.vehicleAssignments?.length ?? (record.vehicleId ? 1 : 0);
const primaryPlate =
record.vehicle?.plateNumber ??
record.vehicleAssignments?.[0]?.vehicle?.plateNumber ??
null;
const details: (string | null)[] = [
null,
vehCount > 1 ? `${vehCount} vehicles` : primaryPlate,
null,
exactKm != null ? `${exactKm} KM` : null,
record.invoice?.number ?? null,
null,
];
return labels.map((label, i) => ({
label,
done: flags[i],
active: i === activeIdx,
detail: details[i],
}));
};
// Paid = record flag set OR its invoice reached PAID.
const isPaidRecord = (r: FirstMileRecord) =>
Boolean((r as { paid?: boolean }).paid) ||
@@ -1320,6 +1365,37 @@ const FirstMilePage = () => {
>
<Stack gap="md">
{activeRecord && <BookingInfo record={activeRecord} />}
{activeRecord && (activeRecord.vehicleAssignments?.length ?? 0) > 0 && (
<Card withBorder padding="md" radius="md">
<Text fw={600} size="sm" mb="sm">Assigned vehicles</Text>
<Stack gap="xs">
{activeRecord.vehicleAssignments!.map((a) => {
const v = a.vehicle;
const label = v
? [v.code, v.plateNumber].filter(Boolean).join(" · ")
: a.vehicleId;
return (
<Group key={a.id} justify="space-between" wrap="nowrap">
<Text size="sm">{label}</Text>
{a.containerNumber ? (
<Badge size="sm" variant="light" color="blue">
{a.containerNumber}
</Badge>
) : (
<Text size="xs" c="dimmed">No container no.</Text>
)}
</Group>
);
})}
</Stack>
</Card>
)}
{activeRecord && (
<Card withBorder padding="md" radius="md">
<Text fw={600} size="sm" mb="sm">Pickup steps</Text>
<LastMileStepper steps={computeFirstMileSteps(activeRecord)} />
</Card>
)}
<Group justify="flex-end">
<Button variant="default" onClick={() => { setDetailOpen(false); setActiveId(null); }}>Close</Button>
</Group>