Skip to main content
Glama
zustand-store.ts4.5 kB
import { create } from 'zustand'; import { persist, createJSONStorage, devtools } from 'zustand/middleware'; // ============================================ // Types // ============================================ interface User { id: string; name: string; email: string; avatar?: string; } interface AuthState { user: User | null; token: string | null; isAuthenticated: boolean; login: (user: User, token: string) => void; logout: () => void; updateProfile: (data: Partial<User>) => void; } interface ThemeState { mode: 'light' | 'dark' | 'system'; setMode: (mode: 'light' | 'dark' | 'system') => void; toggleMode: () => void; } interface CartItem { id: string; name: string; price: number; quantity: number; } interface CartState { items: CartItem[]; addToCart: (item: CartItem) => void; removeFromCart: (id: string) => void; updateQuantity: (id: string, quantity: number) => void; clearCart: () => void; total: () => number; } // ============================================ // Auth Store (Persisted) // ============================================ export const useAuthStore = create<AuthState>()( devtools( persist( (set) => ({ user: null, token: null, isAuthenticated: false, login: (user, token) => set({ user, token, isAuthenticated: true }, false, 'auth/login'), // Action name for devtools logout: () => set({ user: null, token: null, isAuthenticated: false }, false, 'auth/logout'), updateProfile: (data) => set((state) => ({ user: state.user ? { ...state.user, ...data } : null }), false, 'auth/updateProfile'), }), { name: 'auth-storage', storage: createJSONStorage(() => localStorage), partialize: (state) => ({ token: state.token, user: state.user }), // Only persist token and user } ) ) ); // ============================================ // Theme Store // ============================================ export const useThemeStore = create<ThemeState>()( persist( (set, get) => ({ mode: 'system', setMode: (mode) => set({ mode }), toggleMode: () => { const current = get().mode; set({ mode: current === 'light' ? 'dark' : 'light' }); }, }), { name: 'theme-storage' } ) ); // ============================================ // Cart Store (Computed Values) // ============================================ export const useCartStore = create<CartState>((set, get) => ({ items: [], addToCart: (newItem) => set((state) => { const existing = state.items.find(i => i.id === newItem.id); if (existing) { return { items: state.items.map(i => i.id === newItem.id ? { ...i, quantity: i.quantity + 1 } : i ), }; } return { items: [...state.items, { ...newItem, quantity: 1 }] }; }), removeFromCart: (id) => set((state) => ({ items: state.items.filter(i => i.id !== id), })), updateQuantity: (id, quantity) => set((state) => ({ items: quantity <= 0 ? state.items.filter(i => i.id !== id) : state.items.map(i => i.id === id ? { ...i, quantity } : i), })), clearCart: () => set({ items: [] }), total: () => { return get().items.reduce((sum, item) => sum + item.price * item.quantity, 0); }, })); // ============================================ // Selectors (Optimization) // ============================================ // Use these to prevent unnecessary re-renders export const useUser = () => useAuthStore((state) => state.user); export const useIsAuthenticated = () => useAuthStore((state) => state.isAuthenticated); export const useAuthActions = () => useAuthStore((state) => ({ login: state.login, logout: state.logout })); export const useCartTotal = () => useCartStore((state) => state.total()); export const useCartItemsCount = () => useCartStore((state) => state.items.reduce((acc, item) => acc + item.quantity, 0));

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/millsydotdev/Code-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server