75 lines
1.7 KiB
JavaScript
75 lines
1.7 KiB
JavaScript
import { createContext, createElement, useContext, useEffect, useMemo, useState } from 'react'
|
|
import { getMe, getStoredToken, login as loginApi, setStoredToken } from '../lib/api'
|
|
|
|
const AuthContext = createContext(null)
|
|
|
|
export function AuthProvider({ children }) {
|
|
const [user, setUser] = useState(null)
|
|
const [isReady, setIsReady] = useState(false)
|
|
|
|
useEffect(() => {
|
|
async function initializeAuth() {
|
|
const token = getStoredToken()
|
|
if (!token) {
|
|
setIsReady(true)
|
|
return
|
|
}
|
|
|
|
try {
|
|
const data = await getMe()
|
|
setUser(data?.user ?? null)
|
|
} catch {
|
|
setStoredToken(null)
|
|
setUser(null)
|
|
} finally {
|
|
setIsReady(true)
|
|
}
|
|
}
|
|
|
|
initializeAuth()
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
function handleUnauthorized() {
|
|
setUser(null)
|
|
}
|
|
|
|
window.addEventListener('auth:unauthorized', handleUnauthorized)
|
|
return () => window.removeEventListener('auth:unauthorized', handleUnauthorized)
|
|
}, [])
|
|
|
|
async function login(username, password) {
|
|
const data = await loginApi({ username, password })
|
|
setStoredToken(data?.token)
|
|
setUser(data?.user ?? null)
|
|
return data?.user ?? null
|
|
}
|
|
|
|
function logout() {
|
|
setStoredToken(null)
|
|
setUser(null)
|
|
}
|
|
|
|
const value = useMemo(
|
|
() => ({
|
|
user,
|
|
isReady,
|
|
isAuthenticated: Boolean(user),
|
|
isAdmin: user?.role === 'admin',
|
|
login,
|
|
logout,
|
|
}),
|
|
[user, isReady]
|
|
)
|
|
|
|
return createElement(AuthContext.Provider, { value }, children)
|
|
}
|
|
|
|
export function useAuth() {
|
|
const context = useContext(AuthContext)
|
|
if (!context) {
|
|
throw new Error('useAuth must be used inside AuthProvider')
|
|
}
|
|
return context
|
|
}
|