Files
family_budget/frontend/src/store/useStore.ts
2026-01-29 15:17:54 +03:00

148 lines
4.1 KiB
TypeScript

import { create } from 'zustand';
import type { Family, Category, User, FamilyMember, Theme, Locale } from '../types';
const getStoredPreferences = () => {
const theme = (localStorage.getItem('theme') as Theme) || 'light';
const locale = (localStorage.getItem('locale') as Locale) || 'ru';
return { theme, locale };
};
interface CacheEntry<T> {
data: T;
timestamp: number;
}
interface CacheState {
categories: Map<number, CacheEntry<Category[]>>;
members: Map<number, CacheEntry<FamilyMember[]>>;
}
const CACHE_TTL = 5 * 60 * 1000;
interface AppState {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
selectedFamily: Family | null;
families: Family[];
categories: Category[];
familyMembers: FamilyMember[];
preferences: { theme: Theme; locale: Locale };
cache: CacheState;
setUser: (user: User | null) => void;
setIsLoading: (loading: boolean) => void;
setSelectedFamily: (family: Family | null) => void;
setFamilies: (families: Family[]) => void;
setCategories: (categories: Category[]) => void;
setFamilyMembers: (members: FamilyMember[]) => void;
setPreferences: (prefs: Partial<{ theme: Theme; locale: Locale }>) => void;
logout: () => void;
getCachedCategories: (familyId: number) => Category[] | null;
setCachedCategories: (familyId: number, categories: Category[]) => void;
getCachedMembers: (familyId: number) => FamilyMember[] | null;
setCachedMembers: (familyId: number, members: FamilyMember[]) => void;
clearCache: () => void;
}
export const useStore = create<AppState>((set, get) => ({
user: null,
isAuthenticated: false,
isLoading: true,
selectedFamily: null,
families: [],
categories: [],
familyMembers: [],
preferences: getStoredPreferences(),
cache: {
categories: new Map(),
members: new Map(),
},
setUser: (user) => set({ user, isAuthenticated: !!user }),
setIsLoading: (isLoading) => set({ isLoading }),
setSelectedFamily: (family) => set({ selectedFamily: family }),
setFamilies: (families) => set({ families }),
setCategories: (categories) => set({ categories }),
setFamilyMembers: (familyMembers) => set({ familyMembers }),
setPreferences: (prefs) => set((state) => {
const newPrefs = { ...state.preferences, ...prefs };
if (prefs.theme) localStorage.setItem('theme', prefs.theme);
if (prefs.locale) localStorage.setItem('locale', prefs.locale);
return { preferences: newPrefs };
}),
getCachedCategories: (familyId: number) => {
const cached = get().cache.categories.get(familyId);
if (!cached) return null;
if (Date.now() - cached.timestamp > CACHE_TTL) {
set((state) => {
const newCache = { ...state.cache };
newCache.categories.delete(familyId);
return { cache: newCache };
});
return null;
}
return cached.data;
},
setCachedCategories: (familyId: number, categories: Category[]) => {
set((state) => {
const newCache = { ...state.cache };
newCache.categories.set(familyId, { data: categories, timestamp: Date.now() });
return { cache: newCache };
});
},
getCachedMembers: (familyId: number) => {
const cached = get().cache.members.get(familyId);
if (!cached) return null;
if (Date.now() - cached.timestamp > CACHE_TTL) {
set((state) => {
const newCache = { ...state.cache };
newCache.members.delete(familyId);
return { cache: newCache };
});
return null;
}
return cached.data;
},
setCachedMembers: (familyId: number, members: FamilyMember[]) => {
set((state) => {
const newCache = { ...state.cache };
newCache.members.set(familyId, { data: members, timestamp: Date.now() });
return { cache: newCache };
});
},
clearCache: () => {
set((state) => ({
cache: {
categories: new Map(),
members: new Map(),
},
}));
},
logout: () => set({
user: null,
isAuthenticated: false,
selectedFamily: null,
families: [],
categories: [],
familyMembers: [],
cache: {
categories: new Map(),
members: new Map(),
},
}),
}));