bet creation and close complete

This commit is contained in:
warlock 2025-04-03 05:37:29 +05:30
parent 8f80d3c098
commit 609fdcad20
2 changed files with 93 additions and 57 deletions

View File

@ -3,14 +3,12 @@
import { useState } from "react";
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
import { toast } from "sonner";
import { games } from "../data/games"; // Assuming you have a games data file
import { games } from "../data/games";
import { PriceSelection } from "./PriceSelection";
import { GameSelection } from "./GameSelection";
import { createBet } from "@/shared/solana_helpers";
import { Game } from "@/types/Game";
// Change to Mainnet when deploying
interface GameModalProps {
isOpen: boolean;
onClose: () => void;
@ -22,17 +20,15 @@ export default function GameModal({ isOpen, onClose }: GameModalProps) {
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]; // Get connected Privy wallet
const wallet = wallets[0];
if (!wallet) {
toast.error("Please connect your wallet.");
return;
@ -43,24 +39,38 @@ export default function GameModal({ isOpen, onClose }: GameModalProps) {
return;
}
await createBet(wallets[0],selectedPrice,selectedGame);
setIsProcessing(true);
try {
await createBet(wallet, selectedPrice, selectedGame);
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()}
>
<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>
{/* Game Selection */}
<GameSelection games={games} selectedGame={selectedGame} onSelect={setSelectedGame} />
{/* Price Selection */}
<PriceSelection selectedPrice={selectedPrice} onSelect={setSelectedPrice} />
<button
@ -69,6 +79,8 @@ export default function GameModal({ isOpen, onClose }: GameModalProps) {
>
Confirm & Create Bet
</button>
</>
)}
</div>
</div>
);

View File

@ -4,7 +4,7 @@ import Image from "next/image";
import { games } from "../data/games";
import { FiTrash } from "react-icons/fi";
import { useSolanaWallets } from "@privy-io/react-auth";
import { fetchOpenBets, closeBet } from "@/shared/solana_helpers"; // Import close function
import { fetchOpenBets, closeBet } from "@/shared/solana_helpers";
import { Bet } from "../types/Bet";
export default function YourGames() {
@ -12,40 +12,37 @@ export default function YourGames() {
const [openBets, setOpenBets] = useState<Bet[]>([]);
const [myBets, setMyBets] = useState<Bet[]>([]);
const [loading, setLoading] = useState(true);
const [selectedBet, setSelectedBet] = useState<Bet | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
// Function to fetch open bets
// Fetch bets
const updateBets = async () => {
const bets: Bet[] = await fetchOpenBets(wallets[0]);
setMyBets(bets.filter((bet) => bet.owner === wallets[0].address));
setOpenBets(bets);
setLoading(false);
console.log(`Got ${bets.length} bets`);
};
// Auto-refresh every 10 seconds
useEffect(() => {
if (!ready) return;
updateBets();
const interval = setInterval(updateBets, 10000); // Refresh every 10s
return () => clearInterval(interval); // Cleanup on unmount
const interval = setInterval(updateBets, 10000);
return () => clearInterval(interval);
}, [ready]);
// Function to handle bet closing
const handleCloseBet = async (bet: Bet) => {
const confirmed = window.confirm(
`Are you sure you want to close this bet? You will receive your refund back to your wallet.`
);
if (!confirmed) return;
// Handle bet closing
const handleCloseBet = async () => {
if (!selectedBet) return;
setIsProcessing(true);
try {
console.log(`Closing bet ${bet.id}`);
await closeBet(wallets[0], bet.id);
alert("Bet closed successfully!");
updateBets(); // Refresh bets after closing
await closeBet(wallets[0], selectedBet.id);
updateBets();
} catch (error) {
console.error("Error closing bet:", error);
alert("Failed to close the bet. Please try again.");
} finally {
setIsProcessing(false);
setSelectedBet(null);
}
};
@ -60,16 +57,11 @@ export default function YourGames() {
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{myBets.map((bet) => {
console.log(`Finding game for the id ${bet.id}`);
const game = games.find((g) => g.id === bet.id); // Match game
if (!game) return null; // Skip unmatched bets
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"
>
<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
@ -88,10 +80,10 @@ export default function YourGames() {
<p className="text-xs text-white font-mono py-1">{bet.wager} SOL</p>
</div>
{/* Close Button (Trash Icon) */}
{/* 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={() => handleCloseBet(bet)}
onClick={() => setSelectedBet(bet)}
>
<FiTrash size={16} />
</button>
@ -100,6 +92,38 @@ export default function YourGames() {
})}
</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>
);
}