'use client'; import React, { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react'; const API_BASE = process.env.NEXT_PUBLIC_API_URL || ''; interface User { id: string; email: string; name: string; role: string; phone?: string; languagePreference?: string; isClaimed?: boolean; rucNumber?: string; accountStatus?: string; } interface AuthContextType { user: User | null; token: string | null; isLoading: boolean; isAdmin: boolean; hasAdminAccess: boolean; login: (email: string, password: string) => Promise; loginWithGoogle: (credential: string) => Promise; loginWithMagicLink: (token: string) => Promise; register: (data: RegisterData) => Promise; logout: () => void; updateUser: (user: User) => void; setAuthData: (data: { user: User; token: string }) => void; refreshUser: () => Promise; } interface RegisterData { email: string; password: string; name: string; phone?: string; languagePreference?: string; } const AuthContext = createContext(undefined); const TOKEN_KEY = 'spanglish-token'; const USER_KEY = 'spanglish-user'; export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [token, setToken] = useState(null); const [isLoading, setIsLoading] = useState(true); const refreshUser = useCallback(async () => { const currentToken = localStorage.getItem(TOKEN_KEY); if (!currentToken) return; try { const res = await fetch(`${API_BASE}/api/auth/me`, { headers: { 'Authorization': `Bearer ${currentToken}`, 'Content-Type': 'application/json', }, }); if (res.ok) { const data = await res.json(); setUser(data.user); localStorage.setItem(USER_KEY, JSON.stringify(data.user)); } else if (res.status === 401) { // Token is invalid, clear auth state setToken(null); setUser(null); localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY); } } catch (error) { // Network error, keep using cached data console.error('Failed to refresh user data:', error); } }, []); useEffect(() => { // Load auth state from localStorage const savedToken = localStorage.getItem(TOKEN_KEY); const savedUser = localStorage.getItem(USER_KEY); if (savedToken && savedUser) { setToken(savedToken); setUser(JSON.parse(savedUser)); // Refresh user data from server to get latest role/permissions refreshUser().finally(() => setIsLoading(false)); } else { setIsLoading(false); } }, [refreshUser]); const setAuthData = useCallback((data: { user: User; token: string }) => { setToken(data.token); setUser(data.user); localStorage.setItem(TOKEN_KEY, data.token); localStorage.setItem(USER_KEY, JSON.stringify(data.user)); }, []); const login = async (email: string, password: string) => { const res = await fetch(`${API_BASE}/api/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); if (!res.ok) { const error = await res.json(); throw new Error(error.error || 'Login failed'); } const data = await res.json(); setAuthData(data); }; const loginWithGoogle = async (credential: string) => { const res = await fetch(`${API_BASE}/api/auth/google`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ credential }), }); if (!res.ok) { const error = await res.json(); throw new Error(error.error || 'Google login failed'); } const data = await res.json(); setAuthData(data); }; const loginWithMagicLink = async (magicToken: string) => { const res = await fetch(`${API_BASE}/api/auth/magic-link/verify`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: magicToken }), }); if (!res.ok) { const error = await res.json(); throw new Error(error.error || 'Magic link login failed'); } const data = await res.json(); setAuthData(data); }; const register = async (registerData: RegisterData) => { const res = await fetch(`${API_BASE}/api/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(registerData), }); if (!res.ok) { const error = await res.json(); throw new Error(error.error || 'Registration failed'); } const data = await res.json(); setAuthData(data); }; const logout = useCallback(() => { setToken(null); setUser(null); localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY); }, []); const updateUser = useCallback((updatedUser: User) => { setUser(updatedUser); localStorage.setItem(USER_KEY, JSON.stringify(updatedUser)); }, []); const isAdmin = user?.role === 'admin' || user?.role === 'organizer'; const hasAdminAccess = user?.role === 'admin' || user?.role === 'organizer' || user?.role === 'staff' || user?.role === 'marketing'; return ( {children} ); } export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }