// screens/auth-extra.jsx // Telas extras de auth: ForgotPasswordScreen, SignupScreen, TwoFAScreen, WorkspaceScreen const { useState: useAxState, useEffect: useAxEffect, useRef: useAxRef } = React; // ═══════════════════════════════════════════════════════════════════ // ForgotPasswordScreen — 3 steps: email → sent → nova senha // ═══════════════════════════════════════════════════════════════════ function ForgotPasswordScreen({ onBack, onDone }) { const [step, setStep] = useAxState(0); const [email, setEmail] = useAxState(''); const [pwd, setPwd] = useAxState(''); const [pwd2, setPwd2] = useAxState(''); const [showPwd, setShowPwd] = useAxState(false); const [loading, setLoading] = useAxState(false); const [resending, setResending] = useAxState(false); const sendEmail = (e) => { e?.preventDefault(); if (!email) return; setLoading(true); setTimeout(() => { setLoading(false); setStep(1); }, 1100); }; const resend = () => { setResending(true); setTimeout(() => setResending(false), 1200); }; const savePassword = (e) => { e?.preventDefault(); if (!pwd || pwd !== pwd2 || pwd.length < 8) return; setLoading(true); setTimeout(() => { setLoading(false); onDone(); }, 900); }; const backAction = step === 0 ? onBack : step === 1 ? () => setStep(0) : () => setStep(1); return (
{[0, 1, 2].map(i => ( = i ? 'ax-dot-on' : ''}`} /> ))}
{step === 0 && <>
🔑

Esqueci a senha

Digite seu e-mail e enviaremos um link para criar uma nova senha.

} {step === 1 && <>

E-mail enviado!

Mandamos um link para {email}. Verifique sua caixa de entrada — e também o spam.

Não recebeu?{' '}
Já clicou no link?
} {step === 2 && <>
🔒

Nova senha

Crie uma senha forte com pelo menos 8 caracteres.

{pwd && pwd.length > 0 && pwd.length < 8 && (
Mínimo de 8 caracteres
)} {pwd2 && pwd !== pwd2 && (
As senhas não coincidem
)}
}
); } // ═══════════════════════════════════════════════════════════════════ // SignupScreen — split layout com form completo // ═══════════════════════════════════════════════════════════════════ function SignupScreen({ onBack, onDone, onTermos, onPrivacidade }) { const [nome, setNome] = useAxState(''); const [email, setEmail] = useAxState(''); const [empresa, setEmpresa] = useAxState(''); const [cargo, setCargo] = useAxState(''); const [pwd, setPwd] = useAxState(''); const [showPwd, setShowPwd] = useAxState(false); const [terms, setTerms] = useAxState(false); const [loading, setLoading] = useAxState(false); const canSubmit = nome && email && empresa && pwd.length >= 8 && terms; const submit = (e) => { e?.preventDefault(); if (!canSubmit) return; setLoading(true); setTimeout(() => onDone({ name: nome, email }), 1200); }; return (
{/* ─── lateral esquerda — editorial ──────────────────────── */} {/* ─── lateral direita — form ─────────────────────────────── */}
Criar conta gratuita
Já tem conta?
v2.6.1· Termos· Privacidade
); } // ═══════════════════════════════════════════════════════════════════ // TwoFAScreen — 6 dígitos com auto-advance + timer de reenvio // ═══════════════════════════════════════════════════════════════════ function TwoFAScreen({ onBack, onVerified, user }) { const [d0, setD0] = useAxState(''); const [d1, setD1] = useAxState(''); const [d2, setD2] = useAxState(''); const [d3, setD3] = useAxState(''); const [d4, setD4] = useAxState(''); const [d5, setD5] = useAxState(''); const [loading, setLoading] = useAxState(false); const [countdown, setCountdown] = useAxState(60); const r0 = useAxRef(null); const r1 = useAxRef(null); const r2 = useAxRef(null); const r3 = useAxRef(null); const r4 = useAxRef(null); const r5 = useAxRef(null); const setters = [setD0, setD1, setD2, setD3, setD4, setD5]; const getters = [d0, d1, d2, d3, d4, d5]; const refs = [r0, r1, r2, r3, r4, r5]; const code = getters.join(''); const complete = code.length === 6 && getters.every(d => d !== ''); // countdown useAxEffect(() => { if (countdown <= 0) return; const t = setTimeout(() => setCountdown(c => c - 1), 1000); return () => clearTimeout(t); }, [countdown]); // auto-verify when all 6 filled useAxEffect(() => { if (complete && !loading) { setLoading(true); setTimeout(() => { setLoading(false); onVerified(); }, 1300); } }, [complete]); const handleDigit = (i, val) => { const v = val.replace(/\D/g, '').slice(-1); setters[i](v); if (v && i < 5) refs[i + 1].current?.focus(); }; const handleKey = (i, e) => { if (e.key === 'Backspace' && !getters[i] && i > 0) { refs[i - 1].current?.focus(); } if (e.key === 'ArrowLeft' && i > 0) refs[i - 1].current?.focus(); if (e.key === 'ArrowRight' && i < 5) refs[i + 1].current?.focus(); }; const handlePaste = (e) => { const paste = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, 6); if (paste.length > 0) { const chars = paste.split(''); setters.forEach((set, i) => set(chars[i] || '')); refs[Math.min(paste.length, 5)].current?.focus(); } e.preventDefault(); }; const resend = () => { setCountdown(60); setters.forEach(set => set('')); setTimeout(() => refs[0].current?.focus(), 50); }; return (
🛡️

Verificação em
dois fatores

Enviamos um código de 6 dígitos para{' '} {user?.email || 'seu e-mail'}. Ele expira em 10 minutos.

{getters.map((d, i) => ( handleDigit(i, e.target.value)} onKeyDown={e => handleKey(i, e)} disabled={loading} autoFocus={i === 0} /> ))}
{loading && (
Verificando código…
)}
{countdown > 0 ? ( Reenviar em {countdown}s ) : ( <>Não recebeu? )}
Problemas?{' '} Fale com o suporte
); } // ═══════════════════════════════════════════════════════════════════ // WorkspaceScreen — seleção de workspace ao entrar // ═══════════════════════════════════════════════════════════════════ const WS_LIST = [ { id: 'ezza', name: 'EZZA Corp', logo: '🏢', plan: 'Pro', planColor: 'blue', members: 24, role: 'Administrador', lastActive: 'há 2 horas', }, { id: 'solar', name: 'Tecnoluz Solar', logo: '☀️', plan: 'Starter', planColor: 'yellow', members: 8, role: 'Membro', lastActive: 'há 3 dias', }, { id: 'pampa', name: 'Editora Pampa', logo: '📚', plan: 'Business', planColor: 'pink', members: 67, role: 'Convidado', lastActive: 'há 1 semana', }, ]; function WorkspaceScreen({ onBack, onPick, user }) { const [picking, setPicking] = useAxState(null); const pick = (ws) => { if (picking) return; setPicking(ws.id); setTimeout(() => onPick(ws), 800); }; return (
ezzaCRM
{user?.name || 'Letícia Andrade'}
{user?.email || 'leticia@ezza.com.br'}

Selecione um
workspace

Você tem acesso a {WS_LIST.length} workspaces. Qual deseja abrir agora?

{WS_LIST.map(ws => ( ))}
); } // ═══════════════════════════════════════════════════════════════════ // Styles // ═══════════════════════════════════════════════════════════════════ function AuthExtraStyles() { return ( ); } function SignupExtraStyles() { return ( ); } function WorkspaceStyles() { return ( ); } // ═══════════════════════════════════════════════════════════════════ // LegalScreen — layout compartilhado para Termos e Privacidade // ═══════════════════════════════════════════════════════════════════ function LegalScreen({ onBack, title, eyebrow, lastUpdated, sections }) { const [active, setActive] = useAxState(0); const scrollTo = (i) => { setActive(i); document.getElementById('lg-s-' + i)?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; const handleScroll = (e) => { const container = e.currentTarget; let found = 0; for (let i = 0; i < sections.length; i++) { const el = document.getElementById('lg-s-' + i); if (el && el.offsetTop - container.scrollTop < 160) found = i; } setActive(found); }; return (
{/* ── sidebar ── */} {/* ── content ── */}
{eyebrow}

{title}

Última atualização: {lastUpdated} · Versão 2.6

{sections.map((s, i) => (
{String(i + 1).padStart(2, '0')}

{s.title}

{s.content.map((block, j) => ( block.type === 'p' ?

{block.text}

: block.type === 'ul' ?
    {block.items.map((it, k) =>
  • {it}
  • )}
: block.type === 'h3' ?

{block.text}

: null ))}
))}

Esta é a versão atual do documento. Ao continuar usando a plataforma Ezza CRM após eventuais alterações, você confirma a aceitação das novas condições.

); } // ─── Termos de Uso ──────────────────────────────────────────────── function TermosScreen({ onBack }) { const sections = [ { title: 'Aceitação dos Termos', content: [ { type: 'p', text: 'Ao acessar ou usar a plataforma Ezza CRM ("Serviço"), você concorda em ficar vinculado a estes Termos de Uso. Se você não concordar com qualquer parte destes termos, não poderá acessar o Serviço.' }, { type: 'p', text: 'Estes Termos se aplicam a todos os visitantes, usuários e outras pessoas que acessam ou usam o Serviço. O uso continuado da plataforma após qualquer alteração constitui aceitação das novas condições.' }, ], }, { title: 'Descrição do Serviço', content: [ { type: 'p', text: 'A Ezza CRM fornece uma plataforma de gestão de relacionamento com clientes (CRM) na modalidade Software as a Service (SaaS), incluindo funcionalidades de pipeline de vendas, automação de comunicação, gestão de contatos e relatórios analíticos.' }, { type: 'ul', items: [ 'Gestão de pipeline de oportunidades e leads', 'Automação de follow-up por e-mail e WhatsApp', 'Integração com IA para scoring e SDR virtual', 'Relatórios e dashboards em tempo real', 'API pública para integrações externas', ]}, { type: 'p', text: 'Reservamo-nos o direito de modificar ou descontinuar o Serviço a qualquer momento, com aviso prévio de 30 dias para funcionalidades pagas.' }, ], }, { title: 'Cadastro e Responsabilidades', content: [ { type: 'p', text: 'Para usar o Serviço, você deve criar uma conta fornecendo informações precisas, completas e atualizadas. Você é responsável por manter a confidencialidade de sua senha e por todas as atividades realizadas em sua conta.' }, { type: 'h3', text: 'Você concorda em:' }, { type: 'ul', items: [ 'Não compartilhar credenciais de acesso com terceiros não autorizados', 'Notificar imediatamente qualquer uso não autorizado da sua conta', 'Usar o serviço apenas para fins legais e comerciais legítimos', 'Não realizar engenharia reversa ou tentar acessar código-fonte', ]}, ], }, { title: 'Planos e Pagamentos', content: [ { type: 'p', text: 'O Serviço é oferecido em diferentes planos (Starter, Pro e Business) com cobrança mensal ou anual. Os preços estão sujeitos a alteração com aviso prévio de 30 dias.' }, { type: 'p', text: 'O período de teste gratuito de 14 dias não exige cartão de crédito. Ao final do período de teste, a conta será suspensa caso não haja contratação de um plano pago.' }, { type: 'ul', items: [ 'Cobranças são realizadas antecipadamente (pré-pago)', 'Reembolsos são concedidos em até 7 dias após a contratação', 'Cancelamentos entram em vigor no final do período vigente', 'Aceitamos cartão de crédito, Pix e boleto bancário', ]}, ], }, { title: 'Propriedade Intelectual', content: [ { type: 'p', text: 'O Serviço e todo o seu conteúdo original, funcionalidades e características são e permanecerão propriedade exclusiva da Ezza CRM e seus licenciadores. Nossa marca, logotipo e nome de produto são marcas registradas.' }, { type: 'p', text: 'Você retém todos os direitos sobre os dados que inserir na plataforma. Concede à Ezza CRM uma licença limitada para processar esses dados unicamente para prestação do Serviço.' }, ], }, { title: 'Uso Aceitável', content: [ { type: 'p', text: 'Você concorda em não usar o Serviço de maneira que possa danificá-lo, desabilitá-lo, sobrecarregá-lo ou prejudicá-lo. Também concorda em não tentar obter acesso não autorizado a sistemas ou redes conectados ao Serviço.' }, { type: 'ul', items: [ 'É proibido o envio de spam, mensagens em massa não solicitadas', 'É proibido o scraping automatizado de dados da plataforma', 'É proibido o uso para atividades ilegais ou fraudulentas', 'É proibida a revenda do serviço sem autorização expressa', ]}, ], }, { title: 'Limitação de Responsabilidade', content: [ { type: 'p', text: 'Em nenhuma circunstância a Ezza CRM, seus diretores, funcionários, parceiros ou agentes serão responsáveis por danos indiretos, incidentais, especiais, consequenciais ou punitivos, incluindo perda de lucros, dados ou boa vontade.' }, { type: 'p', text: 'Nossa responsabilidade total não excederá o valor pago por você nos 12 meses anteriores ao evento que deu origem à reclamação, ou R$ 500,00, o que for maior.' }, ], }, { title: 'Rescisão', content: [ { type: 'p', text: 'Você pode encerrar sua conta a qualquer momento nas configurações da plataforma. A Ezza CRM pode suspender ou encerrar seu acesso imediatamente, sem aviso prévio, por violação destes Termos.' }, { type: 'p', text: 'Após a rescisão, seu direito de usar o Serviço cessará imediatamente. Você poderá exportar seus dados em até 30 dias após o encerramento.' }, ], }, { title: 'Lei Aplicável e Foro', content: [ { type: 'p', text: 'Estes Termos serão regidos e interpretados de acordo com as leis da República Federativa do Brasil, independentemente de conflito de disposições legais.' }, { type: 'p', text: 'Qualquer disputa decorrente destes Termos será submetida à jurisdição exclusiva dos tribunais da Comarca de São Paulo, Estado de São Paulo, Brasil.' }, ], }, { title: 'Contato', content: [ { type: 'p', text: 'Se tiver dúvidas sobre estes Termos de Uso, entre em contato conosco:' }, { type: 'ul', items: [ 'E-mail jurídico: legal@ezzacrm.com.br', 'Endereço: Av. Paulista, 1000 — São Paulo, SP — 01310-100', 'Telefone: (11) 3000-0000 (seg–sex, 9h–18h)', 'Chat de suporte: disponível na plataforma', ]}, ], }, ]; return ( ); } // ─── Política de Privacidade ───────────────────────────────────── function PrivacidadeScreen({ onBack }) { const sections = [ { title: 'Informações que Coletamos', content: [ { type: 'p', text: 'Coletamos diferentes tipos de informações para fornecer e melhorar nosso Serviço, sempre em conformidade com a Lei Geral de Proteção de Dados (LGPD — Lei 13.709/2018).' }, { type: 'h3', text: 'Dados fornecidos por você:' }, { type: 'ul', items: [ 'Nome completo, e-mail e senha ao criar sua conta', 'Informações de empresa, cargo e telefone no perfil', 'Dados de clientes e contatos inseridos na plataforma', 'Conteúdo de mensagens e notas nas oportunidades', 'Dados de faturamento (nome, CPF/CNPJ, endereço)', ]}, { type: 'h3', text: 'Dados coletados automaticamente:' }, { type: 'ul', items: [ 'Endereço IP e dados de geolocalização aproximada', 'Tipo de navegador, sistema operacional e dispositivo', 'Páginas visitadas, cliques e tempo de sessão', 'Logs de acesso e eventos de uso da plataforma', ]}, ], }, { title: 'Como Usamos as Informações', content: [ { type: 'p', text: 'Utilizamos as informações coletadas para as seguintes finalidades, sempre com base legal adequada conforme a LGPD:' }, { type: 'ul', items: [ 'Prestação e manutenção do Serviço contratado', 'Personalização da experiência na plataforma', 'Envio de comunicações transacionais (recibos, alertas)', 'Suporte técnico e atendimento ao cliente', 'Melhoria contínua dos algoritmos de IA e scoring', 'Cumprimento de obrigações legais e regulatórias', 'Prevenção a fraudes e segurança da plataforma', ]}, ], }, { title: 'Compartilhamento de Dados', content: [ { type: 'p', text: 'Não vendemos, alugamos ou comercializamos seus dados pessoais com terceiros. Podemos compartilhar informações apenas nas seguintes situações:' }, { type: 'ul', items: [ 'Fornecedores de serviço (cloud, pagamentos, e-mail) sob contrato de confidencialidade', 'Obrigação legal ou ordem judicial', 'Proteção de direitos, propriedade ou segurança da Ezza CRM ou usuários', 'Com seu consentimento explícito para casos específicos', ]}, { type: 'p', text: 'Nossos principais subprocessadores incluem: AWS (infraestrutura), Stripe (pagamentos), SendGrid (e-mail transacional) e OpenAI (processamento de IA). Todos operam com adequação à LGPD/GDPR.' }, ], }, { title: 'Seus Direitos — LGPD', content: [ { type: 'p', text: 'Como titular de dados, a LGPD garante a você os seguintes direitos, exercíveis a qualquer momento:' }, { type: 'ul', items: [ 'Confirmação da existência e acesso aos seus dados', 'Correção de dados incompletos, inexatos ou desatualizados', 'Anonimização, bloqueio ou eliminação de dados desnecessários', 'Portabilidade dos dados a outro fornecedor', 'Eliminação de dados tratados com consentimento', 'Revogação do consentimento a qualquer momento', 'Oposição ao tratamento com base em interesse legítimo', ]}, { type: 'p', text: 'Para exercer seus direitos, acesse Configurações > Privacidade ou envie e-mail para privacidade@ezzacrm.com.br. Respondemos em até 15 dias úteis.' }, ], }, { title: 'Cookies e Rastreamento', content: [ { type: 'p', text: 'Utilizamos cookies e tecnologias similares para melhorar sua experiência, manter sessões ativas e analisar o uso da plataforma. Você pode configurar seu navegador para recusar cookies, mas isso pode limitar funcionalidades.' }, { type: 'h3', text: 'Tipos de cookies utilizados:' }, { type: 'ul', items: [ 'Essenciais: necessários para funcionamento da plataforma (sem opção de recusa)', 'Funcionais: lembram preferências e configurações do usuário', 'Analíticos: medem uso e performance (Google Analytics, Mixpanel)', 'Marketing: não utilizamos cookies de rastreamento para publicidade de terceiros', ]}, ], }, { title: 'Segurança dos Dados', content: [ { type: 'p', text: 'Implementamos medidas técnicas e organizacionais adequadas para proteger seus dados contra acesso não autorizado, alteração, divulgação ou destruição.' }, { type: 'ul', items: [ 'Criptografia TLS 1.3 em todas as transmissões', 'Dados em repouso criptografados com AES-256', 'Autenticação de dois fatores disponível para todas as contas', 'Backups automáticos diários com retenção de 30 dias', 'Monitoramento contínuo de intrusão e anomalias', 'Programa de divulgação responsável de vulnerabilidades', ]}, { type: 'p', text: 'Em caso de incidente de segurança, notificaremos os titulares afetados e a ANPD dentro dos prazos legais.' }, ], }, { title: 'Retenção de Dados', content: [ { type: 'p', text: 'Mantemos seus dados pelo tempo necessário para prestar o Serviço e cumprir obrigações legais:' }, { type: 'ul', items: [ 'Dados de conta ativa: pelo período de vigência do contrato', 'Após cancelamento: 30 dias para exportação, depois anonimização', 'Dados fiscais e de faturamento: 5 anos (obrigação legal)', 'Logs de acesso e segurança: 6 meses', 'Backups: até 90 dias após exclusão', ]}, ], }, { title: 'Transferências Internacionais', content: [ { type: 'p', text: 'Alguns de nossos subprocessadores operam fora do Brasil. Nestes casos, adotamos salvaguardas adequadas conforme o Art. 33 da LGPD, incluindo cláusulas contratuais padrão e certificação de adequação.' }, { type: 'p', text: 'Países de destino principais: Estados Unidos (AWS, OpenAI, Stripe) e Irlanda (Google Cloud). Todos com nível de proteção equivalente ao exigido pela LGPD.' }, ], }, { title: 'Encarregado (DPO)', content: [ { type: 'p', text: 'Nossa Encarregada de Proteção de Dados (DPO) é responsável por supervisionar o cumprimento da LGPD e atender solicitações dos titulares.' }, { type: 'ul', items: [ 'Nome: Dra. Camila Rocha', 'E-mail: dpo@ezzacrm.com.br', 'Horário: segunda a sexta, 9h às 17h (horário de Brasília)', 'Prazo de resposta: até 15 dias úteis', ]}, ], }, { title: 'Alterações nesta Política', content: [ { type: 'p', text: 'Podemos atualizar esta Política de Privacidade periodicamente. Notificaremos sobre alterações significativas por e-mail e/ou com aviso destacado na plataforma com pelo menos 15 dias de antecedência.' }, { type: 'p', text: 'Recomendamos revisar esta Política periodicamente. O uso continuado do Serviço após as alterações constitui aceitação da nova Política.' }, ], }, ]; return ( ); } // ─── LegalStyles ───────────────────────────────────────────────── function LegalStyles() { return ( ); } // Exportar globalmente Object.assign(window, { ForgotPasswordScreen, SignupScreen, TwoFAScreen, WorkspaceScreen, TermosScreen, PrivacidadeScreen, });