Skip to content

Commit

Permalink
add account balance history
Browse files Browse the repository at this point in the history
  • Loading branch information
marcusDesk committed Nov 15, 2024
1 parent 5cedc63 commit db64db3
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 0 deletions.
4 changes: 4 additions & 0 deletions explorer/src/components/Consensus/Account/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { AccountExtrinsicList } from './AccountExtrinsicList'
import { AccountGraphs } from './AccountGraphs'
import { AccountRewardsHistory } from './AccountRewardsHistory'
import { AccountTransfersList } from './AccountTransfersList'
import { BalanceHistory } from './BalanceHistory'
import { QUERY_ACCOUNT_BY_ID } from './query'

export const Account: FC = () => {
Expand Down Expand Up @@ -86,6 +87,9 @@ export const Account: FC = () => {
<Tab title='Transfers'>
<AccountTransfersList accountId={accountId} />
</Tab>
<Tab title='Balance History'>
<BalanceHistory accountId={accountId} />
</Tab>
</PageTabs>
</>
) : (
Expand Down
203 changes: 203 additions & 0 deletions explorer/src/components/Consensus/Account/BalanceHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/* eslint-disable camelcase */
import { useApolloClient } from '@apollo/client'
import { SortingState } from '@tanstack/react-table'
import { SortedTable } from 'components/common/SortedTable'
import { Spinner } from 'components/common/Spinner'
import { Tooltip } from 'components/common/Tooltip'
import { NotFound } from 'components/layout/NotFound'
import { PAGE_SIZE } from 'constants/general'
import { INTERNAL_ROUTES, Routes } from 'constants/routes'
import { formatUnits } from 'ethers'
import {
BalanceHistoryByAccountIdQuery,
BalanceHistoryByAccountIdQueryVariables,
Order_By as OrderBy,
Consensus_Transfers_Select_Column as TransferColumn,
Consensus_Transfers_Bool_Exp as TransferWhere,
} from 'gql/graphql'
import useChains from 'hooks/useChains'
import { useSquidQuery } from 'hooks/useSquidQuery'
import { useWindowFocus } from 'hooks/useWindowFocus'
import Link from 'next/link'
import { FC, useCallback, useEffect, useMemo, useState } from 'react'
import { useInView } from 'react-intersection-observer'
import type { Cell } from 'types/table'
import { downloadFullData } from 'utils/downloadFullData'
import { bigNumberToNumber } from 'utils/number'
import { countTablePages } from 'utils/table'
import { QUERY_ACCOUNT_BALANCE_HISTORY } from './query'

type Props = {
accountId: string
}

type Row = BalanceHistoryByAccountIdQuery['consensus_account_histories'][0]

export const BalanceHistory: FC<Props> = ({ accountId }) => {
const { ref, inView } = useInView()
const [sorting, setSorting] = useState<SortingState>([
{ id: TransferColumn.CreatedAt, desc: true },
])
const [pagination, setPagination] = useState({
pageSize: PAGE_SIZE,
pageIndex: 0,
})
const { network, tokenSymbol } = useChains()
const apolloClient = useApolloClient()
const inFocus = useWindowFocus()

const orderBy = useMemo(
() =>
sorting && sorting.length > 0
? sorting[0].id.endsWith('aggregate')
? { [sorting[0].id]: sorting[0].desc ? { count: OrderBy.Desc } : { count: OrderBy.Asc } }
: { [sorting[0].id]: sorting[0].desc ? OrderBy.Desc : OrderBy.Asc }
: { id: OrderBy.Asc },
[sorting],
)

const where: TransferWhere = useMemo(() => ({ id: { _eq: accountId } }), [accountId])

const variables = useMemo(() => {
return {
limit: pagination.pageSize,
offset: pagination.pageIndex > 0 ? pagination.pageIndex * pagination.pageSize : undefined,
orderBy,
where,
}
}, [orderBy, pagination.pageIndex, pagination.pageSize, where])

const { data, loading, setIsVisible } = useSquidQuery<
BalanceHistoryByAccountIdQuery,
BalanceHistoryByAccountIdQueryVariables
>(QUERY_ACCOUNT_BALANCE_HISTORY, {
variables,
skip: !inFocus,
pollInterval: 6000,
})

const fullDataDownloader = useCallback(
() =>
downloadFullData(apolloClient, QUERY_ACCOUNT_BALANCE_HISTORY, 'consensus_account_histories', {
orderBy,
where,
}),
[apolloClient, orderBy, where],
)

const histories = useMemo(() => data && data.consensus_account_histories, [data])
const totalCount = useMemo(
() =>
data && data.consensus_account_histories_aggregate
? data.consensus_account_histories_aggregate.aggregate?.count
: 0,
[data],
)
const pageCount = useMemo(
() => (totalCount ? countTablePages(totalCount, pagination.pageSize) : 0),
[totalCount, pagination.pageSize],
)

const columns = useMemo(
() => [
{
accessorKey: 'created_at',
header: 'Block',
enableSorting: true,
cell: ({ row }: Cell<Row>) => (
<div key={`created_at-${row.original.id}`} className='row flex items-center gap-3'>
<Link
data-testid={`transfer-created_at-${row.index}`}
href={INTERNAL_ROUTES.blocks.id.page(
network,
Routes.consensus,
row.original.created_at,
)}
className='hover:text-primaryAccent'
>
<div>{row.original.created_at}</div>
</Link>
</div>
),
},
{
accessorKey: 'nonce',
header: 'Nonce',
enableSorting: true,
cell: ({ row }: Cell<Row>) => (
<div key={`${row.original.id}-nonce-${row.index}`}>{row.original.nonce}</div>
),
},
{
accessorKey: 'free',
header: 'Free',
enableSorting: true,
cell: ({ row }: Cell<Row>) => (
<div key={`${row.original.id}-free-${row.index}`}>
<Tooltip text={`${formatUnits(row.original.free)} ${tokenSymbol}`}>
{`${bigNumberToNumber(row.original.free, 6)} ${tokenSymbol}`}
</Tooltip>
</div>
),
},
{
accessorKey: 'reserved',
header: 'Reserved',
enableSorting: true,
cell: ({ row }: Cell<Row>) => (
<div key={`${row.original.id}-reserved-${row.index}`}>
<Tooltip text={`${formatUnits(row.original.reserved)} ${tokenSymbol}`}>
{`${bigNumberToNumber(row.original.reserved, 6)} ${tokenSymbol}`}
</Tooltip>
</div>
),
},
{
accessorKey: 'total',
header: 'Total',
enableSorting: true,
cell: ({ row }: Cell<Row>) => (
<div key={`${row.original.id}-total-${row.index}`}>
<Tooltip text={`${formatUnits(row.original.total)} ${tokenSymbol}`}>
{`${bigNumberToNumber(row.original.total, 6)} ${tokenSymbol}`}
</Tooltip>
</div>
),
},
],
[network, tokenSymbol],
)

const noData = useMemo(() => {
if (loading) return <Spinner isSmall />
if (!data) return <NotFound />
return null
}, [data, loading])

useEffect(() => {
setIsVisible(inView)
}, [inView, setIsVisible])

return (
<div className='flex w-full flex-col sm:mt-0'>
<div ref={ref}>
{!loading && histories ? (
<SortedTable
data={histories}
columns={columns}
showNavigation={true}
sorting={sorting}
onSortingChange={setSorting}
pagination={pagination}
pageCount={pageCount}
onPaginationChange={setPagination}
filename='account-balance-history'
fullDataDownloader={fullDataDownloader}
/>
) : (
noData
)}
</div>
</div>
)
}
25 changes: 25 additions & 0 deletions explorer/src/components/Consensus/Account/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,31 @@ export const QUERY_ACCOUNT_TRANSFERS = gql`
}
`

export const QUERY_ACCOUNT_BALANCE_HISTORY = gql`
query BalanceHistoryByAccountId(
$limit: Int!
$offset: Int
$where: consensus_account_histories_bool_exp
$orderBy: [consensus_account_histories_order_by!]!
) {
consensus_account_histories_aggregate(where: $where) {
aggregate {
count
}
}
consensus_account_histories(order_by: $orderBy, limit: $limit, offset: $offset, where: $where) {
id: uuid
reserved
total
nonce
free
created_at
updated_at
_block_range
}
}
`

export const QUERY_ALL_REWARDS_FOR_ACCOUNT_BY_ID = gql`
query AllRewardForAccountById($accountId: String!) {
consensus_rewards(where: { account_id: { _eq: $accountId }, amount: { _gt: 0 } }, limit: 1) {
Expand Down

0 comments on commit db64db3

Please sign in to comment.