diff --git a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx index 565edcc79..2fb05b0de 100644 --- a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx @@ -111,12 +111,16 @@ const computeLastMileSteps = ( releaseRow?: ImportUnloadedItem, ): LastMileStepState[] => { const exactKm = (record as { exactKm?: number | null }).exactKm; + // Truck arrival/leave live in the transient warehouse pickup-ready queue and + // vanish once the item is released. So once the leg is IN_TRANSIT/DELIVERED, + // treat both as done (the truck must have arrived + left to get there). + const past = record.status === "IN_TRANSIT" || record.status === "DELIVERED"; const flags = [ record.status !== "PAYMENT_PENDING", Boolean(record.vehicleId), - Boolean(releaseRow?.releaseOrderReference), - Boolean(releaseRow?.releaseDate), - record.status === "IN_TRANSIT" || record.status === "DELIVERED", + past || Boolean(releaseRow?.releaseOrderReference), + past || Boolean(releaseRow?.releaseDate), + past, exactKm != null, exactKm != null, // Generate Invoice — auto-generated when distance is saved record.status === "DELIVERED", @@ -1005,15 +1009,22 @@ const LastMilePage = () => { const delivered = row.original.status === "DELIVERED"; const releaseRow = pickupReadyByBooking.get(row.original.bookingId) ?? pickupReadyByBooking.get(bookingRef(row.original)); - // Only the current step's action is active; the rest stay disabled. - // Steps: 0 Ready·1 Assign·2 Arrived·3 Leave·4 In-transit·5 Distance·6 Invoice·7 Delivered. - const activeStep = computeLastMileSteps(row.original, releaseRow).findIndex((s) => s.active); - const canAdvance = activeStep === 0 || activeStep === 4 || activeStep === 7; - const canAssignStep = activeStep === 1; - const canDistance = activeStep === 5; - // Truck arrival/leaving are independent of the step sequence — each - // driven only by its own state: arrive once assigned & not arrived, - // leave once arrived & not departed. + // Gate on PERSISTENT state (status/vehicle/distance), not the truck + // arrival/leave signals — those live in the warehouse queue and vanish + // once the item is released, so they can't gate the status advance. + const status = row.original.status; + const hasDistance = row.original.exactKm != null; + // Advance: PAYMENT_PENDING→Ready, READY_TO_TRANSIT→In-transit (needs a + // vehicle), IN_TRANSIT→Delivered (needs distance/invoice). + const canAdvance = + status === "PAYMENT_PENDING" || + (status === "READY_TO_TRANSIT" && assigned) || + (status === "IN_TRANSIT" && hasDistance); + const canAssignStep = !assigned && status !== "DELIVERED"; + const canDistance = status === "IN_TRANSIT"; + // Truck arrival/leaving are independent — each driven only by its own + // warehouse state: arrive once assigned & not arrived, leave once + // arrived & not departed. const canArrive = assigned && !releaseRow?.releaseOrderReference; const canLeave = Boolean(releaseRow?.releaseOrderReference) && !releaseRow?.releaseDate; return (