fix: change top tokens query return type (#4453)

* query return

* fix return

* rm default empty string

* rm ?

* undef

* undefined

* null

* fix

* handle search

* .

* rebase

* top tokens

* rm blank

* rm console log

* make 100
This commit is contained in:
Kaylee George 2022-08-24 12:38:22 -07:00 committed by GitHub
parent 0e530cf92e
commit ac27c89a44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 132 deletions

@ -7,8 +7,8 @@ import { Line } from '@visx/shape'
import { filterTimeAtom } from 'components/Tokens/state'
import { bisect, curveBasis, NumberValue, scaleLinear } from 'd3'
import { useTokenPriceQuery } from 'graphql/data/TokenPriceQuery'
import { TimePeriod } from 'graphql/data/TopTokenQuery'
import { useActiveLocale } from 'hooks/useActiveLocale'
import { TimePeriod } from 'hooks/useExplorePageQuery'
import { useAtom } from 'jotai'
import { useCallback, useState } from 'react'
import { ArrowDownRight, ArrowUpRight } from 'react-feather'

@ -1,4 +1,4 @@
import { TimePeriod } from 'hooks/useExplorePageQuery'
import { TimePeriod } from 'graphql/data/TopTokenQuery'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useAtom } from 'jotai'
import { useRef } from 'react'

