// Main App — owns active screen + tweaks state const { useState, useEffect } = React; // Modo admin: ?admin=1 só abre a TELA de login do painel. // A segurança real é a chave validada no servidor (x-admin-key). const _isAdmin = new URLSearchParams(window.location.search).has('admin'); // Detecta se está num subdomínio de cliente (ex: meldica.ezzacrm.com.br) // Se sim, pula o EntryGate e vai direto pro login function isClientSubdomain() { const host = window.location.hostname; return host.endsWith('.ezzacrm.com.br'); } function App() { const [t, setTweak] = useTweaks(window.TWEAK_DEFAULTS); const hasToken = () => { try { return !!localStorage.getItem('ezza_token'); } catch (e) { return false; } }; // Lê intent vindo da landing page (sessionStorage.ezza-intent: 'demo' | 'login' | 'pricing') const getInitialStage = () => { try { const intent = sessionStorage.getItem('ezza-intent'); if (intent) { sessionStorage.removeItem('ezza-intent'); return intent; } } catch (e) {} // Sessão salva (token JWT no localStorage) → restaura direto pro app if (hasToken()) return 'app'; // Subdomínio de cliente → vai direto pro login if (isClientSubdomain()) return 'login'; return 'gate'; }; const getInitialDemo = () => { try { const intent = sessionStorage.getItem('ezza-intent'); return intent === 'demo'; } catch (e) { return false; } }; const [authStage, setAuthStage] = useState(getInitialStage); const [prevStage, setPrevStage] = useState('signup'); // para voltar dos screens legais const [authUser, setAuthUser] = useState(null); const [isDemo, setIsDemo] = useState(getInitialDemo); const [screen, setScreen] = useState("painel"); const [contactId, setContactId] = useState(null); // when set → contact detail view const [overlay, setOverlay] = useState(null); // 'search' | 'messages' | 'notifs' | 'profile' const [showTour, setShowTour] = useState(false); const goto = (id) => { setScreen(id); setContactId(null); }; const gotoSettings = (id) => { setScreen(id); setContactId(null); setOverlay(null); }; // Restaura sessão: valida o token salvo e recupera dados do usuário useEffect(() => { if (authStage !== 'app' || authUser || isDemo) return; const token = localStorage.getItem('ezza_token'); if (!token) { setAuthStage('login'); return; } fetch('/auth/me', { headers: { 'Authorization': `Bearer ${token}` } }) .then(r => r.json()) .then(d => { if (d.ok) { setAuthUser({ name: d.usuario.nome, email: d.usuario.email }); } else { localStorage.removeItem('ezza_token'); setAuthStage('login'); } }) .catch(() => {}); // erro de rede: mantém no app graciosamente }, []); // ⌘K opens search · Ctrl+Shift+D opens design system useEffect(() => { const h = (e) => { if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setOverlay('search'); } if ((e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === 'd') { e.preventDefault(); setScreen(s => s === 'design-system' ? 'painel' : 'design-system'); } }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, []); // Auth gates: gate → login → splash → app (ou gate → splash demo → app) if (authStage === 'gate') { return ( { setIsDemo(true); setAuthUser({ name: 'Visitante (demo)', email: 'demo@ezza.com.br' }); setAuthStage('splash'); }} onLogin={() => { setIsDemo(false); setAuthStage('login'); }} /> ); } if (authStage === 'login') { return ( { if (user.hint === 'forgot') { setAuthStage('forgot'); return; } if (user.hint === 'signup') { setAuthStage('signup'); return; } setAuthUser(user); setAuthStage('splash'); }} onBack={() => setAuthStage('gate')} /> ); } if (authStage === 'forgot') { return ( setAuthStage('login')} onDone={() => setAuthStage('login')} /> ); } if (authStage === 'signup') { return ( setAuthStage('login')} onDone={(user) => { setAuthUser(user); setIsDemo(false); setAuthStage('2fa'); }} onTermos={() => { setPrevStage('signup'); setAuthStage('termos'); }} onPrivacidade={() => { setPrevStage('signup'); setAuthStage('privacidade'); }} /> ); } if (authStage === 'termos') { return ( setAuthStage(prevStage)} /> ); } if (authStage === 'privacidade') { return ( setAuthStage(prevStage)} /> ); } if (authStage === '2fa') { return ( setAuthStage('signup')} onVerified={() => setAuthStage('workspace')} user={authUser} /> ); } if (authStage === 'workspace') { return ( setAuthStage('gate')} onPick={(ws) => setAuthStage('splash')} user={authUser} /> ); } if (authStage === 'splash') { return ( { setAuthStage('app'); if (isDemo) setShowTour(true); }} /> ); } if (authStage === 'thanks') { return ( { setAuthUser(null); setAuthStage('gate'); }} /> ); } if (authStage === 'pricing') { return ( { setIsDemo(false); setAuthUser(null); setAuthStage('gate'); }} onPick={(planId) => { setIsDemo(false); setAuthStage('login'); }} /> ); } let body = null; if (screen === "painel") body = { setScreen('contatos'); setContactId(id); }} user={authUser} />; else if (screen === "pipeline") body = ; else if (screen === "jornadas") body = ; else if (screen === "contatos") body = ; else if (screen === "oportunidades") body = { setScreen('contatos'); setContactId(id); }} />; else if (screen === "calendario") body = ; else if (screen === "relatorios") body = ; else if (screen === "casos") body = { setScreen('contatos'); setContactId(id); }} />; else if (screen === "conversas") body = ; else if (screen === "perfil") body = setScreen('painel')} />; else if (screen === "equipe") body = setScreen('painel')} onOpenContact={(id) => { setScreen('contatos'); setContactId(id); }} />; else if (screen === "configuracoes") body = setScreen('painel')} />; else if (screen === "ajuda") body = setScreen('painel')} onTour={() => { setScreen('painel'); setShowTour(true); }} />; else if (screen === "app-desktop") body = setScreen('painel')} />; else if (screen === "design-system") body = setScreen('painel')} />; return (
setOverlay('search')} onOpenMessages={() => setOverlay('messages')} onOpenNotifs={() => setOverlay('notifs')} onOpenProfile={() => setOverlay('profile')} />
{body}
{overlay === 'search' && setOverlay(null)} onNavigate={goto} />} {overlay === 'messages' && setOverlay(null)} onNavigate={goto} />} {overlay === 'notifs' && setOverlay(null)} onNavigate={goto} />} {overlay === 'profile' && setOverlay(null)} onNavigate={gotoSettings} onLogout={() => { setOverlay(null); try { localStorage.removeItem('ezza_token'); } catch (e) {} setAuthUser(null); setAuthStage(isDemo ? 'pricing' : 'thanks'); }} />} {isDemo && { setAuthStage('pricing'); }} onSignup={() => { setAuthStage('pricing'); }} />} setTweak("cardStyle", v)} /> setTweak("ticketStyle", v)} />
{/* WelcomeTour renderizado FORA do .app para que position:fixed funcione corretamente (o grid layout do .app cria stacking context que quebra fixed positioning) */} {showTour && setShowTour(false)} goto={goto} />}
); } ReactDOM.createRoot(document.getElementById("root")).render( _isAdmin ? : );