import { useData, usePublish, type PanelRef } from '@jaspers-ai/sdk' import './styles.css' interface Snap { ticker: string last: number | null change: number | null changePercent: number | null volume: number | null updated: string | null [field: string]: unknown } const fmt = (v: number | null | undefined, d = 2) => (typeof v === 'number' ? v.toFixed(d) : '–') const vol = (v: number | null | undefined) => typeof v !== 'number' ? '–' : v >= 1e9 ? `${(v / 1e9).toFixed(2)}B` : v >= 1e6 ? `${(v / 1e6).toFixed(2)}M` : v >= 1e3 ? `${(v / 1e3).toFixed(1)}K` : String(v) const sign = (v: number | null | undefined) => (typeof v !== 'number' || v === 0 ? '' : v > 0 ? 'mv-up' : 'mv-down') export function WatchlistView({ panel }: { panel: PanelRef }) { const state = useData(`workspaces/${panel.workspaceId}/panels/${panel.id}/state`) as { tickers?: string[] } | undefined if (state === undefined) return

Loading…

const tickers = (state.tickers ?? []).map((t) => t.trim().toUpperCase()).filter(Boolean) if (!tickers.length) return return } function Empty({ panel }: { panel: PanelRef }) { usePublish(panel, { tickers: [], count: 0, error: null }) return

No tickers yet. Ask for some.

} function Table({ panel, tickers }: { panel: PanelRef; tickers: string[] }) { const { data, error, loading, refetch } = useData('massive/snapshot', { tickers }) const rows = (data ?? []) as Snap[] usePublish(panel, { tickers: rows.map((r) => r.ticker), count: rows.length, error: error ?? null }) return (
Watchlist
{error ?

{error}

: null} {!data && !error ?

Loading…

: null} {data ? (
{rows.map((r) => ( ))}
Ticker Last Change Change % Volume
{r.ticker} {fmt(r.last)} {fmt(r.change)} {typeof r.changePercent === 'number' ? `${fmt(r.changePercent)}%` : '–'} {vol(r.volume)}
) : null} ) }