From da4f3195b7e575a0329da01f5e87c6fc7dac0554 Mon Sep 17 00:00:00 2001 From: Marcio Bevervanso Date: Thu, 9 Jul 2026 15:19:05 -0300 Subject: [PATCH] chore: CRO na oferta/galeria + remove rotas mortas do checkout antigo Ancora de preco e galeria reduzida na oferta. Remove /checkout e /sucesso (fluxo Woovi antigo, sem nenhum botao apontando pra eles -- compra real ja redireciona pro checkout Efi do site principal). Corrige texto EN/ES que ainda citava Stripe (fluxo intl tambem e Efi). Co-Authored-By: Claude Sonnet 5 --- src/App.tsx | 4 - src/components/Gallery.tsx | 16 +- src/components/Offer.tsx | 4 +- src/i18n.ts | 60 +--- src/pages/Checkout.tsx | 625 ----------------------------------- src/pages/SuccessPage.tsx | 80 ----- src/services/wooviService.ts | 98 ------ 7 files changed, 25 insertions(+), 862 deletions(-) delete mode 100644 src/pages/Checkout.tsx delete mode 100644 src/pages/SuccessPage.tsx delete mode 100644 src/services/wooviService.ts diff --git a/src/App.tsx b/src/App.tsx index 5f7ef30..0ffd41c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,17 +1,13 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; import LandingPage from './pages/LandingPage'; -import SuccessPage from './pages/SuccessPage'; import WhatsAppFunnel from './pages/WhatsAppFunnel'; -import Checkout from './pages/Checkout'; export default function App() { return ( } /> - } /> } /> - } /> ); diff --git a/src/components/Gallery.tsx b/src/components/Gallery.tsx index 5dbf155..37c53ab 100644 --- a/src/components/Gallery.tsx +++ b/src/components/Gallery.tsx @@ -4,27 +4,15 @@ import { useT } from '../i18n'; export default function Gallery() { const t = useT(); - const BASE = "https://s3.seureview.com.br/festamagica/6a591904-cf2a-4a51-8581-1891373eea29"; - const images = [ { src: "/images/galeria-real/topo-de-bolo.webp", title: "Topo de Bolo 3D", desc: "Destaque na mesa do bolo" }, { src: "/images/galeria-real/painel-de-fundo.webp", title: "Painel de Fundo", desc: "Transforma o cenário da festa" }, - { src: `${BASE}/008417cf-b15a-4c4e-ac95-c75b69ec3525/convite-premium.webp`, title: "Convite Premium", desc: "Para impressão ou envio digital" }, { src: "/images/galeria-real/caixa-de-pipoca.webp", title: "Caixa de Pipoca", desc: "A alegria garantida no lanche" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/bandeirolas-com-nome.webp`, title: "Bandeirolas com Nome", desc: "Varal decorativo personalizado" }, { src: "/images/galeria-real/convite-digital.webp", title: "Convite Digital", desc: "Para enviar no WhatsApp" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/caixa-milk.webp`, title: "Caixa Milk", desc: "Lembrancinha charmosa" }, { src: "/images/galeria-real/saia-de-cupcake.webp", title: "Saia de Cupcake", desc: "Mais estilo para os docinhos" }, - { src: `${BASE}/15547b19-daf7-46a0-922b-e6515a320534/centro-de-mesa.webp`, title: "Centro de Mesa", desc: "Arranjo decorativo exclusivo" }, { src: "/images/galeria-real/tag-de-agradecimento.webp", title: "Tag de Agradecimento", desc: "Pronto para as lembrancinhas" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/topper-de-cupcake-personagem.webp`, title: "Topper de Cupcake", desc: "O personagem em cada docinho" }, - { src: "/images/galeria-real/faixa-de-parede.webp", title: "Faixa de Parede", desc: "Decoração com a cara do tema" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/sacolinha-surpresa.webp`, title: "Sacolinha Surpresa", desc: "Lembrancinha que toda criança ama" }, { src: "/images/galeria-real/chapeu-de-festa.webp", title: "Chapéu de Festa", desc: "Divertido, personalizado e único" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/porta-bis-duplo.webp`, title: "Porta Bis Duplo", desc: "Lembrancinha deliciosa e bonita" }, { src: "/images/galeria-real/adesivos-redondos.webp", title: "Adesivos Redondos", desc: "Ideais para potinhos e lembrancinhas" }, - { src: `${BASE}/16ad6afb-4c6f-4b90-8769-cebff489bcb8/caixa-cone.webp`, title: "Caixa Cone", desc: "Diferente e super divertida" }, - { src: `${BASE}/15547b19-daf7-46a0-922b-e6515a320534/display-de-mesa.webp`, title: "Display de Mesa", desc: "Identificação elegante para a mesa" }, ]; return ( @@ -66,6 +54,10 @@ export default function Gallery() { ))} +

+ {t.gallery.moreModels} +

+
-
{t.offer.packLabel}
+
{t.offer.packLabel}
+ +

{t.offer.anchor}

{t.offer.priceCurrency} diff --git a/src/i18n.ts b/src/i18n.ts index 63243f6..6b254a7 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -30,7 +30,7 @@ const PT = { title1: "Transforme a foto do seu filho", title2: "em uma", titleHighlight: "Festa Mágica!", - subtitle: "Pare de gastar horas procurando decoração. Envie uma foto e nossa IA cria, com o rostinho do seu filho no estilo de personagens de cinema, os itens que você escolher de um catálogo com 21 modelos exclusivos de Kit Digital! Prontinho para imprimir.", + subtitle: "Pare de gastar horas procurando decoração. Envie uma foto e nossa IA cria, com o rostinho do seu filho no estilo de personagens de cinema, os itens que você escolher de um catálogo com 33 modelos exclusivos de Kit Digital! Prontinho para imprimir.", statKits: "kits criados", statArts: "artes geradas", statRating: "avaliação", @@ -70,23 +70,14 @@ const PT = { items: [ { title: "Topo de Bolo 3D", desc: "Destaque na mesa do bolo" }, { title: "Painel de Fundo", desc: "Transforma o cenário da festa" }, - { title: "Convite Premium", desc: "Para impressão ou envio digital" }, { title: "Caixa de Pipoca", desc: "A alegria garantida no lanche" }, - { title: "Bandeirolas com Nome", desc: "Varal decorativo personalizado" }, { title: "Convite Digital", desc: "Para enviar no WhatsApp" }, - { title: "Caixa Milk", desc: "Lembrancinha charmosa" }, { title: "Saia de Cupcake", desc: "Mais estilo para os docinhos" }, - { title: "Centro de Mesa", desc: "Arranjo decorativo exclusivo" }, { title: "Tag de Agradecimento", desc: "Pronto para as lembrancinhas" }, - { title: "Topper de Cupcake", desc: "O personagem em cada docinho" }, - { title: "Faixa de Parede", desc: "Decoração com a cara do tema" }, - { title: "Sacolinha Surpresa", desc: "Lembrancinha que toda criança ama" }, { title: "Chapéu de Festa", desc: "Divertido, personalizado e único" }, - { title: "Porta Bis Duplo", desc: "Lembrancinha deliciosa e bonita" }, { title: "Adesivos Redondos", desc: "Ideais para potinhos e lembrancinhas" }, - { title: "Caixa Cone", desc: "Diferente e super divertida" }, - { title: "Display de Mesa", desc: "Identificação elegante para a mesa" }, ], + moreModels: "E mais 25 outros modelos no catálogo — 33 no total, pra montar o kit do jeito que você quiser.", }, howItWorks: { title1: "Como a", @@ -120,16 +111,17 @@ const PT = { offer: { title1: "Crie a melhor festa que", titleHighlight: "seu filho já teve.", - subtitle: "Adquira o pacote inicial e receba 10 créditos para escolher e gerar seus itens favoritos do catálogo com 21 modelos exclusivos, por um valor simbólico.", + subtitle: "Adquira o pacote inicial e receba 10 créditos para escolher e gerar seus itens favoritos do catálogo com 33 modelos exclusivos, por um valor simbólico.", kitName: "O Kit Mágico", benefits: [ "Criação do Personagem com IA Exclusivo", - "10 créditos para escolher e gerar os itens que quiser do catálogo de 21 modelos (1 item = 1 crédito)", + "10 créditos para escolher e gerar os itens que quiser do catálogo de 33 modelos (1 item = 1 crédito)", "Arquivos em PDF já formatados, prontos para impressão", "Acesso imediato à plataforma", ], surprise: "Surpreenda todos os convidados!", packLabel: "Pacote Inicial", + anchor: "Na gráfica, papelaria personalizada assim custa R$150 ou mais.", priceCurrency: "R$", priceInteger: "9", priceDecimals: ",99", @@ -138,7 +130,7 @@ const PT = { emailPlaceholder: "Seu melhor e-mail", buttonIdle: "Quero Meu Kit por R$9,99", buttonLoading: "Gerando Pedido...", - secure: "Compra 100% segura pelo Stripe.", + secure: "Compra 100% segura · Pix ou cartão · acesso na hora.", errEmpty: "Por favor, informe seu e-mail.", errInvalid: "Por favor, informe um e-mail válido.", errCheckout: "Erro ao abrir o pagamento. Tente novamente.", @@ -170,7 +162,7 @@ const EN: typeof PT = { title1: "Turn your child's photo", title2: "into a", titleHighlight: "Magic Party!", - subtitle: "Stop spending hours hunting for decorations. Upload a photo and our AI creates, with your child's face in a movie-character style, the items you pick from a catalog of 21 exclusive Digital Kit models! Ready to print.", + subtitle: "Stop spending hours hunting for decorations. Upload a photo and our AI creates, with your child's face in a movie-character style, the items you pick from a catalog of 33 exclusive Digital Kit models! Ready to print.", statKits: "kits created", statArts: "artworks generated", statRating: "rating", @@ -210,23 +202,14 @@ const EN: typeof PT = { items: [ { title: "3D Cake Topper", desc: "The highlight of the cake table" }, { title: "Backdrop Panel", desc: "Transforms the party scene" }, - { title: "Premium Invitation", desc: "For printing or digital sharing" }, { title: "Popcorn Box", desc: "Guaranteed fun at snack time" }, - { title: "Name Bunting", desc: "Personalized decorative garland" }, { title: "Digital Invitation", desc: "To send on WhatsApp" }, - { title: "Milk Box", desc: "A charming party favor" }, { title: "Cupcake Wrapper", desc: "More style for the treats" }, - { title: "Table Centerpiece", desc: "An exclusive decorative arrangement" }, { title: "Thank You Tag", desc: "Ready for the party favors" }, - { title: "Cupcake Topper", desc: "The character on every treat" }, - { title: "Wall Banner", desc: "Decoration that matches the theme" }, - { title: "Favor Bag", desc: "A favor every kid loves" }, { title: "Party Hat", desc: "Fun, personalized and unique" }, - { title: "Double Chocolate Holder", desc: "A delicious, pretty favor" }, { title: "Round Stickers", desc: "Perfect for jars and favors" }, - { title: "Cone Box", desc: "Different and super fun" }, - { title: "Table Display", desc: "Elegant labeling for the table" }, ], + moreModels: "Plus 25 more models in the catalog — 33 in total, to build the kit your way.", }, howItWorks: { title1: "How the", @@ -260,16 +243,17 @@ const EN: typeof PT = { offer: { title1: "Create the best party", titleHighlight: "your child has ever had.", - subtitle: "Get the starter pack and receive 10 credits to choose and generate your favorite items from the catalog of 21 exclusive models, for a symbolic price.", + subtitle: "Get the starter pack and receive 10 credits to choose and generate your favorite items from the catalog of 33 exclusive models, for a symbolic price.", kitName: "The Magic Kit", benefits: [ "Exclusive AI Character Creation", - "10 credits to choose and generate any items from the 21-model catalog (1 item = 1 credit)", + "10 credits to choose and generate any items from the 33-model catalog (1 item = 1 credit)", "Print-ready, pre-formatted PDF files", "Instant access to the platform", ], surprise: "Wow all your guests!", packLabel: "Starter Pack", + anchor: "At a print shop, custom stationery like this costs $40 or more.", priceCurrency: "$", priceInteger: "6", priceDecimals: ".99", @@ -278,7 +262,7 @@ const EN: typeof PT = { emailPlaceholder: "Your best email", buttonIdle: "Get My Kit for $6.99", buttonLoading: "Processing...", - secure: "100% secure checkout via Stripe.", + secure: "100% secure checkout · Pix or card · instant access.", errEmpty: "Please enter your email.", errInvalid: "Please enter a valid email.", errCheckout: "Error opening checkout. Please try again.", @@ -310,7 +294,7 @@ const ES: typeof PT = { title1: "Convierte la foto de tu hijo", title2: "en una", titleHighlight: "¡Fiesta Mágica!", - subtitle: "Deja de perder horas buscando decoración. Sube una foto y nuestra IA crea, con la carita de tu hijo en estilo de personajes de cine, los artículos que elijas de un catálogo con 21 modelos exclusivos de Kit Digital! Listos para imprimir.", + subtitle: "Deja de perder horas buscando decoración. Sube una foto y nuestra IA crea, con la carita de tu hijo en estilo de personajes de cine, los artículos que elijas de un catálogo con 33 modelos exclusivos de Kit Digital! Listos para imprimir.", statKits: "kits creados", statArts: "artes generadas", statRating: "valoración", @@ -350,23 +334,14 @@ const ES: typeof PT = { items: [ { title: "Toper de Pastel 3D", desc: "El centro de la mesa del pastel" }, { title: "Panel de Fondo", desc: "Transforma el escenario de la fiesta" }, - { title: "Invitación Premium", desc: "Para imprimir o enviar digital" }, { title: "Caja de Palomitas", desc: "Diversión garantizada en la merienda" }, - { title: "Banderines con Nombre", desc: "Guirnalda decorativa personalizada" }, { title: "Invitación Digital", desc: "Para enviar por WhatsApp" }, - { title: "Caja Milk", desc: "Un recuerdo encantador" }, { title: "Capacillo de Cupcake", desc: "Más estilo para los dulces" }, - { title: "Centro de Mesa", desc: "Arreglo decorativo exclusivo" }, { title: "Etiqueta de Agradecimiento", desc: "Lista para los recuerdos" }, - { title: "Toper de Cupcake", desc: "El personaje en cada dulce" }, - { title: "Pancarta de Pared", desc: "Decoración con la cara del tema" }, - { title: "Bolsita Sorpresa", desc: "Recuerdo que todo niño ama" }, { title: "Gorro de Fiesta", desc: "Divertido, personalizado y único" }, - { title: "Porta Chocolate Doble", desc: "Recuerdo delicioso y bonito" }, { title: "Stickers Redondos", desc: "Ideales para frascos y recuerdos" }, - { title: "Caja Cono", desc: "Diferente y súper divertida" }, - { title: "Display de Mesa", desc: "Identificación elegante para la mesa" }, ], + moreModels: "Y 25 modelos más en el catálogo — 33 en total, para armar el kit a tu manera.", }, howItWorks: { title1: "Cómo Sucede la", @@ -400,16 +375,17 @@ const ES: typeof PT = { offer: { title1: "Crea la mejor fiesta que", titleHighlight: "tu hijo haya tenido.", - subtitle: "Adquiere el paquete inicial y recibe 10 créditos para elegir y generar tus artículos favoritos del catálogo con 21 modelos exclusivos, por un valor simbólico.", + subtitle: "Adquiere el paquete inicial y recibe 10 créditos para elegir y generar tus artículos favoritos del catálogo con 33 modelos exclusivos, por un valor simbólico.", kitName: "El Kit Mágico", benefits: [ "Creación del Personaje con IA Exclusivo", - "10 créditos para elegir y generar los artículos que quieras del catálogo de 21 modelos (1 artículo = 1 crédito)", + "10 créditos para elegir y generar los artículos que quieras del catálogo de 33 modelos (1 artículo = 1 crédito)", "Archivos PDF ya formateados, listos para imprimir", "Acceso inmediato a la plataforma", ], surprise: "¡Sorprende a todos los invitados!", packLabel: "Paquete Inicial", + anchor: "En una imprenta, papelería personalizada así cuesta $40 o más.", priceCurrency: "$", priceInteger: "6", priceDecimals: ".99", @@ -418,7 +394,7 @@ const ES: typeof PT = { emailPlaceholder: "Tu mejor correo electrónico", buttonIdle: "Quiero Mi Kit por $6.99", buttonLoading: "Procesando...", - secure: "Compra 100% segura con Stripe.", + secure: "Compra 100% segura · Pix o tarjeta · acceso instantáneo.", errEmpty: "Por favor, ingresa tu correo electrónico.", errInvalid: "Por favor, ingresa un correo válido.", errCheckout: "Error al abrir el pago. Inténtalo de nuevo.", diff --git a/src/pages/Checkout.tsx b/src/pages/Checkout.tsx deleted file mode 100644 index fbad855..0000000 --- a/src/pages/Checkout.tsx +++ /dev/null @@ -1,625 +0,0 @@ -import { useState, useEffect, useRef, type FormEvent } from 'react'; -import { useSearchParams, useNavigate } from 'react-router-dom'; -import { motion, AnimatePresence } from 'framer-motion'; -import { - ShieldCheck, Lock, QrCode, CreditCard, Copy, Check, - Loader2, Gift, Sparkles, ArrowRight, Star, Wand2, Zap, -} from 'lucide-react'; -import { cn } from '../lib/utils'; -import { createPixCharge, pollPixStatus, type PixCharge } from '../services/wooviService'; - -// ─── Planos (espelha src/utils/pricing.ts do app) ────────────────────────── -const PLANS = [ - { - id: 'starter', - name: 'Starter', - credits: 10, - price: 999, - display: 'R$9,99', - perImg: 'R$1,00/img', - priceId: 'price_1TT5lpLjQo8Mvvq1HdDD7paN', - planName: 'Festa Magica IA - Kit Inicial', - }, - { - id: 'popular', - name: 'Kit Festa', - credits: 30, - price: 1999, - display: 'R$19,99', - perImg: 'R$0,67/img', - priceId: 'price_1TT5kTLjQo8Mvvq1Tus1RS5D', - planName: 'Festa Magica IA - Kit Festa', - badge: 'Mais vendido', - }, - { - id: 'pro', - name: 'Festa VIP', - credits: 80, - price: 4999, - display: 'R$49,99', - perImg: 'R$0,62/img', - priceId: 'price_1THThELjQo8Mvvq1uXkgh5jB', - planName: 'Festa Magica IA - Festa VIP', - }, - { - id: 'professional', - name: 'Profissional', - credits: 200, - price: 9999, - display: 'R$99,99', - perImg: 'R$0,50/img', - priceId: 'price_1TT5i9LjQo8Mvvq12yhPqe1G', - planName: 'Festa Magica IA - Profissional', - }, -] as const; - -type Plan = (typeof PLANS)[number]; -type Method = 'pix' | 'card'; - -const STRIPE_URL = 'https://n8n.seureview.com.br/webhook/festa-magica-stripe'; - -function getCookie(name: string) { - const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); - return match ? match[2] : ''; -} - -export default function Checkout() { - const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - - const source = searchParams.get('source') || 'landing'; - const userId = searchParams.get('userId') || ''; - const locked = searchParams.get('lock') === '1' || ['landing', 'funil', 'campanha'].includes(searchParams.get('source') || ''); - const [email, setEmail] = useState(searchParams.get('email') || ''); - const [method, setMethod] = useState('pix'); - const [error, setError] = useState(''); - - // Plano inicial vindo da URL (?plan=popular) ou padrão = starter - const initialPlan = PLANS.find(p => p.id === searchParams.get('plan')) ?? PLANS[0]; - const [plan, setPlan] = useState(initialPlan); - - // ── Pix ────────────────────────────────────────────────────────────────── - const [pixLoading, setPixLoading] = useState(false); - const [pix, setPix] = useState(null); - const [copied, setCopied] = useState(false); - const [confirming, setConfirming] = useState(false); - const pollRef = useRef | null>(null); - - // ── Cartão ──────────────────────────────────────────────────────────────── - const [cardLoading, setCardLoading] = useState(false); - - // ── Skeleton de entrada ─────────────────────────────────────────────────── - const [ready, setReady] = useState(false); - useEffect(() => { - const t = setTimeout(() => setReady(true), 1200); - return () => clearTimeout(t); - }, []); - - useEffect(() => () => { if (pollRef.current) clearInterval(pollRef.current); }, []); - - // Resetar Pix ao trocar de plano - useEffect(() => { - if (pollRef.current) clearInterval(pollRef.current); - setPix(null); - setConfirming(false); - setError(''); - }, [plan.id]); - - const validEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); - - const trackEvent = () => { - if (typeof window !== 'undefined' && 'fbq' in window) { - (window as any).fbq('track', 'InitiateCheckout'); - } - }; - - // ── Pix ────────────────────────────────────────────────────────────────── - const handlePix = async (e?: FormEvent) => { - e?.preventDefault(); - if (!validEmail) { setError('Informe um e-mail válido para continuar.'); return; } - setError(''); - setPixLoading(true); - trackEvent(); - try { - const charge = await createPixCharge({ - userEmail: email, - source, - userId, - value: plan.price, - credits: plan.credits, - planName: plan.planName, - priceId: plan.priceId, - fbp: getCookie('_fbp'), - fbc: getCookie('_fbc'), - }); - setPix(charge); - startPolling(charge.correlationID); - } catch (err: any) { - setError(err.message || 'Não foi possível gerar o Pix. Tente novamente.'); - } finally { - setPixLoading(false); - } - }; - - const startPolling = (correlationID: string) => { - setConfirming(true); - if (pollRef.current) clearInterval(pollRef.current); - pollRef.current = setInterval(async () => { - try { - const status = await pollPixStatus(correlationID); - if (status === 'COMPLETED') { - clearInterval(pollRef.current!); - navigate('/sucesso?status=approved', { replace: true }); - } else if (status === 'EXPIRED') { - clearInterval(pollRef.current!); - setConfirming(false); - setPix(null); - setError('O Pix expirou. Gere um novo código para pagar.'); - } - } catch { /* silencia; tenta no próximo tick */ } - }, 4000); - }; - - const handleCopy = async () => { - if (!pix) return; - try { - await navigator.clipboard.writeText(pix.brCode); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } catch { setError('Não consegui copiar. Copie o código manualmente.'); } - }; - - // ── Cartão ──────────────────────────────────────────────────────────────── - const handleCard = async (e?: FormEvent) => { - e?.preventDefault(); - if (!validEmail) { setError('Informe um e-mail válido para continuar.'); return; } - setError(''); - setCardLoading(true); - trackEvent(); - try { - const res = await fetch(STRIPE_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - source, - userEmail: email, - userId, - priceId: plan.priceId, - credits: plan.credits, - planName: plan.planName, - fbp: getCookie('_fbp'), - fbc: getCookie('_fbc'), - }), - }); - const data = await res.json(); - if (data.success && data.url) { - window.location.href = data.url; - } else { - setCardLoading(false); - setError('Ocorreu um erro ao abrir o pagamento. Tente novamente.'); - } - } catch { - setCardLoading(false); - setError('Erro de conexão. Verifique sua internet e tente novamente.'); - } - }; - - const features = [ - 'Personagem 3D exclusivo criado com IA', - `${plan.credits} créditos para itens do catálogo`, - 'Arquivos em PDF prontos para impressão', - 'Acesso imediato à plataforma', - ]; - - return ( -
- - {/* ── Topo ─────────────────────────────────────────────────────── */} -
-
-
-
- -
- - Festa MágicaIA - -
-
- - Ambiente seguro -
-
-
- -
- - {/* ── Skeleton ─────────────────────────────────────────────────────── */} - - {!ready && ( - - {/* Esquerda */} -
- {!locked && ( -
-
-
- {[...Array(4)].map((_, i) => ( -
- ))} -
-
- )} -
-
- {[...Array(4)].map((_, i) => ( -
- ))} -
-
-
-
-
-
- {/* Direita */} -
-
-
-
-
-
-
-
-
- {[...Array(4)].map((_, i) => ( -
- ))} -
-
- - )} - - - {/* ── Conteúdo real ────────────────────────────────────────────────── */} - - {ready && ( - -
- - {/* ── Coluna esquerda: seletor de plano + resumo ───────────── */} -
- - {/* Seletor de plano — oculto no modo locked (funil/campanha) */} - {!locked && ( - -

- Escolha o plano -

- -
- {PLANS.map((p) => ( - - ))} -
-
- )} - - {/* Resumo do pedido */} - -
-
- -
-
-

Resumo

-

{plan.name}

-
-
- -
    - {features.map((f, i) => ( -
  • - - - - {f} -
  • - ))} -
- - {/* Primeira imagem grátis — só pro starter */} - {plan.id === 'starter' && ( -
- -

- Sua primeira imagem por nossa conta — não consome nenhum crédito. -

-
- )} - - {/* Valor final */} -
- Você paga hoje - {plan.display} -
-

Pagamento único · sem assinatura

- - {/* Prova social */} -
-
- {[...Array(5)].map((_, i) => ( - - ))} -
- +10.000 mães já fizeram a festa -
-
-
- - {/* ── Coluna direita: pagamento ─────────────────────────────── */} - -

Pagamento

- - {/* E-mail */} -
- - { setEmail(e.target.value); if (error) setError(''); }} - placeholder="seu@email.com" - disabled={!!pix} - className="w-full h-11 px-4 rounded-xl border-2 border-gray-100 focus:border-pink-400 outline-none text-sm font-medium text-gray-900 transition-colors placeholder:text-gray-300 disabled:bg-gray-50 disabled:text-gray-400" - /> -

- É aqui que enviamos o acesso ao painel. -

-
- - {/* Método */} -
- - -
- - {/* Erro */} - - {error && ( - - {error} - - )} - - - {/* ── Pix ── */} - - {method === 'pix' && ( - - {!pix ? ( -
- -

- - QR Code gerado na hora · pague pelo app do banco -

-
- ) : ( -
-
- QR Code Pix -
- -

- Escaneie o QR Code ou use o Pix Copia e Cola: -

- -
- - -
- - {confirming && ( -
- - Aguardando confirmação do pagamento... -
- )} -

- Assim que o Pix cair, liberamos seu acesso. Pode deixar esta tela aberta. -

-
- )} -
- )} - - {/* ── Cartão ── */} - {method === 'card' && ( - -
- -

- - Você finaliza no ambiente seguro do Stripe -

-
-
- )} -
- - {/* ── Selos de confiança ── */} -
-
- Pagamento 100% seguro e criptografado -
-
- {[ - { icon: QrCode, label: 'Pix · Banco Central' }, - { icon: CreditCard, label: 'Cartão via Stripe' }, - { icon: Lock, label: 'SSL 256-bit' }, - { icon: ShieldCheck, label: 'Garantia de 7 dias' }, - ].map(({ icon: Icon, label }) => ( -
- - {label} -
- ))} -
-
-
-
- - {/* Rodapé */} -

- Ao prosseguir você concorda com os Termos de Uso e Política de Privacidade. - Garantia de reembolso integral em até 7 dias, sem perguntas. -

-
- )} -
-
-
- ); -} diff --git a/src/pages/SuccessPage.tsx b/src/pages/SuccessPage.tsx deleted file mode 100644 index dc15fba..0000000 --- a/src/pages/SuccessPage.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useEffect, useState } from "react"; -import { useSearchParams, useNavigate } from "react-router-dom"; -import { CheckCircle, Mail, LayoutDashboard, Sparkles } from "lucide-react"; -import Footer from "../components/Footer"; - -export default function SuccessPage() { - const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - const [isValid, setIsValid] = useState(false); - - useEffect(() => { - // O Stripe passa 'session_id' automaticamente quando redireciona, - // Ou podemos checar um parâmetro manual como '?status=approved' - const sessionId = searchParams.get("session_id"); - const status = searchParams.get("status"); - - if (sessionId || status === "approved") { - setIsValid(true); - } else { - // Se não tiver nenhum parâmetro válido, joga de volta pra home - navigate("/", { replace: true }); - } - }, [searchParams, navigate]); - - if (!isValid) { - return null; // Retorna nulo enquanto valida para não piscar a tela - } - - return ( -
-
-
- {/* Success Banner */} -
- -

- Pagamento Confirmado! -

-

- Tudo certo com o seu pedido! Preparamos tudo para você começar a criar a festa dos sonhos em instantes. -

- -
-
-
- -
-

1. Fique de olho no e-mail

-

- Em até 5 minutos, você receberá um e-mail de confirmação com a nota do seu pedido e todos os detalhes. -

-
- -
-
- -
-

2. Acesse o Painel

-

- No mesmo e-mail, enviaremos um link de acesso exclusivo direto para o nosso Painel de Criação Mágica. Não se preocupe em criar conta! -

-
- -
-
- -
-

3. Crie a Magia

-

- Dentro do painel, siga as instruções rápidas, faça o upload da foto e deixe a inteligência artificial transformar tudo em um kit inesquecível! -

-
-
-
-
-
-
-
- ); -} diff --git a/src/services/wooviService.ts b/src/services/wooviService.ts deleted file mode 100644 index 229ae6b..0000000 --- a/src/services/wooviService.ts +++ /dev/null @@ -1,98 +0,0 @@ -// ============================================================ -// Festa Mágica IA — Woovi (Pix) Service -// ============================================================ -// Fluxo Pix transparente: -// Front → n8n (cria cobrança Woovi) → QR/copia-e-cola na tela -// Front faz polling do status via n8n até COMPLETED -// Webhook Woovi → n8n credita / cria usuário / magic link / e-mail -// -// IMPORTANTE: o App ID da Woovi NUNCA passa pelo browser. -// Tanto a criação da cobrança quanto a consulta de status são -// feitas server-side pelo n8n. O front só fala com o n8n. -// ============================================================ - -const N8N_BASE = 'https://n8n.seureview.com.br/webhook'; - -const PIX_CREATE_URL = `${N8N_BASE}/festa-magica-pix`; -const PIX_STATUS_URL = `${N8N_BASE}/festa-magica-pix-status`; - -export interface CreatePixParams { - userEmail: string; - source?: string; // 'landing' | 'funil' | 'default' - userId?: string; - value?: number; // em centavos BRL - credits?: number; - planName?: string; - priceId?: string; - fbp?: string; - fbc?: string; -} - -export interface PixCharge { - correlationID: string; - brCode: string; // código copia-e-cola - qrCodeImage: string; // URL da imagem do QR (PNG) - value: number; // em centavos - expiresDate?: string; -} - -export type PixStatus = 'ACTIVE' | 'COMPLETED' | 'EXPIRED'; - -/** - * Cria uma cobrança Pix na Woovi (via n8n) e retorna os dados - * para exibir o QR Code e o copia-e-cola na própria tela. - */ -export async function createPixCharge(params: CreatePixParams): Promise { - const response = await fetch(PIX_CREATE_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - source: params.source || 'landing', - userEmail: params.userEmail, - userId: params.userId || '', - value: params.value, - credits: params.credits, - planName: params.planName, - priceId: params.priceId, - fbp: params.fbp || '', - fbc: params.fbc || '', - }), - }); - - if (!response.ok) { - throw new Error(`Erro ao gerar Pix: ${response.status}`); - } - - const data = await response.json(); - - if (!data.success || !data.brCode) { - throw new Error(data.error || 'Não foi possível gerar o Pix.'); - } - - return { - correlationID: data.correlationID, - brCode: data.brCode, - qrCodeImage: data.qrCodeImage, - value: data.value, - expiresDate: data.expiresDate, - }; -} - -/** - * Consulta o status de uma cobrança Pix (via n8n). - * Usado no polling enquanto o usuário paga. - */ -export async function pollPixStatus(correlationID: string): Promise { - const response = await fetch(PIX_STATUS_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ correlationID }), - }); - - if (!response.ok) { - throw new Error(`Erro ao consultar status do Pix: ${response.status}`); - } - - const data = await response.json(); - return (data.status as PixStatus) || 'ACTIVE'; -}