Первоначальная версия VidConf
This commit is contained in:
72
frontend/src/auth/AuthProvider.tsx
Normal file
72
frontend/src/auth/AuthProvider.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { useCallback, useEffect, useMemo, useState, type ReactNode } from 'react'
|
||||
import { getMe, login as apiLogin, logout as apiLogout, type CurrentUser } from '@/api/auth'
|
||||
import { authStore } from '@/auth/authStore'
|
||||
import { refreshAccessToken } from '@/api/client'
|
||||
import { AuthContext, type AuthContextValue, type AuthStatus } from '@/auth/authContext'
|
||||
|
||||
/**
|
||||
* Провайдер сессии пользователя.
|
||||
* При монтировании приложения пытается восстановить сессию через
|
||||
* silent-refresh (httpOnly refresh-cookie), т.к. access-токен в памяти
|
||||
* теряется при перезагрузке страницы.
|
||||
*/
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [user, setUser] = useState<CurrentUser | null>(null)
|
||||
const [status, setStatus] = useState<AuthStatus>('loading')
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
async function bootstrap() {
|
||||
const restored = await refreshAccessToken()
|
||||
if (cancelled) return
|
||||
if (!restored) {
|
||||
setStatus('unauthenticated')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const me = await getMe()
|
||||
if (cancelled) return
|
||||
setUser(me)
|
||||
setStatus('authenticated')
|
||||
} catch {
|
||||
if (!cancelled) setStatus('unauthenticated')
|
||||
}
|
||||
}
|
||||
|
||||
void bootstrap()
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
const login = useCallback(async (email: string, password: string) => {
|
||||
const token = await apiLogin(email, password)
|
||||
authStore.setAccessToken(token.access_token)
|
||||
const me = await getMe()
|
||||
setUser(me)
|
||||
setStatus('authenticated')
|
||||
}, [])
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
try {
|
||||
await apiLogout()
|
||||
} finally {
|
||||
authStore.setAccessToken(null)
|
||||
setUser(null)
|
||||
setStatus('unauthenticated')
|
||||
}
|
||||
}, [])
|
||||
|
||||
const refreshUser = useCallback(async () => {
|
||||
const me = await getMe()
|
||||
setUser(me)
|
||||
}, [])
|
||||
|
||||
const value = useMemo<AuthContextValue>(
|
||||
() => ({ user, status, login, logout, refreshUser }),
|
||||
[user, status, login, logout, refreshUser],
|
||||
)
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
|
||||
}
|
||||
Reference in New Issue
Block a user