@@ -10,7 +10,7 @@ import {
1010} from "@/components/ui/dropdown-menu" ;
1111import { useWallet , useWalletList } from "@meshsdk/react" ;
1212import { useSiteStore } from "@/lib/zustand/site" ;
13- import { useEffect , useRef } from "react" ;
13+ import { useEffect , useRef , useState } from "react" ;
1414import useUser from "@/hooks/useUser" ;
1515import { useUserStore } from "@/lib/zustand/user" ;
1616import { getProvider } from "@/utils/get-provider" ;
@@ -35,21 +35,87 @@ export default function ConnectWallet() {
3535 const fetchingNetworkRef = useRef ( false ) ;
3636 const lastNetworkWalletRef = useRef < string | null > ( null ) ;
3737 const userAssets = useUserStore ( ( state ) => state . userAssets ) ;
38+ const [ walletsLoading , setWalletsLoading ] = useState ( true ) ;
39+ const [ isMounted , setIsMounted ] = useState ( false ) ;
40+ const walletsRetryTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
41+
42+ // Ensure component only runs on client side (important for SSR/production)
43+ useEffect ( ( ) => {
44+ setIsMounted ( true ) ;
45+ } , [ ] ) ;
3846
3947 async function connectWallet ( walletId : string ) {
4048 setPastWallet ( walletId ) ;
4149 await connect ( walletId ) ;
4250 }
4351
52+ // Monitor wallet list loading state and retry if empty
53+ useEffect ( ( ) => {
54+ // Only run on client side
55+ if ( ! isMounted ) return ;
56+
57+ if ( wallets . length > 0 ) {
58+ setWalletsLoading ( false ) ;
59+ // Clear any pending retry timeout
60+ if ( walletsRetryTimeoutRef . current ) {
61+ clearTimeout ( walletsRetryTimeoutRef . current ) ;
62+ walletsRetryTimeoutRef . current = null ;
63+ }
64+ } else if ( ! connected ) {
65+ // Only show loading state if not connected (wallets might load after connection)
66+ // If wallets are empty, wait a bit and check again
67+ // This handles cases where wallet extensions load asynchronously
68+ if ( walletsRetryTimeoutRef . current === null ) {
69+ setWalletsLoading ( true ) ;
70+ let retryCount = 0 ;
71+ const maxRetries = 10 ; // Try for up to 10 seconds in production (longer timeout)
72+
73+ const checkWallets = ( ) => {
74+ retryCount ++ ;
75+ // Re-check wallets array length (it might have updated)
76+ if ( wallets . length > 0 ) {
77+ setWalletsLoading ( false ) ;
78+ walletsRetryTimeoutRef . current = null ;
79+ return ;
80+ }
81+
82+ if ( retryCount < maxRetries ) {
83+ walletsRetryTimeoutRef . current = setTimeout ( checkWallets , 1000 ) ; // Check every second
84+ } else {
85+ console . warn ( "Wallet list still empty after retries, wallets may not be available" ) ;
86+ setWalletsLoading ( false ) ; // Stop showing loading state
87+ walletsRetryTimeoutRef . current = null ;
88+ }
89+ } ;
90+
91+ walletsRetryTimeoutRef . current = setTimeout ( checkWallets , 1000 ) ;
92+ }
93+ } else {
94+ // If connected but no wallets, they're probably not needed
95+ setWalletsLoading ( false ) ;
96+ }
97+
98+ return ( ) => {
99+ if ( walletsRetryTimeoutRef . current ) {
100+ clearTimeout ( walletsRetryTimeoutRef . current ) ;
101+ walletsRetryTimeoutRef . current = null ;
102+ }
103+ } ;
104+ } , [ wallets , connected , isMounted ] ) ;
105+
44106 /**
45107 * Try to connect the wallet when the user loads the application, if user had connected before,
46108 * but only if:
47- * 1. The wallet list has been loaded (wallets.length > 0)
48- * 2. The pastWallet exists in the available wallets
49- * 3. We're not already connected
50- * 4. We're not already attempting to connect
109+ * 1. Component is mounted (client-side only)
110+ * 2. The wallet list has been loaded (wallets.length > 0)
111+ * 3. The pastWallet exists in the available wallets
112+ * 4. We're not already connected
113+ * 5. We're not already attempting to connect
51114 */
52115 useEffect ( ( ) => {
116+ // Only run on client side
117+ if ( ! isMounted ) return ;
118+
53119 async function handleAutoWalletConnect ( ) {
54120 // Don't attempt if already connected or already connecting
55121 if ( connected || connectingRef . current ) {
@@ -65,6 +131,7 @@ export default function ConnectWallet() {
65131 // If wallets array is empty, wallets might still be loading
66132 // The effect will re-run when wallets become available
67133 if ( wallets . length === 0 ) {
134+ console . log ( "Waiting for wallets to load..." ) ;
68135 return ;
69136 }
70137
@@ -96,7 +163,7 @@ export default function ConnectWallet() {
96163 }
97164
98165 handleAutoWalletConnect ( ) ;
99- } , [ pastWallet , connected , wallets , connect , setPastWallet ] ) ;
166+ } , [ pastWallet , connected , wallets , connect , setPastWallet , isMounted ] ) ;
100167
101168 useEffect ( ( ) => {
102169 async function lookupWalletAssets ( ) {
@@ -226,12 +293,12 @@ export default function ConnectWallet() {
226293 }
227294 }
228295
229- // Only run if wallet and connected state are available
230- if ( wallet && connected ) {
296+ // Only run if wallet and connected state are available, and component is mounted
297+ if ( isMounted && wallet && connected ) {
231298 handleNetworkChange ( ) ;
232299 getWalletAssets ( ) ;
233300 }
234- } , [ connected , wallet , name , setNetwork , setUserAssets , setUserAssetMetadata ] ) ;
301+ } , [ connected , wallet , name , setNetwork , setUserAssets , setUserAssetMetadata , isMounted ] ) ;
235302
236303 return (
237304 < DropdownMenu >
@@ -246,13 +313,25 @@ export default function ConnectWallet() {
246313 < DropdownMenuContent align = "end" >
247314 < DropdownMenuLabel > Select Wallet</ DropdownMenuLabel >
248315 < DropdownMenuSeparator />
249- { wallets . map ( ( wallet , i ) => {
250- return (
251- < DropdownMenuItem key = { i } onClick = { ( ) => connectWallet ( wallet . id ) } >
252- { wallet . name }
253- </ DropdownMenuItem >
254- ) ;
255- } ) }
316+ { walletsLoading && wallets . length === 0 ? (
317+ < DropdownMenuItem disabled >
318+ < span className = "text-muted-foreground" > Loading wallets...</ span >
319+ </ DropdownMenuItem >
320+ ) : wallets . length === 0 ? (
321+ < DropdownMenuItem disabled >
322+ < span className = "text-muted-foreground" >
323+ No wallets available. Please install a Cardano wallet extension.
324+ </ span >
325+ </ DropdownMenuItem >
326+ ) : (
327+ wallets . map ( ( wallet , i ) => {
328+ return (
329+ < DropdownMenuItem key = { i } onClick = { ( ) => connectWallet ( wallet . id ) } >
330+ { wallet . name }
331+ </ DropdownMenuItem >
332+ ) ;
333+ } )
334+ ) }
256335 </ DropdownMenuContent >
257336 </ DropdownMenu >
258337 ) ;
0 commit comments