| … | … | @@ -1625,14 +1625,17 @@ function updateWalletView() { |
| 1625 | 1625 | } |
| 1626 | 1626 | |
| 1627 | 1627 | // Load wallet addresses into the selector dropdown |
| 1628 | | // Flag to prevent onchange cascade when programmatically updating selector |
| 1629 | | let isUpdatingAddressSelector = false |
| 1628 | // Counter to prevent onchange cascade when programmatically updating selector |
| 1629 | // Using a counter instead of boolean to handle concurrent/nested calls |
| 1630 | let addressSelectorUpdateCount = 0 |
| 1630 | 1631 | |
| 1631 | 1632 | async function loadWalletAddressSelector() { |
| 1632 | 1633 | const select = document.getElementById('wallet-address-select') |
| 1633 | 1634 | |
| 1634 | | // Set flag to prevent onchange from firing during programmatic update |
| 1635 | | isUpdatingAddressSelector = true |
| 1635 | // Increment counter to prevent onchange from firing during programmatic update |
| 1636 | addressSelectorUpdateCount++ |
| 1637 | const myUpdateId = addressSelectorUpdateCount |
| 1638 | |
| 1636 | 1639 | select.innerHTML = '<option value="">Loading...</option>' |
| 1637 | 1640 | |
| 1638 | 1641 | try { |
| … | … | @@ -1641,15 +1644,16 @@ async function loadWalletAddressSelector() { |
| 1641 | 1644 | const res = await authFetch(`/api/addresses/${selectedNetwork}-${addressChain}`) |
| 1642 | 1645 | const data = await res.json() |
| 1643 | 1646 | |
| 1647 | // Check if we're still the latest update (another call may have started) |
| 1648 | if (myUpdateId !== addressSelectorUpdateCount) return |
| 1649 | |
| 1644 | 1650 | if (data.error) { |
| 1645 | 1651 | select.innerHTML = '<option value="">Error loading addresses</option>' |
| 1646 | | isUpdatingAddressSelector = false |
| 1647 | 1652 | return |
| 1648 | 1653 | } |
| 1649 | 1654 | |
| 1650 | 1655 | if (data.addresses.length === 0) { |
| 1651 | 1656 | select.innerHTML = '<option value="">No addresses yet</option>' |
| 1652 | | isUpdatingAddressSelector = false |
| 1653 | 1657 | return |
| 1654 | 1658 | } |
| 1655 | 1659 | |
| … | … | @@ -1664,22 +1668,30 @@ async function loadWalletAddressSelector() { |
| 1664 | 1668 | html += `<option value="${addr.index}" ${addr.isCurrent ? 'selected' : ''}>${displayText}${currentMarker}</option>` |
| 1665 | 1669 | } |
| 1666 | 1670 | |
| 1671 | // Store current value before update to detect programmatic vs user changes |
| 1672 | const previousValue = select.value |
| 1673 | |
| 1667 | 1674 | select.innerHTML = html |
| 1675 | |
| 1676 | // If the selected value changed due to our update (not user), mark as programmatic |
| 1677 | if (select.value !== previousValue) { |
| 1678 | select.dataset.programmaticChange = 'true' |
| 1679 | } |
| 1668 | 1680 | } catch (err) { |
| 1669 | 1681 | console.error('Load address selector error:', err) |
| 1670 | 1682 | select.innerHTML = '<option value="">Failed to load</option>' |
| 1671 | 1683 | } |
| 1672 | | |
| 1673 | | // Clear flag after a tick to allow DOM to settle |
| 1674 | | setTimeout(() => { isUpdatingAddressSelector = false }, 0) |
| 1675 | 1684 | } |
| 1676 | 1685 | |
| 1677 | 1686 | // Handle wallet address selector change |
| 1678 | 1687 | async function onWalletAddressChange() { |
| 1679 | | // Ignore programmatic updates to prevent cascade |
| 1680 | | if (isUpdatingAddressSelector) return |
| 1681 | | |
| 1682 | 1688 | const select = document.getElementById('wallet-address-select') |
| 1689 | |
| 1690 | // Ignore programmatic updates to prevent cascade |
| 1691 | if (select.dataset.programmaticChange === 'true') { |
| 1692 | delete select.dataset.programmaticChange |
| 1693 | return |
| 1694 | } |
| 1683 | 1695 | const selectedIndex = parseInt(select.value) |
| 1684 | 1696 | |
| 1685 | 1697 | if (isNaN(selectedIndex)) return |
| … | … | @@ -1700,6 +1712,12 @@ async function onWalletAddressChange() { |
| 1700 | 1712 | |
| 1701 | 1713 | showSuccess('Wallet address changed!') |
| 1702 | 1714 | |
| 1715 | // Update star markers in the existing options (no reload needed) |
| 1716 | Array.from(select.options).forEach(option => { |
| 1717 | const text = option.textContent.replace(' ⭐', '') |
| 1718 | option.textContent = option.value === String(selectedIndex) ? text + ' ⭐' : text |
| 1719 | }) |
| 1720 | |
| 1703 | 1721 | // Reload balance - use unified view for Ethereum, standard for others |
| 1704 | 1722 | if (selectedChain === 'ethereum') { |
| 1705 | 1723 | await loadEthereumBalances() |
| … | … | @@ -1709,8 +1727,7 @@ async function onWalletAddressChange() { |
| 1709 | 1727 | await loadCurrentQRCode() |
| 1710 | 1728 | await loadTransactions() |
| 1711 | 1729 | |
| 1712 | | // Reload the selector to update the star marker |
| 1713 | | await loadWalletAddressSelector() |
| 1730 | // NOTE: Don't reload selector here - causes cascade. Star markers updated above. |
| 1714 | 1731 | } catch (err) { |
| 1715 | 1732 | showError(`Failed to change address: ${err.message}`) |
| 1716 | 1733 | } |