index.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright 2017-2020 @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 { DeriveStakingOverview, DeriveStakerReward } from '@polkadot/api-derive/types';
  5. import { ActiveEraInfo, EraIndex } from '@polkadot/types/interfaces';
  6. import React, { useCallback, useEffect, useState } from 'react';
  7. import { Button, Table } from '@polkadot/react-components';
  8. import { useCall, useApi, useOwnStashes } from '@polkadot/react-hooks';
  9. import { Option } from '@polkadot/types';
  10. import Account from './Account';
  11. import StartStaking from './NewStake';
  12. import { useTranslation } from '../translate';
  13. interface Props {
  14. allRewards?: Record<string, DeriveStakerReward[]>;
  15. allStashes?: string[];
  16. className?: string;
  17. isVisible: boolean;
  18. next?: string[];
  19. stakingOverview?: DeriveStakingOverview;
  20. }
  21. function Actions ({ allRewards, allStashes, className, isVisible, next, stakingOverview }: Props): React.ReactElement<Props> {
  22. const { t } = useTranslation();
  23. const { api } = useApi();
  24. const activeEra = useCall<EraIndex | undefined>(api.query.staking?.activeEra, [], {
  25. transform: (activeEra: Option<ActiveEraInfo>): EraIndex | undefined =>
  26. activeEra.isSome
  27. ? activeEra.unwrap().index
  28. : undefined
  29. });
  30. const ownStashes = useOwnStashes();
  31. const [isNewStakeOpen, setIsNewStateOpen] = useState(false);
  32. const [foundStashes, setFoundStashes] = useState<[string, boolean][] | null>(null);
  33. const [stashTypes, setStashTypes] = useState<Record<string, number>>({});
  34. useEffect((): void => {
  35. ownStashes && setFoundStashes(
  36. ownStashes.sort((a, b): number =>
  37. (stashTypes[a[0]] || 99) - (stashTypes[b[0]] || 99)
  38. )
  39. );
  40. }, [ownStashes, stashTypes]);
  41. const _toggleNewStake = useCallback(
  42. (): void => setIsNewStateOpen(
  43. (isNewStakeOpen: boolean) => !isNewStakeOpen
  44. ),
  45. []
  46. );
  47. const _onUpdateType = useCallback(
  48. (stashId: string, type: 'validator' | 'nominator' | 'started' | 'other'): void =>
  49. setStashTypes((stashTypes: Record<string, number>) => ({
  50. ...stashTypes,
  51. [stashId]: type === 'validator'
  52. ? 1
  53. : type === 'nominator'
  54. ? 5
  55. : 9
  56. })),
  57. []
  58. );
  59. return (
  60. <div className={`${className} ${!isVisible && 'staking--hidden'}`}>
  61. <Button.Group>
  62. <Button
  63. key='new-stake'
  64. label={t('New stake')}
  65. icon='add'
  66. onClick={_toggleNewStake}
  67. />
  68. </Button.Group>
  69. {isNewStakeOpen && (
  70. <StartStaking onClose={_toggleNewStake} />
  71. )}
  72. <Table>
  73. <Table.Head>
  74. <th className='start' colSpan={2}><h1>{t('stashes')}</h1></th>
  75. <th className='address'>{t('controller')}</th>
  76. <th className='number'>{t('rewards')}</th>
  77. <th className='number'>{t('bonded')}</th>
  78. <th colSpan={2}>&nbsp;</th>
  79. </Table.Head>
  80. <Table.Body empty={t('No funds staked yet. Bond funds to validate or nominate a validator.')}>
  81. {foundStashes?.map(([stashId, isOwnStash]): React.ReactNode => (
  82. <Account
  83. activeEra={activeEra}
  84. allStashes={allStashes}
  85. isOwnStash={isOwnStash}
  86. isVisible={isVisible}
  87. key={stashId}
  88. next={next}
  89. onUpdateType={_onUpdateType}
  90. rewards={allRewards && allRewards[stashId]}
  91. stakingOverview={stakingOverview}
  92. stashId={stashId}
  93. />
  94. ))}
  95. </Table.Body>
  96. </Table>
  97. </div>
  98. );
  99. }
  100. export default React.memo(Actions);