bet creation and close complete
This commit is contained in:
parent
8f80d3c098
commit
609fdcad20
|
|
@ -3,14 +3,12 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
||||||
import { toast } from "sonner";
|
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 { PriceSelection } from "./PriceSelection";
|
||||||
import { GameSelection } from "./GameSelection";
|
import { GameSelection } from "./GameSelection";
|
||||||
import { createBet } from "@/shared/solana_helpers";
|
import { createBet } from "@/shared/solana_helpers";
|
||||||
import { Game } from "@/types/Game";
|
import { Game } from "@/types/Game";
|
||||||
|
|
||||||
// Change to Mainnet when deploying
|
|
||||||
|
|
||||||
interface GameModalProps {
|
interface GameModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
|
@ -22,53 +20,67 @@ export default function GameModal({ isOpen, onClose }: GameModalProps) {
|
||||||
|
|
||||||
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
||||||
const [selectedPrice, setSelectedPrice] = useState<number | null>(null);
|
const [selectedPrice, setSelectedPrice] = useState<number | null>(null);
|
||||||
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const handleCreateGame = async () => {
|
const handleCreateGame = async () => {
|
||||||
|
|
||||||
if (!authenticated) {
|
if (!authenticated) {
|
||||||
toast.error("Please log in with Privy.");
|
toast.error("Please log in with Privy.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wallet = wallets[0]; // Get connected Privy wallet
|
const wallet = wallets[0];
|
||||||
if (!wallet) {
|
if (!wallet) {
|
||||||
toast.error("Please connect your wallet.");
|
toast.error("Please connect your wallet.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selectedGame || selectedPrice === null) {
|
if (!selectedGame || selectedPrice === null) {
|
||||||
toast.error("Please select a game and a price.");
|
toast.error("Please select a game and a price.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await createBet(wallets[0],selectedPrice,selectedGame);
|
setIsProcessing(true);
|
||||||
onClose();
|
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;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/70 flex justify-center items-start pt-10 z-50" onClick={onClose}>
|
<div className="fixed inset-0 bg-black/70 flex justify-center items-start pt-10 z-50" onClick={onClose}>
|
||||||
<div
|
<div className="bg-[rgb(30,30,30)] text-white w-full max-w-lg p-6 rounded-2xl shadow-lg" onClick={(e) => e.stopPropagation()}>
|
||||||
className="bg-[rgb(30,30,30)] text-white w-full max-w-lg p-6 rounded-2xl shadow-lg"
|
{isProcessing ? (
|
||||||
onClick={(e) => e.stopPropagation()}
|
<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">
|
||||||
<h2 className="text-xl font-bold mb-4">Create Game</h2>
|
<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 */}
|
<button
|
||||||
<GameSelection games={games} selectedGame={selectedGame} onSelect={setSelectedGame} />
|
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}
|
||||||
{/* Price Selection */}
|
>
|
||||||
<PriceSelection selectedPrice={selectedPrice} onSelect={setSelectedPrice} />
|
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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import Image from "next/image";
|
||||||
import { games } from "../data/games";
|
import { games } from "../data/games";
|
||||||
import { FiTrash } from "react-icons/fi";
|
import { FiTrash } from "react-icons/fi";
|
||||||
import { useSolanaWallets } from "@privy-io/react-auth";
|
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";
|
import { Bet } from "../types/Bet";
|
||||||
|
|
||||||
export default function YourGames() {
|
export default function YourGames() {
|
||||||
|
|
@ -12,40 +12,37 @@ export default function YourGames() {
|
||||||
const [openBets, setOpenBets] = useState<Bet[]>([]);
|
const [openBets, setOpenBets] = useState<Bet[]>([]);
|
||||||
const [myBets, setMyBets] = useState<Bet[]>([]);
|
const [myBets, setMyBets] = useState<Bet[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
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 updateBets = async () => {
|
||||||
const bets: Bet[] = await fetchOpenBets(wallets[0]);
|
const bets: Bet[] = await fetchOpenBets(wallets[0]);
|
||||||
setMyBets(bets.filter((bet) => bet.owner === wallets[0].address));
|
setMyBets(bets.filter((bet) => bet.owner === wallets[0].address));
|
||||||
setOpenBets(bets);
|
setOpenBets(bets);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
console.log(`Got ${bets.length} bets`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auto-refresh every 10 seconds
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ready) return;
|
if (!ready) return;
|
||||||
updateBets();
|
updateBets();
|
||||||
const interval = setInterval(updateBets, 10000); // Refresh every 10s
|
const interval = setInterval(updateBets, 10000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
return () => clearInterval(interval); // Cleanup on unmount
|
|
||||||
}, [ready]);
|
}, [ready]);
|
||||||
|
|
||||||
// Function to handle bet closing
|
// Handle bet closing
|
||||||
const handleCloseBet = async (bet: Bet) => {
|
const handleCloseBet = async () => {
|
||||||
const confirmed = window.confirm(
|
if (!selectedBet) return;
|
||||||
`Are you sure you want to close this bet? You will receive your refund back to your wallet.`
|
setIsProcessing(true);
|
||||||
);
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`Closing bet ${bet.id}`);
|
await closeBet(wallets[0], selectedBet.id);
|
||||||
await closeBet(wallets[0], bet.id);
|
updateBets();
|
||||||
alert("Bet closed successfully!");
|
|
||||||
updateBets(); // Refresh bets after closing
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error closing bet:", error);
|
console.error("Error closing bet:", error);
|
||||||
alert("Failed to close the bet. Please try again.");
|
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">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
{myBets.map((bet) => {
|
{myBets.map((bet) => {
|
||||||
console.log(`Finding game for the id ${bet.id}`);
|
const game = games.find((g) => g.id === bet.id);
|
||||||
const game = games.find((g) => g.id === bet.id); // Match game
|
if (!game) return null;
|
||||||
|
|
||||||
if (!game) return null; // Skip unmatched bets
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<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">
|
||||||
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 */}
|
{/* Game Thumbnail */}
|
||||||
<div className="relative w-full h-40 overflow-hidden rounded-xl">
|
<div className="relative w-full h-40 overflow-hidden rounded-xl">
|
||||||
<Image
|
<Image
|
||||||
|
|
@ -88,10 +80,10 @@ export default function YourGames() {
|
||||||
<p className="text-xs text-white font-mono py-1">{bet.wager} SOL</p>
|
<p className="text-xs text-white font-mono py-1">{bet.wager} SOL</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Close Button (Trash Icon) */}
|
{/* Close Button */}
|
||||||
<button
|
<button
|
||||||
className="absolute bottom-3 right-3 bg-red-600 text-white p-2 rounded-full transition duration-300 hover:bg-red-800"
|
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} />
|
<FiTrash size={16} />
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -100,6 +92,38 @@ export default function YourGames() {
|
||||||
})}
|
})}
|
||||||
</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>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user