From a20315ce3488cfd8df3488010d7c32a614bce89e Mon Sep 17 00:00:00 2001 From: gahusb Date: Mon, 11 May 2026 19:32:26 +0900 Subject: [PATCH] =?UTF-8?q?feat(stock):=20=ED=8F=AC=ED=8A=B8=ED=8F=B4?= =?UTF-8?q?=EB=A6=AC=EC=98=A4=20=ED=98=84=EC=9E=AC=EA=B0=80=EC=97=90=20NXT?= =?UTF-8?q?=20=EC=8B=9C=EA=B0=84=EC=99=B8=20=EA=B1=B0=EB=9E=98=20=EB=B1=83?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 백엔드 응답의 price_session에 따라 NXT 프리마켓/애프터마켓 거래 중인 종목에 작은 'NXT' / 'NXT 프리' 뱃지를 표시. 툴팁에 거래 시각 노출. 정규장 마감 후에도 평가금액이 자연스럽게 이어지는 흐름을 시각적으로 보강. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/pages/stock/Stock.css | 16 ++++++++++++++ src/pages/stock/components/PortfolioTab.jsx | 24 +++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/pages/stock/Stock.css b/src/pages/stock/Stock.css index 76e4afe..885adf0 100644 --- a/src/pages/stock/Stock.css +++ b/src/pages/stock/Stock.css @@ -901,6 +901,22 @@ font-style: italic; } +.pf-nxt-badge { + display: inline-block; + margin-left: 6px; + padding: 1px 6px; + border-radius: 4px; + border: 1px solid rgba(139, 92, 246, 0.45); + background: rgba(139, 92, 246, 0.12); + color: #c4b5fd; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.04em; + vertical-align: middle; + cursor: help; + white-space: nowrap; +} + .pf-edit-row { grid-column: 1 / -1; display: grid; diff --git a/src/pages/stock/components/PortfolioTab.jsx b/src/pages/stock/components/PortfolioTab.jsx index 43c016e..2104fad 100644 --- a/src/pages/stock/components/PortfolioTab.jsx +++ b/src/pages/stock/components/PortfolioTab.jsx @@ -6,6 +6,26 @@ import { } from 'recharts'; import { formatNumber, formatPercent, toNumeric, profitColorClass, numFitClass } from '../stockUtils'; +const formatPriceTime = (iso) => { + if (!iso) return ''; + const d = new Date(iso); + if (Number.isNaN(d.getTime())) return ''; + return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; +}; + +const PriceSessionBadge = ({ session, asOf }) => { + if (session !== 'NXT_AFTER' && session !== 'NXT_PRE') return null; + const isPre = session === 'NXT_PRE'; + const label = isPre ? 'NXT 프리' : 'NXT'; + const desc = isPre ? 'NXT 프리마켓 거래가' : 'NXT 야간거래 (15:30~20:00)'; + const time = formatPriceTime(asOf); + return ( + + {label} + + ); +}; + const PortfolioTab = ({ pf, asset, handleSell, handleSaveSnapshot }) => ( <> {pf.portfolioError ? ( @@ -527,6 +547,10 @@ const PortfolioTab = ({ pf, asset, handleSell, handleSaveSnapshot }) => ( {item.current_price != null ? formatNumber(item.current_price) : '조회 실패'} +