"use client"; // 목표가 / 손절가 시뮬레이터 (Toss "내 목표가" read-only 클론). // - 현재가 기준 변동률 미리 계산해서 표시 // - 저장 시 localStorage 에만 — 차트 오버레이는 부모 page 가 같은 상태를 읽어 StockChart 에 전달 // - 알림은 별도 AlertsPanel 담당, 여기는 시각화 + 손익 프리뷰만 import { useEffect, useMemo, useState } from "react"; import { readTargets, writeTargets, type Targets } from "../lib/targets"; type Props = { code: string; current: number | null; // 저장/해제 시 부모에 변경을 전달 — 차트에 즉시 반영하도록. onChange?: (t: Targets) => void; }; function parseNum(s: string): number | null { const cleaned = s.replace(/,/g, "").trim(); if (!cleaned) return null; const n = Number(cleaned); return Number.isFinite(n) && n > 0 ? n : null; } function pct(price: number | null, current: number | null): number | null { if (price == null || current == null || current <= 0) return null; return ((price - current) / current) * 100; } export function PriceTargets({ code, current, onChange }: Props) { const [target, setTarget] = useState(""); const [stop, setStop] = useState(""); const [saved, setSaved] = useState({}); // 종목 바뀌면 새로 로드. 입력창도 저장값으로 초기화. useEffect(() => { const t = readTargets(code); setSaved(t); setTarget(t.target != null ? String(t.target) : ""); setStop(t.stop != null ? String(t.stop) : ""); }, [code]); const targetN = useMemo(() => parseNum(target), [target]); const stopN = useMemo(() => parseNum(stop), [stop]); const targetPct = pct(targetN, current); const stopPct = pct(stopN, current); const dirty = (targetN ?? null) !== (saved.target ?? null) || (stopN ?? null) !== (saved.stop ?? null); const save = () => { const next: Targets = { target: targetN, stop: stopN }; writeTargets(code, next); setSaved(next); onChange?.(next); }; const clear = () => { setTarget(""); setStop(""); const next: Targets = {}; writeTargets(code, next); setSaved(next); onChange?.(next); }; const fmtPct = (p: number | null): string => p == null ? "" : `${p >= 0 ? "+" : ""}${p.toFixed(2)}%`; const pctCls = (p: number | null): string => p == null ? "text-zinc-500" : p >= 0 ? "text-rose-400" : "text-sky-400"; return (

내 목표가

브라우저 저장 · 비공개
{current == null && (
현재가 로딩 중 — 변동률은 잠시 후 표시
)}
); } function Row({ label, color, value, onChange, deltaText, deltaCls, }: { label: string; color: string; value: string; onChange: (s: string) => void; deltaText: string; deltaCls: string; }) { return ( ); }