Commit 53ebf37b authored by Kaylee George's avatar Kaylee George Committed by GitHub

feat: add top tokens query for Explore tokens table (#4448)

* progress

* map??

* idk

* maybe progress?

* more

* hook

* rm favs

* add query

* comment

* get rid of page query

* fix autoimports

* Update TokenRow.tsx
parent 624ec336
...@@ -5,9 +5,7 @@ import { EventName } from 'components/AmplitudeAnalytics/constants' ...@@ -5,9 +5,7 @@ import { EventName } from 'components/AmplitudeAnalytics/constants'
import SparklineChart from 'components/Charts/SparklineChart' import SparklineChart from 'components/Charts/SparklineChart'
import CurrencyLogo from 'components/CurrencyLogo' import CurrencyLogo from 'components/CurrencyLogo'
import { getChainInfo } from 'constants/chainInfo' import { getChainInfo } from 'constants/chainInfo'
import { chainIdToChainName } from 'graphql/data/TokenDetailQuery'
import { useTokenPriceQuery } from 'graphql/data/TokenPriceQuery' import { useTokenPriceQuery } from 'graphql/data/TokenPriceQuery'
import { useTokenRowQuery } from 'graphql/data/TokenRowQuery'
import { useCurrency, useToken } from 'hooks/Tokens' import { useCurrency, useToken } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery' import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { useAtom } from 'jotai' import { useAtom } from 'jotai'
...@@ -425,13 +423,13 @@ export default function LoadedRow({ ...@@ -425,13 +423,13 @@ export default function LoadedRow({
tokenAddress, tokenAddress,
tokenListIndex, tokenListIndex,
tokenListLength, tokenListLength,
data, tokenData,
timePeriod, timePeriod,
}: { }: {
tokenAddress: string tokenAddress: string
tokenListIndex: number tokenListIndex: number
tokenListLength: number tokenListLength: number
data: TokenData tokenData: TokenData
timePeriod: TimePeriod timePeriod: TimePeriod
}) { }) {
const token = useToken(tokenAddress) const token = useToken(tokenAddress)
...@@ -468,8 +466,6 @@ export default function LoadedRow({ ...@@ -468,8 +466,6 @@ export default function LoadedRow({
} }
const heartColor = isFavorited ? theme.accentActive : undefined const heartColor = isFavorited ? theme.accentActive : undefined
// TODO: consider using backend network?
const tokenRowData = useTokenRowQuery(tokenAddress, timePeriod, chainIdToChainName(filterNetwork))
// TODO: currency logo sizing mobile (32px) vs. desktop (24px) // TODO: currency logo sizing mobile (32px) vs. desktop (24px)
return ( return (
<StyledLink <StyledLink
...@@ -505,7 +501,7 @@ export default function LoadedRow({ ...@@ -505,7 +501,7 @@ export default function LoadedRow({
price={ price={
<ClickableContent> <ClickableContent>
<PriceInfoCell> <PriceInfoCell>
{tokenRowData.price?.value ? formatDollarAmount(tokenRowData.price?.value) : '-'} {tokenData.price?.value ? formatDollarAmount(tokenData.price?.value) : '-'}
<PercentChangeInfoCell> <PercentChangeInfoCell>
{delta} {delta}
{arrow} {arrow}
...@@ -521,12 +517,14 @@ export default function LoadedRow({ ...@@ -521,12 +517,14 @@ export default function LoadedRow({
} }
marketCap={ marketCap={
<ClickableContent> <ClickableContent>
{tokenRowData.marketCap?.value ? formatDollarAmount(tokenRowData.marketCap?.value) : '-'} {tokenData.marketCap?.value ? formatDollarAmount(tokenData.marketCap?.value) : '-'}
</ClickableContent> </ClickableContent>
} }
volume={ volume={
<ClickableContent> <ClickableContent>
{tokenRowData.volume?.value ? formatDollarAmount(tokenRowData.volume?.value) : '-'} {tokenData.volume?.[timePeriod]?.value
? formatDollarAmount(tokenData.volume?.[timePeriod]?.value ?? undefined)
: '-'}
</ClickableContent> </ClickableContent>
} }
sparkLine={ sparkLine={
......
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
sortDirectionAtom, sortDirectionAtom,
} from 'components/Tokens/state' } from 'components/Tokens/state'
import { useAllTokens } from 'hooks/Tokens' import { useAllTokens } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery' import { TimePeriod, TokenData, UseTopTokensResult } from 'hooks/useExplorePageQuery'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import { ReactNode, useCallback, useMemo } from 'react' import { ReactNode, useCallback, useMemo } from 'react'
import { AlertTriangle } from 'react-feather' import { AlertTriangle } from 'react-feather'
...@@ -75,7 +75,7 @@ function useFilteredTokens(addresses: string[]) { ...@@ -75,7 +75,7 @@ function useFilteredTokens(addresses: string[]) {
) )
} }
function useSortedTokens(addresses: string[], tokenData: TokenData | null) { function useSortedTokens(addresses: string[], tokenData: Record<string, TokenData> | null) {
const sortCategory = useAtomValue(sortCategoryAtom) const sortCategory = useAtomValue(sortCategoryAtom)
const sortDirection = useAtomValue(sortDirectionAtom) const sortDirection = useAtomValue(sortDirectionAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom) const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
...@@ -98,6 +98,7 @@ function useSortedTokens(addresses: string[], tokenData: TokenData | null) { ...@@ -98,6 +98,7 @@ function useSortedTokens(addresses: string[], tokenData: TokenData | null) {
if (!tokenData) { if (!tokenData) {
return 0 return 0
} }
// fix any, delta property
const token1 = tokenData[token1Address] as any const token1 = tokenData[token1Address] as any
const token2 = tokenData[token2Address] as any const token2 = tokenData[token2Address] as any
...@@ -152,13 +153,7 @@ function LoadingTokenTable() { ...@@ -152,13 +153,7 @@ function LoadingTokenTable() {
) )
} }
interface TokenTableProps { export default function TokenTable({ data, error, loading }: UseTopTokensResult) {
data: TokenData | null
error: string | null
loading: boolean
}
export default function TokenTable({ data, error, loading }: TokenTableProps) {
const showFavorites = useAtomValue<boolean>(showFavoritesAtom) const showFavorites = useAtomValue<boolean>(showFavoritesAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom) const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
const topTokenAddresses = data ? Object.keys(data) : [] const topTokenAddresses = data ? Object.keys(data) : []
...@@ -199,7 +194,7 @@ export default function TokenTable({ data, error, loading }: TokenTableProps) { ...@@ -199,7 +194,7 @@ export default function TokenTable({ data, error, loading }: TokenTableProps) {
tokenAddress={tokenAddress} tokenAddress={tokenAddress}
tokenListIndex={index} tokenListIndex={index}
tokenListLength={filteredAndSortedTokens.length} tokenListLength={filteredAndSortedTokens.length}
data={data} tokenData={data[tokenAddress]}
timePeriod={timePeriod} timePeriod={timePeriod}
/> />
))} ))}
......
import graphql from 'babel-plugin-relay/macro' import graphql from 'babel-plugin-relay/macro'
import { TimePeriod } from 'hooks/useExplorePageQuery' import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { useLazyLoadQuery } from 'react-relay' import { useLazyLoadQuery } from 'react-relay'
import type { Chain, TokenRowQuery as TokenRowQueryType } from './__generated__/TokenRowQuery.graphql' import type { TopTokenQuery as TopTokenQueryType } from './__generated__/TopTokenQuery.graphql'
export function useTokenRowQuery(address: string, timePeriod: TimePeriod, chain: Chain) { export function useTopTokenQuery(page: number) {
const tokenRowData = useLazyLoadQuery<TokenRowQueryType>( const topTokenData = useLazyLoadQuery<TopTokenQueryType>(
graphql` graphql`
query TokenRowQuery($contract: ContractInput!) { query TopTokenQuery($page: Int!) {
tokenProjects(contracts: [$contract]) { topTokenProjects(orderBy: MARKET_CAP, pageSize: 50, currency: USD, page: $page) {
name
tokens {
chain
address
symbol
}
markets(currencies: [USD]) { markets(currencies: [USD]) {
price { price {
value value
...@@ -47,27 +53,31 @@ export function useTokenRowQuery(address: string, timePeriod: TimePeriod, chain: ...@@ -47,27 +53,31 @@ export function useTokenRowQuery(address: string, timePeriod: TimePeriod, chain:
} }
`, `,
{ {
contract: { page,
address,
chain,
},
} }
) )
const { price, marketCap, volume1H, volume1D, volume1W, volume1M, volume1Y } =
tokenRowData.tokenProjects?.[0]?.markets?.[0] ?? {} const topTokens: Record<string, TokenData> =
switch (timePeriod) { topTokenData.topTokenProjects?.reduce((acc, token) => {
case TimePeriod.HOUR: const tokenAddress = token?.tokens?.[0].address
return { price, marketCap, volume: volume1H } ?? {} if (tokenAddress) {
case TimePeriod.DAY: acc[tokenAddress] = {
return { price, marketCap, volume: volume1D } ?? {} name: token?.name,
case TimePeriod.WEEK: chain: token?.tokens?.[0].chain,
return { price, marketCap, volume: volume1W } ?? {} symbol: token?.tokens?.[0].symbol,
case TimePeriod.MONTH: price: token?.markets?.[0]?.price,
return { price, marketCap, volume: volume1M } ?? {} marketCap: token?.markets?.[0]?.marketCap,
case TimePeriod.YEAR: volume: {
return { price, marketCap, volume: volume1Y } ?? {} [TimePeriod.HOUR]: token?.markets?.[0]?.volume1H,
case TimePeriod.ALL: [TimePeriod.DAY]: token?.markets?.[0]?.volume1D,
//TODO: Add functionality for ALL, without requesting it at same time as rest of data for performance reasons [TimePeriod.WEEK]: token?.markets?.[0]?.volume1W,
return { price, marketCap, volume: volume1Y } ?? {} [TimePeriod.MONTH]: token?.markets?.[0]?.volume1M,
} [TimePeriod.YEAR]: token?.markets?.[0]?.volume1Y,
[TimePeriod.ALL]: token?.markets?.[0]?.volume1Y, // todo: figure out all
},
}
}
return acc
}, {} as Record<string, TokenData>) ?? {}
return topTokens
} }
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2,15 +2,15 @@ import { Trans } from '@lingui/macro' ...@@ -2,15 +2,15 @@ import { Trans } from '@lingui/macro'
import { PageName } from 'components/AmplitudeAnalytics/constants' import { PageName } from 'components/AmplitudeAnalytics/constants'
import { Trace } from 'components/AmplitudeAnalytics/Trace' import { Trace } from 'components/AmplitudeAnalytics/Trace'
import { MAX_WIDTH_MEDIA_BREAKPOINT, MEDIUM_MEDIA_BREAKPOINT } from 'components/Tokens/constants' import { MAX_WIDTH_MEDIA_BREAKPOINT, MEDIUM_MEDIA_BREAKPOINT } from 'components/Tokens/constants'
import { favoritesAtom, filterStringAtom } from 'components/Tokens/state' import { filterStringAtom } from 'components/Tokens/state'
import FavoriteButton from 'components/Tokens/TokenTable/FavoriteButton' import FavoriteButton from 'components/Tokens/TokenTable/FavoriteButton'
import NetworkFilter from 'components/Tokens/TokenTable/NetworkFilter' import NetworkFilter from 'components/Tokens/TokenTable/NetworkFilter'
import SearchBar from 'components/Tokens/TokenTable/SearchBar' import SearchBar from 'components/Tokens/TokenTable/SearchBar'
import TimeSelector from 'components/Tokens/TokenTable/TimeSelector' import TimeSelector from 'components/Tokens/TokenTable/TimeSelector'
import TokenTable from 'components/Tokens/TokenTable/TokenTable' import TokenTable from 'components/Tokens/TokenTable/TokenTable'
import { TokensNetworkFilterVariant, useTokensNetworkFilterFlag } from 'featureFlags/flags/tokensNetworkFilter' import { TokensNetworkFilterVariant, useTokensNetworkFilterFlag } from 'featureFlags/flags/tokensNetworkFilter'
import useExplorePageQuery from 'hooks/useExplorePageQuery' import { useTopTokenQuery } from 'graphql/data/TopTokenQuery'
import { useAtomValue, useResetAtom } from 'jotai/utils' import { useResetAtom } from 'jotai/utils'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
...@@ -61,11 +61,12 @@ const FiltersWrapper = styled.div` ...@@ -61,11 +61,12 @@ const FiltersWrapper = styled.div`
` `
const Tokens = () => { const Tokens = () => {
const topTokens = useTopTokenQuery(1)
const tokensNetworkFilterFlag = useTokensNetworkFilterFlag() const tokensNetworkFilterFlag = useTokensNetworkFilterFlag()
const favoriteTokens = useAtomValue<string[]>(favoritesAtom)
const { data, error, loading } = useExplorePageQuery(favoriteTokens)
const resetFilterString = useResetAtom(filterStringAtom) const resetFilterString = useResetAtom(filterStringAtom)
const location = useLocation() const location = useLocation()
const error = null
const loading = false
useEffect(() => { useEffect(() => {
resetFilterString() resetFilterString()
}, [location, resetFilterString]) }, [location, resetFilterString])
...@@ -90,7 +91,7 @@ const Tokens = () => { ...@@ -90,7 +91,7 @@ const Tokens = () => {
</FiltersWrapper> </FiltersWrapper>
<TokenTableContainer> <TokenTableContainer>
<TokenTable data={data} error={error} loading={loading} /> <TokenTable data={topTokens} error={error} loading={loading} />
</TokenTableContainer> </TokenTableContainer>
</ExploreContainer> </ExploreContainer>
</Trace> </Trace>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment