feat(inventory): role-aware header navigation - PM top nav without hamburger, admin top nav plus compact account menu
This commit is contained in:
@@ -1,22 +1,24 @@
|
||||
import { useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
import { Header, PageLayout } from "../../components/layout/Header";
|
||||
import { useAuthStore } from "../../store/auth";
|
||||
import { PanelMenu } from "../../components/PanelMenu";
|
||||
import { panelMenuItems, useLogout } from "./panelMenu";
|
||||
import { InventoryTopNav } from "./InventoryTopNav";
|
||||
import { apiV26 } from "../../lib/api";
|
||||
import { useInventoryData, projName } from "./useInventoryData";
|
||||
import { faNum } from "../../lib/formatters";
|
||||
import { isoToJalaliStr } from "../../lib/jalali";
|
||||
|
||||
// انبارها — پورت کامل نسخهی ارسالی (مدیر پروژه: افزودن/ویرایش/حذف)
|
||||
// انبارها — مدیر پروژه: مشاهده انبارهای پروژه خودش + افزودن/ویرایش/حذف (ادمین دسترسی ندارد)
|
||||
export function WarehousesPage() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const logout = useLogout();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const data = useInventoryData();
|
||||
const isAdmin = user?.role === "admin";
|
||||
const isAdmin = user?.role === "admin" || user?.role === "procurement_manager";
|
||||
const isPM = user?.role === "pm";
|
||||
|
||||
const [newName, setNewName] = useState("");
|
||||
@@ -25,6 +27,34 @@ export function WarehousesPage() {
|
||||
const [editName, setEditName] = useState("");
|
||||
const [editDesc, setEditDesc] = useState("");
|
||||
|
||||
// ادمین / مدیر تدارکات به بخش «انبارها» دسترسی ندارد — مدیریت انبارها از «سازماندهی»
|
||||
if (isAdmin) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Header title="انبارها" menu={<PanelMenu title="پنل مدیریت انبار" items={panelMenuItems(location.pathname, user?.role, logout)} />} />
|
||||
<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>
|
||||
<p className="mt-1 text-[12.5px] text-muted">
|
||||
بخش «انبارها» مخصوص مدیران پروژه است. مدیریت انبارها از بخش «سازماندهی» انجام میشود.
|
||||
</p>
|
||||
</div>
|
||||
</PageLayout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (!isPM) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Header title="انبارها" menu={<PanelMenu title="پنل مدیریت انبار" items={panelMenuItems(location.pathname, user?.role, logout)} />} />
|
||||
<PageLayout>
|
||||
<div className="text-[13px] text-muted">این بخش فقط برای مدیر پروژه است.</div>
|
||||
</PageLayout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const addWarehouse = async () => {
|
||||
const name = newName.trim();
|
||||
if (!name) return toast.error("نام انبار الزامی است");
|
||||
@@ -69,15 +99,9 @@ export function WarehousesPage() {
|
||||
<Header
|
||||
title="انبارها"
|
||||
sub={user?.project_name || ""}
|
||||
menu={<PanelMenu title="پنل مدیریت انبار" items={panelMenuItems(location.pathname, user?.role, logout)} />}
|
||||
actions={<InventoryTopNav pathname={location.pathname} onLogout={logout} />}
|
||||
/>
|
||||
<PageLayout className="flex flex-col gap-3">
|
||||
{isAdmin && (
|
||||
<div className="rounded-lg border border-amber/30 bg-amber/5 px-3 py-2 text-[12px] text-amber">
|
||||
🔒 نقش ادمین فقطخواندنی است — مدیریت انبارها با مدیران پروژه است.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isPM && (
|
||||
<div className="rounded-xl border border-line bg-panel p-3">
|
||||
<h3 className="mb-2 text-[13px] font-bold">+ افزودن انبار جدید</h3>
|
||||
@@ -106,7 +130,12 @@ export function WarehousesPage() {
|
||||
const cnt = data.inventory.filter((r) => r.warehouse?.id === w.id).length;
|
||||
const txc = data.transactions.filter((t) => t.warehouse_id === w.id).length;
|
||||
return (
|
||||
<div key={w.id} className="rounded-xl border border-line bg-panel p-4">
|
||||
<div
|
||||
key={w.id}
|
||||
className="cursor-pointer rounded-xl border border-line bg-panel p-4 transition-colors hover:border-accent/50 hover:bg-accent/5"
|
||||
onClick={() => navigate(`/inventory?warehouse=${w.id}`)}
|
||||
title="ورود به داشبورد این انبار (فیلترشده)"
|
||||
>
|
||||
<h3 className="text-[14px] font-bold">🏬 {w.name}</h3>
|
||||
<div className="mt-0.5 text-[11.5px] text-muted">{w.description || "—"}</div>
|
||||
<div className="mt-2 flex flex-col gap-1 text-[12px] text-muted">
|
||||
@@ -115,21 +144,29 @@ export function WarehousesPage() {
|
||||
<span>تراکنشها: <b className="text-foreground">{faNum(txc)}</b></span>
|
||||
<span>تاریخ ایجاد: <b className="text-foreground">{isoToJalaliStr(w.created_at)}</b></span>
|
||||
</div>
|
||||
{isPM && (
|
||||
<div className="mt-3 flex gap-1.5 border-t border-line pt-2">
|
||||
<button
|
||||
className="rounded-lg border border-line px-3 py-1 text-[11.5px]"
|
||||
onClick={() => { setEditId(w.id); setEditName(w.name); setEditDesc(w.description || ""); }}
|
||||
>
|
||||
✏️ ویرایش
|
||||
</button>
|
||||
<button className="rounded-lg border border-red/30 px-3 py-1 text-[11.5px] text-red" onClick={() => void removeWarehouse(w.id)}>
|
||||
✕ حذف
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-3 flex items-center gap-1.5 border-t border-line pt-2">
|
||||
<button
|
||||
className="rounded-lg border border-accent/40 bg-accent/5 px-3 py-1 text-[11.5px] font-bold text-accent"
|
||||
onClick={(e) => { e.stopPropagation(); navigate(`/inventory?warehouse=${w.id}`); }}
|
||||
>
|
||||
📊 مشاهده داشبورد انبار
|
||||
</button>
|
||||
{isPM && (
|
||||
<>
|
||||
<button
|
||||
className="rounded-lg border border-line px-3 py-1 text-[11.5px]"
|
||||
onClick={(e) => { e.stopPropagation(); setEditId(w.id); setEditName(w.name); setEditDesc(w.description || ""); }}
|
||||
>
|
||||
✏️ ویرایش
|
||||
</button>
|
||||
<button className="rounded-lg border border-red/30 px-3 py-1 text-[11.5px] text-red" onClick={(e) => { e.stopPropagation(); void removeWarehouse(w.id); }}>
|
||||
✕ حذف
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{editId === w.id && isPM && (
|
||||
<div className="mt-2 flex flex-col gap-1.5 rounded-lg border border-dashed border-accent/40 p-2">
|
||||
<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"
|
||||
placeholder="نام انبار"
|
||||
|
||||
Reference in New Issue
Block a user