Profil: Begrüßung in Zielsprache, Kategorie-Punkte-Übersicht, ruhigerer Header (kein rotierender Avatar/Online-Dot), Notch-Fix und kompaktere Aktivitäts-Heatmap. Außerdem Capacitor-iOS-Projekt und diverse Auth/Feed/Audio-Verbesserungen aus dem Premium-Redesign. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
1.4 KiB
JavaScript
42 lines
1.4 KiB
JavaScript
import { createContext, useContext, useState, useEffect } from 'react'
|
|
import { getMe } from '../api/directus'
|
|
import { getStoredToken, setStoredToken, clearStoredToken } from '../utils/secureToken'
|
|
|
|
const AuthContext = createContext(null)
|
|
|
|
export function AuthProvider({ children }) {
|
|
const [token, setToken] = useState(null)
|
|
const [user, setUser] = useState(null)
|
|
const [loading, setLoading] = useState(true)
|
|
const [bootstrapped, setBootstrapped] = useState(false)
|
|
|
|
// Token einmalig aus dem sicheren Speicher laden (inkl. Migration aus localStorage).
|
|
useEffect(() => {
|
|
getStoredToken()
|
|
.then(setToken)
|
|
.catch(() => setToken(null))
|
|
.finally(() => setBootstrapped(true))
|
|
}, [])
|
|
|
|
// Profil laden, sobald der Token bekannt ist.
|
|
useEffect(() => {
|
|
if (!bootstrapped) return
|
|
if (!token) { setLoading(false); return }
|
|
getMe(token)
|
|
.then(setUser)
|
|
.catch(() => { clearStoredToken(); setToken(null) })
|
|
.finally(() => setLoading(false))
|
|
}, [token, bootstrapped])
|
|
|
|
const saveToken = async (t) => { await setStoredToken(t); setToken(t) }
|
|
const logout = async () => { await clearStoredToken(); setToken(null); setUser(null) }
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ token, user, setUser, saveToken, logout, loading }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
)
|
|
}
|
|
|
|
export const useAuth = () => useContext(AuthContext)
|