"use client"; import { AnimatePresence, motion } from "framer-motion"; import { Crown, Loader2 } from "lucide-react"; import { useEffect, useState } from "react"; import { ScreenShell } from "@/components/online/ScreenHeader"; import { Avatar } from "@/components/online/Avatar"; import { useGameStore } from "@/lib/game-store"; import { useOnlineStore } from "@/lib/online-store"; import { useSessionStore } from "@/lib/session-store"; import { useUIStore } from "@/lib/ui-store"; import { useI18n } from "@/lib/i18n"; import { getService } from "@/lib/online/service"; export function MatchmakingScreen() { const { t } = useI18n(); const mm = useOnlineStore((s) => s.matchmaking); const cancelMatchmaking = useOnlineStore((s) => s.cancelMatchmaking); const newOnlineMatch = useGameStore((s) => s.newOnlineMatch); const enterServerMatch = useGameStore((s) => s.enterServerMatch); const upgradePlan = useSessionStore((s) => s.upgradePlan); const goGame = useUIStore((s) => s.goGame); const go = useUIStore((s) => s.go); const ready = mm.phase === "ready"; const queued = mm.phase === "queued"; const searching = mm.phase === "searching"; const slots = [0, 1, 2, 3]; // Elapsed seconds while searching (resets when the search (re)starts). const [elapsed, setElapsed] = useState(0); useEffect(() => { if (!searching) { setElapsed(0); return; } const id = setInterval(() => setElapsed((s) => s + 1), 1000); return () => clearInterval(id); }, [searching]); // Live server: the server starts the match itself — auto-enter when ready. useEffect(() => { if (mm.phase === "ready" && getService().live) { enterServerMatch(getService()); goGame("home"); } }, [mm.phase, enterServerMatch, goGame]); const cancel = async () => { await cancelMatchmaking(); go("online"); }; const enter = () => { const players = getService().getMatchPlayers(); if (!players) return; newOnlineMatch({ players: players.map((p) => ({ displayName: p.displayName, avatar: p.avatar, level: p.level, })), targetScore: 7, stake: mm.stake, ranked: mm.ranked, }); goGame("home"); }; if (queued) { return ( ⏳ {t("queue.title")} {t("queue.busy")} {mm.queuePosition ?? 0} {t("queue.position", { n: mm.queuePosition ?? 0 })} upgradePlan()} className="press-3d btn-gold w-full rounded-2xl py-3 flex items-center justify-center gap-2" > {t("queue.upgrade")} {t("queue.skip")} {t("mm.cancel")} ); } return ( {ready ? ( ✅ ) : ( )} {ready ? t("mm.ready") : mm.phase === "found" ? t("mm.found") : t("mm.searching")} {searching && ( <> {elapsed}s {t("mm.fillHint")} > )} {slots.map((i) => { const p = mm.players[i]; return ( {p ? ( {p.displayName} {t("common.level")} {p.level} ) : ( ? )} ); })} {t("mm.cancel")} {ready && ( {t("mm.start")} )} ); }
{t("queue.busy")}
{t("queue.position", { n: mm.queuePosition ?? 0 })}
{t("mm.fillHint")}