From c2649dae3c131fdd88fd610a49711fd9a2be0072 Mon Sep 17 00:00:00 2001 From: Marshal Date: Fri, 3 Jul 2026 23:11:04 +0000 Subject: [PATCH] enhance phase countdown and booking window descriptions for clarity --- .../components/UpcomingWindowsSection.tsx | 53 +++++++++++++++---- .../portal/src/services/bookings.service.ts | 9 ++-- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/edr-freight-web/portal/src/pages/MyPortalPage/components/UpcomingWindowsSection.tsx b/apps/edr-freight-web/portal/src/pages/MyPortalPage/components/UpcomingWindowsSection.tsx index bb5b629de..300ff643f 100644 --- a/apps/edr-freight-web/portal/src/pages/MyPortalPage/components/UpcomingWindowsSection.tsx +++ b/apps/edr-freight-web/portal/src/pages/MyPortalPage/components/UpcomingWindowsSection.tsx @@ -45,22 +45,50 @@ function windowLabel(w: MyBookingWindow): string { } /** - * The deadline + label for whichever phase the window is currently in. Phases - * run: window open (closes at windowClosesAt) → document review (docReviewEndsAt) - * → payment (paymentPhaseEndsAt). Returns null when no phase is timing down. + * The countdown for whichever phase the window is currently in. Phases run: + * pre-window (opens at windowOpensAt) → open (closes at windowClosesAt) → + * document review (docReviewEndsAt) → payment (paymentPhaseEndsAt). + * + * `label` describes the deadline being counted down to; `expiredText` names the + * NEXT step so that when a deadline lapses between the 60s refetches the row + * announces what comes next ("Booking opening now…", "Review starting…") rather + * than the bare word "Expired". Returns null when no phase is timing down. */ function phaseCountdown( w: MyBookingWindow, -): { label: string; deadline: string } | null { +): { label: string; deadline: string; expiredText: string } | null { switch (w.windowPhase) { + case "PRE_WINDOW": + if (w.windowOpensAt) + return { + label: "Booking opens in", + deadline: w.windowOpensAt, + expiredText: "Booking opening now…", + }; + return null; case "OPEN": - if (w.windowClosesAt) return { label: "Window closes in", deadline: w.windowClosesAt }; + if (w.windowClosesAt) + return { + label: "Window closes in", + deadline: w.windowClosesAt, + expiredText: "Document review starting…", + }; return null; case "DOC_REVIEW": - if (w.docReviewEndsAt) return { label: "Document review ends in", deadline: w.docReviewEndsAt }; + if (w.docReviewEndsAt) + return { + label: "Document review ends in", + deadline: w.docReviewEndsAt, + expiredText: "Payment starting…", + }; return null; case "PAYMENT": - if (w.paymentPhaseEndsAt) return { label: "Payment due in", deadline: w.paymentPhaseEndsAt }; + if (w.paymentPhaseEndsAt) + return { + label: "Payment due in", + deadline: w.paymentPhaseEndsAt, + expiredText: "Payment window closing…", + }; return null; default: return null; @@ -141,9 +169,11 @@ interface UpcomingWindowsSectionProps { } /** - * The customer's upcoming/open booking windows on their active-contract - * lanes. Import trains open a window on one booking day; export trains open - * 24h before departure. Hidden entirely when there is nothing to show. + * All announced upcoming/open booking windows, shown to every customer + * regardless of whether they hold a contract on the lane. Import trains open a + * window on one booking day; export trains open 24h before departure. Rows on a + * lane the customer has an active contract for carry a "Book now" action; + * others route to the contract list. Hidden entirely when nothing is announced. */ export const UpcomingWindowsSection = memo(function UpcomingWindowsSection({ windows, @@ -162,7 +192,7 @@ export const UpcomingWindowsSection = memo(function UpcomingWindowsSection({ Booking Windows - Upcoming and open booking windows on your contract lanes + Upcoming and open booking windows across all lanes @@ -211,6 +241,7 @@ export const UpcomingWindowsSection = memo(function UpcomingWindowsSection({ diff --git a/apps/edr-freight-web/portal/src/services/bookings.service.ts b/apps/edr-freight-web/portal/src/services/bookings.service.ts index 79676cab1..c2729bebb 100644 --- a/apps/edr-freight-web/portal/src/services/bookings.service.ts +++ b/apps/edr-freight-web/portal/src/services/bookings.service.ts @@ -47,13 +47,16 @@ export interface PriceLineItem { } /** - * An upcoming/open booking window on one of the signed-in customer's - * active-contract lanes. Import trains open a window on one booking day; + * An announced upcoming/open booking window, shown to every signed-in customer + * regardless of contract. Import trains open a window on one booking day; * export trains open 24h before departure (first come, first served). */ export interface MyBookingWindow { scheduleId: string; - /** Contract whose route this window belongs to, when the row carries it. */ + /** + * The customer's active contract on this lane, when they hold one — enables + * "Book now" to target it. Null for lanes they have no contract on. + */ contractId: string | null; /** ONE_TIME contracts can't draw down against a window — button is hidden. */ contractKind: "ONE_TIME" | "GENERAL" | null;