// Multi-step modal — 3 steps + lead capture const CARGO_OPTIONS = [ "Founder/CEO", "CTO/Head de Tech", "CFO/Head Financeiro", "Head de Produto", "Diretor de Inovação", "Outro", ]; const SEGMENT_OPTIONS = [ { id: "marketplace", label: "Marketplace / Plataforma" }, { id: "saas", label: "SaaS / Software" }, { id: "varejo", label: "Varejo / E-commerce" }, { id: "educacao", label: "Educação / Health / Serviços" }, { id: "fintech", label: "Fintech / Banking" }, { id: "outro", label: "Outro" }, ]; const CLIENTES_OPTIONS = [ { id: "<500", label: "Menos de 500" }, { id: "500-2k", label: "500 a 2.000" }, { id: "2k-10k", label: "2.000 a 10.000" }, { id: "10k-50k", label: "10.000 a 50.000" }, { id: "50k+", label: "Mais de 50.000" }, ]; const FATURAMENTO_OPTIONS = [ { id: "<100k", label: "Até R$ 100k" }, { id: "100k-500k", label: "R$ 100k a R$ 500k" }, { id: "500k-2M", label: "R$ 500k a R$ 2M" }, { id: "2M-10M", label: "R$ 2M a R$ 10M" }, { id: "10M+", label: "Mais de R$ 10M" }, ]; function Chip({ selected, label, onClick }) { return ( ); } function ProductCard({ selected, product, onClick }) { return ( ); } // ---------- STEP 1: Business ---------- function Step1({ form, setForm }) { return (
Passo 1 de 3

Vamos calibrar pelo seu negócio

Três perguntas pra dimensionar a janela de receita. Nada é guardado — selecione e siga.

01 Segmento
Que tipo de negócio você tem?
{SEGMENT_OPTIONS.map(o => ( setForm({...form, segmento: o.id})}/> ))}
02 Tamanho da base
Quantos clientes ativos sua operação tem hoje?
{CLIENTES_OPTIONS.map(o => ( setForm({...form, clientes: o.id})}/> ))}
03 Faturamento
Qual seu faturamento mensal médio?
{FATURAMENTO_OPTIONS.map(o => ( setForm({...form, faturamento: o.id})}/> ))}
); } // ---------- STEP 2: Products ---------- function Step2({ form, setForm }) { const toggle = (pid) => { const has = form.produtos.includes(pid); const next = has ? form.produtos.filter(x => x !== pid) : [...form.produtos, pid]; setForm({...form, produtos: next}); }; return (
Passo 2 de 3

Quais frentes financeiras fazem sentido?

Escolha quantas quiser, pelo menos uma. A gente calcula a receita potencial em cada uma separadamente.

{PRODUCTS.map(p => ( toggle(p.id)}/> ))}
); } // ---------- Teaser animado Step 3 ---------- function CalcTeaser() { const [digits, setDigits] = React.useState("000.000,00"); React.useEffect(() => { let frame; const chars = "0123456789"; let tick = 0; const animate = () => { tick++; // gera número aleatório formatado que "parece" calculando const n = Math.floor(Math.random() * 9000000) + 100000; const fmt = n.toLocaleString("pt-BR", {minimumFractionDigits:2, maximumFractionDigits:2}); setDigits(fmt); if (tick < 18) frame = setTimeout(animate, tick < 8 ? 60 : tick < 14 ? 100 : 180); }; frame = setTimeout(animate, 300); return () => clearTimeout(frame); }, []); return (
Seu potencial estimado
R$ {digits}
Complete o cadastro para liberar
); } // ---------- STEP 3: Lead capture ---------- function Step3({ form, setForm, errors, setErrors }) { // live validate email const onEmail = (e) => { const v = e.target.value; setForm({...form, email: v}); if (errors.email) setErrors({...errors, email: undefined}); }; const onEmailBlur = () => { const v = form.email; if (!v) return; const r = validateEmail(v); if (!r.ok) { setErrors({...errors, email: r.kind}); } else if (errors.email) { setErrors({...errors, email: undefined}); } }; const emailMsg = (() => { if (errors.email === "personal") return { type: "info", msg: "Use o e-mail da empresa — é pra você receber o diagnóstico com qualidade" }; if (errors.email === "format") return { type: "err", msg: "E-mail inválido" }; if (errors.email === "empty") return { type: "err", msg: "Preenche aí" }; return null; })(); return (
Quase lá · Ver resultado

Complete para liberar seu potencial

Preencha seus dados para ver o número. Um especialista SH entra em contato para transformar esse potencial em plano real.

e.preventDefault()}>
{ setForm({...form, nome: e.target.value}); if(errors.nome) setErrors({...errors, nome: undefined}); }} /> {errors.nome &&
{errors.nome}
}
{emailMsg && ( emailMsg.type === "info" ?
{emailMsg.msg}
:
{emailMsg.msg}
)}
+55 { setForm({...form, whatsapp: maskPhone(e.target.value)}); if(errors.whatsapp) setErrors({...errors, whatsapp: undefined}); }} />
{errors.whatsapp &&
{errors.whatsapp}
}
{ setForm({...form, empresa: e.target.value}); if(errors.empresa) setErrors({...errors, empresa: undefined}); }} /> {errors.empresa &&
{errors.empresa}
}
{errors.cargo &&
{errors.cargo}
}
{errors.consent &&
{errors.consent}
}
); } // ---------- MODAL CONTAINER ---------- function CalcModal({ open, onClose, form, setForm, onSubmit }) { const [step, setStep] = React.useState(1); const [errors, setErrors] = React.useState({}); // reset step when modal closes React.useEffect(() => { if (!open) { setStep(1); setErrors({}); } }, [open]); // ESC to close React.useEffect(() => { if (!open) return; const h = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", h); return () => window.removeEventListener("keydown", h); }, [open, onClose]); if (!open) return null; const step1Done = !!form.segmento && !!form.clientes && !!form.faturamento; const step2Done = form.produtos.length >= 1; // step 3 form validity const emailRes = validateEmail(form.email); const step3Done = form.nome.trim().length >= 3 && emailRes.ok && isPhoneValid(form.whatsapp) && form.empresa.trim().length >= 2 && !!form.cargo && !!form.consent; const progress = step === 1 ? 33 : step === 2 ? 66 : 100; const validateStep3 = () => { const errs = {}; if (form.nome.trim().length < 3) errs.nome = "Preenche aí (mín. 3 chars)"; const er = validateEmail(form.email); if (!er.ok) errs.email = er.kind; if (!isPhoneValid(form.whatsapp)) errs.whatsapp = "Número incompleto"; if (form.empresa.trim().length < 2) errs.empresa = "Preenche aí"; if (!form.cargo) errs.cargo = "Selecione um cargo"; if (!form.consent) errs.consent = "É preciso aceitar pra liberar o resultado"; setErrors(errs); return Object.keys(errs).length === 0; }; const next = () => { if (step === 1 && step1Done) setStep(2); else if (step === 2 && step2Done) setStep(3); else if (step === 3) { if (validateStep3()) onSubmit(); } }; const back = () => { if (step > 1) setStep(step - 1); }; const onBackdrop = (e) => { if (e.target === e.currentTarget) onClose(); }; return (
Passo {step} de 3
{step === 1 && } {step === 2 && } {step === 3 && }
{step > 1 ? ( ) :
// 90 segundos · sem spam
}
); } Object.assign(window, { CalcModal });