feat: role system

This commit is contained in:
2026-03-18 20:11:07 +03:00
parent 73070fe233
commit c3127b8d47
47 changed files with 2425 additions and 768 deletions

View File

@@ -37,7 +37,7 @@ import {
ArticlePreviewPage,
CountryAddPage,
} from "@pages";
import { authStore, createSightStore, editSightStore } from "@shared";
import { authStore, createSightStore, editSightStore, ROUTE_REQUIRED_RESOURCES } from "@shared";
import { Layout } from "@widgets";
import { runInAction } from "mobx";
import React, { useEffect } from "react";
@@ -48,6 +48,7 @@ import {
Navigate,
Outlet,
useLocation,
useMatches,
} from "react-router-dom";
const PublicRoute = ({ children }: { children: React.ReactNode }) => {
@@ -65,15 +66,28 @@ const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const need_auth = import.meta.env.VITE_NEED_AUTH == "true";
const location = useLocation();
const matches = useMatches();
if (!isAuthenticated && need_auth) {
return <Navigate to="/login" replace />;
}
if (location.pathname === "/") {
if (location.pathname === "/" && authStore.canRead("map")) {
return <Navigate to="/map" replace />;
}
const lastMatch = matches[matches.length - 1] as
| { handle?: { permissions?: string[] } }
| undefined;
const requiredPermissions = lastMatch?.handle?.permissions ?? [];
if (
requiredPermissions.length > 0 &&
!requiredPermissions.every((permission) => authStore.canAccess(permission))
) {
return <Navigate to="/" replace />;
}
return <>{children}</>;
};
@@ -102,7 +116,10 @@ const router = createBrowserRouter([
</PublicRoute>
),
},
{ path: "route-preview/:id", element: <RoutePreview /> },
{
path: "route-preview/:id",
element: <RoutePreview />,
},
{
path: "/",
element: (
@@ -115,48 +132,258 @@ const router = createBrowserRouter([
</ProtectedRoute>
),
children: [
{ index: true, element: <MainPage /> },
{
index: true,
element: <MainPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/"],
},
},
{ path: "sight", element: <SightListPage /> },
{ path: "sight/create", element: <CreateSightPage /> },
{ path: "sight/:id/edit", element: <EditSightPage /> },
{
path: "sight",
element: <SightListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/sight"],
},
},
{
path: "sight/create",
element: <CreateSightPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/sight/create"],
},
},
{
path: "sight/:id/edit",
element: <EditSightPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/sight/:id/edit"],
},
},
{ path: "devices", element: <DevicesPage /> },
{
path: "devices",
element: <DevicesPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/devices"],
},
},
{ path: "map", element: <MapPage /> },
{
path: "map",
element: <MapPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/map"],
},
},
{ path: "media", element: <MediaListPage /> },
{ path: "media/:id", element: <MediaPreviewPage /> },
{ path: "media/:id/edit", element: <MediaEditPage /> },
{
path: "media",
element: <MediaListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/media"],
},
},
{
path: "media/:id",
element: <MediaPreviewPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/media/:id"],
},
},
{
path: "media/:id/edit",
element: <MediaEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/media/:id/edit"],
},
},
{ path: "country", element: <CountryListPage /> },
{ path: "country/create", element: <CountryCreatePage /> },
{ path: "country/add", element: <CountryAddPage /> },
{ path: "country/:id/edit", element: <CountryEditPage /> },
{ path: "city", element: <CityListPage /> },
{ path: "city/create", element: <CityCreatePage /> },
{ path: "city/:id/edit", element: <CityEditPage /> },
{ path: "route", element: <RouteListPage /> },
{ path: "route/create", element: <RouteCreatePage /> },
{ path: "route/:id/edit", element: <RouteEditPage /> },
{
path: "country",
element: <CountryListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/country"],
},
},
{
path: "country/create",
element: <CountryCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/country/create"],
},
},
{
path: "country/add",
element: <CountryAddPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/country/add"],
},
},
{
path: "country/:id/edit",
element: <CountryEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/country/:id/edit"],
},
},
{
path: "city",
element: <CityListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/city"],
},
},
{
path: "city/create",
element: <CityCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/city/create"],
},
},
{
path: "city/:id/edit",
element: <CityEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/city/:id/edit"],
},
},
{
path: "route",
element: <RouteListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/route"],
},
},
{
path: "route/create",
element: <RouteCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/route/create"],
},
},
{
path: "route/:id/edit",
element: <RouteEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/route/:id/edit"],
},
},
{ path: "user", element: <UserListPage /> },
{ path: "user/create", element: <UserCreatePage /> },
{ path: "user/:id/edit", element: <UserEditPage /> },
{ path: "snapshot", element: <SnapshotListPage /> },
{ path: "snapshot/create", element: <SnapshotCreatePage /> },
{
path: "user",
element: <UserListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/user"],
},
},
{
path: "user/create",
element: <UserCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/user/create"],
},
},
{
path: "user/:id/edit",
element: <UserEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/user/:id/edit"],
},
},
{
path: "snapshot",
element: <SnapshotListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/snapshot"],
},
},
{
path: "snapshot/create",
element: <SnapshotCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/snapshot/create"],
},
},
{ path: "carrier", element: <CarrierListPage /> },
{ path: "carrier/create", element: <CarrierCreatePage /> },
{ path: "carrier/:id/edit", element: <CarrierEditPage /> },
{ path: "station", element: <StationListPage /> },
{ path: "station/create", element: <StationCreatePage /> },
{ path: "station/:id", element: <StationPreviewPage /> },
{ path: "station/:id/edit", element: <StationEditPage /> },
{ path: "vehicle/create", element: <VehicleCreatePage /> },
{ path: "vehicle/:id/edit", element: <VehicleEditPage /> },
{ path: "article", element: <ArticleListPage /> },
{ path: "article/:id", element: <ArticlePreviewPage /> },
{
path: "carrier",
element: <CarrierListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/carrier"],
},
},
{
path: "carrier/create",
element: <CarrierCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/carrier/create"],
},
},
{
path: "carrier/:id/edit",
element: <CarrierEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/carrier/:id/edit"],
},
},
{
path: "station",
element: <StationListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/station"],
},
},
{
path: "station/create",
element: <StationCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/station/create"],
},
},
{
path: "station/:id",
element: <StationPreviewPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/station/:id"],
},
},
{
path: "station/:id/edit",
element: <StationEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/station/:id/edit"],
},
},
{
path: "vehicle/create",
element: <VehicleCreatePage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/vehicle/create"],
},
},
{
path: "vehicle/:id/edit",
element: <VehicleEditPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/vehicle/:id/edit"],
},
},
{
path: "article",
element: <ArticleListPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/article"],
},
},
{
path: "article/:id",
element: <ArticlePreviewPage />,
handle: {
permissions: ROUTE_REQUIRED_RESOURCES["/article/:id"],
},
},
],
},
]);