/
aaronair
/
Test_task_rt_solution
Обзор
Документация
Войти
/
aaronair
/
Test_task_rt_solution
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/app/AppLayout.tsx
75 строк
4 KB
aaronair
Решение
03 июн 2026, 15:04
03 июн 2026, 15:04
72ced40
Код
Авторство
О чём код?
import { useState } from 'react'; import { Outlet, useLocation } from "react-router-dom"; import { Header } from "@/components/Header"; import { SearchChatWidget } from "@/components/SearchChatWidget"; import { ToastHost } from "@/components/Toast"; import { Auth } from '@/components/Auth'; export function AppLayout() { const [token, setToken] = useState<string | null>(localStorage.getItem('token')); const [role, setRole] = useState<string | null>(localStorage.getItem('role')); const [showAuthModal, setShowAuthModal] = useState<boolean>(false); const location = useLocation(); const handleAuthSuccess = (newToken: string, userRole: string, userId: string) => { localStorage.setItem('token', newToken); localStorage.setItem('role', userRole); localStorage.setItem('userId', userId); setToken(newToken); setRole(userRole); setShowAuthModal(false); }; // Прокидываем функцию открытия модалки в глобальное окно, чтобы вызвать её из Header (window as any).openAuthModal = () => setShowAuthModal(true); (window as any).handleLogoutGlobal = () => { localStorage.clear(); setToken(null); setRole(null); window.location.href = '/'; }; return ( <div className="min-h-full flex flex-col bg-slate-50"> {/* Родная шапка проекта, внутрь которой мы перенесли кнопки */} <Header /> {/* Основное содержимое приложения */} <main className="flex-1 container-page py-8"> {/* ВСПЛЫВАЮЩЕЕ ОКНО АВТОРИЗАЦИИ */} {showAuthModal && !token ? ( <div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50 p-4"> <div className="w-full max-w-md bg-white p-2 rounded-xl shadow-2xl border relative"> <button onClick={() => setShowAuthModal(false)} className="absolute top-4 right-4 text-gray-400 hover:text-gray-600 text-lg">✕</button> <Auth onAuthSuccess={handleAuthSuccess} /> </div> </div> ) : null} {/* ЗАЩИТА ПРЯМОГО ДУСТУПА К ВКЛАДКАМ ЧЕРЕЗ АДРЕСНУЮ СТРОКУ */} {location.pathname === '/dashboard' && !token ? ( <div className="max-w-md mx-auto text-center py-12 space-y-4 p-8 bg-white rounded-2xl border shadow-sm mt-10"> <h3 className="text-lg font-semibold text-slate-900">Личный кабинет заблокирован</h3> <p className="text-sm text-slate-500">Необходимо войти в аккаунт для просмотра ваших инициатив.</p> <button onClick={() => setShowAuthModal(true)} className="bg-indigo-600 text-white text-sm px-4 py-2 rounded hover:bg-indigo-500 font-semibold"> Войти в аккаунт </button> </div> ) : location.pathname === '/admin' && role !== 'admin' ? ( <div className="max-w-md mx-auto text-center py-12 space-y-4 p-8 bg-white rounded-2xl border border-red-200 shadow-sm mt-10"> <h3 className="text-lg font-semibold text-red-900">Страница не найдена</h3> <p className="text-sm text-slate-500">Запрашиваемый раздел отсутствует или у вас нет прав на его просмотр.</p> </div> ) : ( <Outlet /> )} </main> <SearchChatWidget /> <ToastHost /> </div> ); }