// =======================================================================
// MariusVPN Franchise — App shell (auth, sidebar, router).
// =======================================================================
const { frApi } = window.FR_API;
function FrShell() {
const [me, setMe] = React.useState(null);
const [booted, setBooted] = React.useState(false);
const [tab, setTab] = React.useState('dashboard');
React.useEffect(() => {
(async () => {
// Telegram Mini App: if opened inside Telegram, auth via initData.
const tg = window.Telegram && window.Telegram.WebApp;
if (tg) { try { tg.ready(); tg.expand(); } catch (e) {} }
if (tg && tg.initData) {
try {
await fetch('/api/tg/franchise-auth', {
method: 'POST', credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ init_data: tg.initData }),
});
} catch (e) {}
}
try { setMe(await frApi('/whoami')); } catch (e) {}
setBooted(true);
})();
}, []);
if (!booted) return
;
if (!me) return setMe(m)}/>;
return setMe(null)} tab={tab} setTab={setTab}/>;
}
const NAV = [
{ id: 'dashboard', label: 'Дашборд', icon: ICONS.dashboard },
{ id: 'users', label: 'Пользователи', icon: ICONS.users },
{ id: 'broadcast', label: 'Рассылка', icon: ICONS.broadcast },
{ id: 'settings', label: 'Настройки', icon: ICONS.settings },
{ id: 'payouts', label: 'Выплаты', icon: ICONS.wallet },
];
function FrApp({ me, onLogout, tab, setTab }) {
const t = useToast();
const logout = async () => {
try { await frApi('/logout', { method: 'POST' }); } catch (e) {}
onLogout();
};
return (
{/* sidebar */}
{/* main */}
{/* mobile topbar */}
{me.franchise_name || 'VPN'}
{tab === 'dashboard' && setTab('payouts')}/>}
{tab === 'users' && }
{tab === 'broadcast' && }
{tab === 'settings' && }
{tab === 'payouts' && }
);
}
// --------------- Mount ---------------------------------------------------
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
);