From 71ab4c3d041cb3f60257481ae1cdf1a91b2d5995 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sun, 23 Aug 2020 18:57:57 +0200 Subject: [PATCH] Rework votes display (#3489) --- packages/page-council/src/Motions/Motion.tsx | 26 ++-- packages/page-council/src/Motions/Voters.tsx | 59 +++++++++ packages/page-council/src/Motions/Votes.tsx | 57 -------- packages/page-council/src/Motions/index.tsx | 3 +- .../src/Overview/Referendum.tsx | 85 ++++++------ .../src/Overview/ReferendumVotes.tsx | 122 ++++++++---------- .../src/Overview/Referendums.tsx | 5 +- packages/react-components/src/Table/Body.tsx | 8 ++ 8 files changed, 189 insertions(+), 176 deletions(-) create mode 100644 packages/page-council/src/Motions/Voters.tsx delete mode 100644 packages/page-council/src/Motions/Votes.tsx diff --git a/packages/page-council/src/Motions/Motion.tsx b/packages/page-council/src/Motions/Motion.tsx index d7f0579630..6e6d7bb9a8 100644 --- a/packages/page-council/src/Motions/Motion.tsx +++ b/packages/page-council/src/Motions/Motion.tsx @@ -13,7 +13,7 @@ import { BlockToTime } from '@polkadot/react-query'; import { formatNumber } from '@polkadot/util'; import Close from './Close'; -import Voters from './Votes'; +import Voters from './Voters'; import Voting from './Voting'; interface Props { @@ -69,17 +69,19 @@ function Motion ({ className = '', isMember, members, motion: { hash, proposal, )} - - + + + + {isVoteable && !isCloseable && ( | null { + const { t } = useTranslation(); + + const counter = useMemo( + (): string => { + const num = threshold.toNumber(); + const max = isAye + ? num + : members?.length + ? (members.length - num) + 1 + : 0; + + return `${votes.length}${max ? `/${max}` : ''}`; + }, + [isAye, members, threshold, votes] + ); + + if (!counter || !votes.length) { + return null; + } + + return ( + ('Aye {{counter}}', { replace: { counter } }) + : t('Nay {{counter}}', { replace: { counter } }) + } + > + {votes.map((address): React.ReactNode => ( + + ))} + + ); +} + +export default React.memo(Voters); diff --git a/packages/page-council/src/Motions/Votes.tsx b/packages/page-council/src/Motions/Votes.tsx deleted file mode 100644 index 842df43a88..0000000000 --- a/packages/page-council/src/Motions/Votes.tsx +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017-2020 @polkadot/app-democracy 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 { AccountId, MemberCount } from '@polkadot/types/interfaces'; - -import React, { useEffect, useState } from 'react'; -import { AddressMini, Expander } from '@polkadot/react-components'; - -import { useTranslation } from '../translate'; - -interface Props { - isAye?: boolean; - members: string[]; - votes: AccountId[]; - threshold: MemberCount; -} - -function Votes ({ isAye, members, threshold, votes }: Props): React.ReactElement { - const { t } = useTranslation(); - const [counter, setCounter] = useState(''); - - useEffect((): void => { - const num = threshold.toNumber(); - const max = isAye - ? num - : members?.length - ? (members.length - num) + 1 - : 0; - - setCounter(`${votes.length}${max ? `/${max}` : ''}`); - }, [isAye, members, threshold, votes]); - - return ( - - {counter && votes.length !== 0 && ( - ('Aye {{counter}}', { replace: { counter } }) - : t('Nay {{counter}}', { replace: { counter } }) - } - > - {votes.map((address): React.ReactNode => ( - - ))} - - )} - - ); -} - -export default React.memo(Votes); diff --git a/packages/page-council/src/Motions/index.tsx b/packages/page-council/src/Motions/index.tsx index 9171e0538f..cb940cf601 100644 --- a/packages/page-council/src/Motions/index.tsx +++ b/packages/page-council/src/Motions/index.tsx @@ -29,8 +29,7 @@ function Proposals ({ className = '', motions, prime }: Props): React.ReactEleme [t('motions'), 'start', 2], [t('threshold')], [t('voting end')], - [undefined, 'address'], - [undefined, 'address'], + [t('votes'), 'start'], [], [undefined, 'badge'], [undefined, 'mini'] diff --git a/packages/page-democracy/src/Overview/Referendum.tsx b/packages/page-democracy/src/Overview/Referendum.tsx index 48dca4d67a..af56a53598 100644 --- a/packages/page-democracy/src/Overview/Referendum.tsx +++ b/packages/page-democracy/src/Overview/Referendum.tsx @@ -6,7 +6,7 @@ import { DeriveReferendumExt } from '@polkadot/api-derive/types'; import { Balance, BlockNumber } from '@polkadot/types/interfaces'; import BN from 'bn.js'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; import { Badge, Button, Icon, LinkExternal } from '@polkadot/react-components'; import { useAccounts, useApi, useCall } from '@polkadot/react-hooks'; @@ -42,33 +42,40 @@ function Referendum ({ className = '', value: { allAye, allNay, image, imageHash const { allAccounts } = useAccounts(); const bestNumber = useCall(api.derive.chain.bestNumber); const totalIssuance = useCall(api.query.balances.totalIssuance); - const [percentages, setPercentages] = useState(null); - const [{ hasVoted, hasVotedAye }, setHasVoted] = useState({ hasVoted: false, hasVotedAye: false }); const { changeAye, changeNay } = useChangeCalc(status.threshold, votedAye, votedNay, votedTotal); const threshold = useMemo( () => status.threshold.type.toString().replace('majority', ' majority '), [status] ); - useEffect((): void => { - if (totalIssuance) { - const aye = allAye.reduce((total: BN, { balance }) => total.add(balance), new BN(0)); - const nay = allNay.reduce((total: BN, { balance }) => total.add(balance), new BN(0)); - const hasVotedAye = allAye.some(({ accountId }) => allAccounts.includes(accountId.toString())); - const hasVoted = hasVotedAye || allNay.some(({ accountId }) => allAccounts.includes(accountId.toString())); + const [percentages, { hasVoted, hasVotedAye }] = useMemo( + (): [Percentages | null, VoteType] => { + if (totalIssuance) { + const aye = allAye.reduce((total: BN, { balance }) => total.add(balance), new BN(0)); + const nay = allNay.reduce((total: BN, { balance }) => total.add(balance), new BN(0)); + const hasVotedAye = allAye.some(({ accountId }) => allAccounts.includes(accountId.toString())); - setPercentages({ - aye: votedTotal.isZero() - ? '' - : `${(aye.muln(10000).div(votedTotal).toNumber() / 100).toFixed(2)}%`, - nay: votedTotal.isZero() - ? '' - : `${(nay.muln(10000).div(votedTotal).toNumber() / 100).toFixed(2)}%`, - turnout: `${((votedTotal.muln(10000).div(totalIssuance).toNumber()) / 100).toFixed(2)}%` - }); - setHasVoted({ hasVoted, hasVotedAye }); - } - }, [allAccounts, allAye, allNay, totalIssuance, votedTotal]); + return [ + { + aye: votedTotal.isZero() + ? '' + : `${(aye.muln(10000).div(votedTotal).toNumber() / 100).toFixed(2)}%`, + nay: votedTotal.isZero() + ? '' + : `${(nay.muln(10000).div(votedTotal).toNumber() / 100).toFixed(2)}%`, + turnout: `${((votedTotal.muln(10000).div(totalIssuance).toNumber()) / 100).toFixed(2)}%` + }, + { + hasVoted: hasVotedAye || allNay.some(({ accountId }) => allAccounts.includes(accountId.toString())), + hasVotedAye + } + ]; + } else { + return [null, { hasVoted: false, hasVotedAye: false }]; + } + }, + [allAccounts, allAye, allNay, totalIssuance, votedTotal] + ); if (!bestNumber || status.end.sub(bestNumber).lten(0)) { return null; @@ -102,22 +109,6 @@ function Referendum ({ className = '', value: { allAye, allNay, image, imageHash )} - - {isBoolean(isPassing) && ( )} + + + + {!image?.proposal && ( diff --git a/packages/page-democracy/src/Overview/ReferendumVotes.tsx b/packages/page-democracy/src/Overview/ReferendumVotes.tsx index ab8ff777eb..038cdeffe3 100644 --- a/packages/page-democracy/src/Overview/ReferendumVotes.tsx +++ b/packages/page-democracy/src/Overview/ReferendumVotes.tsx @@ -5,8 +5,7 @@ import { DeriveReferendumVote } from '@polkadot/api-derive/types'; import BN from 'bn.js'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; +import React, { useMemo, useState } from 'react'; import { Expander, Icon, Tooltip } from '@polkadot/react-components'; import { FormatBalance } from '@polkadot/react-query'; import { formatNumber } from '@polkadot/util'; @@ -18,6 +17,7 @@ interface Props { change: BN; className?: string; count: number; + isAye: boolean; isWinning: boolean; index: BN; total: BN; @@ -28,75 +28,67 @@ const LOCKS = [1, 10, 20, 30, 40, 50, 60]; let id = 0; -function ReferendumVotes ({ change, className = '', count, index, isWinning, total, votes }: Props): React.ReactElement { +function ReferendumVotes ({ change, className, count, index, isAye, isWinning, total, votes }: Props): React.ReactElement | null { const { t } = useTranslation(); const [trigger] = useState(`votes-${index.toString()}-${++id}`); - const [sorted, setSorted] = useState([]); - useEffect((): void => { - setSorted( - votes.sort((a, b) => { - const ta = a.balance.muln(LOCKS[a.vote.conviction.toNumber()]).divn(10); - const tb = b.balance.muln(LOCKS[b.vote.conviction.toNumber()]).divn(10); + const sorted = useMemo( + () => votes.sort((a, b) => { + const ta = a.balance.muln(LOCKS[a.vote.conviction.toNumber()]).divn(10); + const tb = b.balance.muln(LOCKS[b.vote.conviction.toNumber()]).divn(10); - return tb.cmp(ta); - }) - ); - }, [votes]); + return tb.cmp(ta); + }), + [votes] + ); + + if (!count) { + return null; + } return ( - - - } - summarySub={ - change.gtn(0) - ? ( - <> - - - ('The amount this total can be reduced by to change the referendum outcome. This assumes changes to the convictions of the existing votes, with no additional turnout.') - : t('The amount this total should be increased by to change the referendum outcome. This assumes additional turnout with new votes at 1x conviction.') - } - trigger={trigger} - /> - - ) - : '' - } - > - {sorted.map((vote) => - - )} - - + + {isAye + ? t('Aye {{count}}', { replace: { count: ` (${formatNumber(count)})` } }) + : t('Nay {{count}}', { replace: { count: ` (${formatNumber(count)})` } }) + } +
+ + } + summarySub={ +
+ {change.gtn(0) && ( +
+ + + ('The amount this total can be reduced by to change the referendum outcome. This assumes changes to the convictions of the existing votes, with no additional turnout.') + : t('The amount this total should be increased by to change the referendum outcome. This assumes additional turnout with new votes at 1x conviction.') + } + trigger={trigger} + /> +
+ )} +
+ } + > + {sorted.map((vote) => + + )} +
); } -export default React.memo(styled(ReferendumVotes)` - .ui--Expander .ui--Expander-summary .double-icon { - margin-bottom: -0.125rem; - margin-right: 0.375rem; - margin-top: 0.125rem; - } - - .ui--Expander-summary { - .ui--Icon+.ui--Icon { - margin-left: -0.375rem; - } - } -`); +export default React.memo(ReferendumVotes); diff --git a/packages/page-democracy/src/Overview/Referendums.tsx b/packages/page-democracy/src/Overview/Referendums.tsx index fdcba283a4..752a0f7614 100644 --- a/packages/page-democracy/src/Overview/Referendums.tsx +++ b/packages/page-democracy/src/Overview/Referendums.tsx @@ -23,10 +23,9 @@ function Referendums ({ className = '', referendums }: Props): React.ReactElemen [t('remaining'), 'media--1200'], [t('activate'), 'media--1400'], [t('turnout'), 'media--1400'], - [t('aye')], - [t('nay')], - [undefined, undefined, 2], [undefined, 'badge'], + [t('votes'), 'start'], + [undefined, undefined, 2], [undefined, 'mini media--1000'] ]); diff --git a/packages/react-components/src/Table/Body.tsx b/packages/react-components/src/Table/Body.tsx index a8b215f081..e22e94ac54 100644 --- a/packages/react-components/src/Table/Body.tsx +++ b/packages/react-components/src/Table/Body.tsx @@ -84,6 +84,14 @@ export default React.memo(styled(Body)` border-top-width: 0; } + &.expand { + text-align: left; + + .ui--Expander+.ui--Expander { + margin-top: 0.5rem; + } + } + &.hash { font-family: monospace; }