diff --git a/src/components/MarketSwitcher.tsx b/src/components/MarketSwitcher.tsx index ef291c6c33..0e5c7f0cca 100644 --- a/src/components/MarketSwitcher.tsx +++ b/src/components/MarketSwitcher.tsx @@ -19,6 +19,7 @@ import React, { useMemo, useRef, useState } from 'react'; import { ArrowUpRightIcon } from 'src/components/icons/ArrowUpRightIcon'; import { ChevronUpDownIcon } from 'src/components/icons/ChevronUpDownIcon'; import { FAVOURITE_STAR_COLOR, StarIcon } from 'src/components/icons/StarIcon'; +import { hasNoMarketResults, shouldShowLegacySection } from 'src/components/marketSwitcher.utils'; import { ShimmerText } from 'src/components/ShimmerText'; import { useRootStore } from 'src/store/root'; import { BaseNetworkConfig } from 'src/ui-config/networksConfig'; @@ -611,13 +612,23 @@ export const MarketSwitcher = ({ hideDescription }: MarketSwitcherProps) => { ); - const noResults = - pinned.length === 0 && - ethereum.length === 0 && - l2.length === 0 && - other.length === 0 && - v4Ethereum.length === 0 && - v4Other.length === 0; + // An active search reveals matching legacy markets even while the switch is off, so a searched + // market is never hidden from the person who just named it. + const showLegacySection = shouldShowLegacySection({ + showLegacy, + searchQuery, + legacyCount: legacy.length, + }); + + const noResults = hasNoMarketResults([ + pinned.length, + ethereum.length, + l2.length, + other.length, + legacy.length, + v4Ethereum.length, + v4Other.length, + ]); const renderSelectorContent = (mobile: boolean) => ( <> @@ -705,7 +716,7 @@ export const MarketSwitcher = ({ hideDescription }: MarketSwitcherProps) => { )} {/* Legacy */} - {showLegacy && + {showLegacySection && renderSection( Legacy, legacy.map((id) => renderGridItem(id, mobile)) diff --git a/src/components/__tests__/marketSwitcher.utils.test.ts b/src/components/__tests__/marketSwitcher.utils.test.ts new file mode 100644 index 0000000000..8ec7d38af0 --- /dev/null +++ b/src/components/__tests__/marketSwitcher.utils.test.ts @@ -0,0 +1,50 @@ +import { hasNoMarketResults, shouldShowLegacySection } from '../marketSwitcher.utils'; + +describe('shouldShowLegacySection', () => { + it('keeps legacy markets collapsed by default', () => { + expect(shouldShowLegacySection({ showLegacy: false, searchQuery: '', legacyCount: 3 })).toBe( + false + ); + }); + + it('shows legacy markets when the switch is on', () => { + expect(shouldShowLegacySection({ showLegacy: true, searchQuery: '', legacyCount: 3 })).toBe( + true + ); + }); + + // Regression guard for https://github.com/aave/interface/issues/3127: searching for a legacy + // market used to report "No markets found" because the match was never rendered. + it('shows a searched-for legacy market even while the switch is off', () => { + expect( + shouldShowLegacySection({ showLegacy: false, searchQuery: 'gnosis', legacyCount: 1 }) + ).toBe(true); + }); + + it('stays hidden when a search matches no legacy market', () => { + expect( + shouldShowLegacySection({ showLegacy: false, searchQuery: 'base', legacyCount: 0 }) + ).toBe(false); + }); + + it('treats a whitespace-only query as no search', () => { + expect(shouldShowLegacySection({ showLegacy: false, searchQuery: ' ', legacyCount: 3 })).toBe( + false + ); + }); +}); + +describe('hasNoMarketResults', () => { + it('reports no results when every group is empty', () => { + expect(hasNoMarketResults([0, 0, 0, 0, 0, 0, 0])).toBe(true); + }); + + // The other half of #3127: legacy has to count, or a legacy-only match renders the empty state. + it('does not report no results when only a legacy market matched', () => { + expect(hasNoMarketResults([0, 0, 0, 0, 1, 0, 0])).toBe(false); + }); + + it('does not report no results when a non-legacy group matched', () => { + expect(hasNoMarketResults([0, 2, 0, 0, 0, 0, 0])).toBe(false); + }); +}); diff --git a/src/components/marketSwitcher.utils.ts b/src/components/marketSwitcher.utils.ts new file mode 100644 index 0000000000..b0113d076c --- /dev/null +++ b/src/components/marketSwitcher.utils.ts @@ -0,0 +1,28 @@ +/** + * Pure helpers for the market switcher's legacy section. + * + * Legacy markets are collapsed behind a "Show legacy markets" switch. That also hid them from + * search, so searching for one reported "No markets found" while the match sat in the + * un-rendered legacy group (https://github.com/aave/interface/issues/3127). + */ + +/** + * Legacy markets stay collapsed by default, but an explicit search must never hide a match — + * typing a market name has already said which market the user wants. + */ +export const shouldShowLegacySection = ({ + showLegacy, + searchQuery, + legacyCount, +}: { + showLegacy: boolean; + searchQuery: string; + legacyCount: number; +}): boolean => legacyCount > 0 && (showLegacy || searchQuery.trim() !== ''); + +/** + * "No markets found" has to account for every group a match can land in, legacy included, + * otherwise a legacy-only match is reported as no match at all. + */ +export const hasNoMarketResults = (groupCounts: number[]): boolean => + groupCounts.every((count) => count === 0);