tiwiflix-wallet-connector 1.5.1 → 1.5.3
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 +92 -53
- package/dist/index.js +92 -53
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -2344,6 +2344,11 @@ class WalletConnector {
|
|
|
2344
2344
|
...savedState,
|
|
2345
2345
|
error: null, // Don't restore errors
|
|
2346
2346
|
};
|
|
2347
|
+
// PATCH: Prevent invalid connected state
|
|
2348
|
+
if (this.state.status === ConnectionStatus.CONNECTED && !this.state.account) {
|
|
2349
|
+
this.state.status = ConnectionStatus.DISCONNECTED;
|
|
2350
|
+
this.state.wallet = null;
|
|
2351
|
+
}
|
|
2347
2352
|
}
|
|
2348
2353
|
this.eventEmitter = new EventEmitter$1();
|
|
2349
2354
|
// Initialize advanced SDK management
|
|
@@ -6460,7 +6465,7 @@ const BaseModal = ({ isOpen, onClose, title, children, modalPosition = 'bottom',
|
|
|
6460
6465
|
return modalContent;
|
|
6461
6466
|
};
|
|
6462
6467
|
|
|
6463
|
-
const AccountDetailsModal = ({ isOpen, onClose, account, onDisconnect, onCopyAddress, onOpenSwap, onOpenSend, onOpenActivity, balance, balanceLoading, twcBalance, usdValue, nftCount = 0, nftLoading = false, tonBalance = null, tonUsdValue = null, walletIcon, colors, isDarkMode, modalPosition = 'bottom', }) => {
|
|
6468
|
+
const AccountDetailsModal = ({ isOpen, onClose, account, onDisconnect, onCopyAddress, onOpenSwap, onOpenSend, onOpenActivity, balance, balanceLoading, twcBalance, usdValue, nftCount = 0, nftLoading = false, tonBalance = null, tonUsdValue = null, walletIcon, colors, isDarkMode, modalPosition = 'bottom', onSwitchWallet, }) => {
|
|
6464
6469
|
// State for TWC price - hooks must be called before any conditional returns
|
|
6465
6470
|
const [twcPrice, setTwcPrice] = useState(null);
|
|
6466
6471
|
const [priceLoading, setPriceLoading] = useState(false);
|
|
@@ -7502,7 +7507,19 @@ const defaultStyles = {
|
|
|
7502
7507
|
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
7503
7508
|
boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
|
|
7504
7509
|
}};
|
|
7505
|
-
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance, }) => {
|
|
7510
|
+
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7511
|
+
// Provide a default fetchBalance if not passed
|
|
7512
|
+
const fetchBalance = fetchBalanceProp || (async (account) => {
|
|
7513
|
+
// Default: return zero balance with symbol based on chain
|
|
7514
|
+
let symbol = 'TWC';
|
|
7515
|
+
if (account?.chainType === 'ton')
|
|
7516
|
+
symbol = 'TON';
|
|
7517
|
+
if (account?.chainType === 'solana')
|
|
7518
|
+
symbol = 'SOL';
|
|
7519
|
+
if (account?.chainType === 'tron')
|
|
7520
|
+
symbol = 'TRX';
|
|
7521
|
+
return { amount: '0', symbol };
|
|
7522
|
+
});
|
|
7506
7523
|
// Detect dark mode
|
|
7507
7524
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
7508
7525
|
useEffect(() => {
|
|
@@ -8047,6 +8064,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8047
8064
|
});
|
|
8048
8065
|
}
|
|
8049
8066
|
// Subscribe to events
|
|
8067
|
+
// Prevent repeated onConnect calls for the same account
|
|
8068
|
+
const lastOnConnectAddress = React.useRef(null);
|
|
8050
8069
|
const unsubscribeAccount = connector.on(WalletEvent.ACCOUNT_CHANGED, async (acc) => {
|
|
8051
8070
|
setAccount(acc);
|
|
8052
8071
|
// Don't set isInitializing to false yet - wait for balance to load
|
|
@@ -8059,8 +8078,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8059
8078
|
}
|
|
8060
8079
|
}
|
|
8061
8080
|
if (acc && acc.chainType === 'ton') {
|
|
8062
|
-
|
|
8063
|
-
setTwcBalance('0'); // TON wallets don't have TWC
|
|
8081
|
+
setTwcBalance('0');
|
|
8064
8082
|
try {
|
|
8065
8083
|
await Promise.all([
|
|
8066
8084
|
fetchTONBalance(acc),
|
|
@@ -8084,18 +8102,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8084
8102
|
}
|
|
8085
8103
|
}
|
|
8086
8104
|
else if (acc) {
|
|
8087
|
-
// No fetchBalance, check for TWC balance
|
|
8088
8105
|
const state = connector.getState();
|
|
8089
8106
|
if (state.twcBalance && state.twcBalance !== '0' && state.twcBalance !== '0.00') {
|
|
8090
8107
|
setTwcBalance(state.twcBalance);
|
|
8091
8108
|
setUsdValueStable(state.usdValue ?? null);
|
|
8092
|
-
// Save to cache
|
|
8093
8109
|
if (acc.address) {
|
|
8094
8110
|
saveTWCBalanceToCache(acc.address, state.twcBalance, state.usdValue ?? null);
|
|
8095
8111
|
}
|
|
8096
8112
|
}
|
|
8097
8113
|
else if (acc.address) {
|
|
8098
|
-
// Try to load from cache as fallback
|
|
8099
8114
|
const cached = loadTWCBalanceFromCache(acc.address);
|
|
8100
8115
|
if (cached?.balance) {
|
|
8101
8116
|
setTwcBalance(cached.balance);
|
|
@@ -8108,7 +8123,10 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8108
8123
|
setIsInitializing(false);
|
|
8109
8124
|
}
|
|
8110
8125
|
if (acc && onConnect) {
|
|
8111
|
-
|
|
8126
|
+
if (lastOnConnectAddress.current !== acc.address) {
|
|
8127
|
+
onConnect(acc);
|
|
8128
|
+
lastOnConnectAddress.current = acc.address;
|
|
8129
|
+
}
|
|
8112
8130
|
}
|
|
8113
8131
|
});
|
|
8114
8132
|
const unsubscribeStatus = connector.on(WalletEvent.STATUS_CHANGED, (newStatus) => {
|
|
@@ -8503,6 +8521,12 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8503
8521
|
setIsConnecting(false);
|
|
8504
8522
|
}
|
|
8505
8523
|
catch (err) {
|
|
8524
|
+
// Always clear connection state on error
|
|
8525
|
+
setAccount(null);
|
|
8526
|
+
setStatus(ConnectionStatus.DISCONNECTED);
|
|
8527
|
+
setIsInitializing(false);
|
|
8528
|
+
setIsConnecting(false);
|
|
8529
|
+
setShowModal(false);
|
|
8506
8530
|
// Close modal if the user explicitly cancelled the connection
|
|
8507
8531
|
const message = err instanceof Error ? err.message : String(err);
|
|
8508
8532
|
const isUserCancellation = message.toLowerCase().includes('cancelled') ||
|
|
@@ -8513,22 +8537,11 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8513
8537
|
message.toLowerCase().includes('rejected') ||
|
|
8514
8538
|
message.toLowerCase().includes('modal closed by user') ||
|
|
8515
8539
|
message.toLowerCase().includes('connection cancelled by user');
|
|
8516
|
-
if (isUserCancellation) {
|
|
8517
|
-
setShowModal(false);
|
|
8518
|
-
// Reset connecting state and verify actual connection status
|
|
8519
|
-
const actualAccount = await connector.getAccount();
|
|
8520
|
-
if (!actualAccount) {
|
|
8521
|
-
setAccount(null);
|
|
8522
|
-
}
|
|
8523
|
-
}
|
|
8524
|
-
else if (isTonWallet) {
|
|
8540
|
+
if (!isUserCancellation && isTonWallet) {
|
|
8525
8541
|
// For TON, only reopen the modal on non-cancellation errors
|
|
8526
8542
|
setShowModal(true);
|
|
8527
8543
|
}
|
|
8528
8544
|
}
|
|
8529
|
-
finally {
|
|
8530
|
-
setIsConnecting(false);
|
|
8531
|
-
}
|
|
8532
8545
|
}, [connector, fetchBalance, loadBalance]);
|
|
8533
8546
|
const handleDisconnect = useCallback(async () => {
|
|
8534
8547
|
try {
|
|
@@ -8592,25 +8605,46 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8592
8605
|
setError('Failed to switch network. Please switch manually to BSC in your wallet.');
|
|
8593
8606
|
}
|
|
8594
8607
|
}, [connector]);
|
|
8595
|
-
|
|
8608
|
+
// Only open wallet selection modal if not connected, or if explicitly switching
|
|
8609
|
+
const handleOpenModal = useCallback((force = false) => {
|
|
8610
|
+
// If already connected and not explicitly switching, do nothing
|
|
8611
|
+
const state = connector.getState();
|
|
8612
|
+
if (!force && account && state.status === 'connected') {
|
|
8613
|
+
return;
|
|
8614
|
+
}
|
|
8596
8615
|
// Show ALL wallets - use cached wallets to prevent re-renders
|
|
8597
8616
|
if (!walletsRef.current) {
|
|
8598
8617
|
walletsRef.current = connector.getAllWallets();
|
|
8599
8618
|
}
|
|
8600
8619
|
setAvailableWallets(walletsRef.current);
|
|
8601
8620
|
setShowModal(true);
|
|
8602
|
-
}, [connector]);
|
|
8621
|
+
}, [connector, account]);
|
|
8603
8622
|
// Render button based on connection status
|
|
8604
8623
|
const renderButton = () => {
|
|
8605
8624
|
// Check if we're waiting for connection OR waiting for balance to load
|
|
8606
8625
|
// Show loading if: initializing, connecting, OR (account exists but balance hasn't loaded/resolved yet)
|
|
8607
|
-
//
|
|
8608
|
-
|
|
8626
|
+
// For TON: treat as resolved after fetch completes (even if 0). For others: treat zero/empty as resolved.
|
|
8627
|
+
(balance.amount && balance.amount !== '0' && balance.amount !== '0.00' && balance.amount !== '' && balance.amount !== 'Loading...') ||
|
|
8609
8628
|
(twcBalance && twcBalance !== '0' && twcBalance !== '0.00' && twcBalance !== '' && twcBalance !== 'Loading...');
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8629
|
+
let isBalanceResolved;
|
|
8630
|
+
if (account?.chainType === 'ton') {
|
|
8631
|
+
// For TON, resolved if not loading or initializing
|
|
8632
|
+
isBalanceResolved = !balanceLoading && !isInitializing;
|
|
8633
|
+
}
|
|
8634
|
+
else {
|
|
8635
|
+
// For EVM, Solana, Tron: resolved if not loading (even if balance is zero)
|
|
8636
|
+
isBalanceResolved = !balanceLoading && !isInitializing;
|
|
8637
|
+
}
|
|
8613
8638
|
const waitingForBalance = account && !isBalanceResolved;
|
|
8639
|
+
// Patch: If account is null and status is disconnected, always stop initializing/loading
|
|
8640
|
+
if (!account && status === ConnectionStatus.DISCONNECTED && (isInitializing || isConnecting || balanceLoading)) {
|
|
8641
|
+
if (isInitializing)
|
|
8642
|
+
setIsInitializing(false);
|
|
8643
|
+
if (isConnecting)
|
|
8644
|
+
setIsConnecting(false);
|
|
8645
|
+
if (balanceLoading)
|
|
8646
|
+
setBalanceLoading(false);
|
|
8647
|
+
}
|
|
8614
8648
|
const isCheckingConnection = isInitializing || waitingForBalance || ((status === ConnectionStatus.CONNECTING || isConnecting) && !account);
|
|
8615
8649
|
const isActuallyConnecting = (status === ConnectionStatus.CONNECTING || isConnecting) && account && isBalanceResolved;
|
|
8616
8650
|
// Check connection state
|
|
@@ -8820,31 +8854,34 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8820
8854
|
}
|
|
8821
8855
|
// Wallet icon SVG component
|
|
8822
8856
|
const WalletIcon = () => (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8857
|
+
// Only show connect button if not connected
|
|
8858
|
+
if (!account || status !== ConnectionStatus.CONNECTED) {
|
|
8859
|
+
return (jsxs("button", { onClick: () => handleOpenModal(), style: {
|
|
8860
|
+
display: 'flex',
|
|
8861
|
+
alignItems: 'center',
|
|
8862
|
+
gap: '10px',
|
|
8863
|
+
padding: '12px 12px',
|
|
8864
|
+
borderRadius: '12px',
|
|
8865
|
+
border: 'none',
|
|
8866
|
+
backgroundColor: '#FF9814', // Warm golden-orange
|
|
8867
|
+
color: '#000000', // Black text
|
|
8868
|
+
fontWeight: '700',
|
|
8869
|
+
fontSize: '15px',
|
|
8870
|
+
cursor: 'pointer',
|
|
8871
|
+
transition: 'all 0.15s ease',
|
|
8872
|
+
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
8873
|
+
boxShadow: '0 2px 8px rgba(255, 152, 20, 0.3)',
|
|
8874
|
+
...style,
|
|
8875
|
+
}, className: className, onMouseEnter: (e) => {
|
|
8876
|
+
e.currentTarget.style.backgroundColor = '#E8870F';
|
|
8877
|
+
e.currentTarget.style.transform = 'translateY(-1px)';
|
|
8878
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(255, 152, 20, 0.4)';
|
|
8879
|
+
}, onMouseLeave: (e) => {
|
|
8880
|
+
e.currentTarget.style.backgroundColor = '#FF9814';
|
|
8881
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
8882
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(255, 152, 20, 0.3)';
|
|
8883
|
+
}, children: [jsx("span", { style: { color: '#000000', display: 'flex', alignItems: 'center' }, children: jsx(WalletIcon, {}) }), jsx("span", { style: { color: '#000000', fontWeight: '500', fontSize: '14px' }, children: buttonText })] }));
|
|
8884
|
+
}
|
|
8848
8885
|
};
|
|
8849
8886
|
// Group wallets by chain
|
|
8850
8887
|
availableWallets.reduce((acc, wallet) => {
|
|
@@ -8863,7 +8900,9 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8863
8900
|
.tiwiflix-scrollbar-hide::-webkit-scrollbar {
|
|
8864
8901
|
display: none;
|
|
8865
8902
|
}
|
|
8866
|
-
` }), renderButton(), jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition
|
|
8903
|
+
` }), renderButton(), jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition,
|
|
8904
|
+
// Add a Switch Wallet button to allow explicit wallet switching
|
|
8905
|
+
onSwitchWallet: () => handleOpenModal(true) }), jsx(ActivityModal, { isOpen: showActivityModal, onClose: () => setShowActivityModal(false), transactions: txs, loading: txsLoading, error: txsError, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsx(SwapModal, { isOpen: showSwapModal && account?.chainType !== 'ton', onClose: () => setShowSwapModal(false), colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsx(SendModal, { isOpen: showSendModal, onClose: () => setShowSendModal(false), balance: balance, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onSend: async () => {
|
|
8867
8906
|
alert('Send functionality coming soon');
|
|
8868
8907
|
setShowSendModal(false);
|
|
8869
8908
|
} }), jsx(TWCBalanceModal, { isOpen: showTWCBalanceModal, onClose: () => setShowTWCBalanceModal(false), twcBalance: twcBalance, usdValue: usdValue, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onBuyTWC: () => {
|
package/dist/index.js
CHANGED
|
@@ -2346,6 +2346,11 @@ class WalletConnector {
|
|
|
2346
2346
|
...savedState,
|
|
2347
2347
|
error: null, // Don't restore errors
|
|
2348
2348
|
};
|
|
2349
|
+
// PATCH: Prevent invalid connected state
|
|
2350
|
+
if (this.state.status === exports.ConnectionStatus.CONNECTED && !this.state.account) {
|
|
2351
|
+
this.state.status = exports.ConnectionStatus.DISCONNECTED;
|
|
2352
|
+
this.state.wallet = null;
|
|
2353
|
+
}
|
|
2349
2354
|
}
|
|
2350
2355
|
this.eventEmitter = new EventEmitter$1();
|
|
2351
2356
|
// Initialize advanced SDK management
|
|
@@ -6462,7 +6467,7 @@ const BaseModal = ({ isOpen, onClose, title, children, modalPosition = 'bottom',
|
|
|
6462
6467
|
return modalContent;
|
|
6463
6468
|
};
|
|
6464
6469
|
|
|
6465
|
-
const AccountDetailsModal = ({ isOpen, onClose, account, onDisconnect, onCopyAddress, onOpenSwap, onOpenSend, onOpenActivity, balance, balanceLoading, twcBalance, usdValue, nftCount = 0, nftLoading = false, tonBalance = null, tonUsdValue = null, walletIcon, colors, isDarkMode, modalPosition = 'bottom', }) => {
|
|
6470
|
+
const AccountDetailsModal = ({ isOpen, onClose, account, onDisconnect, onCopyAddress, onOpenSwap, onOpenSend, onOpenActivity, balance, balanceLoading, twcBalance, usdValue, nftCount = 0, nftLoading = false, tonBalance = null, tonUsdValue = null, walletIcon, colors, isDarkMode, modalPosition = 'bottom', onSwitchWallet, }) => {
|
|
6466
6471
|
// State for TWC price - hooks must be called before any conditional returns
|
|
6467
6472
|
const [twcPrice, setTwcPrice] = React.useState(null);
|
|
6468
6473
|
const [priceLoading, setPriceLoading] = React.useState(false);
|
|
@@ -7504,7 +7509,19 @@ const defaultStyles = {
|
|
|
7504
7509
|
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
7505
7510
|
boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
|
|
7506
7511
|
}};
|
|
7507
|
-
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance, }) => {
|
|
7512
|
+
const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
|
|
7513
|
+
// Provide a default fetchBalance if not passed
|
|
7514
|
+
const fetchBalance = fetchBalanceProp || (async (account) => {
|
|
7515
|
+
// Default: return zero balance with symbol based on chain
|
|
7516
|
+
let symbol = 'TWC';
|
|
7517
|
+
if (account?.chainType === 'ton')
|
|
7518
|
+
symbol = 'TON';
|
|
7519
|
+
if (account?.chainType === 'solana')
|
|
7520
|
+
symbol = 'SOL';
|
|
7521
|
+
if (account?.chainType === 'tron')
|
|
7522
|
+
symbol = 'TRX';
|
|
7523
|
+
return { amount: '0', symbol };
|
|
7524
|
+
});
|
|
7508
7525
|
// Detect dark mode
|
|
7509
7526
|
const [isDarkMode, setIsDarkMode] = React.useState(false);
|
|
7510
7527
|
React.useEffect(() => {
|
|
@@ -8049,6 +8066,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8049
8066
|
});
|
|
8050
8067
|
}
|
|
8051
8068
|
// Subscribe to events
|
|
8069
|
+
// Prevent repeated onConnect calls for the same account
|
|
8070
|
+
const lastOnConnectAddress = React.useRef(null);
|
|
8052
8071
|
const unsubscribeAccount = connector.on(exports.WalletEvent.ACCOUNT_CHANGED, async (acc) => {
|
|
8053
8072
|
setAccount(acc);
|
|
8054
8073
|
// Don't set isInitializing to false yet - wait for balance to load
|
|
@@ -8061,8 +8080,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8061
8080
|
}
|
|
8062
8081
|
}
|
|
8063
8082
|
if (acc && acc.chainType === 'ton') {
|
|
8064
|
-
|
|
8065
|
-
setTwcBalance('0'); // TON wallets don't have TWC
|
|
8083
|
+
setTwcBalance('0');
|
|
8066
8084
|
try {
|
|
8067
8085
|
await Promise.all([
|
|
8068
8086
|
fetchTONBalance(acc),
|
|
@@ -8086,18 +8104,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8086
8104
|
}
|
|
8087
8105
|
}
|
|
8088
8106
|
else if (acc) {
|
|
8089
|
-
// No fetchBalance, check for TWC balance
|
|
8090
8107
|
const state = connector.getState();
|
|
8091
8108
|
if (state.twcBalance && state.twcBalance !== '0' && state.twcBalance !== '0.00') {
|
|
8092
8109
|
setTwcBalance(state.twcBalance);
|
|
8093
8110
|
setUsdValueStable(state.usdValue ?? null);
|
|
8094
|
-
// Save to cache
|
|
8095
8111
|
if (acc.address) {
|
|
8096
8112
|
saveTWCBalanceToCache(acc.address, state.twcBalance, state.usdValue ?? null);
|
|
8097
8113
|
}
|
|
8098
8114
|
}
|
|
8099
8115
|
else if (acc.address) {
|
|
8100
|
-
// Try to load from cache as fallback
|
|
8101
8116
|
const cached = loadTWCBalanceFromCache(acc.address);
|
|
8102
8117
|
if (cached?.balance) {
|
|
8103
8118
|
setTwcBalance(cached.balance);
|
|
@@ -8110,7 +8125,10 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8110
8125
|
setIsInitializing(false);
|
|
8111
8126
|
}
|
|
8112
8127
|
if (acc && onConnect) {
|
|
8113
|
-
|
|
8128
|
+
if (lastOnConnectAddress.current !== acc.address) {
|
|
8129
|
+
onConnect(acc);
|
|
8130
|
+
lastOnConnectAddress.current = acc.address;
|
|
8131
|
+
}
|
|
8114
8132
|
}
|
|
8115
8133
|
});
|
|
8116
8134
|
const unsubscribeStatus = connector.on(exports.WalletEvent.STATUS_CHANGED, (newStatus) => {
|
|
@@ -8505,6 +8523,12 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8505
8523
|
setIsConnecting(false);
|
|
8506
8524
|
}
|
|
8507
8525
|
catch (err) {
|
|
8526
|
+
// Always clear connection state on error
|
|
8527
|
+
setAccount(null);
|
|
8528
|
+
setStatus(exports.ConnectionStatus.DISCONNECTED);
|
|
8529
|
+
setIsInitializing(false);
|
|
8530
|
+
setIsConnecting(false);
|
|
8531
|
+
setShowModal(false);
|
|
8508
8532
|
// Close modal if the user explicitly cancelled the connection
|
|
8509
8533
|
const message = err instanceof Error ? err.message : String(err);
|
|
8510
8534
|
const isUserCancellation = message.toLowerCase().includes('cancelled') ||
|
|
@@ -8515,22 +8539,11 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8515
8539
|
message.toLowerCase().includes('rejected') ||
|
|
8516
8540
|
message.toLowerCase().includes('modal closed by user') ||
|
|
8517
8541
|
message.toLowerCase().includes('connection cancelled by user');
|
|
8518
|
-
if (isUserCancellation) {
|
|
8519
|
-
setShowModal(false);
|
|
8520
|
-
// Reset connecting state and verify actual connection status
|
|
8521
|
-
const actualAccount = await connector.getAccount();
|
|
8522
|
-
if (!actualAccount) {
|
|
8523
|
-
setAccount(null);
|
|
8524
|
-
}
|
|
8525
|
-
}
|
|
8526
|
-
else if (isTonWallet) {
|
|
8542
|
+
if (!isUserCancellation && isTonWallet) {
|
|
8527
8543
|
// For TON, only reopen the modal on non-cancellation errors
|
|
8528
8544
|
setShowModal(true);
|
|
8529
8545
|
}
|
|
8530
8546
|
}
|
|
8531
|
-
finally {
|
|
8532
|
-
setIsConnecting(false);
|
|
8533
|
-
}
|
|
8534
8547
|
}, [connector, fetchBalance, loadBalance]);
|
|
8535
8548
|
const handleDisconnect = React.useCallback(async () => {
|
|
8536
8549
|
try {
|
|
@@ -8594,25 +8607,46 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8594
8607
|
setError('Failed to switch network. Please switch manually to BSC in your wallet.');
|
|
8595
8608
|
}
|
|
8596
8609
|
}, [connector]);
|
|
8597
|
-
|
|
8610
|
+
// Only open wallet selection modal if not connected, or if explicitly switching
|
|
8611
|
+
const handleOpenModal = React.useCallback((force = false) => {
|
|
8612
|
+
// If already connected and not explicitly switching, do nothing
|
|
8613
|
+
const state = connector.getState();
|
|
8614
|
+
if (!force && account && state.status === 'connected') {
|
|
8615
|
+
return;
|
|
8616
|
+
}
|
|
8598
8617
|
// Show ALL wallets - use cached wallets to prevent re-renders
|
|
8599
8618
|
if (!walletsRef.current) {
|
|
8600
8619
|
walletsRef.current = connector.getAllWallets();
|
|
8601
8620
|
}
|
|
8602
8621
|
setAvailableWallets(walletsRef.current);
|
|
8603
8622
|
setShowModal(true);
|
|
8604
|
-
}, [connector]);
|
|
8623
|
+
}, [connector, account]);
|
|
8605
8624
|
// Render button based on connection status
|
|
8606
8625
|
const renderButton = () => {
|
|
8607
8626
|
// Check if we're waiting for connection OR waiting for balance to load
|
|
8608
8627
|
// Show loading if: initializing, connecting, OR (account exists but balance hasn't loaded/resolved yet)
|
|
8609
|
-
//
|
|
8610
|
-
|
|
8628
|
+
// For TON: treat as resolved after fetch completes (even if 0). For others: treat zero/empty as resolved.
|
|
8629
|
+
(balance.amount && balance.amount !== '0' && balance.amount !== '0.00' && balance.amount !== '' && balance.amount !== 'Loading...') ||
|
|
8611
8630
|
(twcBalance && twcBalance !== '0' && twcBalance !== '0.00' && twcBalance !== '' && twcBalance !== 'Loading...');
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8631
|
+
let isBalanceResolved;
|
|
8632
|
+
if (account?.chainType === 'ton') {
|
|
8633
|
+
// For TON, resolved if not loading or initializing
|
|
8634
|
+
isBalanceResolved = !balanceLoading && !isInitializing;
|
|
8635
|
+
}
|
|
8636
|
+
else {
|
|
8637
|
+
// For EVM, Solana, Tron: resolved if not loading (even if balance is zero)
|
|
8638
|
+
isBalanceResolved = !balanceLoading && !isInitializing;
|
|
8639
|
+
}
|
|
8615
8640
|
const waitingForBalance = account && !isBalanceResolved;
|
|
8641
|
+
// Patch: If account is null and status is disconnected, always stop initializing/loading
|
|
8642
|
+
if (!account && status === exports.ConnectionStatus.DISCONNECTED && (isInitializing || isConnecting || balanceLoading)) {
|
|
8643
|
+
if (isInitializing)
|
|
8644
|
+
setIsInitializing(false);
|
|
8645
|
+
if (isConnecting)
|
|
8646
|
+
setIsConnecting(false);
|
|
8647
|
+
if (balanceLoading)
|
|
8648
|
+
setBalanceLoading(false);
|
|
8649
|
+
}
|
|
8616
8650
|
const isCheckingConnection = isInitializing || waitingForBalance || ((status === exports.ConnectionStatus.CONNECTING || isConnecting) && !account);
|
|
8617
8651
|
const isActuallyConnecting = (status === exports.ConnectionStatus.CONNECTING || isConnecting) && account && isBalanceResolved;
|
|
8618
8652
|
// Check connection state
|
|
@@ -8822,31 +8856,34 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8822
8856
|
}
|
|
8823
8857
|
// Wallet icon SVG component
|
|
8824
8858
|
const WalletIcon = () => (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block' }, children: [jsxRuntime.jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }), jsxRuntime.jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })] }));
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8859
|
+
// Only show connect button if not connected
|
|
8860
|
+
if (!account || status !== exports.ConnectionStatus.CONNECTED) {
|
|
8861
|
+
return (jsxRuntime.jsxs("button", { onClick: () => handleOpenModal(), style: {
|
|
8862
|
+
display: 'flex',
|
|
8863
|
+
alignItems: 'center',
|
|
8864
|
+
gap: '10px',
|
|
8865
|
+
padding: '12px 12px',
|
|
8866
|
+
borderRadius: '12px',
|
|
8867
|
+
border: 'none',
|
|
8868
|
+
backgroundColor: '#FF9814', // Warm golden-orange
|
|
8869
|
+
color: '#000000', // Black text
|
|
8870
|
+
fontWeight: '700',
|
|
8871
|
+
fontSize: '15px',
|
|
8872
|
+
cursor: 'pointer',
|
|
8873
|
+
transition: 'all 0.15s ease',
|
|
8874
|
+
fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
8875
|
+
boxShadow: '0 2px 8px rgba(255, 152, 20, 0.3)',
|
|
8876
|
+
...style,
|
|
8877
|
+
}, className: className, onMouseEnter: (e) => {
|
|
8878
|
+
e.currentTarget.style.backgroundColor = '#E8870F';
|
|
8879
|
+
e.currentTarget.style.transform = 'translateY(-1px)';
|
|
8880
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(255, 152, 20, 0.4)';
|
|
8881
|
+
}, onMouseLeave: (e) => {
|
|
8882
|
+
e.currentTarget.style.backgroundColor = '#FF9814';
|
|
8883
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
8884
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(255, 152, 20, 0.3)';
|
|
8885
|
+
}, children: [jsxRuntime.jsx("span", { style: { color: '#000000', display: 'flex', alignItems: 'center' }, children: jsxRuntime.jsx(WalletIcon, {}) }), jsxRuntime.jsx("span", { style: { color: '#000000', fontWeight: '500', fontSize: '14px' }, children: buttonText })] }));
|
|
8886
|
+
}
|
|
8850
8887
|
};
|
|
8851
8888
|
// Group wallets by chain
|
|
8852
8889
|
availableWallets.reduce((acc, wallet) => {
|
|
@@ -8865,7 +8902,9 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
|
|
|
8865
8902
|
.tiwiflix-scrollbar-hide::-webkit-scrollbar {
|
|
8866
8903
|
display: none;
|
|
8867
8904
|
}
|
|
8868
|
-
` }), renderButton(), jsxRuntime.jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition
|
|
8905
|
+
` }), renderButton(), jsxRuntime.jsx(AccountDetailsModal, { isOpen: showDetailsModal, onClose: () => setShowDetailsModal(false), account: account, onDisconnect: handleDisconnect, onCopyAddress: handleCopyAddress, onOpenSwap: () => setShowSwapModal(true), onOpenSend: () => setShowSendModal(true), onOpenActivity: () => setShowActivityModal(true), balance: balance, balanceLoading: balanceLoading, twcBalance: twcBalance, usdValue: usdValue, nftCount: nftCount, nftLoading: nftLoading, tonBalance: balance.amount || tonBalance, tonUsdValue: balance.usdValue ?? tonUsdValue, walletIcon: walletIcon, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition,
|
|
8906
|
+
// Add a Switch Wallet button to allow explicit wallet switching
|
|
8907
|
+
onSwitchWallet: () => handleOpenModal(true) }), jsxRuntime.jsx(ActivityModal, { isOpen: showActivityModal, onClose: () => setShowActivityModal(false), transactions: txs, loading: txsLoading, error: txsError, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsxRuntime.jsx(SwapModal, { isOpen: showSwapModal && account?.chainType !== 'ton', onClose: () => setShowSwapModal(false), colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition }), jsxRuntime.jsx(SendModal, { isOpen: showSendModal, onClose: () => setShowSendModal(false), balance: balance, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onSend: async () => {
|
|
8869
8908
|
alert('Send functionality coming soon');
|
|
8870
8909
|
setShowSendModal(false);
|
|
8871
8910
|
} }), jsxRuntime.jsx(TWCBalanceModal, { isOpen: showTWCBalanceModal, onClose: () => setShowTWCBalanceModal(false), twcBalance: twcBalance, usdValue: usdValue, colors: colors, isDarkMode: isDarkMode, modalPosition: modalPosition, onBuyTWC: () => {
|
package/package.json
CHANGED