Skip to content

Commit

Permalink
fix(token-selector): show direct match on top (#3395)
Browse files Browse the repository at this point in the history
* fix: show exact match on top of search results

* chore: do not limit search results for active list

* refactor: capitalize constant

* chore: add GNO to Gnosis Chain default favourite list

* fix: filter out bridge info from token names on search
  • Loading branch information
alfetopito committed Nov 15, 2023
1 parent 0fe25e6 commit e4c24b0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useSetAtom } from 'jotai/index'
import { useCallback, useEffect, useMemo } from 'react'

import { TokenWithLogo } from '@cowprotocol/common-const'
import { useNetworkName } from '@cowprotocol/common-hooks'
import { doesTokenMatchSymbolOrAddress } from '@cowprotocol/common-utils'
import { useSearchToken } from '@cowprotocol/tokens'
Expand All @@ -16,7 +17,7 @@ import { TokenSourceTitle } from '../../pure/TokenSourceTitle'
import { updateSelectTokenWidgetAtom } from '../../state/selectTokenWidgetAtom'
import { SelectTokenContext } from '../../types'

const searchResultsLimit = 10
const SEARCH_RESULTS_LIMIT = 10

export interface TokenSearchResultsProps extends SelectTokenContext {
searchInput: string
Expand Down Expand Up @@ -53,16 +54,29 @@ export function TokenSearchResults({
return searchCount === 0
}, [isLoading, searchCount])

const [matchedToken, activeList] = useMemo(() => {
let matched: TokenWithLogo | undefined = undefined
const remaining: TokenWithLogo[] = []

for (const t of activeListsResult) {
if (doesTokenMatchSymbolOrAddress(t, searchInput)) {
matched = t
} else {
remaining.push(t)
}
}

return [matched, remaining]
}, [activeListsResult, searchInput])

// On press Enter, select first token if only one token is found or it's fully matches to the search input
const onInputPressEnter = useCallback(() => {
if (!searchInput || !activeListsResult) return

const matchedToken = activeListsResult.find((token) => doesTokenMatchSymbolOrAddress(token, searchInput))

if (activeListsResult.length === 1 || matchedToken) {
onSelectToken(matchedToken || activeListsResult[0])
}
}, [searchInput, activeListsResult, onSelectToken])
}, [searchInput, activeListsResult, matchedToken, onSelectToken])

useEffect(() => {
updateSelectTokenWidget({
Expand All @@ -84,9 +98,20 @@ export function TokenSearchResults({

return (
<>
{/*Exact match*/}
{matchedToken && (
<TokenListItem
token={matchedToken}
balance={balances ? balances[matchedToken.address]?.value : undefined}
onSelectToken={onSelectToken}
selectedToken={selectedToken}
isUnsupported={!!unsupportedTokens[matchedToken.address.toLowerCase()]}
isPermitCompatible={permitCompatibleTokens[matchedToken.address.toLowerCase()]}
/>
)}
{/*Tokens from active lists*/}
{activeListsResult &&
activeListsResult.slice(0, searchResultsLimit).map((token) => {
{activeList &&
activeList.map((token) => {
const addressLowerCase = token.address.toLowerCase()

return (
Expand All @@ -105,7 +130,7 @@ export function TokenSearchResults({
{/*Tokens from blockchain*/}
{blockchainResult?.length ? (
<styledEl.ImportTokenWrapper id="currency-import">
{blockchainResult.slice(0, searchResultsLimit).map((token) => {
{blockchainResult.slice(0, SEARCH_RESULTS_LIMIT).map((token) => {
return <ImportTokenItem key={token.address} token={token} importToken={addTokenImportCallback} />
})}
</styledEl.ImportTokenWrapper>
Expand All @@ -118,7 +143,7 @@ export function TokenSearchResults({
Expanded results from inactive Token Lists
</TokenSourceTitle>
<div>
{inactiveListsResult.slice(0, searchResultsLimit).map((token) => {
{inactiveListsResult.slice(0, SEARCH_RESULTS_LIMIT).map((token) => {
return (
<ImportTokenItem
key={token.address}
Expand Down
2 changes: 2 additions & 0 deletions libs/tokens/src/const/defaultFavouriteTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DAI,
DAI_GOERLI,
EURE_GNOSIS_CHAIN,
GNO_GNOSIS_CHAIN,
TokenWithLogo,
USDC_GNOSIS_CHAIN,
USDC_GOERLI,
Expand Down Expand Up @@ -43,6 +44,7 @@ export const DEFAULT_FAVOURITE_TOKENS: Record<SupportedChainId, TokensMap> = {
COW[SupportedChainId.GNOSIS_CHAIN],
EURE_GNOSIS_CHAIN,
WRAPPED_NATIVE_CURRENCY[SupportedChainId.GNOSIS_CHAIN],
GNO_GNOSIS_CHAIN,
WETH_GNOSIS_CHAIN,
WBTC_GNOSIS_CHAIN,
]),
Expand Down
7 changes: 6 additions & 1 deletion libs/tokens/src/utils/getTokenSearchFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,10 @@ export function getTokenSearchFilter<T extends Token | TokenInfo>(
return queryParts.every((p) => p.length === 0 || parts.some((sp) => sp.startsWith(p) || sp.endsWith(p)))
}

return ({ name, symbol }: T | NativeCurrency): boolean => Boolean((symbol && match(symbol)) || (name && match(name)))
return ({ name, symbol }: T | NativeCurrency): boolean => {
// Filter out from token names the bridge info to not pollute the results with garbage entries
const filteredName = name?.replace(/\s*(on\s(gnosis|xdai)|from\s(mainnet|ethereum)).*$/i, '')

return Boolean((symbol && match(symbol)) || (filteredName && match(filteredName)))
}
}

2 comments on commit e4c24b0

@vercel
Copy link

@vercel vercel bot commented on e4c24b0 Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on e4c24b0 Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

cosmos – ./

cowswap-seven.vercel.app
cosmos-cowswap.vercel.app
cosmos-git-main-cowswap.vercel.app
cosmos.cow.fi

Please sign in to comment.