/** * Global state management with Zustand */ import { create } from 'zustand' import { api } from './api' interface User { id: number email: string name: string | null is_admin?: boolean is_verified?: boolean } interface Domain { id: number name: string status: string is_available: boolean registrar: string | null expiration_date: string | null notify_on_available: boolean created_at: string last_checked: string | null } interface Subscription { tier: string tier_name?: string domain_limit: number domains_used: number portfolio_limit?: number check_frequency?: string history_days?: number features?: { email_alerts: boolean priority_alerts: boolean full_whois: boolean expiration_tracking: boolean domain_valuation: boolean market_insights: boolean api_access: boolean webhooks: boolean bulk_tools: boolean seo_metrics: boolean } } interface AppState { // Auth user: User | null isAuthenticated: boolean isLoading: boolean // Domains domains: Domain[] domainsTotal: number domainsPage: number // Subscription subscription: Subscription | null // Actions login: (email: string, password: string) => Promise register: (email: string, password: string, name?: string) => Promise logout: () => void checkAuth: () => Promise fetchDomains: (page?: number) => Promise addDomain: (name: string) => Promise deleteDomain: (id: number) => Promise refreshDomain: (id: number) => Promise updateDomain: (id: number, updates: Partial) => void fetchSubscription: () => Promise } export const useStore = create((set, get) => ({ // Initial state user: null, isAuthenticated: false, isLoading: true, domains: [], domainsTotal: 0, domainsPage: 1, subscription: null, // Auth actions login: async (email, password) => { await api.login(email, password) const user = await api.getMe() set({ user, isAuthenticated: true, isLoading: false }) // Fetch user data (only once after login) await Promise.all([ get().fetchDomains(), get().fetchSubscription() ]) }, register: async (email, password, name) => { await api.register(email, password, name) // Auto-login after registration await get().login(email, password) }, logout: () => { api.logout() set({ user: null, isAuthenticated: false, domains: [], subscription: null, }) }, checkAuth: async () => { // Skip if already authenticated and have data (prevents redundant fetches) const state = get() if (state.isAuthenticated && state.user && state.subscription) { set({ isLoading: false }) return } set({ isLoading: true }) try { if (api.getToken()) { const user = await api.getMe() set({ user, isAuthenticated: true }) // Fetch in parallel for speed await Promise.all([ get().fetchDomains(), get().fetchSubscription() ]) } } catch { api.logout() set({ user: null, isAuthenticated: false }) } finally { set({ isLoading: false }) } }, // Domain actions fetchDomains: async (page = 1) => { try { const response = await api.getDomains(page) set({ domains: response.domains, domainsTotal: response.total, domainsPage: response.page, }) } catch (error) { console.error('Failed to fetch domains:', error) } }, addDomain: async (name) => { await api.addDomain(name) await get().fetchDomains(get().domainsPage) await get().fetchSubscription() }, deleteDomain: async (id) => { await api.deleteDomain(id) await get().fetchDomains(get().domainsPage) await get().fetchSubscription() }, refreshDomain: async (id) => { const updated = await api.refreshDomain(id) const domains = get().domains.map((d) => d.id === id ? { ...d, ...updated } : d ) set({ domains }) }, updateDomain: (id, updates) => { const domains = get().domains.map((d) => d.id === id ? { ...d, ...updates } : d ) set({ domains }) }, // Subscription actions fetchSubscription: async () => { try { const sub = await api.getSubscription() set({ subscription: { tier: sub.tier, tier_name: sub.tier_name, domain_limit: sub.domain_limit, domains_used: sub.domains_used, portfolio_limit: sub.portfolio_limit, check_frequency: sub.check_frequency, history_days: sub.history_days, features: sub.features, }, }) } catch { // User might not have subscription } }, }))