import { makeAutoObservable, reaction, runInAction } from 'mobx'; import { getSetting, listSettings } from '@/shared/api'; import { themeStore, type BrandColors } from '@/shared/config'; import { appEvents, storage } from '@/shared/lib'; import { loadRemoteSetting } from '../api/kioskSettingsApi'; import type { AppSettings } from './types'; const STORAGE_KEY = 'app_settings'; const SETTINGS_INTERVAL = 60_000; const HEADER_INTERVAL = 4_000; const CITY_INTERVAL = 120_000; const defaultSettings: AppSettings = { scheduleDeviationSource: 'real', notifVolume: 70, brightness: 80, wifi: true, bluetooth: false, language: 'ru', }; function storedSettings(): AppSettings { const stored = storage.getJson(STORAGE_KEY); return stored ? { ...defaultSettings, ...stored } : { ...defaultSettings }; } class SettingsStore { settings: AppSettings = storedSettings(); private timers: ReturnType[] = []; private lastHeader = ''; constructor() { makeAutoObservable(this, {}, { autoBind: true }); reaction( () => this.settings.brandColorsTablet as BrandColors | undefined, (brand) => themeStore.setBrand(brand ?? null), { fireImmediately: true }, ); } start(): void { if (this.timers.length > 0) return; void this.pullSettings(); void this.pullHeader(); void this.pullCity(); this.timers = [ setInterval(() => void this.pullSettings(), SETTINGS_INTERVAL), setInterval(() => void this.pullHeader(), HEADER_INTERVAL), setInterval(() => void this.pullCity(), CITY_INTERVAL), ]; appEvents.on('app-settings:force-pull', this.forcePull); } stop(): void { for (const timer of this.timers) clearInterval(timer); this.timers = []; appEvents.off('app-settings:force-pull', this.forcePull); } update(patch: Partial): void { this.settings = { ...this.settings, ...patch }; storage.setJson(STORAGE_KEY, this.settings); } reset(): void { this.settings = { ...defaultSettings }; storage.remove(STORAGE_KEY); } private forcePull(): void { this.lastHeader = ''; void this.pullSettings(); void this.pullHeader(); } private async pullSettings(): Promise { const all = await listSettings(); const patch: Record = {}; for (const [key, value] of Object.entries(all)) { if (key.startsWith('ui.') && value != null) patch[key.slice(3)] = value; } if (Object.keys(patch).length === 0) return; runInAction(() => this.update(patch as Partial)); } private async pullHeader(): Promise { const value = await getSetting('ui.tabletHeader'); if (value == null) return; const serialized = JSON.stringify(value); if (serialized === this.lastHeader) return; this.lastHeader = serialized; runInAction(() => this.update({ tabletHeader: value })); } private async pullCity(): Promise { const value = await loadRemoteSetting<{ city?: string; customCityName?: string }>('global_city', {}); if (!value.city) return; if (this.settings.city === value.city && this.settings.customCityName === value.customCityName) return; runInAction(() => this.update({ city: value.city, customCityName: value.customCityName })); } } export const settingsStore = new SettingsStore();