const { useState, useEffect } = React; // --- Funcões Auxilares e Máscaras --- function validarCPF(cpf) { cpf = cpf.replace(/[^\d]+/g, ''); if (cpf.length !== 11 || !!cpf.match(/(\d)\1{10}/)) return false; let soma = 0, resto; for (let i = 1; i <= 9; i++) soma += parseInt(cpf.substring(i - 1, i)) * (11 - i); resto = (soma * 10) % 11; if (resto === 10 || resto === 11) resto = 0; if (resto !== parseInt(cpf.substring(9, 10))) return false; soma = 0; for (let i = 1; i <= 10; i++) soma += parseInt(cpf.substring(i - 1, i)) * (12 - i); resto = (soma * 10) % 11; if (resto === 10 || resto === 11) resto = 0; if (resto !== parseInt(cpf.substring(10, 11))) return false; return true; } function formatCPF(value) { if (!value) return ''; return value.replace(/\D/g, '') .replace(/(\d{3})(\d)/, '$1.$2') .replace(/(\d{3})(\d)/, '$1.$2') .replace(/(\d{3})(\d{1,2})/, '$1-$2') .replace(/(-\d{2})\d+?$/, '$1'); } function formatCNPJ(value) { if (!value) return ''; return value.replace(/\D/g, '') .replace(/(\d{2})(\d)/, '$1.$2') .replace(/(\d{3})(\d)/, '$1.$2') .replace(/(\d{3})(\d)/, '$1/$2') .replace(/(\d{4})(\d{1,2})/, '$1-$2') .replace(/(-\d{2})\d+?$/, '$1'); } function formatCardNumber(value) { return value.replace(/\D/g, '').replace(/(\d{4})/g, '$1 ').trim().substring(0, 19); } function formatExpiry(value) { const v = value.replace(/\D/g, ''); if (v.length >= 2) return v.substring(0, 2) + '/' + v.substring(2, 4); return v; } function validarSenha(senha) { const minLength = 8; const hasUpperCase = /[A-Z]/.test(senha); const hasNumber = /[0-9]/.test(senha); const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(senha); if (senha.length < minLength) return "A senha deve ter pelo menos 8 caracteres."; if (!hasUpperCase) return "A senha deve conter pelo menos uma letra maiúscula."; if (!hasNumber) return "A senha deve conter pelo menos um número."; if (!hasSpecial) return "A senha deve conter pelo menos um caractere especial."; return null; } // RemovidonotasDB mock e integrado com MariaDB via backend. const API_URL = 'https://api.iaagro.app/api'; function App() { const [view, setView] = useState('landing'); const [user, setUser] = useState(null); const [theme, setTheme] = useState('dark'); const [notification, setNotification] = useState({ show: false, msg: '', type: 'info' }); const notify = (msg, type = 'info') => { setNotification({ show: true, msg, type }); setTimeout(() => setNotification({ show: false, msg: '', type: 'info' }), 4000); }; // --- Sistema de Temas --- useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const applyTheme = (isDark) => { const newTheme = isDark ? 'dark' : 'light'; setTheme(newTheme); document.documentElement.setAttribute('data-theme', newTheme); }; applyTheme(mediaQuery.matches); const handleChange = (e) => applyTheme(e.matches); mediaQuery.addEventListener('change', handleChange); // Persistência de Login: Recuperar do localStorage const savedUser = localStorage.getItem('iaagro_user'); if (savedUser) { try { const parsedUser = JSON.parse(savedUser); setUser(parsedUser); setView('portal'); } catch (e) { localStorage.removeItem('iaagro_user'); } } return () => mediaQuery.removeEventListener('change', handleChange); }, []); // --- Observador para Animações de Scroll (Reveal) --- useEffect(() => { const observerOptions = { threshold: 0.15, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('active'); // Opcional: parar de observar após animar uma vez // observer.unobserve(entry.target); } }); }, observerOptions); const revealElements = document.querySelectorAll('.reveal'); revealElements.forEach(el => observer.observe(el)); // Re-observar se a view mudar (importante p/ SPA) return () => { revealElements.forEach(el => observer.unobserve(el)); }; }, [view]); // Dispara novamente ao trocar de tela (landing -> portal etc) const switchTheme = () => { const newTheme = theme === 'dark' ? 'light' : 'dark'; setTheme(newTheme); document.documentElement.setAttribute('data-theme', newTheme); }; const handleLogin = (userData) => { localStorage.setItem('iaagro_user', JSON.stringify(userData)); setUser(userData); setView('portal'); }; const handleLogout = () => { localStorage.removeItem('iaagro_user'); setUser(null); setView('landing'); }; return ( {/* Botão Global de Tema - Efeito Glass Fixo */} {view === 'landing' && } {view === 'login' && } {view === 'register' && } {view === 'portal' && } {/* Botão de WhatsApp Flutuante */} {/* Sistema de Notificação Customizado */}
{notification.msg}
); } // === LANDING PAGE === function Landing({ onNavigate, theme, onSwitchTheme }) { const logoSrc = theme === 'dark' ? 'assets/logo-dark.svg' : 'assets/logo-light.svg'; const [menuOpen, setMenuOpen] = React.useState(false); const [activeDots, setActiveDots] = React.useState(1); // Foco no meio (index 1) const plansRef = React.useRef(null); React.useEffect(() => { // Focar no item do meio (Profissional) ao carregar se for mobile if (window.innerWidth <= 768 && plansRef.current) { const scrollWidth = plansRef.current.scrollWidth; plansRef.current.scrollLeft = (scrollWidth / 3); } }, []); const handleScroll = (e) => { if (window.innerWidth > 768) return; const scrollLeft = e.target.scrollLeft; const scrollWidth = e.target.scrollWidth - e.target.clientWidth; const percentage = scrollLeft / scrollWidth; let index = 1; if (percentage < 0.25) index = 0; else if (percentage > 0.75) index = 2; if (index !== activeDots) setActiveDots(index); }; return (

Revolucione a Emissão de
Notas Fiscais

Esqueça os sistemas complexos. Envie os dados direto pelo WhatsApp e nossa Inteligência Artificial preenche, valida e emite sua nota na hora.

{/* RECURSOS */}

Como a IAAGRO trabalha?

Um fluxo completo e automatizado, do campo até a Receita Federal.

1. Envio de Dados Simplificado

Mande uma mensagem de texto simples dos produtos vendidos e do comprador para o nosso WhatsApp.

2. Extração via IA

Nosso motor de PNL entende a linguagem rural, define os NCMs corretos, as alíquotas aplicáveis e as tributações exigidas.

3. Armazenamento Blindado (5 Anos)

Os XMLs e DANFEs são armazenados com segurança nos servidores da nuuv.cloud pelo tempo exigido por lei.

4. Painel para Contabilidade

Compartilhe acessos limitados para que seu contador consiga exportar relatórios instantâneos de todo período via portal web.

{/* PLANOS */}

Escolha seu Plano

Flexibilidade para todos os tamanhos de negócios e produtores rurais.

Iniciante

R$49
/mês
  • 50 Emissões mensais
  • Bot Básico do WhatsApp
  • Suporte por E-mail em 24h
Mais Escolhido

Profissional

R$129
/mês
  • Emissões Ilimitadas
  • Integração Inteligente via Texto
  • Armazenamento Legal (5 anos)
  • Sincronização Sefaz Direta

Cooperativa

R$299
/mês
  • Tudo do plano Profissional
  • Emissão Múltiplos CNPJs
  • Exportação p/ Lotes Contábeis
  • Relatórios Analíticos Gerenciais
{/* Paginação do Carrossel (Mobile Only) */}
{/* DEPOIMENTOS */}

O que dizem os produtores

Opiniões reais de quem já eliminou processos ultrapassados no agronegócio.

CA

Carlos Almeida

Fazenda Boa Esperança

“Antigamente eu perdia horas no computador puxando XML, era horrível estar no pasto e ter que voltar. Hoje eu mando um texto rápido pelo WhatsApp com os dados da carga, e a nota desponta no e-mail do cliente na mesma hora. Fantástico.”

MF

Marta Fidelis

Cooperativa Agrosul

“Conseguimos alocar a IAAGRO para operar notas de mais de 12 caminhões por dia. Basta digitar o pedido e a IA faz a conversão tributária exata, zeramos multas por esquecimento de regras estaduais complexas.”

RR

Rafael Rios

Engenheiro Agrônomo Independente

“A facilidade de emitir receitas técnicas e vincular faturamento apenas digitando no chat é surreal. A IA reconhece corretamente a descrição dos produtos fitossanitários com poucos caracteres. Recomendo muito.”

{/* FAQ E DUVIDAS */}

Dúvidas Frequentes

Nossa equipe está pronta para lhe integrar à nova era fiscal.

Preciso de um certificado digital para que funcione?

Sim. É requisito legal da Secretaria da Fazenda que toda empresa possua certificado A1 (.pfx) para gerar a assinatura digital nas transações financeiras. Após o upload o robô assume esta etapa por você.

É seguro enviar os dados das vendas pelo WhatsApp?

Absolutamente. Nosso tráfego emprega criptografia E2EE (ponta-a-ponta) e descartamos históricos temporais de conversão em áudio em servidores imediatamente após a geração do Danfe.

O bot do WhatsApp funciona aos finais de semana?

Sim! A automação operada em infraestrutura da IAAGRO está disponível 24 horas por dia, 7 dias por semana, sem intervenção humana, incluindo feriados nacionais.

E se a nota gerar um erro por informações enviadas erradas (Cancelamento)?

Você pode cancelar a NF-e solicitando por mensagem no chat. O próprio bot faz os testes com o Portal Sefaz, caso alguma variável (como valor e CPF incompatíveis) aconteça, o sistema vai pedir confirmação antes da emissão definitiva (draft).

{/* FOOTER OFICIAL NUUV*/}
); } // === LOGIN === function Login({ onNavigate, onLogin, theme, notify }) { const logoSrc = theme === 'dark' ? 'assets/logo-dark.svg' : 'assets/logo-light.svg'; const [phone, setPhone] = useState(''); const [password, setPassword] = useState(''); const [showPass, setShowPass] = useState(false); const handleSubmit = async (e) => { e.preventDefault(); if (!phone || !password) return notify("Preencha todos os campos.", "error"); try { const response = await fetch(`${API_URL}/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: phone.replace(/\D/g, ''), password }) }); const data = await response.json(); if (response.ok) { onLogin(data); notify("Bem-vindo ao IAAGRO!", "success"); } else { notify(data.error || "Erro ao fazer login.", "error"); } } catch (err) { notify("Erro ao conectar com o servidor.", "error"); } }; return (
IAAGRO

Acessar Portal

Emita suas notas via IA no WhatsApp

setPhone(e.target.value)} />
setPassword(e.target.value)} />
Ainda não é cliente?
); } // === REGISTER === function Register({ onNavigate, onLogin, theme, notify }) { const logoSrc = theme === 'dark' ? 'assets/logo-dark.svg' : 'assets/logo-light.svg'; const [formData, setFormData] = useState({ name: '', cpf: '', email: '', cnpj: '', phone: '', password: '', confirmPassword: '' }); const [showPass, setShowPass] = useState(false); const handleChange = (e) => { setFormData({ ...formData, [e.target.id]: e.target.value }); }; const handleSubmit = async (e) => { e.preventDefault(); if (!formData.name || !formData.email || !formData.cnpj || !formData.phone || !formData.password || !formData.cpf) { return notify("Preencha todos os campos.", "error"); } if (!validarCPF(formData.cpf)) { return notify("CPF Inválido. Digite um CPF correto.", "error"); } const erroSenha = validarSenha(formData.password); if (erroSenha) return notify(erroSenha, "error"); if (formData.password !== formData.confirmPassword) { return notify("As senhas não coincidem.", "error"); } try { const response = await fetch(`${API_URL}/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...formData, cpf: formData.cpf.replace(/\D/g, ''), phone: formData.phone.replace(/\D/g, '') }) }); const data = await response.json(); if (response.ok) { onLogin(data); notify("Cadastro realizado com sucesso!", "success"); } else { notify(data.error || "Erro ao registrar.", "error"); } } catch (err) { notify("Erro ao conectar com o servidor.", "error"); } }; return (
IAAGRO

Começar Grátis

Prepare sua conta e seu certificado A1

setFormData({ ...formData, cpf: e.target.value.replace(/\D/g, '') })} />
setFormData({ ...formData, cnpj: e.target.value.replace(/\D/g, '') })} />

Mínimo 8 caracteres, 1 maiúscula, números e símbolos.

