// 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 ? (
) : (
)}
);
}
/* ----------------------------- 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 (
);
}
Object.assign(window, { SALogin, SAOverview, fmtTRY, fmtK });