"use client"; // 홈 상단에 KOSPI / KOSDAQ 인덱스 두 칸. 우측엔 mini sparkline. // macro_daily 가 아직 비어 있으면 안내 카드 한 줄. import { useEffect, useState } from "react"; import { api, type IndicesResponse, type IndexSeries } from "../lib/api"; import { Sparkline } from "./Sparkline"; export function IndicesPanel() { const [data, setData] = useState(null); const [err, setErr] = useState(null); useEffect(() => { let alive = true; api .indices(60) .then((r) => { if (alive) setData(r); }) .catch((e) => { if (alive) setErr(e instanceof Error ? e.message : String(e)); }); return () => { alive = false; }; }, []); if (err) return (
지수 로딩 실패: {err}
); if (!data) return (
지수 로딩 중…
); const allEmpty = data.indices.every((s) => s.points.length === 0); if (allEmpty) return (
지수 데이터 준비 중. macro_daily 가 채워지면 자동으로 표시됩니다.
); return (
{data.indices.map((s) => ( ))}
); } function IndexCard({ s }: { s: IndexSeries }) { const pct = s.pct_change; const tone = pct == null || pct === 0 ? "text-zinc-400" : pct > 0 ? "text-rose-400" : "text-sky-400"; const stroke = pct != null && pct < 0 ? "#3b82f6" : "#ef4444"; const values = s.points.map((p) => p.value); return (
{s.name}
{s.latest != null ? s.latest.toLocaleString(undefined, { maximumFractionDigits: 2 }) : "—"}
{pct != null ? `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%` : "—"}
{values.length >= 2 && ( )}
); }