Já possui conta?
); } // === PORTAL DASHBOARD === function Portal({ user, onLogout, theme, notify }) { const logoSrc = theme === 'dark' ? 'assets/logo-dark.svg' : 'assets/logo-light.svg'; const [tab, setTab] = useState('perfil'); return (
{/* Sidebar */}
{tab === 'notas' && } {tab === 'perfil' && } {tab === 'plano' && } {tab === 'autorizados' && }
); } function NotasView({ userId, notify }) { const [notas, setNotas] = useState([]); const [search, setSearch] = useState(''); const [dataInicio, setDataInicio] = useState(''); const [dataFim, setDataFim] = useState(''); const [selected, setSelected] = useState([]); useEffect(() => { const fetchNotas = async () => { try { const response = await fetch(`${API_URL}/notas?userId=${userId}`); const data = await response.json(); if (response.ok) { setNotas(data); } } catch (err) { console.error("Erro ao carregar notas."); } }; if (userId) fetchNotas(); }, [userId]); // Filtragem const filteredNotas = notas.filter(n => { let match = true; if (search && !n.numero.includes(search) && !n.chave.includes(search)) match = false; if (dataInicio && n.date < dataInicio) match = false; if (dataFim && n.date > dataFim) match = false; return match; }); const toggleSelectAll = (e) => { if (e.target.checked) setSelected(filteredNotas.map(n => n.id)); else setSelected([]); }; const toggleSelect = (id) => { if (selected.includes(id)) setSelected(selected.filter(s => s !== id)); else setSelected([...selected, id]); }; const handleDownload = (nota, type) => { const url = type === 'xml' ? nota.xml : nota.pdf; if (!url || url === '#') return notify("Arquivo não disponível.", "error"); window.open(url, '_blank'); }; const handleBulkDownload = (type) => { if (selected.length === 0) return notify("Selecione ao menos uma nota.", "error"); notify(`Preparando arquivo ZIP com ${selected.length} notas (${type.toUpperCase()})`, "success"); } const renderStatus = (nota) => { const temEvento = nota.status === 'Cancelada' || nota.status === 'Inutilizada' || (nota.eventos && nota.eventos.length > 0); if (temEvento) { return (
Aviso na Nota {nota.eventos && nota.eventos.length > 0 ? nota.eventos.join(', ') : nota.status}
); } return ; } return (

Notas Emitidas e Processadas

Histórico completo de transmissões via Secretaria da Fazenda.

Cota: {notas.length} registradas
setSearch(e.target.value)} />
setDataInicio(e.target.value)} />
setDataFim(e.target.value)} />
{filteredNotas.length > 0 ? ( {filteredNotas.map(n => ( ))}
0} style={{ width: '16px', height: '16px', cursor: 'pointer' }} /> Número Série Data Autorização Valor Bruto Status Sefaz Ações Fiscais Baixar Lote Único
toggleSelect(n.id)} style={{ width: '16px', height: '16px', cursor: 'pointer' }} /> {n.numero} {n.serie} {n.date.split('-').reverse().join('/')} {n.value} {renderStatus(n)}
) : (

Nenhuma nota encontrada nos filtros.

Seus apontamentos com IA ainda não geraram uma Sefaz oficial ou os filtros estão vazios.

)}
) } function PerfilView({ user, notify }) { const [cnpjData, setCnpjData] = useState(null); const [fetchingCnpj, setFetchingCnpj] = useState(false); const [codMunicipio, setCodMunicipio] = useState(null); const [fetchingCodMunicipio, setFetchingCodMunicipio] = useState(false); const [fileError, setFileError] = useState(''); const [isDrag, setIsDrag] = useState(false); const [showModal, setShowModal] = useState(false); const [correctionField, setCorrectionField] = useState('Razão Social'); const [correctionData, setCorrectionData] = useState(''); const [dropdownOpen, setDropdownOpen] = useState(false); const [certFile, setCertFile] = useState(null); const [certPass, setCertPass] = useState(''); const [saving, setSaving] = useState(false); const modalOptions = ["Razão Social", "Endereço / Logradouro", "Inscrição Estadual", "Natureza Jurídica", "Código IBGE"]; useEffect(() => { if (user.cnpj) { setFetchingCodMunicipio(true); const cleanCnpj = user.cnpj.replace(/\D/g, ''); fetch(`https://brasilapi.com.br/api/cnpj/v1/${cleanCnpj}`) .then(res => res.json()) .then(data => { if (data.razao_social) setCodMunicipio(data); }) .catch(err => console.log('Erro ao buscar código do município')) .finally(() => setFetchingCodMunicipio(false)); fetch(`https://api.opencnpj.org/${cleanCnpj}`) .then(res => res.json()) .then(data => { if (data.razao_social) setCnpjData(data); }) .catch(err => console.log('Erro ao buscar CNPJ (Usando Mock Local)')) .finally(() => setFetchingCnpj(false)); } }, [user.cnpj]); const processFile = (file) => { setFileError(''); if (file) { if (!file.name.toLowerCase().endsWith('.pfx')) { setFileError('Segurança: Arquivo rejeitado. Por favor, envie o certificado A1 original criptografado em .PFX.'); } else { setFileError('Sucesso: ' + file.name + ' anexado pronto para validação de senha.'); setCertFile(file); console.log("Certificado PFX aceito na checagem front-end", file); } } }; const handleDrag = (e) => { e.preventDefault(); e.stopPropagation(); if (e.type === 'dragenter' || e.type === 'dragover') setIsDrag(true); else setIsDrag(false); }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setIsDrag(false); if (e.dataTransfer.files && e.dataTransfer.files[0]) { processFile(e.dataTransfer.files[0]); } }; return (

Meu Perfil Físcal

Mantenha seus dados e certificados atualizados para o motor de Inteligência Artificial processar sem falhas.

{fetchingCnpj &&
Sincronizando metadados...
} {cnpjData && !fetchingCnpj && (
Dados da Empresa Sincronizados Oficialmente!

Dados retonados e validados do Emitente {cnpjData.razao_social}

)} {showModal && (

Solicitar Correção de Dado

setDropdownOpen(!dropdownOpen)} style={{ cursor: 'pointer', display: 'flex', justifyContent: 'space-between', alignItems: 'center', userSelect: 'none' }}> {correctionField}
{dropdownOpen && (
{modalOptions.map(opt => (
e.target.style.background = opt === correctionField ? 'var(--primary-color)' : 'rgba(128,128,128,0.1)'} onMouseLeave={(e) => e.target.style.background = opt === correctionField ? 'var(--primary-color)' : 'transparent'} style={{ padding: '0.8rem 1rem', borderRadius: '8px', cursor: 'pointer', transition: 'background 0.2s', backgroundColor: correctionField === opt ? 'var(--primary-color)' : 'transparent', color: correctionField === opt ? '#000' : 'var(--text-primary)', fontWeight: correctionField === opt ? '600' : 'normal', marginBottom: '2px' }} onClick={() => { setCorrectionField(opt); setDropdownOpen(false); }}> {opt}
))}
)}
)}

