'use client' import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react' import { useLocale } from 'next-intl' import { useStore } from '@/lib/store' import { isTokenExpired, clearExpiredToken } from '@/lib/auth/client' import type { User } from '@/types' interface AuthContextType { user: User | null isAuthenticated: boolean isLoading: boolean login: (email: string, password: string) => Promise<{ success: boolean; error?: string }> register: (email: string, password: string, name?: string) => Promise<{ success: boolean; error?: string }> logout: () => Promise refreshUser: () => Promise } const AuthContext = createContext(undefined) interface AuthProviderProps { children: ReactNode } export function AuthProvider({ children }: AuthProviderProps) { const [isLoading, setIsLoading] = useState(true) const [initialized, setInitialized] = useState(false) const locale = useLocale() const { user, setUser } = useStore() const refreshUser = async (forceRefresh = false) => { const token = localStorage.getItem('authToken') if (!token) { setUser(null) setIsLoading(false) return } // Check if token is expired before making request if (isTokenExpired(token)) { localStorage.removeItem('authToken') setUser(null) setIsLoading(false) return } // If we already have a user and this isn't a forced refresh, don't re-fetch if (user && !forceRefresh) { setIsLoading(false) return } try { const response = await fetch(`/api/auth/me?locale=${locale}`, { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() setUser(data.user) } else { localStorage.removeItem('authToken') setUser(null) } } catch (error) { console.error('Auth check failed:', error) // Network error or other issues, clean up auth state localStorage.removeItem('authToken') setUser(null) } finally { setIsLoading(false) } } // Clear expired tokens and sync state immediately on mount useEffect(() => { if (typeof window !== 'undefined') { const token = localStorage.getItem('authToken') if (token) { const expired = isTokenExpired(token) if (expired) { localStorage.removeItem('authToken') setUser(null) } } else if (user) { setUser(null) } clearExpiredToken() } }, []) // Initialize auth state only once on mount useEffect(() => { if (!initialized && typeof window !== 'undefined') { const token = localStorage.getItem('authToken') if (token) { // Check if token is expired before making request if (isTokenExpired(token)) { localStorage.removeItem('authToken') setUser(null) setIsLoading(false) } else { // Token appears valid, try to refresh user data // refreshUser will handle server-side validation failures refreshUser() } } else { // No token, clear any stale user data setUser(null) setIsLoading(false) } setInitialized(true) } }, [initialized]) // Handle hydration issues - ensure we stop loading once initialized useEffect(() => { if (initialized && isLoading) { const token = localStorage.getItem('authToken') if (!token) { setIsLoading(false) } } }, [initialized, isLoading]) const login = async (email: string, password: string): Promise<{ success: boolean; error?: string }> => { try { const response = await fetch(`/api/auth/login?locale=${locale}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), }) const data = await response.json() if (response.ok) { localStorage.setItem('authToken', data.token) setUser(data.user) return { success: true } } else { return { success: false, error: data.error } } } catch (error) { console.error('Login error:', error) return { success: false, error: locale === 'en' ? 'Login failed' : 'Autentificare eșuată' } } } const register = async (email: string, password: string, name?: string): Promise<{ success: boolean; error?: string }> => { try { const response = await fetch(`/api/auth/register?locale=${locale}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password, name }), }) const data = await response.json() if (response.ok) { localStorage.setItem('authToken', data.token) setUser(data.user) return { success: true } } else { return { success: false, error: data.error } } } catch (error) { console.error('Registration error:', error) return { success: false, error: locale === 'en' ? 'Registration failed' : 'Înregistrare eșuată' } } } const logout = async () => { try { const token = localStorage.getItem('authToken') if (token) { await fetch('/api/auth/logout', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }) } } catch (error) { console.error('Logout error:', error) } finally { localStorage.removeItem('authToken') setUser(null) } } const value: AuthContextType = { user, isAuthenticated: !!user, isLoading, login, register, logout, refreshUser: () => refreshUser(true) } return ( {children} ) } export function useAuth(): AuthContextType { const context = useContext(AuthContext) if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider') } return context }