diff --git a/package.json b/package.json index e2e71b8fd1..fba1ff6c8b 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,10 @@ "packages/*" ], "resolutions": { - "@polkadot/api": "^1.0.0-beta.25", - "@polkadot/api-contract": "^1.0.0-beta.25", + "@polkadot/api": "^1.0.0-beta.26", + "@polkadot/api-contract": "^1.0.0-beta.26", "@polkadot/keyring": "^2.0.0-beta.6", - "@polkadot/types": "^1.0.0-beta.25", + "@polkadot/types": "^1.0.0-beta.26", "@polkadot/util": "^2.0.0-beta.6", "@polkadot/util-crypto": "^2.0.0-beta.6", "babel-core": "^7.0.0-bridge.0", diff --git a/packages/app-contracts/package.json b/packages/app-contracts/package.json index bded1dc406..806785bc1a 100644 --- a/packages/app-contracts/package.json +++ b/packages/app-contracts/package.json @@ -11,6 +11,6 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.8.3", - "@polkadot/api-contract": "^1.0.0-beta.25" + "@polkadot/api-contract": "^1.0.0-beta.26" } } diff --git a/packages/app-democracy/src/Overview/Proposal.tsx b/packages/app-democracy/src/Overview/Proposal.tsx index fb3835267a..c778be8138 100644 --- a/packages/app-democracy/src/Overview/Proposal.tsx +++ b/packages/app-democracy/src/Overview/Proposal.tsx @@ -38,7 +38,7 @@ function Proposal ({ className, value: { balance, hash, index, proposal, propose proposalHash={hash} proposal={proposal} /> - + {seconding.length !== 0 && (
@@ -83,8 +83,4 @@ export default styled(Proposal)` margin-bottom: 4px; } } - - .seconding { - padding-top: 1.1rem; - } `; diff --git a/packages/app-society/src/Overview/Candidate.tsx b/packages/app-society/src/Overview/Candidate.tsx index 3a0803216d..e333afca98 100644 --- a/packages/app-society/src/Overview/Candidate.tsx +++ b/packages/app-society/src/Overview/Candidate.tsx @@ -3,19 +3,53 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { DeriveSocietyCandidate } from '@polkadot/api-derive/types'; +import { AccountId, SocietyVote } from '@polkadot/types/interfaces'; -import React from 'react'; -import { AddressSmall } from '@polkadot/react-components'; +import React, { useEffect, useState } from 'react'; +import { AddressMini, AddressSmall } from '@polkadot/react-components'; +import { useApi, useCall } from '@polkadot/react-hooks'; import { FormatBalance } from '@polkadot/react-query'; +import { Option } from '@polkadot/types'; import { useTranslation } from '../translate'; +import CandidateVoting from './CandidateVoting'; interface Props { + allMembers: string[]; + isMember: boolean; + ownMembers: string[]; value: DeriveSocietyCandidate; } -export default function Candidate ({ value: { accountId, kind, value } }: Props): React.ReactElement { +type VoteType = [string, SocietyVote]; + +interface VoteSplit { + allAye: VoteType[]; + allNay: VoteType[]; + allSkeptic: VoteType[]; +} + +export default function Candidate ({ allMembers, isMember, ownMembers, value: { accountId, kind, value } }: Props): React.ReactElement { const { t } = useTranslation(); + const { api } = useApi(); + const [{ allAye, allNay, allSkeptic }, setVoteSplit] = useState({ allAye: [], allNay: [], allSkeptic: [] }); + const votes = useCall(api.query.society.votes.multi as any, [allMembers.map((memberId): [AccountId, string] => [accountId, memberId])] as any, { + transform: (voteOpts: Option[]): VoteType[] => + voteOpts + .map((voteOpt, index): [string, Option] => [allMembers[index], voteOpt]) + .filter(([, voteOpt]): boolean => voteOpt.isSome) + .map(([accountId, voteOpt]): VoteType => [accountId, voteOpt.unwrap()]) + }); + + useEffect((): void => { + if (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 ( @@ -32,6 +66,58 @@ export default function Candidate ({ value: { accountId, kind, value } }: Props) value={value} /> + + {allSkeptic.length !== 0 && ( +
+ + {t('Skeptics ({{count}})', { replace: { count: allSkeptic.length } })} + + {allSkeptic.map(([who]): React.ReactNode => + + )} +
+ )} + + + {allAye.length !== 0 && ( +
+ + {t('Approvals ({{count}})', { replace: { count: allAye.length } })} + + {allAye.map(([who]): React.ReactNode => + + )} +
+ )} + + + {allNay.length !== 0 && ( +
+ + {t('Rejections ({{count}})', { replace: { count: allNay.length } })} + + {allNay.map(([who]): React.ReactNode => + + )} +
+ )} + + + + ); } diff --git a/packages/app-society/src/Overview/CandidateVoting.tsx b/packages/app-society/src/Overview/CandidateVoting.tsx new file mode 100644 index 0000000000..40762bfbe8 --- /dev/null +++ b/packages/app-society/src/Overview/CandidateVoting.tsx @@ -0,0 +1,67 @@ +// 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 React, { useMemo, useState } from 'react'; +import { useToggle } from '@polkadot/react-hooks'; + +import { useTranslation } from '../translate'; +import { Button, Dropdown, InputAddress, Modal, TxButton } from '@polkadot/react-components'; + +interface Props { + candidateId: string; + isMember: boolean; + ownMembers: string[]; +} + +export default function CandidateVoting ({ candidateId, isMember, ownMembers }: Props): React.ReactElement { + const { t } = useTranslation(); + const [isVisible, toggleVisible] = useToggle(); + const [vote, setVote] = useState(true); + const [accountId, setAccountId] = useState(null); + const voteOpts = useMemo(() => [ + { text: t('Aye, I approve'), value: true }, + { text: t('Nay, I do not approve'), value: false } + ], [t]); + + return ( + <> + {isVisible && ( + + + + + + + + + + )} +