import Link from "next/link"; import { InstrumentTable } from "@/components/market/instrument-table"; import { Page, PageHeader } from "@/components/ui/section"; import { apiEnvelope } from "@/lib/api"; import { cx } from "@/lib/format"; import type { InstrumentWithQuote } from "@/lib/types"; const SORTS: Array<[string, string]> = [["-change", "Top gainers"], ["change", "Top losers"], ["volume", "Most active"], ["symbol", "A → Z"]]; /** * Shared server page for one asset-class list (/stocks, /crypto, …). Fetches quoted instruments * from /v1/instruments and renders a live table; pagination and sort via search params. */ export async function ClassPage({ classes, title, kicker, lead, basePath, searchParams, showExchange = true, defaultSort = "-change", note }: { classes: string[]; title: string; kicker?: string; lead: string; basePath: string; searchParams: Promise>; showExchange?: boolean; defaultSort?: string; note?: React.ReactNode }) { const sp = await searchParams; const sort = typeof sp.sort === "string" ? sp.sort : defaultSort; const page = Math.max(1, Number(sp.page ?? 1) || 1); const q = typeof sp.q === "string" ? sp.q : ""; const all = typeof sp.all === "string"; const limit = 100; const lists = await Promise.all( classes.map((c) => apiEnvelope(`/v1/instruments?asset_class=${c}${all ? "" : ""ed=1"}&sort=${encodeURIComponent(sort)}&limit=${limit}&offset=${(page - 1) * limit}${q ? `&q=${encodeURIComponent(q)}` : ""}`)), ); const rows = lists.flatMap((l) => l.data); const total = lists.reduce((a, l) => a + Number(l.meta.total ?? 0), 0); const pages = Math.max(1, Math.ceil(total / limit)); const link = (params: Record) => { const u = new URLSearchParams(); const merged = { sort, page, q, ...(all ? { all: "1" } : {}), ...params }; for (const [k, v] of Object.entries(merged)) if (v !== undefined && v !== "" && !(k === "page" && v === 1) && !(k === "sort" && v === defaultSort)) u.set(k, String(v)); const s = u.toString(); return s ? `${basePath}?${s}` : basePath; }; return (
{SORTS.map(([s, label]) => ( {label} ))}
{sort !== defaultSort && } {all && } {all ? "Quoted only" : "Include unquoted"}
1} defaultSort={sort.replace("-", "") === "change" ? "change" : sort === "volume" ? "volume" : "symbol"} emptyText={q ? `No instruments match “${q}”.` : "No quoted instruments in this class yet."} />
{total.toLocaleString("en-US")} instrument{total === 1 ? "" : "s"} · page {page} of {pages} {page > 1 && ( ← Previous )} {page < pages && ( Next → )}
{note &&

{note}

}
); }