import React, { lazy, Suspense, useEffect, useState } from 'react';
import { Capacitor } from '@capacitor/core';
import { StatusBar, Style } from '@capacitor/status-bar';
import { SplashScreen as CapSplashScreen } from '@capacitor/splash-screen';
import { AuthProvider, useAuth } from './contexts/AuthContext';
import { NavigationProvider, useNavigation } from './contexts/NavigationContext';
import { TradeNotificationProvider, useTradeNotification } from './contexts/TradeNotificationContext';
import { useAppSettings, resolveAppDefaults } from './hooks/useAppSettings';
import TabBar, { type TabId } from './components/TabBar';
import LiveSignalBridge from './components/LiveSignalBridge';
import AppUpdateGate from './components/AppUpdateGate';
import LoginScreen from './screens/LoginScreen';
import '@frontend/styles/splashScreen.css';
import './theme/global.css';
const VirtualTradingScreen = lazy(() => import('./screens/virtual/VirtualTradingScreen'));
const StrategyEditorScreen = lazy(() => import('./screens/strategy/StrategyEditorScreen'));
const NotificationsScreen = lazy(() => import('./screens/notifications/NotificationsScreen'));
const SettingsScreen = lazy(() => import('./screens/settings/SettingsScreen'));
function ToastStack() {
const { toastNotifications, dismissToast } = useTradeNotification();
if (toastNotifications.length === 0) return null;
return (
{toastNotifications.slice(0, 3).map(t => (
dismissToast(t.id)}>
{t.signalType === 'BUY' ? '매수' : '매도'}
{' '}{t.market} · ₩{t.price?.toLocaleString()}
))}
);
}
function MainApp() {
const { tab, setTab, openVirtualFocus, goVirtualList, goNotifyList } = useNavigation();
const { unreadCount } = useTradeNotification();
const { sessionKey } = useAuth();
const { settings, isLoaded } = useAppSettings(sessionKey);
const defaults = resolveAppDefaults(settings);
/** FCM/알림 권한: 로그인·메인 진입 시 호출하지 않음 — 설정 버튼에서만 */
useEffect(() => {
document.documentElement.setAttribute('data-theme', defaults.theme ?? 'dark');
}, [defaults.theme]);
useEffect(() => {
if (tab === 'virtual') goNotifyList();
else if (tab === 'notifications') goVirtualList();
}, [tab, goVirtualList, goNotifyList]);
const screens: Record = {
virtual: ,
strategy: ,
notifications: ,
settings: ,
};
return (
로딩…
}>
{screens[tab]}
);
}
function AppRoot() {
const {
authReady,
isAppEntered,
handleLoginSuccess,
handleGuestEnter,
sessionKey,
} = useAuth();
const [nativeReady, setNativeReady] = useState(false);
useEffect(() => {
void (async () => {
if (Capacitor.isNativePlatform()) {
try {
await StatusBar.setStyle({ style: Style.Dark });
await StatusBar.setBackgroundColor({ color: '#0f0f23' });
await CapSplashScreen.hide();
} catch { /* web dev */ }
}
setNativeReady(true);
})();
}, []);
if (!authReady || !nativeReady) {
return GoldenChart
;
}
if (!isAppEntered) {
return (
);
}
return (
);
}
export default function App() {
return (
);
}