// admin.jsx — admin panel: products CRUD, orders, stats, customers function AdminLayout({ route, setRoute, lang, children }) { const t = (ar, en) => lang === 'ar' ? ar : en; const items = [ { id: 'admin-products', label: t('المنتجات', 'Products'), icon: }, { id: 'admin-orders', label: t('الطلبات', 'Orders'), icon: }, { id: 'admin-stats', label: t('الإحصائيات', 'Analytics'), icon: }, { id: 'admin-customers', label: t('العملاء', 'Customers'), icon: }, { id: 'admin-settings', label: t('الإعدادات', 'Settings'), icon: }, ]; return (
{children}
); } // ── Products ─────────────────────────────────────────────── function AdminProducts({ lang }) { const t = (ar, en) => lang === 'ar' ? ar : en; const [products, setProducts] = React.useState(PRODUCTS); const [q, setQ] = React.useState(''); const [familyFilter, setFamilyFilter] = React.useState('all'); const [edit, setEdit] = React.useState(null); // product being edited (modal) const [creating, setCreating] = React.useState(false); const filtered = products.filter(p => { if (familyFilter !== 'all' && p.family !== familyFilter) return false; if (q && !p.name_ar.includes(q) && !p.name_en.toLowerCase().includes(q.toLowerCase())) return false; return true; }); const save = (p) => { if (creating) { setProducts([{ ...p, id: 'p' + String(products.length + 1).padStart(2, '0') }, ...products]); } else { setProducts(products.map(x => x.id === p.id ? p : x)); } setEdit(null); setCreating(false); }; const del = (id) => { if (!confirm(t('حذف المنتج؟', 'Delete this product?'))) return; setProducts(products.filter(p => p.id !== id)); }; return ( <>
{t('الإدارة · 01', 'Manage · 01')}

{t('المنتجات', 'Products')}

{products.length} {t('منتج', 'products')} · {products.filter(p => p.stock < 10).length} {t('مخزون منخفض', 'low stock')}
setQ(e.target.value)} />
{filtered.map(p => { const fam = SCENT_FAMILIES.find(f => f.id === p.family); const stockClass = p.stock < 8 ? 'crit' : p.stock < 15 ? 'low' : ''; return ( ); })}
{t('المنتج', 'Product')} {t('العائلة', 'Family')} {t('التركيز', 'Concentration')} {t('المخزون', 'Stock')} {t('السعر', 'Price')} {t('التقييم', 'Rating')}
N°{p.id.slice(1)}
{p.name_ar}
{p.name_en}
{lang === 'ar' ? fam.ar : fam.en} {p.concentration}
{p.stock}
{p.price} AED {p.rating}
{edit && { setEdit(null); setCreating(false); }} lang={lang} creating={creating} />} ); } function ProductEditor({ product, onSave, onClose, lang, creating }) { const t = (ar, en) => lang === 'ar' ? ar : en; const [p, setP] = React.useState(product); const upd = (k, v) => setP({ ...p, [k]: v }); const updSize = (i, k, v) => { const sizes = [...p.sizes]; sizes[i] = { ...sizes[i], [k]: Number(v) }; setP({ ...p, sizes }); }; return (
e.stopPropagation()}>
{t('معاينة', 'Preview')}
ISTABRAQ
{p.name_en || 'NAME'}
{SCENT_FAMILIES.map(f => (
{creating ? t('منتج جديد', 'New product') : t('تعديل منتج', 'Edit product')}

{p.name_ar || t('بلا اسم', 'Untitled')}

upd('name_ar', e.target.value)} />
upd('name_en', e.target.value)} />
upd('origin', e.target.value)} placeholder="e.g. Mysore" />
upd('year', +e.target.value)} />
upd('top_ar', e.target.value)} />
upd('heart_ar', e.target.value)} />
upd('base_ar', e.target.value)} />
upd('price', +e.target.value)} />
upd('stock', +e.target.value)} />
{t('الأحجام والأسعار', 'Sizes & prices')}
{p.sizes.map((s, i) => (
updSize(i, 'price', e.target.value)} style={{ fontSize: 18, fontFamily: 'var(--f-en-head)', fontStyle: 'italic' }} />
))}
); } // ── Orders ───────────────────────────────────────────────── function AdminOrders({ lang }) { const t = (ar, en) => lang === 'ar' ? ar : en; const [orders, setOrders] = React.useState(ORDERS); const [statusFilter, setStatusFilter] = React.useState('all'); const filtered = orders.filter(o => statusFilter === 'all' || o.status === statusFilter); const setStatus = (id, status) => setOrders(orders.map(o => o.id === id ? { ...o, status } : o)); const tabs = [ { id: 'all', label: t('الكل', 'All'), count: orders.length }, { id: 'pending', label: t('قيد الانتظار', 'Pending'), count: orders.filter(o => o.status === 'pending').length }, { id: 'shipped', label: t('تم الشحن', 'Shipped'), count: orders.filter(o => o.status === 'shipped').length }, { id: 'delivered', label: t('تم التسليم', 'Delivered'), count: orders.filter(o => o.status === 'delivered').length }, { id: 'cancelled', label: t('ملغية', 'Cancelled'), count: orders.filter(o => o.status === 'cancelled').length }, ]; const statusLabel = (s) => ({ pending: t('قيد الانتظار', 'Pending'), shipped: t('تم الشحن', 'Shipped'), delivered: t('تم التسليم', 'Delivered'), cancelled: t('ملغية', 'Cancelled'), })[s]; return ( <>
{t('الإدارة · 02', 'Manage · 02')}

