Skip to content

Commit

Permalink
Fix Hydration error and frontend changes
Browse files Browse the repository at this point in the history
  • Loading branch information
luloxi committed Jan 12, 2024
1 parent c6099e5 commit 1805a30
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 113 deletions.
4 changes: 4 additions & 0 deletions packages/hardhat/contracts/TicTacToe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ contract TicTacToe {
return games[_gameId].moves % 2 == 0 ? 1 : 2;
}

function getNumberOfMoves(uint256 _gameId) public view returns (uint8) {
return games[_gameId].moves;
}

function getBoard(uint256 _gameId) external view returns (uint8[9] memory) {
return games[_gameId].board;
}
Expand Down
7 changes: 1 addition & 6 deletions packages/nextjs/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,7 @@ export const Header = () => {
</div>
<div className="flex flex-col">
<span className="font-bold leading-tight">TicTacToe</span>
<span className="text-xs">
Made with{" "}
<Link className={"underline"} href="https://scaffoldeth.io/">
Scaffold-ETH 2
</Link>
</span>
<span className="text-xs">Made with Scaffold-ETH 2</span>
</div>
</Link>
<ul className="hidden lg:flex lg:flex-nowrap menu menu-horizontal px-1 gap-2">
Expand Down
157 changes: 95 additions & 62 deletions packages/nextjs/components/tictactoe/TicTacToeBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import React, { useEffect, useState } from "react";
import { Address } from "../scaffold-eth";
import { Button, Flex, Grid } from "@chakra-ui/react";
import { Box, Button, Flex, Grid } from "@chakra-ui/react";
import { ethers } from "ethers";
import { useScaffoldContractRead, useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
import { TicTacToeBoardProps } from "~~/types/TicTacToeTypes";

const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({ game, isGameAccepted, movesAmount, isGameFinished }) => {
const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({ game, isGameAccepted, isGameFinished }) => {
const [position, setPosition] = useState<number>(0);
const [board, setBoard] = useState<number[]>(Array(9).fill(0)); // Initialize an empty board

const { data: getBoard } = useScaffoldContractRead({
const { data: boardFromContract } = useScaffoldContractRead({
contractName: "TicTacToe",
functionName: "getBoard",
args: [BigInt(game.gameId)],
});

console.log("getBoard reads: ", getBoard);
const { data: numberOfMoves } = useScaffoldContractRead({
contractName: "TicTacToe",
functionName: "getNumberOfMoves",
args: [BigInt(game.gameId)],
});

console.log("boardFromContract: ", boardFromContract);
console.log("numberOfMoves: ", numberOfMoves);

useEffect(() => {
// Update the local board based on the latest data from the contract
if (getBoard) {
setBoard(getBoard.map(Number));
if (boardFromContract) {
setBoard(boardFromContract.map(Number));
}
}, [getBoard]);
}, [boardFromContract]);

const { writeAsync: makeMove } = useScaffoldContractWrite({
contractName: "TicTacToe",
Expand All @@ -46,68 +53,94 @@ const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({ game, isGameAccepted, m
};

return (
<div key={game.gameId}>
<Flex alignItems={"center"} justifyContent={"center"} paddingTop={3}>
GameId: {game.gameId}
<Box key={game.gameId}>
<Flex fontSize={24} textColor={"red"} alignItems={"center"} justifyContent={"center"} paddingTop={3}>
Game Id #
<Box fontSize={36} textColor={"white"}>
<strong> {game.gameId}</strong>
</Box>
</Flex>
<Flex direction="row" justifyContent={"space-around"} gap={6}>
<p>
<Flex direction="row" justifyContent={"space-around"} textAlign={"center"} gap={6} padding={3}>
<Box>
Player 1: <Address address={game.player1} />
</p>
<p>
</Box>
<Box>
Player 2: <Address address={game.player2} />
</p>
<p>
Each player bets: <br /> {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
</p>
</Box>
</Flex>
<Flex direction="row" justifyContent={"space-around"} gap={6}>
<p>
Is game accepted?: <br />
{isGameAccepted ? (
"Yes"
) : (
<Button colorScheme={"red"} onClick={() => acceptGame()}>
{isGameAccepted ? (
""
) : (
<Flex
direction="row"
alignItems={"center"}
textAlign={"center"}
justifyContent={"space-around"}
gap={6}
paddingBottom={3}
>
<Box>
<Button colorScheme={"green"} onClick={() => acceptGame()}>
Accept game
</Button>
)}
</p>
<p>
# of moves made: <br />
{movesAmount}
</p>
<p>
Is game finished?: <br />
{isGameFinished ? "Yes" : "No"}
</p>
</Flex>

</Box>
<Box>
Each player bets: <br /> {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
</Box>
</Flex>
)}
{isGameAccepted ? (
<Flex
direction="row"
alignItems={"center"}
textAlign={"center"}
justifyContent={"space-around"}
gap={6}
paddingBottom={3}
>
<Box>
Each player betted: <br /> {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
</Box>
<Box>
# of moves made: <br />
{numberOfMoves}
</Box>
<Box>
Game state: <br />
{isGameFinished ? "Finished" : "Not finished"}
</Box>
</Flex>
) : (
""
)}
{/* Render the Tic Tac Toe board here */}
<Grid templateColumns="repeat(3, 1fr)" gap={2}>
{board.map((cell, index) => (
<Button
key={index}
size="xl"
fontSize="4xl"
fontWeight="bold"
colorScheme="gray"
width={70}
height={70}
disabled={cell !== 0 || !isGameAccepted || isGameFinished}
onClick={() => {
if (!isGameFinished) {
setPosition(index);
handleMakeMove();
}
}}
>
{cell === 1 ? "✖️" : cell === 2 ? "⭕" : ""}
</Button>
))}
</Grid>
<p></p>
<hr />
</div>
{isGameAccepted ? (
<Grid templateColumns="repeat(3, 1fr)" gap={2}>
{board.map((cell, index) => (
<Button
key={index}
size="xl"
fontSize="4xl"
fontWeight="bold"
colorScheme="gray"
width={70}
height={70}
disabled={cell !== 0 || !isGameAccepted || isGameFinished}
onClick={() => {
if (!isGameFinished) {
setPosition(index);
handleMakeMove();
}
}}
>
{cell === 1 ? "✖️" : cell === 2 ? "⭕" : ""}
</Button>
))}
</Grid>
) : (
""
)}
</Box>
);
};

Expand Down
21 changes: 20 additions & 1 deletion packages/nextjs/contracts/deployedContracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";
const deployedContracts = {
31337: {
TicTacToe: {
address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
abi: [
{
anonymous: false,
Expand Down Expand Up @@ -241,6 +241,25 @@ const deployedContracts = {
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "_gameId",
type: "uint256",
},
],
name: "getNumberOfMoves",
outputs: [
{
internalType: "uint8",
name: "",
type: "uint8",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
Expand Down
56 changes: 14 additions & 42 deletions packages/nextjs/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { useEffect, useState } from "react";
import { GameAcceptedProps, GameCreatedProps, GameFinishedProps, MoveMadeProps } from "../types/TicTacToeTypes";
import { GameAcceptedProps, GameCreatedProps, GameFinishedProps } from "../types/TicTacToeTypes";
import { Card, CardBody, Flex, Heading } from "@chakra-ui/react";
import type { NextPage } from "next";
import { MetaHeader } from "~~/components/MetaHeader";
import CreateChallengeBox from "~~/components/tictactoe/CreateChallengeBox";
import TicTacToeBoard from "~~/components/tictactoe/TicTacToeBoard";
import { useScaffoldEventHistory, useScaffoldEventSubscriber } from "~~/hooks/scaffold-eth";
import { useScaffoldContractRead, useScaffoldEventHistory, useScaffoldEventSubscriber } from "~~/hooks/scaffold-eth";

const Home: NextPage = () => {
const [gameHistory, setGameHistory] = useState<GameCreatedProps[]>([]);
const [gameAcceptedHistory, setGameAcceptedHistory] = useState<GameAcceptedProps[]>([]);
const [moveMadeHistory, setMoveMadeHistory] = useState<MoveMadeProps[]>([]);
const [gameFinishedHistory, setGameFinishedHistory] = useState<GameFinishedProps[]>([]);

const { data: gameIdCounter } = useScaffoldContractRead({
contractName: "TicTacToe",
functionName: "gameIdCounter",
args: undefined,
});

console.log("gameIdCounter: ", gameIdCounter);

// Event history hooks
const { data: GameCreatedHistory } = useScaffoldEventHistory({
contractName: "TicTacToe",
Expand All @@ -28,13 +35,6 @@ const Home: NextPage = () => {
blockData: false,
});

const { data: MoveMadeHistory } = useScaffoldEventHistory({
contractName: "TicTacToe",
eventName: "MoveMade",
fromBlock: BigInt(process.env.NEXT_PUBLIC_DEPLOY_BLOCK || "0"),
blockData: false,
});

const { data: GameFinishedHistory } = useScaffoldEventHistory({
contractName: "TicTacToe",
eventName: "GameFinished",
Expand Down Expand Up @@ -62,15 +62,6 @@ const Home: NextPage = () => {
setGameAcceptedHistory(mappedHistory);
}, [GameAcceptedHistory]);

useEffect(() => {
const mappedHistory = MoveMadeHistory?.map(event => ({
gameId: parseInt(event.args[0].toString()),
player: event.args[1],
position: parseInt(event.args[2].toString()),
})) as MoveMadeProps[];
setMoveMadeHistory(mappedHistory);
}, [MoveMadeHistory]);

useEffect(() => {
const mappedHistory = GameFinishedHistory?.map(event => ({
gameId: parseInt(event.args[0].toString()),
Expand Down Expand Up @@ -122,21 +113,6 @@ const Home: NextPage = () => {
},
});

useScaffoldEventSubscriber({
contractName: "TicTacToe",
eventName: "MoveMade",
listener: (logs: any[]) => {
setMoveMadeHistory(indexedHistory => {
const newMoveMade: MoveMadeProps = {
gameId: parseInt(logs[0].args[0].toString()),
player: logs[0].args[1],
position: parseInt(logs[0].args[2].toString()),
};
return [newMoveMade, ...indexedHistory];
});
},
});

useScaffoldEventSubscriber({
contractName: "TicTacToe",
eventName: "GameFinished",
Expand All @@ -154,11 +130,9 @@ const Home: NextPage = () => {

const gameCards = gameHistory?.map(game => {
const isGameAccepted = gameAcceptedHistory.some(acceptedGame => acceptedGame.gameId === game.gameId);
const movesList = moveMadeHistory.filter(move => move.gameId === game.gameId);
const movesAmount = movesList.length;
const isGameFinished = gameFinishedHistory.some(finishedGame => finishedGame.gameId === game.gameId);

return { game, isGameAccepted, movesList, movesAmount, isGameFinished };
return { game, isGameAccepted, isGameFinished };
});

return (
Expand All @@ -184,28 +158,26 @@ const Home: NextPage = () => {
filter: "brightness(0.3)",
}}
/>
<Flex direction={{ base: "column", md: "row" }} justify="center" gap={10} align="center" marginTop={4}>
<Flex direction={{ base: "column", md: "row" }} justify="space-around" gap={10} align="center" marginTop={4}>
<CreateChallengeBox />
<Card
direction={{ base: "column", sm: "row" }}
width="container.sm"
maxWidth={{ base: "container.sm", sm: "container.sm", md: "container.md" }}
variant="solid"
maxHeight={{ base: "container.sm", sm: "container.sm", md: "480" }}
maxHeight={{ base: "container.md", sm: "container.sm", md: "720" }}
overflow={"auto"}
textColor={"white"}
backgroundColor={"gray.900"}
>
<CardBody>
<Heading size="xl">⭕ See your active challenges! ❌</Heading>
<Flex direction="column" alignItems="center" justifyContent="center">
{gameCards?.map(({ game, isGameAccepted, movesList, movesAmount, isGameFinished }) => (
{gameCards?.map(({ game, isGameAccepted, isGameFinished }) => (
<TicTacToeBoard
key={game.gameId}
game={game}
isGameAccepted={isGameAccepted}
movesList={movesList}
movesAmount={movesAmount}
isGameFinished={isGameFinished}
/>
))}
Expand Down
2 changes: 0 additions & 2 deletions packages/nextjs/types/TicTacToeTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,5 @@ export type GameFinishedProps = {
export type TicTacToeBoardProps = {
game: GameCreatedProps;
isGameAccepted: boolean;
movesList: MoveMadeProps[];
movesAmount: number;
isGameFinished: boolean;
};

0 comments on commit 1805a30

Please sign in to comment.