diff --git a/src/tictactoe/MatchList.tsx b/src/tictactoe/MatchList.tsx
new file mode 100644
index 0000000..e83110a
--- /dev/null
+++ b/src/tictactoe/MatchList.tsx
@@ -0,0 +1,55 @@
+import { Match } from "@heroiclabs/nakama-js";
+
+interface MatchListProps {
+ matches: Match[];
+}
+
+export default function MatchList({ matches }: MatchListProps) {
+ if (!matches.length) return
No open matches
;
+
+ return (
+
+
Open Matches
+
+
+
+
+ | Sr No. |
+ Match ID |
+ Label |
+
+
+
+
+ {matches
+ .filter(m => m.size ?? 0 > 0)
+ .map((m, index) => (
+
+ | {index + 1} |
+ {m.match_id} |
+ {m.label ?? "-"} |
+
+ ))}
+
+
+
+ );
+}
+
+const th: React.CSSProperties = {
+ textAlign: "left",
+ padding: "8px",
+ background: "#f2f2f2",
+ borderBottom: "1px solid #ccc",
+};
+
+const td: React.CSSProperties = {
+ padding: "8px",
+ borderBottom: "1px solid #eee",
+};
diff --git a/src/tictactoe/TicTacToe.tsx b/src/tictactoe/TicTacToe.tsx
index 1981370..04342be 100644
--- a/src/tictactoe/TicTacToe.tsx
+++ b/src/tictactoe/TicTacToe.tsx
@@ -1,6 +1,8 @@
import { useState, useEffect } from "react";
import { useNakama } from "./providers/NakamaProvider";
+import { Match } from "@heroiclabs/nakama-js";
import Board from "./Board";
+import MatchList from "./MatchList";
export default function TicTacToe() {
const [username, setUsername] = useState("");
@@ -11,12 +13,14 @@ export default function TicTacToe() {
]);
const [turn, setTurn] = useState(0);
const [winner, setWinner] = useState(null);
+ const [openMatches, setOpenMatches] = useState([]);
const {
loginOrRegister,
joinMatchmaker,
onMatchData,
sendMatchData,
+ listOpenMatches,
matchId,
} = useNakama();
@@ -32,6 +36,25 @@ export default function TicTacToe() {
});
}, [onMatchData]);
+ useEffect(() => {
+ let active = true;
+
+ async function refreshLoop() {
+ while (active) {
+ const matches = await listOpenMatches();
+ setOpenMatches(matches);
+
+ await new Promise(res => setTimeout(res, 500)); // 0.5s refresh
+ }
+ }
+
+ refreshLoop();
+
+ return () => {
+ active = false;
+ };
+ }, [listOpenMatches]);
+
// ------------------------------------------
// CONNECT
// ------------------------------------------
@@ -82,6 +105,9 @@ export default function TicTacToe() {
/>
+
>
)}
diff --git a/src/tictactoe/providers/NakamaProvider.tsx b/src/tictactoe/providers/NakamaProvider.tsx
index eeed378..2daab52 100644
--- a/src/tictactoe/providers/NakamaProvider.tsx
+++ b/src/tictactoe/providers/NakamaProvider.tsx
@@ -3,10 +3,12 @@ import {
Session,
Socket,
MatchmakerTicket,
- Match,
MatchData,
MatchmakerMatched,
} from "@heroiclabs/nakama-js";
+// @ts-ignore
+import { ApiMatch } from "@heroiclabs/nakama-js/dist/api.gen"
+
import React, { createContext, useContext, useState } from "react";
function getOrCreateDeviceId(): string {
@@ -32,6 +34,7 @@ export interface NakamaContextType {
sendMatchData(matchId: string, op: number, data: object): void;
onMatchData(cb: (msg: any) => void): void;
+ listOpenMatches(): Promise;
}
export const NakamaContext = createContext(null!);
@@ -128,6 +131,19 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) {
};
}
+ async function listOpenMatches(): Promise {
+ if (!session) {
+ console.warn("[Nakama] listOpenMatches called before login");
+ return [];
+ }
+
+ const result = await client.listMatches(session, 10);
+
+ console.log("[Nakama] Open matches:", result.matches);
+
+ return result.matches ?? [];
+ }
+
return (
{children}