Files
aurora-moments/web/src/context/AuthContext.tsx
T
KrisandClaude Sonnet 5 4877e0a779 Initial commit: Aurora Moments self-hosted photo/video sharing platform
Django/DRF + PostgreSQL/Redis/Celery backend with accounts, library,
moments, and notifications apps; React/TypeScript/Vite frontend with
Instagram-style sidebar nav, feed, profiles, nested comment replies,
notifications, and photo/video upload with ffmpeg-generated posters.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-10 10:28:53 -05:00

78 lines
2.2 KiB
TypeScript

import { createContext, useCallback, useContext, useEffect, useState } from 'react'
import type { ReactNode } from 'react'
import * as authApi from '../api/auth'
import { setAuthFailureHandler, tokenStorage } from '../api/client'
import type { User } from '../api/types'
interface AuthContextValue {
user: User | null
loading: boolean
login: (email: string, password: string) => Promise<void>
register: (email: string, username: string, password: string) => Promise<void>
logout: () => void
refreshUser: () => Promise<void>
}
const AuthContext = createContext<AuthContextValue | undefined>(undefined)
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
const refreshMe = useCallback(async () => {
if (!tokenStorage.getAccess()) {
setUser(null)
setLoading(false)
return
}
try {
setUser(await authApi.getMe())
} catch {
tokenStorage.clear()
setUser(null)
} finally {
setLoading(false)
}
}, [])
useEffect(() => {
refreshMe()
}, [refreshMe])
// Fires when a request's 401 survives a refresh attempt (refresh token
// missing/expired/revoked) — drop back to logged-out state so
// ProtectedRoute sends the user to /login instead of the app silently
// failing every request.
useEffect(() => {
setAuthFailureHandler(() => setUser(null))
return () => setAuthFailureHandler(() => {})
}, [])
const login = async (email: string, password: string) => {
await authApi.login(email, password)
await refreshMe()
}
const register = async (email: string, username: string, password: string) => {
await authApi.register(email, username, password)
await refreshMe()
}
const logout = () => {
authApi.logout()
setUser(null)
}
return (
<AuthContext.Provider value={{ user, loading, login, register, logout, refreshUser: refreshMe }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth must be used within AuthProvider')
return ctx
}