open matches listing with available players
This commit is contained in:
55
src/tictactoe/MatchList.tsx
Normal file
55
src/tictactoe/MatchList.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { Match } from "@heroiclabs/nakama-js";
|
||||||
|
|
||||||
|
interface MatchListProps {
|
||||||
|
matches: Match[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MatchList({ matches }: MatchListProps) {
|
||||||
|
if (!matches.length) return <p>No open matches</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ marginTop: "20px" }}>
|
||||||
|
<h3>Open Matches</h3>
|
||||||
|
|
||||||
|
<table
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
borderCollapse: "collapse",
|
||||||
|
marginTop: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style={th}>Sr No.</th>
|
||||||
|
<th style={th}>Match ID</th>
|
||||||
|
<th style={th}>Label</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{matches
|
||||||
|
.filter(m => m.size ?? 0 > 0)
|
||||||
|
.map((m, index) => (
|
||||||
|
<tr key={m.match_id}>
|
||||||
|
<td style={td}>{index + 1}</td>
|
||||||
|
<td style={td}>{m.match_id}</td>
|
||||||
|
<td style={td}>{m.label ?? "-"}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const th: React.CSSProperties = {
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "8px",
|
||||||
|
background: "#f2f2f2",
|
||||||
|
borderBottom: "1px solid #ccc",
|
||||||
|
};
|
||||||
|
|
||||||
|
const td: React.CSSProperties = {
|
||||||
|
padding: "8px",
|
||||||
|
borderBottom: "1px solid #eee",
|
||||||
|
};
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useNakama } from "./providers/NakamaProvider";
|
import { useNakama } from "./providers/NakamaProvider";
|
||||||
|
import { Match } from "@heroiclabs/nakama-js";
|
||||||
import Board from "./Board";
|
import Board from "./Board";
|
||||||
|
import MatchList from "./MatchList";
|
||||||
|
|
||||||
export default function TicTacToe() {
|
export default function TicTacToe() {
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@@ -11,12 +13,14 @@ export default function TicTacToe() {
|
|||||||
]);
|
]);
|
||||||
const [turn, setTurn] = useState<number>(0);
|
const [turn, setTurn] = useState<number>(0);
|
||||||
const [winner, setWinner] = useState<string | null>(null);
|
const [winner, setWinner] = useState<string | null>(null);
|
||||||
|
const [openMatches, setOpenMatches] = useState<Match[]>([]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loginOrRegister,
|
loginOrRegister,
|
||||||
joinMatchmaker,
|
joinMatchmaker,
|
||||||
onMatchData,
|
onMatchData,
|
||||||
sendMatchData,
|
sendMatchData,
|
||||||
|
listOpenMatches,
|
||||||
matchId,
|
matchId,
|
||||||
} = useNakama();
|
} = useNakama();
|
||||||
|
|
||||||
@@ -32,6 +36,25 @@ export default function TicTacToe() {
|
|||||||
});
|
});
|
||||||
}, [onMatchData]);
|
}, [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
|
// CONNECT
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
@@ -82,6 +105,9 @@ export default function TicTacToe() {
|
|||||||
/>
|
/>
|
||||||
<button onClick={connect}>Connect</button>
|
<button onClick={connect}>Connect</button>
|
||||||
<button onClick={startQueue}>Join Matchmaking</button>
|
<button onClick={startQueue}>Join Matchmaking</button>
|
||||||
|
<MatchList
|
||||||
|
matches={openMatches}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import {
|
|||||||
Session,
|
Session,
|
||||||
Socket,
|
Socket,
|
||||||
MatchmakerTicket,
|
MatchmakerTicket,
|
||||||
Match,
|
|
||||||
MatchData,
|
MatchData,
|
||||||
MatchmakerMatched,
|
MatchmakerMatched,
|
||||||
} from "@heroiclabs/nakama-js";
|
} from "@heroiclabs/nakama-js";
|
||||||
|
// @ts-ignore
|
||||||
|
import { ApiMatch } from "@heroiclabs/nakama-js/dist/api.gen"
|
||||||
|
|
||||||
import React, { createContext, useContext, useState } from "react";
|
import React, { createContext, useContext, useState } from "react";
|
||||||
|
|
||||||
function getOrCreateDeviceId(): string {
|
function getOrCreateDeviceId(): string {
|
||||||
@@ -32,6 +34,7 @@ export interface NakamaContextType {
|
|||||||
sendMatchData(matchId: string, op: number, data: object): void;
|
sendMatchData(matchId: string, op: number, data: object): void;
|
||||||
|
|
||||||
onMatchData(cb: (msg: any) => void): void;
|
onMatchData(cb: (msg: any) => void): void;
|
||||||
|
listOpenMatches(): Promise<ApiMatch[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NakamaContext = createContext<NakamaContextType>(null!);
|
export const NakamaContext = createContext<NakamaContextType>(null!);
|
||||||
@@ -128,6 +131,19 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listOpenMatches(): Promise<ApiMatch[]> {
|
||||||
|
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 (
|
return (
|
||||||
<NakamaContext.Provider
|
<NakamaContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@@ -140,6 +156,7 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) {
|
|||||||
joinMatch,
|
joinMatch,
|
||||||
sendMatchData,
|
sendMatchData,
|
||||||
onMatchData,
|
onMatchData,
|
||||||
|
listOpenMatches,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user