137 lines
5.5 KiB
TypeScript
137 lines
5.5 KiB
TypeScript
import React, { useCallback } from 'react';
|
|
import type { PaperAllocationDto } from '../../utils/backendApi';
|
|
import { patchPaperAllocation } from '../../utils/backendApi';
|
|
import { fmtKrw } from '../TradeOrderPanel';
|
|
|
|
function coinCode(symbol: string): string {
|
|
return symbol.replace(/^KRW-/, '');
|
|
}
|
|
|
|
interface Props {
|
|
allocations: PaperAllocationDto[];
|
|
selectedMarket?: string;
|
|
onSelectMarket?: (market: string) => void;
|
|
onChanged?: () => void;
|
|
}
|
|
|
|
const PaperAllocationTable: React.FC<Props> = ({
|
|
allocations,
|
|
selectedMarket,
|
|
onSelectMarket,
|
|
onChanged,
|
|
}) => {
|
|
const toggleActive = useCallback(async (row: PaperAllocationDto) => {
|
|
await patchPaperAllocation(row.symbol, { isActive: !row.isActive });
|
|
onChanged?.();
|
|
}, [onChanged]);
|
|
|
|
if (!allocations.length) {
|
|
return (
|
|
<div className="ptd-item-card-section ptd-alloc-card-section">
|
|
<div className="vtd-target-list-head">
|
|
<span>종목별 한도</span>
|
|
<span className="vtd-target-count">0종목</span>
|
|
</div>
|
|
<p className="ptd-muted ptd-item-card-empty">등록된 종목 한도가 없습니다. 가상투자 대상 추가 시 동기화됩니다.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="ptd-item-card-section ptd-alloc-card-section">
|
|
<div className="vtd-target-list-head">
|
|
<span>종목별 한도</span>
|
|
<span className="vtd-target-count">{allocations.length}종목</span>
|
|
</div>
|
|
<div className="ptd-item-card-scroll">
|
|
<div className="vtd-target-list ptd-item-card-list">
|
|
{allocations.map(row => {
|
|
const ret = row.symbolReturnPct ?? 0;
|
|
const selected = row.symbol === selectedMarket;
|
|
const name = row.koreanName || coinCode(row.symbol);
|
|
const code = coinCode(row.symbol);
|
|
const up = ret >= 0;
|
|
|
|
return (
|
|
<div
|
|
key={row.symbol}
|
|
className={[
|
|
'vtd-target-item',
|
|
'ptd-item-card',
|
|
'ptd-alloc-card',
|
|
selected ? 'vtd-target-item--active' : '',
|
|
row.isActive === false ? 'ptd-alloc-card--inactive' : '',
|
|
].filter(Boolean).join(' ')}
|
|
role="button"
|
|
tabIndex={0}
|
|
onClick={() => onSelectMarket?.(row.symbol)}
|
|
onKeyDown={e => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
onSelectMarket?.(row.symbol);
|
|
}
|
|
}}
|
|
>
|
|
<div className="vtd-target-item-main">
|
|
<div className="vtd-target-names">
|
|
<span className="vtd-target-ko">{name}</span>
|
|
<span className="vtd-target-en">{code}/KRW</span>
|
|
</div>
|
|
<div className="vtd-target-item-actions">
|
|
<button
|
|
type="button"
|
|
className={`ptd-alloc-toggle${row.isActive !== false ? ' ptd-alloc-toggle--on' : ''}`}
|
|
onClick={e => {
|
|
e.stopPropagation();
|
|
void toggleActive(row);
|
|
}}
|
|
title={row.isActive !== false ? '신규 매수 허용' : '신규 매수 차단'}
|
|
>
|
|
{row.isActive !== false ? 'ON' : 'OFF'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="ptd-item-card-metrics">
|
|
<div className="vtd-target-strategy-field">
|
|
<span className="vtd-target-strategy-label">비중</span>
|
|
<span className="vtd-trade-meta-value">{(row.weightPct ?? 0).toFixed(1)}%</span>
|
|
</div>
|
|
<div className="vtd-target-strategy-field">
|
|
<span className="vtd-target-strategy-label">한도</span>
|
|
<span className="vtd-trade-meta-value">{fmtKrw(row.maxInvestKrw)}</span>
|
|
</div>
|
|
<div className="vtd-target-strategy-field">
|
|
<span className="vtd-target-strategy-label">투입</span>
|
|
<span className="vtd-trade-meta-value">{fmtKrw(row.investedKrw ?? 0)}</span>
|
|
</div>
|
|
<div className="vtd-target-strategy-field">
|
|
<span className="vtd-target-strategy-label">평가</span>
|
|
<span className="vtd-trade-meta-value">{fmtKrw(row.evalAmount ?? 0)}</span>
|
|
</div>
|
|
<div className="vtd-target-strategy-field">
|
|
<span className="vtd-target-strategy-label">수익률</span>
|
|
<span className={`vtd-trade-meta-value ${up ? 'vtd-target-up' : 'vtd-target-dn'}`}>
|
|
{ret >= 0 ? '+' : ''}{ret.toFixed(2)}%
|
|
</span>
|
|
</div>
|
|
{(row.buyStage1Krw || row.buyStage2Krw || row.sellStage1Krw) ? (
|
|
<div className="vtd-target-strategy-field ptd-alloc-stage-badge">
|
|
<span className="vtd-target-strategy-label">분할</span>
|
|
<span className="vtd-trade-meta-value">
|
|
매수 {row.buyStageDone ?? 0}/3 · 매도 {row.sellStageDone ?? 0}/3
|
|
</span>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PaperAllocationTable;
|