Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/pages/MatrixPage.cache.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,31 @@ describe('MatrixPage — scan cache', () => {
expect(fetchSpy).toHaveBeenCalled();
});
});

it('refresh preserves user-visible chains when balances are zero', async () => {
storage.setScanCache(ADDR, { balances: {}, prices: {} });
// hiddenChains defaults to empty in storage, so all chains start visible.
globalThis.fetch = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ jsonrpc: '2.0', id: 1, result: '0x0' }), {
status: 200,
headers: { 'content-type': 'application/json' },
}),
) as unknown as typeof fetch;

const user = userEvent.setup();
renderWithProviders(routes, [`/address/${ADDR}`]);

// Ethereum (chain id 1) is visible after hydrating from cache.
expect(await screen.findByText('Ethereum Mainnet')).toBeInTheDocument();

const btn = await screen.findByRole('button', { name: /Refresh/ });
await user.click(btn);

// After a refresh with zero balances everywhere, the Ethereum column
// must still be visible — the old auto-hide pass used to remove it on
// every refresh.
await waitFor(() => {
expect(screen.getByText('Ethereum Mainnet')).toBeInTheDocument();
});
});
});
22 changes: 14 additions & 8 deletions src/state/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ export function WalletProvider({ children }: { children: ReactNode }) {
}));
}, []);

const startScan = useCallback(async (address: string) => {
const startScan = useCallback(async (address: string, opts: { autoHide?: boolean } = {}) => {
const autoHide = opts.autoHide ?? true;
setState((s) => ({ ...s, address, demo: false, scanning: true, activeChain: null, scanProgress: {} }));

// Scan chains sequentially, ordered by numeric chain ID (Ethereum first).
Expand Down Expand Up @@ -221,19 +222,24 @@ export function WalletProvider({ children }: { children: ReactNode }) {
// Persist so repeat visits don't need to re-scan all chains.
storage.setScanCache(address, { balances, prices });

// Auto-hide chains that have no tokens of value.
const autoHidden = new Set<ChainId>();
CHAINS.forEach((c) => {
if (!chainsWithValue.has(c.id)) autoHidden.add(c.id);
});
// On first connect, hide empty chains so the matrix isn't mostly blank.
// On refresh, keep whatever the user has since chosen to show or hide.
let nextHidden: Set<ChainId> | null = null;
if (autoHide) {
nextHidden = new Set<ChainId>();
CHAINS.forEach((c) => {
if (!chainsWithValue.has(c.id)) nextHidden!.add(c.id);
});
storage.setHiddenChains(nextHidden);
}

setState((s) => ({
...s,
balances,
prices,
scanning: false,
activeChain: null,
hiddenChains: autoHidden,
hiddenChains: nextHidden ?? s.hiddenChains,
lastRefreshedAt: Date.now(),
fromCache: false,
}));
Expand Down Expand Up @@ -427,7 +433,7 @@ export function WalletProvider({ children }: { children: ReactNode }) {
const refreshBalances = useCallback(async (): Promise<void> => {
const addr = loadedKeyRef.current;
if (!addr || addr === 'demo') return;
await startScan(addr);
await startScan(addr, { autoHide: false });
}, [startScan]);

const disconnect = useCallback(() => {
Expand Down
Loading