gui version

This commit is contained in:
Den Piligrim
2026-01-28 12:05:10 +03:00
parent f574931c25
commit ba6db6edd5
102 changed files with 19151 additions and 2673 deletions
+36
View File
@@ -0,0 +1,36 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import api from '../api';
interface AuthContextType {
token: string | null;
login: (token: string) => void;
logout: () => void;
isAuthenticated: boolean;
}
const AuthContext = createContext<AuthContextType>(null!);
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [token, setToken] = useState<string | null>(localStorage.getItem('token'));
useEffect(() => {
if (token) {
localStorage.setItem('token', token);
api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
} else {
localStorage.removeItem('token');
delete api.defaults.headers.common['Authorization'];
}
}, [token]);
const login = (newToken: string) => setToken(newToken);
const logout = () => setToken(null);
return (
<AuthContext.Provider value={{ token, login, logout, isAuthenticated: !!token }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
+29
View File
@@ -0,0 +1,29 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import api from '../api';
import { useAuth } from './AuthContext';
export function AxiosInterceptor() {
const { logout } = useAuth();
const navigate = useNavigate();
useEffect(() => {
const interceptor = api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
console.warn('Session expired or unauthorized. Logging out...');
logout();
navigate('/login');
}
return Promise.reject(error);
}
);
return () => {
api.interceptors.response.eject(interceptor);
};
}, [logout, navigate]);
return null;
}
+12
View File
@@ -0,0 +1,12 @@
import { Navigate, Outlet } from 'react-router-dom';
import { useAuth } from './AuthContext';
export default function PublicRoute() {
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Navigate to="/" replace />;
}
return <Outlet />;
}
+14
View File
@@ -0,0 +1,14 @@
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from './AuthContext';
import type React from 'react';
export default function RequireAuth({ children }: { children: React.ReactNode }) {
const { isAuthenticated } = useAuth();
const location = useLocation();
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}