ghost-portal/packages/page-staking/src/Overview/CurrentList.tsx
Jaco Greeff 617fea34ac
Bump API (#2335)
* Bump API

* Cleanup staking Address render
2020-03-06 14:40:18 +01:00

161 lines
5.5 KiB
TypeScript

// Copyright 2017-2020 @polkadot/app-staking authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
import { AccountId } from '@polkadot/types/interfaces';
import { AddressDetails } from './types';
import React, { useEffect, useReducer, useState } from 'react';
import { Input, Table } from '@polkadot/react-components';
import { useAccounts, useFavorites } from '@polkadot/react-hooks';
import { STORE_FAVS_BASE } from '../constants';
import { useTranslation } from '../translate';
import Address from './Address';
interface Props {
authorsMap: Record<string, string>;
hasQueries: boolean;
isIntentions: boolean;
isVisible: boolean;
lastAuthors?: string[];
next: string[];
recentlyOnline?: DerivedHeartbeats;
setNominators: (nominators: string[]) => void;
stakingOverview?: DerivedStakingOverview;
}
type AccountExtend = [string, boolean, boolean];
function sortByFav ([,, isFavA]: AccountExtend, [,, isFavB]: AccountExtend): number {
return isFavA === isFavB
? 0
: (isFavA ? -1 : 1);
}
function filterAccounts (accounts: string[] = [], elected: string[], favorites: string[], without: string[]): AccountExtend[] {
return accounts
.filter((accountId): boolean => !without.includes(accountId as any))
.map((accountId): AccountExtend => [
accountId,
elected.includes(accountId),
favorites.includes(accountId)
])
.sort(sortByFav);
}
function accountsToString (accounts: AccountId[]): string[] {
return accounts.map((accountId): string => accountId.toString());
}
function reduceDetails (state: Record<string, AddressDetails>, _details: AddressDetails | AddressDetails[]): Record<string, AddressDetails> {
const details = Array.isArray(_details)
? _details
: [_details];
return details.reduce((result, details): Record<string, AddressDetails> => {
result[details.address] = {
...(state[details.address] || {}),
...details
};
return result;
}, { ...state });
}
export default function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAuthors, next, recentlyOnline, setNominators, stakingOverview }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { allAccounts } = useAccounts();
const [favorites, toggleFavorite] = useFavorites(STORE_FAVS_BASE);
const [{ allElected, elected, validators, waiting }, setFiltered] = useState<{ allElected: string[]; elected: AccountExtend[]; validators: AccountExtend[]; waiting: AccountExtend[] }>({ allElected: [], elected: [], validators: [], waiting: [] });
const [nameFilter, setNameFilter] = useState<string>('');
const [addressDetails, dispatchDetails] = useReducer(reduceDetails, {});
useEffect((): void => {
if (isVisible && stakingOverview) {
const allElected = accountsToString(stakingOverview.nextElected);
const _validators = accountsToString(stakingOverview.validators);
const validators = filterAccounts(_validators, allElected, favorites, []);
const elected = filterAccounts(allElected, allElected, favorites, _validators);
setFiltered({
allElected,
elected,
validators,
waiting: filterAccounts(next, [], favorites, allElected)
});
}
}, [favorites, isVisible, next, stakingOverview?.nextElected, stakingOverview?.validators]);
useEffect((): void => {
if (stakingOverview?.eraPoints) {
const allPoints = stakingOverview.eraPoints
? [...stakingOverview.eraPoints.individual.entries()]
: [];
dispatchDetails(validators.map(([address]): AddressDetails => {
const points = allPoints.find(([accountId]): boolean => accountId.eq(address));
return {
address,
points: points
? points[1]
: undefined
};
}));
}
}, [stakingOverview?.eraPoints, allElected, validators]);
const _renderRows = (addresses: AccountExtend[], defaultName: string, isMain: boolean): React.ReactNode =>
addresses.map(([address, isElected, isFavorite]): React.ReactNode => (
<Address
address={address}
defaultName={defaultName}
filterName={nameFilter}
hasQueries={hasQueries}
heartbeat={
isMain && recentlyOnline
? recentlyOnline[address]
: undefined
}
isAuthor={lastAuthors && lastAuthors.includes(address)}
isElected={isElected}
isFavorite={isFavorite}
key={address}
lastBlock={authorsMap[address]}
myAccounts={allAccounts}
points={
isMain
? addressDetails[address] && addressDetails[address].points
: undefined
}
setNominators={isIntentions ? undefined : setNominators}
toggleFavorite={toggleFavorite}
/>
));
return (
<div className={`${!isVisible && 'staking--hidden'}`}>
<Input
autoFocus
isFull
label={t('filter by name, address or index')}
onChange={setNameFilter}
value={nameFilter}
/>
<Table className={isIntentions ? 'staking--hidden' : ''}>
<Table.Body>
{_renderRows(validators, t('validators'), true)}
</Table.Body>
</Table>
<Table className={isIntentions ? '' : 'staking--hidden'}>
<Table.Body>
{_renderRows(elected, t('intention'), false)}
{_renderRows(waiting, t('intention'), false)}
</Table.Body>
</Table>
</div>
);
}