From 0758c850d6ba79283e75fa98d8bcc1c6cc646f28 Mon Sep 17 00:00:00 2001 From: Jed Duffey Date: Sat, 5 Jul 2025 16:36:42 -0400 Subject: [PATCH 1/7] Fix most recent numbers UI by updating ExecutedWager event listeners - Updated MostRecentSpinResults and SpinResult components to handle new 4-parameter ExecutedWager event signature - Updated blockchainWrapper event definition to match updated smart contract - Added BetPlaced and BetCleared events to blockchainWrapper for future use - Fixes issue where most recent numbers were not displaying after contract updates --- src/common/blockchainWrapper.js | 4 +++- src/components/roulette/MostRecentSpinResults.js | 2 +- src/components/roulette/SpinResult.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/common/blockchainWrapper.js b/src/common/blockchainWrapper.js index 515f304..c8b1649 100644 --- a/src/common/blockchainWrapper.js +++ b/src/common/blockchainWrapper.js @@ -133,7 +133,9 @@ async function getTokenSymbol() { const rouletteContractEvents = new ethers.Contract( ROULETTE_CONTRACT_ADDRESS, [ - 'event ExecutedWager(address indexed, uint256)', + 'event ExecutedWager(address indexed, uint256, uint256, uint256)', + 'event BetPlaced(address indexed, string, uint256)', + 'event BetCleared(address indexed)', ], provider ); diff --git a/src/components/roulette/MostRecentSpinResults.js b/src/components/roulette/MostRecentSpinResults.js index b037a6e..863e708 100644 --- a/src/components/roulette/MostRecentSpinResults.js +++ b/src/components/roulette/MostRecentSpinResults.js @@ -8,7 +8,7 @@ const CLASS_NAME = "MostRecentSpinResults-component"; export function MostRecentSpinResults(props) { const [spinResults, setSpinResults] = useState([]); - rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber) => { + rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { if (playerAddress === props.playerAddress) { const copySpinResults = [...spinResults]; copySpinResults.push(parseInt(wheelNumber, 10)); diff --git a/src/components/roulette/SpinResult.js b/src/components/roulette/SpinResult.js index 671074a..0473c79 100644 --- a/src/components/roulette/SpinResult.js +++ b/src/components/roulette/SpinResult.js @@ -14,7 +14,7 @@ export function SpinResult(props) { setBgColor(getWheelNumberColor(props.spinResult)); setMostRecentSpinResultText(props.spinResult === 37 ? "00" : props.spinResult); } else { - rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber) => { + rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { if (playerAddress === props.playerAddress) { setBgColor(getWheelNumberColor(parseInt(wheelNumber, 10))); setMostRecentSpinResultText(parseInt(wheelNumber, 10) === 37 ? "00" : parseInt(wheelNumber, 10)); From 11bd3a8ac23039f91cb73200763e1edc04645958 Mon Sep 17 00:00:00 2001 From: Jed Duffey Date: Sat, 5 Jul 2025 16:59:09 -0400 Subject: [PATCH 2/7] Fix timing difference between HitNumbers and MostRecent boxes - Replace polling with event-driven updates in NumbersHitTracker - Remove 1-second delay that caused HitNumbers to update after MostRecent - Use ExecutedWager event listener instead of setTimeout polling - Add proper event listener cleanup to prevent memory leaks - Both boxes now update simultaneously when wheel spins --- src/components/roulette/NumbersHitTracker.js | 41 +++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/components/roulette/NumbersHitTracker.js b/src/components/roulette/NumbersHitTracker.js index 2ba05ef..3f8cd56 100644 --- a/src/components/roulette/NumbersHitTracker.js +++ b/src/components/roulette/NumbersHitTracker.js @@ -2,18 +2,47 @@ import { useEffect, useState } from 'react'; import { WHEEL_NUMBERS } from "../../common/wheelNumbers"; -import { getPlayerNumberCompletionSetCurrent } from "../../common/blockchainWrapper"; +import { getPlayerNumberCompletionSetCurrent, rouletteContractEvents } from "../../common/blockchainWrapper"; const CLASS_NAME = "NumbersHitTracker-component"; export function NumbersHitTracker(props) { const [currentSet, setCurrentSet] = useState(new Set()); + // Initialize the current set on component mount useEffect(() => { - setTimeout(async () => { - const currentNumbers = await getPlayerNumberCompletionSetCurrent(props.playerAddress); - setCurrentSet(new Set(currentNumbers)); - }, 1000); - }, [props.playerAddress, currentSet]); + const initializeSet = async () => { + try { + const currentNumbers = await getPlayerNumberCompletionSetCurrent(props.playerAddress); + setCurrentSet(new Set(currentNumbers)); + } catch (error) { + console.error('Error initializing numbers hit tracker:', error); + } + }; + + initializeSet(); + }, [props.playerAddress]); + + // Listen for ExecutedWager events to update the set immediately + useEffect(() => { + const handleExecutedWager = async (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { + if (playerAddress === props.playerAddress) { + try { + // Get the updated completion set from the blockchain + const currentNumbers = await getPlayerNumberCompletionSetCurrent(props.playerAddress); + setCurrentSet(new Set(currentNumbers)); + } catch (error) { + console.error('Error updating numbers hit tracker:', error); + } + } + }; + + rouletteContractEvents.on('ExecutedWager', handleExecutedWager); + + // Cleanup event listener + return () => { + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); + }; + }, [props.playerAddress]); return (
Date: Sat, 5 Jul 2025 17:03:24 -0400 Subject: [PATCH 3/7] Add Clear All Bets functionality - Create ClearBetsButton component with proper styling and state management - Add handleClearBetsClick function to Roulette component - Integrate with existing clearBets blockchain function - Add proper validation (no bets to clear, wheel spinning) - Include optimistic UI updates with error handling - Add comprehensive tests for ClearBetsButton component - Update CSS styling for button positioning and appearance - Update test snapshots to include new component --- src/components/roulette/ClearBetsButton.js | 29 +++++++ src/components/roulette/Roulette.js | 42 ++++++++++ src/index.css | 11 +++ .../components/__snapshots__/App.test.js.snap | 24 ++++++ .../roulette/ClearBetsButton.test.js | 45 ++++++++++ .../ClearBetsButton.test.js.snap | 82 +++++++++++++++++++ .../__snapshots__/Roulette.test.js.snap | 24 ++++++ 7 files changed, 257 insertions(+) create mode 100644 src/components/roulette/ClearBetsButton.js create mode 100644 src/test/components/roulette/ClearBetsButton.test.js create mode 100644 src/test/components/roulette/__snapshots__/ClearBetsButton.test.js.snap diff --git a/src/components/roulette/ClearBetsButton.js b/src/components/roulette/ClearBetsButton.js new file mode 100644 index 0000000..a0cd228 --- /dev/null +++ b/src/components/roulette/ClearBetsButton.js @@ -0,0 +1,29 @@ +const CLASS_NAME = "ClearBetsButton-component"; + +export function ClearBetsButton(props) { + const hasBets = props.pendingBets && props.pendingBets.length > 0; + const isDisabled = props.wheelIsSpinning || !hasBets; + + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/src/components/roulette/Roulette.js b/src/components/roulette/Roulette.js index 320b7f2..5a37fd8 100644 --- a/src/components/roulette/Roulette.js +++ b/src/components/roulette/Roulette.js @@ -8,6 +8,7 @@ import { CompletionsCounter } from './CompletionsCounter'; import { BetResultsInfo } from './BetResultsInfo'; import { Board } from "./Board"; import { ChipSelection } from './ChipSelection'; +import { ClearBetsButton } from './ClearBetsButton'; import { PendingBetsTable } from './PendingBetsTable'; import { MostRecentSpinResults } from './MostRecentSpinResults'; import { NumbersHitTracker } from './NumbersHitTracker'; @@ -21,6 +22,7 @@ import { getPlayerAllowance, executeWager, placeBet, + clearBets, getPendingBets, rouletteContractEvents, getBlock, @@ -193,6 +195,41 @@ export function Roulette(props) { }); } + function handleClearBetsClick() { + if (pendingBets.length === 0) { + alert("No bets to clear!"); + return; + } + + if (wheelIsSpinning) { + alert("Cannot clear bets while wheel is spinning!"); + return; + } + + // Optimistically clear UI + setPendingBets([]); + + // Clear bets on the blockchain + clearBets() + .then((tx) => { + console.log('Bets cleared:', tx); + return tx.wait(); // wait for mining to ensure block number is available + }) + .then((receipt) => { + // Update latest block number from mined receipt + setLatestBlockNumber(receipt.blockNumber); + // Refresh balances after transaction is mined + refreshBalances(); + refreshPendingBets(); + }) + .catch((error) => { + console.error('Error clearing bets:', error); + alert('Failed to clear bets. Please try again.'); + // Restore pending bets on error + refreshPendingBets(); + }); + } + return (
+ handleClearBetsClick()} + pendingBets={pendingBets} + wheelIsSpinning={wheelIsSpinning} + />
+
+ +
diff --git a/src/test/components/roulette/ClearBetsButton.test.js b/src/test/components/roulette/ClearBetsButton.test.js new file mode 100644 index 0000000..98a834a --- /dev/null +++ b/src/test/components/roulette/ClearBetsButton.test.js @@ -0,0 +1,45 @@ +import renderer from 'react-test-renderer'; + +import { ClearBetsButton } from '../../../components/roulette/ClearBetsButton'; +import { PendingBet } from '../../../common/PendingBet'; + +describe('ClearBetsButton', () => { + it('renders enabled when there are bets and wheel is not spinning', () => { + const sut = + {}} + pendingBets={[new PendingBet("test", 10)]} + wheelIsSpinning={false} + />; + + const view = renderer.create(sut); + + expect(view).toMatchSnapshot(); + }); + + it('renders disabled when there are no bets', () => { + const sut = + {}} + pendingBets={[]} + wheelIsSpinning={false} + />; + + const view = renderer.create(sut); + + expect(view).toMatchSnapshot(); + }); + + it('renders disabled when wheel is spinning', () => { + const sut = + {}} + pendingBets={[new PendingBet("test", 10)]} + wheelIsSpinning={true} + />; + + const view = renderer.create(sut); + + expect(view).toMatchSnapshot(); + }); +}); \ No newline at end of file diff --git a/src/test/components/roulette/__snapshots__/ClearBetsButton.test.js.snap b/src/test/components/roulette/__snapshots__/ClearBetsButton.test.js.snap new file mode 100644 index 0000000..2831174 --- /dev/null +++ b/src/test/components/roulette/__snapshots__/ClearBetsButton.test.js.snap @@ -0,0 +1,82 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ClearBetsButton renders disabled when there are no bets 1`] = ` +
+ +
+`; + +exports[`ClearBetsButton renders disabled when wheel is spinning 1`] = ` +
+ +
+`; + +exports[`ClearBetsButton renders enabled when there are bets and wheel is not spinning 1`] = ` +
+ +
+`; diff --git a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap index 1c9c102..f510ede 100644 --- a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap +++ b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap @@ -2138,6 +2138,30 @@ exports[`Roulette renders 1`] = ` -
+
+ +
From a6d0e0af9a8f6c8f365357150c3ac4f2659b6f62 Mon Sep 17 00:00:00 2001 From: Jed Duffey Date: Sat, 5 Jul 2025 17:08:36 -0400 Subject: [PATCH 4/7] Improve UI update consistency with event-driven architecture - Fix event listener setup in MostRecentSpinResults and SpinResult components - Add proper event listener cleanup to prevent memory leaks and duplicate listeners - Optimize spin flow by setting up event listeners BEFORE transaction execution - Add centralized event management in main Roulette component - Implement event-driven updates for BetPlaced, BetCleared, and ExecutedWager events - Remove redundant getRandomWheelNumber call that was causing delays - Ensure all UI components update simultaneously when blockchain events occur - Improve error handling and cleanup for event listeners --- .../roulette/MostRecentSpinResults.js | 27 ++++-- src/components/roulette/Roulette.js | 93 +++++++++++++------ src/components/roulette/SpinResult.js | 26 ++++-- 3 files changed, 98 insertions(+), 48 deletions(-) diff --git a/src/components/roulette/MostRecentSpinResults.js b/src/components/roulette/MostRecentSpinResults.js index 863e708..7600aad 100644 --- a/src/components/roulette/MostRecentSpinResults.js +++ b/src/components/roulette/MostRecentSpinResults.js @@ -8,17 +8,24 @@ const CLASS_NAME = "MostRecentSpinResults-component"; export function MostRecentSpinResults(props) { const [spinResults, setSpinResults] = useState([]); - rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { - if (playerAddress === props.playerAddress) { - const copySpinResults = [...spinResults]; - copySpinResults.push(parseInt(wheelNumber, 10)); - setSpinResults(copySpinResults.slice(-20)); // Only keep the last 20 results - } - }); - useEffect(() => { - // render - }, [spinResults, props.playerAddress]); + const handleExecutedWager = (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { + if (playerAddress === props.playerAddress) { + setSpinResults(prevResults => { + const copySpinResults = [...prevResults]; + copySpinResults.push(parseInt(wheelNumber, 10)); + return copySpinResults.slice(-20); // Only keep the last 20 results + }); + } + }; + + rouletteContractEvents.on('ExecutedWager', handleExecutedWager); + + // Cleanup event listener + return () => { + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); + }; + }, [props.playerAddress]); return (
{ + const handleBetPlaced = (playerAddress, betName, betAmount) => { + if (playerAddress === props.playerAddress) { + // Refresh pending bets when a bet is placed + refreshPendingBets(); + refreshBalances(); + } + }; + + const handleBetCleared = (playerAddress) => { + if (playerAddress === props.playerAddress) { + // Refresh pending bets when bets are cleared + refreshPendingBets(); + refreshBalances(); + } + }; + + const handleExecutedWager = (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { + if (playerAddress === props.playerAddress) { + // Refresh all data when wager is executed + refreshBalances(); + refreshPendingBets(); + } + }; + + // Set up event listeners + rouletteContractEvents.on('BetPlaced', handleBetPlaced); + rouletteContractEvents.on('BetCleared', handleBetCleared); + rouletteContractEvents.on('ExecutedWager', handleExecutedWager); + + // Cleanup event listeners + return () => { + rouletteContractEvents.off('BetPlaced', handleBetPlaced); + rouletteContractEvents.off('BetCleared', handleBetCleared); + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); + }; + }, [props.playerAddress, refreshBalances, refreshPendingBets]); + function handleBettingSquareClick(bettingSquareName) { const availableBalance = (playerBalance !== undefined ? parseFloat(playerBalance) : 0) - calculateTotalBetAmount(pendingBets); @@ -159,39 +198,33 @@ export function Roulette(props) { setWheelIsSpinning(true); - getRandomWheelNumber(`${Date.now()}${playerAddress}`) - .then(randomWheelNumber => { - const resultsOfRound = getCompleteResultsOfRound(playerBalance, pendingBets, randomWheelNumber); - - setPreviousRoundResultsForBetResultsInfo(resultsOfRound); - - executeWager(playerAddress) - .then((response) => response.wait()) // wait for mining first - .then((receipt) => { - // Use mined block number - setLatestBlockNumber(receipt.blockNumber); - // Refresh balances after transaction is mined - refreshBalances(); - refreshPendingBets(); - }) - .then(() => { - rouletteContractEvents.on('ExecutedWager', (playerAddr, wheelNum, totalWinnings, totalBetsReturned) => { - if (playerAddr === props.playerAddress) { - setWheelNumber(parseInt(wheelNum, 10)); - setWheelIsSpinning(false); - } - }); - }) - .catch((error) => { - console.error('Error executing wager:', error); - setWheelIsSpinning(false); - alert('Failed to execute wager. Please try again.'); - }); + // Set up event listener BEFORE starting the transaction + const handleExecutedWager = (playerAddr, wheelNum, totalWinnings, totalBetsReturned) => { + if (playerAddr === props.playerAddress) { + setWheelNumber(parseInt(wheelNum, 10)); + setWheelIsSpinning(false); + // Remove the listener after handling the event + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); + } + }; + + rouletteContractEvents.on('ExecutedWager', handleExecutedWager); + + // Execute the wager transaction + executeWager(playerAddress) + .then((response) => response.wait()) // wait for mining + .then((receipt) => { + // Update block number and refresh data + setLatestBlockNumber(receipt.blockNumber); + refreshBalances(); + refreshPendingBets(); }) .catch((error) => { - console.error('Error getting random wheel number:', error); + console.error('Error executing wager:', error); setWheelIsSpinning(false); - alert('Failed to get random number. Please try again.'); + alert('Failed to execute wager. Please try again.'); + // Remove the listener on error + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); }); } diff --git a/src/components/roulette/SpinResult.js b/src/components/roulette/SpinResult.js index 0473c79..eefea61 100644 --- a/src/components/roulette/SpinResult.js +++ b/src/components/roulette/SpinResult.js @@ -13,15 +13,25 @@ export function SpinResult(props) { if (props.spinResult) { setBgColor(getWheelNumberColor(props.spinResult)); setMostRecentSpinResultText(props.spinResult === 37 ? "00" : props.spinResult); - } else { - rouletteContractEvents.on('ExecutedWager', (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { - if (playerAddress === props.playerAddress) { - setBgColor(getWheelNumberColor(parseInt(wheelNumber, 10))); - setMostRecentSpinResultText(parseInt(wheelNumber, 10) === 37 ? "00" : parseInt(wheelNumber, 10)); - } - }); } - }, [mostRecentSpinResultText, props.spinResult, props.playerAddress]); + }, [props.spinResult]); + + useEffect(() => { + const handleExecutedWager = (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { + if (playerAddress === props.playerAddress) { + const wheelNum = parseInt(wheelNumber, 10); + setBgColor(getWheelNumberColor(wheelNum)); + setMostRecentSpinResultText(wheelNum === 37 ? "00" : wheelNum); + } + }; + + rouletteContractEvents.on('ExecutedWager', handleExecutedWager); + + // Cleanup event listener + return () => { + rouletteContractEvents.off('ExecutedWager', handleExecutedWager); + }; + }, [props.playerAddress]); return (
Date: Sat, 5 Jul 2025 17:14:16 -0400 Subject: [PATCH 5/7] Clean up unused imports and variables to fix ESLint warnings - Remove unused imports: getCompleteResultsOfRound, getRandomWheelNumber - Remove unused state variable: previousRoundResultsForBetResultsInfo - Remove unused BetResultsInfo component and import - Update test snapshots to reflect component removal - All ESLint warnings now resolved --- src/components/roulette/Roulette.js | 7 -- .../components/__snapshots__/App.test.js.snap | 103 ------------------ .../__snapshots__/Roulette.test.js.snap | 103 ------------------ 3 files changed, 213 deletions(-) diff --git a/src/components/roulette/Roulette.js b/src/components/roulette/Roulette.js index 73a3f8a..54dde7b 100644 --- a/src/components/roulette/Roulette.js +++ b/src/components/roulette/Roulette.js @@ -1,11 +1,8 @@ import { useEffect, useState, useCallback } from 'react'; import { PendingBet } from '../../common/PendingBet'; -import { getCompleteResultsOfRound } from '../../common/getCompleteResultsOfRound'; -import { getRandomWheelNumber } from '../../common/getRandomWheelNumber'; import { CompletionsCounter } from './CompletionsCounter'; -import { BetResultsInfo } from './BetResultsInfo'; import { Board } from "./Board"; import { ChipSelection } from './ChipSelection'; import { ClearBetsButton } from './ClearBetsButton'; @@ -48,7 +45,6 @@ export function Roulette(props) { const [pendingBets, setPendingBets] = useState([]); const [playerBalance, setPlayerBalance] = useState(undefined); const [playerAllowance, setPlayerAllowance] = useState(undefined); - const [previousRoundResultsForBetResultsInfo, setPreviousRoundResultsForBetResultsInfo] = useState(null); const [wheelIsSpinning, setWheelIsSpinning] = useState(false); const [wheelNumber, setWheelNumber] = useState(null); @@ -300,9 +296,6 @@ export function Roulette(props) { - diff --git a/src/test/components/__snapshots__/App.test.js.snap b/src/test/components/__snapshots__/App.test.js.snap index 3e21ff0..c31d7a5 100644 --- a/src/test/components/__snapshots__/App.test.js.snap +++ b/src/test/components/__snapshots__/App.test.js.snap @@ -3562,109 +3562,6 @@ Array [
-
-
-
- PREVIOUS ROUND RESULTS -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Bet Name - - Bet Amount - - Winnings - - Bet Returned -
- TOTALS - - - - - - - - - -
- Starting - - - -
- Net - - - -
- Final - - - -
-
diff --git a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap index f510ede..00e1ed3 100644 --- a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap +++ b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap @@ -2229,109 +2229,6 @@ exports[`Roulette renders 1`] = `
-
-
-
- PREVIOUS ROUND RESULTS -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Bet Name - - Bet Amount - - Winnings - - Bet Returned -
- TOTALS - - - - - - - - - -
- Starting - - - -
- Net - - - -
- Final - - - -
-
From 57689357427432ef135978c295d3cc0000111393 Mon Sep 17 00:00:00 2001 From: Jed Duffey Date: Sat, 5 Jul 2025 17:43:53 -0400 Subject: [PATCH 6/7] feat: Add BetResultsInfo component to display previous round results - Import and integrate BetResultsInfo component in Roulette.js - Add state management for previousRoundResultsForBetResultsInfo - Calculate and store previous round results when ExecutedWager event fires - Convert wheel number format properly (37 -> '00' for display) - Display bet name, amount, winnings, and bet returned for each bet - Show totals and balance changes (starting, net, final) - Update test snapshots to include new BetResultsInfo component - Improve user experience by showing detailed results after each spin This enhancement provides players with comprehensive feedback about their previous round performance, including individual bet outcomes and overall balance changes. --- src/components/roulette/Roulette.js | 30 ++++- .../components/__snapshots__/App.test.js.snap | 103 ++++++++++++++++++ .../__snapshots__/Roulette.test.js.snap | 103 ++++++++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) diff --git a/src/components/roulette/Roulette.js b/src/components/roulette/Roulette.js index 54dde7b..8862104 100644 --- a/src/components/roulette/Roulette.js +++ b/src/components/roulette/Roulette.js @@ -1,8 +1,11 @@ import { useEffect, useState, useCallback } from 'react'; import { PendingBet } from '../../common/PendingBet'; +import { getCompleteResultsOfRound } from '../../common/getCompleteResultsOfRound'; +import { getRandomWheelNumber } from '../../common/getRandomWheelNumber'; import { CompletionsCounter } from './CompletionsCounter'; +import { BetResultsInfo } from './BetResultsInfo'; import { Board } from "./Board"; import { ChipSelection } from './ChipSelection'; import { ClearBetsButton } from './ClearBetsButton'; @@ -45,6 +48,7 @@ export function Roulette(props) { const [pendingBets, setPendingBets] = useState([]); const [playerBalance, setPlayerBalance] = useState(undefined); const [playerAllowance, setPlayerAllowance] = useState(undefined); + const [previousRoundResultsForBetResultsInfo, setPreviousRoundResultsForBetResultsInfo] = useState(null); const [wheelIsSpinning, setWheelIsSpinning] = useState(false); const [wheelNumber, setWheelNumber] = useState(null); @@ -126,6 +130,25 @@ export function Roulette(props) { const handleExecutedWager = (playerAddress, wheelNumber, totalWinnings, totalBetsReturned) => { if (playerAddress === props.playerAddress) { + // Convert wheel number to proper format for getWinningCriteria + let parsedWheelNumber; + const numericWheelNumber = parseInt(wheelNumber, 10); + if (numericWheelNumber === 37) { + // "00" is represented as 37 in the contract + parsedWheelNumber = "00"; + } else { + // Convert to string for other numbers + parsedWheelNumber = numericWheelNumber.toString(); + } + + // Calculate and store previous round results for display + const previousRoundResults = getCompleteResultsOfRound( + playerBalance || 0, + pendingBets, + parsedWheelNumber + ); + setPreviousRoundResultsForBetResultsInfo(previousRoundResults); + // Refresh all data when wager is executed refreshBalances(); refreshPendingBets(); @@ -197,7 +220,9 @@ export function Roulette(props) { // Set up event listener BEFORE starting the transaction const handleExecutedWager = (playerAddr, wheelNum, totalWinnings, totalBetsReturned) => { if (playerAddr === props.playerAddress) { - setWheelNumber(parseInt(wheelNum, 10)); + // Keep wheel number as number for consistency with other components + const numericWheelNumber = parseInt(wheelNum, 10); + setWheelNumber(numericWheelNumber); setWheelIsSpinning(false); // Remove the listener after handling the event rouletteContractEvents.off('ExecutedWager', handleExecutedWager); @@ -296,6 +321,9 @@ export function Roulette(props) { + diff --git a/src/test/components/__snapshots__/App.test.js.snap b/src/test/components/__snapshots__/App.test.js.snap index c31d7a5..3e21ff0 100644 --- a/src/test/components/__snapshots__/App.test.js.snap +++ b/src/test/components/__snapshots__/App.test.js.snap @@ -3562,6 +3562,109 @@ Array [
+
+
+
+ PREVIOUS ROUND RESULTS +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Bet Name + + Bet Amount + + Winnings + + Bet Returned +
+ TOTALS + + - + + - + + - +
+ Starting + + - +
+ Net + + - +
+ Final + + - +
+
diff --git a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap index 00e1ed3..f510ede 100644 --- a/src/test/components/roulette/__snapshots__/Roulette.test.js.snap +++ b/src/test/components/roulette/__snapshots__/Roulette.test.js.snap @@ -2229,6 +2229,109 @@ exports[`Roulette renders 1`] = `
+
+
+
+ PREVIOUS ROUND RESULTS +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Bet Name + + Bet Amount + + Winnings + + Bet Returned +
+ TOTALS + + - + + - + + - +
+ Starting + + - +
+ Net + + - +
+ Final + + - +
+
From 4597b4a642c8f8ee9d2d52fe738acf69224e7a4c Mon Sep 17 00:00:00 2001 From: Jed Duffey Date: Sat, 5 Jul 2025 21:50:38 -0400 Subject: [PATCH 7/7] fix build warnings --- src/components/roulette/Roulette.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/roulette/Roulette.js b/src/components/roulette/Roulette.js index 8862104..09e4ed4 100644 --- a/src/components/roulette/Roulette.js +++ b/src/components/roulette/Roulette.js @@ -2,7 +2,6 @@ import { useEffect, useState, useCallback } from 'react'; import { PendingBet } from '../../common/PendingBet'; import { getCompleteResultsOfRound } from '../../common/getCompleteResultsOfRound'; -import { getRandomWheelNumber } from '../../common/getRandomWheelNumber'; import { CompletionsCounter } from './CompletionsCounter'; import { BetResultsInfo } from './BetResultsInfo'; @@ -166,7 +165,7 @@ export function Roulette(props) { rouletteContractEvents.off('BetCleared', handleBetCleared); rouletteContractEvents.off('ExecutedWager', handleExecutedWager); }; - }, [props.playerAddress, refreshBalances, refreshPendingBets]); + }, [props.playerAddress, refreshBalances, refreshPendingBets, playerBalance, pendingBets]); function handleBettingSquareClick(bettingSquareName) { const availableBalance = (playerBalance !== undefined ? parseFloat(playerBalance) : 0) - calculateTotalBetAmount(pendingBets);