diff --git a/src/app/admin/v2/orders/[id]/page.tsx b/src/app/admin/v2/orders/[id]/page.tsx index 03bcae7..71b9e44 100644 --- a/src/app/admin/v2/orders/[id]/page.tsx +++ b/src/app/admin/v2/orders/[id]/page.tsx @@ -6,6 +6,7 @@ import PageHeader from "@/components/admin/PageHeader"; import StatusPill, { type StatusKind } from "@/components/admin/StatusPill"; import StickyActionBar from "@/components/admin/StickyActionBar"; import OrderActionButtons from "@/components/admin/orders/OrderActionButtons"; +import FulfillmentTimeline from "@/components/admin/orders/FulfillmentTimeline"; export const dynamic = "force-dynamic"; @@ -109,6 +110,12 @@ export default async function OrderDetailV2Page({ )} + + s.key === step); + const currentIdx = STEPS.findIndex((s) => s.key === current); + if (currentIdx === -1) return "upcoming"; + if (order < currentIdx) return "done"; + if (order === currentIdx) return "current"; + return "upcoming"; +} + +export function FulfillmentTimeline({ + status, + placedAt, + pickedUpAt, +}: FulfillmentTimelineProps) { + if (status === "cancelled") { + return ( + + + STATUS + + + Cancelled + + + ); + } + + return ( + + + FULFILLMENT + + + {STEPS.map((step, i) => { + const state = stepState(step.key, status); + const isLast = i === STEPS.length - 1; + // Pick the right timestamp to display. The "Ready" step has no + // dedicated column in the legacy schema, so we show "—" — the + // user can read the mark-ready time from the audit log. + const ts = + step.key === "placed" + ? placedAt + : step.key === "picked-up" + ? pickedUpAt + : null; + const dotBg = + state === "done" + ? "var(--color-accent)" + : state === "current" + ? "var(--color-accent-2)" + : "var(--color-surface-3)"; + const labelColor = + state === "upcoming" ? "var(--color-text-faint)" : "var(--color-text)"; + return ( + + + + {!isLast && ( + + )} + + + {step.label} + + + {ts ? formatDateTime(ts) : "—"} + + + ); + })} + + + ); +} + +export default FulfillmentTimeline;