Files
pantry-management-frontend/src/context/AuthContext.jsx

82 lines
1.8 KiB
JavaScript

import { createContext, useContext, useEffect, useState } from 'react'
import {
authApi,
getStoredSession,
profileApi,
saveSession,
subscribeToSessionChanges,
} from '../api/client.js'
const AuthContext = createContext(null)
export function AuthProvider({ children }) {
const [session, setSession] = useState(() => getStoredSession())
const [initializing, setInitializing] = useState(() => Boolean(getStoredSession()))
useEffect(() => subscribeToSessionChanges(setSession), [])
useEffect(() => {
let cancelled = false
async function syncStoredSession() {
const existingSession = getStoredSession()
if (!existingSession) {
if (!cancelled) {
setInitializing(false)
}
return
}
try {
const profile = await profileApi.getProfile()
if (!cancelled) {
saveSession({
...existingSession,
user: profile,
})
}
} catch {
// The API client already clears invalid sessions after a failed refresh.
} finally {
if (!cancelled) {
setInitializing(false)
}
}
}
syncStoredSession()
return () => {
cancelled = true
}
}, [])
const user = session?.user ?? null
const userRoles = Array.isArray(user?.roles) ? user.roles : []
const value = {
session,
user,
isAuthenticated: Boolean(session?.accessToken),
isSiteAdmin: userRoles.includes('Admin'),
initializing,
login: authApi.login,
register: authApi.register,
logout: authApi.logout,
}
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
export function useAuth() {
const value = useContext(AuthContext)
if (!value) {
throw new Error('useAuth must be used inside an AuthProvider.')
}
return value
}