feat(inventory): daily control - admin project filter and calendar navigation layout
This commit is contained in:
@@ -3,7 +3,8 @@ import { useLocation, useNavigate } from "react-router-dom";
|
|||||||
import { Header, PageLayout } from "../../components/layout/Header";
|
import { Header, PageLayout } from "../../components/layout/Header";
|
||||||
import { useAuthStore } from "../../store/auth";
|
import { useAuthStore } from "../../store/auth";
|
||||||
import { PanelMenu } from "../../components/PanelMenu";
|
import { PanelMenu } from "../../components/PanelMenu";
|
||||||
import { panelMenuItems, useLogout } from "./panelMenu";
|
import { accountMenuItems, useLogout } from "./panelMenu";
|
||||||
|
import { InventoryTopNav } from "./InventoryTopNav";
|
||||||
import { useInventoryData, unitName, whName } from "./useInventoryData";
|
import { useInventoryData, unitName, whName } from "./useInventoryData";
|
||||||
import { faNum } from "../../lib/formatters";
|
import { faNum } from "../../lib/formatters";
|
||||||
import { gregorianToJalali, MONTHS, toFa } from "../../lib/jalali";
|
import { gregorianToJalali, MONTHS, toFa } from "../../lib/jalali";
|
||||||
@@ -29,10 +30,17 @@ export function DailyControlPage() {
|
|||||||
const [anchor, setAnchor] = useState<Date>(new Date());
|
const [anchor, setAnchor] = useState<Date>(new Date());
|
||||||
const [sel, setSel] = useState<string>(todayKey());
|
const [sel, setSel] = useState<string>(todayKey());
|
||||||
const [actRec, setActRec] = useState<string | null>(null);
|
const [actRec, setActRec] = useState<string | null>(null);
|
||||||
|
// فیلتر پروژه — فقط برای مدیر تدارکات/ادمین (مدیر پروژه به پروژه خودش محدود است)
|
||||||
|
const isAdmin = user?.role === "admin" || user?.role === "procurement_manager";
|
||||||
|
const [projFilter, setProjFilter] = useState("");
|
||||||
|
|
||||||
const txByDay = useMemo(() => {
|
const txByDay = useMemo(() => {
|
||||||
const map = new Map<string, InventoryTransaction[]>();
|
const map = new Map<string, InventoryTransaction[]>();
|
||||||
|
const projWhIds = projFilter
|
||||||
|
? new Set(data.warehouses.filter((w) => String(w.project_id) === String(projFilter)).map((w) => w.id))
|
||||||
|
: null;
|
||||||
data.transactions.forEach((t) => {
|
data.transactions.forEach((t) => {
|
||||||
|
if (projWhIds && !projWhIds.has(t.warehouse_id)) return;
|
||||||
const k = gregKey(new Date(t.transaction_date));
|
const k = gregKey(new Date(t.transaction_date));
|
||||||
const arr = map.get(k) || [];
|
const arr = map.get(k) || [];
|
||||||
arr.push(t);
|
arr.push(t);
|
||||||
@@ -40,7 +48,7 @@ export function DailyControlPage() {
|
|||||||
});
|
});
|
||||||
map.forEach((arr) => arr.sort((a, b) => new Date(a.transaction_date).getTime() - new Date(b.transaction_date).getTime()));
|
map.forEach((arr) => arr.sort((a, b) => new Date(a.transaction_date).getTime() - new Date(b.transaction_date).getTime()));
|
||||||
return map;
|
return map;
|
||||||
}, [data.transactions]);
|
}, [data.transactions, data.warehouses, projFilter]);
|
||||||
|
|
||||||
// cells: 42 روز از شنبه قبلِ اولین روز ماه جلالی
|
// cells: 42 روز از شنبه قبلِ اولین روز ماه جلالی
|
||||||
const cells = useMemo(() => {
|
const cells = useMemo(() => {
|
||||||
@@ -99,18 +107,39 @@ export function DailyControlPage() {
|
|||||||
<Header
|
<Header
|
||||||
title="کنترل روزانه"
|
title="کنترل روزانه"
|
||||||
sub={user?.project_name || ""}
|
sub={user?.project_name || ""}
|
||||||
menu={<PanelMenu title="پنل مدیریت انبار" items={panelMenuItems(location.pathname, user?.role, logout)} />}
|
menu={isAdmin ? <PanelMenu title="پنل مدیریت انبار" items={accountMenuItems(logout)} /> : undefined}
|
||||||
|
actions={isAdmin || isPM ? <InventoryTopNav pathname={location.pathname} onLogout={logout} variant={isAdmin ? "admin" : "pm"} /> : undefined}
|
||||||
/>
|
/>
|
||||||
<PageLayout className="flex flex-col gap-3">
|
<PageLayout className="flex flex-col gap-3">
|
||||||
|
{isAdmin && (
|
||||||
|
<div className="flex flex-wrap items-center gap-2 rounded-xl border border-line bg-panel px-3 py-2 text-[12.5px]">
|
||||||
|
<label className="font-bold">🏢 پروژه:</label>
|
||||||
|
<select
|
||||||
|
className="h-8 rounded-lg border border-line bg-panel px-2 text-[12.5px]"
|
||||||
|
value={projFilter}
|
||||||
|
onChange={(e) => setProjFilter(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="">همه پروژهها</option>
|
||||||
|
{data.lookup.projects.map((p) => (
|
||||||
|
<option key={p.id} value={p.id}>{p.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<span className="text-[11.5px] text-muted">
|
||||||
|
{projFilter
|
||||||
|
? "نمایش کنترل روزانه فقط برای پروژه انتخابی"
|
||||||
|
: "نمایش کنترل روزانه همه پروژهها"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="grid gap-4 lg:grid-cols-2">
|
<div className="grid gap-4 lg:grid-cols-2">
|
||||||
{/* تقویم */}
|
{/* تقویم */}
|
||||||
<div className="rounded-xl border border-line bg-panel p-4">
|
<div className="rounded-xl border border-line bg-panel p-4">
|
||||||
<div className="mb-2 flex items-center justify-between">
|
<div className="mb-2 flex items-center justify-between">
|
||||||
<div className="text-[14px] font-bold">📅 {monthTitle}</div>
|
<div className="text-[14px] font-bold">📅 {monthTitle}</div>
|
||||||
<div className="flex gap-1.5">
|
<div className="flex gap-1.5">
|
||||||
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => setAnchor(new Date(anchor.getTime() + 33 * 86400000))}>◀ ماه بعد</button>
|
|
||||||
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => { setAnchor(new Date()); setSel(todayKey()); setActRec(null); }}>امروز</button>
|
|
||||||
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => setAnchor(new Date(anchor.getTime() - 33 * 86400000))}>▶ ماه قبل</button>
|
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => setAnchor(new Date(anchor.getTime() - 33 * 86400000))}>▶ ماه قبل</button>
|
||||||
|
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => { setAnchor(new Date()); setSel(todayKey()); setActRec(null); }}>امروز</button>
|
||||||
|
<button className="rounded-lg border border-line px-3 py-1 text-[12px]" onClick={() => setAnchor(new Date(anchor.getTime() + 33 * 86400000))}>◀ ماه بعد</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-7 gap-1">
|
<div className="grid grid-cols-7 gap-1">
|
||||||
|
|||||||
Reference in New Issue
Block a user