import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from "@/components/ui/card"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogDescription, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { ArrowRight, CheckCircle2, MapPin, Award, Clock, AlertTriangle, CalendarPlus, Users, Utensils, Check, } from "lucide-react"; import { Progress } from "@/components/ui/progress"; import { useToast } from "@/hooks/use-toast"; import { TOTAL_SEATS, SEATS_TAKEN_START } from "@/lib/seminarConfig"; import { postLead, type SeminarFormData } from "@/lib/postLead"; import { useCountdown } from "@/lib/useCountdown"; import { downloadIcs } from "@/lib/downloadIcs"; const selectCls = "h-14 bg-muted/30 text-base rounded-xl border-border/60 focus:border-primary"; const inputCls = "h-14 bg-muted/30 focus:bg-background transition-colors text-base rounded-xl border-border/60 focus:border-primary"; export default function Index() { const { toast } = useToast(); const [step, setStep] = useState(0); const [isSubmitting, setIsSubmitting] = useState(false); const [wantsCert, setWantsCert] = useState(null); const [seatsTaken, setSeatsTaken] = useState(SEATS_TAKEN_START); const { timeLeft, isExpired } = useCountdown("2026-10-06T23:59:59-06:00"); const [formData, setFormData] = useState({ name: "", phone: "", email: "", guests: "1", consentContact: false, consentMedia: false, propertyType: "", downPayment: "", cardBalance: "", carLoan: "", employment: "", income: "", credit: "", immigration: "", consentFinancial: false, }); const set = (k: string, v: string | boolean) => setFormData((p) => ({ ...p, [k]: v })); const onInput = (e: React.ChangeEvent) => set(e.target.name, e.target.value); const seatsLeft = Math.max(0, TOTAL_SEATS - seatsTaken); const fillPct = (seatsTaken / TOTAL_SEATS) * 100; const handleStep1 = () => { const digits = formData.phone.replace(/\D/g, ""); if (!formData.name.trim() || !formData.email.trim() || !digits) { return toast({ title: "Campos obrigatórios", description: "Preencha nome, e-mail e WhatsApp.", variant: "destructive", }); } if (formData.name.trim().split(/\s+/).length < 2) { return toast({ title: "Nome completo", description: "Escreva nome e sobrenome.", variant: "destructive", }); } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) { return toast({ title: "E-mail inválido", description: "Confira o e-mail digitado.", variant: "destructive", }); } if (digits.length < 10) { return toast({ title: "WhatsApp inválido", description: "O número precisa ter 10 dígitos.", variant: "destructive", }); } if (!formData.consentContact) { return toast({ title: "Consentimento necessário", description: "Precisamos da sua autorização de contato.", variant: "destructive", }); } if (!formData.consentMedia) { return toast({ title: "Autorização de imagem", description: "O evento é filmado — precisamos da sua autorização.", variant: "destructive", }); } postLead(1, false, formData); setStep(2); }; const handleCertSubmit = async () => { const required = [ "propertyType", "downPayment", "cardBalance", "carLoan", "employment", "income", "credit", "immigration", ]; if (required.some((k) => !formData[k as keyof SeminarFormData])) { return toast({ title: "Faltou responder", description: "Responda todas as perguntas para gerarmos seu certificado.", variant: "destructive", }); } if (!formData.consentFinancial) { return toast({ title: "Autorização necessária", description: "Precisamos da sua autorização para usar esses dados.", variant: "destructive", }); } setIsSubmitting(true); await postLead(2, true, formData); setWantsCert(true); setSeatsTaken((s) => Math.min(TOTAL_SEATS, s + Number(formData.guests))); setIsSubmitting(false); setStep(3); }; const handleSkipCert = async () => { setIsSubmitting(true); await postLead(2, false, formData); setWantsCert(false); setSeatsTaken((s) => Math.min(TOTAL_SEATS, s + Number(formData.guests))); setIsSubmitting(false); setStep(3); }; return (
{step === 0 && (
Dos Vistos às Chaves — Seminário Red Ribbon Group
Vagas restantes
{seatsLeft}

Sala pequena — apenas {TOTAL_SEATS} lugares. Cada pessoa ocupa uma vaga.

{!isExpired ? (
Inscrições encerram em:
{timeLeft.days > 0 && {timeLeft.days}d} {String(timeLeft.hours).padStart(2, "0")}h : {String(timeLeft.minutes).padStart(2, "0")}m : {String(timeLeft.seconds).padStart(2, "0")}s
) : (
Inscrições Encerradas
)}

O que você vai descobrir

    {[ "Por que o banco diz não — e o que realmente resolve", "Quanto de entrada você precisa de verdade", "Local comprar em Calgary começando do zero", "Os 3 erros mais caros de quem compra a primeira casa", "Seu certificado de pré-qualificação — na sua mão, no dia", ].map((t, i) => (
  • {t}
  • ))}

First Assembly

6031 Elbow Dr SW
Meeting Place

Comidinha brasileira

Por nossa conta 🇧🇷

)} {(step === 1 || step === 2) && (
{step === 1 && ( <>
Passo 1 de 2
Garanta sua vaga 30 segundos. Só o essencial.

É por aqui que mandamos o lembrete e o endereço.

Cada pessoa ocupa uma vaga. Se vem acompanhado, reserve as duas.

set("consentContact", !!v)} className="mt-1 shrink-0 border-primary/50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" />
set("consentMedia", !!v)} className="mt-1 shrink-0 border-primary/50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" />
)} {step === 2 && ( <>
Passo 2 de 2 · Opcional
Quer sair com seu número na mão? Sua vaga{" "} já está garantida . Isto aqui é o bônus.

Certificado de Pré-Qualificação

A Greice prepara o{" "} seu certificado oficial antes do evento — com o valor que você já pode comprar hoje. Impresso, no seu nome, entregue na sua mão dia 7.

Você não vê o resultado agora. Descobre lá. 🤫

O que já está guardado ou vai receber de presente (gift).

Se vão comprar juntos, some a renda dos dois.

Somando todos os cartões e a linha de crédito.

Carro, leasing, empréstimo estudantil, qualquer parcela fixa.

Não sabe? Escolha a última opção — a Greice trabalha com isso.

Cada situação tem um caminho — nenhuma é caminho fechado.

set("consentFinancial", !!v)} className="mt-1 shrink-0 border-primary/50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" />
)}
)} {step === 3 && (

Vaga confirmada!

{wantsCert ? "Seu certificado vai estar pronto e esperando por você no dia 7. Não vamos adiantar o resultado. 😉" : "Te esperamos dia 7! Se mudar de ideia sobre o certificado, é só responder o WhatsApp."}

Sua entrada

DOS VISTOS
ÀS CHAVES

{[ ["Data", "Quarta, 7 de outubro"], ["Horário", "18h00"], ["Local", "First Assembly · Meeting Place"], ["Endereço", "6031 Elbow Dr SW, Calgary"], ["No nome de", formData.name], [ "Vagas", `${formData.guests} ${Number(formData.guests) > 1 ? "vagas" : "vaga"}`, ], ].map(([k, v]) => (
{k} {v}
))} {wantsCert && (
Certificado de pré-qualificação reservado no seu nome 🎓
)}

IMPORTANTE: tire um print desta tela. É a sua confirmação de vaga — a sala tem só 20 lugares.

Você vai receber a confirmação na mensagem de texto ou WhatsApp.

)}

