diff --git a/src/tictactoe/Player.tsx b/src/tictactoe/Player.tsx index 64880f1..faa47f3 100644 --- a/src/tictactoe/Player.tsx +++ b/src/tictactoe/Player.tsx @@ -21,6 +21,7 @@ export default function Player({ localStorage.getItem("username") ?? "" ); const [selectedMode, setSelectedMode] = useState("classic"); + const [isQueueing, setIsQueueing] = useState(false); // ------------------------------------------ // CONNECT @@ -36,8 +37,21 @@ export default function Player({ // MATCHMAKING // ------------------------------------------ async function startQueue(selectedMode: string) { - const ticket = await joinMatchmaker(selectedMode); - console.log("Queued:", ticket); + setIsQueueing(true); + + try { + const ticket = await joinMatchmaker(selectedMode); + console.log("Queued:", ticket); + } catch (err) { + console.error("Matchmaking failed:", err); + setIsQueueing(false); + } + } + + function cancelQueue() { + setIsQueueing(false); + // Nakama matchmaker tickets auto-expire by default in your setup. + // If you later add manual ticket cancel RPC, call it here. } useEffect(() => { @@ -148,22 +162,75 @@ export default function Player({ - startQueue(selectedMode)} - style={{ - padding: "10px 20px", - borderRadius: "12px", - background: "#3498db", - color: "white", - border: "none", - marginRight: "10px", - cursor: "pointer", - fontWeight: 600, - }} - > - Join Matchmaking - + {!isQueueing && ( + startQueue(selectedMode)} + style={{ + padding: "10px 20px", + borderRadius: "12px", + background: "#3498db", + color: "white", + border: "none", + marginRight: "10px", + cursor: "pointer", + fontWeight: 600, + }} + > + Join Matchmaking + + )} + + {/* Queueing animation */} + {isQueueing && ( + +
+ Finding an opponent… +
+ + {/* Animated pulsing dots */} + + ● ● ● + + + {/* Cancel button */} + +
+ )}