/* Otmix Dashboard — admin overview */ const { useState, useEffect, useMemo, useRef } = React; const I = ({ d, s = 16, sw = 1.8 }) => ( {d} ); const ic = { home: }/>, bot: }/>, ops: }/>, users: }/>, reports: }/>, card: }/>, plug: }/>, cog: }/>, search: }/>, bell: }/>, bolt: }/>, chev: }/>, chevR: }/>, arrow: }/>, arrowL: }/>, plus: }/>, filter: }/>, download: }/>, more: }/>, eye: }/>, edit: }/>, sun: }/>, spark: }/>, alert: }/>, cash: }/>, flame: }/>, }; const AGENTS = [ { code:"P1", name:"الذمم الدائنة", icon:"AP", status:"live", kpi:"١٬٢٤٧", unit:"فاتورة هذا الأسبوع", spark:[8,11,9,14,12,18,17] }, { code:"P2", name:"الطلبات", icon:"OR", status:"live", kpi:"٤٢٣", unit:"طلب اليوم", spark:[10,12,15,11,18,22,28] }, { code:"P3", name:"السمعة", icon:"RP", status:"live", kpi:"٨٩", unit:"تقييم تم الرد", spark:[5,8,6,9,7,11,10] }, { code:"P4", name:"المطابقة", icon:"RC", status:"warn", kpi:"٣ استثناءات", unit:"تحتاج مراجعة", spark:[14,12,15,11,9,7,3] }, { code:"P5", name:"الرواتب", icon:"PR", status:"idle", kpi:"٢٤٨", unit:"موظف · جاهز", spark:[6,6,6,6,6,6,6] }, { code:"P6", name:"التوظيف", icon:"TL", status:"live", kpi:"٥٧", unit:"سيرة فُرزت", spark:[3,5,8,7,11,9,13] }, { code:"P7", name:"العقود", icon:"CT", status:"live", kpi:"١٢", unit:"عقد قيد المراجعة", spark:[4,6,5,7,8,10,9] }, { code:"P8", name:"التسويق", icon:"MK", status:"live", kpi:"٣٤", unit:"محتوى نُشر", spark:[7,9,11,10,13,15,14] }, { code:"P9", name:"المعرفة", icon:"KN", status:"live", kpi:"٢٬٨٤٠", unit:"محادثة هذا الأسبوع", spark:[18,22,19,25,28,32,30] }, ]; const KPIS = [ { lbl:"الفواتير المعالجة", v:"١٢٬٨٤٧", delta:"+12.4%", unit:"", spark:[12,15,14,18,17,22,21,26,28,30,29,34], dn:false }, { lbl:"الوكلاء النشطون", v:"٨", small:"/٩", delta:"+1", unit:"", spark:[7,7,7,8,8,8,8,8,8,8,8,8], dn:false }, { lbl:"التوفير الشهري", v:"٤٨٬٢٩٠", small:"ر.س", delta:"+18%", spark:[20,22,25,24,28,30,33,35,38,42,45,48], dn:false }, { lbl:"متوسط زمن المعالجة", v:"٨", small:"دقائق", delta:"-22%", spark:[18,17,15,14,13,12,11,10,9,9,8,8], dn:true }, ]; const ACTIVITY = [ { id:"#OPS-48291", type:"فاتورة", agent:"P1 · الذمم", agentColor:"AP", amt:"٤٬٨٢٠ ر.س", status:"معالج", sk:"ok", time:"قبل ٢ د" }, { id:"#ORD-12847", type:"طلب", agent:"P2 · الطلبات", agentColor:"OR", amt:"١٥٦ ر.س", status:"معالج", sk:"ok", time:"قبل ٤ د" }, { id:"#REC-00428", type:"مطابقة", agent:"P4 · المطابقة", agentColor:"RC", amt:"٢٤٬٣٤٠ ر.س", status:"استثناء", sk:"exc", time:"قبل ٧ د" }, { id:"#KNW-92041", type:"محادثة", agent:"P9 · المعرفة", agentColor:"KN", amt:"—", status:"معالج", sk:"ok", time:"قبل ١١ د" }, { id:"#OPS-48289", type:"فاتورة", agent:"P1 · الذمم", agentColor:"AP", amt:"٢٬١٤٠ ر.س", status:"قيد المراجعة", sk:"rev", time:"قبل ١٤ د" }, { id:"#TLT-04812", type:"سيرة ذاتية", agent:"P6 · التوظيف", agentColor:"TL", amt:"—", status:"معالج", sk:"ok", time:"قبل ١٨ د" }, { id:"#REP-22841", type:"تقييم", agent:"P3 · السمعة", agentColor:"RP", amt:"⭐ ٤", status:"معالج", sk:"ok", time:"قبل ٢٢ د" }, { id:"#CTR-01294", type:"عقد", agent:"P7 · العقود", agentColor:"CT", amt:"خطر متوسط", status:"قيد المراجعة", sk:"rev", time:"قبل ٢٧ د" }, ]; const INSIGHTS = [ { kind:"g", ico:ic.flame, ev:<>وكيل الفواتير اكتشف ١٢ فاتورة مكررة من Vendor X هذا الأسبوع. وفّر ٤٬٨٠٠ ر.س., time:"قبل ٤ د", tag:"ذمم دائنة", act:"مراجعة" }, { kind:"y", ico:ic.alert, ev:<>المطابقة البنكية سجّلت ٣ استثناءات في حساب الراجحي تحتاج موافقة يدوية., time:"قبل ١٢ د", tag:"مطابقة", act:"اعتماد" }, { kind:"g", ico:ic.cash, ev:<>الطلبات رفعت متوسط القيمة من ٤٢ ر.س إلى ٥٨ ر.س عبر بيع تكميلي تلقائي., time:"قبل ٢٥ د", tag:"طلبات", act:"عرض" }, { kind:"b", ico:ic.spark, ev:<>المعرفة أجاب على ٢٬٨٤٠ سؤال هذا الأسبوع · ٩٤٪ بثقة عالية بدون تصعيد., time:"قبل ساعة", tag:"معرفة", act:"عرض" }, { kind:"r", ico:ic.alert, ev:<>الرواتب · ٣ موظفين لم يكتمل تسجيلهم في GOSI قبل تنفيذ راتب الشهر., time:"قبل ٢ س", tag:"رواتب", act:"إصلاح" }, ]; /* ---------- Sparkline (mini) ---------- */ function Spark({ data, color = "currentColor", h = 30, fill = false }) { const w = 100; const max = Math.max(...data); const min = Math.min(...data); const range = Math.max(1, max - min); const pts = data.map((v, i) => [(i/(data.length-1))*w, h - ((v-min)/range)*(h-4) - 2]); const d = pts.map((p,i) => (i===0?"M":"L") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" "); return ( {fill && } ); } /* ---------- Big Chart ---------- */ function BigChart({ tab }) { const datasets = { invoices: [180,210,260,240,310,340,380,360,420,440,490,520,540,580,610,640,670,690,710,750,780,810,800,860,890,920,940,970,1010,1050], orders: [80,95,110,140,160,180,210,240,260,280,310,340,360,390,420,460,490,510,540,580,610,640,680,720,760,800,830,870,910,950], payroll: [40,40,42,42,44,44,46,46,48,48,50,50,52,52,54,54,56,56,58,58,60,60,62,62,64,64,66,66,68,68], all: [300,360,400,440,500,560,600,640,720,780,850,910,980,1040,1110,1180,1250,1320,1390,1460,1540,1610,1690,1770,1860,1950,2030,2110,2200,2300], }; const data = datasets[tab] || datasets.invoices; const W = 800, H = 200, PL = 40, PR = 14, PT = 18, PB = 30; const max = Math.max(...data); const min = 0; const range = max - min; const ix = i => PL + (i/(data.length-1))*(W-PL-PR); const iy = v => PT + (1 - (v-min)/range)*(H-PT-PB); const pts = data.map((v,i) => [ix(i), iy(v)]); const d = pts.map((p,i) => (i===0?"M":"L") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" "); const fillD = d + ` L ${ix(data.length-1).toFixed(1)} ${(H-PB).toFixed(1)} L ${ix(0).toFixed(1)} ${(H-PB).toFixed(1)} Z`; const [hover, setHover] = useState(null); const onMove = (e) => { const rect = e.currentTarget.getBoundingClientRect(); const x = e.clientX - rect.left; const fx = (x / rect.width) * W; const idx = Math.round(((fx - PL) / (W - PL - PR)) * (data.length-1)); if (idx >= 0 && idx < data.length) setHover({ idx, v: data[idx], x: pts[idx][0], y: pts[idx][1] }); }; // y-axis ticks const ticks = [0, 0.25, 0.5, 0.75, 1].map(t => ({ y: PT + (1-t)*(H-PT-PB), v: Math.round(min + t*range) })); // x-axis ticks (every 5 days) const xTicks = [0,5,10,15,20,25,29].map(i => ({ x: ix(i), label: (i+1) })); return (
setHover(null)}> {ticks.map((t,i) => ( {t.v >= 1000 ? (t.v/1000).toFixed(1)+"k" : t.v} ))} {xTicks.map((t,i) => ( {t.label} ))} {hover && ( )} {hover && (
يوم {hover.idx+1}: {hover.v.toLocaleString("ar-EG")}
)}
); } /* ---------- Donut ---------- */ function Donut() { const data = [ { code:"P1", label:"الذمم", v:32, c:"#4bec42" }, { code:"P2", label:"الطلبات", v:24, c:"#080808" }, { code:"P9", label:"المعرفة", v:18, c:"#888" }, { code:"P3", label:"السمعة", v:8, c:"#bdbdb7" }, { code:"P6", label:"التوظيف", v:6, c:"#888" }, { code:"P4", label:"المطابقة", v:5, c:"#444" }, { code:"P8", label:"التسويق", v:4, c:"#aaa" }, { code:"P7", label:"العقود", v:2, c:"#666" }, { code:"P5", label:"الرواتب", v:1, c:"#ccc" }, ]; const total = data.reduce((a,b)=>a+b.v,0); const size = 160; const r = 64; const cx = size/2; const cy = size/2; const sw = 24; let acc = 0; const C = 2*Math.PI*r; return (
{data.map((d,i) => { const frac = d.v/total; const dash = frac*C; const offset = -acc*C; acc += frac; return ( ); })} ١٤٬٢١٠ عملية / ٧ أيام
{data.slice(0,6).map((d,i)=>(
{d.code} · {d.label} {d.v}٪
))}
); } /* ---------- Sidebar ---------- */ function Sidebar() { const [agentsOpen, setAgentsOpen] = useState(true); return ( ); } /* ---------- Topbar ---------- */ function Topbar({ openCmdK }) { return (
الرئيسية{ic.chevR}نظرة عامة
{ic.search} ⌘K
أ
); } /* ---------- Command Palette ---------- */ function CmdK({ open, onClose }) { const [q, setQ] = useState(""); useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose(); }; if (open) { window.addEventListener("keydown", onKey); setQ(""); } return () => window.removeEventListener("keydown", onKey); }, [open, onClose]); const items = [ { g:"الانتقال", items:[ { ico:ic.home, nm:"الرئيسية / نظرة عامة", kbd:"G H" }, { ico:ic.bot, nm:"أخصائي الحسابات الدائنة المؤتمت", kbd:"G P1" }, { ico:ic.bot, nm:"وكيل مبيعات الواتساب الذكي", kbd:"G P2" }, { ico:ic.ops, nm:"العمليات", kbd:"G O" }, { ico:ic.card, nm:"الفوترة والاشتراكات", kbd:"G B" }, ]}, { g:"إجراءات", items:[ { ico:ic.plus, nm:"تشغيل وكيل جديد", kbd:"⇧ N" }, { ico:ic.download, nm:"تصدير العمليات (CSV)" }, { ico:ic.spark, nm:"اطلب من Claude تحليلاً" }, ]}, ]; return (
e.stopPropagation()}>
{ic.search} setQ(e.target.value)}/> ESC
{items.map((g,gi)=>(
{g.g}
{g.items.filter(it=>!q||it.nm.includes(q)).map((it,i)=>(
{it.ico} {it.nm} {it.kbd && {it.kbd}}
))}
))}
); } /* ---------- Main ---------- */ function App() { const [tab, setTab] = useState("invoices"); const [cmdOpen, setCmdOpen] = useState(false); const [counts, setCounts] = useState(KPIS.map(() => 0)); useEffect(() => { const onKey = (e) => { if ((e.metaKey||e.ctrlKey) && e.key.toLowerCase()==="k") { e.preventDefault(); setCmdOpen(true); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []); return (
setCmdOpen(true)}/>
{/* Welcome */}

صباح الخير، أحمد 👋

💡 وكيل الفواتير اكتشف ١٢ فاتورة مكررة هذا الأسبوع — وفّر ٤٬٨٠٠ ر.س.
{/* KPI Row */}
{KPIS.map((k,i)=>(
{k.lbl}
{k.v}{k.small && {k.small}}
{k.dn?"▼":"▲"} {k.delta} مقارنة بالشهر السابق
))}
{/* Two-column row: chart + insights */}

العمليات عبر آخر ٣٠ يوماً

إجمالي ١٢٬٨٤٧ عملية · متوسط ٤٢٨/يوم
{[["invoices","الفواتير"],["orders","الطلبات"],["payroll","الرواتب"],["all","الكل"]].map(([k,l])=>( ))}
عمليات يومية منطقة التراكم تحديث منذ ٤٢ ث

رؤى من Claude

{INSIGHTS.map((it,i)=>(
{it.ico}
{it.ev}
{it.time}·{it.tag}
))}
{/* Donut + Agents */}

توزيع العمليات حسب الوكيل

آخر ٧ أيام

أداء الوكلاء

{AGENTS.slice(0,6).map(a => (
{a.icon}
{a.code} · {a.name}
{a.status==="live"?"نشط":a.status==="warn"?"تحذير":"خامل"}
{a.kpi}{a.unit}
زمن التشغيل ٩٩٫٩٪ ↗ {a.code==="P4"?"-12%":"+8%"}
))}
{/* Activity Table */}

آخر العمليات

تحديث لحظي · ٣٤٢ عملية اليوم
{ACTIVITY.map((r,i)=>( ))}
المعرّف النوع الوكيل القيمة الحالة الوقت
{r.id} {r.type}
{r.agentColor}
{r.agent}
{r.amt} {r.status} {r.time}
عرض ١-٨ من ٣٤٢
setCmdOpen(false)}/>
); } ReactDOM.createRoot(document.getElementById("root")).render();