"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { ArrowRight, Check, Copy, Loader2, AlertCircle, MessageCircle, } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { invokeFunction } from "@/lib/invoke-function"; import { cn } from "@/lib/utils"; import { sanitizeForUsername, suggestBotUsername, } from "@/lib/telegram-username"; const TOKEN_REGEX = /^\d+:[A-Za-z0-9_-]+$/; interface Props { agentName: string; fullName: string; onActivated: (bot: { bot_username: string; bot_name: string; bot_id: number }) => void; onSkip: () => void; } type Phase = "configure" | "awaiting_start" | "captured"; export function BotFatherWizard({ agentName, fullName, onActivated, onSkip }: Props) { const [phase, setPhase] = useState("configure"); const [step1Done, setStep1Done] = useState(false); const [step2Done, setStep2Done] = useState(false); const [step3Done, setStep3Done] = useState(false); const [token, setToken] = useState(""); const [submitting, setSubmitting] = useState(false); const [errorMsg, setErrorMsg] = useState(null); const [validatedBot, setValidatedBot] = useState<{ bot_username: string; bot_name: string; bot_id: number; } | null>(null); const pollRef = useRef(null); const suggestedUsername = useMemo(() => { const base = sanitizeForUsername(agentName).replace(/^mikade/, "mika"); if (base.length >= 5) { const trimmed = base.slice(0, 28); return trimmed.endsWith("bot") ? trimmed : `${trimmed}bot`; } return suggestBotUsername(fullName); }, [agentName, fullName]); const tokenValid = TOKEN_REGEX.test(token.trim()); function handleOpenBotFather() { window.open("https://t.me/BotFather", "_blank", "noopener,noreferrer"); setStep1Done(true); } async function handleActivate() { if (!tokenValid) return; setSubmitting(true); setErrorMsg(null); const { data, error } = await invokeFunction<{ bot_username: string; bot_name: string; bot_id: number; }>("validate-telegram-bot", { token: token.trim() }); if (error || !data?.bot_username) { setSubmitting(false); setErrorMsg( error?.message ?? "Token inválido. Verifique e tente novamente.", ); return; } setSubmitting(false); setValidatedBot(data); setPhase("awaiting_start"); } function handleOpenMyBot() { if (!validatedBot?.bot_username) return; window.open( `https://t.me/${validatedBot.bot_username}`, "_blank", "noopener,noreferrer", ); } // Polling: enquanto phase === awaiting_start, chama capture-telegram-owner a cada 2.5s useEffect(() => { if (phase !== "awaiting_start") return; let cancelled = false; async function tick() { if (cancelled) return; const { data, error } = await invokeFunction<{ found: boolean; chat_id?: number; first_name?: string; bot_username?: string; }>("capture-telegram-owner", {}); if (cancelled) return; if (error) { console.warn("capture-telegram-owner error", error); return; } if (data?.found && validatedBot) { setPhase("captured"); setTimeout(() => onActivated(validatedBot), 1400); } } tick(); pollRef.current = window.setInterval(tick, 2500); return () => { cancelled = true; if (pollRef.current) window.clearInterval(pollRef.current); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [phase, validatedBot]); if (phase === "awaiting_start" || phase === "captured") { return ( ); } return (
{/* COLUNA ESQUERDA — passos */}

Crie seu bot em 2 minutos

Siga os passos abaixo. Cada um leva alguns segundos.

    Depois envie este comando:

    {}} />
    setStep2Done(true)} /> setStep3Done(true)} />
    { setToken(e.target.value); if (errorMsg) setErrorMsg(null); }} placeholder="1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" className={cn( "h-11 font-mono text-sm bg-white/5 border-white/20 text-white placeholder:text-white/30", tokenValid && "border-emerald-400/60 focus-visible:ring-emerald-400/40", )} disabled={submitting} /> {tokenValid && (

    Token válido!

    )} {errorMsg && (

    {errorMsg}

    )}
{/* COLUNA DIREITA — preview animado (apenas desktop) */}
); } function Step({ number, emoji, title, description, done, highlight, children, }: { number: number; emoji: string; title: string; description: string; done: boolean; highlight: boolean; children?: React.ReactNode; }) { return (
  • {done ? : number}

    {emoji} {title}

    {description}

    {children}
  • ); } function CopyChip({ value, onCopied, }: { value: string; onCopied: () => void; }) { const [copied, setCopied] = useState(false); async function handleCopy() { try { await navigator.clipboard.writeText(value); setCopied(true); toast.success("Copiado!"); onCopied(); setTimeout(() => setCopied(false), 1500); } catch { toast.error("Não foi possível copiar."); } } return ( ); } function ChatPreview({ agentName, firstName, }: { agentName: string; firstName: string; }) { const safeName = (agentName || "Mika").trim(); const safeFirst = (firstName || "você").trim(); const reply = `Olá, ${safeFirst}! 👋 Sou a Mika, sua assistente pessoal. Como posso ajudar você hoje?`; // Cycle: 0 = só "Oi!", 1 = typing, 2 = resposta digitando, 3 = completa, depois reseta const [cycle, setCycle] = useState(0); const [typed, setTyped] = useState(""); useEffect(() => { if (cycle === 0) { const t = setTimeout(() => setCycle(1), 900); return () => clearTimeout(t); } if (cycle === 1) { const t = setTimeout(() => setCycle(2), 1100); return () => clearTimeout(t); } if (cycle === 2) { // typewriter let i = 0; setTyped(""); const interval = setInterval(() => { i += 1; setTyped(reply.slice(0, i)); if (i >= reply.length) { clearInterval(interval); setTimeout(() => setCycle(3), 1500); } }, 25); return () => clearInterval(interval); } if (cycle === 3) { const t = setTimeout(() => { setTyped(""); setCycle(0); }, 2500); return () => clearTimeout(t); } }, [cycle, reply]); return (

    Prévia do seu bot

    🤖

    {safeName}

    online

    {/* Mensagem do usuário */}
    Oi!
    {/* Typing indicator */} {cycle === 1 && (
    {[0, 1, 2].map((i) => ( ))}
    )}
    {/* Resposta do bot */} {(cycle === 2 || cycle === 3) && (
    {cycle === 2 ? typed : reply} {cycle === 2 && ( )}
    )}
    ); } function AwaitingStartPanel({ botUsername, botName, captured, onOpenBot, }: { botUsername: string; botName: string; captured: boolean; onOpenBot: () => void; }) { return (
    {captured ? (

    Conectado! 🎉

    Identificamos você no Telegram. Estamos finalizando a ativação do seu agente — em alguns instantes ele começa a responder.

    ) : (

    Última etapa: diga "oi" pro {botName}

    Abra seu bot no Telegram e envie qualquer mensagem (pode ser /start). Assim a gente sabe que é você e libera o acesso exclusivo.

    Aguardando sua primeira mensagem…

    Por que isso?

    Seu agente responde só pra você. Ao enviar a primeira mensagem, capturamos seu ID do Telegram e bloqueamos o bot para qualquer outra pessoa — segurança total.

    )}
    ); }