diff --git a/src/components/Overviews.vue b/src/components/Overviews.vue index 632b6d8..64d05e0 100644 --- a/src/components/Overviews.vue +++ b/src/components/Overviews.vue @@ -1,31 +1,19 @@ diff --git a/src/components/RecentBlocks.vue b/src/components/RecentBlocks.vue index 6e91402..c08f662 100644 --- a/src/components/RecentBlocks.vue +++ b/src/components/RecentBlocks.vue @@ -76,6 +76,9 @@ export default { this.fetchBlocks() this.pollData() }, + unmounted() { + clearInterval(this.polling) + }, methods: { async fetchBlocks() { const limit = this.isTestnet ? 5 : 7 diff --git a/src/components/TransactionsTable.vue b/src/components/TransactionsTable.vue index c1a47eb..023e4b7 100644 --- a/src/components/TransactionsTable.vue +++ b/src/components/TransactionsTable.vue @@ -118,7 +118,7 @@ export default { addr, { limit: this.limit, - page: this.page, + page: this.page || 1, sort: sortQuery } ) diff --git a/src/components/index/CreateModal.vue b/src/components/index/CreateModal.vue index 08528cf..aa59473 100644 --- a/src/components/index/CreateModal.vue +++ b/src/components/index/CreateModal.vue @@ -213,6 +213,7 @@ export default { }, this.sessionPassword) await this.$store.dispatch('loadWallets', this.sessionPassword) + this.$store.dispatch('refresh') this.$emit('created') this.reset() this.close() diff --git a/src/components/index/RestoreModal.vue b/src/components/index/RestoreModal.vue index cc7342d..96a04bb 100644 --- a/src/components/index/RestoreModal.vue +++ b/src/components/index/RestoreModal.vue @@ -177,6 +177,7 @@ export default { }, this.sessionPassword) await this.$store.dispatch('loadWallets', this.sessionPassword) + this.$store.dispatch('refresh') this.$emit('imported') this.reset() this.close() diff --git a/src/components/stakes/CreateStakeModal.vue b/src/components/stakes/CreateStakeModal.vue index 273f114..60ea2c7 100644 --- a/src/components/stakes/CreateStakeModal.vue +++ b/src/components/stakes/CreateStakeModal.vue @@ -174,9 +174,7 @@ export default { stakeType: '', completedTx: null, - submitError: '', - - vars: null + submitError: '' } }, validations() { @@ -189,8 +187,9 @@ export default { } }, computed: { - ...mapState(['address', 'balance', 'nextNonce']), + ...mapState(['address', 'balance', 'nextNonce', 'vars']), canAffordStake() { + if (!this.vars) return false return this.balance >= this.vars.host_stake_amount }, canCreate() { @@ -200,15 +199,19 @@ export default { return (this.balance - this.stakeAmount) / 1e6 }, shortHostStakeAmount() { + if (!this.vars) return '' return this.formatShortAmount(this.vars.host_stake_amount) }, shortGatewayStakeAmount() { + if (!this.vars) return '' return this.formatShortAmount(this.vars.gateway_stake_amount) }, shortStargateStakeAmount() { + if (!this.vars) return '' return this.formatShortAmount(this.vars.stargate_stake_amount) }, stakeAmount() { + if (!this.vars) return 0 switch (this.stakeType) { case 'host': return this.vars.host_stake_amount @@ -290,10 +293,8 @@ export default { goto(step) { this.step = step }, - async updateVars() { - this.vars = await xe.vars(import.meta.env.VITE_BLOCKCHAIN_API_URL) - }, isStakeAffordable(type) { + if (!this.vars) return false return this.balance - this.vars[type + '_stake_amount'] > 0 }, reset() { @@ -313,9 +314,6 @@ export default { } } }, - mounted() { - this.updateVars() - }, setup() { return { v$: useVuelidate() @@ -326,7 +324,7 @@ export default { if (v === oldv) return if (v) { this.$store.dispatch('refresh') - this.updateVars() + this.$store.dispatch('refreshVars') this.stakeType = 'host' } } diff --git a/src/components/stakes/ReleaseStakeModal.vue b/src/components/stakes/ReleaseStakeModal.vue index 6eec218..68e4583 100644 --- a/src/components/stakes/ReleaseStakeModal.vue +++ b/src/components/stakes/ReleaseStakeModal.vue @@ -242,9 +242,7 @@ export default { confirmPhrase: '', completedTx: null, - submitError: '', - - vars: null + submitError: '' } }, validations() { @@ -260,7 +258,7 @@ export default { } }, computed: { - ...mapState(['address', 'nextNonce']), + ...mapState(['address', 'nextNonce', 'vars']), canRelease() { if (this.isUnlocked) return !this.v$.password.$invalid else return !this.v$.$invalid @@ -273,11 +271,11 @@ export default { return this.unlocksAt < this.currentTime }, releaseFeeParsed() { - if (this.isUnlocked) return 0 + if (this.isUnlocked || !this.vars) return 0 else return this.stake.amount * this.vars.stake_express_release_fee / 1e6 }, releasePc() { - if (this.isUnlocked) return 0 + if (this.isUnlocked || !this.vars) return 0 else return this.vars.stake_express_release_fee * 100 }, returnAmountParsed() { @@ -335,9 +333,6 @@ export default { return false } }, - async updateVars() { - this.vars = await xe.vars(import.meta.env.VITE_BLOCKCHAIN_API_URL) - }, goto(step) { this.step = step }, @@ -407,9 +402,6 @@ export default { } } }, - mounted() { - this.updateVars() - }, setup() { return { v$: useVuelidate() @@ -420,7 +412,7 @@ export default { if (v === oldv) return if (v) { this.$store.dispatch('refresh') - this.updateVars() + this.$store.dispatch('refreshVars') } }, stake() { diff --git a/src/main.js b/src/main.js index a0cce73..2c319e3 100644 --- a/src/main.js +++ b/src/main.js @@ -35,6 +35,7 @@ const init = async () => { if (store.state.address) store.dispatch('refresh') store.dispatch('refreshIndexConfig') + store.dispatch('refreshVars') setInterval(() => store.dispatch('backgroundRefresh'), WALLET_REFRESH_INTERVAL) } diff --git a/src/store.js b/src/store.js index f938645..54aa765 100644 --- a/src/store.js +++ b/src/store.js @@ -58,6 +58,7 @@ const init = async () => { }, bridgeOnline: false, + vars: null, // Multi-wallet support wallets: [], @@ -93,6 +94,9 @@ const init = async () => { setBridgeOnline(state, online) { state.bridgeOnline = online }, + setVars(state, vars) { + state.vars = vars + }, setNextNonce(state, nextNonce) { state.nextNonce = nextNonce }, @@ -183,6 +187,10 @@ const init = async () => { console.error('Refresh failed:', err) } }, + async refreshVars({ commit, state }) { + const vars = await xe.vars(state.config.blockchain.baseURL) + commit('setVars', vars) + }, async refreshIndexConfig({ commit, state }) { const res = await fetch(`${state.config.index.baseURL}/v2/config`) if (!res.ok) { @@ -262,6 +270,15 @@ const init = async () => { if (activeWallet) { commit('setActiveWalletId', activeWallet.id) commit('setAddress', activeWallet.address) + // Reset balance state so stale values from a previous wallet don't linger + const cachedBalance = state.walletBalances[activeWallet.id] + commit('setBalance', cachedBalance != null ? cachedBalance : 0) + commit('setNextNonce', 0) + if (cachedBalance != null && state.usdPerXE != null) { + commit('setUSDBalance', state.usdPerXE * (cachedBalance / 1e6)) + } else { + commit('setUSDBalance', undefined) + } await storage.setActiveWalletId(activeWallet.id) } } catch (err) { @@ -275,11 +292,12 @@ const init = async () => { const walletIds = state.wallets.map(w => w.id) commit('setWalletBalancesLoading', walletIds) - // Fetch balances in parallel + // Fetch balances in parallel (uses info, not infoWithNextNonce, + // to avoid unnecessary pending transaction requests for non-active wallets) const results = await Promise.allSettled( state.wallets.map(async (wallet) => { try { - const info = await xe.wallet.infoWithNextNonce(state.config.blockchain.baseURL, wallet.address) + const info = await xe.wallet.info(state.config.blockchain.baseURL, wallet.address) return { walletId: wallet.id, balance: info.balance } } catch (err) { console.error(`Failed to fetch balance for ${wallet.address}:`, err) diff --git a/src/views/Overview.vue b/src/views/Overview.vue index 7104d43..f7d8746 100644 --- a/src/views/Overview.vue +++ b/src/views/Overview.vue @@ -16,12 +16,11 @@

Recent transactions

-

{{error}}

- +
-
+
View all
@@ -36,26 +35,11 @@ import NewsPromo from '@/components/NewsPromo.vue' import Overviews from '@/components/Overviews.vue' import RecentBlocks from '@/components/RecentBlocks.vue' import TestnetFaucet from '@/components/Faucet.vue' -import dayjs from 'dayjs' -import { fetchTransactions } from '../utils/api' -import { mapState } from 'vuex' -import relativeTime from 'dayjs/plugin/relativeTime' - -dayjs.extend(relativeTime) - -const txCache = {} - export default { name: 'ViewOverview', title: 'Overview', data: function () { return { - transactions: [], - loading: true, - error: '', - polling: null, - overviews: [], - transactionRefreshInterval: 5000, isTestnet: import.meta.env.VITE_IS_TESTNET === 'true' } }, @@ -66,49 +50,6 @@ export default { NewsPromo, RecentBlocks, TestnetFaucet - }, - computed: mapState(['address']), - watch: { - address(newAddr) { - const cached = txCache[newAddr] - if (cached) { - this.transactions = cached.transactions - this.metadata = cached.metadata - } else { - this.transactions = [] - } - this.updateTransactions() - } - }, - mounted() { - this.initialise() - }, - unmounted() { - clearInterval(this.polling) - }, - methods: { - async initialise() { - await this.updateTransactions() - this.pollData() - }, - async updateTransactions() { - const addr = this.address - if (!addr) return - const { transactions, metadata } = await fetchTransactions(addr, { limit: 5 }) - - txCache[addr] = { transactions, metadata } - // Only update display if address hasn't changed during fetch - if (this.address === addr) { - this.transactions = transactions - this.metadata = metadata - this.loading = false - } - }, - pollData() { - this.polling = setInterval(() => { - this.updateTransactions() - }, this.transactionRefreshInterval) - } } }