From 826598c1b17db7057c10b8f43187bf024569e83b Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 17 Jul 2020 22:43:00 +0200 Subject: [PATCH] Display turnout for poll (#3223) --- README.md | 2 +- .../page-accounts/src/Accounts/modals/Qr.tsx | 1 + packages/page-poll/src/index.tsx | 50 ++++++++++++++++--- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index aede3e5afb..25efecb612 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A Portal into the Polkadot and Substrate networks. Provides a view and interacti This can be accessed as a hosted application via https://polkadot.js.org/apps/ or you can access the IPFS hosted version via https://polkadot.js.org/apps/ipfs (via hash) or https://dotapps.io (via ipns) to explore any of the supported Polkadot and Substrate chains. -If you run one or more IPFS node(s), pinning the UI (which only getes updated on releases) will make it faster for you and others. You can find details about that below in the IPFS chapter below. +If you run one or more IPFS node(s), pinning the UI (which only gets updated on releases) will make it faster for you and others. You can find details about that below in the IPFS chapter below. **Important** If you are a chain developer and would like to add support for your chain to the UI, all the local configuration (API types, settings, logos) can be customized in [the apps-config package](packages/apps-config#README.md), complete with instructions of what goes where. diff --git a/packages/page-accounts/src/Accounts/modals/Qr.tsx b/packages/page-accounts/src/Accounts/modals/Qr.tsx index 5fea445c3e..65fd23d8cb 100644 --- a/packages/page-accounts/src/Accounts/modals/Qr.tsx +++ b/packages/page-accounts/src/Accounts/modals/Qr.tsx @@ -51,6 +51,7 @@ function QrModal ({ className = '', onClose, onStatusChange }: Props): React.Rea const _onScan = useCallback( (scanned: Scanned): void => { setScanned(scanned); + const { content, genesisHash } = scanned; setIsAddress(scanned.isAddress); diff --git a/packages/page-poll/src/index.tsx b/packages/page-poll/src/index.tsx index 9e1537705c..444431ac56 100644 --- a/packages/page-poll/src/index.tsx +++ b/packages/page-poll/src/index.tsx @@ -2,7 +2,7 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { Balance, BlockNumber } from '@polkadot/types/interfaces'; +import { Approvals, Balance, BlockNumber } from '@polkadot/types/interfaces'; import { ITuple } from '@polkadot/types/types'; import BN from 'bn.js'; @@ -12,7 +12,7 @@ import styled from 'styled-components'; import { Button, Columar, InputAddress, Progress, Spinner, Toggle, TxButton } from '@polkadot/react-components'; import { useApi, useCall } from '@polkadot/react-hooks'; import { FormatBalance, BlockToTime } from '@polkadot/react-query'; -import { BN_ONE, BN_ZERO, bnMax, formatNumber } from '@polkadot/util'; +import { BN_ONE, BN_ZERO, bnMax, formatBalance, formatNumber } from '@polkadot/util'; import { useTranslation } from './translate'; @@ -20,6 +20,11 @@ interface Props { className?: string; } +interface Turnout { + percentage: number; + voted: BN; +} + const DIV = new BN(1_000_000); function PollApp ({ className }: Props): React.ReactElement { @@ -27,7 +32,9 @@ function PollApp ({ className }: Props): React.ReactElement { const { api } = useApi(); const totals = useCall>(api.query.poll.totals, []); const bestNumber = useCall(api.derive.chain.bestNumber, []); + const totalIssuance = useCall(api.query.balances.totalIssuance, []); const [accountId, setAccountId] = useState(null); + const [turnout, setTurnout] = useState(null); const [opt10m, setOpt10m] = useState(false); const [opt100m, setOpt100m] = useState(false); const [opt1b, setOpt1b] = useState(false); @@ -35,12 +42,22 @@ function PollApp ({ className }: Props): React.ReactElement { const [progress, setProgress] = useState(); useEffect((): void => { - if (totals) { + if (totalIssuance && totals) { const max = bnMax(BN_ONE, ...totals); setProgress(totals.map((total) => total.mul(DIV).div(max))); + + api.query.poll.voteOf + .entries>() + .then((entries): void => { + const voted = entries.reduce((voted: BN, [, [, balance]]) => voted.iadd(balance), new BN(0)); + const percentage = voted.muln(10_000).div(totalIssuance).toNumber() / 100; + + setTurnout({ percentage, voted }); + }) + .catch(console.log); } - }, [totals]); + }, [api, totalIssuance, totals]); if (!totals || !progress || !bestNumber) { return ( @@ -52,6 +69,8 @@ function PollApp ({ className }: Props): React.ReactElement { ); } + console.error(turnout); + const blocksLeft = (api.consts.poll.end as BlockNumber).sub(bestNumber); const canVote = blocksLeft.gt(BN_ZERO); const options: [string, string, boolean, (value: boolean) => void][] = [ @@ -70,8 +89,16 @@ function PollApp ({ className }: Props): React.ReactElement {

{t('denomination vote')}

- {canVote && } -
#{formatNumber(api.consts.poll.end as BlockNumber)}
+ {turnout && ( +
+
{t('{{balance}} voted', { replace: { balance: formatBalance(turnout.voted) } })}
+
{t('{{percentage}}% turnout', { replace: { percentage: turnout.percentage.toFixed(2) } })}
+
+ )} +
+ {canVote && } +
#{formatNumber(api.consts.poll.end as BlockNumber)}
+
@@ -169,10 +196,19 @@ export default React.memo(styled(PollApp)` .pollBlocksRight { position: absolute; - right: 0.5rem; + right: 0; text-align: right; opacity: 0.75; bottom: 0; + + > div { + display: inline-block; + padding: 0 0.75rem; + + &+div { + border-left: 1px solid #bbb; + } + } } .pollContainer {