"use client"; // 동종업종(테마) 비교 패널 — 토스의 "동일업종 비교" 톤. // /api/themes/peer/{code} 한 번 호출로 (테마 라벨, 본인 수익률, 평균, 상/하위 N) 모두 받음. // 테마 무소속 종목은 패널을 통째로 숨김. import Link from "next/link"; import { useEffect, useState } from "react"; import { api, type PeerCompareItem, type PeerCompareResponse } from "../lib/api"; export function PeerComparePanel({ code }: { code: string }) { const [data, setData] = useState(null); const [err, setErr] = useState(null); useEffect(() => { let alive = true; api .peerCompare(code, 21, 5) .then((r) => { if (alive) setData(r); }) .catch((e) => { if (alive) setErr(e instanceof Error ? e.message : String(e)); }); return () => { alive = false; }; }, [code]); if (err) { return (
동종업종 로딩 실패: {err}
); } if (!data) { return (
동종업종 로딩 중…
); } // 테마 무소속 → 패널 숨김 if (data.themes.length === 0) return null; const self = data.self_pct; const avg = data.peer_avg_pct; const diff = self != null && avg != null ? self - avg : null; return (
동종업종 비교
최근 {data.window}거래일 · peer {data.peer_count ?? 0}종목
{data.themes.map((t) => ( #{t.name} ))}
); } function CompareTile({ label, pct, bold = false, sign = false, }: { label: string; pct: number | null; bold?: boolean; sign?: boolean; }) { const tone = pct == null || pct === 0 ? "text-zinc-400" : pct > 0 ? "text-rose-400" : "text-sky-400"; const text = pct == null ? "—" : sign ? `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%p` : `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%`; return (
{label}
{text}
); } function PeerList({ title, items, }: { title: string; items: PeerCompareItem[]; }) { return (
{title}
    {items.length === 0 && (
  • 데이터 없음
  • )} {items.map((it) => { const tone = it.pct_change == null || it.pct_change === 0 ? "text-zinc-400" : it.pct_change > 0 ? "text-rose-400" : "text-sky-400"; return (
  • {it.name} {it.pct_change == null ? "—" : `${it.pct_change >= 0 ? "+" : ""}${it.pct_change.toFixed(2)}%`}
  • ); })}
); }