Files
goldenChart/frontend/src/utils/uiPreferencesMigrate.ts
T
2026-05-28 14:44:19 +09:00

166 lines
5.5 KiB
TypeScript

/**
* localStorage → gc_app_settings.ui_preferences_json 1회 이전
*/
import type { AppSettingsDto } from './backendApi';
import type { UiPreferences } from '../types/uiPreferences';
import { resolveUiPreferences } from './uiPreferencesDb';
const MIGRATED_FLAG = 'gc_ui_prefs_migrated_v1';
function readJson<T>(key: string): T | null {
try {
const raw = localStorage.getItem(key);
if (!raw) return null;
return JSON.parse(raw) as T;
} catch {
return null;
}
}
function removeKeys(keys: string[]): void {
for (const k of keys) {
try { localStorage.removeItem(k); } catch { /* ignore */ }
}
}
/** 이미 DB에 uiPreferences가 있으면 스킵. 없으면 localStorage 병합 후 키 제거. */
export function migrateLocalStorageToUiPreferences(
current: AppSettingsDto,
): { uiPreferences: UiPreferences; changed: boolean } | null {
try {
if (localStorage.getItem(MIGRATED_FLAG) === '1' && current.uiPreferences) {
return null;
}
} catch { /* ignore */ }
const base = resolveUiPreferences(current.uiPreferences);
const patch: UiPreferences = { ...base };
let changed = false;
const editorMode = localStorage.getItem('gc_se_editor_mode');
if (editorMode === 'list' || editorMode === 'graph') {
patch.strategyEditor = { ...patch.strategyEditor, editorMode };
changed = true;
}
const canvasMode = localStorage.getItem('gc_se_canvas_interaction');
if (canvasMode) {
patch.strategyEditor = { ...patch.strategyEditor, canvasInteraction: canvasMode };
changed = true;
}
const paletteAux = readJson<unknown[]>('se-palette-auxiliary-v1');
if (paletteAux?.length) {
patch.strategyEditor = { ...patch.strategyEditor, paletteAuxiliary: paletteAux as NonNullable<UiPreferences['strategyEditor']>['paletteAuxiliary'] };
changed = true;
}
const paletteComp = readJson<unknown[]>('se-palette-composite-v1');
if (paletteComp?.length) {
patch.strategyEditor = { ...patch.strategyEditor, paletteComposite: paletteComp as NonNullable<UiPreferences['strategyEditor']>['paletteComposite'] };
changed = true;
}
const customTabs = readJson<NonNullable<UiPreferences['indicator']>['customTabs']>('gc-indicator-custom-tabs-v1' as never);
if (customTabs?.length) {
patch.indicator = { ...patch.indicator, customTabs };
changed = true;
}
const mainTabOrder = readJson<string[]>('gc_indicator_main_tab_order');
if (mainTabOrder?.length) {
patch.indicator = { ...patch.indicator, mainTabOrder };
changed = true;
}
const listOrder = readJson<string[]>('gc_indicator_settings_list_order');
if (listOrder?.length) {
patch.indicator = { ...patch.indicator, listOrder };
changed = true;
}
const chartState = readJson<{ alertPrices?: number[]; indicators?: unknown[] }>('trading_chart_state');
if (chartState?.alertPrices?.length || chartState?.indicators?.length) {
patch.chart = {
...patch.chart,
alertPrices: chartState.alertPrices,
legacyIndicators: chartState.indicators as NonNullable<UiPreferences['chart']>['legacyIndicators'],
};
changed = true;
}
const panels: Record<string, number | boolean | string> = { ...patch.panels };
for (const key of ['se-left-width', 'se-terminal-height', 'btd-left-width', 'btd-right-width']) {
const v = localStorage.getItem(key);
if (v != null) {
const n = Number(v);
panels[key] = Number.isFinite(n) ? n : v;
changed = true;
}
}
const virtualTargets = readJson<unknown[]>('gc_virtual_targets_v1');
const virtualSession = readJson<unknown>('gc_virtual_session_v1');
const cardView = localStorage.getItem('gc_virtual_card_view_v1');
if (virtualTargets?.length || virtualSession || cardView) {
patch.virtual = {
...patch.virtual,
...(virtualTargets?.length ? { targets: virtualTargets as NonNullable<UiPreferences['virtual']>['targets'] } : {}),
...(virtualSession ? { session: virtualSession as NonNullable<UiPreferences['virtual']>['session'] } : {}),
...(cardView === 'detail' || cardView === 'summary' ? { cardViewMode: cardView } : {}),
};
changed = true;
}
const readIds = readJson<string[]>('gc_trade_notify_read_v1');
const hiddenIds = readJson<string[]>('gc_trade_notify_hidden_v1');
if (readIds?.length || hiddenIds?.length) {
patch.tradeNotifications = {
readIds: readIds ?? [],
hiddenIds: hiddenIds ?? [],
};
changed = true;
}
const displayMode = localStorage.getItem('tsd-display-mode');
if (displayMode === 'chart' || displayMode === 'summary') {
changed = true;
}
if (!changed && current.uiPreferences) {
try { localStorage.setItem(MIGRATED_FLAG, '1'); } catch { /* ignore */ }
return null;
}
if (!changed) return null;
removeKeys([
'gc_se_editor_mode',
'gc_se_canvas_interaction',
'se-palette-auxiliary-v1',
'se-palette-composite-v1',
'gc-indicator-custom-tabs-v1',
'gc_indicator_main_tab_order',
'gc_indicator_settings_list_order',
'trading_chart_state',
'chartLayout',
'chartLayoutSync',
'gc_virtual_targets_v1',
'gc_virtual_session_v1',
'gc_virtual_card_view_v1',
'gc_trade_notify_read_v1',
'gc_trade_notify_hidden_v1',
'tsd-display-mode',
'gc_se_flow_layout_v1',
'gc_strat_v2',
'gc_strategies_v1',
'se-left-width',
'se-terminal-height',
'btd-left-width',
'btd-right-width',
]);
try { localStorage.setItem(MIGRATED_FLAG, '1'); } catch { /* ignore */ }
return { uiPreferences: resolveUiPreferences(patch), changed: true };
}