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:
parent
0e530cf92e
commit
ac27c89a44
@ -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
|
Loading…
Reference in New Issue
Block a user