Commit 8b43fcbf authored by tom's avatar tom

refactor menu and usd values

parent 9bb47004
...@@ -15,13 +15,14 @@ import starOutlineIcon from 'icons/star_outline.svg'; ...@@ -15,13 +15,14 @@ import starOutlineIcon from 'icons/star_outline.svg';
import walletIcon from 'icons/wallet.svg'; import walletIcon from 'icons/wallet.svg';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import AddressTokenSelect from 'ui/address/details/AddressTokenSelect';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import ExternalLink from 'ui/shared/ExternalLink'; import ExternalLink from 'ui/shared/ExternalLink';
import HashStringShorten from 'ui/shared/HashStringShorten'; import HashStringShorten from 'ui/shared/HashStringShorten';
import Tokens from './details/Tokens';
interface Props { interface Props {
addressQuery: UseQueryResult<TAddress>; addressQuery: UseQueryResult<TAddress>;
} }
...@@ -97,7 +98,7 @@ const AddressDetails = ({ addressQuery }: Props) => { ...@@ -97,7 +98,7 @@ const AddressDetails = ({ addressQuery }: Props) => {
> >
{ tokenBalancesQuery.data.length > 0 ? ( { tokenBalancesQuery.data.length > 0 ? (
<> <>
<AddressTokenSelect data={ tokenBalancesQuery.data }/> <Tokens data={ tokenBalancesQuery.data }/>
<Button variant="outline" size="sm" ml={ 3 }> <Button variant="outline" size="sm" ml={ 3 }>
<Icon as={ walletIcon } boxSize={ 5 }/> <Icon as={ walletIcon } boxSize={ 5 }/>
</Button> </Button>
......
import { MenuItem, Flex, Text, useColorModeValue } from '@chakra-ui/react'; import { Flex, Text, useColorModeValue } from '@chakra-ui/react';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import React from 'react'; import React from 'react';
import type { AddressTokenBalance } from 'types/api/address'; import type { AddressTokenBalance } from 'types/api/address';
import getCurrencyValue from 'lib/getCurrencyValue';
import TokenLogo from 'ui/shared/TokenLogo'; import TokenLogo from 'ui/shared/TokenLogo';
interface Props { interface Props {
...@@ -13,8 +14,14 @@ interface Props { ...@@ -13,8 +14,14 @@ interface Props {
const AddressTokenSelect = ({ data }: Props) => { const AddressTokenSelect = ({ data }: Props) => {
const tokenDecimals = Number(data.token.decimals) || 18; const tokenDecimals = Number(data.token.decimals) || 18;
const { usd } = getCurrencyValue({
value: data.value,
accuracyUsd: 2,
exchangeRate: data.token.exchange_rate,
});
return ( return (
<MenuItem <Flex
px={ 1 } px={ 1 }
py="10px" py="10px"
display="flex" display="flex"
...@@ -22,25 +29,22 @@ const AddressTokenSelect = ({ data }: Props) => { ...@@ -22,25 +29,22 @@ const AddressTokenSelect = ({ data }: Props) => {
rowGap={ 2 } rowGap={ 2 }
borderColor={ useColorModeValue('blackAlpha.200', 'whiteAlpha.200') } borderColor={ useColorModeValue('blackAlpha.200', 'whiteAlpha.200') }
borderBottomWidth="1px" borderBottomWidth="1px"
_last={{
borderBottomWidth: '0px',
}}
_hover={{ _hover={{
bgColor: useColorModeValue('blue.50', 'gray.800'), bgColor: useColorModeValue('blue.50', 'gray.800'),
}} }}
fontSize="sm" fontSize="sm"
isFocusable={ false } cursor="pointer"
> >
<Flex alignItems="center" w="100%"> <Flex alignItems="center" w="100%">
<TokenLogo hash={ data.token.address } name={ data.token.name } boxSize={ 6 }/> <TokenLogo hash={ data.token.address } name={ data.token.name } boxSize={ 6 }/>
<Text fontWeight={ 700 } ml={ 2 }>{ data.token.name }</Text> <Text fontWeight={ 700 } ml={ 2 }>{ data.token.name }</Text>
<Text fontWeight={ 700 } ml="auto">$23 463.73</Text> { usd && <Text fontWeight={ 700 } ml="auto">${ usd }</Text> }
</Flex> </Flex>
<Flex alignItems="center" justifyContent="space-between" w="100%"> <Flex alignItems="center" justifyContent="space-between" w="100%">
<Text >{ BigNumber(data.value).dividedBy(10 ** tokenDecimals).dp(2).toFormat() } { data.token.symbol }</Text> <Text >{ BigNumber(data.value).dividedBy(10 ** tokenDecimals).dp(2).toFormat() } { data.token.symbol }</Text>
<Text >@1.001</Text> { data.token.exchange_rate && <Text >@{ data.token.exchange_rate }</Text> }
</Flex>
</Flex> </Flex>
</MenuItem>
); );
}; };
......
import { import {
Icon, Text, Button, Menu, MenuButton, MenuGroup, MenuList, Icon, Text,
Input, forwardRef, InputGroup, InputLeftElement, useColorModeValue, Input, InputGroup, InputLeftElement, useColorModeValue,
Popover, PopoverTrigger, PopoverContent, PopoverBody, Box,
useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import _groupBy from 'lodash/groupBy'; import _groupBy from 'lodash/groupBy';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
...@@ -8,28 +10,10 @@ import React from 'react'; ...@@ -8,28 +10,10 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address'; import type { AddressTokenBalance } from 'types/api/address';
import arrowIcon from 'icons/arrows/east-mini.svg';
import searchIcon from 'icons/search.svg'; import searchIcon from 'icons/search.svg';
import tokensIcon from 'icons/tokens.svg';
import AddressTokenSelectErc20 from './AddressTokenSelectErc20'; import TokenItemErc20 from './TokenItemErc20';
import TokensButton from './TokensButton';
const Trigger = forwardRef((props, ref) => {
return (
<Button
{ ...props }
ref={ ref }
size="sm"
variant="outline"
colorScheme="gray"
>
<Icon as={ tokensIcon } boxSize={ 5 } mr={ 2 }/>
<Text fontWeight={ 600 }>2</Text>
<Text whiteSpace="pre" variant="secondary" fontWeight={ 400 }> ($23 463.73 USD)</Text>
<Icon as={ arrowIcon } transform={ props.isActive ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="normal" boxSize={ 5 } ml={ 3 }/>
</Button>
);
});
interface Props { interface Props {
data: Array<AddressTokenBalance>; data: Array<AddressTokenBalance>;
...@@ -37,6 +21,7 @@ interface Props { ...@@ -37,6 +21,7 @@ interface Props {
const AddressTokenSelect = ({ data }: Props) => { const AddressTokenSelect = ({ data }: Props) => {
const [ searchTerm, setSearchTerm ] = React.useState(''); const [ searchTerm, setSearchTerm ] = React.useState('');
const { isOpen, onToggle, onClose } = useDisclosure();
const handleInputChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => { const handleInputChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.target.value); setSearchTerm(event.target.value);
...@@ -54,11 +39,12 @@ const AddressTokenSelect = ({ data }: Props) => { ...@@ -54,11 +39,12 @@ const AddressTokenSelect = ({ data }: Props) => {
const groupedData = _groupBy(filteredData, 'token.type'); const groupedData = _groupBy(filteredData, 'token.type');
return ( return (
<Menu> <Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
{ ({ isOpen }) => ( <PopoverTrigger>
<> <TokensButton isOpen={ isOpen } onClick={ onToggle } data={ data }/>
<MenuButton isActive={ isOpen } as={ Trigger }/> </PopoverTrigger>
<MenuList px={ 4 } py={ 6 } w="355px" bgColor={ bgColor } boxShadow="2xl"> <PopoverContent w="355px" maxH="450px" overflowY="scroll">
<PopoverBody px={ 4 } py={ 6 } bgColor={ bgColor } boxShadow="2xl" >
<InputGroup size="xs" mb={ 5 }> <InputGroup size="xs" mb={ 5 }>
<InputLeftElement > <InputLeftElement >
<Icon as={ searchIcon } boxSize={ 4 } color={ searchIconColor }/> <Icon as={ searchIcon } boxSize={ 4 } color={ searchIconColor }/>
...@@ -73,14 +59,15 @@ const AddressTokenSelect = ({ data }: Props) => { ...@@ -73,14 +59,15 @@ const AddressTokenSelect = ({ data }: Props) => {
/> />
</InputGroup> </InputGroup>
{ groupedData['ERC-20'] && ( { groupedData['ERC-20'] && (
<MenuGroup title={ `ERC-20 tokens (${ groupedData['ERC-20'].length })` } mb={ 3 } mt={ 0 } mx={ 0 } color="gray.500"> <Box color="gray.500">
{ groupedData['ERC-20'].map((data) => <AddressTokenSelectErc20 key={ data.token.address } data={ data }/>) } <Text mb={ 3 } color="gray.500" fontWeight={ 600 } fontSize="sm">ERC-20 tokens ({ groupedData['ERC-20'].length })</Text>
</MenuGroup> { groupedData['ERC-20'].map((data) => <TokenItemErc20 key={ data.token.address } data={ data }/>) }
) } </Box>
</MenuList>
</>
) } ) }
</Menu> { filteredData.length === 0 && searchTerm && <Text fontSize="sm">Could not find any matches.</Text> }
</PopoverBody>
</PopoverContent>
</Popover>
); );
}; };
......
import { Button, Icon, Text } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
import arrowIcon from 'icons/arrows/east-mini.svg';
import tokensIcon from 'icons/tokens.svg';
import { ZERO } from 'lib/consts';
interface Props {
isOpen: boolean;
onClick: () => void;
data: Array<AddressTokenBalance>;
}
const TokensButton = ({ isOpen, onClick, data }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
const usdBn = data.reduce((result, item) => {
if (!item.token.exchange_rate) {
return result;
}
const decimals = Number(item.token.decimals || '18');
return BigNumber(item.value).div(BigNumber(10 ** decimals)).multipliedBy(BigNumber(item.token.exchange_rate));
}, ZERO);
return (
<Button
ref={ ref }
size="sm"
variant="outline"
colorScheme="gray"
onClick={ onClick }
>
<Icon as={ tokensIcon } boxSize={ 4 } mr={ 2 }/>
<Text fontWeight={ 600 }>{ data.length }</Text>
<Text whiteSpace="pre" variant="secondary" fontWeight={ 400 }> (${ usdBn.toFixed(2) })</Text>
<Icon as={ arrowIcon } transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="normal" boxSize={ 5 } ml={ 3 }/>
</Button>
);
};
export default React.forwardRef(TokensButton);
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