/** * šŸ” Auth Store (Zustand) * Gerenciador de estado de autenticação */ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import apiClient, { handleApiError } from '../api'; import { AuthState, AuthUser, SignupPayload, LoginPayload, AuthResponse, } from '../types'; interface AuthStore extends AuthState { // aƧƵes signup: (payload: SignupPayload) => Promise; login: (payload: LoginPayload) => Promise; logout: () => Promise; getProfile: () => Promise; setError: (error: string | null) => void; setLoading: (loading: boolean) => void; } /** * Decodificar JWT para pegar o userId */ const decodeToken = (token: string): { userId: string } | null => { try { const base64Url = token.split('.')[1]; const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); const jsonPayload = decodeURIComponent( atob(base64) .split('') .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) .join(''), ); return JSON.parse(jsonPayload); } catch { return null; } }; /** * Criar store de autenticação */ export const useAuthStore = create()( persist( (set, get) => ({ // Estado inicial user: null, token: null, isAuthenticated: false, isLoading: false, error: null, // ============================================================================ // AƇƕES // ============================================================================ /** * Registrar novo usuĆ”rio */ signup: async (payload: SignupPayload) => { try { set({ isLoading: true, error: null }); const response = await apiClient.post( '/auth/signup', payload, ); const { access_token, user } = response.data; set({ token: access_token, user, isAuthenticated: true, isLoading: false, }); // Salvar token no localStorage localStorage.setItem('auth_token', access_token); localStorage.setItem('auth_user', JSON.stringify(user)); } catch (error) { const message = handleApiError(error); set({ error: message, isLoading: false }); throw new Error(message); } }, /** * Fazer login */ login: async (payload: LoginPayload) => { try { set({ isLoading: true, error: null }); const response = await apiClient.post( '/auth/login', payload, ); const { access_token, user } = response.data; set({ token: access_token, user, isAuthenticated: true, isLoading: false, }); // Salvar no localStorage localStorage.setItem('auth_token', access_token); localStorage.setItem('auth_user', JSON.stringify(user)); } catch (error) { const message = handleApiError(error); set({ error: message, isLoading: false }); throw new Error(message); } }, /** * Fazer logout */ logout: async () => { try { set({ isLoading: true }); // Chamar endpoint de logout (opcional) await apiClient.post('/auth/logout'); } catch (error) { console.error('Erro ao fazer logout:', error); } finally { // Limpar estado e localStorage set({ user: null, token: null, isAuthenticated: false, isLoading: false, error: null, }); localStorage.removeItem('auth_token'); localStorage.removeItem('auth_user'); localStorage.removeItem('auth_store'); } }, /** * Obter perfil do usuĆ”rio */ getProfile: async () => { try { const response = await apiClient.get('/auth/me'); const user = response.data; set({ user, isAuthenticated: true }); localStorage.setItem('auth_user', JSON.stringify(user)); return user; } catch (error) { const message = handleApiError(error); set({ error: message, isAuthenticated: false }); return null; } }, /** * Setar erro */ setError: (error: string | null) => { set({ error }); }, /** * Setar loading */ setLoading: (isLoading: boolean) => { set({ isLoading }); }, }), // Configurar persistĆŖncia { name: 'auth_store', partialize: (state) => ({ token: state.token, user: state.user, isAuthenticated: state.isAuthenticated, }), // Validar token ao recuperar do storage onRehydrateStorage: () => (state) => { if (state?.token) { const decoded = decodeToken(state.token); if (!decoded) { state.token = null; state.isAuthenticated = false; } } }, }, ), ); // Exportar hook separado para debugging export const useAuth = () => { const store = useAuthStore(); return { user: store.user, token: store.token, isAuthenticated: store.isAuthenticated, isLoading: store.isLoading, error: store.error, login: store.login, signup: store.signup, logout: store.logout, getProfile: store.getProfile, }; };