@ -5,8 +5,8 @@ import { EventName } from 'components/AmplitudeAnalytics/constants'
import SparklineChart from 'components/Charts/SparklineChart'
import CurrencyLogo from 'components/CurrencyLogo'
import { getChainInfo } from 'constants/chainInfo'
import { useCurrency, useToken } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { TimePeriod, TokenData } from 'graphql/data/TopTokenQuery'
import { useCurrency } from 'hooks/Tokens'
import { useAtom } from 'jotai'
import { useAtomValue } from 'jotai/utils'
import { ReactNode } from 'react'
@ -245,6 +245,7 @@ const TokenName = styled.div`
`
const TokenSymbol = styled(Cell)`
color: ${({ theme }) => theme.textTertiary};
text-transform: uppercase;
@media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) {
font-size: 12px;
@ -443,10 +444,9 @@ export default function LoadedRow({
tokenData: TokenData
timePeriod: TimePeriod
}) {
const token = useToken(tokenAddress)
const currency = useCurrency(tokenAddress)
const tokenName = token?.name ?? ''
const tokenSymbol = token?.symbol ?? ''
const tokenName = tokenData.name
const tokenSymbol = tokenData.symbol
const theme = useTheme()
const [favoriteTokens] = useAtom(favoritesAtom)
const isFavorited = favoriteTokens.includes(tokenAddress)
@ -454,14 +454,14 @@ export default function LoadedRow({
const filterString = useAtomValue(filterStringAtom)
const filterNetwork = useAtomValue(filterNetworkAtom)
const L2Icon = getChainInfo(filterNetwork).circleLogoUrl
const delta = tokenData.percentChange[timePeriod]?.value
const delta = tokenData.percentChange?.[timePeriod]?.value
const arrow = delta ? getDeltaArrow(delta) : null
const formattedDelta = delta ? formatDelta(delta) : null
const exploreTokenSelectedEventProperties = {
chain_id: filterNetwork,
token_address: tokenAddress,
token_symbol: token?.symbol,
token_symbol: tokenSymbol,
token_list_index: tokenListIndex,
token_list_length: tokenListLength,
time_frame: timePeriod,

@ -6,8 +6,7 @@ import {
sortCategoryAtom,
sortDirectionAtom,
} from 'components/Tokens/state'
import { useAllTokens } from 'hooks/Tokens'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { TimePeriod, TokenData } from 'graphql/data/TopTokenQuery'
import { useAtomValue } from 'jotai/utils'
import { ReactNode, Suspense, useCallback, useMemo } from 'react'
import { AlertTriangle } from 'react-feather'
@ -47,34 +46,33 @@ const TokenRowsContainer = styled.div`
width: 100%;
`
function useFilteredTokens(addresses: string[]) {
function useFilteredTokens(tokens: TokenData[] | undefined) {
const filterString = useAtomValue(filterStringAtom)
const favoriteTokens = useAtomValue(favoritesAtom)
const favoriteTokenAddresses = useAtomValue(favoritesAtom)
const showFavorites = useAtomValue(showFavoritesAtom)
const shownTokens = showFavorites ? favoriteTokens : addresses
const allTokens = useAllTokens()
const shownTokens =
showFavorites && tokens ? tokens.filter((token) => favoriteTokenAddresses.includes(token.address)) : tokens
return useMemo(
() =>
shownTokens.filter((tokenAddress) => {
const token = allTokens[tokenAddress]
const tokenName = token?.name ?? ''
const tokenSymbol = token?.symbol ?? ''
(shownTokens ?? []).filter((token) => {
if (!token.address) {
return false
}
if (!filterString) {
return true
}
const lowercaseFilterString = filterString.toLowerCase()
const addressIncludesFilterString = tokenAddress.toLowerCase().includes(lowercaseFilterString)
const nameIncludesFilterString = tokenName.toLowerCase().includes(lowercaseFilterString)
const symbolIncludesFilterString = tokenSymbol.toLowerCase().includes(lowercaseFilterString)
const addressIncludesFilterString = token?.address?.toLowerCase().includes(lowercaseFilterString)
const nameIncludesFilterString = token?.name?.toLowerCase().includes(lowercaseFilterString)
const symbolIncludesFilterString = token?.symbol?.toLowerCase().includes(lowercaseFilterString)
return nameIncludesFilterString || symbolIncludesFilterString || addressIncludesFilterString
}),
[allTokens, shownTokens, filterString]
[shownTokens, filterString]
)
}
function useSortedTokens(addresses: string[], tokenData: Record<string, TokenData> | null) {
function useSortedTokens(tokenData: TokenData[] | null) {
const sortCategory = useAtomValue(sortCategoryAtom)
const sortDirection = useAtomValue(sortDirectionAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
@ -93,40 +91,38 @@ function useSortedTokens(addresses: string[], tokenData: Record<string, TokenDat
return useMemo(
() =>
addresses.sort((token1Address, token2Address) => {
tokenData &&
tokenData.sort((token1, token2) => {
if (!tokenData) {
return 0
}
// fix any, delta property
const token1 = tokenData[token1Address] as any
const token2 = tokenData[token2Address] as any
// fix delta/percent change property
if (!token1 || !token2 || !sortDirection || !sortCategory) {
return 0
}
let a: number
let b: number
let a: number | null | undefined
let b: number | null | undefined
switch (sortCategory) {
case Category.marketCap:
a = token1.marketCap
b = token2.marketCap
break
case Category.percentChange:
a = token1.delta
b = token2.delta
a = token1.marketCap?.value
b = token2.marketCap?.value
break
case Category.price:
a = token1.price
b = token2.price
a = token1.price?.value
b = token2.price?.value
break
case Category.volume:
a = token1.volume[timePeriod]
b = token2.volume[timePeriod]
a = token1.volume?.[timePeriod]?.value
b = token2.volume?.[timePeriod]?.value
break
case Category.percentChange:
a = token1.percentChange?.[timePeriod]?.value
b = token2.percentChange?.[timePeriod]?.value
break
}
return sortFn(a, b)
}),
[addresses, tokenData, sortDirection, sortCategory, sortFn, timePeriod]
[tokenData, sortDirection, sortCategory, sortFn, timePeriod]
)
}
@ -152,12 +148,11 @@ export function LoadingTokenTable() {
)
}
export default function TokenTable({ data }: { data: Record<string, TokenData> | null }) {
export default function TokenTable({ data }: { data: TokenData[] | undefined }) {
const showFavorites = useAtomValue<boolean>(showFavoritesAtom)
const timePeriod = useAtomValue<TimePeriod>(filterTimeAtom)
const topTokenAddresses = data ? Object.keys(data) : []
const filteredTokens = useFilteredTokens(topTokenAddresses)
const filteredAndSortedTokens = useSortedTokens(filteredTokens, data)
const filteredTokens = useFilteredTokens(data)
const sortedFilteredTokens = useSortedTokens(filteredTokens)
/* loading and error state */
if (data === null) {
@ -173,11 +168,11 @@ export default function TokenTable({ data }: { data: Record<string, TokenData> |
)
}
if (showFavorites && filteredAndSortedTokens.length === 0) {
if (showFavorites && sortedFilteredTokens?.length === 0) {
return <NoTokensState message="You have no favorited tokens" />
}
if (!showFavorites && filteredAndSortedTokens.length === 0) {
if (!showFavorites && sortedFilteredTokens?.length === 0) {
return <NoTokensState message="No tokens found" />
}
@ -186,13 +181,13 @@ export default function TokenTable({ data }: { data: Record<string, TokenData> |
<GridContainer>
<HeaderRow />
<TokenRowsContainer>
{filteredAndSortedTokens.map((tokenAddress, index) => (
{sortedFilteredTokens?.map((token, index) => (
<LoadedRow
key={tokenAddress}
tokenAddress={tokenAddress}
key={token.address}
tokenAddress={token.address}
tokenListIndex={index}
tokenListLength={filteredAndSortedTokens.length}
tokenData={data[tokenAddress]}
tokenListLength={sortedFilteredTokens.length}
tokenData={token}
timePeriod={timePeriod}
/>
))}

@ -1,5 +1,5 @@
import { SupportedChainId } from 'constants/chains'
import { TimePeriod } from 'hooks/useExplorePageQuery'
import { TimePeriod } from 'graphql/data/TopTokenQuery'
import { atom, useAtom } from 'jotai'
import { atomWithReset, atomWithStorage } from 'jotai/utils'
import { useCallback } from 'react'

@ -1,8 +1,8 @@
import graphql from 'babel-plugin-relay/macro'
import { TimePeriod } from 'hooks/useExplorePageQuery'
import { useLazyLoadQuery } from 'react-relay'
import type { Chain, TokenPriceQuery as TokenPriceQueryType } from './__generated__/TokenPriceQuery.graphql'
import { TimePeriod } from './TopTokenQuery'
export function useTokenPriceQuery(address: string, timePeriod: TimePeriod, chain: Chain) {
const tokenPrices = useLazyLoadQuery<TokenPriceQueryType>(

@ -1,14 +1,44 @@
import graphql from 'babel-plugin-relay/macro'
import { TimePeriod, TokenData } from 'hooks/useExplorePageQuery'
import { useLazyLoadQuery } from 'react-relay'
import type { TopTokenQuery as TopTokenQueryType } from './__generated__/TopTokenQuery.graphql'
import type { Chain, Currency, TopTokenQuery as TopTokenQueryType } from './__generated__/TopTokenQuery.graphql'
export enum TimePeriod {
HOUR,
DAY,
WEEK,
MONTH,
YEAR,
ALL,
}
interface IAmount {
currency: Currency | null
value: number | null
}
export type TokenData = {
name: string | null
address: string
chain: Chain | null
symbol: string | null
price: IAmount | null | undefined
marketCap: IAmount | null | undefined
volume: Record<TimePeriod, IAmount | null | undefined>
percentChange: Record<TimePeriod, IAmount | null | undefined>
}
export interface UseTopTokensResult {
data: TokenData[] | undefined
error: string | null
loading: boolean
}
export function useTopTokenQuery(page: number) {
const topTokenData = useLazyLoadQuery<TopTokenQueryType>(
graphql`
query TopTokenQuery($page: Int!) {
topTokenProjects(orderBy: MARKET_CAP, pageSize: 50, currency: USD, page: $page) {
topTokenProjects(orderBy: MARKET_CAP, pageSize: 100, currency: USD, page: $page) {
name
tokens {
chain
@ -85,12 +115,11 @@ export function useTopTokenQuery(page: number) {
}
)
const topTokens: Record<string, TokenData> =
topTokenData.topTokenProjects?.reduce((acc, token) => {
const tokenAddress = token?.tokens?.[0].address
if (tokenAddress) {
acc[tokenAddress] = {
const topTokens: TokenData[] | undefined = topTokenData.topTokenProjects?.map((token) =>
token?.tokens?.[0].address
? {
name: token?.name,
address: token?.tokens?.[0].address,
chain: token?.tokens?.[0].chain,
symbol: token?.tokens?.[0].symbol,
price: token?.markets?.[0]?.price,
@ -112,8 +141,7 @@ export function useTopTokenQuery(page: number) {
[TimePeriod.ALL]: token?.markets?.[0]?.pricePercentChangeAll,
},
}
}
return acc
}, {} as Record<string, TokenData>) ?? {}
: ({} as TokenData)
)
return topTokens
}

@ -1,65 +0,0 @@
import { Chain, Currency } from 'graphql/data/__generated__/TopTokenQuery.graphql'
import { useTopTokenQuery } from 'graphql/data/TopTokenQuery'
import { useEffect, useState } from 'react'
export enum TimePeriod {
HOUR,
DAY,
WEEK,
MONTH,
YEAR,
ALL,
}
interface IAmount {
currency: Currency | null
value: number | null
}
export type TokenData = {
name: string | null | undefined
chain: Chain | undefined
symbol: string | null | undefined
price: IAmount | null | undefined
marketCap: IAmount | null | undefined
volume: Record<TimePeriod, IAmount | null | undefined>
percentChange: Record<TimePeriod, IAmount | null | undefined>
}
export interface UseTopTokensResult {
data: Record<string, TokenData> | null
error: string | null
loading: boolean
}
const useExplorePageQuery = (): UseTopTokensResult => {
const [data, setData] = useState<Record<string, TokenData> | null>(null)
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const FetchTopTokens = async (): Promise<Record<string, TokenData> | void> => {
try {
const topTokens = useTopTokenQuery(1)
return topTokens
} catch (e) {
setError('Error fetching top tokens')
} finally {
setLoading(false)
}
}
useEffect(() => {
setError(null)
setLoading(true)
FetchTopTokens()
.then((data) => {
if (data) setData(data)
})
.catch((e) => setError(e))
.finally(() => setLoading(false))
}, [])
return { data, error, loading }
}
export default useExplorePageQuery