uchill/front_material/contexts/AuthContext.tsx

111 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { getCurrentUser, refreshToken, User } from '@/api/auth';
interface AuthContextType {
user: User | null;
loading: boolean;
login: (token: string, userData?: User) => Promise<void>;
logout: () => void;
refreshUser: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const loadUser = async () => {
try {
const token = typeof window !== 'undefined' ? localStorage.getItem('access_token') : null;
if (!token) {
setUser(null);
setLoading(false);
return;
}
try {
const userData = await getCurrentUser();
setUser(userData);
} catch (firstError) {
// При 401 пробуем обновить токен и повторить загрузку (на случай, если interceptor не сработал)
const refresh = typeof window !== 'undefined' ? localStorage.getItem('refresh_token') : null;
if (refresh) {
try {
const { access } = await refreshToken(refresh);
if (access && typeof window !== 'undefined') {
localStorage.setItem('access_token', access);
const userData = await getCurrentUser();
setUser(userData);
setLoading(false);
return;
}
} catch (_) {
// refresh не удался — выходим
}
}
console.error('[AuthContext] Error loading user:', firstError);
if (typeof window !== 'undefined') {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
}
setUser(null);
}
} catch (error) {
console.error('[AuthContext] Error loading user:', error);
if (typeof window !== 'undefined') {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
}
setUser(null);
} finally {
setLoading(false);
}
};
useEffect(() => {
loadUser();
}, []);
const login = async (token: string, userData?: User) => {
if (typeof window !== 'undefined') {
localStorage.setItem('access_token', token);
}
// Если данные пользователя уже есть, используем их (быстрее)
if (userData) {
setUser(userData);
setLoading(false);
} else {
// Иначе загружаем с сервера
await loadUser();
}
};
const logout = () => {
if (typeof window !== 'undefined') {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
}
setUser(null);
};
const refreshUser = async () => {
await loadUser();
};
return (
<AuthContext.Provider value={{ user, loading, login, logout, refreshUser }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}