shinkan-jinkendo/frontend/src/context/AuthContext.jsx

134 lines
3.8 KiB
React
Raw Normal View History

import { createContext, useContext, useState, useEffect } from 'react'
const AuthContext = createContext(null)
const TOKEN_KEY = 'bodytrack_token'
const PROFILE_KEY = 'bodytrack_active_profile'
export function AuthProvider({ children }) {
const [session, setSession] = useState(null) // {token, profile_id, role}
const [loading, setLoading] = useState(true)
const [needsSetup, setNeedsSetup] = useState(false)
useEffect(() => {
checkStatus()
}, [])
const checkStatus = async () => {
try {
const r = await fetch('/api/auth/status')
const status = await r.json()
if (status.needs_setup) {
setNeedsSetup(true)
setLoading(false)
return
}
// Try existing token
const token = localStorage.getItem(TOKEN_KEY)
if (token) {
const me = await fetch('/api/auth/me', {
headers: { 'X-Auth-Token': token }
})
if (me.ok) {
const profile = await me.json()
setSession({ token, profile_id: profile.id, role: profile.role, profile })
setLoading(false)
return
}
// Token expired
localStorage.removeItem(TOKEN_KEY)
}
} catch(e) {
console.error('Auth check failed', e)
}
setLoading(false)
}
const login = async (credentials) => {
// Support both new {email, pin} and legacy {profile_id, pin}
const body = typeof credentials === 'object' ? credentials : { profile_id: credentials }
const r = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
})
if (!r.ok) {
const err = await r.json()
throw new Error(err.detail || 'Login fehlgeschlagen')
}
const data = await r.json()
localStorage.setItem(TOKEN_KEY, data.token)
localStorage.setItem(PROFILE_KEY, data.profile_id)
// Fetch full profile
const me = await fetch('/api/auth/me', { headers: { 'X-Auth-Token': data.token } })
const profile = await me.json()
setSession({ token: data.token, profile_id: data.profile_id, role: data.role, profile })
return data
}
const setup = async (formData) => {
const r = await fetch('/api/auth/setup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
})
if (!r.ok) {
const err = await r.json()
throw new Error(err.detail || 'Setup fehlgeschlagen')
}
const data = await r.json()
localStorage.setItem(TOKEN_KEY, data.token)
localStorage.setItem(PROFILE_KEY, data.profile_id)
setNeedsSetup(false)
await checkStatus()
return data
}
const setAuthFromToken = (token, profile) => {
// Direct token/profile set (for email verification auto-login)
localStorage.setItem(TOKEN_KEY, token)
localStorage.setItem(PROFILE_KEY, profile.id)
setSession({
token,
profile_id: profile.id,
role: profile.role || 'user',
profile
})
}
const logout = async () => {
const token = localStorage.getItem(TOKEN_KEY)
if (token) {
await fetch('/api/auth/logout', { method: 'POST', headers: { 'X-Auth-Token': token } })
}
localStorage.removeItem(TOKEN_KEY)
setSession(null)
}
const isAdmin = session?.role === 'admin'
const canUseAI = session?.profile?.ai_enabled !== 0
const canExport = session?.profile?.export_enabled !== 0
return (
<AuthContext.Provider value={{
session, loading, needsSetup,
login, setup, logout, setAuthFromToken,
isAdmin, canUseAI, canExport,
token: session?.token,
profileId: session?.profile_id,
}}>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
return useContext(AuthContext)
}
export function getToken() {
return localStorage.getItem(TOKEN_KEY)
}