Files
ds-chat/frontend/src/context/AuthContext.tsx
T
ksmithandClaude Sonnet 5 99aa029c0d Phase 1: auth, room CRUD, WebSocket chat, PWA frontend
Invite-only FastAPI + SQLAlchemy(async) + Postgres backend (session-cookie
auth via CLI-provisioned accounts, open-room CRUD, single-instance /ws/chat)
and a React + Vite PWA frontend (login, room list, chat view). Backend tests
pass against a local Postgres DB. See README.md and backend/README.md for
setup, and ARCHITECTURE.md for the full phased design.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 20:01:17 -06:00

52 lines
1.4 KiB
TypeScript

import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
import * as authApi from '../api/auth'
import { ApiError } from '../api/client'
import type { User } from '../types'
interface AuthContextValue {
user: User | null
loading: boolean
login: (usernameOrEmail: string, password: string) => Promise<void>
logout: () => 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)
useEffect(() => {
authApi
.me()
.then(setUser)
.catch((err) => {
if (!(err instanceof ApiError && err.status === 401)) {
console.error('Failed to load current user', err)
}
})
.finally(() => setLoading(false))
}, [])
async function login(usernameOrEmail: string, password: string) {
setUser(await authApi.login(usernameOrEmail, password))
}
async function logout() {
await authApi.logout()
setUser(null)
}
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth must be used within an AuthProvider')
return ctx
}