95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
import { createContext, useContext, useEffect, useState } from 'react';
|
||
import { useNavigate } from "react-router-dom";
|
||
|
||
import { authApi, IAuthUser } from "@/shared/api";
|
||
import { ROUTES } from "@/shared/lib/hooks/useNavigation";
|
||
|
||
interface IAuthContext {
|
||
user: IAuthUser | null;
|
||
loading: boolean;
|
||
updateUserContext?: (newValues: Partial<IAuthContext>) => void;
|
||
}
|
||
|
||
const AuthContext = createContext<IAuthContext>({
|
||
user: null,
|
||
loading: true,
|
||
});
|
||
|
||
export const useAuth = () => {
|
||
const context = useContext(AuthContext);
|
||
if (!context) {
|
||
throw new Error('useAuth must be used within AuthProvider');
|
||
}
|
||
return context;
|
||
};
|
||
|
||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||
const [user, setUser] = useState<IAuthUser | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const navigate = useNavigate();
|
||
|
||
const validateToken = async () => {
|
||
const accessToken = window.localStorage.getItem("accessToken");
|
||
const refreshToken = window.localStorage.getItem("refreshToken");
|
||
|
||
if (!accessToken) {
|
||
// Токена нет → отправляем на регистрацию
|
||
navigate(ROUTES.REGISTER, { replace: true });
|
||
setLoading(false);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const { data } = await authApi.validateToken();
|
||
|
||
if (data.success) {
|
||
// Токен валиден
|
||
setUser(data.user);
|
||
} else if (refreshToken) {
|
||
// Токен устарел → обновляем
|
||
const { data: refreshData } = await authApi.refreshToken({ refreshToken });
|
||
if (refreshData.accessToken) {
|
||
window.localStorage.setItem("accessToken", refreshData.accessToken);
|
||
// Повторная валидация после обновления токена
|
||
const { data: validated } = await authApi.validateToken();
|
||
if (validated.success) setUser(validated.user);
|
||
} else {
|
||
// Не удалось обновить → отправляем на логин
|
||
navigate(ROUTES.LOGIN, { replace: true });
|
||
}
|
||
} else {
|
||
// Нет refresh токена → отправляем на логин
|
||
navigate(ROUTES.LOGIN, { replace: true });
|
||
}
|
||
} catch (err) {
|
||
/* eslint-disable */
|
||
console.error('Ошибка при проверке токена', err);
|
||
/* eslint-enable */
|
||
navigate(ROUTES.LOGIN, { replace: true });
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
validateToken()
|
||
}, []);
|
||
|
||
const updateUserContext = (newValues: Partial<IAuthContext>) => {
|
||
if (newValues.user !== undefined) {
|
||
setUser(newValues.user);
|
||
}
|
||
};
|
||
|
||
const contextValue: IAuthContext = {
|
||
user,
|
||
loading,
|
||
updateUserContext
|
||
};
|
||
return (
|
||
<AuthContext.Provider value={contextValue}>
|
||
{children}
|
||
</AuthContext.Provider>
|
||
);
|
||
}
|