"use client"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, ReferenceArea, } from "recharts"; import { computeOutages, outageLookup, formatOutageDuration } from "@/lib/outage"; export interface TodaySample { recordedAt: string; localTime: string; isOpen: boolean; waitMinutes: number | null; fastLaneMinutes: number | null; } interface Props { samples: TodaySample[]; hasFastLane: boolean; } const TIME_FMT = new Intl.DateTimeFormat([], { hour: "2-digit", minute: "2-digit", hour12: false, }); export default function WaitTimeTodayChart({ samples, hasFastLane }: Props) { const outages = computeOutages(samples); const outageByTime = outageLookup(samples, outages); // Show the Fast Lane line if either the ride metadata flags it as a Fast // Lane ride OR we have any actual Fast Lane data in today's samples. The // metadata flag can lag (or read false even when SF is reporting waits), // so the data-driven check rescues those rides. const showFastLane = hasFastLane || samples.some((s) => s.fastLaneMinutes !== null); // X-axis time is rendered in the viewer's local timezone (Intl with no // tz arg) so an Eastern-time user sees ET regardless of which park. // Each point also carries its outage (if any) so the custom tooltip can // render "Outage #N — Hh Mm" without re-scanning. const data = samples.map((s) => { const time = TIME_FMT.format(new Date(s.recordedAt)); const outage = !s.isOpen ? outageByTime.get(time) ?? null : null; return { time, wait: s.isOpen ? s.waitMinutes : null, fl: s.isOpen ? s.fastLaneMinutes : null, outageN: outage?.n ?? null, outageDurationMin: outage?.durationMin ?? null, }; }); const tickInterval = Math.max(1, Math.floor(data.length / 8)); return (
{/* top margin leaves room for outage labels rendered with position="top" */} {/* Outage markers — render before the lines so they sit underneath. */} {outages.map((o) => ( ))} } /> {showFastLane && ( )}
); } // ── Custom tooltip ───────────────────────────────────────────────────────── // When hovering on an outage span, replace the standard wait/Fast Lane rows // with a single "Outage #N — duration" line. Otherwise show the per-series // values, formatting 0 explicitly as "walk-on". interface TooltipDatum { outageN: number | null; outageDurationMin: number | null; } interface TooltipEntry { value?: number | null; name?: string | number; dataKey?: string | number; color?: string; payload?: TooltipDatum; } interface RideTooltipProps { active?: boolean; payload?: TooltipEntry[]; label?: string | number; hasFastLane: boolean; } function RideTooltip({ active, payload, label, hasFastLane }: RideTooltipProps) { if (!active || !payload || payload.length === 0) return null; const datum = payload[0]?.payload; const cardStyle: React.CSSProperties = { background: "#1c1c1c", border: "1px solid #333", borderRadius: 6, fontSize: "0.75rem", color: "#f5f5f5", padding: "8px 10px", lineHeight: 1.4, }; if (datum?.outageN && datum.outageDurationMin !== null) { return (
{label}
Outage #{datum.outageN} — {formatOutageDuration(datum.outageDurationMin)}
); } return (
{label}
{payload.map((entry, i) => { const v = entry.value; const display = v === null || v === undefined ? "—" : v === 0 ? "walk-on" : `${v} min`; const dotColor = entry.color ?? "#fff"; return (
{entry.name} {display}
); })} {!hasFastLane && null}
); }