{t('الطلبات', 'Orders')}

{orders.length} {t('طلب · 18,420 AED مبيعات هذا الأسبوع', 'orders · AED 18,420 this week')}
{tabs.map(tab => ( ))}
{filtered.map(o => ( ))}
{t('رقم الطلب', 'Order')} {t('العميل', 'Customer')} {t('المدينة', 'City')} {t('التاريخ', 'Date')} {t('العناصر', 'Items')} {t('المجموع', 'Total')} {t('الحالة', 'Status')}
{o.id}
{o.customer}
{o.email}
{o.city} {o.date} {o.items} AED {o.total.toLocaleString()}
); } // ── Stats ────────────────────────────────────────────────── function AdminStats({ lang }) { const t = (ar, en) => lang === 'ar' ? ar : en; const max = Math.max(...REVENUE_SERIES); const totalRev = REVENUE_SERIES.reduce((a, b) => a + b, 0); const peakIdx = REVENUE_SERIES.indexOf(max); const cards = [ { lbl: t('الإيرادات (14 يوم)', 'Revenue · 14d'), val: `AED ${(totalRev / 1000).toFixed(1)}K`, delta: '+12.4%', up: true }, { lbl: t('الطلبات', 'Orders'), val: '142', delta: '+8.1%', up: true }, { lbl: t('متوسط قيمة الطلب', 'Avg order value'), val: 'AED 612', delta: '+4.2%', up: true }, { lbl: t('معدل التحويل', 'Conversion'), val: '3.8%', delta: '−0.4%', up: false }, ]; // donut const total = FAMILY_SPLIT.reduce((s, x) => s + x.pct, 0); let acc = 0; const r = 70, circ = 2 * Math.PI * r; return ( <>
{t('الإدارة · 03', 'Manage · 03')}

{t('الإحصائيات', 'Analytics')}

{t('آخر ١٤ يوماً', 'Last 14 days')}
{cards.map((c, i) => (
{c.lbl}
{c.val}
{c.up ? : } {c.delta} {t('vs الأسبوع السابق', 'vs last period')}
))}

{t('الإيرادات اليومية · AED', 'Daily revenue · AED')}

peak: {max.toLocaleString()} AED
{REVENUE_SERIES.map((v, i) => (
))}
May 5May 12May 18

{t('المبيعات حسب العائلة', 'Sales by family')}

{FAMILY_SPLIT.map((s, i) => { const fam = SCENT_FAMILIES.find(f => f.id === s.id); const len = (s.pct / total) * circ; const seg = ( ); acc += len + 2; // 2px gap return seg; })}
100%
{t('المبيعات', 'sales')}
{FAMILY_SPLIT.map(s => { const fam = SCENT_FAMILIES.find(f => f.id === s.id); return (
{lang === 'ar' ? fam.ar : fam.en} {s.pct}%
); })}
{/* top products */}

{t('الأكثر مبيعاً هذا الأسبوع', 'Top products this week')}

{[0, 10, 4, 8, 18].map((i, j) => { const p = PRODUCTS[i]; const units = [42, 38, 31, 27, 24][j]; return ( ); })}
{t('المنتج', 'Product')} {t('وحدات مباعة', 'Units sold')} {t('الإيرادات', 'Revenue')} {t('المخزون المتبقي', 'Stock left')}
{lang === 'ar' ? p.name_ar : p.name_en}
{lang === 'ar' ? p.name_en : p.name_ar}
{units} AED {(units * p.price).toLocaleString()}
{p.stock}
); } // ── Customers ────────────────────────────────────────────── function AdminCustomers({ lang }) { const t = (ar, en) => lang === 'ar' ? ar : en; return ( <>
{t('الإدارة · 04', 'Manage · 04')}

{t('العملاء', 'Customers')}

{CUSTOMERS.length} {t('عميل · 3 VIP', 'customers · 3 VIP')}
{CUSTOMERS.map(c => ( ))}
{t('الاسم', 'Name')} {t('البريد', 'Email')} {t('الطلبات', 'Orders')} {t('الإنفاق', 'Spent')} {t('المستوى', 'Tier')}
{c.name[0]}
{c.name}
{c.email} {c.orders} AED {c.spent.toLocaleString()} {c.tier}
); } function AdminSettings({ lang }) { const t = (ar, en) => lang === 'ar' ? ar : en; return ( <>
{t('الإدارة · 05', 'Manage · 05')}

{t('الإعدادات', 'Settings')}

{t('بيانات المتجر وبوابات الدفع', 'Store data & payment gateways')}

{t('بيانات المتجر', 'Store info')}

{t('بوابات الدفع', 'Payment gateways')}

{[ ['Stripe', t('متصل', 'Connected'), true], ['Apple Pay', t('متصل', 'Connected'), true], ['Mada', t('متصل', 'Connected'), true], ['PayPal', t('غير متصل', 'Not connected'), false], ].map(([name, status, on]) => (
{name}
{status}
))}
); } window.AdminLayout = AdminLayout; window.AdminProducts = AdminProducts; window.AdminOrders = AdminOrders; window.AdminStats = AdminStats; window.AdminCustomers = AdminCustomers; window.AdminSettings = AdminSettings;