// app.jsx — root state, session restore, routing const { useState, useEffect } = React; const TWEAK_DEFAULTS = { theme: 'light', variant: 'classic', brandName: 'ProBoost', accentColor: '#0088cc' }; function App() { const _resetToken = new URLSearchParams(window.location.search).get('token'); const _isResetRoute = window.location.pathname === '/reset-password' && !!_resetToken; const _guestOrderId = new URLSearchParams(window.location.search).get('guest_order_id'); const _isGuestReturn = !!_guestOrderId; const [tweaks, setTweaks] = useState(TWEAK_DEFAULTS); const [route, setRoute] = useState(_isGuestReturn ? 'guest-order-success' : (_isResetRoute ? 'auth' : 'landing')); const [authMode, setAuthMode] = useState(_isResetRoute ? 'reset' : 'login'); const [resetToken] = useState(_isResetRoute ? _resetToken : null); const [guestOrderId] = useState(_guestOrderId); const [user, setUser] = useState(null); const [balance, setBalance] = useState(0); const [appLoading, setAppLoading] = useState(true); const [selectedOrder, setSelectedOrder] = useState(null); const [botConfig, setBotConfig] = useState(null); const [adminMode, setAdminMode] = useState( () => localStorage.getItem('admin_mode') === '1' ); // Reflect adminMode on so platform.css applies the neon overrides. useEffect(() => { if (adminMode && user && user.is_admin) { document.documentElement.setAttribute('data-admin-mode', 'on'); } else { document.documentElement.removeAttribute('data-admin-mode'); } }, [adminMode, user]); // Force-off admin mode if the user signs out or isn't admin useEffect(() => { if (!user || !user.is_admin) setAdminMode(false); }, [user]); const toggleAdminMode = () => { const next = !adminMode; setAdminMode(next); localStorage.setItem('admin_mode', next ? '1' : '0'); // When turning ON, jump to admin dashboard. When OFF, back to cabinet. setRoute(next ? 'admin' : 'cabinet'); }; // Load public config (bot deep-link, etc.) once useEffect(() => { api.get('/api/config').then(data => { if (data && !data.__unauthorized) setBotConfig(data); }).catch(() => {}); }, []); // Apply theme + variant to . In admin mode the panel is fully owned by // [data-admin-mode="on"] styles — pin a fixed dark/classic base and drop the // inline --primary so the user's regular-mode theme can't leak in. useEffect(() => { const isAdmin = adminMode && user && user.is_admin; if (isAdmin) { document.documentElement.setAttribute('data-theme', 'dark'); document.documentElement.setAttribute('data-variant', 'classic'); document.documentElement.style.removeProperty('--primary'); return; } document.documentElement.setAttribute('data-theme', tweaks.theme); document.documentElement.setAttribute('data-variant', tweaks.variant); if (tweaks.accentColor) { document.documentElement.style.setProperty('--primary', tweaks.accentColor); } }, [tweaks, adminMode, user]); // Restore session from localStorage on mount useEffect(() => { const token = localStorage.getItem('access_token'); if (!token) { setAppLoading(false); return; } api.get('/api/me').then(data => { if (data.__unauthorized) { localStorage.removeItem('access_token'); } else { setUser({ first_name: data.first_name, user_name: data.user_name, user_id: data.user_id, is_admin: !!data.is_admin, }); setBalance(data.balance); setRoute('cabinet'); } }).catch(() => { localStorage.removeItem('access_token'); }).finally(() => setAppLoading(false)); }, []); const refreshBalance = () => { api.get('/api/me').then(data => { if (!data.__unauthorized) setBalance(data.balance); }).catch(() => {}); }; const setTweak = (key, val) => { setTweaks(prev => typeof key === 'object' ? { ...prev, ...key } : { ...prev, [key]: val }); }; const handleLogin = (token) => { localStorage.setItem('access_token', token); api.get('/api/me').then(data => { setUser({ first_name: data.first_name, user_name: data.user_name, user_id: data.user_id, is_admin: !!data.is_admin, }); setBalance(data.balance); setRoute('cabinet'); }).catch(() => { localStorage.removeItem('access_token'); }); }; const handleLogout = () => { localStorage.removeItem('access_token'); setUser(null); setBalance(0); setRoute('landing'); }; const handleNavigate = (target, payload) => { if (['cabinet', 'order-pf', 'orders', 'profile', 'order-detail', 'notifications'].includes(target) && !user) { setAuthMode('login'); setRoute('auth'); return; } if (['login', 'register', 'login-tg', 'forgot'].includes(target)) { setAuthMode(target); setRoute('auth'); return; } if (target === 'order-detail') { setSelectedOrder(payload || null); } setRoute(target); }; const handleOrderPlaced = (price) => { setBalance(b => b - price); }; if (appLoading) return (
Загрузка...
); const headerProps = { route, user, balance, brandName: tweaks.brandName, theme: tweaks.theme, adminMode, onToggleAdminMode: toggleAdminMode, onToggleTheme: () => setTweak('theme', tweaks.theme === 'dark' ? 'light' : 'dark'), onNavigate: handleNavigate, onLogout: handleLogout, }; const renderScreen = () => { if (adminMode && user && user.is_admin) { switch (route) { case 'admin': case 'admin-users': case 'admin-orders': case 'admin-support': return ; default: return ; } } switch (route) { case 'landing': return ; case 'auth': return ; case 'cabinet': return ; case 'order-pf': return ; case 'guest-order-pf': return ; case 'guest-order-success': return ; case 'orders': return ; case 'notifications': return ; case 'order-detail': return ; case 'profile': return ; default: return ; } }; return (
{adminMode && user && user.is_admin ? : } {renderScreen()} {user && !adminMode && }
); } ReactDOM.createRoot(document.getElementById('root')).render();