mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
desktop view
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
|
||||
import handler from 'lib/api/handler';
|
||||
|
||||
const getUrl = (req: NextApiRequest) => {
|
||||
return `/v2/addresses/${ req.query.id }/coin-balance-history-by-day`;
|
||||
};
|
||||
|
||||
const requestHandler = handler(getUrl, [ 'GET' ]);
|
||||
|
||||
export default requestHandler;
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
|
||||
import getSearchParams from 'lib/api/getSearchParams';
|
||||
import handler from 'lib/api/handler';
|
||||
|
||||
const getUrl = (req: NextApiRequest) => {
|
||||
const searchParamsStr = getSearchParams(req);
|
||||
return `/v2/addresses/${ req.query.id }/coin-balance-history${ searchParamsStr ? '?' + searchParamsStr : '' }`;
|
||||
};
|
||||
|
||||
const requestHandler = handler(getUrl, [ 'GET' ]);
|
||||
|
||||
export default requestHandler;
|
||||
@@ -31,3 +31,19 @@ export interface AddressTokenBalance {
|
||||
token_id: string | null;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AddressCoinBalanceHistoryItem {
|
||||
block_number: number;
|
||||
block_timestamp: string;
|
||||
delta: string;
|
||||
transaction_hash: string | null;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AddressCoinBalanceHistoryResponse {
|
||||
items: Array<AddressCoinBalanceHistoryItem>;
|
||||
next_page_params: {
|
||||
block_number: number;
|
||||
items_count: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AddressCoinBalanceHistoryResponse } from 'types/api/address';
|
||||
import type { BlocksResponse, BlockTransactionsResponse, BlockFilters } from 'types/api/block';
|
||||
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
|
||||
import type { LogsResponse } from 'types/api/log';
|
||||
@@ -16,7 +17,8 @@ export type PaginatedQueryKeys =
|
||||
QueryKeys.txsPending |
|
||||
QueryKeys.txInternals |
|
||||
QueryKeys.txLogs |
|
||||
QueryKeys.txTokenTransfers;
|
||||
QueryKeys.txTokenTransfers |
|
||||
QueryKeys.addressCoinBalanceHistory;
|
||||
|
||||
export type PaginatedResponse<Q extends PaginatedQueryKeys> =
|
||||
Q extends (QueryKeys.blocks | QueryKeys.blocksReorgs | QueryKeys.blocksUncles) ? BlocksResponse :
|
||||
@@ -26,7 +28,8 @@ export type PaginatedResponse<Q extends PaginatedQueryKeys> =
|
||||
Q extends QueryKeys.txInternals ? InternalTransactionsResponse :
|
||||
Q extends QueryKeys.txLogs ? LogsResponse :
|
||||
Q extends QueryKeys.txTokenTransfers ? TokenTransferResponse :
|
||||
never
|
||||
Q extends QueryKeys.addressCoinBalanceHistory ? AddressCoinBalanceHistoryResponse :
|
||||
never
|
||||
|
||||
export type PaginationFilters<Q extends PaginatedQueryKeys> =
|
||||
Q extends QueryKeys.blocks ? BlockFilters :
|
||||
@@ -51,4 +54,5 @@ export const PAGINATION_FIELDS: PaginationFields = {
|
||||
[QueryKeys.txInternals]: [ 'block_number', 'items_count', 'transaction_hash', 'index', 'transaction_index' ],
|
||||
[QueryKeys.txTokenTransfers]: [ 'block_number', 'items_count', 'transaction_hash', 'index' ],
|
||||
[QueryKeys.txLogs]: [ 'items_count', 'transaction_hash', 'index' ],
|
||||
[QueryKeys.addressCoinBalanceHistory]: [ 'items_count', 'block_number' ],
|
||||
};
|
||||
|
||||
@@ -24,4 +24,6 @@ export enum QueryKeys {
|
||||
address='address',
|
||||
addressCounters='address-counters',
|
||||
addressTokenBalances='address-token-balances',
|
||||
addressCoinBalanceHistory='address-coin-balance-history',
|
||||
addressCoinBalanceHistoryByDay='address-coin-balance-history-by-day',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
|
||||
import AddressCoinBalanceChart from './coinBalance/AddressCoinBalanceChart';
|
||||
import AddressCoinBalanceHistory from './coinBalance/AddressCoinBalanceHistory';
|
||||
|
||||
interface Props {
|
||||
addressQuery: UseQueryResult<Address>;
|
||||
}
|
||||
|
||||
const AddressCoinBalance = ({ addressQuery }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<AddressCoinBalanceChart/>
|
||||
<AddressCoinBalanceHistory addressQuery={ addressQuery }/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AddressCoinBalance);
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
const AddressCoinBalanceChart = () => {
|
||||
// chart will be added after stats feature is finalized
|
||||
return <Box p={ 4 } borderColor="gray.200" borderRadius="md" borderWidth="1px">Here will be coin balance chart</Box>;
|
||||
};
|
||||
|
||||
export default AddressCoinBalanceChart;
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Box, Table, Tbody, Th, Tr } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
import { QueryKeys } from 'types/client/queries';
|
||||
|
||||
import appConfig from 'configs/app/config';
|
||||
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
|
||||
import ActionBar from 'ui/shared/ActionBar';
|
||||
import Pagination from 'ui/shared/Pagination';
|
||||
import { default as Thead } from 'ui/shared/TheadSticky';
|
||||
|
||||
import AddressCoinBalanceTableItem from './AddressCoinBalanceTableItem';
|
||||
|
||||
interface Props {
|
||||
addressQuery: UseQueryResult<Address>;
|
||||
}
|
||||
|
||||
const AddressCoinBalanceHistory = ({ addressQuery }: Props) => {
|
||||
const query = useQueryWithPages({
|
||||
apiPath: `/node-api/addresses/${ addressQuery.data?.hash }/coin-balance-history`,
|
||||
queryName: QueryKeys.addressCoinBalanceHistory,
|
||||
options: {
|
||||
enabled: Boolean(addressQuery.data),
|
||||
},
|
||||
});
|
||||
|
||||
if (query.isError || query.isLoading) {
|
||||
return <Box>loading</Box>;
|
||||
}
|
||||
|
||||
const isPaginatorHidden = !query.isLoading && !query.isError && query.pagination.page === 1 && !query.pagination.hasNextPage;
|
||||
|
||||
return (
|
||||
<Box mt={ 8 }>
|
||||
{ !isPaginatorHidden && (
|
||||
<ActionBar>
|
||||
<Pagination ml="auto" { ...query.pagination }/>
|
||||
</ActionBar>
|
||||
) }
|
||||
<Table variant="simple" size="sm">
|
||||
<Thead top={ 80 }>
|
||||
<Tr>
|
||||
<Th width="25%">Block</Th>
|
||||
<Th width="25%">Txn</Th>
|
||||
<Th width="25%">Age</Th>
|
||||
<Th width="25%" isNumeric pr={ 1 }/>
|
||||
<Th width="120px" isNumeric>Balance { appConfig.network.currency.symbol }</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{ query.data.items.map((item) => (
|
||||
<AddressCoinBalanceTableItem key={ item.block_number } { ...item }/>
|
||||
)) }
|
||||
</Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AddressCoinBalanceHistory);
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Link, Td, Tr, Text, Stat, StatHelpText, StatArrow } from '@chakra-ui/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React from 'react';
|
||||
|
||||
import type { AddressCoinBalanceHistoryItem } from 'types/api/address';
|
||||
|
||||
import { WEI, ZERO } from 'lib/consts';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
import link from 'lib/link/link';
|
||||
import Address from 'ui/shared/address/Address';
|
||||
import AddressLink from 'ui/shared/address/AddressLink';
|
||||
|
||||
type Props = AddressCoinBalanceHistoryItem;
|
||||
|
||||
const AddressCoinBalanceTableItem = (props: Props) => {
|
||||
const blockUrl = link('block', { id: String(props.block_number) });
|
||||
const deltaBn = BigNumber(props.delta).div(WEI);
|
||||
const isPositiveDelta = deltaBn.gte(ZERO);
|
||||
|
||||
return (
|
||||
<Tr>
|
||||
<Td>
|
||||
<Link href={ blockUrl } fontWeight="700">{ props.block_number }</Link>
|
||||
</Td>
|
||||
<Td>
|
||||
{ props.transaction_hash ?
|
||||
(
|
||||
<Address maxW="150px" fontWeight="700">
|
||||
<AddressLink hash={ props.transaction_hash } type="transaction"/>
|
||||
</Address>
|
||||
) :
|
||||
<Text fontWeight="700">-</Text>
|
||||
}
|
||||
</Td>
|
||||
<Td>
|
||||
<Text variant="secondary">{ dayjs(props.block_timestamp).fromNow() }</Text>
|
||||
</Td>
|
||||
<Td isNumeric pr={ 1 }>
|
||||
<Text>{ BigNumber(props.value).div(WEI).toFormat() }</Text>
|
||||
</Td>
|
||||
<Td isNumeric display="flex" justifyContent="end">
|
||||
<Stat flexGrow="0">
|
||||
<StatHelpText display="flex" mb={ 0 } alignItems="center">
|
||||
<StatArrow type={ isPositiveDelta ? 'increase' : 'decrease' }/>
|
||||
<Text as="span" color={ isPositiveDelta ? 'green.500' : 'red.500' } fontWeight={ 600 }>
|
||||
{ deltaBn.toFixed(8) }
|
||||
</Text>
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AddressCoinBalanceTableItem);
|
||||
@@ -8,6 +8,7 @@ import { QueryKeys } from 'types/client/queries';
|
||||
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
|
||||
|
||||
import useFetch from 'lib/hooks/useFetch';
|
||||
import AddressCoinBalance from 'ui/address/AddressCoinBalance';
|
||||
import AddressDetails from 'ui/address/AddressDetails';
|
||||
import Page from 'ui/shared/Page/Page';
|
||||
import PageTitle from 'ui/shared/Page/PageTitle';
|
||||
@@ -36,7 +37,7 @@ const AddressPageContent = () => {
|
||||
{ id: 'token_transfers', title: 'Token transfers', component: null },
|
||||
{ id: 'tokens', title: 'Tokens', component: null },
|
||||
{ id: 'internal_txn', title: 'Internal txn', component: null },
|
||||
{ id: 'coin_balance_history', title: 'Coin balance history', component: null },
|
||||
{ id: 'coin_balance_history', title: 'Coin balance history', component: <AddressCoinBalance addressQuery={ addressQuery }/> },
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user