"use client"; import { useEffect, useRef, useState } from "react"; import { cx, formatChange, formatPercent, formatQuoteValue } from "@/lib/format"; import { useLiveQuote } from "@/lib/stream"; import type { Quote } from "@/lib/types"; /** Change colour helpers — colour is supplementary; the sign is always in the text. */ export const toneOf = (v: number | null | undefined) => (v == null || !Number.isFinite(v) || v === 0 ? "text-ink-2" : v > 0 ? "text-positive" : "text-negative"); /** * Price cell that merges the server-rendered quote with the live stream (when the instrument is * subscribed by an ancestor). Flashes subtly on change. Never shows a live value when the * stream quote is older than the server snapshot. */ export function LivePrice({ instrumentId, quote, assetClass, className, showChange = true, big = false }: { instrumentId: string; quote: Quote | null | undefined; assetClass?: string | null; className?: string; showChange?: boolean; big?: boolean }) { const live = useLiveQuote(instrumentId); const serverTs = quote ? Date.parse(quote.updated_at) : 0; const useLive = !!live && live.received >= serverTs && live.price != null; const price = useLive ? live.price : quote?.price ?? null; const change = useLive ? live.change : quote?.change ?? null; const pct = useLive ? live.change_pct : quote?.change_percent ?? null; const currency = useLive ? live.currency : quote?.currency; const prev = useRef(null); const [flash, setFlash] = useState<"" | "flash-up" | "flash-down">(""); useEffect(() => { if (price == null) return; if (prev.current != null && price !== prev.current) { setFlash(price > prev.current ? "flash-up" : "flash-down"); const t = setTimeout(() => setFlash(""), 650); prev.current = price; return () => clearTimeout(t); } prev.current = price; }, [price]); if (price == null) return —; return ( {formatQuoteValue(price, assetClass, currency)} {showChange && ( {big && change != null ? `${formatChange(change, assetClass)} ` : ""} {formatPercent(pct)} )} ); } export function ChangeCell({ value, className }: { value: number | null | undefined; className?: string }) { return {formatPercent(value)}; }