Skip to content

Commit

Permalink
Society vouching (#2204)
Browse files Browse the repository at this point in the history
* Society vouching

* Bump API, decode votes

* Inline count

* Remove unused style
  • Loading branch information
jacogr authored Jan 28, 2020
1 parent b896cd3 commit 5cab16d
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 67 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/app-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
6 changes: 1 addition & 5 deletions packages/app-democracy/src/Overview/Proposal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function Proposal ({ className, value: { balance, hash, index, proposal, propose
proposalHash={hash}
proposal={proposal}
/>
<td className='top seconding'>
<td className='top padtop'>
{seconding.length !== 0 && (
<details>
<summary>
Expand Down Expand Up @@ -83,8 +83,4 @@ export default styled(Proposal)`
margin-bottom: 4px;
}
}
.seconding {
padding-top: 1.1rem;
}
`;
92 changes: 89 additions & 3 deletions packages/app-society/src/Overview/Candidate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> {
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<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [{ allAye, allNay, allSkeptic }, setVoteSplit] = useState<VoteSplit>({ allAye: [], allNay: [], allSkeptic: [] });
const votes = useCall<VoteType[]>(api.query.society.votes.multi as any, [allMembers.map((memberId): [AccountId, string] => [accountId, memberId])] as any, {
transform: (voteOpts: Option<SocietyVote>[]): VoteType[] =>
voteOpts
.map((voteOpt, index): [string, Option<SocietyVote>] => [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 (
<tr>
Expand All @@ -32,6 +66,58 @@ export default function Candidate ({ value: { accountId, kind, value } }: Props)
value={value}
/>
</td>
<td className='top padtop'>
{allSkeptic.length !== 0 && (
<details>
<summary>
{t('Skeptics ({{count}})', { replace: { count: allSkeptic.length } })}
</summary>
{allSkeptic.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</details>
)}
</td>
<td className='top padtop'>
{allAye.length !== 0 && (
<details>
<summary>
{t('Approvals ({{count}})', { replace: { count: allAye.length } })}
</summary>
{allAye.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</details>
)}
</td>
<td className='top padtop'>
{allNay.length !== 0 && (
<details>
<summary>
{t('Rejections ({{count}})', { replace: { count: allNay.length } })}
</summary>
{allNay.map(([who]): React.ReactNode =>
<AddressMini
key={who.toString()}
value={who}
/>
)}
</details>
)}
</td>
<td className='number together top'>
<CandidateVoting
candidateId={accountId.toString()}
isMember={isMember}
ownMembers={ownMembers}
/>
</td>
</tr>
);
}
67 changes: 67 additions & 0 deletions packages/app-society/src/Overview/CandidateVoting.tsx
Original file line number Diff line number Diff line change
@@ -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<Props> {
const { t } = useTranslation();
const [isVisible, toggleVisible] = useToggle();
const [vote, setVote] = useState(true);
const [accountId, setAccountId] = useState<string | null>(null);
const voteOpts = useMemo(() => [
{ text: t('Aye, I approve'), value: true },
{ text: t('Nay, I do not approve'), value: false }
], [t]);

return (
<>
{isVisible && (
<Modal header={t('Vote for candidate')}>
<Modal.Content>
<InputAddress
filter={ownMembers}
help={t('The address to vote from (must be a member)')}
label={t('vote from account')}
onChange={setAccountId}
/>
<Dropdown
help={t('Approve this candidacy.')}
label={t('vote for andidate')}
onChange={setVote}
options={voteOpts}
value={vote}
/>
</Modal.Content>
<Modal.Actions onCancel={toggleVisible}>
<TxButton
accountId={accountId}
icon='check'
label={t('Vote')}
onStart={toggleVisible}
params={[candidateId, vote]}
tx='society.vote'
/>
</Modal.Actions>
</Modal>
)}
<Button
icon='check'
isDisabled={!isMember}
isPrimary
label={t('Vote')}
onClick={toggleVisible}
/>
</>
);
}
5 changes: 5 additions & 0 deletions packages/app-society/src/Overview/Candidates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Table } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';

import { useTranslation } from '../translate';
import useMembers from '../useMembers';
import Candidate from './Candidate';

interface Props {
Expand All @@ -19,6 +20,7 @@ export default function Candidates ({ className }: Props): React.ReactElement<Pr
const { t } = useTranslation();
const { api } = useApi();
const candidates = useCall<DeriveSocietyCandidate[]>(api.derive.society.candidates, []);
const { allMembers, isMember, ownMembers } = useMembers();

return (
<div className={`overviewSection ${className}`}>
Expand All @@ -29,7 +31,10 @@ export default function Candidates ({ className }: Props): React.ReactElement<Pr
<Table.Body>
{candidates.map((candidate): React.ReactNode => (
<Candidate
allMembers={allMembers}
isMember={isMember}
key={candidate.accountId.toString()}
ownMembers={ownMembers}
value={candidate}
/>
))}
Expand Down
35 changes: 35 additions & 0 deletions packages/app-society/src/useMembers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 { DeriveSocietyMember } from '@polkadot/api-derive/types';

import { useEffect, useState } from 'react';
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';

interface OwnMembers {
allMembers: string[];
isMember: boolean;
ownMembers: string[];
}

export default function useMembers (): OwnMembers {
const { api } = useApi();
const { allAccounts } = useAccounts();
const members = useCall<DeriveSocietyMember[]>(api.derive.society.members, []);
const [ownState, setOwnState] = useState<OwnMembers>({ allMembers: [], isMember: false, ownMembers: [] });

useEffect((): void => {
if (allAccounts && members) {
const allMembers = members
.filter((member): boolean => !member.isSuspended)
.map((member): string => member.accountId.toString());
const ownMembers = allMembers
.filter((address): boolean => allAccounts.includes(address));

setOwnState({ allMembers, isMember: ownMembers.length !== 0, ownMembers });
}
}, [allAccounts, members]);

return ownState;
}
2 changes: 1 addition & 1 deletion packages/react-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.8.3",
"@polkadot/api": "^1.0.0-beta.25",
"@polkadot/api": "^1.0.0-beta.26",
"@polkadot/extension-dapp": "^0.20.1",
"edgeware-node-types": "^1.1.0",
"rxjs-compat": "^6.5.3"
Expand Down
5 changes: 2 additions & 3 deletions packages/react-components/src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,8 @@ export default styled(Table)`
}
}
&.toppad {
padding-top: 1.25rem;
vertical-align: top;
&.padtop {
padding-top: 1.1rem;
}
}
Expand Down
11 changes: 6 additions & 5 deletions packages/react-components/src/VoteToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 React from 'react';
import React, { useMemo } from 'react';

import Dropdown from './Dropdown';
import { useTranslation } from './translate';
Expand All @@ -15,16 +15,17 @@ interface Props {

export default function VoteToggle ({ className, onChange, value }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const voteOpts = useMemo(() => [
{ text: t('Aye, I approve'), value: true },
{ text: t('Nay, I do not approve'), value: false }
], [t]);

return (
<Dropdown
className={className}
help={t('Select your vote preferences for this proposal, either to approve or disapprove')}
label={t('record my vote as')}
options={[
{ text: t('Aye, I approve'), value: true },
{ text: t('Nay, I do not approve'), value: false }
]}
options={voteOpts}
onChange={onChange}
value={value}
/>
Expand Down
Loading

0 comments on commit 5cab16d

Please sign in to comment.