dev_arc_aws/src/lib/AuthContext.tsx

77 lines
2 KiB
TypeScript
Raw Normal View History

import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
import { api, getToken, setToken, type AuthUser } from './api'
type AuthStatus = 'loading' | 'needs-setup' | 'enrolling' | 'logged-out' | 'logged-in'
interface AuthContextValue {
status: AuthStatus
user: AuthUser | null
login: (username: string, password: string) => Promise<void>
completeSetup: (username: string, password: string) => Promise<void>
finishEnrollment: () => Promise<void>
logout: () => void
setUser: (user: AuthUser) => void
}
const AuthContext = createContext<AuthContextValue | null>(null)
export function AuthProvider({ children }: { children: ReactNode }) {
const [status, setStatus] = useState<AuthStatus>('loading')
const [user, setUser] = useState<AuthUser | null>(null)
async function refresh() {
if (getToken()) {
try {
const { user } = await api.me()
setUser(user)
setStatus('logged-in')
return
} catch {
setToken(null)
}
}
const { needsSetup } = await api.getSetupStatus()
setStatus(needsSetup ? 'needs-setup' : 'logged-out')
}
useEffect(() => {
refresh()
}, [])
async function login(username: string, password: string) {
const { token } = await api.login(username, password)
setToken(token)
await refresh()
}
async function completeSetup(username: string, password: string) {
const { token } = await api.setup(username, password)
setToken(token)
const { user } = await api.me()
setUser(user)
setStatus('enrolling')
}
async function finishEnrollment() {
await refresh()
}
function logout() {
setToken(null)
setUser(null)
setStatus('logged-out')
}
return (
<AuthContext.Provider value={{ status, user, login, completeSetup, finishEnrollment, logout, setUser }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth must be used within AuthProvider')
return ctx
}