import React from 'react'; import type { PaperTradeDto } from '../../utils/backendApi'; import type { TickerData } from '../../hooks/useMarketTicker'; import { resolveVirtualTargetNames } from '../../utils/virtualTargetNames'; import { fmtKrw } from '../TradeOrderPanel'; function coinCode(symbol: string): string { return symbol.replace(/^KRW-/, ''); } function fmtTradeTime(iso: string | null | undefined): string { if (!iso) return '—'; const d = new Date(iso); if (Number.isNaN(d.getTime())) return iso.slice(0, 19).replace('T', ' '); const pad = (n: number) => String(n).padStart(2, '0'); return `${pad(d.getMonth() + 1)}/${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; } function sourceLabel(source: string | null | undefined): string { if (source === 'STRATEGY') return '자동'; return '수동'; } interface Props { trades: PaperTradeDto[]; strategyNames?: Record; tickers?: Map; emptyText?: string; className?: string; selectedTradeId?: number | null; /** 투자관리 — 체결 행 전체 전달(탭 유지·선택 표시) */ onSelectTrade?: (trade: PaperTradeDto) => void; /** 가상투자 등 — 종목만 (기존 동작) */ onSelectMarket?: (market: string) => void; } const PaperTradeHistoryList: React.FC = ({ trades, strategyNames = {}, tickers, emptyText = '거래 내역이 없습니다.', className = '', selectedTradeId = null, onSelectTrade, onSelectMarket, }) => (
거래 내역 {trades.length}건
{trades.length === 0 ? (

{emptyText}

) : (
{trades.map(t => { const { koreanName: ko, englishName: en } = resolveVirtualTargetNames( t.symbol, tickers?.get(t.symbol)?.koreanName, ); const strategyName = t.strategyId != null ? (strategyNames[t.strategyId] ?? `#${t.strategyId}`) : '—'; const isBuy = t.side === 'BUY'; const clickable = Boolean(onSelectTrade || onSelectMarket); const selected = selectedTradeId != null && selectedTradeId === t.id; const handleActivate = () => { if (onSelectTrade) onSelectTrade(t); else onSelectMarket?.(t.symbol); }; const sideCls = isBuy ? 'vtd-trade-item--buy' : 'vtd-trade-item--sell'; const colorCls = isBuy ? 'vtd-target-up' : 'vtd-target-dn'; return (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleActivate(); } } : undefined} >
{ko} {en}
{isBuy ? '매수' : '매도'}
{isBuy ? '▲' : '▼'} {coinCode(t.symbol)}/KRW
{fmtKrw(t.price)} {fmtKrw(t.netAmount)}
거래구분 {sourceLabel(t.source)}
거래시간 {fmtTradeTime(t.createdAt)}
투자전략 {strategyName}
{!isBuy && t.realizedPnlDelta != null && (
실현손익 = 0 ? 'vtd-target-up' : 'vtd-target-dn'}`}> {t.realizedPnlDelta >= 0 ? '+' : ''}{fmtKrw(t.realizedPnlDelta)}
)}
체결 후 예수금 {fmtKrw(t.cashAfter)}
); })}
)}
); export default PaperTradeHistoryList;