Dedupe votes display (#2507)

This commit is contained in:
Jaco Greeff 2020-04-03 16:50:38 +02:00 committed by GitHub
parent 109c6baa72
commit 305283b09b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 126 additions and 109 deletions

View File

@ -8,11 +8,12 @@ import { DeriveCollectiveProposal } from '@polkadot/api-derive/types';
import BN from 'bn.js';
import React from 'react';
import ProposalCell from '@polkadot/app-democracy/Overview/ProposalCell';
import { AddressMini, LinkExternal } from '@polkadot/react-components';
import { LinkExternal } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import { BlockToTime } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
import Votes from './Votes';
import Voting from './Voting';
interface Props {
@ -40,7 +41,7 @@ function Motion ({ className, isMember, members, motion: { hash, proposal, votes
imageHash={hash}
proposal={proposal}
/>
<td className='number'>
<td className='number together'>
{formatNumber(ayes.length)}/{formatNumber(threshold)}
</td>
<td className='number together'>
@ -51,24 +52,8 @@ function Motion ({ className, isMember, members, motion: { hash, proposal, votes
</>
)}
</td>
<td className='address'>
{ayes.map((address, index): React.ReactNode => (
<AddressMini
key={`${index}:${address}`}
value={address}
withBalance={false}
/>
))}
</td>
<td className='address'>
{nays.map((address, index): React.ReactNode => (
<AddressMini
key={`${index}:${address}`}
value={address}
withBalance={false}
/>
))}
</td>
<Votes votes={ayes} />
<Votes votes={nays} />
<td className='button'>
<Voting
hash={hash}

View File

@ -34,21 +34,17 @@ function Slashing ({ className, isMember, members }: Props): React.ReactElement<
const threshold = Math.ceil((members.length || 0) * 0.5);
useEffect((): void => {
if (slashes?.length) {
setEras(
slashes.map(([era, slashes]): Option => ({
text: t('era {{era}}, {{count}} slashes', {
replace: {
count: slashes.length,
era: era.toNumber()
}
}),
value: era.toNumber()
}))
);
} else {
setEras([]);
}
setEras(
(slashes || []).map(([era, slashes]): Option => ({
text: t('era {{era}}, {{count}} slashes', {
replace: {
count: slashes.length,
era: era.toNumber()
}
}),
value: era.toNumber()
}))
);
}, [slashes, t]);
useEffect((): void => {

View File

@ -0,0 +1,28 @@
// 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 } from '@polkadot/types/interfaces';
import React from 'react';
import { AddressMini } from '@polkadot/react-components';
interface Props {
votes: AccountId[];
}
function Votes ({ votes }: Props): React.ReactElement<Props> {
return (
<td className='address'>
{votes.map((address): React.ReactNode => (
<AddressMini
key={address.toString()}
value={address}
withBalance={false}
/>
))}
</td>
);
}
export default React.memo(Votes);

View File

@ -13,7 +13,7 @@ import { FormatBalance } from '@polkadot/react-query';
import { Option } from '@polkadot/types';
import CandidateVoting from './CandidateVoting';
import VoteDisplay from './VoteDisplay';
import Votes from './Votes';
interface Props {
allMembers: string[];
@ -43,7 +43,7 @@ function Candidate ({ allMembers, isMember, ownMembers, value: { accountId, kind
<td className='number'>
<FormatBalance value={value} />
</td>
<VoteDisplay votes={votes} />
<Votes votes={votes} />
<td className='button'>
<CandidateVoting
candidateId={accountId.toString()}

View File

@ -12,7 +12,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
import { useTranslation } from '../translate';
import DefenderVoting from './DefenderVoting';
import VoteDisplay from './VoteDisplay';
import Votes from './Votes';
interface Props extends OwnMembers {
className?: string;
@ -45,7 +45,7 @@ function Defender ({ className, info, isMember, ownMembers }: Props): React.Reac
<td className='address all'>
<AddressSmall value={info.defender} />
</td>
<VoteDisplay votes={votes} />
<Votes votes={votes} />
<td className='button'>
<DefenderVoting
isMember={isMember}

View File

@ -1,70 +0,0 @@
// Copyright 2017-2020 @polkadot/app-society 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 { VoteSplit, VoteType } from '../types';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { AddressMini, Expander } from '@polkadot/react-components';
import { useTranslation } from '../translate';
interface Props {
className?: string;
votes?: VoteType[];
}
function VoteDisplay ({ className, votes }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [{ allAye, allNay, allSkeptic }, setVoteSplit] = useState<VoteSplit>({ allAye: [], allNay: [], allSkeptic: [] });
useEffect((): void => {
votes && setVoteSplit({
allAye: votes.filter(([, vote]): boolean => vote.isApprove),
allNay: votes.filter(([, vote]): boolean => vote.isReject),
allSkeptic: votes.filter(([, vote]): boolean => vote.isSkeptic)
});
}, [votes]);
return (
<td className={className}>
{allSkeptic.length !== 0 && (
<Expander summary={t('Skeptics ({{count}})', { replace: { count: allSkeptic.length } })}>
{allSkeptic.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</Expander>
)}
{allAye.length !== 0 && (
<Expander summary={t('Approvals ({{count}})', { replace: { count: allAye.length } })}>
{allAye.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</Expander>
)}
{allNay.length !== 0 && (
<Expander summary={t('Rejections ({{count}})', { replace: { count: allNay.length } })}>
{allNay.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</Expander>
)}
</td>
);
}
export default React.memo(styled(VoteDisplay)`
.ui--Expander+ui--Expander {
margin-left: 0.5rem;
}
`);

View File

@ -0,0 +1,46 @@
// Copyright 2017-2020 @polkadot/app-society 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 { VoteSplit, VoteType } from '../types';
import React, { useEffect, useState } from 'react';
import { useTranslation } from '../translate';
import VotesExpander from './VotesExpander';
interface Props {
votes?: VoteType[];
}
function Votes ({ votes }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [{ allAye, allNay, allSkeptic }, setVoteSplit] = useState<VoteSplit>({ allAye: [], allNay: [], allSkeptic: [] });
useEffect((): void => {
votes && setVoteSplit({
allAye: votes.filter(([, vote]): boolean => vote.isApprove),
allNay: votes.filter(([, vote]): boolean => vote.isReject),
allSkeptic: votes.filter(([, vote]): boolean => vote.isSkeptic)
});
}, [votes]);
return (
<td className='start'>
<VotesExpander
label={t('Skeptics')}
votes={allSkeptic}
/>
<VotesExpander
label={t('Approvals')}
votes={allAye}
/>
<VotesExpander
label={t('Rejections')}
votes={allNay}
/>
</td>
);
}
export default React.memo(Votes);

View File

@ -0,0 +1,32 @@
// Copyright 2017-2020 @polkadot/app-society 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 { VoteType } from '../types';
import React from 'react';
import { AddressMini, Expander } from '@polkadot/react-components';
interface Props {
label: string;
votes: VoteType[];
}
function VotesExpander ({ label, votes }: Props): React.ReactElement<Props> | null {
if (votes.length === 0) {
return null;
}
return (
<Expander summary={`${label} (${votes.length})`}>
{votes.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</Expander>
);
}
export default React.memo(VotesExpander);