Files
explore/ui/addresses/AddressesTableItem.tsx
zeekay 5bbb57995a top accounts: read the tags the list actually carries
The addresses list endpoint returns a projection of an address — no tags, no
name, no implementations. AddressesListItem guarded with `public_tags !== null`,
which is true of an absent field, so every visit to /accounts read `.length` off
undefined and the whole page fell to the error boundary. The type said the field
was always present, so nothing caught it.

Partial<AddressParam> states what the endpoint sends, and both read sites reach
for the tags the same optional way.

The error screen it fell to had its own defect: the status glyph is an
inline-block div and gui's H1 renders inline, so the two shared a line box and
"500" ran into "Oops! Something went wrong". The screen is a stack; it now says
so. The heading's own top margin was being outranked by gui's atomic reset.
2026-08-28 23:45:54 -07:00

93 lines
2.8 KiB
TypeScript

import BigNumber from 'bignumber.js';
import React from 'react';
import type { AddressesItem } from 'types/api/addresses';
import config from 'configs/app';
import { Skeleton } from '@luxfi/ui/skeleton';
import { TableCell, TableRow } from '@luxfi/ui/table';
import { Tag } from '@luxfi/ui/tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import SimpleValue from 'ui/shared/value/SimpleValue';
type Props = {
item: AddressesItem;
index: number;
totalSupply: BigNumber;
hasPercentage: boolean;
isLoading?: boolean;
};
const AddressesTableItem = ({
item,
index,
totalSupply,
hasPercentage,
isLoading,
}: Props) => {
const addressBalance = BigNumber(item.coin_balance || 0).div(BigNumber(10 ** config.chain.currency.decimals));
// On pruned nodes, coin_balance may be null even for addresses with transactions.
// Show "Pending" instead of a misleading "0".
const isBalancePending = item.coin_balance === null && Number(item.transactions_count) > 0;
return (
<TableRow>
<TableCell>
<Skeleton loading={ isLoading } display="inline-block" minW={ 6 } lineHeight="24px">
{ index }
</Skeleton>
</TableCell>
<TableCell>
<div className="flex items-center gap-x-2">
<AddressEntity
address={ item }
isLoading={ isLoading }
className="font-bold my-[2px]"
/>
{ item.public_tags?.map(tag => (
<Tag key={ tag.label } loading={ isLoading } truncated>{ tag.display_name }</Tag>
)) }
</div>
</TableCell>
<TableCell isNumeric>
{ isBalancePending ? (
<Skeleton loading={ isLoading } display="inline-block" lineHeight="24px">
<span className="text-[var(--color-text-secondary)] text-sm">Pending</span>
</Skeleton>
) : (
<SimpleValue
value={ addressBalance }
loading={ isLoading }
lineHeight="24px"
/>
) }
</TableCell>
{ hasPercentage && (
<TableCell isNumeric>
{ isBalancePending ? (
<Skeleton loading={ isLoading } display="inline-block" lineHeight="24px">
<span className="text-[var(--color-text-secondary)] text-sm">Pending</span>
</Skeleton>
) : (
<SimpleValue
value={ addressBalance.div(totalSupply).multipliedBy(100) }
loading={ isLoading }
postfix="%"
lineHeight="24px"
/>
) }
</TableCell>
) }
<TableCell isNumeric>
<Skeleton loading={ isLoading } display="inline-block" lineHeight="24px">
{ Number(item.transactions_count).toLocaleString() }
</Skeleton>
</TableCell>
</TableRow>
);
};
export default React.memo(AddressesTableItem);