Commit 5383436c authored by Jordan Frankfurt's avatar Jordan Frankfurt Committed by GitHub

feat(widgets): empty token list on network alert (#3627)

* feat(widgets): empty token list on network alert

* make it work

* pr review

* split dialog header out of tokenselect

* correctly filter token list case

* find -> some

* pr feedback

* clean up query hooks
parent 521f3aae
import { tokens } from '@uniswap/default-token-list'
import { TokenInfo } from '@uniswap/token-lists'
import { SupportedChainId } from 'constants/chains'
import { DAI, USDC_MAINNET } from 'constants/tokens'
import { useUpdateAtom } from 'jotai/utils'
import { TokenListProvider } from 'lib/hooks/useTokenList'
import { useEffect } from 'react'
import { useSelect, useValue } from 'react-cosmos/fixture'
......@@ -56,16 +60,47 @@ function Fixture() {
})
const [defaultOutputAmount] = useValue('defaultOutputAmount', { defaultValue: 0 })
const tokenListNameMap: Record<string, TokenInfo[] | string> = {
'default list': tokens,
'mainnet only': tokens.filter((token) => SupportedChainId.MAINNET === token.chainId),
'arbitrum only': [
{
logoURI: 'https://assets.coingecko.com/coins/images/9956/thumb/4943.png?1636636734',
chainId: 42161,
address: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
name: 'Dai Stablecoin',
symbol: 'DAI',
decimals: 18,
},
{
logoURI: 'https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389',
chainId: 42161,
address: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
name: 'USD Coin (Arb1)',
symbol: 'USDC',
decimals: 6,
},
],
}
const tokenListOptions = Object.keys(tokenListNameMap)
const [tokenListName] = useSelect('tokenList', {
options: tokenListOptions,
defaultValue: tokenListOptions[0],
})
return (
<Swap
convenienceFee={convenienceFee}
convenienceFeeRecipient={convenienceFeeRecipient}
defaultInputTokenAddress={optionsToAddressMap[defaultInputToken]}
defaultInputAmount={defaultInputAmount}
defaultOutputTokenAddress={optionsToAddressMap[defaultOutputToken]}
defaultOutputAmount={defaultOutputAmount}
onConnectWallet={() => console.log('onConnectWallet')} // this handler is included as a test of functionality, but only logs
/>
<TokenListProvider list={tokenListNameMap[tokenListName]}>
<Swap
convenienceFee={convenienceFee}
convenienceFeeRecipient={convenienceFeeRecipient}
defaultInputTokenAddress={optionsToAddressMap[defaultInputToken]}
defaultInputAmount={defaultInputAmount}
defaultOutputTokenAddress={optionsToAddressMap[defaultOutputToken]}
defaultOutputAmount={defaultOutputAmount}
onConnectWallet={() => console.log('onConnectWallet')} // this handler is included as a test of functionality, but only logs
/>
</TokenListProvider>
)
}
......
......@@ -2,6 +2,7 @@ import 'setimmediate'
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import TokenSelect from 'lib/components/TokenSelect'
import { loadingTransitionCss } from 'lib/css/loading'
import styled, { keyframes, ThemedText } from 'lib/theme'
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
......@@ -10,7 +11,6 @@ import Button from '../Button'
import Column from '../Column'
import { DecimalInput } from '../Input'
import Row from '../Row'
import TokenSelect from '../TokenSelect'
const TokenInputRow = styled(Row)`
grid-template-columns: 1fr;
......
......@@ -8,7 +8,7 @@ export default function Fixture() {
return (
<Modal color="module">
<TokenListProvider list={DEFAULT_TOKEN_LIST.tokens}>
<TokenSelectDialog onSelect={() => void 0} />
<TokenSelectDialog onSelect={() => void 0} onClose={() => void 0} />
</TokenListProvider>
</Modal>
)
......
import { Trans } from '@lingui/macro'
import { HelpCircle } from 'lib/icons'
import styled, { css, ThemedText } from 'lib/theme'
import Column from '../Column'
const HelpCircleIcon = styled(HelpCircle)`
height: 64px;
margin-bottom: 12px;
stroke: ${({ theme }) => theme.secondary};
width: 64px;
`
const wrapperCss = css`
display: flex;
height: 80%;
text-align: center;
width: 100%;
`
export default function NoTokensAvailableOnNetwork() {
return (
<Column align="center" justify="center" css={wrapperCss}>
<HelpCircleIcon />
<ThemedText.Body1 color="primary">
<Trans>No tokens are available on this network. Please switch to another network.</Trans>
</ThemedText.Body1>
</Column>
)
}
import { t, Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { Header as DialogHeader } from 'lib/components/Dialog'
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import useTokenList, { useIsTokenListLoaded, useQueryCurrencies } from 'lib/hooks/useTokenList'
import useTokenList, { useIsTokenListLoaded, useQueryTokens } from 'lib/hooks/useTokenList'
import styled, { ThemedText } from 'lib/theme'
import { ElementRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { currencyId } from 'utils/currencyId'
import Column from '../Column'
import Dialog, { Header } from '../Dialog'
import Dialog from '../Dialog'
import { inputCss, StringInput } from '../Input'
import Row from '../Row'
import Rule from '../Rule'
import TokenBase from './TokenBase'
import NoTokensAvailableOnNetwork from './NoTokensAvailableOnNetwork'
import TokenButton from './TokenButton'
import TokenOptions from './TokenOptions'
import TokenOptionsSkeleton from './TokenOptionsSkeleton'
......@@ -42,12 +42,13 @@ function useAreBalancesLoaded(): boolean {
interface TokenSelectDialogProps {
value?: Currency
onSelect: (token: Currency) => void
onClose: () => void
}
export function TokenSelectDialog({ value, onSelect }: TokenSelectDialogProps) {
export function TokenSelectDialog({ value, onSelect, onClose }: TokenSelectDialogProps) {
const [query, setQuery] = useState('')
const queriedTokens = useQueryCurrencies(query)
const tokens = useMemo(() => queriedTokens?.filter((token) => token !== value), [queriedTokens, value])
const list = useTokenList()
const tokens = useQueryTokens(query, list)
const isTokenListLoaded = useIsTokenListLoaded()
const areBalancesLoaded = useAreBalancesLoaded()
......@@ -65,16 +66,26 @@ export function TokenSelectDialog({ value, onSelect }: TokenSelectDialogProps) {
[query, areBalancesLoaded, isTokenListLoaded]
)
const baseTokens: Currency[] = [] // TODO(zzmp): Add base tokens to token list functionality
const input = useRef<HTMLInputElement>(null)
useEffect(() => input.current?.focus({ preventScroll: true }), [input])
const [options, setOptions] = useState<ElementRef<typeof TokenOptions> | null>(null)
const { chainId } = useActiveWeb3React()
const listHasTokens = useMemo(() => list.some((token) => token.chainId === chainId), [chainId, list])
if (!listHasTokens && isLoaded) {
return (
<Dialog color="module" onClose={onClose}>
<DialogHeader title={<Trans>Select a token</Trans>} />
<NoTokensAvailableOnNetwork />
</Dialog>
)
}
return (
<>
<Header title={<Trans>Select a token</Trans>} />
<Dialog color="module" onClose={onClose}>
<DialogHeader title={<Trans>Select a token</Trans>} />
<Column gap={0.75}>
<Row pad={0.75} grow>
<ThemedText.Body1>
......@@ -88,13 +99,6 @@ export function TokenSelectDialog({ value, onSelect }: TokenSelectDialogProps) {
/>
</ThemedText.Body1>
</Row>
{Boolean(baseTokens.length) && (
<Row pad={0.75} gap={0.25} justify="flex-start" flex>
{baseTokens.map((token) => (
<TokenBase value={token} onClick={onSelect} key={currencyId(token)} />
))}
</Row>
)}
<Rule padded />
</Column>
{isLoaded ? (
......@@ -112,7 +116,7 @@ export function TokenSelectDialog({ value, onSelect }: TokenSelectDialogProps) {
) : (
<TokenOptionsSkeleton />
)}
</>
</Dialog>
)
}
......@@ -138,11 +142,7 @@ export default memo(function TokenSelect({ value, collapsed, disabled, onSelect
return (
<>
<TokenButton value={value} collapsed={collapsed} disabled={disabled} onClick={onOpen} />
{open && (
<Dialog color="module" onClose={() => setOpen(false)}>
<TokenSelectDialog value={value} onSelect={selectAndClose} />
</Dialog>
)}
{open && <TokenSelectDialog value={value} onSelect={selectAndClose} onClose={() => setOpen(false)} />}
</>
)
})
import { NativeCurrency, Token } from '@uniswap/sdk-core'
import { Token } from '@uniswap/sdk-core'
import { TokenInfo, TokenList } from '@uniswap/token-lists'
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
import resolveENSContentHash from 'lib/utils/resolveENSContentHash'
......@@ -6,10 +6,11 @@ import { createContext, PropsWithChildren, useCallback, useContext, useEffect, u
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
import fetchTokenList from './fetchTokenList'
import { useQueryTokens } from './querying'
import { ChainTokenMap, tokensToChainTokenMap } from './utils'
import { validateTokens } from './validateTokenList'
export { useQueryTokens } from './useQueryTokens'
export const DEFAULT_TOKEN_LIST = 'https://gateway.ipfs.io/ipns/tokens.uniswap.org'
const MISSING_PROVIDER = Symbol()
......@@ -52,10 +53,6 @@ export function useTokenMap(): TokenMap {
}, [tokenMap])
}
export function useQueryCurrencies(query = ''): (WrappedTokenInfo | NativeCurrency)[] {
return useQueryTokens(query, useTokenList())
}
export function TokenListProvider({
list = DEFAULT_TOKEN_LIST,
children,
......
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