/* eslint-disable react-hooks/exhaustive-deps */ "use client"; import { useEffect, useState, useRef } from "react"; // import Image from "next/image"; import OpenGames from "./OpenGames"; import GameModal from "./GameModal"; import { HowItWorksModal } from "./HowItWorksModal"; import { FirstVisitModal } from "./FirstVisitModal"; import YourGames from "./YourGames"; import { Bet } from "@/types/Bet"; import { fetchOpenBets, createBet, getVaultByAddress, fetchOpenBetsDev } from "@/shared/solana_helpers"; import { ConnectedSolanaWallet, usePrivy, useSolanaWallets } from "@privy-io/react-auth"; import { RematchModal } from "./RematchModal"; import { API_URL, CLUSTER_URL } from '../data/shared'; import { clusterApiUrl } from "@solana/web3.js"; import { getCurrencyByMint } from "@/data/currencies"; export default function HeroSection() { const [isModalOpen, setIsModalOpen] = useState(false); const [isGameModalOpen, setIsGameModalOpen] = useState(false); const [isFirstVisitModalOpen, setIsFirstVisitModalOpen] = useState(false); const [bets, setBets] = useState([]); const [solWallet, setSolWallet] = useState(); const [myActiveBet, setMyActiveBet] = useState(); const [rematch, setRematch] = useState(false); const [lastActiveBet, setLastActiveBet] = useState(); const [rematchInProgress, setRematchInProgress] = useState(false); const [rematchTxError, setRematchTxError] = useState(false); const { wallets, ready } = useSolanaWallets(); const { user } = usePrivy(); const iframeRef = useRef(null); // Check if this is the user's first visit useEffect(() => { if (typeof window !== 'undefined') { const hasVisited = localStorage.getItem('duelfi_has_visited'); if (!hasVisited) { setIsFirstVisitModalOpen(true); localStorage.setItem('duelfi_has_visited', 'true'); } } }, []); const game_close_signal = (status: number) => { setRematch(status == 1); setMyActiveBet(undefined); }; const updateBets = async () => { if(ready){ const wallet = wallets.find((_wallet) => _wallet.type === "solana") || wallets[0]; setSolWallet(wallet); } let fetchedBets:Bet[] = []; if(CLUSTER_URL == clusterApiUrl("devnet")){ fetchedBets = await fetchOpenBetsDev(); }else{ fetchedBets = await fetchOpenBets(); } const filteredBets = fetchedBets.filter((bet) => !(bet.owner_id && bet.joiner_id)); const filledBets = fetchedBets.filter((bet) => bet.owner_id && bet.joiner_id); setBets(filteredBets); if (!ready || wallets.length === 0) return; let activeBet = filledBets.find((bet) => bet.owner_id === user?.id || bet.joiner_id === user?.id); if(activeBet){ await new Promise(resolve => setTimeout(resolve, 2000)); const betHistoryResponse = await fetch(`${API_URL}get_game_completed.php?address=${activeBet.address}`); const betHistory = await betHistoryResponse.text(); console.log(`bet history for ${activeBet.address}: ${betHistory}`); if(betHistory == "1"){ activeBet = undefined; } } if(rematch){ setMyActiveBet(undefined); return; } if (!myActiveBet && lastActiveBet?.address !== activeBet?.address) { setMyActiveBet(activeBet); setLastActiveBet(activeBet); } }; const handleCreateRematch = async () => { console.log('Creating rematch...'); if (!lastActiveBet || !solWallet) return; setRematchInProgress(true); setRematchTxError(false); try { const currency = getCurrencyByMint(lastActiveBet.currency ?? "SOL"); // Step 1: Create new bet const tx = await createBet( solWallet, user?.id ?? "", lastActiveBet.wager, lastActiveBet.id, true, currency?.tokenAddress ?? "11111111111111111111111111111111" ); console.log("Rematch created. Transaction ID:", tx); // Step 2: Inform backend of rematch link const set_response = await fetch( `${API_URL}set_rematch_address.php?address=${lastActiveBet.address}&rematch_address=${tx}` ); console.log(await set_response.text()); // Step 3: Poll until vault account is found const pollUntilFound = async ( maxRetries = 10, delayMs = 10000 ): Promise => { for (let i:number = 0; i < maxRetries; i++) { const vault = await getVaultByAddress(solWallet, tx); if (vault) return vault; console.log(`Waiting for vault account... (${i + 1}/${maxRetries})`); await new Promise(res => setTimeout(res, delayMs)); } return undefined; }; const newBetAcc = await pollUntilFound(); if (!newBetAcc) { console.error("Failed to retrieve new bet vault after retries."); setRematchTxError(true); } else { // Step 4: Set new active bet setMyActiveBet(newBetAcc); setLastActiveBet(newBetAcc); setRematch(false); } } catch (err) { console.error("Create rematch failed:", err); setRematchTxError(true); } finally { setRematchInProgress(false); } }; const handleJoinRematch = async () => { if (!lastActiveBet || !solWallet) return; try { const pollForRematchAddress = async ( maxRetries = 10, delayMs = 10000 ): Promise => { for (let i = 0; i < maxRetries; i++) { console.log(`Polling rematch address... (${i + 1}/${maxRetries})`); const response = await fetch( `${API_URL}get_rematch_address.php?address=${lastActiveBet.address}` ); const rematchAddress = (await response.text()).trim(); if (rematchAddress.length > 5) { console.log("Found rematch address:", rematchAddress); return rematchAddress; } await new Promise(res => setTimeout(res, delayMs)); } console.warn("Rematch address not found after max retries."); return null; }; const rematchAddress = await pollForRematchAddress(); if (!rematchAddress) return; const pollForVault = async ( address: string, maxRetries = 10, delayMs = 10000 ): Promise => { for (let i:number = 0; i < maxRetries; i++) { console.log(`Polling vault for address ${address}... (${i + 1}/${maxRetries})`); const vault = await getVaultByAddress(solWallet, address); if (vault) return vault; await new Promise(res => setTimeout(res, delayMs)); } console.warn("Vault not found after max retries."); return; }; const rematchVault:Bet | undefined = await pollForVault(rematchAddress); if (rematchVault) { // const tx = await joinBet(solWallet, user?.id!, rematchVault.id, rematchVault.address); setMyActiveBet(rematchVault); setLastActiveBet(rematchVault); setRematch(false); console.log("Rematch vault set as active."); } } catch (err) { console.error("Error during handleJoinRematch:", err); } }; useEffect(() => { if(rematch){ if(true){ handleCreateRematch(); }else{ handleJoinRematch(); } } },[rematch, handleCreateRematch, handleJoinRematch]); useEffect(() => { if (ready) { updateBets(); } }, [ready]); useEffect(() => { if (!ready) return; updateBets(); const interval = setInterval(updateBets, 3000); return () => clearInterval(interval); }, [ready]); useEffect(() => { const handleMessage = (event: MessageEvent) => { if (event.origin === window.location.origin && typeof event.data === "string") { try { const message = JSON.parse(event.data); if (message?.type === "gameClose" && typeof message.status === "number") { game_close_signal(message.status); } } catch (error) { console.error("JSON parse error from Unity message:", error); } } }; window.addEventListener("message", handleMessage); return () => window.removeEventListener("message", handleMessage); }, []); return ( <> {myActiveBet ? ( ( myActiveBet.owner_id && myActiveBet.joiner_id ? (