From 4942bfd58553f509675a7468364459a43e9ef5ac Mon Sep 17 00:00:00 2001 From: Marcio Bevervanso Date: Wed, 17 Jun 2026 13:45:31 -0300 Subject: [PATCH] Adiciona rota /funil com conteudo adaptado para Kit Festa R$19,99 - Rota /funil adicionada ao App.tsx - Preco e creditos atualizados: R$19,99 / 30 creditos - Checkout aponta para plan=popular Co-Authored-By: Claude Sonnet 4.6 --- src/App.tsx | 2 + src/pages/WhatsAppFunnel.tsx | 463 +++++++++++++++++++++++++++++++++++ 2 files changed, 465 insertions(+) create mode 100644 src/pages/WhatsAppFunnel.tsx diff --git a/src/App.tsx b/src/App.tsx index 20e15da..5ec0875 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; import LandingPage from './pages/LandingPage'; import SuccessPage from './pages/SuccessPage'; +import WhatsAppFunnel from './pages/WhatsAppFunnel'; export default function App() { return ( @@ -8,6 +9,7 @@ export default function App() { } /> } /> + } /> ); diff --git a/src/pages/WhatsAppFunnel.tsx b/src/pages/WhatsAppFunnel.tsx new file mode 100644 index 0000000..0a01f60 --- /dev/null +++ b/src/pages/WhatsAppFunnel.tsx @@ -0,0 +1,463 @@ +import { useState, useEffect, useRef, type FormEvent } from 'react'; +import { Loader2, Send } from 'lucide-react'; + +type MessageType = 'text' | 'audio' | 'image' | 'video' | 'embed'; + +interface MessageConfig { + text: string; + delay?: number; + type?: MessageType; +} + +interface OptionConfig { + text: string; + nextId?: string; + actionLink?: string; +} + +interface FunnelNode { + id: string; + messages: MessageConfig[]; + options?: OptionConfig[]; + requireEmail?: boolean; +} + +interface RenderedMessage { + id: string; + sender: 'bot' | 'user'; + type: MessageType; + content: string; +} + +const funnelData: FunnelNode[] = [ + { + id: "start", + messages: [ + { text: "Oi! 👋 Tudo bem? Sou do atendimento da Festa MĂĄgica IA.", delay: 1000, type: "text" }, + { text: "Posso te mostrar rapidinho como criar a festa do seu filho gastando muito menos?", delay: 1500, type: "text" } + ], + options: [ + { text: "Pode!", nextId: "step2" }, + { text: "Como assim?", nextId: "step2" }, + { text: "JĂĄ conheço, quero comprar agora", nextId: "step4" } + ] + }, + { + id: "step2", + messages: [ + { text: "Mandar fazer personalizados Ă© caro e demora, nĂ©?", delay: 1800, type: "text" }, + { text: "Nossa InteligĂȘncia Artificial permite que vocĂȘ mesmo faça tudo na hora, do celular.", delay: 2000, type: "text" }, + { text: "Assiste esse vĂ­deo aqui embaixo que mostra a ferramenta funcionando e como Ă© fĂĄcil criar as imagens e os kits👇", delay: 1500, type: "text" }, + { text: "https://s3.seureview.com.br/festamagica/0510(2).mp4", delay: 2000, type: "video" } + ], + options: [ + { text: "Que legal!", nextId: "step3" } + ] + }, + { + id: "step3", + messages: [ + { text: "Legal nĂ©? A IA cria um personagem 3D super realista tipo Disney/Pixar com o rostinho dele(a)!", delay: 1800, type: "text" }, + { text: "Olha essa transformação real que a gente fez aqui — essa Ă© a foto original do Miguel, filho da nossa fundadora:", delay: 1500, type: "text" }, + { text: "/images/antes-depois/miguel-real.webp", delay: 1500, type: "image" }, + { text: "E esse foi o personagem 3D que a nossa IA criou com o rostinho dele, pronto pra virar topo de bolo, convite, adesivo... tudo no tema! đŸ€©", delay: 1800, type: "text" }, + { text: "/images/antes-depois/miguel-avatar.webp", delay: 1800, type: "image" }, + { text: "MĂĄgico, nĂ©? E ela jĂĄ gera todos os arquivos em PDF prontinhos pra imprimir.", delay: 1800, type: "text" } + ], + options: [ + { text: "Amei! Quanto custa?", nextId: "step4" } + ] + }, + { + id: "step4", + messages: [ + { text: "Bem menos que vocĂȘ imagina! đŸ„°", delay: 1200, type: "text" }, + { text: "Liberamos o Kit Festa completo por apenas R$ 19,99 (pagamento Ășnico).", delay: 1500, type: "text" }, + { text: "VocĂȘ jĂĄ entra com 30 crĂ©ditos pra gerar os itens que quiser — e a primeira imagem Ă© por nossa conta, nĂŁo consome nenhum crĂ©dito seu! 🎁", delay: 1800, type: "text" }, + { text: "Quer garantir o seu agora?", delay: 1200, type: "text" } + ], + options: [ + { text: "Eu quero!", nextId: "checkout_step" } + ] + }, + { + id: "checkout_step", + messages: [ + { text: "Ótimo! Pra gente gerar o seu acesso seguro, qual Ă© o seu melhor e-mail?", delay: 1000, type: "text" } + ], + requireEmail: true + } +]; + +let sharedAudioCtx: AudioContext | null = null; +function getAudioContext() { + if (!sharedAudioCtx) { + const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext; + if (AudioContextClass) { + sharedAudioCtx = new AudioContextClass(); + } + } + return sharedAudioCtx; +} + +const FUNNEL_STORAGE_KEY = 'fm_whatsapp_funnel_state'; + +function loadSavedFunnelState() { + try { + const raw = localStorage.getItem(FUNNEL_STORAGE_KEY); + if (!raw) return null; + const parsed = JSON.parse(raw); + if (Array.isArray(parsed.messages) && parsed.messages.length > 0) return parsed; + } catch (e) {} + return null; +} + +function playMessageSound() { + try { + const ctx = getAudioContext(); + if (!ctx) return; + if (ctx.state === 'suspended') ctx.resume(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.type = 'sine'; + osc.frequency.setValueAtTime(800, ctx.currentTime); + osc.frequency.exponentialRampToValueAtTime(300, ctx.currentTime + 0.1); + gain.gain.setValueAtTime(0.2, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.1); + osc.start(ctx.currentTime); + osc.stop(ctx.currentTime + 0.1); + } catch (e) {} +} + +function playTypingSound() { + try { + const ctx = getAudioContext(); + if (!ctx) return; + if (ctx.state === 'suspended') ctx.resume(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.type = 'triangle'; + osc.frequency.setValueAtTime(200, ctx.currentTime); + gain.gain.setValueAtTime(0.01, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.05); + osc.start(ctx.currentTime); + osc.stop(ctx.currentTime + 0.05); + } catch (e) {} +} + +export default function WhatsAppFunnel() { + const [messages, setMessages] = useState([]); + const [isTyping, setIsTyping] = useState(false); + const [currentOptions, setCurrentOptions] = useState([]); + const [currentRequireEmail, setCurrentRequireEmail] = useState(false); + const [emailInput, setEmailInput] = useState(''); + const [isLoadingCheckout, setIsLoadingCheckout] = useState(false); + + const chatEndRef = useRef(null); + + const scrollToBottom = () => { + setTimeout(() => { + chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, 100); + }; + + const playNode = async (nodeId: string) => { + setCurrentOptions([]); + setCurrentRequireEmail(false); + + const node = funnelData.find((n) => n.id === nodeId); + if (!node) return; + + for (let i = 0; i < node.messages.length; i++) { + const msg = node.messages[i]; + + const delayBefore = msg.delay + ? msg.delay + : ((msg.type && msg.type !== 'text') ? 1500 : Math.min(400 + (msg.text.length * 30), 3000)); + + setIsTyping(true); + scrollToBottom(); + + const typingInterval = setInterval(() => { + if (Math.random() > 0.3) playTypingSound(); + }, 150); + + await new Promise((r) => setTimeout(r, delayBefore)); + + clearInterval(typingInterval); + setIsTyping(false); + + playMessageSound(); + setMessages((prev) => [ + ...prev, + { + id: Math.random().toString(), + sender: 'bot', + type: msg.type || 'text', + content: msg.text, + }, + ]); + scrollToBottom(); + + await new Promise((r) => setTimeout(r, 400)); + } + + if (node.options && node.options.length > 0) { + setCurrentOptions(node.options); + scrollToBottom(); + } + if (node.requireEmail) { + setCurrentRequireEmail(true); + scrollToBottom(); + } + }; + + const initialized = useRef(false); + + useEffect(() => { + if (!initialized.current) { + initialized.current = true; + getAudioContext(); + + const saved = loadSavedFunnelState(); + if (saved) { + setMessages(saved.messages); + setCurrentOptions(saved.currentOptions || []); + setCurrentRequireEmail(saved.currentRequireEmail || false); + scrollToBottom(); + } else { + playNode('start'); + } + } + }, []); + + // Salva o progresso da conversa para retomar de onde parou caso a pĂĄgina recarregue + useEffect(() => { + if (messages.length === 0) return; + try { + localStorage.setItem(FUNNEL_STORAGE_KEY, JSON.stringify({ + messages, + currentOptions, + currentRequireEmail, + })); + } catch (e) {} + }, [messages, currentOptions, currentRequireEmail]); + + const handleOptionClick = (opt: OptionConfig) => { + const ctx = getAudioContext(); + if (ctx && ctx.state === 'suspended') { + ctx.resume(); + } + + setMessages((prev) => [ + ...prev, + { + id: Math.random().toString(), + sender: 'user', + type: 'text', + content: opt.text, + }, + ]); + + setCurrentOptions([]); + scrollToBottom(); + + if (opt.actionLink) { + setTimeout(() => { + window.location.href = opt.actionLink!; + }, 800); + } else if (opt.nextId) { + setTimeout(() => { + playNode(opt.nextId!); + }, 600); + } + }; + + const handleEmailSubmit = async (e: FormEvent) => { + e.preventDefault(); + if (!emailInput) return; + + // Add user email message and a bot "loading" message + setMessages((prev) => [ + ...prev, + { + id: Math.random().toString(), + sender: 'user', + type: 'text', + content: emailInput, + }, + { + id: 'loading-checkout', + sender: 'bot', + type: 'text', + content: 'Perfeito! Abrindo o checkout seguro pra vocĂȘ 🎉', + } + ]); + + setCurrentRequireEmail(false); + setIsLoadingCheckout(true); + scrollToBottom(); + + if (typeof window !== 'undefined' && 'fbq' in window) { + (window as any).fbq('track', 'InitiateCheckout'); + } + + setTimeout(() => { + window.location.href = `https://festamagicaia.com.br/checkout?plan=popular&source=funil-30&email=${encodeURIComponent(emailInput)}`; + }, 800); + }; + + const renderMessageContent = (m: RenderedMessage) => { + if (m.type === 'image') { + return ( + Media + ); + } else if (m.type === 'video') { + return ( +