feat(ui): the same accounts on every other network, side by side
ci / gate (push) Waiting to run

An "Other networks" table under the accounts: every profile the settings
allow other than the selected one, each connected on demand and
following heads like the main table, with the account's spendable and
total balance there and the chain's state. One seed gives the same
address on every Quantus-family chain (they share coin type 189189), and
the table says so rather than pretending they are different accounts.

Run on the dev network with testnets shown: Quantus mainnet through
wss://quantus.blackbeard.observer at block 54032 and Planck at 1111122
listed beside the dev chain, both at zero for crystal_alice; a Polkadot
address in the send form refused as "a Polkadot address, not a Local dev
node address".

Closes #37

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ftBXYuba8ARhQeF74oUgW
This commit is contained in:
2026-09-16 09:26:42 +03:00
co-authored by Claude Fable 5.1
parent 9eb0a24d9a
commit 34738a8e32
2 changed files with 90 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
import type { ChainProfile } from '../api/generated/ChainProfile'
import { useBalances, useChainStatus, useChains, useSession, useSettings } from '../api/hooks'
import { formatAmount } from '../lib/format'
/**
* The same accounts on every other network the wallet knows, side by
* side. Quantus-family chains share coin type 189189, so one seed gives
* the same address on each of them; the balances differ, and a testnet's
* is not money. Each row connects its chain on demand and follows heads
* like the main table.
*/
export function NetworkOverview() {
const chains = useChains()
const settings = useSettings()
const session = useSession()
if (!chains.data || !settings.data || !session.data || session.data.locked) return null
const others = chains.data.filter(
(c) =>
c.id !== settings.data!.network && (c.kind === 'mainnet' || settings.data!.show_testnets),
)
if (others.length === 0) return null
return (
<section className="panel">
<div className="panel-head">
<h2 className="panel-title">Other networks</h2>
<span className="muted" style={{ fontSize: 12 }}>
one seed, the same addresses on every Quantus-family chain
</span>
</div>
<table className="table">
<thead>
<tr>
<th>Network</th>
<th>Address</th>
<th className="num">Spendable</th>
<th className="num">Total</th>
<th>State</th>
</tr>
</thead>
<tbody>
{others.map((c) => (
<ChainRows key={c.id} profile={c} />
))}
</tbody>
</table>
</section>
)
}
function ChainRows({ profile }: { profile: ChainProfile }) {
const status = useChainStatus(profile.id)
const balances = useBalances(profile.id, true)
const session = useSession()
const accounts = session.data?.accounts ?? []
const state = status.data?.connected
? `block ${status.data.best_number ?? '…'}`
: (status.data?.last_error ?? 'connecting…')
return (
<>
{accounts.map((a, i) => {
const b = balances.data?.find((x) => x.address === a.address)
return (
<tr key={`${profile.id}-${a.address}`} data-testid={`overview-${profile.id}`}>
<td>
{i === 0 && (
<>
{profile.display_name}
{profile.kind !== 'mainnet' && (
<>
{' '}
<span className="chip testnet">{profile.kind}</span>
</>
)}
</>
)}
</td>
<td className="mono">{a.address}</td>
<td className="num numeral">{b ? `${formatAmount(b.spendable)} ${b.symbol}` : '…'}</td>
<td className="num numeral">{b ? `${formatAmount(b.total)} ${b.symbol}` : '…'}</td>
<td className="muted" style={{ fontSize: 12 }}>
{i === 0 && state}
</td>
</tr>
)
})}
</>
)
}
+2
View File
@@ -1,6 +1,7 @@
import { useBalances, useChains, useSession, useSettings } from '../api/hooks'
import { AccountName } from '../components/AccountName'
import { ChainCaveat } from '../components/ChainCaveat'
import { NetworkOverview } from '../components/NetworkOverview'
import { PendingReversibleList } from '../components/PendingReversible'
import { formatAmount } from '../lib/format'
@@ -80,6 +81,7 @@ export function Accounts() {
{chain && profile && unlocked && (
<PendingReversibleList chain={chain} profile={profile} addresses={addresses} />
)}
<NetworkOverview />
</>
)
}