145 lines
4.5 KiB
TypeScript
145 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { ConnectedSolanaWallet, usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
|
import { Connection, PublicKey } from "@solana/web3.js";
|
|
import { AnchorProvider, Program, BN } from "@coral-xyz/anchor";
|
|
import idl from "../idl/bets_idl.json"; // Ensure this is the correct IDL path
|
|
import { toast } from "sonner";
|
|
import { Bets } from "@/idl/bets";
|
|
import { Game, games } from "../data/games"; // Assuming you have a games data file
|
|
import { PriceSelection } from "./PriceSelection";
|
|
import { GameSelection } from "./GameSelection";
|
|
import { CLUSTER_URL } from "@/data/shared";
|
|
|
|
// Change to Mainnet when deploying
|
|
|
|
interface GameModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function GameModal({ isOpen, onClose }: GameModalProps) {
|
|
const { wallets } = useSolanaWallets();
|
|
const { authenticated } = usePrivy();
|
|
|
|
const [program, setProgram] = useState<Program<Bets>>();
|
|
const [solanaWallet, setSolanaWallet] = useState<ConnectedSolanaWallet>();
|
|
|
|
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
|
const [selectedPrice, setSelectedPrice] = useState<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (wallets.length > 0) {
|
|
const solWallet = wallets[0];
|
|
setSolanaWallet(solWallet);
|
|
|
|
const connection = new Connection(CLUSTER_URL, "confirmed");
|
|
const wallet = {
|
|
publicKey: new PublicKey(solWallet.address),
|
|
signTransaction: solWallet.signTransaction,
|
|
signAllTransactions: solWallet.signAllTransactions,
|
|
};
|
|
|
|
const provider = new AnchorProvider(connection, wallet, {
|
|
preflightCommitment: "processed",
|
|
});
|
|
|
|
const programInstance = new Program<Bets>(idl, provider);
|
|
setProgram(programInstance);
|
|
}
|
|
}, [wallets]);
|
|
|
|
const handleCreateGame = async () => {
|
|
|
|
if (!authenticated) {
|
|
toast.error("Please log in with Privy.");
|
|
return;
|
|
}
|
|
|
|
const wallet = solanaWallet; // Get connected Privy wallet
|
|
if (!wallet) {
|
|
toast.error("Please connect your wallet.");
|
|
return;
|
|
}
|
|
|
|
if (!selectedGame || selectedPrice === null) {
|
|
toast.error("Please select a game and a price.");
|
|
return;
|
|
}
|
|
if (!program) {
|
|
toast.error("Solana program not initialized.");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const nonce = 1;
|
|
const [bet_list_pda] = await PublicKey.findProgramAddress(
|
|
[Buffer.from("bets_list")],
|
|
program.programId
|
|
);
|
|
const connection = new Connection(CLUSTER_URL, "confirmed");
|
|
|
|
console.log(`bets list : ${bet_list_pda}`);
|
|
|
|
// Create transaction
|
|
const tx = await program.methods
|
|
.createBet(new BN(selectedPrice * 1000000000), selectedGame.id, new BN(nonce))
|
|
.accounts({
|
|
betsList: bet_list_pda,
|
|
})
|
|
.transaction(); // Get transaction object instead of RPC call
|
|
|
|
tx.feePayer = new PublicKey(wallet.address);
|
|
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
|
|
// Sign transaction with Privy
|
|
const signedTx = await wallet.signTransaction(tx);
|
|
|
|
// Send transaction// Replace with correct RPC endpoint
|
|
const txId = await connection.sendRawTransaction(signedTx.serialize());
|
|
|
|
toast.success(`Bet created successfully! TX: ${txId}`);
|
|
console.log(`Transaction ID: ${txId}`);
|
|
onClose();
|
|
} catch (error:unknown) {
|
|
|
|
|
|
const errorMessage = String(error); // Converts error to string safely
|
|
|
|
if (errorMessage.includes("already in use")) {
|
|
toast.error("You can't make 2 bets for the same game.");
|
|
} else {
|
|
toast.error("Failed to create bet.");
|
|
console.error(error);
|
|
}
|
|
}
|
|
};
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 bg-black/70 flex justify-center items-start pt-10 z-50" onClick={onClose}>
|
|
<div
|
|
className="bg-[rgb(30,30,30)] text-white w-full max-w-lg p-6 rounded-2xl shadow-lg"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<h2 className="text-xl font-bold mb-4">Create Game</h2>
|
|
|
|
{/* Game Selection */}
|
|
<GameSelection games={games} selectedGame={selectedGame} onSelect={setSelectedGame} />
|
|
|
|
{/* Price Selection */}
|
|
<PriceSelection selectedPrice={selectedPrice} onSelect={setSelectedPrice} />
|
|
|
|
<button
|
|
className="mt-6 w-full py-2 rounded-xl font-semibold bg-[rgb(248,144,22)] text-black hover:bg-white hover:scale-105"
|
|
onClick={handleCreateGame}
|
|
>
|
|
Confirm & Create Bet
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|