- Added isQueueing state to Player component to track matchmaking state.

- Implemented animated "Finding opponent…" UI with pulsing dots using Framer Motion.
- Added cancelQueue() to allow players to cancel matchmaking mid-search.
- Updated startQueue() to set queueing state immediately for instant feedback.
- Improved player experience by clearly showing matchmaking progress instead of silent waiting.
This commit is contained in:
2025-11-29 02:44:54 +05:30
parent a9e2d50b16
commit 8555675740

View File

@@ -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) {
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,6 +162,7 @@ export default function Player({
<option value="blitz">Blitz</option>
</select>
{!isQueueing && (
<motion.button
whileTap={{ scale: 0.95 }}
onClick={() => startQueue(selectedMode)}
@@ -164,6 +179,58 @@ export default function Player({
>
Join Matchmaking
</motion.button>
)}
{/* Queueing animation */}
{isQueueing && (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.3 }}
style={{
marginTop: "10px",
marginBottom: "10px",
padding: "12px 16px",
borderRadius: "12px",
background: "#222",
color: "white",
display: "inline-block",
fontSize: "14px",
border: "1px solid #333",
}}
>
<div style={{ marginBottom: "6px", fontWeight: 600 }}>
Finding an opponent
</div>
{/* Animated pulsing dots */}
<motion.div
animate={{ opacity: [0.3, 1, 0.3] }}
transition={{ duration: 1.2, repeat: Infinity }}
style={{ letterSpacing: "2px", fontSize: "18px" }}
>
</motion.div>
{/* Cancel button */}
<button
onClick={cancelQueue}
style={{
marginTop: "10px",
padding: "6px 12px",
borderRadius: "8px",
background: "#e74c3c",
color: "white",
border: "none",
cursor: "pointer",
fontSize: "12px",
fontWeight: 600,
}}
>
Cancel
</button>
</motion.div>
)}
<motion.button
whileTap={{ scale: 0.95 }}