From 81650339910995cdc50027f41d924cf41f4e2def Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 7 Mar 2020 13:59:20 +0100 Subject: [PATCH] Displays countdowns in time (#2339) * Displays countdowns in time * Lint --- .../page-council/src/Overview/Summary.tsx | 3 +- .../page-democracy/src/Overview/Summary.tsx | 3 +- packages/page-explorer/src/Summary.tsx | 7 +- packages/page-explorer/src/SummarySession.tsx | 6 +- .../page-society/src/Overview/Summary.tsx | 6 +- .../page-treasury/src/Overview/Summary.tsx | 3 +- packages/react-components/src/CardSummary.tsx | 33 ++++++-- packages/react-query/src/BlockToTime.tsx | 80 +++++++++++++++++++ packages/react-query/src/TimePeriod.tsx | 34 -------- packages/react-query/src/index.ts | 2 +- 10 files changed, 126 insertions(+), 51 deletions(-) create mode 100644 packages/react-query/src/BlockToTime.tsx delete mode 100644 packages/react-query/src/TimePeriod.tsx diff --git a/packages/page-council/src/Overview/Summary.tsx b/packages/page-council/src/Overview/Summary.tsx index 14c69e4479..04eacb42cf 100644 --- a/packages/page-council/src/Overview/Summary.tsx +++ b/packages/page-council/src/Overview/Summary.tsx @@ -45,7 +45,8 @@ export default function Summary ({ bestNumber, className, electionsInfo: { membe label={t('term progress')} progress={{ total: termDuration, - value: bestNumber.mod(termDuration) + value: bestNumber.mod(termDuration), + withTime: true }} /> diff --git a/packages/page-democracy/src/Overview/Summary.tsx b/packages/page-democracy/src/Overview/Summary.tsx index b2e0620a91..d810110e68 100644 --- a/packages/page-democracy/src/Overview/Summary.tsx +++ b/packages/page-democracy/src/Overview/Summary.tsx @@ -46,7 +46,8 @@ function Summary ({ t }: Props): React.ReactElement { label={t('launch period')} progress={{ value: bestNumber.mod(api.consts.democracy.launchPeriod).addn(1), - total: api.consts.democracy.launchPeriod + total: api.consts.democracy.launchPeriod, + withTime: true }} /> diff --git a/packages/page-explorer/src/Summary.tsx b/packages/page-explorer/src/Summary.tsx index 6b9bebc901..c62d42a153 100644 --- a/packages/page-explorer/src/Summary.tsx +++ b/packages/page-explorer/src/Summary.tsx @@ -4,13 +4,16 @@ import { I18nProps as Props } from '@polkadot/react-components/types'; +import BN from 'bn.js'; import React from 'react'; import { SummaryBox, CardSummary } from '@polkadot/react-components'; -import { BestFinalized, BestNumber, TimeNow, TimePeriod, TotalIssuance } from '@polkadot/react-query'; +import { BestFinalized, BestNumber, BlockToTime, TimeNow, TotalIssuance } from '@polkadot/react-query'; import SummarySession from './SummarySession'; import translate from './translate'; +const ONE_BLOCK = new BN(1); + function Summary ({ t }: Props): React.ReactElement { return ( @@ -22,7 +25,7 @@ function Summary ({ t }: Props): React.ReactElement { className='ui--media-small' label={t('target')} > - + ) @@ -57,7 +58,8 @@ export default function SummarySession ({ withEra = true, withSession = true }: label={eraLabel} progress={{ total: sessionInfo.eraLength, - value: sessionInfo.eraProgress + value: sessionInfo.eraProgress, + withTime: true }} /> ) diff --git a/packages/page-society/src/Overview/Summary.tsx b/packages/page-society/src/Overview/Summary.tsx index 71e8d0e8f2..c851ffc46d 100644 --- a/packages/page-society/src/Overview/Summary.tsx +++ b/packages/page-society/src/Overview/Summary.tsx @@ -73,7 +73,8 @@ function Summary ({ className, info }: Props): React.ReactElement { label={t('rotation')} progress={{ total: api.consts.society.rotationPeriod as BlockNumber, - value: bestNumber.mod(api.consts.society.rotationPeriod as BlockNumber) + value: bestNumber.mod(api.consts.society.rotationPeriod as BlockNumber), + withTime: true }} /> @@ -82,7 +83,8 @@ function Summary ({ className, info }: Props): React.ReactElement { label={t('challenge')} progress={{ total: api.consts.society.challengePeriod as BlockNumber, - value: bestNumber.mod(api.consts.society.challengePeriod as BlockNumber) + value: bestNumber.mod(api.consts.society.challengePeriod as BlockNumber), + withTime: true }} /> diff --git a/packages/page-treasury/src/Overview/Summary.tsx b/packages/page-treasury/src/Overview/Summary.tsx index 0d92cedcbc..4564f2b8fe 100644 --- a/packages/page-treasury/src/Overview/Summary.tsx +++ b/packages/page-treasury/src/Overview/Summary.tsx @@ -57,7 +57,8 @@ export default function Summary ({ approvalCount, proposalCount }: Props): React label={t('spend period')} progress={{ total: spendPeriod, - value: bestNumber.mod(spendPeriod) + value: bestNumber.mod(spendPeriod), + withTime: true }} /> diff --git a/packages/react-components/src/CardSummary.tsx b/packages/react-components/src/CardSummary.tsx index 274e9f9158..5541bda445 100644 --- a/packages/react-components/src/CardSummary.tsx +++ b/packages/react-components/src/CardSummary.tsx @@ -12,6 +12,7 @@ import { formatNumber, isUndefined } from '@polkadot/util'; import Progress, { Colors as ProgressColors } from './Progress'; import Labelled from './Labelled'; +import { BlockToTime } from '@polkadot/react-query'; interface ProgressProps { color?: ProgressColors; @@ -19,6 +20,7 @@ interface ProgressProps { isPercent?: boolean; total?: BN | UInt; value?: BN | UInt; + withTime?: boolean; } interface Props extends BareProps { @@ -51,6 +53,8 @@ function CardSummary ({ children, className, help, label, progress }: Props): Re return null; } + const isTimed = progress && progress.withTime && !isUndefined(progress.total); + return (
{children}{ progress && !progress.hideValue && ( - !left || isUndefined(progress.total) - ? '-' - : `${left}${progress.isPercent ? '' : '/'}${ - progress.isPercent - ? '%' - : formatNumber(progress.total) - }` + <> + {isTimed && ( + + )} +
+ {!left || isUndefined(progress.total) + ? '-' + : `${left}${progress.isPercent ? '' : '/'}${ + progress.isPercent + ? '%' + : formatNumber(progress.total) + }` + } +
+ ) } {progress && } @@ -120,6 +132,13 @@ export default styled(CardSummary)` margin: 0.2rem 0 -0.5rem !important; background: rgba(0,0,0,0.05); } + + .isSecondary { + font-size: 1.1rem; + font-weight: normal; + line-height: 1.1rem; + margin-top: 0.25rem; + } } @media(max-width: 767px) { diff --git a/packages/react-query/src/BlockToTime.tsx b/packages/react-query/src/BlockToTime.tsx new file mode 100644 index 0000000000..1b471f9d9f --- /dev/null +++ b/packages/react-query/src/BlockToTime.tsx @@ -0,0 +1,80 @@ +// Copyright 2017-2020 @polkadot/react-query 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 { BareProps } from '@polkadot/react-api/types'; + +import BN from 'bn.js'; +import React, { useMemo } from 'react'; +import { useApi } from '@polkadot/react-hooks'; + +import { useTranslation } from './translate'; + +interface Props extends BareProps { + blocks?: BN; + children?: React.ReactNode; + label?: React.ReactNode; +} + +type Time = [number, number, number, number]; + +const HRS = 60 * 60; +const DAY = HRS * 24; + +function addTime (a: Time, b: Time): Time { + return [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]; +} + +function extractTime (value?: number): Time { + if (!value) { + return [0, 0, 0, 0]; + } else if (value < 60) { + return [0, 0, 0, value]; + } + + const mins = value / 60; + + if (mins < 60) { + const round = Math.floor(mins); + + return addTime([0, 0, round, 0], extractTime(value - (round * 60))); + } + + const hrs = mins / 60; + + if (hrs < 24) { + const round = Math.floor(hrs); + + return addTime([0, round, 0, 0], extractTime(value - (round * HRS))); + } + + const round = Math.floor(hrs / 24); + + return addTime([round, 0, 0, 0], extractTime(value - (round * DAY))); +} + +export default function BlockToTime ({ blocks, children, className, label, style }: Props): React.ReactElement { + const { t } = useTranslation(); + const { api } = useApi(); + const time = useMemo((): string => { + const blockTime = (api.consts.babe?.expectedBlockTime || (api.consts.timestamp.minimumPeriod.muln(2))).divn(1000); + const time = extractTime(blocks?.mul(blockTime).toNumber()); + + return [ + time[0] ? (time[0] > 1) ? t('{{d}} days', { replace: { d: time[0] } }) : t('1 day') : null, + time[1] ? (time[1] > 1) ? t('{{h}} hrs', { replace: { h: time[1] } }) : t('1 hr') : null, + time[2] ? (time[2] > 1) ? t('{{m}} mins', { replace: { m: time[2] } }) : t('1 min') : null, + time[3] ? (time[3] > 1) ? t('{{s}} s', { replace: { s: time[3] } }) : t('1 s') : null + ].filter((value): value is string => !!value) + .join(', '); + }, [api, t]); + + return ( +
+ {label || ''}{time}{children} +
+ ); +} diff --git a/packages/react-query/src/TimePeriod.tsx b/packages/react-query/src/TimePeriod.tsx deleted file mode 100644 index b60cbce597..0000000000 --- a/packages/react-query/src/TimePeriod.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2020 @polkadot/react-query 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 { BareProps } from '@polkadot/react-api/types'; - -import React from 'react'; -import { useApi } from '@polkadot/react-hooks'; -import { formatNumber } from '@polkadot/util'; - -interface Props extends BareProps { - children?: React.ReactNode; - label?: React.ReactNode; -} - -export default function TimePeriod ({ children, className, label, style }: Props): React.ReactElement { - const { api } = useApi(); - const minimumPeriod = api.consts?.timestamp?.minimumPeriod; - - return ( -
- {label || ''}{ - api.consts?.babe?.expectedBlockTime - ? `${formatNumber(api.consts.babe.expectedBlockTime.toNumber() / 1000)}s` - : minimumPeriod - ? `${formatNumber(minimumPeriod.gtn(1000) ? (minimumPeriod.toNumber() / 500) : (minimumPeriod.toNumber() * 2))}s` - : '-' - }{children} -
- ); -} diff --git a/packages/react-query/src/index.ts b/packages/react-query/src/index.ts index 0910857543..9b0cf81062 100644 --- a/packages/react-query/src/index.ts +++ b/packages/react-query/src/index.ts @@ -7,6 +7,7 @@ export { default as Balance } from './Balance'; export { default as BalanceFree } from './BalanceFree'; export { default as BalanceVoting } from './BalanceVoting'; export { BlockAuthors, BlockAuthorsContext, ValidatorsContext } from './BlockAuthors'; +export { default as BlockToTime } from './BlockToTime'; export { default as Bonded } from './Bonded'; export { default as BestFinalized } from './BestFinalized'; export { default as BestNumber } from './BestNumber'; @@ -19,5 +20,4 @@ export { default as NodeName } from './NodeName'; export { default as NodeVersion } from './NodeVersion'; export { default as Nonce } from './Nonce'; export { default as TimeNow } from './TimeNow'; -export { default as TimePeriod } from './TimePeriod'; export { default as TotalIssuance } from './TotalIssuance';