feat(org,rbac): dedicate organization panel, enforce role permissions, subheader info, and fix supervisor project sync
This commit is contained in:
@@ -9,52 +9,41 @@ import { useInventoryData, projName } from "./useInventoryData";
|
||||
import { faNum } from "../../lib/formatters";
|
||||
import { isoToJalaliStr } from "../../lib/jalali";
|
||||
|
||||
// انبارها — مدیر پروژه: مشاهده انبارهای پروژه خودش + افزودن/ویرایش/حذف (ادمین دسترسی ندارد)
|
||||
// انبارها — مدیریت انبارها برای مدیران (ادمین، مدیر تدارکات، مدیر پروژه)
|
||||
export function WarehousesPage() {
|
||||
const navigate = useNavigate();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const data = useInventoryData();
|
||||
const isAdmin = user?.role === "admin" || user?.role === "procurement_manager";
|
||||
const isPM = user?.role === "pm";
|
||||
const canManage = user?.role === "admin" || user?.role === "procurement_manager" || user?.role === "pm";
|
||||
|
||||
const [newName, setNewName] = useState("");
|
||||
const [newDesc, setNewDesc] = useState("");
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<string>("");
|
||||
const [editId, setEditId] = useState<string | null>(null);
|
||||
const [editName, setEditName] = useState("");
|
||||
const [editDesc, setEditDesc] = useState("");
|
||||
|
||||
// ادمین / مدیر تدارکات به بخش «انبارها» دسترسی ندارد — مدیریت انبارها از «سازماندهی»
|
||||
if (isAdmin) {
|
||||
if (!canManage) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Header title="انبارها" backTo="/inventory" backLabel="بازگشت به داشبورد" />
|
||||
<PageLayout>
|
||||
<div className="rounded-xl border border-line bg-panel p-8 text-center">
|
||||
<div className="text-3xl">🔒</div>
|
||||
<h3 className="mt-2 text-[15px] font-bold">دسترسی ندارد</h3>
|
||||
<h3 className="mt-2 text-[15px] font-bold">دسترسی محدود</h3>
|
||||
<p className="mt-1 text-[12.5px] text-muted">
|
||||
بخش «انبارها» مخصوص مدیران پروژه است. مدیریت انبارها از بخش «سازماندهی» انجام میشود.
|
||||
مدیریت و تعریف انبارها مخصوص مدیران سیستم است. سرپرست پروژه فقط به ثبت تغییرات موجودی دسترسی دارد.
|
||||
</p>
|
||||
</div>
|
||||
</PageLayout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (!isPM) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Header title="انبارها" backTo="/inventory" backLabel="بازگشت به داشبورد" />
|
||||
<PageLayout>
|
||||
<div className="text-[13px] text-muted">این بخش فقط برای مدیر پروژه است.</div>
|
||||
</PageLayout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const addWarehouse = async () => {
|
||||
const name = newName.trim();
|
||||
if (!name) return toast.error("نام انبار الزامی است");
|
||||
const projectId = user?.project_id;
|
||||
const projectId = selectedProjectId || user?.project_id || data.lookup.projects[0]?.id;
|
||||
if (!projectId) return toast.error("پروژه انبار را انتخاب کنید");
|
||||
try {
|
||||
await apiV26.warehouses.create({ project_id: projectId, name, description: newDesc.trim() || null });
|
||||
@@ -99,13 +88,26 @@ export function WarehousesPage() {
|
||||
backLabel="بازگشت به داشبورد"
|
||||
/>
|
||||
<PageLayout className="flex flex-col gap-3">
|
||||
{isPM && (
|
||||
{canManage && (
|
||||
<div className="rounded-xl border border-line bg-panel p-3">
|
||||
<h3 className="mb-2 text-[13px] font-bold">+ افزودن انبار جدید</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{data.lookup.projects.length > 1 && (
|
||||
<select
|
||||
className="h-9 rounded-lg border border-line bg-panel px-3 text-sm"
|
||||
value={selectedProjectId || user?.project_id || data.lookup.projects[0]?.id || ""}
|
||||
onChange={(e) => setSelectedProjectId(e.target.value)}
|
||||
>
|
||||
{data.lookup.projects.map((p) => (
|
||||
<option key={p.id} value={p.id}>
|
||||
پروژه: {p.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
<input
|
||||
className="h-9 w-52 rounded-lg border border-line bg-panel px-3 text-sm"
|
||||
placeholder="نام انبار (مثلاً انبار موقت)"
|
||||
placeholder="نام انبار (مثلاً انبار مرکزی)"
|
||||
value={newName}
|
||||
onChange={(e) => setNewName(e.target.value)}
|
||||
/>
|
||||
@@ -148,7 +150,7 @@ export function WarehousesPage() {
|
||||
>
|
||||
📊 مشاهده داشبورد انبار
|
||||
</button>
|
||||
{isPM && (
|
||||
{canManage && (
|
||||
<>
|
||||
<button
|
||||
className="rounded-lg border border-line px-3 py-1 text-[11.5px]"
|
||||
@@ -162,7 +164,7 @@ export function WarehousesPage() {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{editId === w.id && isPM && (
|
||||
{editId === w.id && canManage && (
|
||||
<div className="mt-2 flex flex-col gap-1.5 rounded-lg border border-dashed border-accent/40 p-2" onClick={(e) => e.stopPropagation()}>
|
||||
<input
|
||||
className="h-8 rounded-lg border border-line bg-panel px-2 text-sm"
|
||||
|
||||
Reference in New Issue
Block a user