From 753fc3f3ecdee3068db704fa1bc400a53d1c78e8 Mon Sep 17 00:00:00 2001 From: Yaroslav Grachev Date: Fri, 20 Dec 2024 12:00:44 +0300 Subject: [PATCH] Feat: Portfolio search (#2880) --- .../model/__tests__/portfolio-model.test.ts | 4 +- .../model/portfolio-model.ts | 42 +++++++++++++------ src/renderer/shared/lib/utils/search.ts | 3 +- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/renderer/features/assets/AssetsPortfolioView/model/__tests__/portfolio-model.test.ts b/src/renderer/features/assets/AssetsPortfolioView/model/__tests__/portfolio-model.test.ts index 26a126e388..f787485e07 100644 --- a/src/renderer/features/assets/AssetsPortfolioView/model/__tests__/portfolio-model.test.ts +++ b/src/renderer/features/assets/AssetsPortfolioView/model/__tests__/portfolio-model.test.ts @@ -58,8 +58,8 @@ const mockTokens: AssetByChains[] = [ }, ]; -// TODO input data is a bit complex and after refactoring of internal model, chains wallet and etc should be presented. -// For now it's simplier to turn off some of the test and think about simplifying external dependencies. +// TODO: input data is a bit complex and after refactoring of internal model, chains wallet and etc should be presented. +// For now it's simpler to turn off some of the test and think about simplifying external dependencies. describe('Portfolio model', () => { test('should handle activeViewChanged event', async () => { diff --git a/src/renderer/features/assets/AssetsPortfolioView/model/portfolio-model.ts b/src/renderer/features/assets/AssetsPortfolioView/model/portfolio-model.ts index 8746552152..2941ab70e9 100644 --- a/src/renderer/features/assets/AssetsPortfolioView/model/portfolio-model.ts +++ b/src/renderer/features/assets/AssetsPortfolioView/model/portfolio-model.ts @@ -2,7 +2,7 @@ import { combine, createEvent, createStore, restore } from 'effector'; import { once } from 'patronum'; import { type Account, type AssetByChains } from '@/shared/core'; -import { includes, nullable } from '@/shared/lib/utils'; +import { includesMultiple, nullable } from '@/shared/lib/utils'; import { AssetsListView } from '@/entities/asset'; import { balanceModel } from '@/entities/balance'; import { networkModel, networkUtils } from '@/entities/network'; @@ -119,25 +119,43 @@ const $activeTokensWithBalance = combine( ); const $filteredTokensWithBalance = combine( - { activeTokensWithBalance: $activeTokensWithBalance, query: $query }, + { + activeTokensWithBalance: $activeTokensWithBalance, + query: $query, + }, ({ activeTokensWithBalance, query }) => { - const filteredTokens: AssetByChains[] = []; + let filteredTokens: AssetByChains[] = []; + const fullChainMatch: number[] = []; for (const token of activeTokensWithBalance) { - const filteredChains = token.chains.filter((chain) => { - const hasSymbol = includes(chain.assetSymbol, query); - const hasAssetName = includes(token.name, query); - const hasChainName = includes(chain.name, query); + // Case 1: full match for token symbol -> get only that token across all chains + if (query.toLowerCase() === token.symbol.toLowerCase()) { + filteredTokens = [{ ...token, chains: token.chains }]; + break; + } - return hasSymbol || hasAssetName || hasChainName; - }); + let tokenChains = []; + for (const chain of token.chains) { + // Case 2: full match for chain name -> get all tokens for that chain + if (query.toLowerCase() === chain.name.toLowerCase()) { + fullChainMatch.push(filteredTokens.length); + tokenChains = [chain]; + break; + } + // Case 3: partial match for chain name or asset symbol + if (includesMultiple([chain.name, chain.assetSymbol], query)) { + tokenChains.push(chain); + } + } - if (filteredChains.length === 0) continue; + if (tokenChains.length === 0) continue; - filteredTokens.push({ ...token, chains: filteredChains }); + filteredTokens.push({ ...token, chains: tokenChains }); } - return filteredTokens; + if (fullChainMatch.length === 0) return filteredTokens; + + return filteredTokens.filter((_, index) => fullChainMatch.includes(index)); }, ); diff --git a/src/renderer/shared/lib/utils/search.ts b/src/renderer/shared/lib/utils/search.ts index d32834edf9..b4781128dd 100644 --- a/src/renderer/shared/lib/utils/search.ts +++ b/src/renderer/shared/lib/utils/search.ts @@ -18,7 +18,8 @@ const emptyMeta = (): M => { * Performs searching by query and sort using weight of each field * * @param records - List of objects - * @param meta - List of additional info, associated with given record by index + * @param getMeta - List of additional info, associated with given record by + * index * @param query - Requested string * @param queryMinLength - From this query length method starts to perform * search