duelfi/src/components/YourGames.tsx
2025-04-04 20:24:12 +05:30

151 lines
5.5 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import { games } from "../data/games";
import { FiTrash } from "react-icons/fi";
import { useSolanaWallets } from "@privy-io/react-auth";
import { closeBet } from "@/shared/solana_helpers";
import { Bet } from "../types/Bet";
import { toast } from "sonner";
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
interface GameModalProps {
bets: Bet[];
}
export default function YourGames({bets}:GameModalProps) {
const { wallets, ready } = useSolanaWallets();
const [myBets, setMyBets] = useState<Bet[]>([]);
const [loading, setLoading] = useState(true);
const [selectedBet, setSelectedBet] = useState<Bet | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
// Fetch bets
const updateBets = async () => {
let wallet = wallets[0];
wallets.forEach((_wallet) => {
if (wallet.type === "solana") {
wallet = _wallet;
}
});
setMyBets(bets.filter((bet) => bet.owner === wallet.address));
setLoading(false);
};
useEffect(() => {
if (!ready) return;
updateBets();
const interval = setInterval(updateBets, 10000);
return () => clearInterval(interval);
}, [bets]);
// Handle bet closing
const handleCloseBet = async () => {
if (!selectedBet) return;
setIsProcessing(true);
let wallet = wallets[0];
wallets.forEach((_wallet) => {
if (wallet.type === "solana") {
wallet = _wallet;
}
});
try {
const tx = await closeBet(wallet, selectedBet.id);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
toast.success(`Closed the bet successfully!`, {
action: {
label: "View TX",
onClick: () => window.open(url, "_blank"),
},
});
updateBets();
} catch (error) {
console.error("Error closing bet:", error);
toast.message("Failed to close the bet. Please try again.");
} finally {
setIsProcessing(false);
setSelectedBet(null);
}
};
return (
<section className="py-16 px-6">
<h2 className="text-3xl font-bold text-white mb-6">Your Games</h2>
{loading ? (
<p className="text-gray-400">Loading your games...</p>
) : myBets.length === 0 ? (
<></>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{myBets.map((bet) => {
const game = games.find((g) => g.id === bet.id);
if (!game) return null;
return (
<div key={bet.id} className="relative group bg-[rgb(30,30,30)] rounded-2xl p-2 w-50 overflow-hidden cursor-pointer transition-all duration-300">
{/* Game Thumbnail */}
<div className="relative w-full h-40 overflow-hidden rounded-xl">
<Image
src={game.thumbnail}
alt={game.name}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 group-hover:scale-110"
/>
</div>
{/* Game Info */}
<div className="mt-4 px-3 text-left">
<h3 className="text-lg font-semibold text-white py-2">{game.name}</h3>
<p className="text-xs text-gray-400 font-mono py-1">Wager</p>
<p className="text-xs text-white font-mono py-1">{bet.wager} SOL</p>
</div>
{/* Close Button */}
<button
className="absolute bottom-3 right-3 bg-red-600 text-white p-2 rounded-full transition duration-300 hover:bg-red-800"
onClick={() => setSelectedBet(bet)}
>
<FiTrash size={16} />
</button>
</div>
);
})}
</div>
)}
{/* Confirmation Modal */}
{selectedBet && !isProcessing && (
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
<div className="bg-gray-900 text-white p-6 rounded-lg shadow-lg w-96">
<h3 className="text-lg font-semibold mb-4">Close Bet</h3>
<p className="mb-6">Are you sure you want to close this bet? You will receive your refund back to your wallet.</p>
<div className="flex justify-end space-x-4">
<button className="px-4 py-2 bg-gray-600 rounded hover:bg-gray-700" onClick={() => setSelectedBet(null)}>
Cancel
</button>
<button className="px-4 py-2 bg-red-600 rounded hover:bg-red-700" onClick={handleCloseBet}>
Close Bet
</button>
</div>
</div>
</div>
)}
{/* Processing Modal */}
{isProcessing && (
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
<div className="bg-gray-900 text-white p-6 rounded-lg shadow-lg w-96 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">Please wait while we close your bet.</p>
</div>
</div>
)}
</section>
);
}