Skip to content

Commit 75ffa73

Browse files
authored
Fix vault chain selection (#1123)
Keep the vault list aligned with the selected chain filter and\nmake chain switching behave consistently across the page.\n\n- apply selected-chain filtering to holdings in both V2 and V3\n vault filters so other-chain rows do not leak into the list\n- reuse a single-chain selection helper for the top selector and\n row chips so switching chains cannot drift into mixed states\n- add focused tests for selected-chain matching and single-chain\n selection behavior
1 parent f7b4d54 commit 75ffa73

File tree

8 files changed

+53
-9
lines changed

8 files changed

+53
-9
lines changed

src/components/pages/vaults/components/filters/VaultsFiltersBar.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
TransitionChild
99
} from '@headlessui/react'
1010
import { usePlausible } from '@hooks/usePlausible'
11+
import { resolveNextSingleChainSelection } from '@pages/vaults/utils/chainSelection'
1112
import { DEFAULT_MIN_TVL } from '@pages/vaults/utils/constants'
1213
import { getChainDescription } from '@pages/vaults/utils/vaultTagCopy'
1314
import type { TMultiSelectOptionProps } from '@shared/components/MultiSelectDropdown'
@@ -197,11 +198,7 @@ export function VaultsFiltersBar({
197198
}
198199

199200
const handleChainToggle = (chainId: number): void => {
200-
if (chains.selected && chains.selected.length === 1 && chains.selected[0] === chainId) {
201-
chains.onChange(null)
202-
return
203-
}
204-
chains.onChange([chainId])
201+
chains.onChange(resolveNextSingleChainSelection(chains.selected, chainId))
205202
}
206203

207204
const handleApplyAdditionalChains = (ids: number[]): void => {

src/components/pages/vaults/hooks/useVaultsPageModel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
getCommonBlockingKeys,
2121
shouldShowComboBlockingAction
2222
} from '@pages/vaults/utils/blockingFilterInsights'
23+
import { resolveNextSingleChainSelection } from '@pages/vaults/utils/chainSelection'
2324
import {
2425
AGGRESSIVENESS_OPTIONS,
2526
AVAILABLE_TOGGLE_VALUE,
@@ -810,7 +811,7 @@ export function useVaultsPageModel(): TVaultsPageModel {
810811
)
811812
const handleToggleChain = useCallback(
812813
(chainId: number): void => {
813-
handleChainsChange(toggleInArray(displayedChains ?? null, chainId))
814+
handleChainsChange(resolveNextSingleChainSelection(displayedChains, chainId))
814815
},
815816
[displayedChains, handleChainsChange]
816817
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { resolveNextSingleChainSelection } from './chainSelection'
3+
4+
describe('resolveNextSingleChainSelection', () => {
5+
it('selects the requested chain when nothing is selected', () => {
6+
expect(resolveNextSingleChainSelection(null, 1)).toEqual([1])
7+
expect(resolveNextSingleChainSelection([], 10)).toEqual([10])
8+
})
9+
10+
it('switches directly to the requested chain', () => {
11+
expect(resolveNextSingleChainSelection([1], 10)).toEqual([10])
12+
expect(resolveNextSingleChainSelection([1, 10], 42161)).toEqual([42161])
13+
})
14+
15+
it('clears the filter when reselecting the only active chain', () => {
16+
expect(resolveNextSingleChainSelection([1], 1)).toBeNull()
17+
})
18+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function resolveNextSingleChainSelection(
2+
currentChains: number[] | null | undefined,
3+
chainId: number
4+
): number[] | null {
5+
if (currentChains && currentChains.length === 1 && currentChains[0] === chainId) {
6+
return null
7+
}
8+
9+
return [chainId]
10+
}

src/components/shared/hooks/useV2VaultFilter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
createCheckHasHoldings,
3333
getVaultKey,
3434
isV3Vault,
35+
matchesSelectedChains,
3536
type TVaultFlags
3637
} from './useVaultFilterUtils'
3738

@@ -307,7 +308,7 @@ export function useV2VaultFilter(
307308
return
308309
}
309310

310-
if (!hasUserHoldings && hasChainFilter && !chains?.includes(getVaultChainID(vault))) {
311+
if (hasChainFilter && !matchesSelectedChains(getVaultChainID(vault), chains)) {
311312
return
312313
}
313314

src/components/shared/hooks/useV3VaultFilter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
createCheckHasHoldings,
3333
getVaultKey,
3434
isV3Vault,
35+
matchesSelectedChains,
3536
type TVaultFlags
3637
} from './useVaultFilterUtils'
3738

@@ -320,7 +321,7 @@ export function useV3VaultFilter(
320321
return
321322
}
322323

323-
if (!hasUserHoldings && hasChainFilter && !chains?.includes(getVaultChainID(vault))) {
324+
if (hasChainFilter && !matchesSelectedChains(getVaultChainID(vault), chains)) {
324325
return
325326
}
326327

src/components/shared/hooks/useVaultFilterUtils.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from 'vitest'
2-
import { getVaultHoldingsUsdValue } from './useVaultFilterUtils'
2+
import { getVaultHoldingsUsdValue, matchesSelectedChains } from './useVaultFilterUtils'
33

44
const VAULT_ADDRESS = '0x8589462548984c5C0f2C0140FB276351B5a77fe1'
55
const ASSET_ADDRESS = '0x0000000000000000000000000000000000000002'
@@ -69,3 +69,15 @@ describe('getVaultHoldingsUsdValue', () => {
6969
expect(value).toBeCloseTo(2.1, 8)
7070
})
7171
})
72+
73+
describe('matchesSelectedChains', () => {
74+
it('treats null or empty selections as all chains', () => {
75+
expect(matchesSelectedChains(1, null)).toBe(true)
76+
expect(matchesSelectedChains(1, [])).toBe(true)
77+
})
78+
79+
it('only matches vaults from the selected chains', () => {
80+
expect(matchesSelectedChains(1, [1])).toBe(true)
81+
expect(matchesSelectedChains(10, [1])).toBe(false)
82+
})
83+
})

src/components/shared/hooks/useVaultFilterUtils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ export function matchesSearch(vault: TVaultLike, search: string): boolean {
241241
}
242242
}
243243

244+
export function matchesSelectedChains(chainID: number, chains: number[] | null | undefined): boolean {
245+
return !chains?.length || chains.includes(chainID)
246+
}
247+
244248
export function isV3Vault(vault: TVaultLike, isAllocatorOverride: boolean): boolean {
245249
const version = getVaultVersion(vault)
246250
return version.startsWith('3') || version.startsWith('~3') || isAllocatorOverride

0 commit comments

Comments
 (0)