mobile download
This commit is contained in:
+23
-22
@@ -39,7 +39,7 @@ import {
|
||||
import { normalizeSmaConfig, createDefaultSmaPlotVisibility } from './utils/smaConfig';
|
||||
import { normalizeIchimokuConfig } from './utils/ichimokuConfig';
|
||||
import { isUpbitMarket, UPBIT_MARKETS } from './utils/upbitApi';
|
||||
import { getFavorites, saveFavorites, FAVORITES_CHANGED_EVENT } from './utils/marketStorage';
|
||||
import { getFavorites, saveFavorites, initFavoritesFromDb, initHoldingsFromDb, FAVORITES_CHANGED_EVENT } from './utils/marketStorage';
|
||||
import { useChartRealtimeData, type WsStatus } from './hooks/useChartRealtimeData';
|
||||
import type { OHLCVBar, ChartType, Theme, Timeframe, IndicatorConfig, LegendData, Drawing, ChartMode, MainChartStyle, TradeOrderFillRequest } from './types';
|
||||
import type { ChartManager } from './utils/ChartManager';
|
||||
@@ -105,6 +105,7 @@ import { notifyPaperTradesChanged } from './utils/paperTradeEvents';
|
||||
import { useIsMobile } from './hooks/useMediaQuery';
|
||||
import MobileChartDock from './components/MobileChartDock';
|
||||
import LoginModal from './components/LoginModal';
|
||||
import AppDownloadModal from './components/AppDownloadModal';
|
||||
import SplashScreen from './components/SplashScreen';
|
||||
import { getAuthSession, setAuthSession, clearAuthSession, type AuthSession } from './utils/auth';
|
||||
import { isAppEntered, setAppEntered, clearAppEntered } from './utils/appEntry';
|
||||
@@ -161,6 +162,7 @@ function App() {
|
||||
isAppEntered() && !getAuthSession(),
|
||||
);
|
||||
const [loginOpen, setLoginOpen] = useState(false);
|
||||
const [appDownloadOpen, setAppDownloadOpen] = useState(false);
|
||||
|
||||
// 전역 지표 파라미터 + 시각 설정 DB 동기화
|
||||
const {
|
||||
@@ -217,16 +219,8 @@ function App() {
|
||||
const { tickers: marketTickers, loading: marketLoading, usdRate } = useMarketTicker();
|
||||
|
||||
// ── 레이아웃 상태 ─────────────────────────────────────────────────────
|
||||
const [layoutDef, setLayoutDef] = useState<LayoutDef>(() => {
|
||||
const saved = localStorage.getItem('chartLayout');
|
||||
return LAYOUTS.find(l => l.id === saved) ?? LAYOUTS[0];
|
||||
});
|
||||
const [syncOptions, setSyncOptions] = useState<SyncOptions>(() => {
|
||||
try {
|
||||
const s = localStorage.getItem('chartLayoutSync');
|
||||
return s ? JSON.parse(s) : DEFAULT_SYNC;
|
||||
} catch { return DEFAULT_SYNC; }
|
||||
});
|
||||
const [layoutDef, setLayoutDef] = useState<LayoutDef>(() => LAYOUTS[0]);
|
||||
const [syncOptions, setSyncOptions] = useState<SyncOptions>(DEFAULT_SYNC);
|
||||
const [activeSlot, setActiveSlot] = useState(0);
|
||||
// 멀티 레이아웃에서 현재 활성 슬롯의 지표 목록 (IndicatorModal 표시용)
|
||||
const [activeSlotIndicators, setActiveSlotIndicators] = useState<IndicatorConfig[]>([]);
|
||||
@@ -387,13 +381,18 @@ function App() {
|
||||
saveAppDef({ defaultLayoutId: def.id });
|
||||
}, [layoutDef.count, activeSlot, symbol, timeframe, indicators, saveAppDef]);
|
||||
|
||||
// 레이아웃/싱크 변경 시 localStorage 저장
|
||||
const appLayoutHydratedRef = useRef(false);
|
||||
useEffect(() => {
|
||||
localStorage.setItem('chartLayout', layoutDef.id);
|
||||
}, [layoutDef]);
|
||||
useEffect(() => {
|
||||
localStorage.setItem('chartLayoutSync', JSON.stringify(syncOptions));
|
||||
}, [syncOptions]);
|
||||
if (!appSettingsLoaded || appLayoutHydratedRef.current) return;
|
||||
appLayoutHydratedRef.current = true;
|
||||
if (appDefaults.layoutId) {
|
||||
const def = LAYOUTS.find(l => l.id === appDefaults.layoutId);
|
||||
if (def) setLayoutDef(def);
|
||||
}
|
||||
if (appDefaults.syncOptions) {
|
||||
setSyncOptions(appDefaults.syncOptions);
|
||||
}
|
||||
}, [appSettingsLoaded, appDefaults.layoutId, appDefaults.syncOptions]);
|
||||
|
||||
// 다중 → 싱글 전환 시 activeSlotIndicators 초기화
|
||||
useEffect(() => {
|
||||
@@ -1118,10 +1117,6 @@ function App() {
|
||||
return map;
|
||||
}, [watchlist]);
|
||||
|
||||
// ── 상태 저장 (localStorage) ───────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
saveState({ symbol, timeframe, chartType, theme, indicators, watchlist, alertPrices: alerts.map(a => a.price) });
|
||||
}, [symbol, timeframe, chartType, theme, indicators, watchlist, alerts]);
|
||||
|
||||
// body 포털(알림 팝업 등) 테마 CSS 변수 동기화
|
||||
useEffect(() => {
|
||||
@@ -1201,10 +1196,10 @@ function App() {
|
||||
},
|
||||
onWatchlistLoad: (items: WatchlistItem[]) => {
|
||||
const syms = items.map(i => i.symbol);
|
||||
initFavoritesFromDb(syms);
|
||||
if (syms.length > 0) {
|
||||
setWatchlist(syms);
|
||||
setFavoritesList(syms);
|
||||
saveFavorites(syms, false);
|
||||
}
|
||||
},
|
||||
noAutoSave: !dbLoaded,
|
||||
@@ -1672,6 +1667,7 @@ function App() {
|
||||
theme={theme}
|
||||
onPage={guardedSetMenuPage}
|
||||
onTheme={handleThemeToggle}
|
||||
onOpenAppDownload={() => setAppDownloadOpen(true)}
|
||||
authUser={authUser}
|
||||
guestMode={guestMode}
|
||||
menuPermissions={menuPermissions}
|
||||
@@ -1691,6 +1687,10 @@ function App() {
|
||||
onSuccess={handleLoginSuccess}
|
||||
/>
|
||||
|
||||
{appDownloadOpen && (
|
||||
<AppDownloadModal onClose={() => setAppDownloadOpen(false)} />
|
||||
)}
|
||||
|
||||
{/* ── 투자전략 화면 ──────────────────────────────────────────────── */}
|
||||
{menuPage === 'dashboard' && (
|
||||
<DashboardPage theme={theme} onGoChart={m => { goToMarketChart(m); setMenuPage('chart'); }} />
|
||||
@@ -1900,6 +1900,7 @@ function App() {
|
||||
|
||||
<ChartToolbarNotify
|
||||
onOpenNotifyList={openNotificationsPage}
|
||||
onOpenAppDownload={() => setAppDownloadOpen(true)}
|
||||
symbol={symbol} timeframe={layoutDef.count > 1 ? activeSlotTf : timeframe} chartType={chartType}
|
||||
theme={theme} mode={mode} logScale={logScale} showGrid={showGrid}
|
||||
activeIndicators={toolbarActiveIndicators}
|
||||
|
||||
Reference in New Issue
Block a user