Red Ribbon Group

Serviços imobiliários por Taryn Pessanha, corretora licenciada · Real Broker (corretora responsável)

Pré-qualificação por Greice Pereira-Galhardo · Mortgage Connection

Calgary, AB · Seus dados são tratados conforme a CASL.
Aviso sobre o Certificado Leia antes de se inscrever.

1. O que é o certificado: uma estimativa de pré-qualificação preparada por Greice Pereira-Galhardo (Mortgage Connection) com base nas informações que você fornecer no formulário.

2. O que NÃO é: não é aprovação de crédito, não é compromisso de financiamento por nenhuma instituição, e{" "} não há consulta ao seu histórico de crédito . Valores e taxas são ilustrativos e sujeitos a alteração.

3. Aprovação real: depende de análise completa do credor no momento da compra, com documentação verificada.

4. Seus dados: as informações financeiras são usadas exclusivamente para preparar seu certificado e são apagadas após o evento. Não são compartilhadas com terceiros além da corretora de crédito responsável.

5. Evento gratuito: não há custo, não há compra, não há obrigação de contratar qualquer serviço.

6. Imagem: o evento será fotografado e filmado. Ao se inscrever você autoriza o uso dessas imagens pelo Red Ribbon Group.

7. Vagas: 20 lugares, por ordem de inscrição. Cada pessoa ocupa uma vaga.

8. Privacidade e CASL: seus dados são tratados em conformidade com a Legislação Canadense Anti-Spam. Você pode cancelar a inscrição a qualquer momento.

); }