import { create } from 'zustand'; import { authApi, type TokenPair, type UserProfile, type LoginPayload, type RegisterPayload } from './auth-api'; import { ApiError } from './api-client'; export type { TokenPair }; const TOKEN_KEY = 'goodgo_tokens'; function persistTokens(tokens: TokenPair | null) { if (typeof window === 'undefined') return; if (tokens) { localStorage.setItem(TOKEN_KEY, JSON.stringify(tokens)); } else { localStorage.removeItem(TOKEN_KEY); } } function loadTokens(): TokenPair | null { if (typeof window === 'undefined') return null; const raw = localStorage.getItem(TOKEN_KEY); if (!raw) return null; try { return JSON.parse(raw); } catch { return null; } } interface AuthState { tokens: TokenPair | null; user: UserProfile | null; isLoading: boolean; error: string | null; login: (data: LoginPayload) => Promise; register: (data: RegisterPayload) => Promise; handleOAuthCallback: (tokens: TokenPair) => Promise; logout: () => void; refreshToken: () => Promise; fetchProfile: () => Promise; initialize: () => Promise; clearError: () => void; } export const useAuthStore = create((set, get) => ({ tokens: null, user: null, isLoading: false, error: null, login: async (data) => { set({ isLoading: true, error: null }); try { const tokens = await authApi.login(data); persistTokens(tokens); set({ tokens, isLoading: false }); await get().fetchProfile(); } catch (e) { const message = e instanceof ApiError ? e.message : 'Đăng nhập thất bại'; set({ isLoading: false, error: message }); throw e; } }, register: async (data) => { set({ isLoading: true, error: null }); try { const tokens = await authApi.register(data); persistTokens(tokens); set({ tokens, isLoading: false }); await get().fetchProfile(); } catch (e) { const message = e instanceof ApiError ? e.message : 'Đăng ký thất bại'; set({ isLoading: false, error: message }); throw e; } }, handleOAuthCallback: async (tokens) => { set({ isLoading: true, error: null }); try { persistTokens(tokens); set({ tokens, isLoading: false }); await get().fetchProfile(); } catch (e) { const message = e instanceof ApiError ? e.message : 'Đăng nhập OAuth thất bại'; set({ isLoading: false, error: message }); throw e; } }, logout: () => { persistTokens(null); set({ tokens: null, user: null, error: null }); }, refreshToken: async () => { const { tokens } = get(); if (!tokens?.refreshToken) return false; try { const newTokens = await authApi.refresh(tokens.refreshToken); persistTokens(newTokens); set({ tokens: newTokens }); return true; } catch { get().logout(); return false; } }, fetchProfile: async () => { const { tokens } = get(); if (!tokens?.accessToken) return; try { const user = await authApi.getProfile(tokens.accessToken); set({ user }); } catch (e) { if (e instanceof ApiError && e.status === 401) { const refreshed = await get().refreshToken(); if (refreshed) { const newTokens = get().tokens; if (newTokens) { const user = await authApi.getProfile(newTokens.accessToken); set({ user }); } } } } }, initialize: async () => { const tokens = loadTokens(); if (!tokens) return; set({ tokens }); await get().fetchProfile(); }, clearError: () => set({ error: null }), }));