// aerOS Superadmin — Plans & Billing const { useState: _bS } = React; function SABilling({ t, orgs }) { const toast = useToast(); const D = window.SA_DATA; const [plans, setPlans] = _bS(D.PLANS); const [edit, setEdit] = _bS(null); const totalSubs = orgs.filter(o => o.is_active).length; const mrr = orgs.filter(o => o.is_active).reduce((s, o) => { const p = plans.find(p => p.tier === o.plan_tier); return s + (p ? p.price : 0); }, 0); const savePlan = async () => { try { await window.SA_API.updatePlan(edit); const fresh = await window.SA_API.listPlans(); // re-pull persisted plans if (Array.isArray(fresh) && fresh.length) { setPlans(fresh); window.SA_DATA.PLANS = fresh; } else setPlans(ps => ps.map(p => p.tier === edit.tier ? edit : p)); toast.ok(`${edit.name}`, t.planChanged); setEdit(null); } catch (e) { toast.error(e.message || 'Hata'); } }; return (
{t.planDefs}
{plans.map(p => { const subCount = orgs.filter(o => o.plan_tier === p.tier).length; return (
{p.popular &&
{t.mostPopular}
}
{p.name}
{p.price ? <>{fmtTRY(p.price)}{t.perMonth} : Özel fiyat}
= 9999 ? '∞' : p.maxRooms} icon={Icon.bed} /> = 9999 ? '∞' : p.maxProducts} icon={Icon.utensils} />
{p.features.map((ft, i) => (
{Icon.check({ size: 14 })}{ft}
))}
{subCount} {t.subscribers.toLowerCase()}
); })}
{o.name}
}, { key: 'plan_tier', label: t.plan, sortable: true, render: o => planBadge(o.plan_tier) }, { key: 'price', label: t.price, align: 'right', sortable: true, sortValue: o => { const p = plans.find(p => p.tier === o.plan_tier); return p ? p.price : 0; }, render: o => { const p = plans.find(p => p.tier === o.plan_tier); return {p && p.price ? fmtTRY(p.price) + '/ay' : 'Özel'}; } }, { 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, align: 'right', sortable: true, render: o => {o.created_at} }, ]} rows={orgs} searchKeys={['name', 'slug']} searchPlaceholder={t.searchOrg} pageSize={6} filters={[{ key: 'plan_tier', label: t.plan, options: [{ value: '', label: t.all + ' · ' + t.plan }, ...plans.map(p => ({ value: p.tier, label: p.name }))] }]} />
setEdit(null)} title={t.editPlan} subtitle={edit?.name} icon={Icon.layers} width={460} footer={<>}> {edit && ( setEdit(e => ({ ...e, name: v }))} /> setEdit(e => ({ ...e, maxRooms: +v }))} suffix={t.rooms.toLowerCase()} /> setEdit(e => ({ ...e, maxProducts: +v }))} suffix={t.products.toLowerCase()} /> setEdit(e => ({ ...e, price: +v }))} prefix="€" suffix={t.perMonth} /> )}
); } function LimitChip({ label, value, icon }) { return (
{icon({ size: 12 })}{label} {value}
); } Object.assign(window, { SABilling });