duelfi_web/src/components/GameModal.tsx
2025-04-03 12:05:52 +05:30

97 lines
3.2 KiB
TypeScript

"use client";
import { useState } from "react";
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
import { toast } from "sonner";
import { games } from "../data/games";
import { PriceSelection } from "./PriceSelection";
import { GameSelection } from "./GameSelection";
import { createBet } from "@/shared/solana_helpers";
import { Game } from "@/types/Game";
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
interface GameModalProps {
isOpen: boolean;
onClose: () => void;
}
export default function GameModal({ isOpen, onClose }: GameModalProps) {
const { wallets } = useSolanaWallets();
const { authenticated } = usePrivy();
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
const [selectedPrice, setSelectedPrice] = useState<number | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const handleCreateGame = async () => {
if (!authenticated) {
toast.error("Please log in with Privy.");
return;
}
const wallet = wallets[0];
if (!wallet) {
toast.error("Please connect your wallet.");
return;
}
if (!selectedGame || selectedPrice === null) {
toast.error("Please select a game and a price.");
return;
}
setIsProcessing(true);
try {
const tx = await createBet(wallet, selectedPrice, selectedGame);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
toast.success(`Bet created successfully!`, {
action: {
label: "View TX",
onClick: () => window.open(url, "_blank"),
},
});
onClose();
} catch (error) {
console.error("Error creating bet:", error);
toast.error("Failed to create bet. Please try again.");
} finally {
setIsProcessing(false);
}
};
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()}>
{isProcessing ? (
<div className="flex flex-col items-center">
<svg className="animate-spin h-8 w-8 text-blue-400 mb-4" viewBox="0 0 24 24" fill="none">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path>
</svg>
<h3 className="text-lg font-semibold">Processing...</h3>
<p className="text-gray-400 text-sm mt-2">Creating your bet, please wait...</p>
</div>
) : (
<>
<h2 className="text-xl font-bold mb-4">Create Game</h2>
<GameSelection games={games} selectedGame={selectedGame} onSelect={setSelectedGame} />
<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>
);
}