Commit 22fba855 authored by isstuev's avatar isstuev

address tokens balances

parent 90ad298f
import React from 'react';
import TokenBalances from './tokens/TokenBalances';
const AddressTokens = () => {
return <TokenBalances/>;
};
export default AddressTokens;
import { Box, Button, Icon, Skeleton, Text, useColorModeValue } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import arrowIcon from 'icons/arrows/east-mini.svg';
import tokensIcon from 'icons/tokens.svg';
import { ZERO } from 'lib/consts';
import type { EnhancedData } from './utils';
import type { EnhancedData } from '../utils/tokenUtils';
import { getTokenBalanceTotal } from '../utils/tokenUtils';
interface Props {
isOpen: boolean;
......@@ -16,7 +15,7 @@ interface Props {
}
const TokenSelectButton = ({ isOpen, isLoading, onClick, data }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
const totalBn = data.reduce((result, item) => !item.usd ? result : result.plus(BigNumber(item.usd)), ZERO);
const totalBn = getTokenBalanceTotal(data);
const skeletonBgColor = useColorModeValue('white', 'black');
const handleClick = React.useCallback(() => {
......
......@@ -6,7 +6,7 @@ import link from 'lib/link/link';
import HashStringShorten from 'ui/shared/HashStringShorten';
import TokenLogo from 'ui/shared/TokenLogo';
import type { EnhancedData } from './utils';
import type { EnhancedData } from '../utils/tokenUtils';
interface Props {
data: EnhancedData;
......
......@@ -8,9 +8,9 @@ import type { TokenType } from 'types/api/tokenInfo';
import arrowIcon from 'icons/arrows/east.svg';
import searchIcon from 'icons/search.svg';
import type { Sort, EnhancedData } from '../utils/tokenUtils';
import { sortTokenGroups, sortingFns } from '../utils/tokenUtils';
import TokenSelectItem from './TokenSelectItem';
import type { Sort, EnhancedData } from './utils';
import { sortTokenGroups, sortingFns } from './utils';
interface Props {
searchTerm: string;
......
......@@ -4,8 +4,8 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
import type { Sort } from './utils';
import { calculateUsdValue, filterTokens } from './utils';
import type { Sort } from '../utils/tokenUtils';
import { calculateUsdValue, filterTokens } from '../utils/tokenUtils';
export default function useData(data: Array<AddressTokenBalance>) {
const [ searchTerm, setSearchTerm ] = React.useState('');
......
import { Box, Flex, Icon, Skeleton, Text, useColorModeValue } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import { useRouter } from 'next/router';
import React from 'react';
import appConfig from 'configs/app/config';
import walletIcon from 'icons/wallet.svg';
import useApiQuery from 'lib/api/useApiQuery';
import getCurrencyValue from 'lib/getCurrencyValue';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import { getTokenBalanceTotal, calculateUsdValue } from '../utils/tokenUtils';
const TokenBalances = () => {
const router = useRouter();
const addressQuery = useApiQuery('address', {
pathParams: { id: router.query.id?.toString() },
queryOptions: { enabled: Boolean(router.query.id) },
});
const balancesQuery = useApiQuery('address_token_balances', {
pathParams: { id: addressQuery.data?.hash },
queryOptions: { enabled: Boolean(addressQuery.data) },
});
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
if (addressQuery.isError || balancesQuery.isError) {
return <DataFetchAlert/>;
}
if (addressQuery.isLoading || balancesQuery.isLoading) {
const item = <Skeleton w={{ base: '100%', lg: '240px' }} h="82px" borderRadius="16px"/>;
return (
<Flex columnGap={ 3 } rowGap={ 3 } mt={{ base: '6px', lg: 0 }} flexDirection={{ base: 'column', lg: 'row' }}>
{ item }
{ item }
{ item }
</Flex>
);
}
const addressData = addressQuery.data;
const { valueStr: nativeValue, usd: nativeUsd } = getCurrencyValue({
value: addressData.coin_balance || '0',
accuracy: 8,
accuracyUsd: 2,
exchangeRate: addressData.exchange_rate,
decimals: String(appConfig.network.currency.decimals),
});
const tokenBalanceBn = getTokenBalanceTotal(balancesQuery.data.map(calculateUsdValue)).toFixed(2);
const totalUsd = nativeUsd ? BigNumber(nativeUsd).toNumber() + BigNumber(tokenBalanceBn).toNumber() : undefined;
const itemProps = {
p: 5,
bgColor,
borderRadius: '16px',
alignItems: 'center',
};
return (
<Flex columnGap={ 3 } rowGap={ 3 } mt={{ base: '6px', lg: 0 }} flexDirection={{ base: 'column', lg: 'row' }}>
<Flex { ...itemProps }>
<Icon as={ walletIcon } boxSize="30px" mr={ 3 }/>
<Box>
<Text variant="secondary" fontSize="xs">Net Worth</Text>
<Text fontWeight="500">{ totalUsd ? `$${ totalUsd } USD` : 'N/A' }</Text>
</Box>
</Flex>
<Flex { ...itemProps }>
<Icon as={ walletIcon } boxSize="30px" mr={ 3 }/>
<Box>
<Text variant="secondary" fontSize="xs">{ `${ appConfig.network.currency.symbol } Balance` }</Text>
<Text fontWeight="500">{ nativeUsd && `$${ nativeUsd } USD | ` } { `${ nativeValue } ${ appConfig.network.currency.symbol }` }</Text>
</Box>
</Flex>
<Flex { ...itemProps }>
<Icon as={ walletIcon } boxSize="30px" mr={ 3 }/>
<Box>
<Text variant="secondary" fontSize="xs">Tokens</Text>
<Text fontWeight="500">
{ `$${ tokenBalanceBn } USD ` }
{ Boolean(balancesQuery.data.length) && ` | ${ balancesQuery.data.length } ${ balancesQuery.data.length === 1 ? 'token' : 'tokens' }` }
</Text>
</Box>
</Flex>
</Flex>
);
};
export default React.memo(TokenBalances);
......@@ -3,6 +3,8 @@ import BigNumber from 'bignumber.js';
import type { AddressTokenBalance } from 'types/api/address';
import type { TokenType } from 'types/api/tokenInfo';
import { ZERO } from 'lib/consts';
export type EnhancedData = AddressTokenBalance & {
usd?: BigNumber ;
}
......@@ -77,3 +79,7 @@ export const calculateUsdValue = (data: AddressTokenBalance): EnhancedData => {
usd: BigNumber(data.value).div(BigNumber(10 ** decimals)).multipliedBy(BigNumber(exchangeRate)),
};
};
export const getTokenBalanceTotal = (data: Array<EnhancedData>) => {
return data.reduce((result, item) => !item.usd ? result : result.plus(BigNumber(item.usd)), ZERO);
};
......@@ -12,6 +12,7 @@ import AddressContract from 'ui/address/AddressContract';
import AddressDetails from 'ui/address/AddressDetails';
import AddressInternalTxs from 'ui/address/AddressInternalTxs';
import AddressLogs from 'ui/address/AddressLogs';
import AddressTokens from 'ui/address/AddressTokens';
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
import AddressTxs from 'ui/address/AddressTxs';
import ContractCode from 'ui/address/contract/ContractCode';
......@@ -72,7 +73,7 @@ const AddressPageContent = () => {
addressQuery.data?.has_token_transfers ?
{ id: 'token_transfers', title: 'Token transfers', component: <AddressTokenTransfers scrollRef={ tabsScrollRef }/> } :
undefined,
addressQuery.data?.has_tokens ? { id: 'tokens', title: 'Tokens', component: null } : undefined,
addressQuery.data?.has_tokens ? { id: 'tokens', title: 'Tokens', component: <AddressTokens/> } : undefined,
{ id: 'internal_txns', title: 'Internal txns', component: <AddressInternalTxs scrollRef={ tabsScrollRef }/> },
{ id: 'coin_balance_history', title: 'Coin balance history', component: <AddressCoinBalance/> },
addressQuery.data?.has_validated_blocks ?
......
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