"use client"; import { cx, formatDateTime, formatDuration, relativeTime, STATUS_LABEL, toMs } from "@/lib/format"; import { useLiveQuote, useNow } from "@/lib/stream"; import type { Quote } from "@/lib/types"; /** * Human freshness label, ticking every second: * REALTIME → "Updated 320 ms ago" · DELAYED → "Delayed 15 min · 12s ago" · AT_CLOSE → "At close · Fri 16:00 ET" * END_OF_DAY → "End of day · Sep 11" · STALE → "Stale · last 4h 12m ago" · WITHHELD → "Withheld (rights)". */ export function FreshnessLabel({ quote, className, exchangeTz }: { quote: Quote | null | undefined; className?: string; exchangeTz?: string | null }) { const now = useNow(1000); const live = useLiveQuote(quote?.instrument_id); if (!quote) return No observation yet; const status = quote.data_status; const liveTs = live && live.received >= Date.parse(quote.updated_at) ? live.timestamp : null; const srcTs = liveTs ?? toMs(quote.source_timestamp) ?? toMs(quote.updated_at); const age = srcTs != null && now ? Math.max(0, now - srcTs) : quote.freshness_ms; let text: string; switch (status) { case "REALTIME": text = age == null ? "Live" : age < 60_000 ? `Updated ${formatDuration(age)} ago` : `Live · last ${relativeTime(srcTs, now || Date.now())}`; break; case "DELAYED": text = `Delayed 15 min · ${relativeTime(srcTs, now || Date.now())}`; break; case "AT_CLOSE": text = `At close · ${formatDateTime(srcTs, { tz: exchangeTz ?? "America/New_York" })}`; break; case "END_OF_DAY": text = `End of day · ${formatDateTime(srcTs, { tz: "UTC", dateOnly: true })}`; break; case "STALE": text = `Stale · last update ${relativeTime(srcTs, now || Date.now())}`; break; case "WITHHELD": text = "Value withheld (data rights)"; break; default: text = STATUS_LABEL[status] ?? status; } const tone = status === "REALTIME" ? "text-positive" : status === "STALE" || status === "WITHHELD" ? "text-stale" : status === "DELAYED" ? "text-warning" : "text-ink-3"; return ( {status === "REALTIME" && } {text} ); } export function RelativeTime({ value, className }: { value: string | number | null | undefined; className?: string }) { const now = useNow(1000); const ms = typeof value === "number" ? value : toMs(value); return ( ); }