/* Bonyan ERP — dark side navigation rail */ const BNY_NAV = [ { id: "dashboard", label: "الرئيسية", labelLong: "الرئيسية", icon: "dashboard", perm: "dashboard" }, { id: "pos", label: "فاتورة", labelLong: "فاتورة جديدة", icon: "invoice", perm: "pos" }, { id: "invoices", label: "الفواتير", labelLong: "الفواتير", icon: "invoice", perm: "invoices_view" }, { id: "customers", label: "العملاء", labelLong: "العملاء", icon: "users", perm: "customers" }, { id: "suppliers", label: "الموردون", labelLong: "الموردون", icon: "supplier", perm: "suppliers" }, { id: "accounts", label: "الحسابات", labelLong: "الحسابات", icon: "wallet", perm: "customers" }, { id: "inventory", label: "المواد", labelLong: "المواد", icon: "inventory", perm: "inventory_view" }, { id: "warehouses", label: "المخازن", labelLong: "إدارة المخازن", icon: "building", perm: "inventory_edit" }, { id: "pricing", label: "التسعير", labelLong: "التسعير", icon: "card", perm: "pricing" }, { id: "reports", label: "التقارير", labelLong: "التقارير", icon: "chart", perm: "reports" }, // مجموعة الإعدادات: قائمة منسدلة تضم إعدادات الفاتورة والصلاحيات والحركات { id: "settings-group", label: "الإعدادات", labelLong: "الإعدادات", icon: "settings", children: [ { id: "settings", label: "الفاتورة", labelLong: "إعدادات الفاتورة", icon: "printer", perm: "invoice_settings" }, { id: "users", label: "الصلاحيات", labelLong: "صلاحيات المستخدمين", icon: "users", perm: "users_manage" }, { id: "activity", label: "الحركات", labelLong: "الحركات", icon: "history", perm: "activity" }, ]}, ]; /* قائمة مسطّحة (للجوال) — تفرد عناصر المجموعات */ function bnyAllowedNav(user) { const out = []; BNY_NAV.forEach((n) => { if (n.children) n.children.forEach((c) => { if (window.BnyCan(user, c.perm)) out.push(c); }); else if (window.BnyCan(user, n.perm)) out.push(n); }); return out; } function Rail({ active, onNav, user, onLogout }) { const I = window.BnyIcon; const D = window.BnyData; // عناصر المستوى الأول: عادية مسموحة + مجموعات فيها عنصر مسموح واحد على الأقل const topNav = BNY_NAV.map((n) => { if (!n.children) return window.BnyCan(user, n.perm) ? n : null; const kids = n.children.filter((c) => window.BnyCan(user, c.perm)); return kids.length ? { ...n, children: kids } : null; }).filter(Boolean); const groupOfActive = (n) => n.children && n.children.some((c) => c.id === active); const [openGroups, setOpenGroups] = React.useState(() => { const o = {}; topNav.forEach((n) => { if (groupOfActive(n)) o[n.id] = true; }); return o; }); React.useEffect(() => { // افتح المجموعة تلقائيًا عند تفعيل أحد عناصرها topNav.forEach((n) => { if (groupOfActive(n)) setOpenGroups((s) => ({ ...s, [n.id]: true })); }); }, [active]); // eslint-disable-line const roleName = (user && (D.roles.find((r) => r.id === user.role) || {}).name) || ""; const initials = (user ? user.name : "").split(/[\s—-]+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join(""); const wrap = { width: "var(--rail-width)", flex: "none", background: "var(--bg-rail)", color: "#fff", display: "flex", flexDirection: "column", padding: "var(--space-6) var(--space-5)", gap: "var(--space-2)", }; const item = (on) => ({ display: "flex", alignItems: "center", gap: "var(--space-4)", padding: "var(--space-4) var(--space-5)", borderRadius: "var(--radius-md)", color: on ? "#fff" : "rgba(255,255,255,0.62)", background: on ? "rgba(255,255,255,0.10)" : "transparent", fontSize: "var(--text-sm)", fontWeight: on ? 600 : 500, cursor: "pointer", transition: "var(--transition-control)", borderInlineStart: on ? "3px solid var(--amber-500)" : "3px solid transparent", }); return (
بُنيان نظام محاسبي متكامل
{topNav.map((n) => { const Icon = I[n.icon]; if (!n.children) { return (
onNav(n.id)}> {n.labelLong}
); } const open = !!openGroups[n.id]; const hasActive = groupOfActive(n); return (
setOpenGroups((s) => ({ ...s, [n.id]: !s[n.id] }))} role="button" aria-expanded={open}> {n.labelLong}
{open && n.children.map((c) => { const CIcon = I[c.icon]; return (
onNav(c.id)}> {c.labelLong}
); })}
); })}
تمت المزامنة · متصل
{initials || "؟"}
{user ? user.name : ""}
{roleName}
); } window.Rail = Rail; /* Bonyan ERP — mobile side drawer (fires from the ☰ button, slides from the right in RTL) */ function MobileDrawer({ open, active, onNav, user, onLogout, onClose }) { const I = window.BnyIcon; const D = window.BnyData; // نفس بنية Rail: عناصر مسموحة + مجموعات فيها عنصر مسموح const topNav = BNY_NAV.map((n) => { if (!n.children) return window.BnyCan(user, n.perm) ? n : null; const kids = n.children.filter((c) => window.BnyCan(user, c.perm)); return kids.length ? { ...n, children: kids } : null; }).filter(Boolean); const groupOfActive = (n) => n.children && n.children.some((c) => c.id === active); const [openGroups, setOpenGroups] = React.useState({}); React.useEffect(() => { if (open) { const o = {}; topNav.forEach((n) => { if (groupOfActive(n)) o[n.id] = true; }); setOpenGroups(o); } }, [open, active]); // eslint-disable-line // امنع تمرير الخلفية أثناء فتح الدرج React.useEffect(() => { if (!open) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = prev; }; }, [open]); const roleName = (user && (D.roles.find((r) => r.id === user.role) || {}).name) || ""; const initials = (user ? user.name : "").split(/[\s—-]+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join(""); const go = (id) => { onNav(id); onClose(); }; const item = (on) => ({ display: "flex", alignItems: "center", gap: 14, width: "100%", boxSizing: "border-box", padding: "13px 16px", borderRadius: "var(--radius-md)", border: 0, textAlign: "start", color: on ? "#fff" : "rgba(255,255,255,0.66)", background: on ? "rgba(255,255,255,0.10)" : "transparent", fontSize: 15, fontWeight: on ? 600 : 500, cursor: "pointer", fontFamily: "var(--font-body)", borderInlineStart: on ? "3px solid var(--amber-500)" : "3px solid transparent", }); return (
{/* الخلفية المعتّمة */}
{/* اللوحة المنزلقة من اليمين */}
{/* الرأس: الشعار + إغلاق */}
بُنيان نظام محاسبي متكامل
{/* الأقسام (قابلة للطي) */}
{topNav.map((n) => { const Icon = I[n.icon]; if (!n.children) { return ( ); } const isOpen = !!openGroups[n.id]; const hasActive = groupOfActive(n); return (
{isOpen && n.children.map((c) => { const CIcon = I[c.icon]; return ( ); })}
); })}
{/* التذييل: المستخدم + خروج */}
{initials || "؟"}
{user ? user.name : ""}
{roleName}
); } window.MobileDrawer = MobileDrawer; /* توافق خلفي: MobileNav لم يعد يُعرض (استُبدل بالدرج الجانبي) */ window.MobileNav = function () { return null; };