diff --git a/src/components/ChessGame/ChessGame.tsx b/src/components/ChessGame/ChessGame.tsx
index 3309e614..db069a88 100644
--- a/src/components/ChessGame/ChessGame.tsx
+++ b/src/components/ChessGame/ChessGame.tsx
@@ -22,8 +22,8 @@ const ChessGame = ({ id, type }: ChessGameType) => {
moves,
playing,
customSquares,
- gameFen,
- setGameFen,
+ // gameFen,
+ // setGameFen,
onPieceDrop,
undoMove,
startGame,
@@ -65,7 +65,7 @@ const ChessGame = ({ id, type }: ChessGameType) => {
id={id}
onPieceDrop={onPieceDrop}
// boardOrientation="black" TODO: make the bot play 1st, or just ignore, bot ALWAYS 'black'.
- position={gameFen}
+ position={game.fen()}
customBoardStyle={{
borderRadius: "8px",
boxShadow: "0 2px 10px rgba(0, 0, 0, 0.5)",
@@ -81,7 +81,7 @@ const ChessGame = ({ id, type }: ChessGameType) => {
{playing ? (
) : (
diff --git a/src/hooks/useChessSocket.tsx b/src/hooks/useChessSocket.tsx
index 1c2d473c..3a1ecd03 100644
--- a/src/hooks/useChessSocket.tsx
+++ b/src/hooks/useChessSocket.tsx
@@ -3,6 +3,7 @@ import React from "react";
import { Chess, Move, Square } from "chess.js";
import { io, Socket } from "socket.io-client";
import { CustomSquares, ShortMove } from "@/types";
+import { useLocalStorage } from "./useLocalStorage";
export type ChessType = "random" | "computer" | "minimax";
@@ -65,6 +66,22 @@ const useChessSocket = ({ type, id }: Props) => {
}
}, [disconnectSocket, setConnectionStatus, socket]);
+ React.useEffect(() => {
+ // Auto open socket connection on page load
+ connectSocket();
+ const savedMoves = localStorage.getItem(`@stockchess/useLocalStorage/ComputerChessBoard-moves`)
+ if (savedMoves) {
+ const parsedSavedMoves = JSON.parse(savedMoves) as Move[];
+ const newGame = new Chess();
+ try {
+ parsedSavedMoves.forEach((move) => newGame.move(move));
+ } catch (error) {
+ console.log("[!!!] Error in initializing saved game: ", error);
+ }
+ setGame(newGame);
+ }
+ }, []);
+
// Send latest move over socket
const sendMove = (move: string) => {
console.log("MOVE: ", move);
@@ -93,9 +110,17 @@ const useChessSocket = ({ type, id }: Props) => {
// End of socket
const [game, setGame] = useState(new Chess());
- const [playing, setPlaying] = useState(false);
- const [moves, setMoves] = useState([]);
- const [gameFen, setGameFen] = useState(game.fen());
+ // const [playing, setPlaying] = useState(false);
+ const [playing, setPlaying] = useLocalStorage({
+ name: `${id}-is-playing`,
+ defaultValue: false,
+ });
+ const [moves, setMoves] = useLocalStorage({
+ name: `${id}-moves`,
+ defaultValue: [],
+ });
+ // const [moves, setMoves] = useState([]);
+ // const [gameFen, setGameFen] = useState("start");
const [currentTimeout, setCurrentTimeout] = useState();
const [customSquares, updateCustomSquares] = useReducer(squareReducer, {
check: {},
@@ -107,9 +132,9 @@ const useChessSocket = ({ type, id }: Props) => {
const result = gameCopy.move(move);
if (result) {
- setMoves((prevMoves) => [result, ...prevMoves]);
+ setMoves(gameCopy.history({verbose: true}));
setGame(gameCopy);
- setGameFen(gameCopy.fen());
+ // setGameFen(gameCopy.fen());
let kingSquare = undefined;
if (game.inCheck()) {
@@ -156,7 +181,7 @@ const useChessSocket = ({ type, id }: Props) => {
const gameCopy = game;
gameCopy.reset();
setGame(gameCopy);
- setGameFen(gameCopy.fen());
+ // setGameFen(gameCopy.fen());
cleanOldGame();
setMoves([]);
@@ -166,7 +191,8 @@ const useChessSocket = ({ type, id }: Props) => {
};
const startGame = () => {
- connectSocket();
+ // NOTE: I think it's better to init socket on page load
+ // connectSocket();
resetGame();
setPlaying(true);
};
@@ -183,8 +209,7 @@ const useChessSocket = ({ type, id }: Props) => {
movesCopy.shift();
setGame(gameCopy);
- setGameFen(gameCopy.fen());
- setMoves(movesCopy);
+ // setGameFen(gameCopy.fen());
updateCustomSquares({ check: undefined }); // Reset style
};
@@ -195,8 +220,9 @@ const useChessSocket = ({ type, id }: Props) => {
customSquares,
- gameFen,
- setGameFen,
+ // NOTE: Since FEN can be easily extract from `games`, we dont need to maintain it
+ // gameFen,
+ // setGameFen,
onPieceDrop,
undoMove,
diff --git a/src/hooks/useLocalStorage.tsx b/src/hooks/useLocalStorage.tsx
new file mode 100644
index 00000000..c39aaf47
--- /dev/null
+++ b/src/hooks/useLocalStorage.tsx
@@ -0,0 +1,55 @@
+import { useState, useEffect } from 'react';
+
+type Args = {
+ name: string;
+ defaultValue: T;
+};
+
+export function useLocalStorage(args: Args): [T, (arg: T) => void, () => void] {
+ const { defaultValue, name } = args;
+ const [value, setValue] = useState(undefined);
+ const persistenceKey = `@stockchess/useLocalStorage/${name}`;
+
+ useEffect(function didMount() {
+ if (isLocalStorageAvailable()) {
+ const persistedState = localStorage.getItem(persistenceKey);
+ if (persistedState) {
+ setValue(JSON.parse(persistedState));
+ } else {
+ // setValue(defaultValue);
+ // setValue()
+ }
+ }
+ }, []);
+
+ useEffect(
+ function persistOnChange() {
+ if (isLocalStorageAvailable() && value !== undefined)
+ localStorage.setItem(persistenceKey, JSON.stringify(value));
+ },
+ [value]
+ );
+
+ function removeValue() {
+ if (isLocalStorageAvailable()) localStorage.removeItem(persistenceKey);
+ }
+
+ return [value ?? defaultValue, setValue, removeValue];
+}
+
+export function isLocalStorageAvailable(): boolean {
+ try {
+ if (!window.localStorage || localStorage === null || typeof localStorage === 'undefined') {
+ return false;
+ }
+
+ localStorage.setItem('localStorage:test', 'value');
+ if (localStorage.getItem('localStorage:test') !== 'value') {
+ return false;
+ }
+ localStorage.removeItem('localStorage:test');
+ return true;
+ } catch {
+ return false;
+ }
+}