feat: polish select (#3160)
* feat: filter selected currency from select * test: use infura urls * fix: load native with chain * fix: use currencyId for key * feat: switch currencies when selecting other * fix: resolve merge conflict name
This commit is contained in:
parent
567fb0181c
commit
b501974a76
@ -20,6 +20,7 @@ import {
|
||||
import AutoSizer from 'react-virtualized-auto-sizer'
|
||||
import { areEqual, FixedSizeList, FixedSizeListProps } from 'react-window'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { currencyId } from 'utils/currencyId'
|
||||
|
||||
import { BaseButton } from '../Button'
|
||||
import Column from '../Column'
|
||||
@ -107,10 +108,7 @@ function TokenOption({ index, value, style }: TokenOptionProps) {
|
||||
)
|
||||
}
|
||||
|
||||
const itemKey = (index: number, tokens: ItemData) => {
|
||||
if (tokens[index].isNative) return 'native'
|
||||
return tokens[index].wrapped.address
|
||||
}
|
||||
const itemKey = (index: number, tokens: ItemData) => currencyId(tokens[index])
|
||||
const ItemRow = memo(function ItemRow({
|
||||
data: tokens,
|
||||
index,
|
||||
|
@ -2,7 +2,8 @@ import { t, Trans } from '@lingui/macro'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { useQueryTokenList } from 'lib/hooks/useTokenList'
|
||||
import styled, { ThemedText } from 'lib/theme'
|
||||
import { ElementRef, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { ElementRef, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { currencyId } from 'utils/currencyId'
|
||||
|
||||
import Column from '../Column'
|
||||
import Dialog, { Header } from '../Dialog'
|
||||
@ -17,14 +18,18 @@ const SearchInput = styled(StringInput)`
|
||||
${inputCss}
|
||||
`
|
||||
|
||||
export function TokenSelectDialog({ onSelect }: { onSelect: (token: Currency) => void }) {
|
||||
interface TokenSelectDialogProps {
|
||||
value?: Currency
|
||||
onSelect: (token: Currency) => void
|
||||
}
|
||||
|
||||
export function TokenSelectDialog({ value, onSelect }: TokenSelectDialogProps) {
|
||||
const [query, setQuery] = useState('')
|
||||
const tokens = useQueryTokenList(query)
|
||||
const queriedTokens = useQueryTokenList(query)
|
||||
const tokens = useMemo(() => queriedTokens.filter((token) => token !== value), [queriedTokens, value])
|
||||
|
||||
const baseTokens: Currency[] = [] // TODO(zzmp): Add base tokens to token list functionality
|
||||
|
||||
// TODO(zzmp): Disable already selected tokens (passed as props?)
|
||||
|
||||
const input = useRef<HTMLInputElement>(null)
|
||||
useEffect(() => input.current?.focus(), [input])
|
||||
|
||||
@ -49,7 +54,7 @@ export function TokenSelectDialog({ onSelect }: { onSelect: (token: Currency) =>
|
||||
{Boolean(baseTokens.length) && (
|
||||
<Row pad={0.75} gap={0.25} justify="flex-start" flex>
|
||||
{baseTokens.map((token) => (
|
||||
<TokenBase value={token} onClick={onSelect} key={token.wrapped.address} />
|
||||
<TokenBase value={token} onClick={onSelect} key={currencyId(token)} />
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
@ -81,7 +86,7 @@ export default function TokenSelect({ value, collapsed, disabled, onSelect }: To
|
||||
<TokenButton value={value} collapsed={collapsed} disabled={disabled} onClick={() => setOpen(true)} />
|
||||
{open && (
|
||||
<Dialog color="module" onClose={() => setOpen(false)}>
|
||||
<TokenSelectDialog onSelect={selectAndClose} />
|
||||
<TokenSelectDialog value={value} onSelect={selectAndClose} />
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { INFURA_NETWORK_URLS } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from 'constants/locales'
|
||||
import Widget from 'lib/components/Widget'
|
||||
import { darkTheme, defaultTheme, lightTheme } from 'lib/theme'
|
||||
import { ReactNode, useEffect, useMemo } from 'react'
|
||||
import { useSelect, useValue } from 'react-cosmos/fixture'
|
||||
import { initializeConnector } from 'widgets-web3-react/core'
|
||||
import { MetaMask } from 'widgets-web3-react/metamask'
|
||||
|
||||
import { metaMask } from '../connectors/metaMask'
|
||||
import { URLS } from '../connectors/network'
|
||||
export const [metaMask] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
|
||||
|
||||
export default function Wrapper({ children }: { children: ReactNode }) {
|
||||
const [width] = useValue('width', { defaultValue: 360 })
|
||||
@ -21,8 +23,8 @@ export default function Wrapper({ children }: { children: ReactNode }) {
|
||||
|
||||
const NO_JSON_RPC = 'None'
|
||||
const [jsonRpcEndpoint] = useSelect('JSON-RPC', {
|
||||
defaultValue: URLS[SupportedChainId.MAINNET][0] || NO_JSON_RPC,
|
||||
options: [NO_JSON_RPC, ...Object.values(URLS).flat()],
|
||||
defaultValue: INFURA_NETWORK_URLS[SupportedChainId.MAINNET],
|
||||
options: [NO_JSON_RPC, ...Object.values(INFURA_NETWORK_URLS).sort()],
|
||||
})
|
||||
|
||||
const NO_PROVIDER = 'None'
|
||||
|
@ -1,4 +0,0 @@
|
||||
import { initializeConnector } from 'widgets-web3-react/core'
|
||||
import { MetaMask } from 'widgets-web3-react/metamask'
|
||||
|
||||
export const [metaMask, hooks] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
|
@ -1,14 +0,0 @@
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
|
||||
const ALCHEMY_KEY = '-mzwnEVG3Ssm75WVbmsEpYiekfTF3W1z'
|
||||
const alchemyUrl = (network: string) => `https://${network}.alchemyapi.io/v2/${ALCHEMY_KEY}`
|
||||
|
||||
export const URLS = {
|
||||
[SupportedChainId.MAINNET]: [alchemyUrl('eth-mainnet')],
|
||||
[SupportedChainId.ROPSTEN]: [alchemyUrl('eth-ropsten')],
|
||||
[SupportedChainId.RINKEBY]: [alchemyUrl('eth-rinkeby')],
|
||||
[SupportedChainId.GOERLI]: [alchemyUrl('eth-goerli')],
|
||||
[SupportedChainId.KOVAN]: [alchemyUrl('eth-kovan')],
|
||||
[SupportedChainId.OPTIMISM]: [alchemyUrl('optimism-mainnet')],
|
||||
[SupportedChainId.ARBITRUM_ONE]: [alchemyUrl('arbitrum-mainnet')],
|
||||
}
|
@ -6,25 +6,15 @@ import { amountAtom, Field, independentFieldAtom, swapAtom } from 'lib/state/swa
|
||||
import { useCallback, useMemo } from 'react'
|
||||
export { default as useSwapInfo } from './useSwapInfo'
|
||||
|
||||
export function useSwapCurrency(field: Field): [Currency | undefined, (currency?: Currency) => void] {
|
||||
const atom = useMemo(() => pickAtom(swapAtom, field), [field])
|
||||
return useAtom(atom)
|
||||
}
|
||||
|
||||
export function useSwapAmount(field: Field): [string | undefined, (amount: string) => void] {
|
||||
const amount = useAtomValue(amountAtom)
|
||||
const independentField = useAtomValue(independentFieldAtom)
|
||||
const value = useMemo(() => (independentField === field ? amount : undefined), [amount, independentField, field])
|
||||
const updateSwap = useUpdateAtom(swapAtom)
|
||||
const updateAmount = useCallback(
|
||||
(amount: string) =>
|
||||
updateSwap((swap) => {
|
||||
swap.independentField = field
|
||||
swap.amount = amount
|
||||
}),
|
||||
[field, updateSwap]
|
||||
)
|
||||
return [value, updateAmount]
|
||||
function otherField(field: Field) {
|
||||
switch (field) {
|
||||
case Field.INPUT:
|
||||
return Field.OUTPUT
|
||||
break
|
||||
case Field.OUTPUT:
|
||||
return Field.INPUT
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
export function useSwitchSwapCurrencies() {
|
||||
@ -45,3 +35,38 @@ export function useSwitchSwapCurrencies() {
|
||||
})
|
||||
}, [update])
|
||||
}
|
||||
|
||||
export function useSwapCurrency(field: Field): [Currency | undefined, (currency?: Currency) => void] {
|
||||
const atom = useMemo(() => pickAtom(swapAtom, field), [field])
|
||||
const otherAtom = useMemo(() => pickAtom(swapAtom, otherField(field)), [field])
|
||||
const [currency, setCurrency] = useAtom(atom)
|
||||
const otherCurrency = useAtomValue(otherAtom)
|
||||
const switchSwapCurrencies = useSwitchSwapCurrencies()
|
||||
const setOrSwitchCurrency = useCallback(
|
||||
(currency?: Currency) => {
|
||||
if (currency === otherCurrency) {
|
||||
switchSwapCurrencies()
|
||||
} else {
|
||||
setCurrency(currency)
|
||||
}
|
||||
},
|
||||
[otherCurrency, setCurrency, switchSwapCurrencies]
|
||||
)
|
||||
return [currency, setOrSwitchCurrency]
|
||||
}
|
||||
|
||||
export function useSwapAmount(field: Field): [string | undefined, (amount: string) => void] {
|
||||
const amount = useAtomValue(amountAtom)
|
||||
const independentField = useAtomValue(independentFieldAtom)
|
||||
const value = useMemo(() => (independentField === field ? amount : undefined), [amount, independentField, field])
|
||||
const updateSwap = useUpdateAtom(swapAtom)
|
||||
const updateAmount = useCallback(
|
||||
(amount: string) =>
|
||||
updateSwap((swap) => {
|
||||
swap.independentField = field
|
||||
swap.amount = amount
|
||||
}),
|
||||
[field, updateSwap]
|
||||
)
|
||||
return [value, updateAmount]
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { nativeOnChain } from 'constants/tokens'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
|
||||
import { useTokenBalances } from 'lib/hooks/useCurrencyBalance'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
import { useMemo } from 'react'
|
||||
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
|
||||
|
||||
@ -9,7 +9,7 @@ import { getTokenFilter } from './filtering'
|
||||
import { tokenComparator, useSortTokensByQuery } from './sorting'
|
||||
|
||||
export function useQueryTokens(query: string, tokens: WrappedTokenInfo[]) {
|
||||
const { account } = useActiveWeb3React()
|
||||
const { chainId, account } = useActiveWeb3React()
|
||||
const balances = useTokenBalances(account, tokens)
|
||||
const sortedTokens = useMemo(
|
||||
// Create a new array because sort is in-place and returns a referentially equivalent array.
|
||||
@ -23,7 +23,7 @@ export function useQueryTokens(query: string, tokens: WrappedTokenInfo[]) {
|
||||
|
||||
const queriedTokens = useSortTokensByQuery(debouncedQuery, filteredTokens)
|
||||
|
||||
const native = useNativeCurrency()
|
||||
const native = useMemo(() => chainId && nativeOnChain(chainId), [chainId])
|
||||
return useMemo(() => {
|
||||
if (native && filter(native)) {
|
||||
return [native, ...queriedTokens]
|
||||
|
Loading…
Reference in New Issue
Block a user