From 2cd585a3acec9367043f44bb620a6888c8307bea Mon Sep 17 00:00:00 2001 From: Nathnael Date: Thu, 11 Jun 2026 07:11:43 +0000 Subject: [PATCH] style: ui fixes to booking detail page --- .../BookingDetailPage/DraftBookingView.tsx | 120 +++++------ .../BookingDetailPage/ReadonlyBookingView.tsx | 20 +- .../components/ActivityCard.tsx | 12 +- .../components/ContractCard.tsx | 65 +++--- .../components/Documents.tsx | 103 ++++++---- .../BookingDetailPage/components/Notices.tsx | 192 +++++++++++++++++- .../components/PageHeader.tsx | 2 +- .../components/ScheduleCard.tsx | 46 ++++- .../components/StatusHero.tsx | 46 +++-- .../BookingDetailPage/components/Steps.tsx | 131 +++++++----- .../BookingDetailPage/components/layout.tsx | 4 +- .../BookingDetailPage/components/pricing.tsx | 44 +++- 12 files changed, 567 insertions(+), 218 deletions(-) diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/DraftBookingView.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/DraftBookingView.tsx index 03919c4b9..2c2835266 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/DraftBookingView.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/DraftBookingView.tsx @@ -29,7 +29,11 @@ import { CardTitle, PageShell, SectionCard } from "./components/layout"; import { CountChip, DocRow, IconSquare } from "./components/Documents"; import { EstimateCard } from "./components/pricing"; import { HeaderButton, PageHeader } from "./components/PageHeader"; -import { MutationErrors, NoticeBanner } from "./components/Notices"; +import { + ActionRequiredBanner, + MutationErrors, + NoticeBanner, +} from "./components/Notices"; import { ScheduleCard } from "./components/ScheduleCard"; import { ShipmentDetailsCard } from "./components/ShipmentDetailsCard"; import { StatusHero } from "./components/StatusHero"; @@ -132,30 +136,39 @@ export function DraftBookingView({ } - label="Continue editing" - onClick={() => navigate(`/bookings/${booking.id}/edit`)} - /> + <> + } + label="Documents" + onClick={() => + documentsRef.current?.scrollIntoView({ behavior: "smooth" }) + } + /> + } + label="Continue editing" + onClick={() => navigate(`/bookings/${booking.id}/edit`)} + /> + } /> - {booking.status === "CHANGES_REQUESTED" && - booking.latestChangeRequestNote && ( - } - title="Changes requested by staff" - > - {booking.latestChangeRequestNote} - - )} - + + {booking.status === "CHANGES_REQUESTED" && + booking.latestChangeRequestNote ? ( + navigate(`/bookings/${booking.id}/edit`)} + > + {booking.latestChangeRequestNote} + + ) : undefined} + - navigate(`/bookings/${booking.id}/edit`)} - > - Edit - - } - /> + - documentsRef.current?.scrollIntoView({ - behavior: "smooth", - }) - } - > - Upload - - ) + } + onClick={() => + documentsRef.current?.scrollIntoView({ + behavior: "smooth", + }) + } + > + Add documents + } /> @@ -223,7 +222,10 @@ export function DraftBookingView({ onClick={handleSubmitRequest} disabled={submitMutation.isPending} loading={submitMutation.isPending} - styles={{ root: { height: 46 }, label: { fontWeight: 700 } }} + styles={{ + root: { height: 46 }, + label: { fontSize: 14, fontWeight: 800 }, + }} > {submitMutation.isPending ? "Submitting…" : "Submit for review"} @@ -268,7 +270,7 @@ export function DraftBookingView({ ? (file?.name ?? "Uploaded") : selected ? selected.name - : "Required · not uploaded" + : "Not added yet" } status={ isUploaded ? "verified" : selected ? "ready" : "missing" @@ -297,22 +299,26 @@ export function DraftBookingView({ /> {selected && ( setCancelDialogOpen(true)} /> diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx index 917894626..d5281b98b 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/ReadonlyBookingView.tsx @@ -10,12 +10,14 @@ import { ActivityCard } from "./components/ActivityCard"; import { ContractCard } from "./components/ContractCard"; import { DocRow, IconSquare } from "./components/Documents"; import { BodyGrid, CardTitle, PageShell, SectionCard } from "./components/layout"; +import { CancelledBanner } from "./components/Notices"; import { HeaderButton, PageHeader } from "./components/PageHeader"; import { PaymentCard } from "./components/pricing"; import { ScheduleCard } from "./components/ScheduleCard"; import { ShipmentDetailsCard } from "./components/ShipmentDetailsCard"; import { StatusHero } from "./components/StatusHero"; import { SupportCard } from "./components/SupportCard"; +import { fmtDate, isNegative } from "./utils"; export function ReadonlyBookingView({ booking }: { booking: Freight.IBooking }) { const navigate = useNavigate(); @@ -49,7 +51,23 @@ export function ReadonlyBookingView({ booking }: { booking: Freight.IBooking }) } /> - + {isNegative(status) ? ( + navigate("/bookings/new")} + /> + ) : ( + + )} diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ActivityCard.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ActivityCard.tsx index 851f5f92c..c08b6d5f5 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ActivityCard.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ActivityCard.tsx @@ -1,5 +1,4 @@ import { Box, Group, Text } from "@mantine/core"; -import { Train } from "lucide-react"; import type { Freight } from "@edr/types"; @@ -59,16 +58,11 @@ export function ActivityCard({ booking }: { booking: Freight.IBooking }) { style={{ width: 18, height: 18, - display: "flex", - alignItems: "center", - justifyContent: "center", borderRadius: 999, backgroundColor: first ? "#0EA371" : "#D4E9DF", boxShadow: first ? "0 0 0 4px #BFE8D4" : undefined, }} - > - {first && } - + /> {!lastItem && ( - Latest + Current )} diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ContractCard.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ContractCard.tsx index e9836703c..aa0abb384 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ContractCard.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ContractCard.tsx @@ -10,29 +10,27 @@ const CONTRACT_CONFIG: Record< title: string; description: string; buttonLabel?: string; - urgent?: boolean; } > = { APPROVED_PENDING_SIGNATURE: { - title: "Contract being prepared", + title: "Your contract is being prepared.", description: "Your booking has been approved. The contract will be available shortly.", }, CONTRACT_READY: { - title: "Action required — sign your contract", + title: "Review and sign your contract to proceed.", description: - "Your contract is ready. Review the agreement and apply your digital signature to proceed.", - buttonLabel: "View & sign contract", - urgent: true, + "Once all parties sign, we'll issue your payment reference (PNR) and schedule the cargo.", + buttonLabel: "Review & Sign", }, SIGNED_CUSTOMER: { - title: "You have signed the contract", + title: "You have signed the contract.", description: "Your signature has been submitted. Awaiting the final staff signature.", buttonLabel: "View contract", }, FULLY_EXECUTED: { - title: "Contract fully executed", + title: "Contract fully executed — proceed to payment.", description: "The contract has been signed by all parties. You can now proceed to payment.", buttonLabel: "View contract", @@ -48,37 +46,54 @@ export function ContractCard({ }) { const c = CONTRACT_CONFIG[booking.status as string]; if (!c) return null; - const urgent = c.urgent; return ( - + - - + + + What's next + + {c.title} - + {c.description} @@ -87,10 +102,10 @@ export function ContractCard({ + )} + + ); +} + +export function CancelledBanner({ + pillLabel = "Cancelled", + title, + subtitle, + reason, + onRebook, +}: { + pillLabel?: string; + title: string; + subtitle: string; + reason?: string | null; + onRebook?: () => void; +}) { + return ( + + + + + + + + + + {pillLabel} + + + {title} + + + {subtitle} + + + + {onRebook && ( + + )} + + {reason && ( + + + + + Reason for cancellation + + + {reason} + + + + )} + + + ); +} + export function MutationErrors({ mutations, }: { diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PageHeader.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PageHeader.tsx index f326f86f0..a0c372a9e 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PageHeader.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/PageHeader.tsx @@ -27,7 +27,7 @@ export function PageHeader({ - + {booking.reference} m.toUpperCase()); + + return ( + + + {label} + + ); +} + export function ScheduleCard({ booking, title, @@ -30,6 +68,11 @@ export function ScheduleCard({ muted: !booking.trainId, }; + const statusRow: Row = { + label: "Status", + value: , + }; + const rows: Row[] = consignment ? [ { label: "Consignment ID", value: booking.reference }, @@ -40,6 +83,7 @@ export function ScheduleCard({ { label: "Consolidation", value: consolidation }, ] : [ + statusRow, { label: "Service", value: service }, { label: "Equipment return", value: equipmentReturn }, { label: "Proposed date", value: fmtDate(booking.scheduledDate) }, diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/StatusHero.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/StatusHero.tsx index b85bd81b1..89b3e7024 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/StatusHero.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/StatusHero.tsx @@ -1,5 +1,5 @@ import { Box, Group, Text } from "@mantine/core"; -import { AlertTriangle, Check, Clock, FileText, History } from "lucide-react"; +import { AlertTriangle, Check, FileText, History } from "lucide-react"; import type { Freight } from "@edr/types"; @@ -7,7 +7,13 @@ import { PROGRESS_STAGES, STATUS_MAP } from "../constants"; import { fmtDate, isDraftLike, isNegative } from "../utils"; import { SectionCard } from "./layout"; -export function StatusHero({ booking }: { booking: Freight.IBooking }) { +export function StatusHero({ + booking, + children, +}: { + booking: Freight.IBooking; + children?: React.ReactNode; +}) { const status = booking.status as string; const cfg = STATUS_MAP[status] ?? STATUS_MAP.DRAFT; const negative = isNegative(status); @@ -34,7 +40,7 @@ export function StatusHero({ booking }: { booking: Freight.IBooking }) { ); return ( - + - + {cfg.title} - + {cfg.description} @@ -72,25 +78,33 @@ export function StatusHero({ booking }: { booking: Freight.IBooking }) { backgroundColor: "#F7FAFC", }} > - + - + {chipLabel} - + {chipValue} - + - + {children ?? ( + + )} ); } @@ -185,7 +199,7 @@ function ProgressTracker({ @@ -193,7 +207,7 @@ function ProgressTracker({ diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/Steps.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/Steps.tsx index cecc9639e..8ad1646c3 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/Steps.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/Steps.tsx @@ -2,6 +2,41 @@ import { Box, Button, Group, Text } from "@mantine/core"; import { Check } from "lucide-react"; import type { ReactNode } from "react"; +function StepCircle({ + index, + done, + active, +}: { + index: number; + done?: boolean; + active?: boolean; +}) { + const style: React.CSSProperties = done + ? { backgroundColor: "#0EA371", color: "#fff" } + : active + ? { backgroundColor: "#0C1A2B", color: "#fff" } + : { backgroundColor: "#EEF2F6", color: "#9AA8B5" }; + + return ( + + {done ? : index} + + ); +} + export function StepLine({ index, title, @@ -9,63 +44,49 @@ export function StepLine({ action, done, active, - highlight, }: { index: number; title: string; - desc: string; + desc?: string; action?: ReactNode; done?: boolean; active?: boolean; - highlight?: boolean; }) { - const badgeStyle: React.CSSProperties = done - ? { backgroundColor: "#0EA371", color: "#fff" } - : active - ? { backgroundColor: "#0C1A2B", color: "#fff" } - : { - backgroundColor: "#EEF2F6", - color: "#9AA8B5", - border: "1px solid #E1E7EE", - }; + if (active) { + return ( + + + + + + {title} + + {desc && ( + + {desc} + + )} + + + {action} + + ); + } return ( - - - {done ? : index} - - - - {title} - - - {desc} - - - {action} + + + + {title} + ); } @@ -73,18 +94,26 @@ export function StepLine({ export function StepGhostButton({ children, onClick, + icon, }: { children: ReactNode; onClick?: () => void; + icon?: ReactNode; }) { return (