From 93575c60fcb61de5655063d56f0a4111ab2497da Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sun, 19 Apr 2020 12:13:13 +0200 Subject: [PATCH] Show time remaining to claim payouts (#2584) --- packages/page-staking/src/Payouts/Stash.tsx | 19 ++++++++--- .../page-staking/src/Payouts/Validator.tsx | 10 ++++-- packages/page-staking/src/Payouts/index.tsx | 2 ++ .../page-staking/src/Payouts/useEraBlocks.ts | 32 +++++++++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 packages/page-staking/src/Payouts/useEraBlocks.ts diff --git a/packages/page-staking/src/Payouts/Stash.tsx b/packages/page-staking/src/Payouts/Stash.tsx index 0805fa8f45..e3fbcf2070 100644 --- a/packages/page-staking/src/Payouts/Stash.tsx +++ b/packages/page-staking/src/Payouts/Stash.tsx @@ -11,10 +11,11 @@ import React, { useEffect, useState } from 'react'; import ApiPromise from '@polkadot/api/promise'; import { AddressMini, Badge, TxButton } from '@polkadot/react-components'; import { useApi, useCall } from '@polkadot/react-hooks'; -import { FormatBalance } from '@polkadot/react-query'; +import { BlockToTime, FormatBalance } from '@polkadot/react-query'; import { useTranslation } from '../translate'; import { createErasString } from './util'; +import useEraBlocks from './useEraBlocks'; interface Props { className?: string; @@ -23,6 +24,11 @@ interface Props { stakerPayoutsAfter: BN; } +interface EraInfo { + eraStr: string; + oldestEra?: BN; +} + function createPrevPayoutType (api: ApiPromise, { era, isValidator, nominating }: DeriveStakerReward): SubmittableExtrinsic<'promise'> { return isValidator ? api.tx.staking.payoutValidator(era) @@ -41,13 +47,15 @@ function Stash ({ className, isDisabled, payout: { available, rewards, stashId } const { t } = useTranslation(); const { api } = useApi(); const [extrinsic, setExtrinsic] = useState | null>(null); - const [eraStr, setEraStr] = useState(''); + const [{ eraStr, oldestEra }, setEraInfo] = useState({ eraStr: '' }); + const eraBlocks = useEraBlocks(oldestEra); const stakingAccount = useCall(api.derive.staking.account, [stashId]); useEffect((): void => { - rewards && setEraStr( - createErasString(rewards.map(({ era }): BN => era)) - ); + rewards && setEraInfo({ + eraStr: createErasString(rewards.map(({ era }): BN => era)), + oldestEra: rewards[0]?.era + }); }, [rewards]); useEffect((): void => { @@ -78,6 +86,7 @@ function Stash ({ className, isDisabled, payout: { available, rewards, stashId } {eraStr} + {eraBlocks && } ; numNominators: number; + oldestEra?: BN; } function Payout ({ className, isDisabled, payout }: Props): React.ReactElement { const { t } = useTranslation(); - const [{ eraStr, nominators, numNominators }, setState] = useState({ + const [{ eraStr, nominators, numNominators, oldestEra }, setState] = useState({ eraStr: '', nominators: {}, numNominators: 0 }); + const eraBlocks = useEraBlocks(oldestEra); useEffect((): void => { const eraStr = createErasString(payout.eras.map(({ era }) => era)); @@ -47,7 +50,7 @@ function Payout ({ className, isDisabled, payout }: Props): React.ReactElement

{eraStr} + {eraBlocks && } [t('payout/stash'), 'start'], [t('eras'), 'start'], [t('available')], + [('remaining')], [undefined, undefined, 3] ]} isFixed @@ -137,6 +138,7 @@ function Payouts ({ className, isInElection }: Props): React.ReactElement [t('payout/validator'), 'start'], [t('eras'), 'start'], [t('total')], + [('remaining')], [undefined, undefined, 3] ]} isFixed diff --git a/packages/page-staking/src/Payouts/useEraBlocks.ts b/packages/page-staking/src/Payouts/useEraBlocks.ts new file mode 100644 index 0000000000..2aaf4ffcba --- /dev/null +++ b/packages/page-staking/src/Payouts/useEraBlocks.ts @@ -0,0 +1,32 @@ +// 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 { DeriveSessionProgress } from '@polkadot/api-derive/types'; + +import BN from 'bn.js'; +import { useEffect, useState } from 'react'; +import { useApi, useCall } from '@polkadot/react-hooks'; + +const ONE = new BN(1); + +export default function useEraBlocks (era?: BN): BN | undefined { + const { api } = useApi(); + const depth = useCall(api.query.staking.historyDepth, []); + const progress = useCall(api.derive.session.progress, []); + const [duration, setDuration] = useState(); + + useEffect((): void => { + depth && era && progress?.sessionLength.gt(ONE) && setDuration( + progress.eraLength + .mul( + depth + .sub(progress.activeEra.sub(era)) + .add(ONE) + ) + .sub(progress.eraProgress) + ); + }, [api, depth, era, progress]); + + return duration; +}