(containerId: string)
| 60 | private unsubAiFlow: (() => void) | null = null; |
| 61 | |
| 62 | constructor(containerId: string) { |
| 63 | const el = document.getElementById(containerId); |
| 64 | if (!el) throw new Error(`Container ${containerId} not found`); |
| 65 | |
| 66 | const PANEL_ORDER_KEY = 'panel-order'; |
| 67 | const PANEL_SPANS_KEY = 'worldmonitor-panel-spans'; |
| 68 | |
| 69 | const isMobile = isMobileDevice(); |
| 70 | const isDesktopApp = isDesktopRuntime(); |
| 71 | const monitors = loadFromStorage<Monitor[]>(STORAGE_KEYS.monitors, []); |
| 72 | |
| 73 | // Use mobile-specific defaults on first load (no saved layers) |
| 74 | const defaultLayers = isMobile ? MOBILE_DEFAULT_MAP_LAYERS : DEFAULT_MAP_LAYERS; |
| 75 | |
| 76 | let mapLayers: MapLayers; |
| 77 | let panelSettings: Record<string, PanelConfig>; |
| 78 | |
| 79 | // Check if variant changed - reset all settings to variant defaults |
| 80 | const storedVariant = localStorage.getItem('worldmonitor-variant'); |
| 81 | const currentVariant = SITE_VARIANT; |
| 82 | console.log(`[App] Variant check: stored="${storedVariant}", current="${currentVariant}"`); |
| 83 | if (storedVariant !== currentVariant) { |
| 84 | // Variant changed - use defaults for new variant, clear old settings |
| 85 | console.log('[App] Variant changed - resetting to defaults'); |
| 86 | localStorage.setItem('worldmonitor-variant', currentVariant); |
| 87 | localStorage.removeItem(STORAGE_KEYS.mapLayers); |
| 88 | localStorage.removeItem(STORAGE_KEYS.panels); |
| 89 | localStorage.removeItem(PANEL_ORDER_KEY); |
| 90 | localStorage.removeItem(PANEL_SPANS_KEY); |
| 91 | mapLayers = { ...defaultLayers }; |
| 92 | panelSettings = { ...DEFAULT_PANELS }; |
| 93 | } else { |
| 94 | mapLayers = loadFromStorage<MapLayers>(STORAGE_KEYS.mapLayers, defaultLayers); |
| 95 | // Happy variant: force non-happy layers off even if localStorage has stale true values |
| 96 | if (currentVariant === 'happy') { |
| 97 | const unhappyLayers: (keyof MapLayers)[] = ['conflicts', 'bases', 'hotspots', 'nuclear', 'irradiators', 'sanctions', 'military', 'protests', 'pipelines', 'waterways', 'ais', 'flights', 'spaceports', 'minerals', 'natural', 'fires', 'outages', 'cyberThreats', 'weather', 'economic', 'cables', 'datacenters', 'ucdpEvents', 'displacement', 'climate', 'iranAttacks']; |
| 98 | unhappyLayers.forEach(layer => { mapLayers[layer] = false; }); |
| 99 | } |
| 100 | panelSettings = loadFromStorage<Record<string, PanelConfig>>( |
| 101 | STORAGE_KEYS.panels, |
| 102 | DEFAULT_PANELS |
| 103 | ); |
| 104 | // Merge in any new panels that didn't exist when settings were saved |
| 105 | for (const [key, config] of Object.entries(DEFAULT_PANELS)) { |
| 106 | if (!(key in panelSettings)) { |
| 107 | panelSettings[key] = { ...config }; |
| 108 | } |
| 109 | } |
| 110 | console.log('[App] Loaded panel settings from storage:', Object.entries(panelSettings).filter(([_, v]) => !v.enabled).map(([k]) => k)); |
| 111 | |
| 112 | // One-time migration: reorder panels for existing users (v1.9 panel layout) |
| 113 | const PANEL_ORDER_MIGRATION_KEY = 'worldmonitor-panel-order-v1.9'; |
| 114 | if (!localStorage.getItem(PANEL_ORDER_MIGRATION_KEY)) { |
| 115 | const savedOrder = localStorage.getItem(PANEL_ORDER_KEY); |
| 116 | if (savedOrder) { |
| 117 | try { |
| 118 | const order: string[] = JSON.parse(savedOrder); |
| 119 | const priorityPanels = ['insights', 'strategic-posture', 'cii', 'strategic-risk']; |
nothing calls this directly
no test coverage detected