From a339ea620e06d9f179eea8d64aad8062e9c0a4dd Mon Sep 17 00:00:00 2001 From: Marshal Date: Fri, 21 Aug 2026 08:59:44 +0000 Subject: [PATCH] feat(train-scheduling): add showWagonStat prop to control wagon stats visibility --- .../compositionEditor/TrainConsistView.tsx | 4 ++ .../compositionEditor/TrainStatsBar.tsx | 29 ++++++++----- .../TrainScheduleV2DetailPage.tsx | 1 + .../TrainScheduleV2ListPage.tsx | 43 +++++++------------ 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainConsistView.tsx b/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainConsistView.tsx index d29807ecc..2b22a2ccc 100644 --- a/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainConsistView.tsx +++ b/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainConsistView.tsx @@ -18,6 +18,8 @@ interface TrainConsistViewProps { scheduleDetail: TrainScheduleDetail; scheduleId: string; maxWagons: number; + /** Hide the consist-wide Wagons stat tile (dispatch shows leg capacity instead). */ + showWagonStat?: boolean; /** Booking id selected in the side panel — highlights its wagons in the consist. */ highlightBookingId?: string | null; } @@ -45,6 +47,7 @@ export const TrainConsistView = ({ scheduleDetail, scheduleId, maxWagons, + showWagonStat = true, highlightBookingId, }: TrainConsistViewProps) => { const [selectedWagonId, setSelectedWagonId] = useState(null); @@ -172,6 +175,7 @@ export const TrainConsistView = ({ lengthMax={lengthMax} wagonCount={wagonsUsed} wagonMax={maxWagons} + showWagons={showWagonStat} /> {/* Consist panel */} diff --git a/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainStatsBar.tsx b/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainStatsBar.tsx index 3403258ef..b99c62254 100644 --- a/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainStatsBar.tsx +++ b/apps/edr-freight-web/backoffice/src/components/trainScheduling/compositionEditor/TrainStatsBar.tsx @@ -9,6 +9,12 @@ interface TrainStatsBarProps { lengthMax: number | null; wagonCount: number; wagonMax: number; + /** + * The wagon tile is a consist-wide count, which reads as wrong on a + * multi-leg schedule where per-leg capacity is the real number. Dispatch + * hides it (leg capacity is shown there instead); the batch board keeps it. + */ + showWagons?: boolean; } function pctColor(pct: number) { @@ -83,6 +89,7 @@ export const TrainStatsBar = ({ lengthMax, wagonCount, wagonMax, + showWagons = true, }: TrainStatsBarProps) => { const weightPct = weightMax ? (weightUsed / weightMax) * 100 : null; const lengthPct = lengthMax ? (lengthUsed / lengthMax) * 100 : null; @@ -95,7 +102,7 @@ export const TrainStatsBar = ({ withBorder style={{ borderColor: "var(--mantine-color-gray-2)", background: "white" }} > - + } label="Gross weight" @@ -108,7 +115,7 @@ export const TrainStatsBar = ({ px={{ base: 0, xs: "lg" }} style={{ borderLeft: "1px solid var(--mantine-color-gray-2)", - borderRight: "1px solid var(--mantine-color-gray-2)", + borderRight: showWagons ? "1px solid var(--mantine-color-gray-2)" : undefined, }} > - } - label="Wagons" - pct={wagonPct} - current={String(wagonCount)} - max={String(wagonMax)} - unit="" - /> + {showWagons ? ( + } + label="Wagons" + pct={wagonPct} + current={String(wagonCount)} + max={String(wagonMax)} + unit="" + /> + ) : null} ); diff --git a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2DetailPage.tsx b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2DetailPage.tsx index 5d9616cec..69be66d15 100644 --- a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2DetailPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2DetailPage.tsx @@ -848,6 +848,7 @@ export default function TrainScheduleV2DetailPage() { scheduleDetail={schedule} scheduleId={scheduleId ?? ""} maxWagons={schedule.maxWagons ?? 53} + showWagonStat={false} /> ) : ( ( - - - {row.original.routeName ?? "—"} - - {row.original.direction ? ( - - {row.original.direction} - - ) : null} - - + + {row.original.direction ? ( + + {row.original.direction} + + ) : null} + + ), }, @@ -888,12 +885,12 @@ export default function TrainScheduleV2ListPage() { } /** - * The row's wagon chips, matching the detail page's wagon plan: used is slots - * carrying a booking allocation, the denominator is the schedule's capacity - * (API-computed: the larger of coupled consist and planned `maxWagons`, since - * wagons are coupled on demand), and remaining excludes wagons reserved by - * bookings that have not paid yet — that space is claimed, so it is not - * bookable. + * The row's wagon chips: used is slots carrying a booking allocation, the + * denominator is the schedule's capacity (API-computed: the larger of coupled + * consist and planned `maxWagons`, since wagons are coupled on demand). Both + * are consist-wide totals, so on a multi-leg schedule they do not describe any + * single leg — the bookable/planned counts were dropped for that reason; the + * detail page's wagon plan is the per-leg source of truth. */ /** Green tint for departures dedicated to a shipping line (overrides direction tint). */ const SHIPPING_LINE_ROW_STYLE = { @@ -965,20 +962,15 @@ function WagonChips({ schedule }: { schedule: TrainScheduleListItem }) { const total = schedule.wagonsTotal ?? schedule.wagonCount; const used = schedule.wagonsUsed; const reserved = schedule.wagonsReserved ?? 0; - const remaining = schedule.wagonsRemaining; - if (used == null) { + if (used == null || schedule.wagonCount === 0) { return ; } return ( <> - + {reserved > used ? : null} - {remaining != null ? : null} ); } @@ -1049,9 +1041,6 @@ function ScheduleCard({ {schedule.reference} ) : null} - - {schedule.routeName ?? "Train schedule"} - {day} · {time}