"use client"; // 시장 overview: 등락 상위 / 등락 하위 / 거래대금 상위 / 거래량 상위 4 컬럼. // /api/markets/movers 응답을 그대로 표 형태로 렌더. // 거래대금 = close × volume, 단위 억원. 토스 톤의 핵심 랭킹. import Link from "next/link"; import { useEffect, useState } from "react"; import { api, type Mover, type MoversResponse } from "../lib/api"; export function MarketsOverview() { const [data, setData] = useState(null); const [err, setErr] = useState(null); useEffect(() => { let alive = true; api .movers("ALL", 10) .then((r) => { if (alive) setData(r); }) .catch((e) => { if (alive) setErr(e instanceof Error ? e.message : String(e)); }); return () => { alive = false; }; }, []); if (err) return (
시장 overview 로딩 실패: {err}
); if (!data) return (
시장 overview 로딩 중…
); // 아직 ohlcv_daily 가 비어 있으면 모든 리스트가 빈 배열로 옴 — 안내만. const empty = !data.gainers.length && !data.losers.length && !data.by_volume.length && !data.by_trading_value.length; if (empty) return (
시장 데이터 준비 중. ohlcv_daily 가 채워지면 자동으로 표시됩니다.
); return (
); } type Metric = "price" | "volume" | "trading_value"; function MoverList({ title, items, metric = "price", }: { title: string; items: Mover[]; metric?: Metric; }) { return (
{title}
{items.length === 0 ? (
데이터 없음
) : (
    {items.map((m, i) => ( ))}
)}
); } function MoverRow({ rank, m, metric, }: { rank: number; m: Mover; metric: Metric; }) { const pct = m.pct_change; const tone = pct == null || pct === 0 ? "text-zinc-400" : pct > 0 ? "text-rose-400" : "text-sky-400"; let primary: string; if (metric === "volume") { primary = fmtVol(m.volume); } else if (metric === "trading_value") { primary = fmtKrw(m.trading_value ?? null); } else { primary = m.close != null ? m.close.toLocaleString(undefined, { maximumFractionDigits: 0 }) : "—"; } return (
  • {rank} {m.name}
    {primary}
    {pct != null ? `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%` : ""}
  • ); } function fmtVol(n: number | null): string { if (n == null) return "—"; if (n >= 1e8) return `${(n / 1e8).toFixed(1)}억`; if (n >= 1e4) return `${(n / 1e4).toFixed(1)}만`; return n.toLocaleString(); } // 거래대금 원 → 억/조 표기. 토스에서 가장 흔한 단위. function fmtKrw(n: number | null): string { if (n == null) return "—"; if (n >= 1e12) return `${(n / 1e12).toFixed(2)}조`; if (n >= 1e8) return `${Math.round(n / 1e8).toLocaleString()}억`; if (n >= 1e4) return `${(n / 1e4).toFixed(0)}만`; return n.toLocaleString(); }