Dados Tributários (Portal Automático)

Certificado Digital Sefaz

Para habilitar o disparo criptografado das notas, faça o upload de seu arquivo .PFX Tipo A1 válido.

processFile(e.target.files[0])} className="drop-input" />

Arraste seu certificado .pfx aqui ou clique para procurar

{fileError &&

{fileError}

}
setCertPass(e.target.value)} />
); } function AuthorizedNumbersView({ userId, notify }) { const [numbers, setNumbers] = useState([]); const [loading, setLoading] = useState(true); const [newName, setNewName] = useState(''); const [newPhone, setNewPhone] = useState(''); const fetchNumbers = async () => { try { const res = await fetch(`${API_URL}/authorized-numbers/${userId}`); const data = await res.json(); setNumbers(data); } catch(err) { console.error(err); } finally { setLoading(false); } }; useEffect(() => { fetchNumbers(); }, []); const handleAdd = async (e) => { e.preventDefault(); if(!newName || !newPhone) return notify("Preencha nome e número.", "error"); try { const res = await fetch(`${API_URL}/authorized-numbers/add`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ userId, name: newName, phone: newPhone }) }); if(res.ok) { setNewName(''); setNewPhone(''); fetchNumbers(); notify("Número autorizado com sucesso!", "success"); } } catch(err) { console.error(err); } }; const handleDelete = async (id) => { if(!confirm("Deseja remover esta autorização?")) return; try { const res = await fetch(`${API_URL}/authorized-numbers/${id}`, { method: 'DELETE' }); if(res.ok) { fetchNumbers(); notify("Autorização removida.", "info"); } } catch(err) { console.error(err); } }; return (

Números Autorizados

Gerencie quem pode emitir notas fiscais pelo WhatsApp em seu nome.

Adicionar Nova Autorização

setNewName(e.target.value)} placeholder="Ex: João da Fazenda" />
setNewPhone(e.target.value)} placeholder="11999999999" />

Lista de Autorizados

{loading ?

Carregando...

: ( {numbers.map(n => ( ))} {numbers.length === 0 && ( )}
Nome Número (WhatsApp) Data Autorização Ações
{n.name} {n.phone} {new Date(n.created_at).toLocaleDateString()}
Ninguém autorizado ainda.
)}
); } function PlanoView({ user, notify }) { const [loading, setLoading] = useState(false); const [currentUser, setCurrentUser] = useState(user); const [showPayForm, setShowPayForm] = useState(null); // 'iniciante', 'profissional', etc const [cardData, setCardData] = useState({ holderName: '', number: '', expiry: '', cvv: '' }); useEffect(() => { // Atualiza dados do usuário para pegar plano/vencimento novo fetch(`${API_URL}/user/${user.id}`) .then(res => res.json()) .then(data => { if(data.id) setCurrentUser(data); }); }, []); const handleSubscribe = async (planKey) => { setLoading(true); try { const response = await fetch(`${API_URL}/subscription/checkout`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: user.id, planKey }) }); const data = await response.json(); if (response.ok) { if (data.invoiceUrl) { const width = 600; const height = 800; const left = (window.screen.width / 2) - (width / 2); const top = (window.screen.height / 2) - (height / 2); const popup = window.open(data.invoiceUrl, 'AsaasCheckout', `width=${width},height=${height},top=${top},left=${left}`); if (!popup || popup.closed || typeof popup.closed === 'undefined') { notify("Checkout bloqueado pelo navegador. Por favor, libere popups e tente novamente.", "error"); // Adicional: Abrir fallback em aba normal window.open(data.invoiceUrl, '_blank'); } else { notify("Janela de pagamento aberta! Aguarde a conclusão.", "info"); } // Polling para verificar quando o status muda para ACTIVE const checkStatus = setInterval(async () => { const res = await fetch(`${API_URL}/user/${user.id}`); const updated = await res.json(); if (updated.subscription_status === 'ACTIVE') { setCurrentUser(updated); notify("Pagamento confirmado! Plano ativado.", "success"); clearInterval(checkStatus); } }, 5000); // Limpar polling após 10 minutos setTimeout(() => clearInterval(checkStatus), 600000); } else { notify("Troca de plano agendada com sucesso! Você continuará usando o plano atual até o próximo ciclo.", "success"); } } else { notify(data.error || "Erro ao processar assinatura.", "error"); } } catch (err) { notify("Erro de conexão.", "error"); } finally { setLoading(false); } }; const isCurrentPlan = (key) => currentUser.plan_key === key; const isScheduled = (key) => currentUser.next_plan_key === key; return (

Gestão de Assinatura

Status atual: {currentUser.subscription_status === 'ACTIVE' ? `Pago - Válido até ${new Date(currentUser.due_date).toLocaleDateString()}` : 'Aguardando Pagamento / Inativo'}

Cota de Emissão: {currentUser.notes_used || 0} / {currentUser.notes_limit > 1000 ? 'Ilimitado' : (currentUser.notes_limit || 0)} notas

{isCurrentPlan('iniciante') &&
Seu Plano
}

Iniciante

R$49/mês
  • 50 Emissões/mês
  • Bot WhatsApp Básico
{isCurrentPlan('profissional') ?
Seu Plano
:
Recomendado
}

Profissional

R$129/mês
  • 100 Emissões/mês
  • Motor de IA Avançado
  • Sincroniza Sefaz
{isCurrentPlan('cooperativa') &&
Seu Plano
}

Cooperativa

R$299/mês
  • Múltiplos CNPJs
  • Relatórios p/ Contador
); } // === COMPONENTE DE FUNDO INTERATIVO === function InteractiveBackground() { const glowRef = React.useRef(null); const gridRef = React.useRef(null); useEffect(() => { let mouseX = window.innerWidth / 2; let mouseY = window.innerHeight / 2; const handleMouseMove = (e) => { mouseX = e.clientX; mouseY = e.clientY; }; window.addEventListener('mousemove', handleMouseMove); let animationFrameId; let currentX = mouseX; let currentY = mouseY; const render = () => { currentX += (mouseX - currentX) * 0.06; currentY += (mouseY - currentY) * 0.06; if (glowRef.current) { glowRef.current.style.transform = `translate(calc(${currentX}px - 50%), calc(${currentY}px - 50%))`; } if (gridRef.current) { // Mascara o GRID iluminando somente a área envolta do cursor dinamicamente const maskStyle = `radial-gradient(circle 350px at ${currentX}px ${currentY}px, black 0%, transparent 100%)`; gridRef.current.style.maskImage = maskStyle; gridRef.current.style.WebkitMaskImage = maskStyle; } animationFrameId = requestAnimationFrame(render); }; render(); return () => { window.removeEventListener('mousemove', handleMouseMove); cancelAnimationFrame(animationFrameId); }; }, []); return (
{/* O Grid Transparente que é revelado pelo mouse */}
{/* Orbe dinâmico de luz verde/neon */}
); } // Render do React const root = ReactDOM.createRoot(document.getElementById('root')); root.render();