tiwiflix-wallet-connector 1.5.5 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +120 -7
- package/dist/index.js +120 -7
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -7530,7 +7530,7 @@ const defaultStyles = {
|
|
|
7530
7530
|
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
7531
7531
|
boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
|
|
7532
7532
|
}};
|
|
7533
|
-
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7533
|
+
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet Now', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7534
7534
|
// Provide a default fetchBalance if not passed
|
|
7535
7535
|
const fetchBalance = fetchBalanceProp || (async (account) => {
|
|
7536
7536
|
// Default: return zero balance with symbol based on chain
|
|
@@ -7662,12 +7662,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7662
7662
|
});
|
|
7663
7663
|
// Stable USD value updater - only updates if value changes significantly
|
|
7664
7664
|
const setUsdValueStable = useCallback((newValue) => {
|
|
7665
|
-
// Set USD value immediately - only skip if value is the same
|
|
7666
7665
|
setUsdValue((prevValue) => {
|
|
7667
7666
|
// If new value is null/undefined and we have a previous value, keep it
|
|
7668
7667
|
if ((newValue === null || newValue === undefined) && prevValue !== null) {
|
|
7669
7668
|
return prevValue;
|
|
7670
7669
|
}
|
|
7670
|
+
// Only update if value actually changed
|
|
7671
|
+
if (prevValue === newValue) {
|
|
7672
|
+
return prevValue;
|
|
7673
|
+
}
|
|
7671
7674
|
// Otherwise set the new value
|
|
7672
7675
|
return newValue;
|
|
7673
7676
|
});
|
|
@@ -7832,6 +7835,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7832
7835
|
});
|
|
7833
7836
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
7834
7837
|
}, [account?.address, fetchTransactions, cacheTimeout]);
|
|
7838
|
+
// Fallback guard to avoid getting stuck in a loading state (e.g., after page refresh)
|
|
7839
|
+
useEffect(() => {
|
|
7840
|
+
// Only run when we are actually in a loading state
|
|
7841
|
+
if (!isInitializing && !balanceLoading && !isConnecting)
|
|
7842
|
+
return;
|
|
7843
|
+
const timeout = setTimeout(() => {
|
|
7844
|
+
setIsInitializing(false);
|
|
7845
|
+
setBalanceLoading(false);
|
|
7846
|
+
setIsConnecting(false);
|
|
7847
|
+
}, 4000); // force-resolve after 4s
|
|
7848
|
+
return () => clearTimeout(timeout);
|
|
7849
|
+
}, [isInitializing, balanceLoading, isConnecting]);
|
|
7835
7850
|
// Check chain ID and validate network
|
|
7836
7851
|
useEffect(() => {
|
|
7837
7852
|
const checkChain = async () => {
|
|
@@ -7881,9 +7896,29 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7881
7896
|
const walletsRef = useRef(null);
|
|
7882
7897
|
// Initialize and subscribe to events
|
|
7883
7898
|
useEffect(() => {
|
|
7899
|
+
let isMounted = true;
|
|
7884
7900
|
// Get initial state
|
|
7885
7901
|
const initialState = connector.getState();
|
|
7886
7902
|
setStatus(initialState.status);
|
|
7903
|
+
// Immediate hydration from cached state/localStorage to avoid loading flashes on page changes
|
|
7904
|
+
if (initialState.account) {
|
|
7905
|
+
setAccount(initialState.account);
|
|
7906
|
+
// Prefer fresh TWC state, otherwise restore from localStorage cache
|
|
7907
|
+
if (initialState.twcBalance && initialState.twcBalance !== '0' && initialState.twcBalance !== '0.00') {
|
|
7908
|
+
setTwcBalance(initialState.twcBalance);
|
|
7909
|
+
setUsdValueStable(initialState.usdValue ?? null);
|
|
7910
|
+
}
|
|
7911
|
+
else {
|
|
7912
|
+
const cached = loadTWCBalanceFromCache(initialState.account.address);
|
|
7913
|
+
if (cached?.balance) {
|
|
7914
|
+
setTwcBalance(cached.balance);
|
|
7915
|
+
setUsdValueStable(cached.usdValue);
|
|
7916
|
+
}
|
|
7917
|
+
}
|
|
7918
|
+
// Since we have hydrated from cache, avoid showing the loading state
|
|
7919
|
+
setIsInitializing(false);
|
|
7920
|
+
setBalanceLoading(false);
|
|
7921
|
+
}
|
|
7887
7922
|
// Safety: Clear isConnecting on mount (in case it was stuck from previous session)
|
|
7888
7923
|
setIsConnecting(false);
|
|
7889
7924
|
// Only set wallets once to prevent re-renders
|
|
@@ -7902,6 +7937,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7902
7937
|
setBalanceLoading(false);
|
|
7903
7938
|
}, 2000);
|
|
7904
7939
|
connector.getAccount().then(async (acc) => {
|
|
7940
|
+
if (!isMounted)
|
|
7941
|
+
return;
|
|
7905
7942
|
setAccount(acc);
|
|
7906
7943
|
// Load balance when account is available
|
|
7907
7944
|
if (acc && acc.chainType === 'ton') {
|
|
@@ -7912,10 +7949,14 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7912
7949
|
fetchTONBalance(acc),
|
|
7913
7950
|
fetchTONNFTs(acc)
|
|
7914
7951
|
]);
|
|
7952
|
+
if (!isMounted)
|
|
7953
|
+
return;
|
|
7915
7954
|
clearTimeout(safetyTimeout);
|
|
7916
7955
|
setIsInitializing(false);
|
|
7917
7956
|
}
|
|
7918
7957
|
catch (err) {
|
|
7958
|
+
if (!isMounted)
|
|
7959
|
+
return;
|
|
7919
7960
|
clearTimeout(safetyTimeout);
|
|
7920
7961
|
setIsInitializing(false);
|
|
7921
7962
|
}
|
|
@@ -7924,6 +7965,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7924
7965
|
try {
|
|
7925
7966
|
setBalanceLoading(true);
|
|
7926
7967
|
const hasRealBalance = await loadBalance();
|
|
7968
|
+
if (!isMounted)
|
|
7969
|
+
return;
|
|
7927
7970
|
// Always stop loading state after balance fetch
|
|
7928
7971
|
setBalanceLoading(false);
|
|
7929
7972
|
clearTimeout(safetyTimeout);
|
|
@@ -7931,6 +7974,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7931
7974
|
setIsInitializing(false);
|
|
7932
7975
|
}
|
|
7933
7976
|
catch (err) {
|
|
7977
|
+
if (!isMounted)
|
|
7978
|
+
return;
|
|
7934
7979
|
setBalanceLoading(false);
|
|
7935
7980
|
clearTimeout(safetyTimeout);
|
|
7936
7981
|
// Always stop initializing on error
|
|
@@ -7942,6 +7987,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7942
7987
|
const state = connector.getState();
|
|
7943
7988
|
const stateTwcBalance = state.twcBalance;
|
|
7944
7989
|
if (acc && stateTwcBalance && stateTwcBalance !== '0' && stateTwcBalance !== '0.00') {
|
|
7990
|
+
if (!isMounted)
|
|
7991
|
+
return;
|
|
7945
7992
|
setTwcBalance(stateTwcBalance);
|
|
7946
7993
|
setUsdValueStable(state.usdValue ?? null);
|
|
7947
7994
|
// Save to cache
|
|
@@ -7955,6 +8002,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7955
8002
|
// Try to load from cache as fallback
|
|
7956
8003
|
const cached = loadTWCBalanceFromCache(acc.address);
|
|
7957
8004
|
if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00') {
|
|
8005
|
+
if (!isMounted)
|
|
8006
|
+
return;
|
|
7958
8007
|
setTwcBalance(cached.balance);
|
|
7959
8008
|
setUsdValueStable(cached.usdValue);
|
|
7960
8009
|
clearTimeout(safetyTimeout);
|
|
@@ -7964,6 +8013,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7964
8013
|
// No real balance yet, but for EVM wallets, proactively fetch with retries
|
|
7965
8014
|
if (acc.chainType === 'evm') {
|
|
7966
8015
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8016
|
+
if (!isMounted)
|
|
8017
|
+
return;
|
|
7967
8018
|
if (result) {
|
|
7968
8019
|
setTwcBalance(result.balance);
|
|
7969
8020
|
setUsdValueStable(result.usdValue);
|
|
@@ -7980,6 +8031,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7980
8031
|
setIsInitializing(false);
|
|
7981
8032
|
}
|
|
7982
8033
|
}).catch((error) => {
|
|
8034
|
+
if (!isMounted)
|
|
8035
|
+
return;
|
|
7983
8036
|
// On error - show connected button with 0 balance
|
|
7984
8037
|
setTwcBalance('0');
|
|
7985
8038
|
clearTimeout(safetyTimeout);
|
|
@@ -7995,9 +8048,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7995
8048
|
fetchTONBalance(acc),
|
|
7996
8049
|
fetchTONNFTs(acc)
|
|
7997
8050
|
]).then(() => {
|
|
8051
|
+
if (!isMounted)
|
|
8052
|
+
return;
|
|
7998
8053
|
clearTimeout(safetyTimeout);
|
|
7999
8054
|
setIsInitializing(false);
|
|
8000
8055
|
}).catch((err) => {
|
|
8056
|
+
if (!isMounted)
|
|
8057
|
+
return;
|
|
8001
8058
|
clearTimeout(safetyTimeout);
|
|
8002
8059
|
setIsInitializing(false);
|
|
8003
8060
|
});
|
|
@@ -8005,6 +8062,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8005
8062
|
else if (fetchBalance) {
|
|
8006
8063
|
// For other non-EVM chains: If fetchBalance is provided, load balance and then stop initializing
|
|
8007
8064
|
fetchTWCBalanceWithRetry(1, 100).then((result) => {
|
|
8065
|
+
if (!isMounted)
|
|
8066
|
+
return;
|
|
8008
8067
|
if (result) {
|
|
8009
8068
|
setTwcBalance(result.balance);
|
|
8010
8069
|
setUsdValueStable(result.usdValue);
|
|
@@ -8016,12 +8075,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8016
8075
|
clearTimeout(safetyTimeout);
|
|
8017
8076
|
setIsInitializing(false);
|
|
8018
8077
|
}).catch(() => {
|
|
8078
|
+
if (!isMounted)
|
|
8079
|
+
return;
|
|
8019
8080
|
// Stop initializing even on error
|
|
8020
8081
|
clearTimeout(safetyTimeout);
|
|
8021
8082
|
setIsInitializing(false);
|
|
8022
8083
|
});
|
|
8023
8084
|
}
|
|
8024
8085
|
else {
|
|
8086
|
+
if (!isMounted)
|
|
8087
|
+
return;
|
|
8025
8088
|
// No fetchBalance and no cached balance - stop initializing with 0 balance
|
|
8026
8089
|
setTwcBalance('0');
|
|
8027
8090
|
clearTimeout(safetyTimeout);
|
|
@@ -8032,6 +8095,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8032
8095
|
}
|
|
8033
8096
|
}
|
|
8034
8097
|
}).catch((err) => {
|
|
8098
|
+
if (!isMounted)
|
|
8099
|
+
return;
|
|
8035
8100
|
clearTimeout(safetyTimeout);
|
|
8036
8101
|
setIsInitializing(false);
|
|
8037
8102
|
// If we can't get account even though status is connected, disconnect
|
|
@@ -8044,9 +8109,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8044
8109
|
setIsInitializing(true);
|
|
8045
8110
|
// Set a shorter timeout to prevent stuck loading state
|
|
8046
8111
|
initTimeout = setTimeout(() => {
|
|
8112
|
+
if (!isMounted)
|
|
8113
|
+
return;
|
|
8047
8114
|
setIsInitializing(false);
|
|
8048
8115
|
// If still no account after timeout, ensure we show connect button
|
|
8049
8116
|
connector.getAccount().then((acc) => {
|
|
8117
|
+
if (!isMounted)
|
|
8118
|
+
return;
|
|
8050
8119
|
if (!acc) {
|
|
8051
8120
|
setAccount(null);
|
|
8052
8121
|
// If status is disconnected and no account, ensure we're fully disconnected
|
|
@@ -8058,11 +8127,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8058
8127
|
}
|
|
8059
8128
|
}
|
|
8060
8129
|
}).catch((err) => {
|
|
8130
|
+
if (!isMounted)
|
|
8131
|
+
return;
|
|
8061
8132
|
setAccount(null);
|
|
8062
8133
|
setStatus(ConnectionStatus.DISCONNECTED);
|
|
8063
8134
|
});
|
|
8064
8135
|
}, 1500); // Reduced to 1.5 second timeout to prevent stuck loading
|
|
8065
8136
|
connector.getAccount().then((acc) => {
|
|
8137
|
+
if (!isMounted)
|
|
8138
|
+
return;
|
|
8066
8139
|
if (initTimeout)
|
|
8067
8140
|
clearTimeout(initTimeout);
|
|
8068
8141
|
setAccount(acc);
|
|
@@ -8077,6 +8150,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8077
8150
|
}
|
|
8078
8151
|
}
|
|
8079
8152
|
}).catch((err) => {
|
|
8153
|
+
if (!isMounted)
|
|
8154
|
+
return;
|
|
8080
8155
|
if (initTimeout)
|
|
8081
8156
|
clearTimeout(initTimeout);
|
|
8082
8157
|
setIsInitializing(false);
|
|
@@ -8090,6 +8165,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8090
8165
|
}
|
|
8091
8166
|
// Subscribe to events
|
|
8092
8167
|
const unsubscribeAccount = connector.on(WalletEvent.ACCOUNT_CHANGED, async (acc) => {
|
|
8168
|
+
if (!isMounted)
|
|
8169
|
+
return;
|
|
8093
8170
|
setAccount(acc);
|
|
8094
8171
|
// Clear isConnecting when account changes (connection succeeded)
|
|
8095
8172
|
setIsConnecting(false);
|
|
@@ -8110,9 +8187,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8110
8187
|
fetchTONBalance(acc),
|
|
8111
8188
|
fetchTONNFTs(acc)
|
|
8112
8189
|
]);
|
|
8190
|
+
if (!isMounted)
|
|
8191
|
+
return;
|
|
8113
8192
|
setIsInitializing(false);
|
|
8114
8193
|
}
|
|
8115
8194
|
catch (err) {
|
|
8195
|
+
if (!isMounted)
|
|
8196
|
+
return;
|
|
8116
8197
|
setIsInitializing(false);
|
|
8117
8198
|
}
|
|
8118
8199
|
}
|
|
@@ -8120,9 +8201,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8120
8201
|
setBalanceLoading(true);
|
|
8121
8202
|
try {
|
|
8122
8203
|
await loadBalance();
|
|
8204
|
+
if (!isMounted)
|
|
8205
|
+
return;
|
|
8123
8206
|
setIsInitializing(false);
|
|
8124
8207
|
}
|
|
8125
8208
|
catch (err) {
|
|
8209
|
+
if (!isMounted)
|
|
8210
|
+
return;
|
|
8126
8211
|
setIsInitializing(false);
|
|
8127
8212
|
setBalanceLoading(false);
|
|
8128
8213
|
}
|
|
@@ -8245,6 +8330,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8245
8330
|
}
|
|
8246
8331
|
});
|
|
8247
8332
|
return () => {
|
|
8333
|
+
isMounted = false;
|
|
8248
8334
|
clearTimeout(initTimeout);
|
|
8249
8335
|
unsubscribeAccount();
|
|
8250
8336
|
unsubscribeStatus();
|
|
@@ -8390,16 +8476,23 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8390
8476
|
}, [connector]);
|
|
8391
8477
|
// Load balance when account changes
|
|
8392
8478
|
useEffect(() => {
|
|
8479
|
+
let isActive = true;
|
|
8393
8480
|
if (account && fetchBalance) {
|
|
8394
8481
|
setBalanceLoading(true);
|
|
8395
8482
|
loadBalance()
|
|
8396
8483
|
.then(() => {
|
|
8484
|
+
if (!isActive)
|
|
8485
|
+
return;
|
|
8397
8486
|
// Always stop initializing once balance request completes
|
|
8398
8487
|
})
|
|
8399
8488
|
.catch(() => {
|
|
8489
|
+
if (!isActive)
|
|
8490
|
+
return;
|
|
8400
8491
|
// Ignore errors, we still clear loading states
|
|
8401
8492
|
})
|
|
8402
8493
|
.finally(() => {
|
|
8494
|
+
if (!isActive)
|
|
8495
|
+
return;
|
|
8403
8496
|
setBalanceLoading(false);
|
|
8404
8497
|
setIsInitializing(false);
|
|
8405
8498
|
});
|
|
@@ -8432,6 +8525,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8432
8525
|
// Only fetch if we don't have a balance yet
|
|
8433
8526
|
if (!hasBalance) {
|
|
8434
8527
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8528
|
+
if (!isActive)
|
|
8529
|
+
return;
|
|
8435
8530
|
if (result) {
|
|
8436
8531
|
setTwcBalance(result.balance);
|
|
8437
8532
|
setUsdValueStable(result.usdValue);
|
|
@@ -8447,6 +8542,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8447
8542
|
setIsInitializing(false);
|
|
8448
8543
|
}
|
|
8449
8544
|
}).catch(() => {
|
|
8545
|
+
if (!isActive)
|
|
8546
|
+
return;
|
|
8450
8547
|
setIsInitializing(false);
|
|
8451
8548
|
});
|
|
8452
8549
|
}
|
|
@@ -8467,22 +8564,33 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8467
8564
|
}
|
|
8468
8565
|
}
|
|
8469
8566
|
}
|
|
8567
|
+
return () => {
|
|
8568
|
+
isActive = false;
|
|
8569
|
+
};
|
|
8470
8570
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8471
8571
|
}, [account?.address, fetchBalance]);
|
|
8472
8572
|
// Polling mechanism as fallback to ensure TWC balance is always fetched
|
|
8473
8573
|
useEffect(() => {
|
|
8474
|
-
if (!account || account.chainType !== 'evm'
|
|
8574
|
+
if (!account || account.chainType !== 'evm') {
|
|
8475
8575
|
return;
|
|
8476
8576
|
}
|
|
8477
|
-
//
|
|
8478
|
-
const
|
|
8479
|
-
|
|
8577
|
+
// Check if we already have a balance
|
|
8578
|
+
const currentBalance = twcBalance;
|
|
8579
|
+
const hasBalance = currentBalance && currentBalance !== '0' && currentBalance !== '0.00';
|
|
8580
|
+
if (!hasBalance && !isInitializing) {
|
|
8480
8581
|
// Poll every 2 seconds, up to 3 times (6 seconds total) - faster polling
|
|
8481
8582
|
let pollCount = 0;
|
|
8482
8583
|
const maxPolls = 3;
|
|
8584
|
+
let isActive = true;
|
|
8483
8585
|
const pollInterval = setInterval(() => {
|
|
8586
|
+
if (!isActive) {
|
|
8587
|
+
clearInterval(pollInterval);
|
|
8588
|
+
return;
|
|
8589
|
+
}
|
|
8484
8590
|
pollCount++;
|
|
8485
8591
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8592
|
+
if (!isActive)
|
|
8593
|
+
return;
|
|
8486
8594
|
if (result) {
|
|
8487
8595
|
setTwcBalance(result.balance);
|
|
8488
8596
|
setUsdValueStable(result.usdValue);
|
|
@@ -8495,17 +8603,22 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8495
8603
|
clearInterval(pollInterval);
|
|
8496
8604
|
}
|
|
8497
8605
|
}).catch((error) => {
|
|
8606
|
+
if (!isActive)
|
|
8607
|
+
return;
|
|
8498
8608
|
if (pollCount >= maxPolls) {
|
|
8499
8609
|
clearInterval(pollInterval);
|
|
8500
8610
|
}
|
|
8501
8611
|
});
|
|
8502
8612
|
}, 2000); // Poll every 2 seconds (faster)
|
|
8503
8613
|
return () => {
|
|
8614
|
+
isActive = false;
|
|
8504
8615
|
clearInterval(pollInterval);
|
|
8505
8616
|
};
|
|
8506
8617
|
}
|
|
8618
|
+
return undefined;
|
|
8619
|
+
// Only depend on account address - check balance inside effect
|
|
8507
8620
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8508
|
-
}, [account?.address
|
|
8621
|
+
}, [account?.address]);
|
|
8509
8622
|
// Load transactions when details modal opens
|
|
8510
8623
|
useEffect(() => {
|
|
8511
8624
|
if (showDetailsModal && account) {
|
package/dist/index.js
CHANGED
|
@@ -7532,7 +7532,7 @@ const defaultStyles = {
|
|
|
7532
7532
|
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
7533
7533
|
boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
|
|
7534
7534
|
}};
|
|
7535
|
-
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7535
|
+
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet Now', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7536
7536
|
// Provide a default fetchBalance if not passed
|
|
7537
7537
|
const fetchBalance = fetchBalanceProp || (async (account) => {
|
|
7538
7538
|
// Default: return zero balance with symbol based on chain
|
|
@@ -7664,12 +7664,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7664
7664
|
});
|
|
7665
7665
|
// Stable USD value updater - only updates if value changes significantly
|
|
7666
7666
|
const setUsdValueStable = React.useCallback((newValue) => {
|
|
7667
|
-
// Set USD value immediately - only skip if value is the same
|
|
7668
7667
|
setUsdValue((prevValue) => {
|
|
7669
7668
|
// If new value is null/undefined and we have a previous value, keep it
|
|
7670
7669
|
if ((newValue === null || newValue === undefined) && prevValue !== null) {
|
|
7671
7670
|
return prevValue;
|
|
7672
7671
|
}
|
|
7672
|
+
// Only update if value actually changed
|
|
7673
|
+
if (prevValue === newValue) {
|
|
7674
|
+
return prevValue;
|
|
7675
|
+
}
|
|
7673
7676
|
// Otherwise set the new value
|
|
7674
7677
|
return newValue;
|
|
7675
7678
|
});
|
|
@@ -7834,6 +7837,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7834
7837
|
});
|
|
7835
7838
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
7836
7839
|
}, [account?.address, fetchTransactions, cacheTimeout]);
|
|
7840
|
+
// Fallback guard to avoid getting stuck in a loading state (e.g., after page refresh)
|
|
7841
|
+
React.useEffect(() => {
|
|
7842
|
+
// Only run when we are actually in a loading state
|
|
7843
|
+
if (!isInitializing && !balanceLoading && !isConnecting)
|
|
7844
|
+
return;
|
|
7845
|
+
const timeout = setTimeout(() => {
|
|
7846
|
+
setIsInitializing(false);
|
|
7847
|
+
setBalanceLoading(false);
|
|
7848
|
+
setIsConnecting(false);
|
|
7849
|
+
}, 4000); // force-resolve after 4s
|
|
7850
|
+
return () => clearTimeout(timeout);
|
|
7851
|
+
}, [isInitializing, balanceLoading, isConnecting]);
|
|
7837
7852
|
// Check chain ID and validate network
|
|
7838
7853
|
React.useEffect(() => {
|
|
7839
7854
|
const checkChain = async () => {
|
|
@@ -7883,9 +7898,29 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7883
7898
|
const walletsRef = React.useRef(null);
|
|
7884
7899
|
// Initialize and subscribe to events
|
|
7885
7900
|
React.useEffect(() => {
|
|
7901
|
+
let isMounted = true;
|
|
7886
7902
|
// Get initial state
|
|
7887
7903
|
const initialState = connector.getState();
|
|
7888
7904
|
setStatus(initialState.status);
|
|
7905
|
+
// Immediate hydration from cached state/localStorage to avoid loading flashes on page changes
|
|
7906
|
+
if (initialState.account) {
|
|
7907
|
+
setAccount(initialState.account);
|
|
7908
|
+
// Prefer fresh TWC state, otherwise restore from localStorage cache
|
|
7909
|
+
if (initialState.twcBalance && initialState.twcBalance !== '0' && initialState.twcBalance !== '0.00') {
|
|
7910
|
+
setTwcBalance(initialState.twcBalance);
|
|
7911
|
+
setUsdValueStable(initialState.usdValue ?? null);
|
|
7912
|
+
}
|
|
7913
|
+
else {
|
|
7914
|
+
const cached = loadTWCBalanceFromCache(initialState.account.address);
|
|
7915
|
+
if (cached?.balance) {
|
|
7916
|
+
setTwcBalance(cached.balance);
|
|
7917
|
+
setUsdValueStable(cached.usdValue);
|
|
7918
|
+
}
|
|
7919
|
+
}
|
|
7920
|
+
// Since we have hydrated from cache, avoid showing the loading state
|
|
7921
|
+
setIsInitializing(false);
|
|
7922
|
+
setBalanceLoading(false);
|
|
7923
|
+
}
|
|
7889
7924
|
// Safety: Clear isConnecting on mount (in case it was stuck from previous session)
|
|
7890
7925
|
setIsConnecting(false);
|
|
7891
7926
|
// Only set wallets once to prevent re-renders
|
|
@@ -7904,6 +7939,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7904
7939
|
setBalanceLoading(false);
|
|
7905
7940
|
}, 2000);
|
|
7906
7941
|
connector.getAccount().then(async (acc) => {
|
|
7942
|
+
if (!isMounted)
|
|
7943
|
+
return;
|
|
7907
7944
|
setAccount(acc);
|
|
7908
7945
|
// Load balance when account is available
|
|
7909
7946
|
if (acc && acc.chainType === 'ton') {
|
|
@@ -7914,10 +7951,14 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7914
7951
|
fetchTONBalance(acc),
|
|
7915
7952
|
fetchTONNFTs(acc)
|
|
7916
7953
|
]);
|
|
7954
|
+
if (!isMounted)
|
|
7955
|
+
return;
|
|
7917
7956
|
clearTimeout(safetyTimeout);
|
|
7918
7957
|
setIsInitializing(false);
|
|
7919
7958
|
}
|
|
7920
7959
|
catch (err) {
|
|
7960
|
+
if (!isMounted)
|
|
7961
|
+
return;
|
|
7921
7962
|
clearTimeout(safetyTimeout);
|
|
7922
7963
|
setIsInitializing(false);
|
|
7923
7964
|
}
|
|
@@ -7926,6 +7967,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7926
7967
|
try {
|
|
7927
7968
|
setBalanceLoading(true);
|
|
7928
7969
|
const hasRealBalance = await loadBalance();
|
|
7970
|
+
if (!isMounted)
|
|
7971
|
+
return;
|
|
7929
7972
|
// Always stop loading state after balance fetch
|
|
7930
7973
|
setBalanceLoading(false);
|
|
7931
7974
|
clearTimeout(safetyTimeout);
|
|
@@ -7933,6 +7976,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7933
7976
|
setIsInitializing(false);
|
|
7934
7977
|
}
|
|
7935
7978
|
catch (err) {
|
|
7979
|
+
if (!isMounted)
|
|
7980
|
+
return;
|
|
7936
7981
|
setBalanceLoading(false);
|
|
7937
7982
|
clearTimeout(safetyTimeout);
|
|
7938
7983
|
// Always stop initializing on error
|
|
@@ -7944,6 +7989,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7944
7989
|
const state = connector.getState();
|
|
7945
7990
|
const stateTwcBalance = state.twcBalance;
|
|
7946
7991
|
if (acc && stateTwcBalance && stateTwcBalance !== '0' && stateTwcBalance !== '0.00') {
|
|
7992
|
+
if (!isMounted)
|
|
7993
|
+
return;
|
|
7947
7994
|
setTwcBalance(stateTwcBalance);
|
|
7948
7995
|
setUsdValueStable(state.usdValue ?? null);
|
|
7949
7996
|
// Save to cache
|
|
@@ -7957,6 +8004,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7957
8004
|
// Try to load from cache as fallback
|
|
7958
8005
|
const cached = loadTWCBalanceFromCache(acc.address);
|
|
7959
8006
|
if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00') {
|
|
8007
|
+
if (!isMounted)
|
|
8008
|
+
return;
|
|
7960
8009
|
setTwcBalance(cached.balance);
|
|
7961
8010
|
setUsdValueStable(cached.usdValue);
|
|
7962
8011
|
clearTimeout(safetyTimeout);
|
|
@@ -7966,6 +8015,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7966
8015
|
// No real balance yet, but for EVM wallets, proactively fetch with retries
|
|
7967
8016
|
if (acc.chainType === 'evm') {
|
|
7968
8017
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8018
|
+
if (!isMounted)
|
|
8019
|
+
return;
|
|
7969
8020
|
if (result) {
|
|
7970
8021
|
setTwcBalance(result.balance);
|
|
7971
8022
|
setUsdValueStable(result.usdValue);
|
|
@@ -7982,6 +8033,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7982
8033
|
setIsInitializing(false);
|
|
7983
8034
|
}
|
|
7984
8035
|
}).catch((error) => {
|
|
8036
|
+
if (!isMounted)
|
|
8037
|
+
return;
|
|
7985
8038
|
// On error - show connected button with 0 balance
|
|
7986
8039
|
setTwcBalance('0');
|
|
7987
8040
|
clearTimeout(safetyTimeout);
|
|
@@ -7997,9 +8050,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
7997
8050
|
fetchTONBalance(acc),
|
|
7998
8051
|
fetchTONNFTs(acc)
|
|
7999
8052
|
]).then(() => {
|
|
8053
|
+
if (!isMounted)
|
|
8054
|
+
return;
|
|
8000
8055
|
clearTimeout(safetyTimeout);
|
|
8001
8056
|
setIsInitializing(false);
|
|
8002
8057
|
}).catch((err) => {
|
|
8058
|
+
if (!isMounted)
|
|
8059
|
+
return;
|
|
8003
8060
|
clearTimeout(safetyTimeout);
|
|
8004
8061
|
setIsInitializing(false);
|
|
8005
8062
|
});
|
|
@@ -8007,6 +8064,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8007
8064
|
else if (fetchBalance) {
|
|
8008
8065
|
// For other non-EVM chains: If fetchBalance is provided, load balance and then stop initializing
|
|
8009
8066
|
fetchTWCBalanceWithRetry(1, 100).then((result) => {
|
|
8067
|
+
if (!isMounted)
|
|
8068
|
+
return;
|
|
8010
8069
|
if (result) {
|
|
8011
8070
|
setTwcBalance(result.balance);
|
|
8012
8071
|
setUsdValueStable(result.usdValue);
|
|
@@ -8018,12 +8077,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8018
8077
|
clearTimeout(safetyTimeout);
|
|
8019
8078
|
setIsInitializing(false);
|
|
8020
8079
|
}).catch(() => {
|
|
8080
|
+
if (!isMounted)
|
|
8081
|
+
return;
|
|
8021
8082
|
// Stop initializing even on error
|
|
8022
8083
|
clearTimeout(safetyTimeout);
|
|
8023
8084
|
setIsInitializing(false);
|
|
8024
8085
|
});
|
|
8025
8086
|
}
|
|
8026
8087
|
else {
|
|
8088
|
+
if (!isMounted)
|
|
8089
|
+
return;
|
|
8027
8090
|
// No fetchBalance and no cached balance - stop initializing with 0 balance
|
|
8028
8091
|
setTwcBalance('0');
|
|
8029
8092
|
clearTimeout(safetyTimeout);
|
|
@@ -8034,6 +8097,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8034
8097
|
}
|
|
8035
8098
|
}
|
|
8036
8099
|
}).catch((err) => {
|
|
8100
|
+
if (!isMounted)
|
|
8101
|
+
return;
|
|
8037
8102
|
clearTimeout(safetyTimeout);
|
|
8038
8103
|
setIsInitializing(false);
|
|
8039
8104
|
// If we can't get account even though status is connected, disconnect
|
|
@@ -8046,9 +8111,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8046
8111
|
setIsInitializing(true);
|
|
8047
8112
|
// Set a shorter timeout to prevent stuck loading state
|
|
8048
8113
|
initTimeout = setTimeout(() => {
|
|
8114
|
+
if (!isMounted)
|
|
8115
|
+
return;
|
|
8049
8116
|
setIsInitializing(false);
|
|
8050
8117
|
// If still no account after timeout, ensure we show connect button
|
|
8051
8118
|
connector.getAccount().then((acc) => {
|
|
8119
|
+
if (!isMounted)
|
|
8120
|
+
return;
|
|
8052
8121
|
if (!acc) {
|
|
8053
8122
|
setAccount(null);
|
|
8054
8123
|
// If status is disconnected and no account, ensure we're fully disconnected
|
|
@@ -8060,11 +8129,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8060
8129
|
}
|
|
8061
8130
|
}
|
|
8062
8131
|
}).catch((err) => {
|
|
8132
|
+
if (!isMounted)
|
|
8133
|
+
return;
|
|
8063
8134
|
setAccount(null);
|
|
8064
8135
|
setStatus(exports.ConnectionStatus.DISCONNECTED);
|
|
8065
8136
|
});
|
|
8066
8137
|
}, 1500); // Reduced to 1.5 second timeout to prevent stuck loading
|
|
8067
8138
|
connector.getAccount().then((acc) => {
|
|
8139
|
+
if (!isMounted)
|
|
8140
|
+
return;
|
|
8068
8141
|
if (initTimeout)
|
|
8069
8142
|
clearTimeout(initTimeout);
|
|
8070
8143
|
setAccount(acc);
|
|
@@ -8079,6 +8152,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8079
8152
|
}
|
|
8080
8153
|
}
|
|
8081
8154
|
}).catch((err) => {
|
|
8155
|
+
if (!isMounted)
|
|
8156
|
+
return;
|
|
8082
8157
|
if (initTimeout)
|
|
8083
8158
|
clearTimeout(initTimeout);
|
|
8084
8159
|
setIsInitializing(false);
|
|
@@ -8092,6 +8167,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8092
8167
|
}
|
|
8093
8168
|
// Subscribe to events
|
|
8094
8169
|
const unsubscribeAccount = connector.on(exports.WalletEvent.ACCOUNT_CHANGED, async (acc) => {
|
|
8170
|
+
if (!isMounted)
|
|
8171
|
+
return;
|
|
8095
8172
|
setAccount(acc);
|
|
8096
8173
|
// Clear isConnecting when account changes (connection succeeded)
|
|
8097
8174
|
setIsConnecting(false);
|
|
@@ -8112,9 +8189,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8112
8189
|
fetchTONBalance(acc),
|
|
8113
8190
|
fetchTONNFTs(acc)
|
|
8114
8191
|
]);
|
|
8192
|
+
if (!isMounted)
|
|
8193
|
+
return;
|
|
8115
8194
|
setIsInitializing(false);
|
|
8116
8195
|
}
|
|
8117
8196
|
catch (err) {
|
|
8197
|
+
if (!isMounted)
|
|
8198
|
+
return;
|
|
8118
8199
|
setIsInitializing(false);
|
|
8119
8200
|
}
|
|
8120
8201
|
}
|
|
@@ -8122,9 +8203,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8122
8203
|
setBalanceLoading(true);
|
|
8123
8204
|
try {
|
|
8124
8205
|
await loadBalance();
|
|
8206
|
+
if (!isMounted)
|
|
8207
|
+
return;
|
|
8125
8208
|
setIsInitializing(false);
|
|
8126
8209
|
}
|
|
8127
8210
|
catch (err) {
|
|
8211
|
+
if (!isMounted)
|
|
8212
|
+
return;
|
|
8128
8213
|
setIsInitializing(false);
|
|
8129
8214
|
setBalanceLoading(false);
|
|
8130
8215
|
}
|
|
@@ -8247,6 +8332,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8247
8332
|
}
|
|
8248
8333
|
});
|
|
8249
8334
|
return () => {
|
|
8335
|
+
isMounted = false;
|
|
8250
8336
|
clearTimeout(initTimeout);
|
|
8251
8337
|
unsubscribeAccount();
|
|
8252
8338
|
unsubscribeStatus();
|
|
@@ -8392,16 +8478,23 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8392
8478
|
}, [connector]);
|
|
8393
8479
|
// Load balance when account changes
|
|
8394
8480
|
React.useEffect(() => {
|
|
8481
|
+
let isActive = true;
|
|
8395
8482
|
if (account && fetchBalance) {
|
|
8396
8483
|
setBalanceLoading(true);
|
|
8397
8484
|
loadBalance()
|
|
8398
8485
|
.then(() => {
|
|
8486
|
+
if (!isActive)
|
|
8487
|
+
return;
|
|
8399
8488
|
// Always stop initializing once balance request completes
|
|
8400
8489
|
})
|
|
8401
8490
|
.catch(() => {
|
|
8491
|
+
if (!isActive)
|
|
8492
|
+
return;
|
|
8402
8493
|
// Ignore errors, we still clear loading states
|
|
8403
8494
|
})
|
|
8404
8495
|
.finally(() => {
|
|
8496
|
+
if (!isActive)
|
|
8497
|
+
return;
|
|
8405
8498
|
setBalanceLoading(false);
|
|
8406
8499
|
setIsInitializing(false);
|
|
8407
8500
|
});
|
|
@@ -8434,6 +8527,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8434
8527
|
// Only fetch if we don't have a balance yet
|
|
8435
8528
|
if (!hasBalance) {
|
|
8436
8529
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8530
|
+
if (!isActive)
|
|
8531
|
+
return;
|
|
8437
8532
|
if (result) {
|
|
8438
8533
|
setTwcBalance(result.balance);
|
|
8439
8534
|
setUsdValueStable(result.usdValue);
|
|
@@ -8449,6 +8544,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8449
8544
|
setIsInitializing(false);
|
|
8450
8545
|
}
|
|
8451
8546
|
}).catch(() => {
|
|
8547
|
+
if (!isActive)
|
|
8548
|
+
return;
|
|
8452
8549
|
setIsInitializing(false);
|
|
8453
8550
|
});
|
|
8454
8551
|
}
|
|
@@ -8469,22 +8566,33 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8469
8566
|
}
|
|
8470
8567
|
}
|
|
8471
8568
|
}
|
|
8569
|
+
return () => {
|
|
8570
|
+
isActive = false;
|
|
8571
|
+
};
|
|
8472
8572
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8473
8573
|
}, [account?.address, fetchBalance]);
|
|
8474
8574
|
// Polling mechanism as fallback to ensure TWC balance is always fetched
|
|
8475
8575
|
React.useEffect(() => {
|
|
8476
|
-
if (!account || account.chainType !== 'evm'
|
|
8576
|
+
if (!account || account.chainType !== 'evm') {
|
|
8477
8577
|
return;
|
|
8478
8578
|
}
|
|
8479
|
-
//
|
|
8480
|
-
const
|
|
8481
|
-
|
|
8579
|
+
// Check if we already have a balance
|
|
8580
|
+
const currentBalance = twcBalance;
|
|
8581
|
+
const hasBalance = currentBalance && currentBalance !== '0' && currentBalance !== '0.00';
|
|
8582
|
+
if (!hasBalance && !isInitializing) {
|
|
8482
8583
|
// Poll every 2 seconds, up to 3 times (6 seconds total) - faster polling
|
|
8483
8584
|
let pollCount = 0;
|
|
8484
8585
|
const maxPolls = 3;
|
|
8586
|
+
let isActive = true;
|
|
8485
8587
|
const pollInterval = setInterval(() => {
|
|
8588
|
+
if (!isActive) {
|
|
8589
|
+
clearInterval(pollInterval);
|
|
8590
|
+
return;
|
|
8591
|
+
}
|
|
8486
8592
|
pollCount++;
|
|
8487
8593
|
fetchTWCBalanceWithRetry(2, 200).then((result) => {
|
|
8594
|
+
if (!isActive)
|
|
8595
|
+
return;
|
|
8488
8596
|
if (result) {
|
|
8489
8597
|
setTwcBalance(result.balance);
|
|
8490
8598
|
setUsdValueStable(result.usdValue);
|
|
@@ -8497,17 +8605,22 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8497
8605
|
clearInterval(pollInterval);
|
|
8498
8606
|
}
|
|
8499
8607
|
}).catch((error) => {
|
|
8608
|
+
if (!isActive)
|
|
8609
|
+
return;
|
|
8500
8610
|
if (pollCount >= maxPolls) {
|
|
8501
8611
|
clearInterval(pollInterval);
|
|
8502
8612
|
}
|
|
8503
8613
|
});
|
|
8504
8614
|
}, 2000); // Poll every 2 seconds (faster)
|
|
8505
8615
|
return () => {
|
|
8616
|
+
isActive = false;
|
|
8506
8617
|
clearInterval(pollInterval);
|
|
8507
8618
|
};
|
|
8508
8619
|
}
|
|
8620
|
+
return undefined;
|
|
8621
|
+
// Only depend on account address - check balance inside effect
|
|
8509
8622
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8510
|
-
}, [account?.address
|
|
8623
|
+
}, [account?.address]);
|
|
8511
8624
|
// Load transactions when details modal opens
|
|
8512
8625
|
React.useEffect(() => {
|
|
8513
8626
|
if (showDetailsModal && account) {
|
package/package.json
CHANGED