Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"history": "^5.3.0",
"lucide-react": "^0.372.0",
"react": "^18.2.0",
"react-chessboard": "^4.5.0",
"react-confetti": "^6.1.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
Expand Down
39 changes: 0 additions & 39 deletions apps/frontend/src/components/ChessBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { useRecoilState } from 'recoil';
import {
isBoardFlippedAtom,
movesAtom,
userSelectedMoveIndexAtom,
} from '@repo/store/chessBoard';

export function isPromoting(chess: Chess, from: Square, to: Square) {
Expand Down Expand Up @@ -77,9 +76,6 @@ export const ChessBoard = memo(({
const { height, width } = useWindowSize();

const [isFlipped, setIsFlipped] = useRecoilState(isBoardFlippedAtom);
const [userSelectedMoveIndex, setUserSelectedMoveIndex] = useRecoilState(
userSelectedMoveIndexAtom,
);
const [moves, setMoves] = useRecoilState(movesAtom);
const [lastMove, setLastMove] = useState<{ from: string; to: string } | null>(
null,
Expand Down Expand Up @@ -182,32 +178,6 @@ export const ChessBoard = memo(({
}
}, [moves]);

useEffect(() => {
if (userSelectedMoveIndex !== null) {
const move = moves[userSelectedMoveIndex];
setLastMove({
from: move.from,
to: move.to,
});
chess.load(move.after);
setBoard(chess.board());
return;
}
}, [userSelectedMoveIndex]);

useEffect(() => {
if (userSelectedMoveIndex !== null) {
chess.reset();
moves.forEach((move) => {
chess.move({ from: move.from, to: move.to });
});
setBoard(chess.board());
setUserSelectedMoveIndex(null);
} else {
setBoard(chess.board());
}
}, [moves]);

return (
<>
{gameOver && <Confetti />}
Expand Down Expand Up @@ -248,15 +218,6 @@ export const ChessBoard = memo(({
if (!started) {
return;
}
if (userSelectedMoveIndex !== null) {
chess.reset();
moves.forEach((move) => {
chess.move({ from: move.from, to: move.to });
});
setBoard(chess.board());
setUserSelectedMoveIndex(null);
return;
}
if (!from && square?.color !== chess.turn()) return;
if (!isMyTurn) return;
if (from != squareRepresentation) {
Expand Down
68 changes: 68 additions & 0 deletions apps/frontend/src/components/ChessBoardLatest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { BoardOrientation } from '@repo/store/chessBoard';
import { Chess, Color } from 'chess.js';
import { useEffect } from 'react';
import { Chessboard } from 'react-chessboard';
import { useRecoilState } from 'recoil';
import { boardOrientationAtom } from '../../../../packages/store/src/atoms/chessBoard';
import { useLiveGameBoard } from '@/hooks/useLiveGameBoard';

const ChessBoardLatest = ({
gameId,
started,
myColor,
chess,
socket,
}: {
myColor: Color;
gameId: string;
started: boolean;
chess: Chess;
socket: WebSocket;
}) => {
const {
boardState,
handlePieceDrop,
liveGamePosition,
handleSquareClick,
handlePromotionPieceSelect,
handleSquareRightClick,
} = useLiveGameBoard({
gameId,
started,
myColor,
chess,
socket,
});
const [boardOrientation, setBoardOrientation] =
useRecoilState(boardOrientationAtom);

useEffect(() => {
setBoardOrientation(
myColor === 'w' ? BoardOrientation.WHITE : BoardOrientation.BLACK,
);
}, [myColor]);

return (
<Chessboard
onPieceDrop={handlePieceDrop}
position={liveGamePosition}
arePremovesAllowed={true}
onSquareClick={handleSquareClick}
onPromotionPieceSelect={handlePromotionPieceSelect}
onSquareRightClick={handleSquareRightClick}
isDraggablePiece={({ piece }) => piece[0] === myColor}
customSquareStyles={{
...boardState.optionSquares,
...boardState.rightClickedSquares,
}}
customBoardStyle={{
borderRadius: '4px',
}}
promotionToSquare={boardState.moveTo}
showPromotionDialog={boardState.showPromotionDialog}
boardOrientation={boardOrientation}
/>
);
};

export default ChessBoardLatest;
4 changes: 2 additions & 2 deletions apps/frontend/src/components/GameEndModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import WhiteKing from '../../public/wk.png';
import BlackKing from '../../public/bk.png';
import WhiteKing from '/wk.png';
import BlackKing from '/bk.png';
import { GameResult, Result } from '@/screens/Game';

interface ModalProps {
Expand Down
102 changes: 60 additions & 42 deletions apps/frontend/src/components/MovesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {
isBoardFlippedAtom,
movesAtom,
userSelectedMoveIndexAtom,
BoardOrientation,
boardOrientationAtom,
liveGamePositionAtom,
selectedMoveIndexAtom,
} from '@repo/store/chessBoard';
import { Move } from 'chess.js';
import { Chess, Move } from 'chess.js';
import { useEffect, useRef } from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilState, useSetRecoilState } from 'recoil';
import {
HandshakeIcon,
FlagIcon,
Expand All @@ -16,13 +17,14 @@ import {
RefreshCw,
} from 'lucide-react';

const MovesTable = () => {
const [userSelectedMoveIndex, setUserSelectedMoveIndex] = useRecoilState(
userSelectedMoveIndexAtom,
);
const setIsFlipped = useSetRecoilState(isBoardFlippedAtom);
const moves = useRecoilValue(movesAtom);
const MovesTable = ({ chess }: { chess: Chess }) => {
const setLiveGamePosition = useSetRecoilState(liveGamePositionAtom);
const setBoardOrientation = useSetRecoilState(boardOrientationAtom);
const movesTableRef = useRef<HTMLInputElement>(null);
const moves = chess.history({ verbose: true });

const [selectedMoveIndex, setSelectedMoveIndex] = useRecoilState(selectedMoveIndexAtom)

const movesArray = moves.reduce((result, _, index: number, array: Move[]) => {
if (index % 2 === 0) {
result.push(array.slice(index, index + 2));
Expand All @@ -31,13 +33,42 @@ const MovesTable = () => {
}, [] as Move[][]);

useEffect(() => {
console.log("rerender");

setSelectedMoveIndex(null);
if (movesTableRef && movesTableRef.current) {
movesTableRef.current.scrollTo({
top: movesTableRef.current.scrollHeight,
behavior: 'smooth',
});
}
}, [moves]);

const handleMoveSelection = (moveIndex: number | null) => {
const move =
moveIndex !== null ? moves[moveIndex] : moves[moves.length - 1];
setLiveGamePosition(move.after);
setSelectedMoveIndex(moveIndex);
};

const handleGoToMove = (moveIndex: number | null) => {
if (moveIndex === null) {
handleMoveSelection(null);
} else {
const newIndex = Math.max(0, Math.min(moves.length - 1, moveIndex));
handleMoveSelection(newIndex);
}
};

const goToFirstMove = () => handleGoToMove(0);
const goToPreviousMove = () =>
handleGoToMove(
selectedMoveIndex === null ? moves.length - 2 : selectedMoveIndex - 1,
);
const goToNextMove = () =>
handleGoToMove(selectedMoveIndex === null ? null : selectedMoveIndex + 1);
const goToLastMove = () => handleGoToMove(null);

return (
<div className="text-[#C3C3C0] relative w-full ">
<div
Expand All @@ -54,12 +85,11 @@ const MovesTable = () => {
<span className="text-[#C3C3C0] px-2 py-1.5">{`${index + 1}.`}</span>

{movePairs.map((move, movePairIndex) => {
const isLastIndex =
movePairIndex === movePairs.length - 1 &&
movesArray.length - 1 === index;
const moveIndex = index * 2 + movePairIndex;
const isLastIndex = moveIndex === moves.length - 1;
const isHighlighted =
userSelectedMoveIndex !== null
? userSelectedMoveIndex === index * 2 + movePairIndex
selectedMoveIndex !== null
? moveIndex === selectedMoveIndex
: isLastIndex;
const { san } = move;

Expand All @@ -68,7 +98,8 @@ const MovesTable = () => {
key={movePairIndex}
className={`col-span-2 cursor-pointer flex items-center w-full pl-1 ${isHighlighted ? 'bg-[#484644] rounded border-b-[#5A5858] border-b-[3px]' : ''}`}
onClick={() => {
setUserSelectedMoveIndex(index * 2 + movePairIndex);
setLiveGamePosition(move.after);
setSelectedMoveIndex(isLastIndex ? null : moveIndex);
}}
>
<span className="text-[#C3C3C0]">{san}</span>
Expand All @@ -94,55 +125,42 @@ const MovesTable = () => {
</div>
<div className="flex gap-1">
<button
onClick={() => {
setUserSelectedMoveIndex(0);
}}
disabled={userSelectedMoveIndex === 0}
onClick={goToFirstMove}
disabled={selectedMoveIndex === 0}
className="hover:text-white"
title="Go to first move"
>
<ChevronFirst />
</button>

<button
onClick={() => {
setUserSelectedMoveIndex((prev) =>
prev !== null ? prev - 1 : moves.length - 2,
);
}}
disabled={userSelectedMoveIndex === 0}
onClick={goToPreviousMove}
disabled={selectedMoveIndex === 0}
className="hover:text-white"
>
<ChevronLeft />
</button>
<button
onClick={() => {
setUserSelectedMoveIndex((prev) =>
prev !== null
? prev + 1 >= moves.length - 1
? moves.length - 1
: prev + 1
: null,
);
}}
disabled={userSelectedMoveIndex === null}
onClick={goToNextMove}
disabled={
selectedMoveIndex === null ||
selectedMoveIndex === moves.length - 1
}
className="hover:text-white"
>
<ChevronRight />
</button>
<button
onClick={() => {
setUserSelectedMoveIndex(moves.length - 1);
}}
disabled={userSelectedMoveIndex === null}
onClick={goToLastMove}
disabled={selectedMoveIndex === null}
className="hover:text-white"
title="Go to last move"
>
<ChevronLast />
</button>
<button
onClick={() => {
setIsFlipped((prev) => !prev);
setBoardOrientation(prev=> prev === BoardOrientation.WHITE? BoardOrientation.BLACK: BoardOrientation.WHITE)
}}
title="Flip the board"
>
Expand Down
Loading