124 lines
No EOL
4.2 KiB
TypeScript
124 lines
No EOL
4.2 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import {nodesSettings} from "./config/nodesSettings";
|
|
import { networkSettings } from './config/networkSettings';
|
|
import {appearanceSettings} from "./config/appearanceSettings";
|
|
|
|
type SettingValue = any;
|
|
type SettingsDictionary = Record<string, SettingValue>;
|
|
|
|
export type Setting = {
|
|
readonly id: string;
|
|
readonly type: 'boolean' | 'select' | 'text' | 'number' | 'button' | 'hidden';
|
|
readonly label: string;
|
|
readonly defaultValue: any;
|
|
value?: string;
|
|
readonly min?: number;
|
|
readonly max?: number;
|
|
readonly options?: any;
|
|
readonly sectionId: string;
|
|
readonly required?: boolean;
|
|
readonly action?: () => void;
|
|
};
|
|
|
|
type SettingsState = {
|
|
settingsConfig: Setting[];
|
|
settingsValues: SettingsDictionary;
|
|
activeSection: string | null;
|
|
pendingChanges: SettingsDictionary;
|
|
setActiveSection: (sectionId: string | null) => void;
|
|
updateSetting: (id: string, value: any) => void;
|
|
initializeSettings: () => void;
|
|
getSetting: (id: string) => Setting & { currentValue: any };
|
|
resetSettings: () => void;
|
|
applyChanges: () => void;
|
|
discardChanges: () => void;
|
|
getSettingValue: <T = any>(id: string) => T;
|
|
getNumberSetting: (id: string, fallback?: number) => number;
|
|
};
|
|
|
|
const defaultSettings: Setting[] = [
|
|
...nodesSettings,
|
|
...networkSettings,
|
|
...appearanceSettings,
|
|
];
|
|
|
|
export const useSettingsStore = create<SettingsState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
settingsConfig: defaultSettings,
|
|
settingsValues: {},
|
|
activeSection: null,
|
|
pendingChanges: {},
|
|
|
|
setActiveSection: (sectionId) => set({ activeSection: sectionId }),
|
|
|
|
updateSetting: (id, value) =>
|
|
set((state) => ({
|
|
pendingChanges: { ...state.pendingChanges, [id]: value }
|
|
})),
|
|
|
|
applyChanges: () =>
|
|
set((state) => ({
|
|
settingsValues: { ...state.settingsValues, ...state.pendingChanges },
|
|
pendingChanges: {}
|
|
})),
|
|
|
|
discardChanges: () => set({ pendingChanges: {} }),
|
|
|
|
initializeSettings: () => {
|
|
const { settingsValues, settingsConfig } = get();
|
|
const newValues = { ...settingsValues };
|
|
|
|
settingsConfig.forEach(setting => {
|
|
if (newValues[setting.id] === undefined) {
|
|
newValues[setting.id] = setting.defaultValue;
|
|
}
|
|
});
|
|
|
|
set({ settingsValues: newValues });
|
|
},
|
|
|
|
getSetting: (id) => {
|
|
const state = get();
|
|
const setting = state.settingsConfig.find(s => s.id === id);
|
|
if (!setting) throw new Error(`Setting ${id} not found`);
|
|
|
|
const hasPendingChange = Object.prototype.hasOwnProperty.call(state.pendingChanges, id);
|
|
const hasSavedValue = Object.prototype.hasOwnProperty.call(state.settingsValues, id);
|
|
|
|
const currentValue = hasPendingChange
|
|
? state.pendingChanges[id]
|
|
: hasSavedValue
|
|
? state.settingsValues[id]
|
|
: setting.defaultValue;
|
|
|
|
return {
|
|
...setting,
|
|
currentValue
|
|
};
|
|
},
|
|
getSettingValue: (id: string) => {
|
|
const state = get();
|
|
return state.settingsValues[id] ??
|
|
state.settingsConfig.find(s => s.id === id)?.defaultValue;
|
|
},
|
|
|
|
getNumberSetting: (id: string, fallback = 0) => {
|
|
const value = get().getSettingValue(id);
|
|
return Number(value) || fallback;
|
|
},
|
|
|
|
resetSettings: () => set({ settingsValues: {}, pendingChanges: {} }),
|
|
}),
|
|
{
|
|
name: 'app-settings',
|
|
partialize: (state) => ({
|
|
settingsValues: state.settingsValues
|
|
}),
|
|
onRehydrateStorage: () => (state) => {
|
|
state?.initializeSettings();
|
|
}
|
|
}
|
|
)
|
|
); |