This commit is contained in:
2026-10-30 11:04:23 +03:00
commit 2a19c16002
194 changed files with 24054 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
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<AppSettings>(STORAGE_KEY);
return stored ? { ...defaultSettings, ...stored } : { ...defaultSettings };
}
class SettingsStore {
settings: AppSettings = storedSettings();
private timers: ReturnType<typeof setInterval>[] = [];
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<AppSettings>): 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<void> {
const all = await listSettings();
const patch: Record<string, unknown> = {};
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<AppSettings>));
}
private async pullHeader(): Promise<void> {
const value = await getSetting<AppSettings['tabletHeader']>('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<void> {
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();