feat: PM panel under ERP shell + project-supervisor role
- /panel/pm: the PM app (served on the same origin under /pm) is embedded as a full-height iframe; supervisors are funneled there from every route, ERP MobileTabBar hidden on that route - Panels menu: «مدیریت پروژه (PM)» is an internal route (admin/pm/supervisor only — procurement managers do not see it); PM link is no longer external - New system role 'supervisor' (user_role enum): label in users router, allowed in UserRoleUpdate schema, deny-by-default on all ERP routers; admin panel can grant/revoke it alongside procurement manager - Removed the obsolete VITE_PM_URL build plumbing (same-origin now)
This commit is contained in:
+37
-1
@@ -1,5 +1,5 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { Navigate, Route, Routes } from "react-router-dom";
|
||||
import { Navigate, Route, Routes, useLocation } from "react-router-dom";
|
||||
import { useAuthStore } from "./store/auth";
|
||||
import { ErrorBoundary } from "./components/ErrorBoundary";
|
||||
import { RequirePmProjects } from "./components/RequirePmProjects";
|
||||
@@ -53,9 +53,14 @@ function Loading() {
|
||||
}
|
||||
|
||||
// همهی صفحات پشت ورود هستند — بدون نشست، به صفحهی ورود میرویم.
|
||||
// سرپرست پروژه (فقطِ پنل PM) از هر مسیری به پنل PM هدایت میشود.
|
||||
function RequireAuth({ children }: { children: React.ReactNode }) {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const { pathname } = useLocation();
|
||||
if (!user) return <Navigate to="/login" replace />;
|
||||
if (user.role === "supervisor" && pathname !== "/panel/pm") {
|
||||
return <Navigate to="/panel/pm" replace />;
|
||||
}
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -66,6 +71,26 @@ function HomeRoute() {
|
||||
return <DashboardPage />;
|
||||
}
|
||||
|
||||
// پنل «مدیریت پروژه (PM)» — اپ PM روی همان دامنه زیر مسیر /pm سرو میشود و
|
||||
// اینجا بهصورت iframe تمامصفحه داخل پوسته ERP نمایش داده میشود.
|
||||
function PmPanelPage() {
|
||||
return (
|
||||
<iframe
|
||||
src="/pm/"
|
||||
title="مدیریت پروژه (PM)"
|
||||
className="h-dvh w-full border-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// دسترسی پنل PM: ادمین، مدیر پروژه و سرپرست پروژه — مدیر تدارکات ندارد
|
||||
function RequirePmPanel({ children }: { children: React.ReactNode }) {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const allowed = user?.role === "admin" || user?.role === "pm" || user?.role === "supervisor";
|
||||
if (!allowed) return <Navigate to="/" replace />;
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
@@ -207,6 +232,17 @@ export default function App() {
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
{/* پنل مدیریت پروژه — فقط ادمین و مدیر پروژه */}
|
||||
<Route
|
||||
path="/panel/pm"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<RequirePmPanel>
|
||||
<PmPanelPage />
|
||||
</RequirePmPanel>
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
|
||||
Reference in New Issue
Block a user