// aerOS Superadmin — Login gate + Overview screen const { useState: _saS, useMemo: _saM } = React; function fmtTRY(n) { return '€' + Number(n || 0).toLocaleString('de-DE'); } // planning figures in EUR function fmtK(n) { return n >= 1000 ? (n / 1000).toFixed(n % 1000 === 0 ? 0 : 1) + 'B' : String(n); } /* ----------------------------- Login ----------------------------- */ function SALogin({ t, ui, onAuth }) { const [email, setEmail] = _saS(''); const [pass, setPass] = _saS(''); const [loading, setLoading] = _saS(false); const [err, setErr] = _saS(''); const [tfa, setTfa] = _saS(null); const [code, setCode] = _saS(''); // 2FA (TOTP) const submit = async (e) => { e && e.preventDefault(); if (!email || !pass) return; setLoading(true); setErr(''); try { const d = await window.SA_API.login(email, pass); if (d && d.two_factor) { setTfa(d); setLoading(false); return; } onAuth(); } catch (ex) { setErr(ex.message === 'not_superadmin' ? (t.notSuperadmin || 'Bu hesap platform yöneticisi değil.') : (t.loginFailed || 'Giriş başarısız. Bilgileri kontrol edin.')); setLoading(false); } }; const submitCode = async (e) => { e && e.preventDefault(); if ((code || '').trim().length < 6) return; setLoading(true); setErr(''); try { await window.SA_API.twoFactorVerify(tfa.challenge, code.trim()); onAuth(); } catch (ex) { setErr(ex.message === 'not_superadmin' ? (t.notSuperadmin || 'Bu hesap platform yöneticisi değil.') : 'Kod hatalı veya süresi doldu.'); setLoading(false); } }; return (
{Icon.layers({ size: 26 })}

{t.appName} · {t.loginTitle}

{t.loginSub}

{tfa ? (
{tfa.two_factor === 'setup' ? 'Google Authenticator ile QR kodu tarayın, sonra 6 haneli kodu girin.' : 'Google Authenticator uygulamasındaki 6 haneli kodu girin.'}
{tfa.two_factor === 'setup' && tfa.qr_png &&
QR
} {err &&
{err}
}
) : (
{err &&
{err}
}
{t.loginHint}
)}
); } /* ----------------------------- Overview ----------------------------- */ function SAOverview({ t, orgs, loading }) { const [range, setRange] = _saS('12m'); const D = window.SA_DATA; const stats = _saM(() => { const total = orgs.length; const active = orgs.filter(o => o.is_active).length; const orders = orgs.reduce((s, o) => s + o.monthly_orders, 0); const rev = orgs.reduce((s, o) => s + o.monthly_revenue, 0); const mrr = orgs.filter(o => o.is_active).reduce((s, o) => { const p = D.PLANS.find(p => p.tier === o.plan_tier); return s + (p ? p.price : 0); }, 0); return { total, active, suspended: total - active, orders, rev, mrr }; }, [orgs]); const planDist = _saM(() => D.PLANS.map((p, i) => ({ label: p.name, value: orgs.filter(o => o.plan_tier === p.tier).length, color: ['#94a3b8', 'var(--brand)', '#0d9488', '#7c3aed'][i] })).filter(d => d.value > 0), [orgs]); const vertDist = _saM(() => [ { label: t.hotel, value: orgs.filter(o => o.vertical === 'hotel').length, color: '#2563eb' }, { label: t.restaurant, value: orgs.filter(o => o.vertical === 'restaurant').length, color: '#d97706' }, { label: t.hospital, value: orgs.filter(o => o.vertical === 'hospital').length, color: '#0d9488' }, ].filter(d => d.value > 0), [orgs]); if (loading) return ; // No mock history: series reflect real current values (flat) until the // platform tracks time-series metrics. const sRev = Array(12).fill((stats.mrr || 0) / 1000); const sOrgs = Array(12).fill(stats.total || 0); return (
}> {range === '12m' ? fmtTRY(v * 1000)} /> : i % 5 === 0 ? (i + 1) : '')} height={240} valueFmt={v => fmtK(v)} />}
({ label: v.label, value: v.value, color: v.color }))} />
{[...orgs].sort((a, b) => (b.created_at || '').localeCompare(a.created_at || '')).slice(0, 8).map((o, i, arr) => (
{o.name}
{o.slug}{o.city ? ' · ' + o.city : ''}
{t[o.vertical]} {o.is_active ? t.active : t.suspended} {o.created_at}
))}
); } function Legend({ color, label, value }) { return (
{label} {value}
); } function OverviewSkeleton() { return (
{[0, 1, 2].map(i =>
)}
); } Object.assign(window, { SALogin, SAOverview, fmtTRY, fmtK });