CurrentList.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2017-2019 @polkadot/app-staking authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import { AccountId } from '@polkadot/types/interfaces';
  5. import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
  6. import { I18nProps } from '@polkadot/react-components/types';
  7. import { ValidatorFilter } from '../types';
  8. import React, { useContext, useEffect, useState } from 'react';
  9. import { ApiContext } from '@polkadot/react-api';
  10. import { Columar, Column, Dropdown, FilterOverlay } from '@polkadot/react-components';
  11. import keyring from '@polkadot/ui-keyring';
  12. import translate from '../translate';
  13. import Address from './Address';
  14. interface Props extends I18nProps {
  15. authorsMap: Record<string, string>;
  16. lastAuthors?: string[];
  17. next: string[];
  18. recentlyOnline?: DerivedHeartbeats;
  19. stakingOverview?: DerivedStakingOverview;
  20. }
  21. function renderColumn(
  22. myAccounts: string[],
  23. addresses: AccountId[] | string[],
  24. defaultName: string,
  25. withOnline: boolean,
  26. filter: string,
  27. { authorsMap, lastAuthors, recentlyOnline, stakingOverview }: Props,
  28. pointIndexes?: number[]
  29. ): React.ReactNode {
  30. return (addresses as AccountId[]).map(
  31. (address, index): React.ReactNode => (
  32. <Address
  33. address={address}
  34. authorsMap={authorsMap}
  35. defaultName={defaultName}
  36. filter={filter}
  37. isElected={
  38. stakingOverview && stakingOverview.currentElected.some((accountId): boolean => accountId.eq(address))
  39. }
  40. lastAuthors={lastAuthors}
  41. key={address.toString()}
  42. myAccounts={myAccounts}
  43. points={
  44. stakingOverview && pointIndexes && pointIndexes[index] !== -1
  45. ? stakingOverview.eraPoints.individual[pointIndexes[index]]
  46. : undefined
  47. }
  48. recentlyOnline={withOnline ? recentlyOnline : undefined}
  49. />
  50. )
  51. );
  52. }
  53. function filterAccounts(list: string[] = [], without: AccountId[] | string[]): string[] {
  54. return list.filter((accountId): boolean => !without.includes(accountId as any));
  55. }
  56. function CurrentList(props: Props): React.ReactElement<Props> {
  57. const { isSubstrateV2 } = useContext(ApiContext);
  58. const [filter, setFilter] = useState<ValidatorFilter>('all');
  59. const [myAccounts] = useState(keyring.getAccounts().map(({ address }): string => address));
  60. const [{ electedFiltered, nextFiltered, pointIndexes }, setFiltered] = useState<{
  61. electedFiltered: string[];
  62. nextFiltered: string[];
  63. pointIndexes: number[];
  64. }>({ electedFiltered: [], nextFiltered: [], pointIndexes: [] });
  65. const { next, stakingOverview, t } = props;
  66. useEffect((): void => {
  67. if (stakingOverview) {
  68. const elected = stakingOverview.currentElected.map((accountId): string => accountId.toString());
  69. setFiltered({
  70. electedFiltered: isSubstrateV2 ? filterAccounts(elected, stakingOverview.validators) : [],
  71. nextFiltered: filterAccounts(next, elected),
  72. pointIndexes: stakingOverview.validators.map((validator): number => elected.indexOf(validator.toString()))
  73. });
  74. }
  75. }, [next, stakingOverview]);
  76. return (
  77. <div>
  78. <FilterOverlay
  79. style={{
  80. top: myAccounts.length ? '5.5rem' : '5px'
  81. }}
  82. >
  83. <Dropdown
  84. onChange={setFilter}
  85. options={[
  86. { text: t('Show all validators and intentions'), value: 'all' },
  87. { text: t('Show only my nominations'), value: 'iNominated' },
  88. { text: t('Show only with nominators'), value: 'hasNominators' },
  89. { text: t('Show only without nominators'), value: 'noNominators' },
  90. { text: t('Show only with warnings'), value: 'hasWarnings' },
  91. { text: t('Show only without warnings'), value: 'noWarnings' },
  92. { text: t('Show only elected for next session'), value: 'nextSet' }
  93. ]}
  94. value={filter}
  95. withLabel={false}
  96. />
  97. </FilterOverlay>
  98. <Columar className="validator--ValidatorsList">
  99. <Column emptyText={t('No addresses found')} headerText={t('validators')}>
  100. {stakingOverview &&
  101. renderColumn(myAccounts, stakingOverview.validators, t('validator'), true, filter, props, pointIndexes)}
  102. </Column>
  103. <Column emptyText={t('No addresses found')} headerText={t('next up')}>
  104. {(electedFiltered.length !== 0 || nextFiltered.length !== 0) && (
  105. <>
  106. {renderColumn(myAccounts, electedFiltered, t('intention'), false, filter, props)}
  107. {renderColumn(myAccounts, nextFiltered, t('intention'), false, filter, props)}
  108. </>
  109. )}
  110. </Column>
  111. </Columar>
  112. </div>
  113. );
  114. }
  115. export default translate(CurrentList);