테블릿 로딩 이슈 수정
This commit is contained in:
+24
-9
@@ -689,8 +689,9 @@ function App() {
|
|||||||
}, [symbol]);
|
}, [symbol]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appSettingsLoaded) refreshPaperAccount();
|
if (!appSettingsLoaded || !formalLogin) return;
|
||||||
}, [appSettingsLoaded, refreshPaperAccount]);
|
refreshPaperAccount();
|
||||||
|
}, [appSettingsLoaded, formalLogin, refreshPaperAccount]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!appSettingsLoaded || !appDefaults.fcmPushEnabled) return;
|
if (!appSettingsLoaded || !appDefaults.fcmPushEnabled) return;
|
||||||
@@ -702,8 +703,9 @@ function App() {
|
|||||||
}, [appSettingsLoaded, appDefaults.fcmPushEnabled]);
|
}, [appSettingsLoaded, appDefaults.fcmPushEnabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appSettingsLoaded && paperTradingEnabled) refreshPaperAccount(symbol);
|
if (!appSettingsLoaded || !formalLogin || !paperTradingEnabled) return;
|
||||||
}, [symbol, appSettingsLoaded, paperTradingEnabled, refreshPaperAccount]);
|
refreshPaperAccount(symbol);
|
||||||
|
}, [symbol, appSettingsLoaded, formalLogin, paperTradingEnabled, refreshPaperAccount]);
|
||||||
|
|
||||||
const [alerts, setAlerts] = useState<Array<{ price: number; label: string }>>(
|
const [alerts, setAlerts] = useState<Array<{ price: number; label: string }>>(
|
||||||
(initial.alertPrices ?? []).map(p => ({ price: p, label: '' }))
|
(initial.alertPrices ?? []).map(p => ({ price: p, label: '' }))
|
||||||
@@ -808,8 +810,12 @@ function App() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!formalLogin) {
|
||||||
|
setActiveLiveSettings([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
refreshActiveLiveSettings();
|
refreshActiveLiveSettings();
|
||||||
}, [refreshActiveLiveSettings, isVirtualActive, virtualMonitoredMarkets.join(','), virtualSession.executionType, virtualSession.positionMode]);
|
}, [formalLogin, refreshActiveLiveSettings, isVirtualActive, virtualMonitoredMarkets.join(','), virtualSession.executionType, virtualSession.positionMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onVirtualChanged = () => refreshActiveLiveSettings();
|
const onVirtualChanged = () => refreshActiveLiveSettings();
|
||||||
@@ -818,7 +824,7 @@ function App() {
|
|||||||
}, [refreshActiveLiveSettings]);
|
}, [refreshActiveLiveSettings]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!appSettingsLoaded) return;
|
if (!appSettingsLoaded || !formalLogin) return;
|
||||||
if (isVirtualActive) {
|
if (isVirtualActive) {
|
||||||
const active = activeLiveSettings.find(s => s.market === symbol);
|
const active = activeLiveSettings.find(s => s.market === symbol);
|
||||||
setLiveStrategyCandleTypes(active?.strategyCandleTypes);
|
setLiveStrategyCandleTypes(active?.strategyCandleTypes);
|
||||||
@@ -827,7 +833,7 @@ function App() {
|
|||||||
loadLiveStrategySettings(symbol)
|
loadLiveStrategySettings(symbol)
|
||||||
.then(s => setLiveStrategyCandleTypes(s.strategyCandleTypes))
|
.then(s => setLiveStrategyCandleTypes(s.strategyCandleTypes))
|
||||||
.catch(() => { /* optional */ });
|
.catch(() => { /* optional */ });
|
||||||
}, [symbol, appSettingsLoaded, appDefaults.liveStrategyId, isVirtualActive, activeLiveSettings]);
|
}, [symbol, appSettingsLoaded, formalLogin, appDefaults.liveStrategyId, isVirtualActive, activeLiveSettings]);
|
||||||
|
|
||||||
const liveStrategySettings: LiveStrategySettingsDto = useMemo(() => {
|
const liveStrategySettings: LiveStrategySettingsDto = useMemo(() => {
|
||||||
if (isVirtualActive) {
|
if (isVirtualActive) {
|
||||||
@@ -876,6 +882,10 @@ function App() {
|
|||||||
}, [monitoredMarkets, activeLiveSettings, marketSubscriptions, liveStrategyCandleTypes]);
|
}, [monitoredMarkets, activeLiveSettings, marketSubscriptions, liveStrategyCandleTypes]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!formalLogin) {
|
||||||
|
setMarketSubscriptions([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (monitoredMarkets.length === 0) {
|
if (monitoredMarkets.length === 0) {
|
||||||
setMarketSubscriptions([]);
|
setMarketSubscriptions([]);
|
||||||
return;
|
return;
|
||||||
@@ -893,7 +903,7 @@ function App() {
|
|||||||
loadActiveLiveStrategySettings()
|
loadActiveLiveStrategySettings()
|
||||||
.then(list => setMarketSubscriptions(expandLiveStrategySubscriptions(list)))
|
.then(list => setMarketSubscriptions(expandLiveStrategySubscriptions(list)))
|
||||||
.catch(() => { /* liveStompSubscriptions 폴백 */ });
|
.catch(() => { /* liveStompSubscriptions 폴백 */ });
|
||||||
}, [isVirtualActive, appDefaults.liveStrategyCheck, appDefaults.liveStrategyId, monitoredMarkets.join(','), activeLiveSettings]);
|
}, [formalLogin, isVirtualActive, appDefaults.liveStrategyCheck, appDefaults.liveStrategyId, monitoredMarkets.join(','), activeLiveSettings]);
|
||||||
|
|
||||||
const handleLiveSettingsChange = useCallback((saved: LiveStrategySettingsDto) => {
|
const handleLiveSettingsChange = useCallback((saved: LiveStrategySettingsDto) => {
|
||||||
if (isVirtualActive) return;
|
if (isVirtualActive) return;
|
||||||
@@ -998,8 +1008,12 @@ function App() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!formalLogin) {
|
||||||
|
setLiveStrategies([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
refreshLiveStrategies();
|
refreshLiveStrategies();
|
||||||
}, [menuPage, showLivePanel, refreshLiveStrategies]);
|
}, [menuPage, showLivePanel, formalLogin, refreshLiveStrategies]);
|
||||||
|
|
||||||
const liveNotifierRef = useRef<LiveSignalNotifierHandle>(null);
|
const liveNotifierRef = useRef<LiveSignalNotifierHandle>(null);
|
||||||
const clearLiveMarkers = useCallback(() => {
|
const clearLiveMarkers = useCallback(() => {
|
||||||
@@ -2653,6 +2667,7 @@ function App() {
|
|||||||
onOpenChange={isMobile ? setMobileRightOpen : undefined}
|
onOpenChange={isMobile ? setMobileRightOpen : undefined}
|
||||||
activeTab={isMobile ? mobileRightTab : undefined}
|
activeTab={isMobile ? mobileRightTab : undefined}
|
||||||
onTabChange={isMobile ? setMobileRightTab : undefined}
|
onTabChange={isMobile ? setMobileRightTab : undefined}
|
||||||
|
wsFeedEnabled={chartScreenActive && useUpbit}
|
||||||
market={chartSymbol}
|
market={chartSymbol}
|
||||||
tradePrice={chartTicker?.tradePrice ?? null}
|
tradePrice={chartTicker?.tradePrice ?? null}
|
||||||
asks={orderbook.asks}
|
asks={orderbook.asks}
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ export interface RightSidePanelProps {
|
|||||||
paperTradingEnabled?: boolean;
|
paperTradingEnabled?: boolean;
|
||||||
paperAutoTradeEnabled?: boolean;
|
paperAutoTradeEnabled?: boolean;
|
||||||
onPaperOrderFilled?: () => void;
|
onPaperOrderFilled?: () => void;
|
||||||
|
/** 차트 화면·업비트 종목일 때만 체결 WS/REST */
|
||||||
|
wsFeedEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RightSidePanel: React.FC<RightSidePanelProps> = ({
|
const RightSidePanel: React.FC<RightSidePanelProps> = ({
|
||||||
@@ -74,6 +76,7 @@ const RightSidePanel: React.FC<RightSidePanelProps> = ({
|
|||||||
paperTradingEnabled = false,
|
paperTradingEnabled = false,
|
||||||
paperAutoTradeEnabled = false,
|
paperAutoTradeEnabled = false,
|
||||||
onPaperOrderFilled,
|
onPaperOrderFilled,
|
||||||
|
wsFeedEnabled = true,
|
||||||
}) => {
|
}) => {
|
||||||
const [openInternal, setOpenInternal] = useState(false);
|
const [openInternal, setOpenInternal] = useState(false);
|
||||||
const [tabInternal, setTabInternal] = useState<TradeRightPanelTab>('trade');
|
const [tabInternal, setTabInternal] = useState<TradeRightPanelTab>('trade');
|
||||||
@@ -81,7 +84,7 @@ const RightSidePanel: React.FC<RightSidePanelProps> = ({
|
|||||||
|
|
||||||
const isOpenControlled = openControlled !== undefined && onOpenChange !== undefined;
|
const isOpenControlled = openControlled !== undefined && onOpenChange !== undefined;
|
||||||
const open = isOpenControlled ? !!openControlled : openInternal;
|
const open = isOpenControlled ? !!openControlled : openInternal;
|
||||||
const { trades: recentTrades, strength: tradeStrength } = useUpbitRecentTrades(market, open);
|
const { trades: recentTrades, strength: tradeStrength } = useUpbitRecentTrades(market, open && wsFeedEnabled);
|
||||||
const setOpen = (next: boolean | ((p: boolean) => boolean)) => {
|
const setOpen = (next: boolean | ((p: boolean) => boolean)) => {
|
||||||
const cur = isOpenControlled ? !!openControlled : openInternal;
|
const cur = isOpenControlled ? !!openControlled : openInternal;
|
||||||
const value = typeof next === 'function' ? next(cur) : next;
|
const value = typeof next === 'function' ? next(cur) : next;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'
|
|||||||
import { ReactFlowProvider } from '@xyflow/react';
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
import DraggableModalFrame from './DraggableModalFrame';
|
import DraggableModalFrame from './DraggableModalFrame';
|
||||||
import type { Theme } from '../types/index';
|
import type { Theme } from '../types/index';
|
||||||
import { loadStrategies, loadStrategy, saveStrategy, deleteStrategy, type StrategyDto as ApiStrategyDto } from '../utils/backendApi';
|
import { hasRegisteredUser, loadStrategies, loadStrategy, saveStrategy, deleteStrategy, type StrategyDto as ApiStrategyDto } from '../utils/backendApi';
|
||||||
import { syncStrategyTimeframesFromLayoutIfNeeded } from '../utils/strategyTimeframeSync';
|
import { syncStrategyTimeframesFromLayoutIfNeeded } from '../utils/strategyTimeframeSync';
|
||||||
import type { LogicNode } from '../utils/strategyTypes';
|
import type { LogicNode } from '../utils/strategyTypes';
|
||||||
import {
|
import {
|
||||||
@@ -512,6 +512,7 @@ export default function StrategyEditorPage({ theme }: Props) {
|
|||||||
useEffect(() => { saveStratsLocal(strategies); }, [strategies]);
|
useEffect(() => { saveStratsLocal(strategies); }, [strategies]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!hasRegisteredUser()) return;
|
||||||
loadStrategies().then(async list => {
|
loadStrategies().then(async list => {
|
||||||
if (list?.length) {
|
if (list?.length) {
|
||||||
setStrategies(list.map(s => ({
|
setStrategies(list.map(s => ({
|
||||||
@@ -647,6 +648,9 @@ export default function StrategyEditorPage({ theme }: Props) {
|
|||||||
|
|
||||||
// flow layout START 분봉이 DB DSL보다 최신이면 서버에 반영 (실시간 평가는 DB 기준)
|
// flow layout START 분봉이 DB DSL보다 최신이면 서버에 반영 (실시간 평가는 DB 기준)
|
||||||
void (async () => {
|
void (async () => {
|
||||||
|
if (!hasRegisteredUser() || s.id == null) return;
|
||||||
|
const exists = await loadStrategy(s.id);
|
||||||
|
if (!exists) return;
|
||||||
const synced = await syncStrategyTimeframesFromLayoutIfNeeded(s.id, { ...s, flowLayout: stored ?? s.flowLayout });
|
const synced = await syncStrategyTimeframesFromLayoutIfNeeded(s.id, { ...s, flowLayout: stored ?? s.flowLayout });
|
||||||
if (!synced) return;
|
if (!synced) return;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -52,6 +52,14 @@ function getDeviceId(): string {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 정식 회원(userId) — 매매·전략·모의 API 필수 */
|
||||||
|
export function hasRegisteredUser(): boolean {
|
||||||
|
const id = localStorage.getItem('gc_user_id');
|
||||||
|
if (!id) return false;
|
||||||
|
const n = Number(id);
|
||||||
|
return Number.isFinite(n) && n > 0;
|
||||||
|
}
|
||||||
|
|
||||||
function authHeaders(): Record<string, string> {
|
function authHeaders(): Record<string, string> {
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -90,7 +98,12 @@ async function request<T>(path: string, init?: RequestInit): Promise<T | null> {
|
|||||||
});
|
});
|
||||||
if (res.status === 204) return null;
|
if (res.status === 204) return null;
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
console.error(`[backendApi] ${init?.method ?? 'GET'} ${path} → ${res.status}`);
|
const method = init?.method ?? 'GET';
|
||||||
|
const guest403 = res.status === 403 && !hasRegisteredUser();
|
||||||
|
const missing404 = res.status === 404 && method === 'GET';
|
||||||
|
if (!guest403 && !missing404) {
|
||||||
|
console.error(`[backendApi] ${method} ${path} → ${res.status}`);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (await res.json()) as T;
|
return (await res.json()) as T;
|
||||||
@@ -759,6 +772,7 @@ export interface PaperOrderRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loadPaperSummary(markPrices?: Record<string, number>): Promise<PaperSummaryDto | null> {
|
export async function loadPaperSummary(markPrices?: Record<string, number>): Promise<PaperSummaryDto | null> {
|
||||||
|
if (!hasRegisteredUser()) return null;
|
||||||
if (markPrices && Object.keys(markPrices).length > 0) {
|
if (markPrices && Object.keys(markPrices).length > 0) {
|
||||||
return request<PaperSummaryDto>('/paper/summary', {
|
return request<PaperSummaryDto>('/paper/summary', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -1041,11 +1055,13 @@ export interface StrategyDto {
|
|||||||
|
|
||||||
/** 전략 목록 로드 */
|
/** 전략 목록 로드 */
|
||||||
export async function loadStrategies(): Promise<StrategyDto[]> {
|
export async function loadStrategies(): Promise<StrategyDto[]> {
|
||||||
|
if (!hasRegisteredUser()) return [];
|
||||||
return (await request<StrategyDto[]>('/strategies')) ?? [];
|
return (await request<StrategyDto[]>('/strategies')) ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 단일 전략 로드 */
|
/** 단일 전략 로드 */
|
||||||
export async function loadStrategy(id: number): Promise<StrategyDto | null> {
|
export async function loadStrategy(id: number): Promise<StrategyDto | null> {
|
||||||
|
if (!hasRegisteredUser()) return null;
|
||||||
return request<StrategyDto>(`/strategies/${id}`);
|
return request<StrategyDto>(`/strategies/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1290,6 +1306,9 @@ export interface LiveStrategySettingsDto {
|
|||||||
export async function loadLiveStrategySettings(
|
export async function loadLiveStrategySettings(
|
||||||
market: string,
|
market: string,
|
||||||
): Promise<LiveStrategySettingsDto> {
|
): Promise<LiveStrategySettingsDto> {
|
||||||
|
if (!hasRegisteredUser()) {
|
||||||
|
return { market, strategyId: null, isLiveCheck: false, executionType: 'CANDLE_CLOSE', positionMode: 'LONG_ONLY' };
|
||||||
|
}
|
||||||
return (await request<LiveStrategySettingsDto>(
|
return (await request<LiveStrategySettingsDto>(
|
||||||
`/strategy/settings?market=${encodeURIComponent(market)}`,
|
`/strategy/settings?market=${encodeURIComponent(market)}`,
|
||||||
)) ?? { market, strategyId: null, isLiveCheck: false, executionType: 'CANDLE_CLOSE', positionMode: 'LONG_ONLY' };
|
)) ?? { market, strategyId: null, isLiveCheck: false, executionType: 'CANDLE_CLOSE', positionMode: 'LONG_ONLY' };
|
||||||
@@ -1317,6 +1336,7 @@ export function expandLiveStrategySubscriptions(
|
|||||||
|
|
||||||
/** 현재 디바이스에서 실시간 체크 ON + 전략 지정된 종목 목록 */
|
/** 현재 디바이스에서 실시간 체크 ON + 전략 지정된 종목 목록 */
|
||||||
export async function loadActiveLiveStrategySettings(): Promise<LiveStrategySettingsDto[]> {
|
export async function loadActiveLiveStrategySettings(): Promise<LiveStrategySettingsDto[]> {
|
||||||
|
if (!hasRegisteredUser()) return [];
|
||||||
return (await request<LiveStrategySettingsDto[]>('/strategy/settings/active')) ?? [];
|
return (await request<LiveStrategySettingsDto[]>('/strategy/settings/active')) ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1376,12 +1396,14 @@ export async function fetchLiveConditionStatus(
|
|||||||
|
|
||||||
/** 전략 DSL에 포함된 평가 시간봉 목록 (실시간 체크·STOMP 구독용) */
|
/** 전략 DSL에 포함된 평가 시간봉 목록 (실시간 체크·STOMP 구독용) */
|
||||||
export async function loadStrategyTimeframes(strategyId: number): Promise<string[]> {
|
export async function loadStrategyTimeframes(strategyId: number): Promise<string[]> {
|
||||||
|
if (!hasRegisteredUser()) return ['1m'];
|
||||||
const list = await request<string[]>(`/strategies/${strategyId}/timeframes`);
|
const list = await request<string[]>(`/strategies/${strategyId}/timeframes`);
|
||||||
return list?.length ? list : ['1m'];
|
return list?.length ? list : ['1m'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DB DSL TIMEFRAME 래핑 보정 (3분봉 전략이 1m으로 평가되는 레거시 수정) */
|
/** DB DSL TIMEFRAME 래핑 보정 (3분봉 전략이 1m으로 평가되는 레거시 수정) */
|
||||||
export async function repairStrategyTimeframes(strategyId: number): Promise<void> {
|
export async function repairStrategyTimeframes(strategyId: number): Promise<void> {
|
||||||
|
if (!hasRegisteredUser()) return;
|
||||||
await request(`/strategies/${strategyId}/repair-timeframes`, { method: 'POST' });
|
await request(`/strategies/${strategyId}/repair-timeframes`, { method: 'POST' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ export async function syncStrategyTimeframesFromLayoutIfNeeded(
|
|||||||
strategy?: StrategyDto | null,
|
strategy?: StrategyDto | null,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const strat = (await loadStrategy(strategyId)) ?? strategy ?? null;
|
const strat = (await loadStrategy(strategyId)) ?? strategy ?? null;
|
||||||
if (!strat) return true;
|
if (!strat) return false;
|
||||||
|
|
||||||
const uiTfs = collectUiEvaluationTimeframes(strategyId, strat);
|
const uiTfs = collectUiEvaluationTimeframes(strategyId, strat);
|
||||||
if (uiTfs.length === 0) return true;
|
if (uiTfs.length === 0) return true;
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ function listenerCount(): number {
|
|||||||
return listeners.size;
|
return listeners.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mayOpenSocket(): boolean {
|
||||||
|
if (listenerCount() === 0) return false;
|
||||||
|
if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function cancelPendingDisconnect(): void {
|
function cancelPendingDisconnect(): void {
|
||||||
if (disconnectTimer) {
|
if (disconnectTimer) {
|
||||||
clearTimeout(disconnectTimer);
|
clearTimeout(disconnectTimer);
|
||||||
@@ -134,7 +140,7 @@ function dispatch(text: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function scheduleReconnect(): void {
|
function scheduleReconnect(): void {
|
||||||
if (listenerCount() === 0) return;
|
if (!mayOpenSocket()) return;
|
||||||
if (reconnectTimer) return;
|
if (reconnectTimer) return;
|
||||||
const delay = Math.min(RECONNECT_BASE * 2 ** retryCount, RECONNECT_MAX);
|
const delay = Math.min(RECONNECT_BASE * 2 ** retryCount, RECONNECT_MAX);
|
||||||
retryCount += 1;
|
retryCount += 1;
|
||||||
@@ -236,6 +242,17 @@ export function subscribeUpbitWsConnection(listener: ConnectionListener): () =>
|
|||||||
return () => connectionListeners.delete(listener);
|
return () => connectionListeners.delete(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.visibilityState === 'hidden') {
|
||||||
|
cancelPendingConnect();
|
||||||
|
if (listenerCount() === 0) teardownSocket();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mayOpenSocket()) scheduleConnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 업비트 WS 채널 구독 (참조 카운트). codes 가 비어 있으면 구독하지 않음.
|
* 업비트 WS 채널 구독 (참조 카운트). codes 가 비어 있으면 구독하지 않음.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* ui_preferences.virtual.targets 가 비었을 때 서버·레거시에서 투자대상 복구
|
* ui_preferences.virtual.targets 가 비었을 때 서버·레거시에서 투자대상 복구
|
||||||
*/
|
*/
|
||||||
import { loadActiveLiveStrategySettings, loadWatchlist } from './backendApi';
|
import { hasRegisteredUser, loadActiveLiveStrategySettings, loadWatchlist } from './backendApi';
|
||||||
import {
|
import {
|
||||||
loadVirtualSession,
|
loadVirtualSession,
|
||||||
loadVirtualTargets,
|
loadVirtualTargets,
|
||||||
@@ -67,6 +67,8 @@ export async function hydrateVirtualTargetsIfEmpty(): Promise<VirtualTargetItem[
|
|||||||
const session = loadVirtualSession();
|
const session = loadVirtualSession();
|
||||||
const globalId = session.globalStrategyId;
|
const globalId = session.globalStrategyId;
|
||||||
|
|
||||||
|
if (!hasRegisteredUser()) return [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const active = await loadActiveLiveStrategySettings();
|
const active = await loadActiveLiveStrategySettings();
|
||||||
if (active.length > 0) return fromLiveSettings(active, globalId);
|
if (active.length > 0) return fromLiveSettings(active, globalId);
|
||||||
|
|||||||
Reference in New Issue
Block a user