Skip to content

Commit

Permalink
Merge pull request #98 from multiversx/auctio-list-expand-row
Browse files Browse the repository at this point in the history
Auction List Expand Row
  • Loading branch information
radumojic authored May 28, 2024
2 parents 8f001b8 + 8d1ce51 commit 09cb580
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 370 deletions.
256 changes: 174 additions & 82 deletions src/components/Nodes/AuctionListTable/AuctionListBaseRow.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useState } from 'react';
import BigNumber from 'bignumber.js';
import classNames from 'classnames';

import { ELLIPSIS, ZERO } from 'appConstants';
import { ELLIPSIS, ZERO, MAX_RESULTS } from 'appConstants';
import {
FormatAmount,
NodeThreshold,
Expand All @@ -12,10 +13,20 @@ import {
FormatNumber,
NetworkLink,
SharedIdentity,
Trim
Trim,
Loader,
PageState,
NodesTable
} from 'components';
import { urlBuilder } from 'helpers';
import { AuctionValidatorType } from 'types';
import { useAdapter } from 'hooks';
import { faCogs } from 'icons/regular';
import {
AuctionValidatorType,
NodeType,
NodeTypeEnum,
SortOrderEnum
} from 'types';

import { AuctionListBaseRowUIType } from './types';

Expand All @@ -34,6 +45,25 @@ const getIdentityLink = (validator: AuctionValidatorType) => {
return '';
};

const getNodesFilters = (validator: AuctionValidatorType) => {
const { auctionValidators, identity, provider, owner } = validator;
if (!auctionValidators || !(identity || provider || owner)) {
return;
}

return {
size: MAX_RESULTS,
type: NodeTypeEnum.validator,
sort: 'qualifiedStake',
order: SortOrderEnum.desc,
isAuctioned: true,
withIdentityInfo: true,
...(identity ? { identity } : {}),
...(provider ? { provider } : {}),
...(owner ? { owner } : {})
};
};

export const AuctionListBaseRow = ({
validator,
index,
Expand All @@ -57,6 +87,27 @@ export const AuctionListBaseRow = ({
auctionPosition
} = validator;

const { getNodes } = useAdapter();

const [collapsed, setCollapsed] = useState(true);
const [showDetails, setShowDetails] = useState(false);
const [dataReady, setDataReady] = useState<boolean | undefined>();
const [identityNodes, setIdentityNodes] = useState<NodeType[]>([]);

const expand = (auctionValidator: AuctionValidatorType) => () => {
if (dataReady === undefined) {
const nodeFilters = getNodesFilters(auctionValidator);
if (nodeFilters) {
getNodes(nodeFilters).then((nodes) => {
setDataReady(nodes.success);
setIdentityNodes(nodes.data);
});
}
}
setShowDetails(true);
setCollapsed((collapsed) => !collapsed);
};

const identityLink = getIdentityLink(validator);

const bNauctionValidators = new BigNumber(auctionValidators ?? 0);
Expand Down Expand Up @@ -84,91 +135,132 @@ export const AuctionListBaseRow = ({
};

return (
<tr
key={auctionPosition ?? index}
className={classNames(className, {
q: bNqualifiedAuctionValidators.isGreaterThan(0),
nq: bNqualifiedAuctionValidators.isZero()
})}
>
{showPosition && <td>{auctionPosition ?? index + 1}</td>}
<td>
<div className='d-flex align-items-center'>
<NetworkLink to={identityLink}>
<SharedIdentity.Avatar
identity={{ identity, name, avatar }}
className='identity-avatar-md me-2'
<>
<tr
key={auctionPosition ?? index}
onClick={expand(validator)}
className={classNames('auction-list-row', className, {
q: bNqualifiedAuctionValidators.isGreaterThan(0),
nq: bNqualifiedAuctionValidators.isZero(),
collapsed: collapsed,
'cursor-pointer': auctionValidators && auctionValidators > 0
})}
>
{showPosition && <td>{auctionPosition ?? index + 1}</td>}
<td>
<div className='d-flex align-items-center'>
<NetworkLink to={identityLink}>
<SharedIdentity.Avatar
identity={{ identity, name, avatar }}
className='identity-avatar-md me-2'
/>
</NetworkLink>
<div className='d-flex flex-column'>
<NetworkLink
to={identityLink}
className='trim-wrapper trim-size-xl font-headings-regular'
>
<IdentityName />
{details && (
<span className='text-neutral-400 ms-1'>({details})</span>
)}
</NetworkLink>
</div>
</div>
</td>
<td>{auctionValidators ? auctionValidators : ELLIPSIS}</td>
<td>
<div
className={classNames('d-flex align-items-center gap-2', {
'text-success': qualifiedAuctionValidators,
'text-neutral-400': !qualifiedAuctionValidators
})}
>
<Led
color={classNames('mt-0', {
'bg-success': qualifiedAuctionValidators,
'bg-neutral-400': !qualifiedAuctionValidators
})}
/>
</NetworkLink>
<div className='d-flex flex-column'>
<NetworkLink
to={identityLink}
className='trim-wrapper trim-size-xl font-headings-regular'
>
<IdentityName />
{details && (
<span className='text-neutral-400 ms-1'>({details})</span>
{qualifiedAuctionValidators && qualifiedAuctionValidators > 0 ? (
<FormatNumber value={qualifiedAuctionValidators} />
) : (
ZERO
)}
{new BigNumber(dangerZoneValidators ?? 0).isGreaterThan(0) &&
qualifiedStake && (
<NodeDangerZoneTooltip qualifiedStake={qualifiedStake} />
)}
</NetworkLink>
</div>
</div>
</td>
<td>{auctionValidators ? auctionValidators : ELLIPSIS}</td>
<td>
<div
className={classNames('d-flex align-items-center gap-2', {
'text-success': qualifiedAuctionValidators,
'text-neutral-400': !qualifiedAuctionValidators
</td>
<td
className={classNames('mt-0', {
'text-red-400': formattedDroppedValidators,
'text-neutral-400': !formattedDroppedValidators
})}
>
<Led
color={classNames('mt-0', {
'bg-success': qualifiedAuctionValidators,
'bg-neutral-400': !qualifiedAuctionValidators
})}
/>
{qualifiedAuctionValidators && qualifiedAuctionValidators > 0 ? (
<FormatNumber value={qualifiedAuctionValidators} />
{formattedDroppedValidators ? formattedDroppedValidators : ZERO}
</td>
<td className='text-neutral-100'>
{qualifiedStake ? (
<Overlay
title={
<LockedStakeTooltip
stake={stake}
auctionTopUp={auctionTopUp}
showAuctionTopup
/>
}
tooltipClassName='tooltip-text-start tooltip-lg'
persistent
truncate
>
<FormatAmount value={qualifiedStake} showTooltip={false} />
</Overlay>
) : (
ZERO
ELLIPSIS
)}
{new BigNumber(dangerZoneValidators ?? 0).isGreaterThan(0) &&
qualifiedStake && (
<NodeDangerZoneTooltip qualifiedStake={qualifiedStake} />
)}
</div>
</td>
<td
className={classNames('mt-0', {
'text-red-400': formattedDroppedValidators,
'text-neutral-400': !formattedDroppedValidators
})}
>
{formattedDroppedValidators ? formattedDroppedValidators : ZERO}
</td>
<td className='text-neutral-100'>
{qualifiedStake ? (
<Overlay
title={
<LockedStakeTooltip
stake={stake}
auctionTopUp={auctionTopUp}
showAuctionTopup
/>
}
tooltipClassName='tooltip-text-start tooltip-lg'
persistent
truncate
>
<FormatAmount value={qualifiedStake} showTooltip={false} />
</Overlay>
) : (
ELLIPSIS
)}
</td>
<td>
<NodeThreshold qualifiedStake={qualifiedStake} showPercentage />
</td>
</tr>
</td>
<td>
<NodeThreshold qualifiedStake={qualifiedStake} showPercentage />
</td>
</tr>
{showDetails && (
<tr
className={classNames('auction-list-expand-row', {
collapsed: collapsed
})}
>
<td colSpan={7} className='p-0'>
<div className='content'>
{dataReady === undefined && (
<div className='py-4'>
<Loader small={true} noText={true} />
</div>
)}
{dataReady === false && (
<PageState
icon={faCogs}
title='Unable to load validators'
isError
/>
)}
{dataReady === true && (
<div className='nodes-table-wrapper py-2 px-4'>
<NodesTable hideFilters={true} auctionList>
<NodesTable.Body
nodes={identityNodes}
showTresholdRow={false}
showPosition
auctionList
/>
</NodesTable>
</div>
)}
</div>
</td>
</tr>
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface NodesTableBodyUIType {
status?: NodeType['status'];
auctionList?: boolean;
showPosition?: boolean;
showTresholdRow?: boolean;
}

const findThresholdNode = (
Expand Down Expand Up @@ -50,7 +51,8 @@ export const NodesTableBody = ({
type,
status,
auctionList,
showPosition
showPosition,
showTresholdRow = true
}: NodesTableBodyUIType) => {
const {
unprocessed: { minimumAuctionQualifiedStake }
Expand Down Expand Up @@ -90,8 +92,11 @@ export const NodesTableBody = ({
return (
<tbody>
{nodes.map((nodeData, index) => {
const showThresholdRow = Boolean(
thresholdIndex && index === thresholdIndex && hasNoFilters
const hasTresholdRow = Boolean(
showTresholdRow &&
thresholdIndex &&
index === thresholdIndex &&
hasNoFilters
);

if (statistics) {
Expand All @@ -105,7 +110,7 @@ export const NodesTableBody = ({
<AuctionRow
nodeData={nodeData}
key={nodeData.bls}
showThresholdRow={showThresholdRow}
showThresholdRow={hasTresholdRow}
index={index + 1}
showPosition={showPosition}
/>
Expand All @@ -119,7 +124,7 @@ export const NodesTableBody = ({
type={type}
status={status}
key={nodeData.bls}
showThresholdRow={showThresholdRow}
showThresholdRow={hasTresholdRow}
showPosition={showPosition}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,38 @@ import { useIsSovereign } from 'hooks';

import { NodesTableFilterHead } from '../NodesTableFilterHead';

export const AuctionHead = () => {
export const AuctionHead = ({ hideFilters }: { hideFilters?: boolean }) => {
const isSovereign = useIsSovereign();
return (
<thead>
<tr>
<th scope='col' data-testid='node'>
<NodesGeneralFilter text='Public Key' />
<NodesGeneralFilter text='Public Key' hideFilters={hideFilters} />
</th>
<th scope='col' data-testid='name'>
<Sort id='name' text='Name' />
<Sort id='name' text='Name' hideFilters={hideFilters} />
</th>
<th scope='col' data-testid='shard'>
<ShardFilter text={isSovereign ? 'Chain' : 'Shard'} />
<ShardFilter
text={isSovereign ? 'Chain' : 'Shard'}
hideFilters={hideFilters}
/>
</th>
<th scope='col' data-testid='version'>
<Sort id='version' text='Version' />
<Sort id='version' text='Version' hideFilters={hideFilters} />
</th>
<th scope='col' data-testid='qualifiedStake'>
<Sort id='qualifiedStake' text='Qualified Stake / Node' />
<Sort
id='qualifiedStake'
text='Qualified Stake / Node'
hideFilters={hideFilters}
/>
</th>
<th scope='col' data-testid='delta'>
<Sort id='qualifiedStake' text='Delta' />
<Sort id='qualifiedStake' text='Delta' hideFilters={hideFilters} />
</th>
<th scope='col' data-testid='status'>
<NodesQualifiedFilter text='Status' />
<NodesQualifiedFilter text='Status' hideFilters={hideFilters} />
</th>
</tr>
<NodesTableFilterHead colSpan={7} />
Expand Down
Loading

0 comments on commit 09cb580

Please sign in to comment.