"use client"; import { useState, useEffect } from "react"; import Link from "next/link"; import { Input, Checkbox, Button, Select, SearchableSelect } from "@/components/ui"; import toast, { Toaster } from 'react-hot-toast'; import DynamicBranding from "@/components/cadastro/DynamicBranding"; import DashboardPreview from "@/components/cadastro/DashboardPreview"; import { saveAuth } from '@/lib/auth'; import { API_ENDPOINTS, apiRequest } from '@/lib/api'; import dynamic from 'next/dynamic'; const ThemeToggle = dynamic(() => import('@/components/ThemeToggle'), { ssr: false }); interface ContactField { id: number; whatsapp: string; } export default function CadastroPage() { const [currentStep, setCurrentStep] = useState(1); const [completedSteps, setCompletedSteps] = useState([]); const [formData, setFormData] = useState>({}); const [contacts, setContacts] = useState([{ id: 1, whatsapp: "" }]); const [password, setPassword] = useState(""); const [passwordStrength, setPasswordStrength] = useState(0); const [cnpjData, setCnpjData] = useState({ razaoSocial: "", endereco: "" }); const [cepData, setCepData] = useState({ state: "", city: "", neighborhood: "", street: "" }); const [loadingCnpj, setLoadingCnpj] = useState(false); const [loadingCep, setLoadingCep] = useState(false); const [subdomain, setSubdomain] = useState(""); const [domainAvailable, setDomainAvailable] = useState(null); const [checkingDomain, setCheckingDomain] = useState(false); const [primaryColor, setPrimaryColor] = useState("#FF3A05"); const [secondaryColor, setSecondaryColor] = useState("#FF0080"); const [logoUrl, setLogoUrl] = useState(""); const [showPreviewMobile, setShowPreviewMobile] = useState(false); // Carregar dados do localStorage ao montar useEffect(() => { const saved = localStorage.getItem('cadastroFormData'); if (saved) { try { const data = JSON.parse(saved); setCurrentStep(data.currentStep || 1); setCompletedSteps(data.completedSteps || []); setFormData(data.formData || {}); setContacts(data.contacts || [{ id: 1, whatsapp: "" }]); setPassword(data.password || ""); setPasswordStrength(data.passwordStrength || 0); setCnpjData(data.cnpjData || { razaoSocial: "", endereco: "" }); setCepData(data.cepData || { state: "", city: "", neighborhood: "", street: "" }); setSubdomain(data.subdomain || ""); setDomainAvailable(data.domainAvailable ?? null); setPrimaryColor(data.primaryColor || "#FF3A05"); setSecondaryColor(data.secondaryColor || "#FF0080"); setLogoUrl(data.logoUrl || ""); } catch (error) { console.error('Erro ao carregar dados:', error); } } }, []); // Salvar no localStorage sempre que houver mudanças useEffect(() => { const dataToSave = { currentStep, completedSteps, formData, contacts, password, passwordStrength, cnpjData, cepData, subdomain, domainAvailable, primaryColor, secondaryColor, logoUrl }; localStorage.setItem('cadastroFormData', JSON.stringify(dataToSave)); }, [currentStep, completedSteps, formData, contacts, password, passwordStrength, cnpjData, cepData, subdomain, domainAvailable, primaryColor, secondaryColor, logoUrl]); // Função para atualizar formData const updateFormData = (name: string, value: any) => { setFormData(prev => ({ ...prev, [name]: value })); }; const steps = [ { number: 1, title: "Dados Pessoais", heading: "Seus Dados Pessoais", description: "Informe seus dados para criar sua conta de administrador." }, { number: 2, title: "Empresa", heading: "Dados da Empresa", description: "Cadastre as informações básicas da sua empresa." }, { number: 3, title: "Localização e Contato", heading: "Endereço e Contato", description: "Informe a localização da sua empresa e os contatos para comunicação." }, { number: 4, title: "Domínio", heading: "Escolha seu Domínio", description: "Defina o endereço único para acessar o painel da sua empresa." }, { number: 5, title: "Personalização", heading: "Personalize seu Painel", description: "Configure as cores e identidade visual da sua empresa." }, ]; const currentStepData = steps.find(s => s.number === currentStep); const validateCurrentStep = () => { const form = document.querySelector('form') || document; const inputs = form.querySelectorAll('input[required], select[required], textarea[required]'); // Mapeamento de nomes de campos para labels amigáveis const fieldLabels: Record = { fullName: 'Nome Completo', email: 'E-mail', password: 'Senha', confirmPassword: 'Confirmar Senha', terms: 'Termos de Uso', companyName: 'Nome da Empresa', cnpj: 'CNPJ', description: 'Descrição', industry: 'Segmento', teamSize: 'Tamanho da Equipe', cep: 'CEP', state: 'Estado', city: 'Cidade', neighborhood: 'Bairro', street: 'Rua', number: 'Número', domain: 'Domínio', }; for (const input of inputs) { const element = input as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; if (!element.value || element.value.trim() === '') { const fieldName = element.getAttribute('name') || ''; // Tratamento especial para campos de WhatsApp let fieldLabel = fieldLabels[fieldName]; if (fieldName.startsWith('whatsapp-')) { fieldLabel = 'WhatsApp'; } else { fieldLabel = fieldLabel || 'Este campo'; } toast.error(`O campo "${fieldLabel}" é obrigatório e precisa ser preenchido.`); element.focus(); return false; } } // Validações específicas por etapa if (currentStep === 1) { if (!formData.fullName || formData.fullName.trim().length < 3) { toast.error('Por favor, insira seu nome completo (mínimo 3 caracteres).'); return false; } if (!formData.email || !formData.email.includes('@')) { toast.error('Por favor, insira um email válido. Exemplo: seu@email.com'); return false; } if (password.length < 8) { toast.error('A senha deve ter no mínimo 8 caracteres para maior segurança.'); return false; } if (passwordStrength < 2) { toast.error('Sua senha está muito fraca. Use maiúsculas, minúsculas, números e símbolos.'); return false; } if (password !== formData.confirmPassword) { toast.error('As senhas não coincidem. Por favor, digite a mesma senha nos dois campos.'); return false; } if (!formData.terms) { toast.error('Você precisa aceitar os Termos de Uso para continuar o cadastro.'); return false; } } if (currentStep === 2) { if (!formData.companyName || formData.companyName.trim().length < 3) { toast.error('O nome da empresa deve ter pelo menos 3 caracteres.'); return false; } const cnpjNumbers = formData.cnpj?.replace(/\D/g, '') || ''; if (cnpjNumbers.length !== 14) { toast.error(`CNPJ incompleto. Digite os 14 dígitos (você digitou ${cnpjNumbers.length}).`); return false; } if (!formData.description || formData.description.trim().length < 10) { toast.error('A descrição da empresa deve ter pelo menos 10 caracteres.'); return false; } if (!formData.industry) { toast.error('Por favor, selecione o segmento/indústria da sua empresa.'); return false; } if (!formData.teamSize) { toast.error('Por favor, selecione o tamanho da equipe da sua empresa.'); return false; } } if (currentStep === 3) { const cepNumbers = formData.cep?.replace(/\D/g, '') || ''; if (cepNumbers.length !== 8) { toast.error(`CEP incompleto. Digite os 8 dígitos (você digitou ${cepNumbers.length}).`); return false; } if (!cepData.state || cepData.state.length !== 2) { toast.error('Digite a sigla do estado (UF) com 2 letras. Exemplo: SP, RJ, MG'); return false; } if (!cepData.city || cepData.city.trim().length < 2) { toast.error('Digite o nome da cidade.'); return false; } if (!cepData.neighborhood || cepData.neighborhood.trim().length < 2) { toast.error('Digite o nome do bairro.'); return false; } if (!cepData.street || cepData.street.trim().length < 3) { toast.error('Digite o nome da rua/avenida.'); return false; } if (!formData.number || formData.number.trim().length < 1) { toast.error('Número do endereço não preenchido.'); return false; } // Validar contatos da empresa for (let i = 0; i < contacts.length; i++) { if (!contacts[i].whatsapp || contacts[i].whatsapp.replace(/\D/g, '').length < 10) { toast.error(`WhatsApp não preenchido ou incompleto. Digite um número válido com DDD.`); return false; } } } if (currentStep === 4) { if (!subdomain || subdomain.trim().length < 3) { toast.error('O subdomínio deve ter pelo menos 3 caracteres. Exemplo: minhaempresa'); return false; } if (!/^[a-z0-9-]+$/.test(subdomain)) { toast.error('O subdomínio deve conter apenas letras minúsculas, números e hífens.'); return false; } if (domainAvailable === false) { toast.error('Este subdomínio já está em uso. Escolha outro.'); return false; } if (domainAvailable === null) { toast.error('Aguarde a verificação de disponibilidade do domínio.'); return false; } } return true; }; const handleSubmitRegistration = async () => { try { const payload = { // Dados da agência agencyName: formData.companyName, subdomain: subdomain, cnpj: formData.cnpj, razaoSocial: formData.razaoSocial, description: formData.description, website: formData.website, industry: formData.industry, // Endereço cep: formData.cep, state: formData.state, city: formData.city, neighborhood: formData.neighborhood, street: formData.street, number: formData.number, complement: formData.complement, // Admin adminEmail: formData.email, adminPassword: password, adminName: formData.fullName, }; console.log('📤 Enviando cadastro completo:', payload); toast.loading('Criando sua conta...', { id: 'register' }); const response = await fetch('/api/admin/agencies', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'Erro ao criar conta'); } const data = await response.json(); console.log('📥 Resposta data:', data); // Salvar autenticação if (data.token) { saveAuth(data.token, { id: data.id, email: data.email, name: data.name, role: data.role || 'ADMIN_AGENCIA', tenantId: data.tenantId, company: data.company, subdomain: data.subdomain }); } // Sucesso - limpar localStorage do form localStorage.removeItem('cadastroFormData'); toast.success('Conta criada com sucesso! Redirecionando para seu painel...', { id: 'register', duration: 2000, style: { background: '#10B981', color: '#fff', }, }); // Redirecionar para o painel da agência no subdomínio setTimeout(() => { const agencyUrl = `http://${data.subdomain}.localhost/login`; window.location.href = agencyUrl; }, 2000); } catch (error: any) { console.error('❌ Erro no cadastro:', error); toast.error(error.message || 'Erro ao criar conta. Tente novamente.', { id: 'register', }); } }; // MODO TESTE - Preencher dados automaticamente const fillTestData = () => { const testData = { fullName: "Teste Usuario", email: "teste@idealpages.com", confirmPassword: "senha12345", terms: true, newsletter: false, companyName: "IdealPages", cnpj: "12.345.678/0001-90", description: "Agência de desenvolvimento web e aplicativos mobile especializada em soluções digitais", website: "https://idealpages.com", industry: "agencia-digital", teamSize: "1-10", cep: "01310-100", number: "123", complement: "Sala 101", }; setFormData(testData); setPassword("senha12345"); setPasswordStrength(4); setCnpjData({ razaoSocial: "IdealPages LTDA", endereco: "Av Paulista, 1000" }); setCepData({ state: "SP", city: "São Paulo", neighborhood: "Bela Vista", street: "Av Paulista" }); setContacts([{ id: 1, whatsapp: "(11) 98765-4321" }]); setSubdomain("idealpages"); setDomainAvailable(true); setPrimaryColor("#FF3A05"); setSecondaryColor("#FF0080"); // Marcar todos os steps como completos e ir pro step 5 setCompletedSteps([1, 2, 3, 4]); setCurrentStep(5); toast.success('Dados de teste preenchidos! Clique em Finalizar.', { duration: 3000, }); }; const handleNext = (e?: React.FormEvent) => { if (e) { e.preventDefault(); } if (!validateCurrentStep()) { return; } if (currentStep < 5) { setCompletedSteps([...completedSteps, currentStep]); setCurrentStep(currentStep + 1); } else { // Última etapa - enviar dados para o backend handleSubmitRegistration(); } }; const addContact = () => { const newId = contacts.length > 0 ? Math.max(...contacts.map(c => c.id)) + 1 : 1; setContacts([...contacts, { id: newId, whatsapp: "" }]); }; const removeContact = (id: number) => { if (contacts.length > 1) { setContacts(contacts.filter(c => c.id !== id)); } }; const formatPhone = (value: string) => { const numbers = value.replace(/\D/g, ""); if (numbers.length <= 10) { return numbers.replace(/(\d{2})(\d{4})(\d{0,4})/, "($1) $2-$3").replace(/-$/, ""); } return numbers.replace(/(\d{2})(\d{5})(\d{0,4})/, "($1) $2-$3").replace(/-$/, ""); }; const calculatePasswordStrength = (pwd: string): number => { let strength = 0; if (pwd.length >= 8) strength++; if (pwd.length >= 12) strength++; if (/[a-z]/.test(pwd) && /[A-Z]/.test(pwd)) strength++; if (/\d/.test(pwd)) strength++; if (/[^a-zA-Z0-9]/.test(pwd)) strength++; return strength; }; const checkDomainAvailability = async (domain: string) => { if (!domain || domain.length < 3) { setDomainAvailable(null); return; } if (!/^[a-z0-9-]+$/.test(domain)) { setDomainAvailable(null); toast.error('Domínio inválido. Use apenas letras minúsculas, números e hífens.'); return; } setCheckingDomain(true); setDomainAvailable(null); try { // Simulação de verificação - substituir pela API real await new Promise(resolve => setTimeout(resolve, 1000)); // Lista de domínios já ocupados (exemplo) const unavailableDomains = ['teste', 'demo', 'admin', 'api', 'app', 'www']; const isAvailable = !unavailableDomains.includes(domain.toLowerCase()); setDomainAvailable(isAvailable); if (isAvailable) { toast.success(`✓ ${domain}.aggios.app está disponível!`, { duration: 3000, style: { background: '#10B981', color: '#fff', }, }); } else { toast.error(`✗ ${domain}.aggios.app já está em uso. Tente outro.`, { duration: 3000, }); } } catch (error) { toast.error('Erro ao verificar disponibilidade. Tente novamente.'); setDomainAvailable(null); } finally { setCheckingDomain(false); } }; const handlePasswordChange = (e: React.ChangeEvent) => { const newPassword = e.target.value; setPassword(newPassword); setPasswordStrength(calculatePasswordStrength(newPassword)); }; const getPasswordStrengthLabel = () => { if (password.length === 0) return ""; if (passwordStrength <= 1) return "Muito fraca"; if (passwordStrength === 2) return "Fraca"; if (passwordStrength === 3) return "Média"; if (passwordStrength === 4) return "Forte"; return "Muito forte"; }; const getPasswordStrengthColor = () => { if (passwordStrength <= 1) return "#EF4444"; if (passwordStrength === 2) return "#F59E0B"; if (passwordStrength === 3) return "#3B82F6"; if (passwordStrength === 4) return "#10B981"; return "#059669"; }; const fetchCnpjData = async (cnpj: string) => { const numbers = cnpj.replace(/\D/g, ""); if (numbers.length !== 14) return; setLoadingCnpj(true); try { const response = await fetch(`https://brasilapi.com.br/api/cnpj/v1/${numbers}`); if (response.ok) { const data = await response.json(); setCnpjData({ razaoSocial: data.razao_social || "", endereco: `${data.logradouro}, ${data.numero} - ${data.bairro}, ${data.municipio}/${data.uf}` }); } } catch (error) { console.error("Erro ao buscar CNPJ:", error); } finally { setLoadingCnpj(false); } }; const fetchCepData = async (cep: string) => { const numbers = cep.replace(/\D/g, ""); if (numbers.length !== 8) return; setLoadingCep(true); try { const response = await fetch(`https://viacep.com.br/ws/${numbers}/json/`); if (response.ok) { const data = await response.json(); if (!data.erro) { setCepData({ state: data.uf || "", city: data.localidade || "", neighborhood: data.bairro || "", street: data.logradouro || "" }); } } } catch (error) { console.error("Erro ao buscar CEP:", error); } finally { setLoadingCep(false); } }; const formatCnpj = (value: string) => { const numbers = value.replace(/\D/g, ""); return numbers.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5").substring(0, 18); }; const formatCep = (value: string) => { const numbers = value.replace(/\D/g, ""); return numbers.replace(/(\d{5})(\d{3})/, "$1-$2").substring(0, 9); }; return ( <>
{/* Lado Esquerdo - Formulário */}
{/* Título e texto */}
{/* Theme Toggle */}
{/* Progresso Circular */}
{Math.round((currentStep / 5) * 100)}%
{/* Título e Descrição */}

{currentStepData?.heading}

{currentStepData?.description}

{/* Formulário */}
{ e.preventDefault(); handleNext(e); }} className="space-y-6"> {currentStep === 1 && (
updateFormData('fullName', e.target.value)} required /> updateFormData('email', e.target.value)} required /> {/* Separador de seção */}

Crie sua senha de acesso

{password.length > 0 && (
Força da senha: {getPasswordStrengthLabel()}
)}
updateFormData('confirmPassword', e.target.value)} required />
updateFormData('terms', e.target.checked)} label={ Concordo com os{" "} Termos de Uso } /> updateFormData('newsletter', e.target.checked)} /> {/* Link para login */}

Já possui uma conta?{" "} Fazer login

)} {currentStep === 2 && (
updateFormData('companyName', e.target.value)} required /> { const formatted = formatCnpj(e.target.value); updateFormData('cnpj', formatted); if (formatted.replace(/\D/g, "").length === 14) { fetchCnpjData(formatted); } }} required />