From 7ddc7157b5ba5964f02e56e05ebaa4744871ca07 Mon Sep 17 00:00:00 2001 From: "MH.Dmitrii" Date: Mon, 5 Oct 2026 09:41:31 +0300 Subject: [PATCH] permission context --- frontend/src/App.tsx | 6 +++- frontend/src/contexts/PermissionContext.ts | 8 +++++ frontend/src/contexts/PermissionProvider.tsx | 31 ++++++++++++++++++ frontend/src/hooks/usePermissions.ts | 8 +++++ .../src/layouts/Main/Dashboard.module.css | 4 +-- frontend/src/layouts/Main/Dashboard.tsx | 32 +++---------------- frontend/src/utils/permissions.ts | 16 ++++++++++ 7 files changed, 74 insertions(+), 31 deletions(-) create mode 100644 frontend/src/contexts/PermissionContext.ts create mode 100644 frontend/src/contexts/PermissionProvider.tsx create mode 100644 frontend/src/hooks/usePermissions.ts create mode 100644 frontend/src/utils/permissions.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f1abb1b..be8e198 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3,13 +3,17 @@ import { Route, Routes } from "react-router-dom"; import { LoginPage } from "./pages/LoginPage"; import { ForgotPasswordPage } from "./pages/ForgotPasswordPage"; import { DashboardPage } from './pages/Dashboard'; +import { PermissionProvider } from './contexts/PermissionProvider'; function App() { return ( } /> } /> - } /> + + + } /> ); } diff --git a/frontend/src/contexts/PermissionContext.ts b/frontend/src/contexts/PermissionContext.ts new file mode 100644 index 0000000..765e94c --- /dev/null +++ b/frontend/src/contexts/PermissionContext.ts @@ -0,0 +1,8 @@ +import { createContext } from "react"; + +export type PermissionsState = { + permissions: Set; + loading: boolean; +}; + +export const PermissionContext = createContext(null); diff --git a/frontend/src/contexts/PermissionProvider.tsx b/frontend/src/contexts/PermissionProvider.tsx new file mode 100644 index 0000000..6506871 --- /dev/null +++ b/frontend/src/contexts/PermissionProvider.tsx @@ -0,0 +1,31 @@ +import { useEffect, useState, type ReactNode } from "react"; +import { useNavigate } from "react-router-dom"; +import { loadPermissions } from "../utils/permissions"; +import { PermissionContext } from "./PermissionContext"; + +export function PermissionProvider({ children }: { children: ReactNode }) { + const navigate = useNavigate(); + const [loading, setLoading] = useState(true); + const [permissions, setPermissions] = useState>(new Set()); + + useEffect(function () { + async function load() { + try { + const response = await loadPermissions(); + setPermissions(response); + setLoading(false); + } catch { + navigate("/"); + } + } + load(); + }, [navigate]); + + return ( + + {children} + + ); +} + + diff --git a/frontend/src/hooks/usePermissions.ts b/frontend/src/hooks/usePermissions.ts new file mode 100644 index 0000000..6bc9c3a --- /dev/null +++ b/frontend/src/hooks/usePermissions.ts @@ -0,0 +1,8 @@ +import { useContext } from "react"; +import { PermissionContext } from "../contexts/PermissionContext"; + +export function usePermissions() { + const ctx = useContext(PermissionContext); + if (!ctx) throw new Error("usePermissions must be used inside PermissionProvider"); + return ctx; +} \ No newline at end of file diff --git a/frontend/src/layouts/Main/Dashboard.module.css b/frontend/src/layouts/Main/Dashboard.module.css index 9df92b2..5b75642 100644 --- a/frontend/src/layouts/Main/Dashboard.module.css +++ b/frontend/src/layouts/Main/Dashboard.module.css @@ -1,7 +1,7 @@ -* { +/* * { outline: 1px solid red; -} +} */ .wrapper { display: grid; grid-template-columns: 20% 1fr; diff --git a/frontend/src/layouts/Main/Dashboard.tsx b/frontend/src/layouts/Main/Dashboard.tsx index 06275c3..47c9652 100644 --- a/frontend/src/layouts/Main/Dashboard.tsx +++ b/frontend/src/layouts/Main/Dashboard.tsx @@ -1,42 +1,18 @@ import type { ReactNode } from "react"; import styles from "./Dashboard.module.css" -import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { fetchUser } from "../../api/UserAPI/User"; import { logout } from "../../api/token"; +import { usePermissions } from "../../hooks/usePermissions"; export function MainLayout({sidebar, header, content, right_sidebar }: { sidebar: ReactNode;header: ReactNode; content: ReactNode; right_sidebar: ReactNode }) { const navigate = useNavigate(); - const [loading, setLoading] = useState(true); - const [permissions, setPermissions] = useState>(new Set()); - - useEffect(function () { - async function load() { - try { - const user = await fetchUser(); - - const permissions = new Set(); - - for (const p of user.direct_permissions) { - permissions.add(p.permission); - } - for (const g of user.group) { - for (const p of g.permissions) { - permissions.add(p.permission); - } - } - setPermissions(permissions); - setLoading(false); - } catch { - navigate("/"); - } - } - load(); - }, [navigate]); + const { permissions, loading } = usePermissions(); + if (loading) { return null; } + async function handleLogout() { await logout(); navigate("/"); diff --git a/frontend/src/utils/permissions.ts b/frontend/src/utils/permissions.ts new file mode 100644 index 0000000..47cc291 --- /dev/null +++ b/frontend/src/utils/permissions.ts @@ -0,0 +1,16 @@ +import { fetchUser } from "../api/UserAPI/User"; + +export async function loadPermissions(): Promise> { + const user = await fetchUser(); + + const permissions = new Set(); + for (const p of user.direct_permissions) { + permissions.add(p.permission); + } + for (const g of user.group) { + for (const p of g.permissions) { + permissions.add(p.permission); + } + } + return permissions; +} \ No newline at end of file