codenuk_frontend_mine/src/contexts/auth-context.tsx
2025-09-09 11:23:58 +05:30

130 lines
4.5 KiB
TypeScript

"use client"
import React, { createContext, useContext, useEffect, useState } from 'react'
import { safeLocalStorage } from '@/lib/utils'
import { logout as logoutApi } from '@/components/apis/authApiClients'
interface User {
id: string
email: string
username: string
role?: 'user' | 'admin'
}
interface AuthContextValue {
user: User | null
isAdmin: boolean
isLoading: boolean
setUserFromApi: (user: User) => void
logout: () => Promise<void>
}
const AuthContext = createContext<AuthContextValue | undefined>(undefined)
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
const stored = safeLocalStorage.getItem('codenuk_user')
const accessToken = safeLocalStorage.getItem('accessToken')
const refreshToken = safeLocalStorage.getItem('refreshToken')
console.log('🔐 [AuthContext] Checking localStorage for user data...')
console.log('🔐 [AuthContext] Stored user data:', stored)
console.log('🔐 [AuthContext] Access token exists:', !!accessToken)
console.log('🔐 [AuthContext] Refresh token exists:', !!refreshToken)
console.log('🔐 [AuthContext] Token details:', {
accessTokenLength: accessToken?.length || 0,
refreshTokenLength: refreshToken?.length || 0,
timestamp: new Date().toISOString()
})
// Only restore user if we have both user data AND at least one token
if (stored && (accessToken || refreshToken)) {
try {
const userData = JSON.parse(stored)
console.log('🔐 [AuthContext] Restoring user session:', userData?.username)
console.log('🔐 [AuthContext] User ID from localStorage:', userData?.id)
setUser(userData)
} catch (error) {
console.error('Failed to parse stored user data:', error)
safeLocalStorage.removeItem('codenuk_user')
}
} else {
console.log('🔐 [AuthContext] No valid user session found')
// Clear any partial data
if (stored && !accessToken && !refreshToken) {
console.log('🔐 [AuthContext] Clearing orphaned user data without tokens')
safeLocalStorage.removeItem('codenuk_user')
}
}
setIsLoading(false)
}, [])
// Listen for storage changes to sync auth state across tabs
useEffect(() => {
const handleStorageChange = (e: StorageEvent) => {
if (e.key === 'codenuk_user' || e.key === 'accessToken' || e.key === 'refreshToken') {
console.log('🔐 [AuthContext] Storage changed, re-checking auth state')
const stored = safeLocalStorage.getItem('codenuk_user')
const accessToken = safeLocalStorage.getItem('accessToken')
const refreshToken = safeLocalStorage.getItem('refreshToken')
if (stored && (accessToken || refreshToken)) {
try {
const userData = JSON.parse(stored)
setUser(userData)
} catch (error) {
console.error('Failed to parse user data after storage change:', error)
setUser(null)
}
} else {
setUser(null)
}
}
}
window.addEventListener('storage', handleStorageChange)
return () => window.removeEventListener('storage', handleStorageChange)
}, [])
const setUserFromApi = (u: User) => {
console.log('🔐 [AuthContext] Setting user from API:', u)
console.log('🔐 [AuthContext] User ID being set:', u?.id)
setUser(u)
safeLocalStorage.setItem('codenuk_user', JSON.stringify(u))
console.log('🔐 [AuthContext] User data saved to localStorage')
}
const logout = async () => {
try {
// Call the logout API to invalidate tokens on the server
await logoutApi()
} catch (error) {
console.error('Logout API call failed:', error)
// Continue with local logout even if API call fails
} finally {
// Always clear local data
setUser(null)
safeLocalStorage.removeItem('codenuk_user')
safeLocalStorage.removeItem('accessToken')
safeLocalStorage.removeItem('refreshToken')
// Redirect to signin page
window.location.href = '/signin'
}
}
return (
<AuthContext.Provider value={{ user, isAdmin: user?.role === 'admin', isLoading, setUserFromApi, logout }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth must be used within AuthProvider')
return ctx
}