추세검색 설정 추가
This commit is contained in:
@@ -50,6 +50,8 @@ import {
|
||||
syncVirtualTargetsToBackend,
|
||||
stopVirtualLiveOnBackend,
|
||||
} from '../utils/virtualLiveStrategySync';
|
||||
import { persistVirtualTargetPinned } from '../utils/virtualTargetMutations';
|
||||
import { virtualTargetLimitMessage } from '../utils/virtualTargetLimits';
|
||||
import '../styles/virtualTradingDashboard.css';
|
||||
|
||||
type RightTab = 'trade' | 'orderbook' | 'history';
|
||||
@@ -95,6 +97,7 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
?? 'BACKEND_STOMP') as ChartRealtimeSource;
|
||||
const chartSeriesPriceLabels = appChartDefaults.chartSeriesPriceLabels;
|
||||
const chartLiveReceiveHighlight = appChartDefaults.chartLiveReceiveHighlight;
|
||||
const virtualTargetMaxCount = appChartDefaults.virtualTargetMaxCount;
|
||||
|
||||
useEffect(() => {
|
||||
void Promise.all([
|
||||
@@ -104,6 +107,29 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
]).finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
/** DB is_pinned → localStorage 투자대상 목록 동기화 (최초 1회) */
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
const initial = loadVirtualTargets();
|
||||
if (initial.length === 0) return;
|
||||
void (async () => {
|
||||
const merged = await Promise.all(
|
||||
initial.map(async t => {
|
||||
try {
|
||||
const s = await loadLiveStrategySettings(t.market);
|
||||
const pinned = !!s.isPinned;
|
||||
if (!!t.pinned === pinned) return t;
|
||||
return { ...t, pinned };
|
||||
} catch {
|
||||
return t;
|
||||
}
|
||||
}),
|
||||
);
|
||||
if (!cancelled) setTargets(merged);
|
||||
})();
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
useEffect(() => { saveVirtualTargets(targets); }, [targets]);
|
||||
useEffect(() => { saveVirtualSession(session); }, [session]);
|
||||
useEffect(() => { saveVirtualCardViewMode(viewMode); }, [viewMode]);
|
||||
@@ -185,11 +211,27 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
}, [tickers]);
|
||||
|
||||
const handleTargetsChange = useCallback((items: VirtualTargetItem[]) => {
|
||||
if (items.length > virtualTargetMaxCount) {
|
||||
window.alert(virtualTargetLimitMessage(virtualTargetMaxCount));
|
||||
return;
|
||||
}
|
||||
setTargets(items);
|
||||
if (items.length > 0 && !items.some(t => t.market === selectedMarket)) {
|
||||
handleSelectMarket(items[0].market);
|
||||
}
|
||||
}, [selectedMarket, handleSelectMarket]);
|
||||
}, [selectedMarket, handleSelectMarket, virtualTargetMaxCount]);
|
||||
|
||||
const handleTogglePin = useCallback((market: string) => {
|
||||
setTargets(prev => {
|
||||
const item = prev.find(t => t.market === market);
|
||||
if (!item) return prev;
|
||||
const pinned = !item.pinned;
|
||||
void persistVirtualTargetPinned(market, pinned).catch(() => {
|
||||
window.alert('고정 설정 저장에 실패했습니다.');
|
||||
});
|
||||
return prev.map(t => (t.market === market ? { ...t, pinned } : t));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleGlobalStrategyChange = useCallback((strategyId: number | null) => {
|
||||
const next = { ...session, globalStrategyId: strategyId };
|
||||
@@ -386,6 +428,8 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
onTargetsChange={handleTargetsChange}
|
||||
onSelectMarket={handleSelectMarket}
|
||||
onTargetStrategyChange={(market, strategyId) => void handleTargetStrategyChange(market, strategyId)}
|
||||
onTogglePin={handleTogglePin}
|
||||
virtualTargetMaxCount={virtualTargetMaxCount}
|
||||
/>
|
||||
)}
|
||||
center={(
|
||||
|
||||
Reference in New Issue
Block a user