import React, { useState, useEffect, useMemo } from 'react'; import { TrendingUp, Wallet, Activity, Briefcase, PieChart, Database, Zap, Timer, Trash2 } from 'lucide-react'; import { StockItem, TradeOrder, MarketType, WatchlistGroup, OrderType, AutoTradeConfig, ReservedOrder } from '../types'; import { DbService, HoldingItem } from '../services/dbService'; import StockDetailModal from '../components/StockDetailModal'; import TradeModal from '../components/TradeModal'; import { StatCard } from '../components/CommonUI'; import { StockRow } from '../components/StockRow'; interface DashboardProps { marketMode: MarketType; watchlistGroups: WatchlistGroup[]; stocks: StockItem[]; orders: TradeOrder[]; reservedOrders: ReservedOrder[]; autoTrades: AutoTradeConfig[]; onManualOrder: (order: Omit) => Promise; onAddReservedOrder: (order: Omit) => Promise; onDeleteReservedOrder: (id: string) => Promise; onRefreshHoldings: () => void; } const Dashboard: React.FC = ({ marketMode, watchlistGroups, stocks, reservedOrders, onAddReservedOrder, onDeleteReservedOrder, onRefreshHoldings, orders }) => { const [holdings, setHoldings] = useState([]); const [summary, setSummary] = useState({ totalAssets: 0, buyingPower: 0 }); const [activeGroupId, setActiveGroupId] = useState(null); const [detailStock, setDetailStock] = useState(null); const [tradeContext, setTradeContext] = useState<{ stock: StockItem, type: OrderType } | null>(null); const dbService = useMemo(() => new DbService(), []); useEffect(() => { loadData(); }, [orders, marketMode, reservedOrders]); const activeMarketGroups = useMemo(() => { return watchlistGroups.filter(group => group.market === marketMode); }, [watchlistGroups, marketMode]); useEffect(() => { if (activeMarketGroups.length > 0) { if (!activeGroupId || !activeMarketGroups.find(g => g.id === activeGroupId)) { setActiveGroupId(activeMarketGroups[0].id); } } else { setActiveGroupId(null); } }, [marketMode, activeMarketGroups, activeGroupId]); const loadData = async () => { const allHoldings = await dbService.getHoldings(); const filteredHoldings = allHoldings.filter(h => h.market === marketMode); const accSummary = await dbService.getAccountSummary(); setHoldings(filteredHoldings); setSummary(accSummary); }; const calculatePL = (holding: HoldingItem) => { const currentStock = stocks.find(s => s.code === holding.code); const currentPrice = currentStock ? currentStock.price : holding.avgPrice; const pl = (currentPrice - holding.avgPrice) * holding.quantity; const plPercent = ((currentPrice - holding.avgPrice) / holding.avgPrice) * 100; const value = currentPrice * holding.quantity; return { pl, plPercent, currentPrice, value, stock: currentStock }; }; const totalLiquidationSummary = holdings.reduce((acc, h) => { const plData = calculatePL(h); return { totalValue: acc.totalValue + plData.value, totalPL: acc.totalPL + plData.pl, totalCost: acc.totalCost + (h.avgPrice * h.quantity) }; }, { totalValue: 0, totalPL: 0, totalCost: 0 }); const aggregatePLPercent = totalLiquidationSummary.totalCost > 0 ? (totalLiquidationSummary.totalPL / totalLiquidationSummary.totalCost) * 100 : 0; const selectedGroup = activeMarketGroups.find(g => g.id === activeGroupId) || activeMarketGroups[0]; return (
} /> = 0} icon={= 0 ? "text-emerald-500" : "text-rose-500"} />} /> } /> } />

관심 그룹

{activeMarketGroups.map(group => ( ))}
{selectedGroup?.codes.map(code => stocks.find(s => s.code === code)).filter(s => s?.market === marketMode).map(stock => { if (!stock) return null; return ( setTradeContext({ stock, type })} onClick={() => setDetailStock(stock)} /> ); })}

보유 포트폴리오

{holdings.map(holding => { const { pl, plPercent, stock } = calculatePL(holding); if (!stock) return null; return ( setTradeContext({ stock, type })} onClick={() => setDetailStock(stock)} /> ); })}
종목 현재가 수익금 (%) 주문

실시간 감시 목록

{reservedOrders.filter(o => o.market === marketMode).map(order => (

{order.stockName}

))}
{detailStock && setDetailStock(null)} />} {tradeContext && setTradeContext(null)} onExecute={onAddReservedOrder} />}
); }; export default Dashboard;