From df43c06473754ffde8b0e50fe5dcb8bea12f4528 Mon Sep 17 00:00:00 2001 From: QSchlegel Date: Wed, 19 Nov 2025 19:45:00 +0100 Subject: [PATCH] Implement retry logic for wallet detection in ConnectWallet component - Added useRef hooks to manage retry count and timeout for wallet detection, improving handling of asynchronous wallet loading. - Enhanced useEffect to retry wallet detection with increasing delays, ensuring better synchronization with browser extensions. - Updated RootLayout to force re-mount of ConnectWallet on navigation, addressing cache issues and ensuring fresh component state. --- .../common/cardano-objects/connect-wallet.tsx | 76 ++++++++++++++++++- .../common/overall-layout/layout.tsx | 9 ++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/components/common/cardano-objects/connect-wallet.tsx b/src/components/common/cardano-objects/connect-wallet.tsx index 02597c2..f067d6b 100644 --- a/src/components/common/cardano-objects/connect-wallet.tsx +++ b/src/components/common/cardano-objects/connect-wallet.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/dropdown-menu"; import { useWallet, useWalletList, useNetwork, useAssets } from "@meshsdk/react"; import { useSiteStore } from "@/lib/zustand/site"; -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; import useUser from "@/hooks/useUser"; import { useUserStore } from "@/lib/zustand/user"; import { getProvider } from "@/utils/get-provider"; @@ -30,12 +30,86 @@ export default function ConnectWallet() { const networkId = useNetwork(); const assets = useAssets(); const network = useSiteStore((state) => state.network); + const retryTimeoutRef = useRef(null); + const retryCountRef = useRef(0); + const walletsRef = useRef(wallets); + + // Keep wallets ref in sync + useEffect(() => { + walletsRef.current = wallets; + }, [wallets]); async function connectWallet(walletId: string) { setPastWallet(walletId); await connect(walletId); } + // Retry wallet detection on mount to handle cached loads + // Browser extensions inject wallets asynchronously, and cached scripts may load + // before MeshProvider/wallet detection is fully initialized + useEffect(() => { + // If wallets are already detected, no need to retry + if (wallets.length > 0) { + retryCountRef.current = 0; + if (retryTimeoutRef.current) { + clearTimeout(retryTimeoutRef.current); + retryTimeoutRef.current = null; + } + return; + } + + // Clear any existing timeout + if (retryTimeoutRef.current) { + clearTimeout(retryTimeoutRef.current); + retryTimeoutRef.current = null; + } + + // Reset retry count + retryCountRef.current = 0; + + // Retry detection with increasing delays: immediate, 100ms, 500ms, 1000ms + // This gives MeshProvider and browser extensions time to initialize + const delays = [0, 100, 500, 1000]; + const maxRetries = delays.length; + + const checkWallets = () => { + // Check current wallets (using ref to avoid closure issues) + if (walletsRef.current.length > 0) { + retryCountRef.current = 0; + if (retryTimeoutRef.current) { + clearTimeout(retryTimeoutRef.current); + retryTimeoutRef.current = null; + } + return; + } + + // If we've reached max retries, stop + if (retryCountRef.current >= maxRetries) { + retryCountRef.current = 0; + return; + } + + // Schedule next retry + const delay = delays[retryCountRef.current]; + retryCountRef.current++; + + // Use setTimeout even for 0ms delay to avoid recursion issues + retryTimeoutRef.current = setTimeout(checkWallets, delay); + }; + + // Start checking immediately (using setTimeout with 0ms for next tick) + retryTimeoutRef.current = setTimeout(checkWallets, 0); + retryCountRef.current = 1; + + return () => { + if (retryTimeoutRef.current) { + clearTimeout(retryTimeoutRef.current); + retryTimeoutRef.current = null; + } + retryCountRef.current = 0; + }; + }, [wallets.length]); + // Auto-connect if user had connected before useEffect(() => { if (pastWallet && !connected && wallets.length > 0) { diff --git a/src/components/common/overall-layout/layout.tsx b/src/components/common/overall-layout/layout.tsx index 65a0390..e6b89ff 100644 --- a/src/components/common/overall-layout/layout.tsx +++ b/src/components/common/overall-layout/layout.tsx @@ -28,9 +28,14 @@ import { MobileNavigation } from "@/components/ui/mobile-navigation"; import { MobileActionsMenu } from "@/components/ui/mobile-actions-menu"; // Dynamically import ConnectWallet with SSR disabled to avoid production SSR issues +// Using a version-based key ensures fresh mount on updates, preventing cache issues const ConnectWallet = dynamic( () => import("@/components/common/cardano-objects/connect-wallet"), - { ssr: false } + { + ssr: false, + // Force re-mount on navigation to handle cache issues + loading: () => null, + } ); // Enhanced error boundary component for wallet errors @@ -211,7 +216,7 @@ export default function RootLayout({ {/* Right: Control buttons */}
{!connected ? ( - + ) : ( <> {/* Desktop buttons */}