feat(stock): 포트폴리오 현재가에 NXT 시간외 거래 뱃지
백엔드 응답의 price_session에 따라 NXT 프리마켓/애프터마켓 거래 중인 종목에 작은 'NXT' / 'NXT 프리' 뱃지를 표시. 툴팁에 거래 시각 노출. 정규장 마감 후에도 평가금액이 자연스럽게 이어지는 흐름을 시각적으로 보강. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -901,6 +901,22 @@
|
|||||||
font-style: italic;
|
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 {
|
.pf-edit-row {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -6,6 +6,26 @@ import {
|
|||||||
} from 'recharts';
|
} from 'recharts';
|
||||||
import { formatNumber, formatPercent, toNumeric, profitColorClass, numFitClass } from '../stockUtils';
|
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 (
|
||||||
|
<span className="pf-nxt-badge" title={time ? `${desc} · ${time}` : desc}>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const PortfolioTab = ({ pf, asset, handleSell, handleSaveSnapshot }) => (
|
const PortfolioTab = ({ pf, asset, handleSell, handleSaveSnapshot }) => (
|
||||||
<>
|
<>
|
||||||
{pf.portfolioError ? (
|
{pf.portfolioError ? (
|
||||||
@@ -527,6 +547,10 @@ const PortfolioTab = ({ pf, asset, handleSell, handleSaveSnapshot }) => (
|
|||||||
{item.current_price != null
|
{item.current_price != null
|
||||||
? formatNumber(item.current_price)
|
? formatNumber(item.current_price)
|
||||||
: '조회 실패'}
|
: '조회 실패'}
|
||||||
|
<PriceSessionBadge
|
||||||
|
session={item.price_session}
|
||||||
|
asOf={item.price_as_of}
|
||||||
|
/>
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
<div className="stock-holdings__metric">
|
<div className="stock-holdings__metric">
|
||||||
|
|||||||
Reference in New Issue
Block a user