import { useMemo, useRef, useState } from "react"; import { useNavigate, Link } from "react-router-dom"; import { ChevronRight, ChevronLeft, Calendar as CalendarIcon, Building2, Plus, RotateCcw, PackageX, Trash2, Clock } from "lucide-react"; import { Header, PageLayout } from "../../components/layout/Header"; import { useAuthStore } from "../../store/auth"; import { inventorySubheader } from "./panelMenu"; import { useInventoryData, unitName, whName } from "./useInventoryData"; import { faNum } from "../../lib/formatters"; import { gregorianToJalali, jalaliToGregorian, MONTHS, toFa } from "../../lib/jalali"; import type { InventoryTransaction } from "../../lib/types"; function gregKey(d: Date): string { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; } function todayKey(): string { return gregKey(new Date()); } export function DailyControlPage() { const user = useAuthStore((s) => s.user); const data = useInventoryData(); const navigate = useNavigate(); const isPM = user?.role === "pm"; const [anchor, setAnchor] = useState(new Date()); const [sel, setSel] = useState(todayKey()); const [actRec, setActRec] = useState(null); const isAdmin = user?.role === "admin" || user?.role === "procurement_manager"; const [projFilter, setProjFilter] = useState(""); const txByDay = useMemo(() => { const map = new Map(); const projWhIds = projFilter ? new Set(data.warehouses.filter((w) => String(w.project_id) === String(projFilter)).map((w) => w.id)) : null; data.transactions.forEach((t) => { if (projWhIds && !projWhIds.has(t.warehouse_id)) return; const k = gregKey(new Date(t.transaction_date)); const arr = map.get(k) || []; arr.push(t); map.set(k, arr); }); map.forEach((arr) => arr.sort((a, b) => new Date(a.transaction_date).getTime() - new Date(b.transaction_date).getTime())); return map; }, [data.transactions, data.warehouses, projFilter]); const cells = useMemo(() => { const [ty, tm] = gregorianToJalali(anchor.getFullYear(), anchor.getMonth() + 1, anchor.getDate()); let first: Date | null = null; for (let i = 0; i <= 33; i++) { const d = new Date(anchor.getTime() - i * 86400000); const [py, pm] = gregorianToJalali(d.getFullYear(), d.getMonth() + 1, d.getDate()); if (py !== ty || pm !== tm) { first = new Date(anchor.getTime() - (i - 1) * 86400000); break; } } if (!first) first = new Date(anchor.getTime() - 33 * 86400000); const offset = (first.getDay() + 1) % 7; const gridStart = new Date(first.getTime() - offset * 86400000); const out: { d: Date; inMonth: boolean; isToday: boolean; n: number }[] = []; for (let c = 0; c < 42; c++) { const day = new Date(gridStart.getTime() + c * 86400000); const [jy, jm] = gregorianToJalali(day.getFullYear(), day.getMonth() + 1, day.getDate()); const k = gregKey(day); out.push({ d: day, inMonth: jy === ty && jm === tm, isToday: k === todayKey(), n: (txByDay.get(k) || []).length, }); } return out; }, [anchor, txByDay]); const [ty, tm] = gregorianToJalali(anchor.getFullYear(), anchor.getMonth() + 1, anchor.getDate()); const monthTitle = `${toFa(ty)} ${MONTHS[tm - 1]}`; const shiftMonth = (delta: number) => { let nm = tm + delta; let ny = ty; if (nm < 1) { nm = 12; ny -= 1; } else if (nm > 12) { nm = 1; ny += 1; } const [gy, gm, gd] = jalaliToGregorian(ny, nm, 1); setAnchor(new Date(gy, gm - 1, gd)); }; const dayTx = txByDay.get(sel) || []; const navLast = useRef<{ key: string; at: number }>({ key: "", at: 0 }); const navFire = (key: string, action: () => void) => { const now = Date.now(); if (navLast.current.key === key && now - navLast.current.at < 350) return; navLast.current = { key, at: now }; action(); }; const navBtnProps = (key: string, action: () => void) => ({ type: "button" as const, onPointerUp: (e: React.PointerEvent) => { e.preventDefault(); navFire(key, action); }, onClick: () => navFire(key, action), onKeyDown: (e: React.KeyboardEvent) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); navFire(key, action); } }, }); const withdrawals = dayTx.filter((t) => t.transaction_type === "WITHDRAWAL"); const wGroups = useMemo(() => { const gmap = new Map(); withdrawals.forEach((t) => { const g = gmap.get(t.inventory_id); if (!g) { gmap.set(t.inventory_id, { recId: t.inventory_id, q: Math.abs(t.quantity_number || 0), last: t.transaction_date, tx: t }); } else { g.q += Math.abs(t.quantity_number || 0); if (t.transaction_date > g.last) g.last = t.transaction_date; } }); return [...gmap.values()]; }, [withdrawals]); const isToday = sel === todayKey(); const selDate = new Date(Number(sel.split("-")[0]), Number(sel.split("-")[1]) - 1, Number(sel.split("-")[2])); const [sy, sm, sd] = gregorianToJalali(selDate.getFullYear(), selDate.getMonth() + 1, selDate.getDate()); return (
{/* نوار پروژه سفید و شفاف */}
پروژه: {isAdmin ? ( ) : ( پروژه فعال )} {projFilter ? "نمایش برای پروژه انتخابی" : "نمایش تمام پروژه‌ها"}
ثبت خروج / تغییر موجودی
{/* ستون تقویم — سفید، خوانا و بدون هدر تیره */}
{monthTitle}
{/* روزهای هفته */}
{["ش", "ی", "د", "س", "چ", "پ", "ج"].map((d) => (
{d}
))} {cells.map((c, i) => { const [, , jd] = gregorianToJalali(c.d.getFullYear(), c.d.getMonth() + 1, c.d.getDate()); const k = gregKey(c.d); const isSelected = sel === k; return ( ); })}
{/* ستون جزئیات روز — سفید یکدست */}

{isToday ? "امروز — " : "کنترل — "} {toFa(sd)} {MONTHS[sm - 1]} {toFa(sy)}

0 ? "bg-amber-50 text-amber-700 border border-amber-200" : "text-slate-400 border border-slate-100" }`} > {faNum(wGroups.length)} برداشت

اقلام برداشت‌شده از انبار در این تاریخ:

{!wGroups.length ? (
{isToday ? "امروز هنوز هیچ برداشتی ثبت نشده است." : "در این تاریخ برداشتی ثبت نشده است."} ثبت برداشت جدید
) : (
{wGroups.map((g) => (
{actRec === g.recId && isPM && (
)}
))}
)}
); }