// Tela: Configurações const SET_TABS = [ { id: 'conta', label: 'Conta', icon: 'user', hint: 'Dados da empresa' }, { id: 'faturamento', label: 'Faturamento', icon: 'briefcase', hint: 'Plano e cobrança' }, { id: 'whatsapp', label: 'WhatsApp', icon: 'whatsapp', hint: 'Número e templates', badge: '●' }, { id: 'agente', label: 'Agente IA', icon: 'bolt2', hint: 'SDR virtual · VAPI', badge: '●' }, { id: 'status', label: 'Status', icon: 'check', hint: 'APIs e integrações' }, { id: 'integracoes', label: 'Integrações', icon: 'link', hint: '12 conectadas' }, { id: 'notificacoes', label: 'Notificações', icon: 'bell', hint: 'E-mail, push, in-app' }, { id: 'automacoes', label: 'Automações', icon: 'bolt2', hint: 'Regras e gatilhos' }, { id: 'privacidade', label: 'Privacidade', icon: 'help', hint: 'Dados e LGPD' }, ]; function Configuracoes({ onBack }) { const [tab, setTab] = React.useState('conta'); return ( <> Configurações da conta} subtitle="Personalize a Ezza para sua operação" back onBack={onBack} />
{tab === 'conta' && } {tab === 'faturamento' && } {tab === 'whatsapp' && } {tab === 'agente' && } {tab === 'status' && } {tab === 'integracoes' && } {tab === 'notificacoes' && } {tab === 'automacoes' && } {tab === 'privacidade' && }
); } function SetSection({ title, sub, right, children }) { return (
{title}
{sub &&
{sub}
}
{right}
{children}
); } const cfgHeaders = () => { const t = localStorage.getItem('ezza_token'); return { 'Content-Type':'application/json', ...(t?{'Authorization':`Bearer ${t}`}:{}) }; }; function SetConta() { const toast = useToast(); const [razao, setRazao] = React.useState(''); const [fantasia, setFantasia] = React.useState(''); const [cnpj, setCnpj] = React.useState(''); const [ie, setIe] = React.useState(''); const [end, setEnd] = React.useState(''); const [dirty, setDirty] = React.useState(false); // Carrega dados salvos do banco React.useEffect(() => { fetch('/api/configuracoes', { headers: cfgHeaders() }) .then(r => r.json()) .then(d => { const c = (d.ok && d.configuracoes && d.configuracoes.empresa) || null; if (c) { setRazao(c.razao||''); setFantasia(c.fantasia||''); setCnpj(c.cnpj||''); setIe(c.ie||''); setEnd(c.endereco||''); } setDirty(false); }) .catch(() => {}); }, []); const mark = (setter) => (e) => { setter(e.target.value); setDirty(true); }; const salvar = async () => { try { await fetch('/api/configuracoes', { method:'PUT', headers: cfgHeaders(), body: JSON.stringify({ dados: { empresa: { razao, fantasia, cnpj, ie, endereco: end } } }) }); setDirty(false); toast('Dados da empresa salvos ✓'); } catch (e) { toast('Erro ao salvar'); } }; return ( <> {ICN.check} Salvar} >
); } function AdicionarCartaoModal({ onClose, onAdd }) { const [titular, setTitular] = React.useState(''); const [numero, setNumero] = React.useState(''); const [validade, setValidade] = React.useState(''); const [cvv, setCvv] = React.useState(''); const toast = useToast(); React.useEffect(() => { const h = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [onClose]); // formata número: 1234 5678 9012 3456 const fmtNumero = (v) => v.replace(/\D/g,'').slice(0,16).replace(/(.{4})/g,'$1 ').trim(); // formata validade: MM/AA const fmtValid = (v) => v.replace(/\D/g,'').slice(0,4).replace(/^(\d{2})(\d)/, '$1/$2'); const bandeira = () => { const d = numero.replace(/\s/g,''); if (d.startsWith('4')) return 'VISA'; if (d.startsWith('5') || d.startsWith('2')) return 'MASTER'; if (d.startsWith('3')) return 'AMEX'; return '···'; }; const valid = titular.trim().length > 2 && numero.replace(/\s/g,'').length === 16 && validade.length === 5 && cvv.length >= 3; const submit = () => { if (!valid) return; const last4 = numero.replace(/\s/g,'').slice(-4); onAdd({ bandeira: bandeira(), last4, validade, titular: titular.trim() }); toast(`Cartão ${bandeira()} •••• ${last4} adicionado ✓`); onClose(); }; return (
e.stopPropagation()} style={{width:460}}>
Adicionar cartão
Seus dados são protegidos com criptografia SSL.
{ICN.x}
setNumero(fmtNumero(e.target.value))} maxLength={19} /> {bandeira()}
setTitular(e.target.value)} autoFocus />
setValidade(fmtValid(e.target.value))} maxLength={5} />
setCvv(e.target.value.replace(/\D/g,'').slice(0,4))} maxLength={4} type="password" />
Conexão segura · criptografia SSL 256-bit
); } function SetFat() { const toast = useToast(); const [showUpgrade, setShowUpgrade] = React.useState(false); const [showAddCard, setShowAddCard] = React.useState(false); const [cartoes, setCartoes] = React.useState([ { bandeira: 'VISA', last4: '4827', validade: '09/2029', titular: 'Letícia A. Borges', padrao: true }, ]); const downloadFatura = (r) => { const linhas = [ '================================================', ' EZZA CRM — FATURA', '================================================', '', `Data: ${r.d}`, `Descrição: ${r.t}`, `Valor: ${r.v}`, `Status: ${r.s}`, '', '------------------------------------------------', 'Ezza Tecnologia LTDA', 'CNPJ: 42.108.554/0001-77', 'Av. Brigadeiro Faria Lima, 3477 — 12º andar', 'São Paulo, SP · 04538-133', 'suporte@ezza.com.br', '================================================', ].join('\n'); const blob = new Blob([linhas], { type: 'text/plain;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `fatura-ezza-${r.d.replace(/\//g,'-')}.txt`; a.click(); URL.revokeObjectURL(url); toast('Fatura baixada ✓'); }; return ( <> Pro · Anual}>
Plano Pro · faturado anualmente
R$ 12.948/ano
12 assentos · próxima renovação em 06/04/2027
7 / 12
Assentos usados
68 GB / 100 GB
Armazenamento
12 / ∞
Automações ativas
3 / 5
Pipelines
setShowAddCard(true)}>{ICN.plus} Adicionar cartão}> {cartoes.map((c, i) => (
0 ? '12px 0 0' : '0'}}>
{c.bandeira}
•••• •••• •••• {c.last4}
Vence {c.validade} · Titular: {c.titular}
{c.padrao ? Padrão : } toast('Editar cartão · atualize pelo portal de pagamento')} />
))}
{[ { d: '06/04/2026', t: 'Plano Pro · anual', v: 'R$ 5.964,00', s: 'Pago', c: 'mint' }, { d: '06/04/2025', t: 'Plano Pro · anual', v: 'R$ 5.964,00', s: 'Pago', c: 'mint' }, { d: '12/02/2025', t: 'Upgrade · +4 assentos', v: 'R$ 1.080,00', s: 'Pago', c: 'mint' }, { d: '06/04/2024', t: 'Plano Starter · anual', v: 'R$ 2.964,00', s: 'Pago', c: 'mint' }, ].map((r,i) => ( ))}
DataDescriçãoValorStatus
{r.d} {r.t} {r.v} {r.s} downloadFatura(r)} />
{showAddCard && ( setShowAddCard(false)} onAdd={(c) => setCartoes(prev => [...prev, c])} /> )} {showUpgrade && (
setShowUpgrade(false)}>
e.stopPropagation()} style={{width: 580}}>
Comparar planos
Escolha o melhor plano para sua equipe
setShowUpgrade(false)}>{ICN.x}
{[ { name:'Starter', price:'R$ 297', sub:'/mês · até 3 usuários', features:['Pipeline completo','1.000 leads','WhatsApp integrado','IA de qualificação','Suporte por e-mail'], color:'', current:false }, { name:'Pro', price:'R$ 597', sub:'/mês · até 10 usuários', features:['Leads ilimitados','IA SDR completa','Jornadas customizadas','Automações ilimitadas','Relatórios avançados','Suporte prioritário'], color:'lav', current:true }, { name:'Enterprise', price:'Sob consulta', sub:'usuários ilimitados', features:['Tudo do Pro','White-label','SSO + LGPD','API dedicada','CSM exclusivo','SLA 99,9%'], color:'dark', current:false }, ].map(p => (
{p.current &&
Atual
}
{p.name}
{p.price}
{p.sub}
{p.features.map((f,i) => (
{ICN.check} {f}
))}
{!p.current && ( )}
))}
)} ); } const INTEGRACOES = [ { sw:'GW', label: 'Google Workspace', desc: 'Agenda, Gmail e Drive', color:'blue', on: true }, { sw:'OF', label: 'Outlook 365', desc: 'Calendar e e-mail corporativo', color:'blue', on: false }, { sw:'WA', label: 'WhatsApp Business', desc: 'Conversas e templates aprovados', color:'mint', on: true }, { sw:'IG', label: 'Instagram Direct', desc: 'Mensagens diretas e leads de ads', color:'pink', on: true }, { sw:'MA', label: 'Meta Ads', desc: 'Captura de leads de campanhas', color:'blue', on: true }, { sw:'GA', label: 'Google Ads', desc: 'Atribuição de receita a campanhas', color:'yellow',on: true }, { sw:'RD', label: 'RD Station', desc: 'Sincronização bidirecional de contatos', color:'lav', on: false }, { sw:'SL', label: 'Slack', desc: 'Notificações em canais', color:'lav', on: true }, { sw:'ZP', label: 'Zapier', desc: '5.000+ apps via webhooks', color:'pink', on: true }, { sw:'OM', label: 'Omie', desc: 'ERP e emissão de NF-e', color:'yellow',on: true }, { sw:'CT', label: 'Conta Azul', desc: 'ERP e contabilidade', color:'mint', on: false }, { sw:'AW', label: 'AWS S3', desc: 'Backup e armazenamento de anexos', color:'blue', on: true }, ]; function SetInt() { const [integs, setIntegs] = React.useState(INTEGRACOES.map(it => ({...it}))); const toggle = (i) => setIntegs(prev => prev.map((it, idx) => idx === i ? {...it, on: !it.on} : it)); const toast = useToast(); return ( <> i.on).length} conectadas`} right={}>
{integs.map((it,i) => (
{it.sw}
{it.label}
{it.desc}
{it.on && (
● Conectado · Sincronizado há 4 minutos
)}
))}
); } function SetNot() { const [items, setItems] = React.useState([ { lbl: 'Novo lead atribuído a você', e: true, p: true, i: true }, { lbl: 'Lead muda de etapa no pipeline', e: false, p: true, i: true }, { lbl: 'Comentário ou menção a você', e: true, p: true, i: true }, { lbl: 'Oportunidade fechada (ganha ou perdida)', e: true, p: true, i: true }, { lbl: 'Tarefa próxima do vencimento', e: true, p: false, i: true }, { lbl: 'SLA de caso prestes a estourar', e: true, p: true, i: true }, { lbl: 'Resumo diário de pipeline', e: true, p: false, i: false }, { lbl: 'Resumo semanal de equipe', e: true, p: false, i: false }, ]); const toggle = (i, key) => setItems(prev => prev.map((it, idx) => idx === i ? {...it, [key]: !it[key]} : it)); return ( {items.map((it, i) => ( ))}
EventoE-mailPushIn-app
{it.lbl}
); } function NovaAutomacaoModal({ onClose, onAdd }) { const [gatilho, setGatilho] = React.useState('Lead novo'); const [acao, setAcao] = React.useState('Enviar WhatsApp'); const [nome, setNome] = React.useState(''); const toast = useToast(); const GATILHOS = ['Lead novo','Lead sem atividade 7 dias','Oportunidade ganha','Oportunidade perdida','Caso aberto crítico','Tarefa vencida']; const ACOES = ['Enviar WhatsApp','Notificar Slack','Criar tarefa','Enviar e-mail','Ligar via IA','Mover etapa do pipeline']; const valid = nome.trim().length > 0; const submit = () => { if (!valid) return; onAdd({ tit: `${gatilho} → ${acao}`, desc: `${nome.trim()}`, on: true, runs: '0 execuções' }); toast('Automação criada com sucesso ✓'); onClose(); }; return (
e.stopPropagation()} style={{width:520}}>
Nova Automação
Defina o gatilho e a ação
{ICN.x}
setNome(e.target.value)} autoFocus />
); } function SetAuto() { const [autos, setAutos] = React.useState([ { tit: 'Lead novo de Meta Ads → WhatsApp', desc: 'Envia mensagem inicial em até 60s quando um lead chega via Meta Ads.', on: true, runs: '1.248 execuções' }, { tit: 'Oportunidade ganha → notificar #vendas', desc: 'Posta no Slack quando uma oportunidade é marcada como Ganha.', on: true, runs: '42 execuções' }, { tit: 'Caso crítico → SMS para responsável', desc: 'Envia SMS quando um caso é aberto com prioridade Crítica.', on: true, runs: '11 execuções' }, { tit: 'Lead sem atividade 7 dias → tarefa', desc: 'Cria tarefa para o dono do lead reativar.', on: false, runs: '0 execuções' }, ]); const toggle = (i) => setAutos(prev => prev.map((a, idx) => idx === i ? {...a, on: !a.on} : a)); const [showNovaAuto, setShowNovaAuto] = React.useState(false); return ( <> {showNovaAuto && setShowNovaAuto(false)} onAdd={(a) => setAutos(prev => [...prev, a])} />} setShowNovaAuto(true)}>{ICN.plus} Criar automação}> {autos.map((a, i) => (
{ICN.bolt2}
{a.tit}
{a.desc}
{a.runs} no mês
))}
); } function SetPriv() { const toast = useToast(); const exportarDados = () => { // Exporta um JSON com os dados visíveis do protótipo como demonstração const payload = { exportadoEm: new Date().toISOString(), conta: 'Ezza Tecnologia LTDA', contatos: CONTATOS.map(c => ({ id: c.id, nome: c.nome, empresa: c.empresa, email: c.email })), leads: LEADS.map(l => ({ id: l.id, nome: l.nome, empresa: l.empresa, etapa: l.etapa, pontos: l.pontos })), casos: CASOS.map(c => ({ id: c.id, assunto: c.assunto, prioridade: c.prioridade, status: c.status })), }; const json = JSON.stringify(payload, null, 2); const a = Object.assign(document.createElement('a'), { href: URL.createObjectURL(new Blob([json], { type: 'application/json' })), download: `ezza-dados-${new Date().toISOString().slice(0,10)}.json`, }); a.click(); URL.revokeObjectURL(a.href); toast('Exportação iniciada · arquivo JSON baixado ✓'); }; const compartilharAuditoria = () => { const link = `https://app.ezza.com.br/auditoria?token=audit_${Math.random().toString(36).slice(2,10)}&expires=${Date.now()+86400000}`; navigator.clipboard?.writeText(link).catch(() => {}); toast('Link de auditoria copiado · válido por 24h ✓'); }; return ( <> { window.open('mailto:privacidade@ezza.com.br?subject=Solicitação de Exclusão de Dados (Art. 18 LGPD)'); toast('Abrindo e-mail para solicitação formal ✓'); }} /> ); } function Toggle({ label, hint, defaultOn, hasArrow }) { const [on, setOn] = React.useState(!!defaultOn); return (
{label}
{hint}
{hasArrow ? {ICN.chevron} : }
); } /* SetWA, SetAI, SetStatus, SecRow → configuracoes-extra.jsx */ // Inline styles helpers const _setStyles = ` .bil-hero { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; padding-bottom: 18px; border-bottom: 1px solid oklch(0.93 0.01 255); margin-bottom: 18px; } .bil-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } .bil-stat-v { font-size: 16px; font-weight: 700; letter-spacing: -0.015em; } .bil-stat-l { font-size: 11px; color: var(--ink-muted); margin-top: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; } .card-chip { width: 56px; height: 38px; border-radius: 8px; background: linear-gradient(135deg, oklch(0.25 0.08 250), oklch(0.18 0.04 250)); color: white; font-family: var(--font-mono); font-weight: 700; font-size: 11px; display: grid; place-items: center; letter-spacing: 0.04em; } `; const _setStyleEl = document.createElement('style'); _setStyleEl.textContent = _setStyles; document.head.appendChild(_setStyleEl); window.Configuracoes = Configuracoes;