import { create } from 'zustand'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { authApi, userApi, handleApiError } from './api'; import { User, LoginRequest, SignupRequest } from './types'; // Storage keys const USER_KEY = 'auth_user'; interface AuthState { // State user: User | null; isAuthenticated: boolean; isLoading: boolean; isInitialized: boolean; error: string | null; // Actions initialize: () => Promise; login: (data: LoginRequest) => Promise; signup: (data: SignupRequest) => Promise; logout: () => Promise; clearError: () => void; setUser: (user: User) => void; updateUser: (data: Partial) => Promise; } export const useAuthStore = create((set, get) => ({ // Initial state user: null, isAuthenticated: false, isLoading: false, isInitialized: false, error: null, // Initialize auth state on app start initialize: async () => { try { set({ isLoading: true, error: null }); // Check for stored token const token = await authApi.getStoredToken(); if (token) { // Try to fetch current user try { const user = await userApi.getMe(); await AsyncStorage.setItem(USER_KEY, JSON.stringify(user)); set({ user, isAuthenticated: true, isInitialized: true, isLoading: false, }); } catch { // Token invalid or expired - try to refresh try { await authApi.refreshToken(); const user = await userApi.getMe(); await AsyncStorage.setItem(USER_KEY, JSON.stringify(user)); set({ user, isAuthenticated: true, isInitialized: true, isLoading: false, }); } catch { // Refresh failed - clear auth state await authApi.logout(); await AsyncStorage.removeItem(USER_KEY); set({ user: null, isAuthenticated: false, isInitialized: true, isLoading: false, }); } } } else { // No token - check for cached user data for offline display const cachedUser = await AsyncStorage.getItem(USER_KEY); set({ user: cachedUser ? JSON.parse(cachedUser) : null, isAuthenticated: false, isInitialized: true, isLoading: false, }); } } catch (error) { set({ user: null, isAuthenticated: false, isInitialized: true, isLoading: false, error: handleApiError(error), }); } }, // Login login: async (data: LoginRequest) => { try { set({ isLoading: true, error: null }); const response = await authApi.login(data); const { user } = response; // Cache user data await AsyncStorage.setItem(USER_KEY, JSON.stringify(user)); set({ user, isAuthenticated: true, isLoading: false, error: null, }); } catch (error) { set({ isLoading: false, error: handleApiError(error), }); throw error; } }, // Signup signup: async (data: SignupRequest) => { try { set({ isLoading: true, error: null }); const response = await authApi.signup(data); const { user } = response; // Cache user data await AsyncStorage.setItem(USER_KEY, JSON.stringify(user)); set({ user, isAuthenticated: true, isLoading: false, error: null, }); } catch (error) { set({ isLoading: false, error: handleApiError(error), }); throw error; } }, // Logout logout: async () => { try { set({ isLoading: true }); await authApi.logout(); await AsyncStorage.removeItem(USER_KEY); set({ user: null, isAuthenticated: false, isLoading: false, error: null, }); } catch (error) { // Still clear local state even if API call fails await AsyncStorage.removeItem(USER_KEY); set({ user: null, isAuthenticated: false, isLoading: false, error: null, }); } }, // Clear error clearError: () => { set({ error: null }); }, // Set user (for updates from other parts of the app) setUser: (user: User) => { set({ user }); AsyncStorage.setItem(USER_KEY, JSON.stringify(user)); }, // Update user profile updateUser: async (data: Partial) => { try { set({ isLoading: true, error: null }); const updatedUser = await userApi.updateMe(data); await AsyncStorage.setItem(USER_KEY, JSON.stringify(updatedUser)); set({ user: updatedUser, isLoading: false, }); } catch (error) { set({ isLoading: false, error: handleApiError(error), }); throw error; } }, })); // Selector hooks for specific state slices export const useUser = () => useAuthStore((state) => state.user); export const useIsAuthenticated = () => useAuthStore((state) => state.isAuthenticated); export const useIsLoading = () => useAuthStore((state) => state.isLoading); export const useAuthError = () => useAuthStore((state) => state.error); export const useIsInitialized = () => useAuthStore((state) => state.isInitialized);