"use client"; import { useEffect, useState } from "react"; import Web3 from "web3"; import Commit from "./Commit"; import Reveal from "./Reveal"; import { showErrorToast } from "@/app/lib/toast"; export type Player = { addr: string; bet: string; encrMove: string; move: number; nickname: string; }; export type GameDetails = { playerA: Player; playerB: Player; initialBet: string; outcome: number; isActive: boolean; returnGameId: number; }; interface GameModalProps { gameId?: number; isOpen: boolean; onClose: () => void; account: string; contract: any; config: Config | null; web3: Web3 | null; setStatus: (status: string) => void; } export default function GameModal({ gameId, isOpen, onClose, account, contract, config, web3, setStatus, }: Readonly) { const [phase, setPhase] = useState<"commit" | "reveal">("commit"); const [whoAmI, setWhoAmI] = useState<"player1" | "player2" | "">(""); const [gameDetails, setGameDetails] = useState(null); const [selectedMove, setSelectedMove] = useState(null); const [secret, setSecret] = useState(""); // Helper function to generate game-specific storage key const getGameStorageKey = () => `game_${gameDetails?.returnGameId}`; // Game storage object structure type GameStorage = { secret: string; selectedMove: string | null; playMove: string; }; // Storage helper functions const loadFromStorage = () => { if (!gameDetails) return; const storedData = sessionStorage.getItem(getGameStorageKey()); if (storedData) { try { const parsed: GameStorage = JSON.parse(storedData); if (parsed.secret) setSecret(parsed.secret); if (parsed.selectedMove) setSelectedMove(parsed.selectedMove); } catch (err) { console.error("Failed to parse stored game data:", err); } } }; const saveGameData = (updates: Partial) => { const storedData = sessionStorage.getItem(getGameStorageKey()); let currentData: GameStorage = { secret: "", selectedMove: null, playMove: "" }; if (storedData) { try { currentData = JSON.parse(storedData); } catch (err) { console.error("Failed to parse stored game data:", err); } } const updatedData = { ...currentData, ...updates }; sessionStorage.setItem(getGameStorageKey(), JSON.stringify(updatedData)); }; const saveSecret = (value: string) => { setSecret(value); saveGameData({ secret: value }); }; const saveMoveSelection = (move: string | null) => { setSelectedMove(move); if (move !== null) { saveGameData({ selectedMove: move }); } }; const savePlayMove = (playMove: string) => { saveGameData({ playMove }); }; useEffect(() => { const fetchPlayerInfo = async () => { if (contract && account && gameId !== undefined) { try { let player = await contract.methods.whoAmI(gameId).call({ from: account }); if(player == 1) player = "player1"; else if(player == 2) player = "player2"; else player = ""; setWhoAmI(player); } catch (err: any) { showErrorToast("Error fetching player info: " + err.message); } } } const fetchGameDetails = async () => { if (contract && gameId !== undefined) { try { const details = await contract.methods.getGameDetails(gameId).call(); console.log("Game details:", details); setGameDetails(details); // Determine the correct phase based on game state const playerAHasMove = Number(details.playerA.encrMove) !== 0; const playerBHasMove = Number(details.playerB.encrMove) !== 0; const playerARevealed = Number(details.playerA.move) !== 0; const playerBRevealed = Number(details.playerB.move) !== 0; // If both players have revealed their moves, show reveal phase (with results) if (playerARevealed && playerBRevealed) { setPhase("reveal"); } // If both players have committed but not revealed, show reveal phase else if (playerAHasMove && playerBHasMove) { setPhase("reveal"); } // Otherwise, show commit phase else { setPhase("commit"); } } catch (err: any) { showErrorToast("Error fetching game details: " + err.message); } } }; // Only reset state when game ID actually changes (not on first render) if (gameDetails) { setSelectedMove(null); setSecret(""); } fetchGameDetails(); fetchPlayerInfo(); // Refetch game details periodically every 2 seconds const intervalId = setInterval(fetchGameDetails, 2000); return () => clearInterval(intervalId); }, [contract, account, gameId]); // Load from storage after game details are fetched useEffect(() => { loadFromStorage(); }, [gameDetails]); const handleClose = () => { // Reset state when closing setPhase("commit"); setSelectedMove(null); setSecret(""); onClose(); }; if (!isOpen) return null; return (
{/* Header */}

{gameId ? `Game #${gameId}` : "Game"}

{phase === "commit" ? "Commit your move" : "Reveal your move"}

{/* Content */}
{/* Phase Content */}
{phase === "commit" && ( )} {phase === "reveal" && ( )}
); }