// aerOS Superadmin — Organizations: list, create wizard, detail, actions, impersonate
const { useState: _oS } = React;
function vBadge(t, v) { return {t[v]}; }
function planBadge(tier) {
const map = { starter: 'neutral', basic: 'neutral', growth: 'brand', pro: 'brand', scale: 'info', enterprise: 'ok' };
// Real plan name from the hydrated plan list; fallback to a capitalised slug.
const plan = ((window.SA_DATA && window.SA_DATA.PLANS) || []).find(p => p.tier === tier);
const label = (plan && plan.name) || (tier ? tier.charAt(0).toUpperCase() + tier.slice(1) : '—');
return {label};
}
function _lim(v) { return (v === -1 || v >= 9999) ? '∞' : v; }
/* ----------------------------- Org list ----------------------------- */
function SAOrgs({ t, orgs, setOrgs, onImpersonate, onCreate }) {
const toast = useToast();
const D = window.SA_DATA;
const [detail, setDetail] = _oS(null);
const [confirm, setConfirm] = _oS(null);
const [menuFor, setMenuFor] = _oS(null);
const doSuspendToggle = async (org) => {
const next = !org.is_active;
try {
next ? await window.SA_API.activate(org.id) : await window.SA_API.suspend(org.id);
setOrgs(os => os.map(o => o.id === org.id ? { ...o, is_active: next } : o));
toast.ok(`${org.name} ${next ? t.active.toLowerCase() : t.suspended.toLowerCase()}.`, t.statusChanged);
} catch (e) { toast.error(e.message || 'Hata', t.statusChanged); }
};
const doChangePlan = async (org, tier) => {
const p = D.PLANS.find(p => p.tier === tier);
try {
await window.SA_API.changePlan(org.id, tier);
setOrgs(os => os.map(o => o.id === org.id ? { ...o, plan_tier: tier, rooms_max: p ? p.maxRooms : o.rooms_max, products_max: p ? p.maxProducts : o.products_max } : o));
toast.ok(`${org.name} → ${p ? p.name : tier}`, t.planChanged);
setDetail(d => d && d.id === org.id ? { ...d, plan_tier: tier, rooms_max: p ? p.maxRooms : d.rooms_max, products_max: p ? p.maxProducts : d.products_max } : d);
} catch (e) { toast.error(e.message || 'Hata', t.planChanged); }
};
const columns = [
{ key: 'name', label: t.name, sortable: true, render: o => (
) },
{ key: 'vertical', label: t.vertical, sortable: true, render: o => vBadge(t, o.vertical) },
{ key: 'plan_tier', label: t.plan, sortable: true, render: o => planBadge(o.plan_tier) },
{ key: 'usage', label: t.usage, render: o => (
{o.rooms_used}/{_lim(o.rooms_max)} {t.rooms.toLowerCase()}
) },
{ key: 'monthly_orders', label: t.monthlyOrders, align: 'right', sortable: true, render: o => {o.monthly_orders.toLocaleString('tr-TR')} },
{ key: 'is_active', label: t.status, sortable: true, sortValue: o => o.is_active ? 1 : 0, render: o => {o.is_active ? t.active : t.suspended} },
{ key: 'created_at', label: t.created, sortable: true, align: 'right', render: o => {o.created_at} },
{ key: 'act', label: '', align: 'right', render: o => (
{ e.stopPropagation(); setMenuFor(menuFor === o.id ? null : o.id); }} active={menuFor === o.id} />
{menuFor === o.id && (
<>
{ e.stopPropagation(); setMenuFor(null); }} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
e.stopPropagation()} style={{ position: 'absolute', right: 0, top: 38, zIndex: 51, background: 'var(--bg-0)', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)', boxShadow: 'var(--shadow-lg)', padding: 5, minWidth: 184, textAlign: 'left' }}>
>
)}
) },
];
return (
setDetail(o)}
filters={[
{ key: 'vertical', label: t.vertical, options: [{ value: '', label: t.all + ' · ' + t.vertical }, { value: 'hotel', label: t.hotel }, { value: 'restaurant', label: t.restaurant }, { value: 'hospital', label: t.hospital }] },
{ key: 'plan_tier', label: t.plan, options: [{ value: '', label: t.all + ' · ' + t.plan }, ...D.PLANS.map(p => ({ value: p.tier, label: p.name }))] },
{ key: 'is_active', label: t.status, options: [{ value: '', label: t.all + ' · ' + t.status }, { value: 'true', label: t.active }, { value: 'false', label: t.suspended }] },
]}
rightTools={}
initialSort={{ key: 'created_at', dir: 'desc' }}
/>
setDetail(null)} onChangePlan={doChangePlan} onToggle={(o) => setConfirm({ org: o, type: o.is_active ? 'suspend' : 'activate' })} onImpersonate={onImpersonate} />
setConfirm(null)}
onConfirm={() => doSuspendToggle(confirm.org)}
tone={confirm?.type === 'suspend' ? 'danger' : 'ok'}
title={confirm?.type === 'suspend' ? t.suspendConfirm : t.activateConfirm}
message={<>{confirm?.org.name} {confirm?.type === 'suspend' ? t.suspendMsg : t.activateMsg}>}
confirmLabel={confirm?.type === 'suspend' ? t.suspend : t.activate} cancelLabel={t.cancel} />
);
}
function MenuItem({ icon, label, onClick, tone }) {
const [h, setH] = _oS(false);
return (
);
}
/* ----------------------------- Org detail sheet ----------------------------- */
function OrgDetailSheet({ t, org, onClose, onChangePlan, onToggle, onImpersonate }) {
const D = window.SA_DATA;
if (!org) return null;
return (
>}>
{vBadge(t, org.vertical)}{planBadge(org.plan_tier)}{org.is_active ? t.active : t.suspended}
{t.created}: {org.created_at}
{t.changePlan}
{t.ordersTrend} · {t.last12}
v} color="var(--brand)" />
);
}
function MiniStat({ label, value }) {
return (
);
}
function SecLabel({ children }) { return {children}
; }
/* ----------------------------- Create wizard ----------------------------- */
function SACreateOrg({ t, open, onClose, onCreated }) {
const toast = useToast();
const D = window.SA_DATA;
const [step, setStep] = _oS(0);
const blank = { name: '', slug: '', vertical: 'hotel', plan: 'pro', currency: '₺', lang: 'tr', color: '#6E9F2A', adminLogin: '', adminMail: '', adminPass: '' };
const [f, setF] = _oS(blank);
const set = (k, v) => setF(s => ({ ...s, [k]: v }));
const autoSlug = (name) => name.toLowerCase().replace(/ı/g, 'i').replace(/ş/g, 's').replace(/ğ/g, 'g').replace(/ü/g, 'u').replace(/ö/g, 'o').replace(/ç/g, 'c').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
const steps = [t.step_org, t.step_brand, t.step_admin];
const canNext = step === 0 ? f.name && f.slug : step === 1 ? true : f.adminLogin && f.adminMail && f.adminPass;
const reset = () => { setStep(0); setF(blank); };
const submit = () => {
onCreated(f);
toast.ok(`${f.name} ${t.orgCreatedMsg}`, t.orgCreated);
reset(); onClose();
};
const colors = ['#6E9F2A', '#2563eb', '#0d9488', '#b45309', '#7c3aed', '#be123c', '#0891b2', '#334155'];
return (
{ onClose(); }} title={t.createTitle} subtitle={t.createSub} icon={Icon.building} width={620}
footer={<>
{step > 0 && }
{step < 2
?
: }
>}>
{/* stepper */}
{steps.map((s, i) => (
{i < step ? Icon.check({ size: 14 }) : i + 1}
{s}
{i < 2 && }
))}
{step === 0 && (
{ set('name', v); if (!f._slugTouched) { const s = autoSlug(v); set('slug', s); if (!f._adminTouched) { set('adminLogin', s ? s + '-admin' : ''); set('adminMail', s ? 'admin@' + s + '.com' : ''); } } }} placeholder="Radisson Collection Vadistanbul" />
{ const s = autoSlug(v); set('slug', s); set('_slugTouched', true); if (!f._adminTouched) { set('adminLogin', s ? s + '-admin' : ''); set('adminMail', s ? 'admin@' + s + '.com' : ''); } }} suffix=".qrmenu.boranyazilim.com" />
)}
{step === 1 && (
{colors.map(c => (
{/* live brand preview */}
Önizleme
{(f.name || 'A')[0]}
{f.name || t.orgName}
Sipariş ver
Menü
)}
{step === 2 && (
)}
);
}
Object.assign(window, { SAOrgs, SACreateOrg });