diff --git a/client/src/app/game/[code]/page.tsx b/client/src/app/game/[code]/page.tsx
index 8345876..5034bda 100644
--- a/client/src/app/game/[code]/page.tsx
+++ b/client/src/app/game/[code]/page.tsx
@@ -1,4 +1,4 @@
-import Game from "@/components/game/Game";
+import GameWrapper from "@/components/game/GameWrapper";
import { getGame } from "@/lib/game";
import { notFound } from "next/navigation";
@@ -8,5 +8,5 @@ export default async function GamePage({ params }: { params: { code: string } })
notFound();
}
- return ;
+ return ;
}
diff --git a/client/src/components/game/Game.tsx b/client/src/components/game/GameWrapper.tsx
similarity index 64%
rename from client/src/components/game/Game.tsx
rename to client/src/components/game/GameWrapper.tsx
index 46602af..7ef9bc0 100644
--- a/client/src/components/game/Game.tsx
+++ b/client/src/components/game/GameWrapper.tsx
@@ -1,22 +1,90 @@
"use client";
-// all of this in a client component for now to easily handle socket events
+// TODO: restructure?
import { Chessboard } from "react-chessboard";
import { IconCopy } from "@tabler/icons-react";
-import { useState, useEffect } from "react";
+import { useState, useEffect, useContext } from "react";
import Image from "next/image";
import { Game } from "@chessu/types";
import { io } from "socket.io-client";
import { API_URL } from "@/config";
+import { SessionContext } from "@/context/session";
+import { Chess } from "chess.js";
-const socket = io(API_URL, { withCredentials: true, autoConnect: true });
-
-const pgn = "1. e4 e5 2. f3 Nf6 3. d4 exd4 4. Qxd4 Nxe4 5. Qxe4+ Qe7 6. Qxe7+";
+const socket = io(API_URL, { withCredentials: true, autoConnect: false });
export default function GameWrapper({ initialLobby }: { initialLobby: Game }) {
+ const session = useContext(SessionContext);
+
+ // TODO: useReducer
const [lobbyData, setLobbyData] = useState(initialLobby);
- // TODO
+ const [game, setGame] = useState(new Chess());
+ const [side, setSide] = useState<"b" | "w" | "s">("s");
+
+ const [boardWidth, setBoardWidth] = useState(480);
+
+ useEffect(() => {
+ if (!session?.user || !session.user?.id) return;
+
+ window.addEventListener("resize", handleResize);
+ handleResize();
+
+ if (game.pgn() !== lobbyData.pgn) {
+ const gameCopy = { ...game } as Chess;
+ gameCopy.loadPgn(lobbyData.pgn as string);
+ setGame(gameCopy);
+ }
+
+ if (lobbyData.black?.id === session?.user?.id) {
+ if (side !== "b") setSide("b");
+ } else if (lobbyData.white?.id === session?.user?.id) {
+ if (side !== "w") setSide("w");
+ } else if (side !== "s") {
+ setSide("s");
+ }
+
+ socket.on("connect", () => {
+ socket.emit("joinLobby", initialLobby.code);
+ });
+ // TODO: handle disconnect
+
+ socket.on("receivedLatestLobby", (latestLobby: Game) => {
+ setLobbyData(latestLobby);
+
+ if (latestLobby.pgn && latestLobby.pgn !== game.pgn()) {
+ const gameCopy = { ...game } as Chess;
+ gameCopy.loadPgn(lobbyData.pgn as string);
+ setGame(gameCopy);
+ }
+
+ if (latestLobby.black?.id === session?.user?.id) {
+ if (side !== "b") setSide("b");
+ } else if (latestLobby.white?.id === session?.user?.id) {
+ if (side !== "w") setSide("w");
+ } else if (side !== "s") {
+ setSide("s");
+ }
+ });
+
+ return () => {
+ socket.off("connect");
+ socket.off("receivedLatestLobby");
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [session?.user]);
+
+ function handleResize() {
+ if (window.innerWidth >= 1920) {
+ setBoardWidth(580);
+ } else if (window.innerWidth >= 1536) {
+ setBoardWidth(540);
+ } else if (window.innerWidth >= 768) {
+ setBoardWidth(480);
+ } else {
+ setBoardWidth(350);
+ }
+ }
return (
@@ -30,10 +98,11 @@ export default function GameWrapper({ initialLobby }: { initialLobby: Game }) {
@@ -70,7 +139,7 @@ export default function GameWrapper({ initialLobby }: { initialLobby: Game }) {
- {pgn
+ {(lobbyData.pgn as string)
.split(/\d+\./)
.filter((move) => move.trim() !== "")
.map((moveSet, i) => {