"use client"; import { useEffect, useState } from "react"; import { clientApi } from "@/lib/client-api"; import { useNow } from "@/lib/stream"; import { cx } from "@/lib/format"; import type { Exchange } from "@/lib/types"; const CLOCKS: Array<{ id: string; label: string; tz: string }> = [ { id: "xnys", label: "New York", tz: "America/New_York" }, { id: "xlon", label: "London", tz: "Europe/London" }, { id: "xetr", label: "Frankfurt", tz: "Europe/Berlin" }, { id: "xtks", label: "Tokyo", tz: "Asia/Tokyo" }, { id: "xhkg", label: "Hong Kong", tz: "Asia/Hong_Kong" }, { id: "xasx", label: "Sydney", tz: "Australia/Sydney" }, ]; const fmts = new Map(); const timeIn = (tz: string, now: number) => { let f = fmts.get(tz); if (!f) { f = new Intl.DateTimeFormat("en-GB", { timeZone: tz, hour: "2-digit", minute: "2-digit", hourCycle: "h23" }); fmts.set(tz, f); } return f.format(new Date(now)); }; export const STATE_DOT: Record = { OPEN: "bg-positive", PRE: "bg-warning", POST: "bg-warning", AUCTION: "bg-warning", HALTED: "bg-negative", CLOSED: "bg-stale", UNKNOWN: "bg-stale", }; /** Global clock strip: local time and session state of the main market centres (refreshed every 60 s). */ export function MarketClock({ className }: { className?: string }) { const now = useNow(1000); const [states, setStates] = useState>({}); useEffect(() => { let alive = true; const load = () => clientApi("/v1/exchanges") .then((xs) => alive && setStates(Object.fromEntries(xs.map((x) => [x.id, x.status?.state ?? "UNKNOWN"])))) .catch(() => {}); load(); const t = setInterval(load, 60_000); return () => { alive = false; clearInterval(t); }; }, []); return (
{CLOCKS.map((c) => { const st = states[c.id] ?? "UNKNOWN"; return ( {c.label} {now ? timeIn(c.tz, now) : "--:--"} ); })}
); }