diff --git a/.changeset/shy-oranges-guess.md b/.changeset/shy-oranges-guess.md new file mode 100644 index 000000000..180e2e3d5 --- /dev/null +++ b/.changeset/shy-oranges-guess.md @@ -0,0 +1,6 @@ +--- +'@reservoir0x/relay-kit-hooks': patch +'@reservoir0x/relay-kit-ui': patch +--- + +Add relay trending tokens to token selector diff --git a/packages/hooks/src/hooks/useTrendingCurrencies.ts b/packages/hooks/src/hooks/useTrendingCurrencies.ts new file mode 100644 index 000000000..96bff3c39 --- /dev/null +++ b/packages/hooks/src/hooks/useTrendingCurrencies.ts @@ -0,0 +1,54 @@ +import { + useQuery, + type DefaultError, + type QueryKey +} from '@tanstack/react-query' +import { + setParams, + type paths, + MAINNET_RELAY_API +} from '@reservoir0x/relay-sdk' +import fetcher from '../fetcher.js' + +export type TrendingCurrenciesQuery = + paths['/currencies/trending']['get']['parameters']['query'] & { + referrer?: string + } + +export type TrendingCurrenciesResponse = + paths['/currencies/trending']['get']['responses']['200']['content']['application/json'] + +type QueryType = typeof useQuery< + TrendingCurrenciesResponse, + DefaultError, + TrendingCurrenciesResponse, + QueryKey +> +type QueryOptions = Parameters['0'] + +export const queryTrendingCurrencies = function ( + baseApiUrl: string = MAINNET_RELAY_API, + options?: TrendingCurrenciesQuery, + headers?: Record +): Promise { + const url = new URL(`${baseApiUrl}/currencies/trending`) + setParams(url, options ?? {}) + return fetcher(url.href, headers) +} + +export default ( + baseApiUrl?: string, + queryParams?: TrendingCurrenciesQuery, + queryOptions?: Partial +) => { + const queryKey = ['useTrendingCurrencies', queryParams] + + const response = (useQuery as QueryType)({ + queryKey: queryKey, + queryFn: () => queryTrendingCurrencies(baseApiUrl, queryParams), + ...queryOptions, + enabled: queryOptions?.enabled + }) + + return response +} diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index e3d77cee7..dc7cc1401 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -21,6 +21,10 @@ export { default as useTokenPrice, queryTokenPrice } from './hooks/useTokenPrice.js' +export { + default as useTrendingCurrencies, + queryTrendingCurrencies +} from './hooks/useTrendingCurrencies.js' //types export type { CurrencyList, Currency } from './hooks/useTokenList.js' diff --git a/packages/ui/src/components/common/TokenSelector/TokenList.tsx b/packages/ui/src/components/common/TokenSelector/TokenList.tsx index 23e2f3255..1ebfce571 100644 --- a/packages/ui/src/components/common/TokenSelector/TokenList.tsx +++ b/packages/ui/src/components/common/TokenSelector/TokenList.tsx @@ -1,4 +1,4 @@ -import { type FC } from 'react' +import { useState, type FC } from 'react' import { Flex, Text, @@ -9,7 +9,11 @@ import { Button } from '../../primitives/index.js' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' +import { + faChevronDown, + faChevronUp, + faExclamationTriangle +} from '@fortawesome/free-solid-svg-icons' import { formatBN, formatDollar } from '../../../utils/numbers.js' import { truncateAddress } from '../../../utils/truncate.js' import type { EnhancedToken } from '../../../hooks/useEnhancedTokensList.js' @@ -20,15 +24,23 @@ type TokenListProps = { isLoading: boolean isLoadingBalances?: boolean chainFilterId?: number + showMoreButton?: boolean } export const TokenList: FC = ({ title, - tokens, + tokens: rawTokens, isLoading, isLoadingBalances, - chainFilterId + chainFilterId, + showMoreButton }) => { + const [tokensExpanded, setTokensExpanded] = useState(false) + const tokens = + showMoreButton && rawTokens && rawTokens.length > 4 && !tokensExpanded + ? rawTokens.slice(0, 4) + : rawTokens + if (isLoading) { return ( <> @@ -213,6 +225,30 @@ export const TokenList: FC = ({ ) })} + {showMoreButton && ( + + )} ) } diff --git a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx index f2a3aeac9..8613728d7 100644 --- a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx +++ b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx @@ -51,6 +51,7 @@ import { sortChains } from '../../../utils/tokenSelector.js' import { useInternalRelayChains } from '../../../hooks/index.js' +import { useTrendingCurrencies } from '@reservoir0x/relay-kit-hooks' export type TokenSelectorProps = { token?: Token @@ -238,6 +239,17 @@ const TokenSelector: FC = ({ chainFilter.id ) + const { data: trendingTokens, isLoading: isLoadingTrendingTokens } = + useTrendingCurrencies( + relayClient?.baseApiUrl, + { + referrer: relayClient?.source + }, + { + enabled: context === 'to' + } + ) + // Get main token list const { data: tokenList, isLoading: isLoadingTokenList } = useTokenList( relayClient?.baseApiUrl, @@ -291,6 +303,14 @@ const TokenSelector: FC = ({ true ) + const sortedTrendingTokens = useEnhancedTokensList( + trendingTokens, + tokenBalances, + 'to', + multiWalletSupportEnabled, + undefined, + false + ) const sortedCombinedTokens = useEnhancedTokensList( combinedTokenList, tokenBalances, @@ -648,15 +668,29 @@ const TokenSelector: FC = ({ show: sortedUserTokens.length > 0 }, { - title: 'Tokens by 24H volume', + title: 'Global 24H Volume', tokens: sortedCombinedTokens, isLoading: isLoadingTokenList, show: true + }, + { + title: 'Relay 24H Volume', + tokens: sortedTrendingTokens, + isLoading: isLoadingTrendingTokens, + show: + context === 'to' && chainFilter.id === undefined, + showMoreButton: true } ] .sort((a, b) => (context === 'to' ? -1 : 1)) // Reverse order depending on context .map( - ({ title, tokens, isLoading, show }) => + ({ + title, + tokens, + isLoading, + show, + showMoreButton + }) => show && ( = ({ isLoading={isLoading} isLoadingBalances={isLoadingBalances} chainFilterId={chainFilter.id} + showMoreButton={showMoreButton} /> ) )} diff --git a/packages/ui/src/components/primitives/Button.tsx b/packages/ui/src/components/primitives/Button.tsx index 7af3dca82..ba4802a62 100644 --- a/packages/ui/src/components/primitives/Button.tsx +++ b/packages/ui/src/components/primitives/Button.tsx @@ -93,6 +93,13 @@ const ButtonCss = cva({ backgroundColor: 'amber4', color: 'amber11' } + }, + grey: { + backgroundColor: 'gray3', + color: 'gray11', + '&:hover': { + backgroundColor: 'gray4' + } } }, corners: {