From 4484883afca911b4f126cff1820716dcbab2b4d1 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 15 Aug 2018 10:35:53 +0200 Subject: [PATCH] Basic democracy (Referendum) overview (#216) * Basic democacry (Referendum) overview * Summary in-place * Fix package name * Proposals & Referendums are showing up * Some basic Extrinsic formatting. (WIP) * Basic referendum/proposal summary in place * Referendum outcome chart * Voting in place. It works. * Remove extra console.log/error * Only show balances as label --- jest.config.js | 2 +- packages/app-democracy/LICENSE | 15 + packages/app-democracy/README.md | 1 + packages/app-democracy/package.json | 19 ++ packages/app-democracy/src/Extrinsic.tsx | 45 +++ packages/app-democracy/src/Item.tsx | 64 ++++ packages/app-democracy/src/Proposal.tsx | 86 ++++++ packages/app-democracy/src/Proposals.tsx | 64 ++++ packages/app-democracy/src/Referendum.tsx | 171 +++++++++++ packages/app-democracy/src/Referendums.tsx | 64 ++++ packages/app-democracy/src/Summary.tsx | 79 +++++ packages/app-democracy/src/Voting.tsx | 72 +++++ packages/app-democracy/src/VotingButtons.tsx | 78 +++++ packages/app-democracy/src/index.css | 100 +++++++ packages/app-democracy/src/index.tsx | 28 ++ packages/app-democracy/src/translate.ts | 7 + packages/app-example/package.json | 2 +- packages/app-explorer/package.json | 2 +- packages/app-extrinsics/package.json | 2 +- packages/app-extrinsics/src/Account.tsx | 4 +- .../app-extrinsics/src/Params/Account.tsx | 2 +- .../app-extrinsics/src/Params/Extrinsic.tsx | 4 +- packages/app-staking/package.json | 2 +- packages/app-staking/src/Account.tsx | 4 +- packages/app-staking/src/StakeList.tsx | 4 +- packages/app-staking/src/Summary.tsx | 13 +- packages/app-staking/src/index.tsx | 4 +- packages/apps/package.json | 1 + .../apps/public/locales/en/democracy.json | 1 + packages/apps/public/locales/en/staking.json | 1 + packages/apps/src/routing/democracy.ts | 20 ++ packages/apps/src/routing/index.ts | 16 +- packages/apps/webpack.config.js | 20 +- packages/ui-app/package.json | 12 +- packages/ui-app/src/AddressMini.tsx | 5 +- packages/ui-app/src/Button/index.tsx | 5 +- packages/ui-app/src/Button/types.d.ts | 1 + packages/ui-app/src/CardSummary.tsx | 2 +- packages/ui-app/src/Chart/Doughnut.tsx | 69 +++++ packages/ui-app/src/Params/Param/Account.tsx | 4 +- packages/ui-app/src/Params/Param/Amount.tsx | 6 +- packages/ui-app/src/Params/Param/Base.tsx | 7 +- .../ui-app/src/Params/Param/BaseBytes.tsx | 9 +- packages/ui-app/src/Params/Param/Bool.tsx | 4 +- packages/ui-app/src/Params/Param/Code.tsx | 11 +- packages/ui-app/src/Params/Param/File.tsx | 4 +- packages/ui-app/src/Params/Param/Hash.tsx | 2 +- .../{KeyValue.tsx => StorageKeyValue.tsx} | 4 +- ...rageArray.tsx => StorageKeyValueArray.tsx} | 45 ++- packages/ui-app/src/Params/Param/String.tsx | 7 +- .../ui-app/src/Params/Param/VoteThreshold.tsx | 7 +- .../ui-app/src/Params/Param/findComponent.ts | 20 +- packages/ui-app/src/Params/Param/index.tsx | 8 +- packages/ui-app/src/Params/index.tsx | 39 ++- packages/ui-app/src/Params/initValue.ts | 2 +- packages/ui-app/src/Params/types.d.ts | 5 +- packages/ui-app/src/styles/app.css | 6 + packages/ui-app/src/styles/components.css | 13 + packages/ui-react-rx/package.json | 6 +- .../index.ts} | 282 +++++++++++++++--- .../ui-react-rx/src/ApiObservable/types.d.ts | 92 ++++++ packages/ui-react-rx/src/types.d.ts | 50 +--- packages/ui-react-rx/src/with/observable.tsx | 5 +- .../ui-react-rx/src/with/observableDiv.ts | 3 +- packages/ui-signer/package.json | 2 +- tsconfig.json | 1 + yarn.lock | 125 +++++--- 67 files changed, 1626 insertions(+), 234 deletions(-) create mode 100644 packages/app-democracy/LICENSE create mode 100644 packages/app-democracy/README.md create mode 100644 packages/app-democracy/package.json create mode 100644 packages/app-democracy/src/Extrinsic.tsx create mode 100644 packages/app-democracy/src/Item.tsx create mode 100644 packages/app-democracy/src/Proposal.tsx create mode 100644 packages/app-democracy/src/Proposals.tsx create mode 100644 packages/app-democracy/src/Referendum.tsx create mode 100644 packages/app-democracy/src/Referendums.tsx create mode 100644 packages/app-democracy/src/Summary.tsx create mode 100644 packages/app-democracy/src/Voting.tsx create mode 100644 packages/app-democracy/src/VotingButtons.tsx create mode 100644 packages/app-democracy/src/index.css create mode 100644 packages/app-democracy/src/index.tsx create mode 100644 packages/app-democracy/src/translate.ts create mode 100644 packages/apps/public/locales/en/democracy.json create mode 100644 packages/apps/public/locales/en/staking.json create mode 100644 packages/apps/src/routing/democracy.ts create mode 100644 packages/ui-app/src/Chart/Doughnut.tsx rename packages/ui-app/src/Params/Param/{KeyValue.tsx => StorageKeyValue.tsx} (95%) rename packages/ui-app/src/Params/Param/{KeyValueStorageArray.tsx => StorageKeyValueArray.tsx} (69%) rename packages/ui-react-rx/src/{ApiObservable.ts => ApiObservable/index.ts} (56%) create mode 100644 packages/ui-react-rx/src/ApiObservable/types.d.ts diff --git a/jest.config.js b/jest.config.js index f65223627a..65d8ea1d37 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,7 @@ const config = require('@polkadot/dev-react/config/jest'); module.exports = Object.assign({}, config, { moduleNameMapper: { - '@polkadot/app-(accounts|addresses|example|explorer|extrinsics|rpc|staking|storage|toolbox|vanitygen)(.*)$': '/packages/ui-$1/src/$2', + '@polkadot/app-(accounts|addresses|democracy|example|explorer|extrinsics|rpc|staking|storage|toolbox|vanitygen)(.*)$': '/packages/ui-$1/src/$2', '@polkadot/ui-(app|identicon|keyring|react-rx|react|signer)(.*)$': '/packages/ui-$1/src/$2', '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object', '\\.(css|less)$': 'empty/object' diff --git a/packages/app-democracy/LICENSE b/packages/app-democracy/LICENSE new file mode 100644 index 0000000000..3f30c1da65 --- /dev/null +++ b/packages/app-democracy/LICENSE @@ -0,0 +1,15 @@ +ISC License (ISC) + +Copyright 2017-2018 @polkadot/app-democracy authors & contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/app-democracy/README.md b/packages/app-democracy/README.md new file mode 100644 index 0000000000..afd905e52f --- /dev/null +++ b/packages/app-democracy/README.md @@ -0,0 +1 @@ +# @polkadot/app-democracy diff --git a/packages/app-democracy/package.json b/packages/app-democracy/package.json new file mode 100644 index 0000000000..83d614e4eb --- /dev/null +++ b/packages/app-democracy/package.json @@ -0,0 +1,19 @@ +{ + "name": "@polkadot/app-democracy", + "version": "0.19.30", + "description": "A referendum & proposal app", + "main": "index.js", + "scripts": {}, + "author": "Jaco Greeff ", + "maintainers": [ + "Jaco Greeff " + ], + "license": "ISC", + "dependencies": { + "@babel/runtime": "^7.0.0-beta.51", + "@polkadot/storage": "^0.28.11", + "@polkadot/ui-react": "^0.19.30", + "@polkadot/ui-react-rx": "^0.19.30", + "@polkadot/util-keyring": "^0.28.1" + } +} diff --git a/packages/app-democracy/src/Extrinsic.tsx b/packages/app-democracy/src/Extrinsic.tsx new file mode 100644 index 0000000000..a8d4e41331 --- /dev/null +++ b/packages/app-democracy/src/Extrinsic.tsx @@ -0,0 +1,45 @@ +// Copyright 2017-2018 @polkadot/ui-app authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { ExtrinsicDecoded } from '@polkadot/params/types'; +import { I18nProps } from '@polkadot/ui-app/types'; +import { RawParam } from '@polkadot/ui-app/Params/types'; + +import React from 'react'; +import Params from '@polkadot/ui-app/Params'; +import classes from '@polkadot/ui-app/util/classes'; + +import translate from './translate'; + +export type Props = I18nProps & { + children?: React.ReactNode, + value: ExtrinsicDecoded +}; + +class Extrinsic extends React.PureComponent { + render () { + const { children, className, style, value: { extrinsic, params } } = this.props; + const values: Array = extrinsic.params.map(({ type }, index) => ({ + isValid: true, + value: params[index], + type + })); + + return ( +
+ {children} + +
+ ); + } +} + +export default translate(Extrinsic); diff --git a/packages/app-democracy/src/Item.tsx b/packages/app-democracy/src/Item.tsx new file mode 100644 index 0000000000..9e434b0026 --- /dev/null +++ b/packages/app-democracy/src/Item.tsx @@ -0,0 +1,64 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { ExtrinsicDecoded } from '@polkadot/params/types'; +import { I18nProps } from '@polkadot/ui-app/types'; + +import BN from 'bn.js'; +import React from 'react'; +import Card from '@polkadot/ui-app/Card'; +import classes from '@polkadot/ui-app/util/classes'; +import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; + +// TODO This would be nice as a shared component, move to ui-app as soon as +// we have actual "more-than-one-use" apps +import Extrinsic from './Extrinsic'; +import translate from './translate'; + +type Props = I18nProps & { + children?: React.ReactNode, + proposal: ExtrinsicDecoded, + proposalExtra?: React.ReactNode, + idNumber: BN +}; + +class Item extends React.PureComponent { + render () { + const { children, className, idNumber, proposal, proposalExtra, style } = this.props; + + return ( + +
+
+
+ {proposal.extrinsic.section}.{proposal.extrinsic.name} +
+
+ {proposal.extrinsic.description} +
+
+
+ #{numberFormat(idNumber)} +
+
+
+ + {proposalExtra} + +
+ {children} +
+
+
+ ); + } +} + +export default translate(Item); diff --git a/packages/app-democracy/src/Proposal.tsx b/packages/app-democracy/src/Proposal.tsx new file mode 100644 index 0000000000..91c2527ea8 --- /dev/null +++ b/packages/app-democracy/src/Proposal.tsx @@ -0,0 +1,86 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { RxProposal, RxProposalDeposits } from '@polkadot/ui-react-rx/ApiObservable/types'; + +import BN from 'bn.js'; +import React from 'react'; +import AddressMini from '@polkadot/ui-app/AddressMini'; +import Labelled from '@polkadot/ui-app/Labelled'; +import Static from '@polkadot/ui-app/Static'; +import classes from '@polkadot/ui-app/util/classes'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; +import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; + +import Item from './Item'; +import translate from './translate'; + +type Props = I18nProps & { + democracyProposalDeposits?: RxProposalDeposits, + idNumber: BN, + value: RxProposal +}; + +class Proposal extends React.PureComponent { + render () { + const { className, idNumber, style, value } = this.props; + + return ( + + {this.renderVoting()} + + ); + } + + private renderExtra () { + const { democracyProposalDeposits, t } = this.props; + + if (!democracyProposalDeposits) { + return null; + } + + const { balance, addresses } = democracyProposalDeposits; + + return ( +
+ +
+ {addresses.map((address) => ( + + ))} +
+
+ + {numberFormat(balance)} + +
+ ); + } + + private renderVoting () { + return null; + } +} + +export default withMulti( + Proposal, + translate, + withObservable('democracyProposalDeposits', { paramProp: 'idNumber' }) +); diff --git a/packages/app-democracy/src/Proposals.tsx b/packages/app-democracy/src/Proposals.tsx new file mode 100644 index 0000000000..ce50f80956 --- /dev/null +++ b/packages/app-democracy/src/Proposals.tsx @@ -0,0 +1,64 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { RxProposal } from '@polkadot/ui-react-rx/ApiObservable/types'; + +import React from 'react'; +import classes from '@polkadot/ui-app/util/classes'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; + +import Proposal from './Proposal'; +import translate from './translate'; + +type Props = I18nProps & { + democracyProposals?: Array +}; + +class Proposals extends React.PureComponent { + render () { + const { className, style, t } = this.props; + + return ( +
+

{t('proposals.header', { + defaultValue: 'proposals' + })}

+ {this.renderProposals()} +
+ ); + } + + private renderProposals () { + const { democracyProposals, t } = this.props; + + if (!democracyProposals || !democracyProposals.length) { + return ( +
+ {t('proposals.none', { + defaultValue: 'no available proposals' + })} +
+ ); + } + + return democracyProposals.map((proposal) => ( + + )); + } +} + +export default withMulti( + Proposals, + translate, + withObservable('democracyProposals') +); diff --git a/packages/app-democracy/src/Referendum.tsx b/packages/app-democracy/src/Referendum.tsx new file mode 100644 index 0000000000..96c9fc6583 --- /dev/null +++ b/packages/app-democracy/src/Referendum.tsx @@ -0,0 +1,171 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { RawParam } from '@polkadot/ui-app/Params/types'; +import { RxReferendum, RxReferendumVote } from '@polkadot/ui-react-rx/ApiObservable/types'; + +import BN from 'bn.js'; +import React from 'react'; +import Static from '@polkadot/ui-app/Static'; +import Doughnut from '@polkadot/ui-app/Chart/Doughnut'; +import VoteThreshold from '@polkadot/ui-app/Params/Param/VoteThreshold'; +import classes from '@polkadot/ui-app/util/classes'; +import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; + +import Item from './Item'; +import Voting from './Voting'; +import translate from './translate'; + +const COLORS_YAY = ['#4d4', '#4e4']; +const COLORS_NAY = ['#d44', '#e44']; + +type Props = I18nProps & { + bestNumber?: BN, + democracyReferendumVoters?: Array, + idNumber: BN, + value: RxReferendum +}; + +type State = { + voteCount: number, + voteCountYay: number, + voteCountNay: number, + votedTotal: BN, + votedNay: BN, + votedYay: BN +}; + +class Referendum extends React.PureComponent { + state: State; + + constructor (props: Props) { + super(props); + + this.state = { + voteCount: 0, + voteCountYay: 0, + voteCountNay: 0, + votedTotal: new BN(0), + votedYay: new BN(0), + votedNay: new BN(0) + }; + } + + static getDerivedStateFromProps ({ democracyReferendumVoters }: Props, prevState: State): State | null { + if (!democracyReferendumVoters) { + return null; + } + + const newState: State = democracyReferendumVoters.reduce((state, { balance, vote }) => { + if (vote) { + state.voteCountYay++; + state.votedYay = state.votedYay.add(balance); + } else { + state.voteCountNay++; + state.votedNay = state.votedNay.add(balance); + } + + state.voteCount++; + state.votedTotal = state.votedTotal.add(balance); + + return state; + }, { + voteCount: 0, + voteCountYay: 0, + voteCountNay: 0, + votedTotal: new BN(0), + votedYay: new BN(0), + votedNay: new BN(0) + }); + + if (newState.votedYay.eq(prevState.votedNay) && newState.votedNay.eq(prevState.votedNay)) { + return null; + } + + return newState; + } + + render () { + const { className, idNumber, style, value } = this.props; + + return ( + + + {this.renderResults()} + + ); + } + + private renderExtra () { + const { bestNumber, t, value: { blockNumber, voteThreshold } } = this.props; + + if (!bestNumber) { + return null; + } + + return ( +
+ + {t('referendum.endInfo', { + defaultValue: '{{remaining}} blocks remaining, ending at block #{{blockNumber}}', + replace: { + blockNumber: numberFormat(blockNumber), + remaining: numberFormat(blockNumber.sub(bestNumber)) + } + })} + + +
+ ); + } + + private renderResults () { + const { voteCount, voteCountYay, voteCountNay, votedTotal, votedYay, votedNay } = this.state; + + if (voteCount === 0 || votedTotal.eqn(0)) { + return null; + } + + return ( +
+ +
+ ); + } +} + +export default withMulti( + translate(Referendum), + withObservable('bestNumber'), + withObservable('democracyReferendumVoters', { paramProp: 'idNumber' }) +); diff --git a/packages/app-democracy/src/Referendums.tsx b/packages/app-democracy/src/Referendums.tsx new file mode 100644 index 0000000000..8f3a70c1e0 --- /dev/null +++ b/packages/app-democracy/src/Referendums.tsx @@ -0,0 +1,64 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { RxReferendum } from '@polkadot/ui-react-rx/ApiObservable/types'; + +import React from 'react'; +import classes from '@polkadot/ui-app/util/classes'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; + +import Referendum from './Referendum'; +import translate from './translate'; + +type Props = I18nProps & { + democracyReferendums?: Array +}; + +class Referendums extends React.PureComponent { + render () { + const { className, style, t } = this.props; + + return ( +
+

{t('referendums.header', { + defaultValue: 'referendums' + })}

+ {this.renderReferendums()} +
+ ); + } + + private renderReferendums () { + const { democracyReferendums, t } = this.props; + + if (!democracyReferendums || !democracyReferendums.length) { + return ( +
+ {t('proposals.none', { + defaultValue: 'no available referendums' + })} +
+ ); + } + + return democracyReferendums.map((referendum) => ( + + )); + } +} + +export default withMulti( + Referendums, + translate, + withObservable('democracyReferendums') +); diff --git a/packages/app-democracy/src/Summary.tsx b/packages/app-democracy/src/Summary.tsx new file mode 100644 index 0000000000..4a0eef2fe9 --- /dev/null +++ b/packages/app-democracy/src/Summary.tsx @@ -0,0 +1,79 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; + +import BN from 'bn.js'; +import React from 'react'; +import classes from '@polkadot/ui-app/util/classes'; +import CardSummary from '@polkadot/ui-app/CardSummary'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; +import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; + +import translate from './translate'; + +type Props = I18nProps & { + democracyLaunchPeriod?: BN, + democracyNextTally?: BN, + democracyProposalCount?: BN, + democracyReferendumCount?: BN, + democracyVotingPeriod?: BN +}; + +class Summary extends React.PureComponent { + render () { + const { className, democracyLaunchPeriod, democracyNextTally = new BN(0), democracyProposalCount, democracyReferendumCount = new BN(0), democracyVotingPeriod, style, t } = this.props; + + return ( +
+
+ + {numberFormat(democracyProposalCount)} + + + {numberFormat(democracyReferendumCount)} + + + {democracyNextTally && democracyReferendumCount + ? numberFormat(democracyReferendumCount.sub(democracyNextTally)) + : 0 + } + +
+
+ + {numberFormat(democracyVotingPeriod)} + + + {numberFormat(democracyLaunchPeriod)} + +
+
+ ); + } +} + +export default withMulti( + Summary, + translate, + withObservable('democracyLaunchPeriod'), + withObservable('democracyReferendumCount'), + withObservable('democracyNextTally'), + withObservable('democracyProposalCount'), + withObservable('democracyVotingPeriod') +); diff --git a/packages/app-democracy/src/Voting.tsx b/packages/app-democracy/src/Voting.tsx new file mode 100644 index 0000000000..2cd77511ec --- /dev/null +++ b/packages/app-democracy/src/Voting.tsx @@ -0,0 +1,72 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { QueueProps } from '@polkadot/ui-signer/types'; + +import BN from 'bn.js'; +import React from 'react'; +import InputAddress from '@polkadot/ui-app/InputAddress'; +import { QueueConsumer } from '@polkadot/ui-signer/Context'; + +import VotingButtons from './VotingButtons'; +import translate from './translate'; + +type Props = I18nProps & { + referendumId: BN +}; + +type State = { + publicKey?: Uint8Array +}; + +class Voting extends React.PureComponent { + state: State = {}; + + render () { + const { t } = this.props; + + return ( +
+ + {this.renderButtons()} +
+ ); + } + + private renderButtons () { + const { referendumId } = this.props; + const { publicKey } = this.state; + + if (!publicKey) { + return null; + } + + return ( + + {({ queueExtrinsic }: QueueProps) => ( + + )} + + ); + } + + private onChangeAccount = (publicKey?: Uint8Array) => { + this.setState({ publicKey }); + } +} + +export default translate(Voting); diff --git a/packages/app-democracy/src/VotingButtons.tsx b/packages/app-democracy/src/VotingButtons.tsx new file mode 100644 index 0000000000..3ddeb06ffd --- /dev/null +++ b/packages/app-democracy/src/VotingButtons.tsx @@ -0,0 +1,78 @@ +// Copyright 2017-2018 @polkadot/app-democracy authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { I18nProps } from '@polkadot/ui-app/types'; +import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-signer/types'; + +import BN from 'bn.js'; +import React from 'react'; +import extrinsics from '@polkadot/extrinsics'; +import Button from '@polkadot/ui-app/Button'; +import withMulti from '@polkadot/ui-react-rx/with/multi'; +import withObservable from '@polkadot/ui-react-rx/with/observable'; + +import translate from './translate'; + +type Props = I18nProps & { + publicKey?: Uint8Array, + queueExtrinsic: QueueTx$ExtrinsicAdd, + referendumId: BN, + systemAccountIndexOf?: BN +}; + +class VotingButton extends React.PureComponent { + render () { + const { publicKey, t } = this.props; + + return ( + +