// 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')}
/>
{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 ? :
);