Rework staking rendering (object passing) (#2425)

* Rework staking rendering (object passing)

* onlineCount check

* Rework reward sorting
This commit is contained in:
Jaco Greeff 2020-03-20 13:14:10 +01:00 committed by GitHub
parent 71ffaf7487
commit 7c7df9873c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 38 deletions

View File

@ -2,8 +2,8 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, RewardPoint } from '@polkadot/types/interfaces';
import { DeriveAccountInfo, DerivedStakingQuery, DerivedHeartbeatAuthor } from '@polkadot/api-derive/types';
import { AccountId, Balance } from '@polkadot/types/interfaces';
import { DeriveAccountInfo, DerivedStakingQuery } from '@polkadot/api-derive/types';
import BN from 'bn.js';
import React, { useCallback, useEffect, useState } from 'react';
@ -22,13 +22,14 @@ interface Props {
defaultName: string;
filterName: string;
hasQueries: boolean;
heartbeat?: false | DerivedHeartbeatAuthor;
isAuthor?: boolean;
isElected: boolean;
isFavorite: boolean;
isMain?: boolean;
lastBlock?: string;
points?: false | RewardPoint;
onlineCount?: false | number;
onlineMessage?: boolean;
points?: false | number;
setNominators?: false | ((nominators: string[]) => void);
toggleFavorite: (accountId: string) => void;
withNominations?: boolean;
@ -97,7 +98,7 @@ function checkVisibility (api: ApiPromise, address: string, filterName: string,
return isVisible;
}
function Address ({ address, className, filterName, hasQueries, heartbeat, isAuthor, isElected, isFavorite, isMain, lastBlock, points, setNominators, toggleFavorite, withNominations }: Props): React.ReactElement<Props> | null {
function Address ({ address, className, filterName, hasQueries, isAuthor, isElected, isFavorite, isMain, lastBlock, onlineCount, onlineMessage, points, setNominators, toggleFavorite, withNominations }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const info = useCall<DeriveAccountInfo>(api.derive.accounts.info as any, [address]);
@ -160,12 +161,12 @@ function Address ({ address, className, filterName, hasQueries, heartbeat, isAut
type='next'
/>
)}
{heartbeat && (heartbeat.blockCount.gtn(0) || heartbeat.hasMessage) && (
{(!!onlineCount || onlineMessage) && (
<Badge
hover={t('Active with {{blocks}} blocks authored{{hasMessage}} heartbeat message', {
replace: {
blocks: formatNumber(heartbeat.blockCount),
hasMessage: heartbeat.hasMessage ? ' and a' : ', no'
blocks: formatNumber(onlineCount || 0),
hasMessage: onlineMessage ? ' and a' : ', no'
}
})}
info={<Icon name='check' />}
@ -219,7 +220,7 @@ function Address ({ address, className, filterName, hasQueries, heartbeat, isAut
)}
</td>
<td className='number'>
{points && points.gtn(0) && (
{points && (
<><label>{t('points')}</label>{formatNumber(points)}</>
)}
</td>

View File

@ -77,7 +77,7 @@ function getDetails (stakingOverview: DerivedStakingOverview, validators: Accoun
return {
address,
points: points
? points[1]
? points[1].toNumber()
: undefined
};
});
@ -123,13 +123,14 @@ function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAut
defaultName={defaultName}
filterName={nameFilter}
hasQueries={hasQueries}
heartbeat={isMain && recentlyOnline && recentlyOnline[address]}
isAuthor={lastAuthors && lastAuthors.includes(address)}
isElected={isElected}
isFavorite={isFavorite}
isMain={isMain}
key={address}
lastBlock={authorsMap[address]}
onlineCount={isMain && recentlyOnline?.[address]?.blockCount.toNumber()}
onlineMessage={isMain && recentlyOnline?.[address]?.hasMessage}
points={isMain && addressDetails[address] && addressDetails[address].points}
setNominators={isIntentions && setNominators}
toggleFavorite={toggleFavorite}

View File

@ -2,9 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { RewardPoint } from '@polkadot/types/interfaces';
export interface AddressDetails {
address: string;
points?: RewardPoint;
points?: number;
}

View File

@ -27,6 +27,7 @@ interface Props {
interface AllInfo {
nominators: string[];
sorted?: ValidatorInfo[];
totalStaked?: BN;
validators: ValidatorInfo[];
}
@ -154,6 +155,18 @@ function extractInfo (allAccounts: string[], amount: BN = new BN(0), electedInfo
return { nominators, totalStaked, validators };
}
function sort (sortBy: SortBy, sortFromMax: boolean, validators: ValidatorInfo[]): ValidatorInfo[] {
return validators
.sort((a, b): number => sortFromMax
? a[sortBy] - b[sortBy]
: b[sortBy] - a[sortBy]
)
.sort((a, b): number => a.isFavorite === b.isFavorite
? 0
: (a.isFavorite ? -1 : 1)
);
}
function Targets ({ className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
@ -170,41 +183,29 @@ function Targets ({ className }: Props): React.ReactElement<Props> {
const [_amount, setAmount] = useState<BN | undefined>(new BN(1_000));
const electedInfo = useCall<DerivedStakingElected>(api.derive.staking.electedInfo, []);
const [favorites, toggleFavorite] = useFavorites(STORE_FAVS_BASE);
const [{ nominators, validators, totalStaked }, setWorkable] = useState<AllInfo>({ nominators: [], validators: [] });
const [{ sorted, sortBy, sortFromMax }, setSorted] = useState<{ sorted?: ValidatorInfo[]; sortBy: SortBy; sortFromMax: boolean }>({ sortBy: 'rankOverall', sortFromMax: true });
const [{ nominators, validators, sorted, totalStaked }, setWorkable] = useState<AllInfo>({ nominators: [], validators: [] });
const [{ sortBy, sortFromMax }, setSortBy] = useState<{ sortBy: SortBy; sortFromMax: boolean }>({ sortBy: 'rankOverall', sortFromMax: true });
const amount = useDebounce(_amount);
const _sort = useCallback(
(newSortBy: SortBy, unsorted: ValidatorInfo[] = validators, isAdjust = true): void => {
const newSortFromMax = isAdjust && newSortBy === sortBy
? !sortFromMax
: true;
setSorted({
(newSortBy: SortBy): void =>
setSortBy(({ sortBy, sortFromMax }) => ({
sortBy: newSortBy,
sortFromMax: newSortFromMax,
sorted: unsorted
.sort((a, b): number => newSortFromMax
? a[newSortBy] - b[newSortBy]
: b[newSortBy] - a[newSortBy]
)
.sort((a, b): number => a.isFavorite === b.isFavorite
? 0
: (a.isFavorite ? -1 : 1)
)
});
},
[sortBy, sortFromMax, validators]
sortFromMax: newSortBy === sortBy
? !sortFromMax
: true
})),
[sortBy]
);
useEffect((): void => {
if (electedInfo) {
const { nominators, totalStaked, validators } = extractInfo(allAccounts, amount, electedInfo, favorites, lastReward);
const sorted = sort(sortBy, sortFromMax, validators);
setWorkable({ nominators, totalStaked, validators });
_sort('rankOverall', validators, false);
setWorkable({ nominators, totalStaked, sorted, validators });
}
}, [allAccounts, amount, electedInfo, favorites, lastReward]);
}, [allAccounts, amount, electedInfo, favorites, lastReward, sortBy, sortFromMax]);
if (!sorted) {
return <Spinner />;