bet creation and close complete
This commit is contained in:
parent
8f80d3c098
commit
609fdcad20
|
|
@ -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,53 +20,67 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
if (!selectedGame || selectedPrice === null) {
|
||||
toast.error("Please select a game and a price.");
|
||||
return;
|
||||
}
|
||||
|
||||
await createBet(wallets[0],selectedPrice,selectedGame);
|
||||
onClose();
|
||||
|
||||
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()}
|
||||
>
|
||||
<h2 className="text-xl font-bold mb-4">Create Game</h2>
|
||||
<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} />
|
||||
|
||||
{/* 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>
|
||||
<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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user