| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- 'use client'
- import { createContext, useContext, useState, useCallback, useEffect, type ReactNode } from 'react'
- import type { User } from '@/types'
- import { api, setAccessToken } from '@/lib/api'
- /**
- * Состояние аутентификации, доступное через контекст
- * @property user - Текущий пользователь или null
- * @property isLoading - Флаг загрузки сессии
- * @property login - Функция входа (email, пароль)
- * @property register - Функция регистрации (email, пароль, роль)
- * @property logout - Функция выхода
- * @property refreshSession - Функция обновления сессии
- */
- interface AuthState {
- user: User | null
- isLoading: boolean
- login: (email: string, password: string) => Promise<void>
- register: (email: string, password: string, role: string) => Promise<void>
- logout: () => Promise<void>
- refreshSession: () => Promise<void>
- }
- const AuthContext = createContext<AuthState | null>(null)
- /**
- * Провайдер аутентификации. Оборачивает приложение в контекст AuthState.
- * При монтировании пытается восстановить сессию через /auth/me.
- * Предоставляет дочерним компонентам методы login, register, logout, refreshSession.
- */
- export function AuthProvider({ children }: { children: ReactNode }) {
- const [user, setUser] = useState<User | null>(null)
- const [isLoading, setIsLoading] = useState(true)
- const refreshSession = useCallback(async () => {
- try {
- const res = await api.get<User>('/auth/me')
- setUser(res)
- } catch {
- setAccessToken(null)
- setUser(null)
- }
- }, [])
- useEffect(() => {
- refreshSession().finally(() => setIsLoading(false))
- }, [refreshSession])
- const login = useCallback(async (email: string, password: string) => {
- const res = await api.post<{ user: User; access_token: string }>('/auth/login', { email, password })
- setAccessToken(res.access_token)
- setUser(res.user)
- }, [])
- const register = useCallback(async (email: string, password: string, role: string) => {
- const res = await api.post<{ user: User; access_token: string }>('/auth/register', { email, password, role })
- setAccessToken(res.access_token)
- setUser(res.user)
- }, [])
- const logout = useCallback(async () => {
- try {
- await api.post('/auth/logout', {})
- } catch {}
- setAccessToken(null)
- setUser(null)
- }, [])
- return (
- <AuthContext.Provider value={{ user, isLoading, login, register, logout, refreshSession }}>
- {children}
- </AuthContext.Provider>
- )
- }
- /**
- * Хук для доступа к контексту аутентификации.
- * Должен использоваться внутри компонента AuthProvider.
- * @returns Объект AuthState с пользователем, состоянием загрузки и методами auth
- * @throws Ошибка, если хук вызван вне AuthProvider
- */
- export function useAuth() {
- const ctx = useContext(AuthContext)
- if (!ctx) throw new Error('useAuth must be used within AuthProvider')
- return ctx
- }
|