diff --git a/frontend/src/app/components/dropdown/dropdownFaucetMenu.tsx b/frontend/src/app/components/dropdown/dropdownFaucetMenu.tsx index 50aeb8c..64cb85d 100644 --- a/frontend/src/app/components/dropdown/dropdownFaucetMenu.tsx +++ b/frontend/src/app/components/dropdown/dropdownFaucetMenu.tsx @@ -24,7 +24,7 @@ function DropdownFaucetMenu() { - + {/* ETH Scroll Sepolia @@ -50,9 +50,9 @@ function DropdownFaucetMenu() { - + */} - + {/* BNB Faucet & Bridge @@ -74,9 +74,9 @@ function DropdownFaucetMenu() { - + */} - + {/* Matic Polygon Amoy @@ -103,7 +103,7 @@ function DropdownFaucetMenu() { - + */} diff --git a/frontend/src/app/components/logo/logo.tsx b/frontend/src/app/components/logo/logo.tsx index d7e2189..1157962 100644 --- a/frontend/src/app/components/logo/logo.tsx +++ b/frontend/src/app/components/logo/logo.tsx @@ -12,9 +12,9 @@ export default function Logo(): ReactNode { We're on Testnet retypeme logo diff --git a/frontend/src/app/components/start-deposit-button/startDepositButton.tsx b/frontend/src/app/components/start-deposit-button/startDepositButton.tsx index 9c51287..31e647a 100644 --- a/frontend/src/app/components/start-deposit-button/startDepositButton.tsx +++ b/frontend/src/app/components/start-deposit-button/startDepositButton.tsx @@ -19,7 +19,8 @@ import RestApiService from "@/app/api/rest-api-service"; import getUserGameBalance from "@/app/contract-utils/get-user-game-balance"; import { Button } from "@/app/components/ui/button"; -import {useConfigStore} from "@/app/store/configStore"; +import { useConfigStore } from "@/app/store/configStore"; +import Spinner from "../ui/spinner"; interface IStartDepositButton { txSuccessful: boolean; @@ -27,6 +28,7 @@ interface IStartDepositButton { isButtonDisabled: boolean; handleStartGame: () => void; startBtnText: string; + isConfirmingJoin: boolean; } function StartDepositButton({ @@ -35,14 +37,16 @@ function StartDepositButton({ isButtonDisabled, handleStartGame, startBtnText, + isConfirmingJoin, }: IStartDepositButton) { - const {contractConfig} = useConfigStore(); + const { contractConfig } = useConfigStore(); const { isSignedIn, signIn } = useSIWE(); const { isConnected, chainId, address, chain } = useAccount(); const isEnough = isEnoughBalance(); const { openSwitchNetworks } = useModal(); const { writeContract, data: hash } = useWriteContract(); - const contractAddress = contractConfig.contractAddressesMap[chain?.name as string]; + const contractAddress = + contractConfig.contractAddressesMap[chain?.name as string]; async function signInWithEthereum(): Promise { await signIn(); @@ -93,6 +97,7 @@ function StartDepositButton({ <> {showDepositButton && !isConfirmed && userStatus !== "registered" ? ( )} diff --git a/frontend/src/app/components/ui/spinner.tsx b/frontend/src/app/components/ui/spinner.tsx new file mode 100644 index 0000000..0e60eb2 --- /dev/null +++ b/frontend/src/app/components/ui/spinner.tsx @@ -0,0 +1,5 @@ +import { Loader2 } from "lucide-react"; + +export default function Spinner() { + return ; +} diff --git a/frontend/src/app/components/user-and-game-balance-popover.tsx b/frontend/src/app/components/user-and-game-balance-popover.tsx index 1591d2a..5477d24 100644 --- a/frontend/src/app/components/user-and-game-balance-popover.tsx +++ b/frontend/src/app/components/user-and-game-balance-popover.tsx @@ -1,5 +1,10 @@ -import React, { useRef } from "react"; -import { useAccount, useBalance, useWriteContract } from "wagmi"; +import React, { useEffect, useRef } from "react"; +import { + useAccount, + useBalance, + useWaitForTransactionReceipt, + useWriteContract, +} from "wagmi"; import { Address, formatUnits, parseEther } from "viem"; import { Button } from "@/app/components/ui/button"; import { @@ -15,25 +20,35 @@ import { } from "@/app/components/ui/tabs"; import { Input } from "@/app/components/ui/input"; import getUserGameBalance from "../contract-utils/get-user-game-balance"; -import {useConfigStore} from "@/app/store/configStore"; +import { useConfigStore } from "@/app/store/configStore"; +import Spinner from "./ui/spinner"; +import { useQueryClient } from "@tanstack/react-query"; export default function UserAndGameBalancePopover() { - - const {contractConfig} = useConfigStore(); + const { contractConfig } = useConfigStore(); const { address, chainId, chain } = useAccount(); const { data, isError, isLoading } = useBalance({ address: address, chainId: chainId, }); - - const contractAddress = contractConfig.contractAddressesMap[chain?.name as string]; - const { writeContract, data: hash, isSuccess } = useWriteContract(); + const queryClient = useQueryClient(); + const contractAddress = + contractConfig.contractAddressesMap[chain?.name as string]; + const { + writeContract, + data: hash, + isPending: isPendingTx, + } = useWriteContract(); const withdrawInputRef = useRef(null); const depositInputRef = useRef(null); - const { humanReadableBalance: userGameBalanceValue, refetch } = - getUserGameBalance(); + const { + isPending, + error, + humanReadableBalance: userGameBalanceValue, + queryKey, + } = getUserGameBalance(); let shortUserBalanceValue; let userBalanceValue; @@ -44,9 +59,11 @@ export default function UserAndGameBalancePopover() { const userBalances = (
- {isLoading && "Fetching balanceā€¦"} - {isError && "Error fetching balance"} - {data && `${shortUserBalanceValue} | ${userGameBalanceValue}`} + {isLoading && } + {isError && "Error"} + {data && `${shortUserBalanceValue}`} | {isPending && } + {error && error} + {userGameBalanceValue && userGameBalanceValue}
); @@ -73,6 +90,15 @@ export default function UserAndGameBalancePopover() { } } + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + }); + + useEffect(() => { + queryClient.invalidateQueries({ queryKey }); + }, [isConfirmed]); + return ( {userBalances} @@ -111,6 +137,7 @@ export default function UserAndGameBalancePopover() { handleUserDeposit(depositInputRef.current?.value); }} > + {(isConfirming || isPendingTx) && } Deposit @@ -140,6 +167,7 @@ export default function UserAndGameBalancePopover() { }} className="mt-2 self-stretch" > + {(isConfirming || isPendingTx) && } Withdraw diff --git a/frontend/src/app/contract-utils/get-user-game-balance.ts b/frontend/src/app/contract-utils/get-user-game-balance.ts index de1e4e2..c2994ed 100644 --- a/frontend/src/app/contract-utils/get-user-game-balance.ts +++ b/frontend/src/app/contract-utils/get-user-game-balance.ts @@ -1,17 +1,18 @@ import { useReadContract, useAccount } from "wagmi"; import { formatEther, Address, BaseError } from "viem"; -import {useConfigStore} from "@/app/store/configStore"; +import { useConfigStore } from "@/app/store/configStore"; export default function getUserGameBalance() { const { address, chain } = useAccount(); - const {contractConfig} = useConfigStore(); - const contractAddress = contractConfig.contractAddressesMap[chain?.name as string]; + const { contractConfig } = useConfigStore(); + const contractAddress = + contractConfig.contractAddressesMap[chain?.name as string]; const { data: balance, error, isPending, - refetch, + queryKey, } = useReadContract({ abi: contractConfig.abi, address: contractAddress as Address, @@ -20,16 +21,16 @@ export default function getUserGameBalance() { }); if (isPending) { - return { balance: "Loading...", refetch }; + return { isPending: "Loading...", queryKey }; } - if (error) + if (error) { return { - balance: `Error: ${(error as BaseError).shortMessage || error.message}`, - refetch, + error: `Error: ${(error as BaseError).shortMessage || error.message}`, + queryKey, }; + } const humanReadableBalance = formatEther(balance as bigint); - - return { balance, humanReadableBalance, refetch }; + return { humanReadableBalance, queryKey }; } diff --git a/frontend/src/app/game/[id]/page.tsx b/frontend/src/app/game/[id]/page.tsx index 8f63ef1..8f71200 100644 --- a/frontend/src/app/game/[id]/page.tsx +++ b/frontend/src/app/game/[id]/page.tsx @@ -29,11 +29,10 @@ import { Address, keccak256, toBytes } from "viem"; import "./page.css"; import getUserGameBalance from "@/app/contract-utils/get-user-game-balance"; -import {useConfigStore} from "@/app/store/configStore"; +import { useConfigStore } from "@/app/store/configStore"; const GamePage = () => { - - const {contractConfig} = useConfigStore(); + const { contractConfig } = useConfigStore(); const [textVisible, setTextVisible] = useState(false); const [startBtnText, setStartBtnText] = useState("Start game"); const [isButtonDisabled, setIsButtonDisabled] = useState(false); @@ -70,7 +69,8 @@ const GamePage = () => { hash, }); - const contractAddress = contractConfig.contractAddressesMap[chain?.name as string]; + const contractAddress = + contractConfig.contractAddressesMap[chain?.name as string]; useAccountEffect({ onConnect(data) { @@ -391,6 +391,7 @@ const GamePage = () => { isButtonDisabled={isButtonDisabled} handleStartGame={handleStartGame} startBtnText={startBtnText} + isConfirmingJoin={isConfirming} /> {textVisible && (
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index f0b9a23..377342b 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -145,11 +145,12 @@ export default function Home() {
{streamingText}
keyboard