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'
import SparklineChart from 'components/Charts/SparklineChart'
import CurrencyLogo from 'components/CurrencyLogo'
import { getChainInfo } from 'constants/chainInfo'
import { chainIdToChainName } from 'graphql/data/TokenDetailQuery'
import { useTokenPriceQuery } from 'graphql/data/TokenPriceQuery'
import { useTokenRowQuery } from 'graphql/data/TokenRowQuery'
import { useCurrency, useToken } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { useAtom } from 'jotai'
......@@ -425,13 +423,13 @@ export default function LoadedRow({
tokenAddress,
tokenListIndex,
tokenListLength,
data,
tokenData,
timePeriod,
}: {
tokenAddress: string
tokenListIndex: number
tokenListLength: number
data: TokenData
tokenData: TokenData
timePeriod: TimePeriod
}) {
const token = useToken(tokenAddress)
......@@ -468,8 +466,6 @@ export default function LoadedRow({
}
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)
return (
<StyledLink
......@@ -505,7 +501,7 @@ export default function LoadedRow({
price={
<ClickableContent>
<PriceInfoCell>
{tokenRowData.price?.value ? formatDollarAmount(tokenRowData.price?.value) : '-'}
{tokenData.price?.value ? formatDollarAmount(tokenData.price?.value) : '-'}
<PercentChangeInfoCell>
{delta}
{arrow}
......@@ -521,12 +517,14 @@ export default function LoadedRow({
}
marketCap={
<ClickableContent>
{tokenRowData.marketCap?.value ? formatDollarAmount(tokenRowData.marketCap?.value) : '-'}
{tokenData.marketCap?.value ? formatDollarAmount(tokenData.marketCap?.value) : '-'}
</ClickableContent>
}
volume={
<ClickableContent>
{tokenRowData.volume?.value ? formatDollarAmount(tokenRowData.volume?.value) : '-'}
{tokenData.volume?.[timePeriod]?.value
? formatDollarAmount(tokenData.volume?.[timePeriod]?.value ?? undefined)
: '-'}
</ClickableContent>
}
sparkLine={
......
......@@ -7,7 +7,7 @@ import {
sortDirectionAtom,
} from 'components/Tokens/state'
import { useAllTokens } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { TimePeriod, TokenData, UseTopTokensResult } from 'hooks/useExplorePageQuery'
import { useAtomValue } from 'jotai/utils'
import { ReactNode, useCallback, useMemo } from 'react'
import { AlertTriangle } from 'react-feather'
......@@ -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 sortDirection = useAtomValue(sortDirectionAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
......@@ -98,6 +98,7 @@ function useSortedTokens(addresses: string[], tokenData: TokenData | null) {
if (!tokenData) {
return 0
}
// fix any, delta property
const token1 = tokenData[token1Address] as any
const token2 = tokenData[token2Address] as any
......@@ -152,13 +153,7 @@ function LoadingTokenTable() {
)
}
interface TokenTableProps {
data: TokenData | null
error: string | null
loading: boolean
}
export default function TokenTable({ data, error, loading }: TokenTableProps) {
export default function TokenTable({ data, error, loading }: UseTopTokensResult) {
const showFavorites = useAtomValue<boolean>(showFavoritesAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
const topTokenAddresses = data ? Object.keys(data) : []
......@@ -199,7 +194,7 @@ export default function TokenTable({ data, error, loading }: TokenTableProps) {
tokenAddress={tokenAddress}
tokenListIndex={index}
tokenListLength={filteredAndSortedTokens.length}
data={data}
tokenData={data[tokenAddress]}
timePeriod={timePeriod}
/>
))}
......
import graphql from 'babel-plugin-relay/macro'
import { TimePeriod } from 'hooks/useExplorePageQuery'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
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) {
const tokenRowData = useLazyLoadQuery<TokenRowQueryType>(
export function useTopTokenQuery(page: number) {
const topTokenData = useLazyLoadQuery<TopTokenQueryType>(
graphql`
query TokenRowQuery($contract: ContractInput!) {
tokenProjects(contracts: [$contract]) {
query TopTokenQuery($page: Int!) {
topTokenProjects(orderBy: MARKET_CAP, pageSize: 50, currency: USD, page: $page) {
name
tokens {
chain
address
symbol
}
markets(currencies: [USD]) {
price {
value
......@@ -47,27 +53,31 @@ export function useTokenRowQuery(address: string, timePeriod: TimePeriod, chain:
}
`,
{
contract: {
address,
chain,
},
page,
}
)
const { price, marketCap, volume1H, volume1D, volume1W, volume1M, volume1Y } =
tokenRowData.tokenProjects?.[0]?.markets?.[0] ?? {}
switch (timePeriod) {
case TimePeriod.HOUR:
return { price, marketCap, volume: volume1H } ?? {}
case TimePeriod.DAY:
return { price, marketCap, volume: volume1D } ?? {}
case TimePeriod.WEEK:
return { price, marketCap, volume: volume1W } ?? {}
case TimePeriod.MONTH:
return { price, marketCap, volume: volume1M } ?? {}
case TimePeriod.YEAR:
return { price, marketCap, volume: volume1Y } ?? {}
case TimePeriod.ALL:
//TODO: Add functionality for ALL, without requesting it at same time as rest of data for performance reasons
return { price, marketCap, volume: volume1Y } ?? {}
}
const topTokens: Record<string, TokenData> =
topTokenData.topTokenProjects?.reduce((acc, token) => {
const tokenAddress = token?.tokens?.[0].address
if (tokenAddress) {
acc[tokenAddress] = {
name: token?.name,
chain: token?.tokens?.[0].chain,
symbol: token?.tokens?.[0].symbol,
price: token?.markets?.[0]?.price,
marketCap: token?.markets?.[0]?.marketCap,
volume: {
[TimePeriod.HOUR]: token?.markets?.[0]?.volume1H,
[TimePeriod.DAY]: token?.markets?.[0]?.volume1D,
[TimePeriod.WEEK]: token?.markets?.[0]?.volume1W,
[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'
import { PageName } from 'components/AmplitudeAnalytics/constants'
import { Trace } from 'components/AmplitudeAnalytics/Trace'
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 NetworkFilter from 'components/Tokens/TokenTable/NetworkFilter'
import SearchBar from 'components/Tokens/TokenTable/SearchBar'
import TimeSelector from 'components/Tokens/TokenTable/TimeSelector'
import TokenTable from 'components/Tokens/TokenTable/TokenTable'
import { TokensNetworkFilterVariant, useTokensNetworkFilterFlag } from 'featureFlags/flags/tokensNetworkFilter'
import useExplorePageQuery from 'hooks/useExplorePageQuery'
import { useAtomValue, useResetAtom } from 'jotai/utils'
import { useTopTokenQuery } from 'graphql/data/TopTokenQuery'
import { useResetAtom } from 'jotai/utils'
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import styled from 'styled-components/macro'
......@@ -61,11 +61,12 @@ const FiltersWrapper = styled.div`
`
const Tokens = () => {
const topTokens = useTopTokenQuery(1)
const tokensNetworkFilterFlag = useTokensNetworkFilterFlag()
const favoriteTokens = useAtomValue<string[]>(favoritesAtom)
const { data, error, loading } = useExplorePageQuery(favoriteTokens)
const resetFilterString = useResetAtom(filterStringAtom)
const location = useLocation()
const error = null
const loading = false
useEffect(() => {
resetFilterString()
}, [location, resetFilterString])
......@@ -90,7 +91,7 @@ const Tokens = () => {
</FiltersWrapper>
<TokenTableContainer>
<TokenTable data={data} error={error} loading={loading} />
<TokenTable data={topTokens} error={error} loading={loading} />
</TokenTableContainer>
</ExploreContainer>
</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