모의투자 관리 기능 추가

This commit is contained in:
Macbook
2026-05-31 03:47:07 +09:00
parent 9d7dddfa57
commit 16d0e2c226
78 changed files with 4688 additions and 972 deletions
+47 -90
View File
@@ -4,9 +4,13 @@
* - 호가 탭: 실시간 호가창
*/
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { OrderbookPanel } from './OrderbookPanel';
import TradeOrderPanel from './TradeOrderPanel';
import PaperSplitPanel from './paper/PaperSplitPanel';
import {
TradeSplitOrderPanel,
TradeOrderbookPanelContent,
TradeRightPanelTabs,
TradeRightPanelBody,
type TradeRightPanelTab,
} from './trade';
import type { OrderbookDisplayUnit, WsStatus } from '../hooks/useUpbitOrderbook';
import { useUpbitRecentTrades } from '../hooks/useUpbitRecentTrades';
import type { OrderbookTickerInfo } from './OrderbookPanel';
@@ -19,8 +23,8 @@ export interface RightSidePanelProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
/** 모바일 도크에서 호가/매매 탭 지정 */
activeTab?: PanelTab;
onTabChange?: (tab: PanelTab) => void;
activeTab?: TradeRightPanelTab;
onTabChange?: (tab: TradeRightPanelTab) => void;
market: string;
tradePrice: number | null;
asks: OrderbookDisplayUnit[];
@@ -44,11 +48,6 @@ export interface RightSidePanelProps {
onPaperOrderFilled?: () => void;
}
const PANEL_TABS: { id: PanelTab; label: string }[] = [
{ id: 'trade', label: '매매' },
{ id: 'orderbook', label: '호가' },
];
const RightSidePanel: React.FC<RightSidePanelProps> = ({
open: openControlled,
onOpenChange,
@@ -77,7 +76,7 @@ const RightSidePanel: React.FC<RightSidePanelProps> = ({
onPaperOrderFilled,
}) => {
const [openInternal, setOpenInternal] = useState(false);
const [tabInternal, setTabInternal] = useState<PanelTab>('trade');
const [tabInternal, setTabInternal] = useState<TradeRightPanelTab>('trade');
const tradeSectionRef = useRef<HTMLDivElement>(null);
const { trades: recentTrades, strength: tradeStrength } = useUpbitRecentTrades(market);
@@ -91,7 +90,7 @@ const RightSidePanel: React.FC<RightSidePanelProps> = ({
};
const activeTab = activeTabControlled ?? tabInternal;
const setActiveTab = useCallback((tab: PanelTab) => {
const setActiveTab = useCallback((tab: TradeRightPanelTab) => {
if (onTabChange) onTabChange(tab);
else setTabInternal(tab);
}, [onTabChange]);
@@ -130,91 +129,49 @@ const RightSidePanel: React.FC<RightSidePanelProps> = ({
</svg>
</button>
<div className="rsp-panel">
<div className="rsp-tabs bps-right-tabs">
{PANEL_TABS.map(tab => (
<button
key={tab.id}
type="button"
className={`bps-right-tab${activeTab === tab.id ? ' bps-right-tab--on' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.label}
</button>
))}
</div>
<div className="rsp-panel trade-right-panel">
<TradeRightPanelTabs
activeTab={activeTab}
onTabChange={setActiveTab}
className="rsp-tabs"
/>
<div className="rsp-body ptd-right-body" ref={tradeSectionRef}>
<TradeRightPanelBody anchorRef={tradeSectionRef} className="rsp-body-wrap">
{activeTab === 'trade' && (
<PaperSplitPanel
className="ptd-split-panel--right"
topTitle="매수"
bottomTitle="매도"
top={(
<div className="ptd-order-card">
<TradeOrderPanel
side="buy"
market={market}
tradePrice={tradePrice}
availableKrw={availableKrw}
fillRequest={fillRequest}
searchAnchorRef={tradeSectionRef}
onMarketSelect={onMarketSelect}
showSymbolField
paperTradingEnabled={paperTradingEnabled}
paperAutoTradeEnabled={paperAutoTradeEnabled}
onPaperOrderFilled={onPaperOrderFilled}
/>
</div>
)}
bottom={(
<div className="ptd-order-card">
<TradeOrderPanel
side="sell"
market={market}
tradePrice={tradePrice}
availableKrw={availableKrw}
availableCoinQty={availableCoinQty}
fillRequest={fillRequest}
searchAnchorRef={tradeSectionRef}
onMarketSelect={onMarketSelect}
showSymbolField={false}
paperTradingEnabled={paperTradingEnabled}
paperAutoTradeEnabled={paperAutoTradeEnabled}
onPaperOrderFilled={onPaperOrderFilled}
/>
</div>
)}
<TradeSplitOrderPanel
market={market}
tradePrice={tradePrice}
availableKrw={availableKrw}
availableCoinQty={availableCoinQty}
fillRequest={fillRequest}
searchAnchorRef={tradeSectionRef}
onMarketSelect={onMarketSelect}
paperTradingEnabled={paperTradingEnabled}
paperAutoTradeEnabled={paperAutoTradeEnabled}
onPaperOrderFilled={onPaperOrderFilled}
/>
)}
{activeTab === 'orderbook' && (
<div className="rsp-ob-stack ptd-ob-stack--fill">
<div className="rsp-trade-card rsp-ob-card">
<div className="rsp-trade-card-title rsp-ob-card-title"> </div>
<div className="rsp-trade-card-body rsp-ob-card-body">
<OrderbookPanel
market={market}
asks={asks}
bids={bids}
totalAskSize={totalAskSize}
totalBidSize={totalBidSize}
wsStatus={wsStatus}
bestAsk={bestAsk}
bestBid={bestBid}
spread={spread}
spreadPct={spreadPct}
prevClose={prevClose}
tickerInfo={tickerInfo}
recentTrades={recentTrades}
tradeStrength={tradeStrength}
onRowClick={handleOrderbookRowClick}
/>
</div>
</div>
</div>
<TradeOrderbookPanelContent
market={market}
asks={asks}
bids={bids}
totalAskSize={totalAskSize}
totalBidSize={totalBidSize}
wsStatus={wsStatus}
bestAsk={bestAsk}
bestBid={bestBid}
spread={spread}
spreadPct={spreadPct}
prevClose={prevClose}
tickerInfo={tickerInfo}
recentTrades={recentTrades}
tradeStrength={tradeStrength ?? undefined}
onRowClick={handleOrderbookRowClick}
/>
)}
</div>
</TradeRightPanelBody>
</div>
</div>
);