가상투자 화면 추가

This commit is contained in:
Macbook
2026-05-25 13:14:36 +09:00
parent 1fe3e404fa
commit 339e2355eb
23 changed files with 2230 additions and 457 deletions
@@ -0,0 +1,81 @@
import React, { useMemo } from 'react';
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
import {
buildConditionMetrics,
computeMatchRate,
formatUpdatedTime,
getTrafficLightState,
} from '../../utils/virtualSignalMetrics';
import VirtualSignalEqualizer from './VirtualSignalEqualizer';
import VirtualSignalTrafficLight from './VirtualSignalTrafficLight';
import VirtualConditionList from './VirtualConditionList';
import VirtualIndicatorCompareTable from './VirtualIndicatorCompareTable';
import type { VirtualCardViewMode } from '../../utils/virtualTradingStorage';
interface Props {
snapshot: VirtualIndicatorSnapshot | undefined;
viewMode?: VirtualCardViewMode;
receiving?: boolean;
className?: string;
}
const VirtualTargetSignalPanel: React.FC<Props> = ({
snapshot,
viewMode = 'summary',
receiving = false,
className = '',
}) => {
const rows = snapshot?.rows ?? [];
const isDetail = viewMode === 'detail';
const metrics = useMemo(() => buildConditionMetrics(rows), [rows]);
const matchRate = useMemo(
() => computeMatchRate(metrics, snapshot?.matchRate),
[metrics, snapshot?.matchRate],
);
const trafficState = useMemo(() => getTrafficLightState(matchRate, metrics), [matchRate, metrics]);
const metCount = metrics.filter(m => m.status === 'match').length;
const evalCount = metrics.filter(m => m.status !== 'unknown').length;
if (rows.length === 0) {
return (
<p className={`vtd-muted vtd-card-empty${className ? ` ${className}` : ''}`}>
·
</p>
);
}
return (
<div
className={[
'vtd-sig-panel-wrap',
isDetail ? '' : 'vtd-sig-panel-wrap--summary',
receiving ? 'vtd-sig-panel-wrap--receiving' : '',
className,
].filter(Boolean).join(' ')}
>
{isDetail && evalCount > 0 && (
<div className="vtd-focus-sig-meta">
<span className="vtd-card-met-count">{metCount}/{evalCount} </span>
</div>
)}
<div className={`vtd-sig-panel${isDetail ? '' : ' vtd-sig-panel--summary'}`}>
<div className="vtd-sig-panel-title">SIGNAL INTELLIGENCE &amp; MATCH RATES</div>
<div className="vtd-sig-visual">
<div className="vtd-sig-visual-eq">
<VirtualSignalEqualizer matchRate={matchRate} />
</div>
<VirtualConditionList metrics={metrics} />
<VirtualSignalTrafficLight state={trafficState} matchRate={matchRate} />
</div>
{isDetail && <VirtualIndicatorCompareTable metrics={metrics} />}
</div>
<div className="vtd-card-foot">
<span className="vtd-card-updated"> {formatUpdatedTime(snapshot?.updatedAt)}</span>
<span className="vtd-card-match-summary"> {matchRate}%</span>
</div>
</div>
);
};
export default VirtualTargetSignalPanel;