추세검색 설정 수정
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
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 {
|
||||
@@ -22,6 +24,7 @@ function sourceLabel(source: string | null | undefined): string {
|
||||
interface Props {
|
||||
trades: PaperTradeDto[];
|
||||
strategyNames?: Record<number, string>;
|
||||
tickers?: Map<string, TickerData>;
|
||||
emptyText?: string;
|
||||
className?: string;
|
||||
onSelectMarket?: (market: string) => void;
|
||||
@@ -30,57 +33,102 @@ interface Props {
|
||||
const PaperTradeHistoryList: React.FC<Props> = ({
|
||||
trades,
|
||||
strategyNames = {},
|
||||
tickers,
|
||||
emptyText = '거래 내역이 없습니다.',
|
||||
className = '',
|
||||
onSelectMarket,
|
||||
}) => (
|
||||
<div className={`ptd-trade-history${className ? ` ${className}` : ''}`}>
|
||||
{trades.length === 0 ? (
|
||||
<p className="ptd-muted ptd-trade-history-empty">{emptyText}</p>
|
||||
) : (
|
||||
<div className="ptd-trade-history-scroll">
|
||||
<table className="ptd-table ptd-table--compact ptd-table--trades">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>시간</th>
|
||||
<th>종목</th>
|
||||
<th>유형</th>
|
||||
<th>구분</th>
|
||||
<th>체결가</th>
|
||||
<th>수량</th>
|
||||
<th>금액</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<div className={`ptd-trade-history vtd-trade-history${className ? ` ${className}` : ''}`}>
|
||||
<section className="vtd-target-section vtd-trade-section">
|
||||
<div className="vtd-target-list-head">
|
||||
<span>거래 내역</span>
|
||||
<span className="vtd-target-count">{trades.length}건</span>
|
||||
</div>
|
||||
|
||||
{trades.length === 0 ? (
|
||||
<p className="vtd-muted ptd-trade-history-empty">{emptyText}</p>
|
||||
) : (
|
||||
<div className="ptd-trade-history-scroll">
|
||||
<div className="vtd-target-list vtd-trade-list">
|
||||
{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}`)
|
||||
: null;
|
||||
: '—';
|
||||
const isBuy = t.side === 'BUY';
|
||||
const clickable = Boolean(onSelectMarket);
|
||||
const sideCls = isBuy ? 'vtd-trade-item--buy' : 'vtd-trade-item--sell';
|
||||
const colorCls = isBuy ? 'vtd-target-up' : 'vtd-target-dn';
|
||||
|
||||
return (
|
||||
<tr
|
||||
<div
|
||||
key={t.id}
|
||||
className={onSelectMarket ? 'ptd-row--click' : undefined}
|
||||
onClick={onSelectMarket ? () => onSelectMarket(t.symbol) : undefined}
|
||||
title={strategyName ? `전략: ${strategyName}` : undefined}
|
||||
className={[
|
||||
'vtd-target-item',
|
||||
'vtd-trade-item',
|
||||
sideCls,
|
||||
clickable ? 'vtd-trade-item--click' : '',
|
||||
].filter(Boolean).join(' ')}
|
||||
role={clickable ? 'button' : undefined}
|
||||
tabIndex={clickable ? 0 : undefined}
|
||||
onClick={clickable ? () => onSelectMarket!(t.symbol) : undefined}
|
||||
onKeyDown={clickable ? e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
onSelectMarket!(t.symbol);
|
||||
}
|
||||
} : undefined}
|
||||
>
|
||||
<td className="ptd-time">{fmtTradeTime(t.createdAt)}</td>
|
||||
<td>{coinCode(t.symbol)}</td>
|
||||
<td className={t.side === 'BUY' ? 'up' : 'down'}>
|
||||
{t.side === 'BUY' ? '매수' : '매도'}
|
||||
</td>
|
||||
<td className={t.source === 'STRATEGY' ? 'ptd-source--auto' : 'ptd-source--manual'}>
|
||||
{sourceLabel(t.source)}
|
||||
</td>
|
||||
<td>{fmtKrw(t.price)}</td>
|
||||
<td>{t.quantity}</td>
|
||||
<td>{fmtKrw(t.netAmount)}</td>
|
||||
</tr>
|
||||
<div className="vtd-target-item-main">
|
||||
<div className="vtd-target-names">
|
||||
<span className="vtd-target-ko">{ko}</span>
|
||||
<span className="vtd-target-en">{fmtTradeTime(t.createdAt)} · {en}</span>
|
||||
</div>
|
||||
<div className="vtd-target-item-actions">
|
||||
<span className={`vtd-trade-side-badge vtd-trade-side-badge--${isBuy ? 'buy' : 'sell'}`}>
|
||||
{isBuy ? '매수' : '매도'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="vtd-target-quote vtd-trade-quote" aria-label="체결 정보">
|
||||
<div className="vtd-target-quote-left">
|
||||
<span className={`vtd-target-arrow vtd-target-arrow--${isBuy ? 'rise' : 'fall'}`}>
|
||||
{isBuy ? '▲' : '▼'}
|
||||
</span>
|
||||
<span className="vtd-target-quote-pair">{coinCode(t.symbol)}/KRW</span>
|
||||
</div>
|
||||
<div className="vtd-target-quote-right">
|
||||
<span className={`vtd-target-price ${colorCls}`}>{fmtKrw(t.price)}</span>
|
||||
<span className={`vtd-target-change ${colorCls}`}>{fmtKrw(t.netAmount)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="vtd-target-strategy-field vtd-trade-meta-field">
|
||||
<span className="vtd-target-strategy-label">거래구분</span>
|
||||
<span
|
||||
className={`vtd-trade-meta-value${t.source === 'STRATEGY' ? ' vtd-trade-meta-value--auto' : ''}`}
|
||||
>
|
||||
{sourceLabel(t.source)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="vtd-target-strategy-field vtd-trade-meta-field">
|
||||
<span className="vtd-target-strategy-label">투자전략</span>
|
||||
<span className="vtd-trade-meta-value vtd-trade-meta-value--strategy" title={strategyName}>
|
||||
{strategyName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user