/
softailor
/
gridient
Обзор
Документация
Войти
/
softailor
/
gridient
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/src/components/Layout/Layout.tsx
113 строк
4 KB
Jenkins
Auto add
18 фев 2026, 10:19
18 фев 2026, 10:19
1e6c4f8
Код
Авторство
О чём код?
import { FC, useEffect, useMemo, useRef, useState } from "react"; import { Navigate, Outlet, useLocation, useNavigate } from "react-router-dom"; import { useAuthorization } from "hooks"; import { useGetListsQuery, useGetUserQuery } from "services"; import { AuthorizationContext, Operation, ResourceType } from "models/authorization"; import { Header } from "../Header"; import "./Layout.scss"; export const Layout: FC = () => { const location = useLocation(); const navigate = useNavigate(); const { data: lists, isLoading: listsLoading } = useGetListsQuery(); const { data: user, isLoading: userLoading } = useGetUserQuery(); // Проверяем доступ: либо ManageSystem, либо ListRead на первом списке const firstList = lists?.find((list) => !list.isDeleted); const authContexts = useMemo<AuthorizationContext[]>(() => { const contexts: AuthorizationContext[] = [ { resourceType: ResourceType.System, operation: Operation.ManageSystem, }, ]; if (firstList) { contexts.push({ resourceType: ResourceType.List, operation: Operation.ListRead, resourceId: firstList.id.toString(), }); } return contexts; }, [firstList]); // Отключаем автоматическую проверку и запускаем вручную после загрузки списков const { results, isLoading: authLoading, check } = useAuthorization(authContexts, false); // Строковое представление контекстов для сравнения const contextsString = useMemo(() => JSON.stringify(authContexts), [authContexts]); const lastCheckedContexts = useRef<string>(""); const [hasCheckedAuth, setHasCheckedAuth] = useState<boolean>(false); // Запускаем проверку авторизации только после загрузки списков и только если контексты изменились useEffect(() => { if (!listsLoading && lists !== undefined) { // Если контексты пустые, считаем проверку выполненной if (authContexts.length === 0) { setHasCheckedAuth(true); return; } if (lastCheckedContexts.current !== contextsString) { lastCheckedContexts.current = contextsString; setHasCheckedAuth(false); check().finally(() => { setHasCheckedAuth(true); }); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [listsLoading, lists, contextsString, authContexts.length]); useEffect(() => { if (location.pathname === "/" && lists) { const firstNotDictionaryList = lists .filter((list) => !list.isDeleted) .find((list) => !list.isDictionary); const firstDictionaryList = lists .filter((list) => !list.isDeleted) .find((list) => list.isDictionary); if (firstNotDictionaryList) { navigate(`/list/${firstNotDictionaryList.id}`); } else if (firstDictionaryList) { navigate(`/list/${firstDictionaryList.id}`); } else { navigate("/empty"); } } }, [location, lists, navigate]); // Показываем загрузку, пока загружаются пользователь, списки или проверяется авторизация // Также ждем, пока проверка авторизации не будет выполнена хотя бы раз if (userLoading || listsLoading || authLoading || !hasCheckedAuth) { return null; } if (!user) { return <Navigate to="/login" replace />; } // Проверяем, есть ли у пользователя хотя бы один доступ (ManageSystem или ListRead) // Проверяем доступ только если проверка авторизации была выполнена const hasAccess = results.length > 0 && results.some((result) => result.isAllowed); if (!hasAccess) { return <Navigate to="/no-access" replace />; } return ( <div className="layout-root"> <Header /> <main className="main"> <Outlet /> </main> </div> ); };