mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 10:00:17 +05:30
feat(renderer): useSettingsStore (persisted, validated, reset-able)
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist, createJSONStorage } from 'zustand/middleware';
|
||||
import { settingsSchema, type Settings } from '@/lib/validators';
|
||||
|
||||
type SettingsLeaf = keyof Omit<Settings, never>;
|
||||
|
||||
interface SettingsState extends Settings {
|
||||
setSetting: <K extends SettingsLeaf>(key: K, value: Settings[K]) => void;
|
||||
resetToDefaults: () => void;
|
||||
}
|
||||
|
||||
const DEFAULTS = settingsSchema.parse({});
|
||||
|
||||
export const useSettingsStore = create<SettingsState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
...DEFAULTS,
|
||||
setSetting: (key, value) => set((s) => ({ ...s, [key]: value }) as Partial<SettingsState>),
|
||||
resetToDefaults: () => set(() => ({ ...DEFAULTS })),
|
||||
}),
|
||||
{
|
||||
name: 'mc-settings-store',
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => {
|
||||
const { setSetting, resetToDefaults, ...rest } = state;
|
||||
return rest;
|
||||
},
|
||||
onRehydrateStorage: () => (state) => {
|
||||
if (!state) return;
|
||||
const result = settingsSchema.safeParse(state);
|
||||
if (!result.success) {
|
||||
console.warn('[settings-store] invalid persisted state, resetting to defaults', result.error);
|
||||
useSettingsStore.setState({ ...DEFAULTS } as any);
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,44 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
|
||||
describe('useSettingsStore', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
useSettingsStore.setState(useSettingsStore.getInitialState());
|
||||
});
|
||||
|
||||
it('has sensible defaults', () => {
|
||||
const s = useSettingsStore.getState();
|
||||
expect(s.fontSize).toBe(14);
|
||||
expect(s.theme).toBe('auto');
|
||||
expect(s.pdfFormat).toBe('a4');
|
||||
expect(s.docxTemplate).toBe('standard');
|
||||
expect(s.renderTablesAsAscii).toBe(false);
|
||||
expect(s.welcomeDismissed).toBe(false);
|
||||
});
|
||||
|
||||
it('setSetting updates a leaf field', () => {
|
||||
useSettingsStore.getState().setSetting('fontSize', 18);
|
||||
expect(useSettingsStore.getState().fontSize).toBe(18);
|
||||
});
|
||||
|
||||
it('resetToDefaults restores all defaults', () => {
|
||||
useSettingsStore.getState().setSetting('fontSize', 22);
|
||||
useSettingsStore.getState().setSetting('theme', 'dark');
|
||||
useSettingsStore.getState().resetToDefaults();
|
||||
expect(useSettingsStore.getState().fontSize).toBe(14);
|
||||
expect(useSettingsStore.getState().theme).toBe('auto');
|
||||
});
|
||||
|
||||
it('persists only leaf settings (partialize), not actions', () => {
|
||||
useSettingsStore.getState().setSetting('fontSize', 16);
|
||||
useSettingsStore.getState().setSetting('docxTemplate', 'modern');
|
||||
const raw = localStorage.getItem('mc-settings-store');
|
||||
expect(raw).toBeTruthy();
|
||||
const parsed = JSON.parse(raw!);
|
||||
expect(parsed.state.fontSize).toBe(16);
|
||||
expect(parsed.state.docxTemplate).toBe('modern');
|
||||
expect(parsed.state.setSetting).toBeUndefined();
|
||||
expect(parsed.state.resetToDefaults).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user