Browse Source

Submit candidacy (#1402)

* Change council to collective/elections

* fix proposal type

* package

* Submit candidacy

* update index

* Minor eslint cleanups

* rename back to council

* blank line
kwingram25 5 years ago
parent
commit
a7791a8e69

+ 0 - 1
packages/app-collective/README.md

@@ -1 +0,0 @@
-# @polkadot/app-collective

+ 0 - 21
packages/app-collective/src/Overview/index.tsx

@@ -1,21 +0,0 @@
-// Copyright 2017-2019 @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 React from 'react';
-
-import Members from './Members';
-import Summary from './Summary';
-
-interface Props {}
-
-export default class Overview extends React.PureComponent<Props> {
-  public render (): React.ReactNode {
-    return (
-      <>
-        <Summary />
-        <Members />
-      </>
-    );
-  }
-}

+ 0 - 0
packages/app-collective/src/Proposals/Summary.tsx


+ 0 - 0
packages/app-collective/LICENSE → packages/app-council/LICENSE


+ 1 - 0
packages/app-council/README.md

@@ -0,0 +1 @@
+# @polkadot/app-council

+ 2 - 2
packages/app-collective/package.json → packages/app-council/package.json

@@ -1,7 +1,7 @@
 {
-  "name": "@polkadot/app-collective",
+  "name": "@polkadot/app-council",
   "version": "0.34.0-beta.65",
-  "description": "Collective",
+  "description": "Council",
   "main": "index.js",
   "scripts": {},
   "author": "Jaco Greeff <jacogr@gmail.com>",

+ 3 - 12
packages/app-collective/src/Proposals/Proposal.tsx → packages/app-council/src/Motions/Motion.tsx

@@ -7,7 +7,6 @@ import { Option, Proposal as ProposalType, Votes } from '@polkadot/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import styled from 'styled-components';
 import { ActionItem, InputAddress, Labelled, Voting } from '@polkadot/ui-app';
 import { withCalls, withMulti } from '@polkadot/ui-api';
 
@@ -26,7 +25,7 @@ interface State {
   votedAye: number;
 }
 
-class Proposal extends React.PureComponent<Props, State> {
+class Motion extends React.PureComponent<Props, State> {
   public state: State = {
     votedTotal: 0,
     votedAye: 0,
@@ -64,7 +63,7 @@ class Proposal extends React.PureComponent<Props, State> {
         accessory={
           <Voting
             hash={hash}
-            isCollective
+            isCouncil
             idNumber={index}
             proposal={proposal}
           />
@@ -140,15 +139,7 @@ class Proposal extends React.PureComponent<Props, State> {
 }
 
 export default withMulti(
-  styled(Proposal as React.ComponentClass<Props>)`
-    .democracy--Proposal-results {
-      margin-bottom: 1em;
-
-      &.chart {
-        text-align: center;
-      }
-    }
-  `,
+  Motion,
   translate,
   withCalls<Props>(
     [

+ 10 - 10
packages/app-collective/src/Proposals/Propose.tsx → packages/app-council/src/Motions/Propose.tsx

@@ -15,16 +15,16 @@ import { withApi, withCalls, withMulti } from '@polkadot/ui-api';
 import translate from '../translate';
 
 type Props = TxModalProps & ApiProps & {
-  memberCount: number;
+  memberCount: number
 };
 
-interface State extends TxModalState {
-  method: Method | null;
-  threshold: BN | null;
-}
+type State = TxModalState & {
+  method: Method | null,
+  threshold: BN | null
+};
 
 class Propose extends TxModal<Props, State> {
-  public constructor (props: Props) {
+  constructor (props: Props) {
     super(props);
 
     this.defaultState = {
@@ -43,7 +43,7 @@ class Propose extends TxModal<Props, State> {
     return null;
   }
 
-  headerText = () => this.props.t('Make a collective proposal');
+  headerText = () => this.props.t('Propose a council motion');
 
   txMethod = () => 'collective.propose';
   txParams = () => {
@@ -72,7 +72,7 @@ class Propose extends TxModal<Props, State> {
       <Button.Group>
         <Button
           isPrimary
-          label={t('Make a collective proposal')}
+          label={t('Propose a council motion')}
           labelIcon='add'
           onClick={this.showModal}
         />
@@ -89,7 +89,7 @@ class Propose extends TxModal<Props, State> {
         <InputNumber
           className='medium'
           label={t('threshold')}
-          help={t('The minimum number of collective votes required to approve this proposal')}
+          help={t('The minimum number of council votes required to approve this motion')}
           isError={!threshold || threshold.eqn(0) || threshold.gtn(memberCount)}
           onChange={this.onChangeThreshold}
           onEnter={this.sendTx}
@@ -137,7 +137,7 @@ export default withMulti(
       'query.elections.members',
       {
         propName: 'memberCount',
-        transform: (value: any[]) => value.length
+        transform: (value: Array<any>) => value.length
       }
     ]
   )

+ 4 - 4
packages/app-collective/src/Proposals/index.tsx → packages/app-council/src/Motions/index.tsx

@@ -10,7 +10,7 @@ import React from 'react';
 import { withCalls } from '@polkadot/ui-api';
 import { CardGrid } from '@polkadot/ui-app';
 
-import Proposal from './Proposal';
+import Motion from './Motion';
 import Propose from './Propose';
 import translate from '../translate';
 
@@ -24,8 +24,8 @@ class Proposals extends React.PureComponent<Props> {
 
     return (
       <CardGrid
-        emptyText={t('No proposals')}
-        headerText={t('Proposals')}
+        emptyText={t('No council motions')}
+        headerText={t('Motions')}
         buttons={
           <Propose />
         }
@@ -39,7 +39,7 @@ class Proposals extends React.PureComponent<Props> {
     const { collective_proposals = [] } = this.props;
 
     return collective_proposals.map((hash: Hash): React.ReactNode => (
-      <Proposal
+      <Motion
         hash={hash.toHex()}
         key={hash.toHex()}
       />

+ 0 - 0
packages/app-collective/src/Overview/Candidate.tsx → packages/app-council/src/Overview/Candidate.tsx


+ 6 - 6
packages/app-collective/src/Overview/Member.tsx → packages/app-council/src/Overview/Member.tsx

@@ -11,19 +11,19 @@ import { formatNumber } from '@polkadot/util';
 
 import translate from '../translate';
 
-interface Props extends I18nProps {
-  address: string;
-  block: BN;
-}
+type Props = I18nProps & {
+  address: string,
+  block: BN
+};
 
 class Member extends React.PureComponent<Props> {
-  public render (): React.ReactNode {
+  render () {
     const { address, block, t } = this.props;
 
     return (
       <AddressCard
         buttons={<div><label>{t('active until')}</label>#{formatNumber(block)}</div>}
-        defaultName='collective member'
+        defaultName='council member'
         value={address}
       />
     );

+ 7 - 21
packages/app-collective/src/Overview/Members.tsx → packages/app-council/src/Overview/Members.tsx

@@ -4,24 +4,23 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
+import { ElectionsInfo } from './types';
 
 import React from 'react';
-import { AccountId, BlockNumber } from '@polkadot/types';
 import { Columar, Column } from '@polkadot/ui-app';
-import { withCalls } from '@polkadot/ui-api';
 
 import translate from '../translate';
 import Candidate from './Candidate';
 import Member from './Member';
 
 interface Props extends I18nProps {
-  elections_members?: [string, BlockNumber][];
-  elections_candidates?: string[];
+  electionsInfo: ElectionsInfo;
 }
 
 class Members extends React.PureComponent<Props> {
   public render (): React.ReactNode {
-    const { elections_members = [], elections_candidates = [], t } = this.props;
+    const { electionsInfo, t } = this.props;
+    const { members, candidates } = electionsInfo;
 
     return (
       <Columar>
@@ -29,7 +28,7 @@ class Members extends React.PureComponent<Props> {
           emptyText={t('No members found')}
           headerText={t('members')}
         >
-          {elections_members.map(([address, block]): React.ReactNode => (
+          {members.map(([address, block]): React.ReactNode => (
             <Member
               address={address}
               block={block}
@@ -41,7 +40,7 @@ class Members extends React.PureComponent<Props> {
           emptyText={t('No members found')}
           headerText={t('candidates')}
         >
-          {elections_candidates.map((address): React.ReactNode => (
+          {candidates.map((address): React.ReactNode => (
             <Candidate
               address={address}
               key={address}
@@ -53,17 +52,4 @@ class Members extends React.PureComponent<Props> {
   }
 }
 
-export default translate(
-  withCalls<Props>(
-    ['query.elections.members', {
-      transform: (active: [AccountId, BlockNumber][]): [string, BlockNumber][] =>
-        active.map(([accountId, blockNumber]): [string, BlockNumber] =>
-          [accountId.toString(), blockNumber]
-        )
-    }],
-    ['query.elections.candidates', {
-      transform: (candidates: AccountId[]): string[] =>
-        candidates.map((accountId): string => accountId.toString())
-    }]
-  )(Members)
-);
+export default translate(Members);

+ 56 - 0
packages/app-council/src/Overview/SubmitCandidacy.tsx

@@ -0,0 +1,56 @@
+// Copyright 2017-2019 @polkadot/ui-staking 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 { ElectionsInfo } from './types';
+
+import React from 'react';
+import { Button } from '@polkadot/ui-app';
+import TxModal, { TxModalState, TxModalProps } from '@polkadot/ui-app/TxModal';
+
+import translate from '../translate';
+
+type Props = TxModalProps & {
+  electionsInfo: ElectionsInfo
+};
+
+type State = TxModalState;
+
+class SubmitCandidacy extends TxModal<Props, State> {
+  headerText = () => this.props.t('Submit your council candidacy');
+
+  accountLabel = () => this.props.t('Candidate account');
+  accountHelp = () => this.props.t('This account will be nominated to fill the council slot you specify.');
+
+  txMethod = () => 'elections.submitCandidacy';
+  txParams = () => {
+    const { electionsInfo: { candidateCount } } = this.props;
+
+    return [
+      candidateCount
+    ];
+  }
+
+  isDisabled = () => {
+    const { accountId } = this.state;
+
+    return !accountId;
+  }
+
+  renderTrigger = () => {
+    const { t } = this.props;
+
+    return (
+      <Button.Group>
+        <Button
+          isPrimary
+          label={t('Submit candidacy')}
+          labelIcon='add'
+          onClick={this.showModal}
+        />
+      </Button.Group>
+    );
+  }
+}
+
+export default translate(SubmitCandidacy);

+ 11 - 23
packages/app-collective/src/Overview/Summary.tsx → packages/app-council/src/Overview/Summary.tsx

@@ -4,60 +4,48 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
+import { ElectionsInfo } from './types';
 
-import BN from 'bn.js';
 import React from 'react';
-import { AccountId, BlockNumber } from '@polkadot/types';
 import { SummaryBox, CardSummary } from '@polkadot/ui-app';
-import { withCalls } from '@polkadot/ui-api';
 import { formatNumber } from '@polkadot/util';
 
 import translate from '../translate';
 
 interface Props extends I18nProps {
-  elections_members?: [AccountId, BlockNumber][];
-  elections_candidateCount?: BN;
-  elections_desiredSeats?: BN;
-  elections_termDuration?: BN;
-  elections_voteCount?: BN;
+  electionsInfo: ElectionsInfo;
 }
 
 class Summary extends React.PureComponent<Props> {
   public render (): React.ReactNode {
-    const { elections_members = [], elections_candidateCount = new BN(0), elections_desiredSeats = new BN(1), elections_termDuration = new BN(0), elections_voteCount = new BN(0), t } = this.props;
+    const { electionsInfo, t } = this.props;
+
+    const { members, candidateCount, desiredSeats, termDuration, voteCount } = electionsInfo;
 
     return (
       <SummaryBox>
         <section>
           <CardSummary label={t('seats')}>
-            {formatNumber(elections_members.length)}/{formatNumber(elections_desiredSeats)}
+            {formatNumber(members.length)}/{formatNumber(desiredSeats)}
           </CardSummary>
           <CardSummary label={t('candidates')}>
-            {formatNumber(elections_candidateCount)}
+            {formatNumber(candidateCount)}
           </CardSummary>
         </section>
         <section>
           <CardSummary label={t('total votes')}>
-            {formatNumber(elections_voteCount)}
+            {formatNumber(voteCount)}
           </CardSummary>
         </section>
 
         <section>
           <CardSummary label={t('term duration')}>
-            {formatNumber(elections_termDuration)}
-          </CardSummary>
+              {formatNumber(termDuration)}
+           </CardSummary>
         </section>
       </SummaryBox>
     );
   }
 }
 
-export default translate(
-  withCalls<Props>(
-    'query.elections.members',
-    'query.elections.candidateCount',
-    'query.elections.desiredSeats',
-    'query.elections.termDuration',
-    'query.elections.voteCount'
-  )(Summary)
-);
+export default translate(Summary);

+ 76 - 0
packages/app-council/src/Overview/index.tsx

@@ -0,0 +1,76 @@
+// Copyright 2017-2019 @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, BlockNumber } from '@polkadot/types';
+import { ElectionsInfo } from './types';
+
+import BN from 'bn.js';
+import React from 'react';
+
+import { withCalls } from '@polkadot/ui-api';
+
+import Members from './Members';
+import SubmitCandidacy from './SubmitCandidacy';
+import Summary from './Summary';
+
+interface Props {
+  elections_members?: [string, BlockNumber][];
+  elections_candidates?: string[];
+  elections_candidateCount?: BN;
+  elections_desiredSeats?: BN;
+  elections_termDuration?: BN;
+  elections_voteCount?: BN;
+}
+
+interface State {
+  electionsInfo: ElectionsInfo;
+}
+
+class Overview extends React.PureComponent<Props, State> {
+  public static getDerivedStateFromProps ({
+    elections_members: members = [],
+    elections_candidates: candidates = [],
+    elections_candidateCount: candidateCount = new BN(0),
+    elections_desiredSeats: desiredSeats = new BN(0),
+    elections_termDuration: termDuration = new BN(0),
+    elections_voteCount: voteCount = new BN(0)
+  }: Props): State {
+    const electionsInfo: ElectionsInfo = {
+      members, candidates, candidateCount, desiredSeats, termDuration, voteCount
+    };
+
+    return { electionsInfo };
+  }
+
+  public render (): React.ReactNode {
+    const { electionsInfo } = this.state;
+
+    return (
+      <>
+        <Summary electionsInfo={electionsInfo} />
+        <SubmitCandidacy electionsInfo={electionsInfo} />
+        <Members electionsInfo={electionsInfo} />
+      </>
+    );
+  }
+}
+
+export default withCalls<Props>(
+  ['query.elections.members', {
+    transform: (active: [AccountId, BlockNumber][]): [string, BlockNumber][] =>
+      active.map(([accountId, blockNumber]): [string, BlockNumber] =>
+        [accountId.toString(), blockNumber]
+      )
+  }],
+  ['query.elections.candidates', {
+    transform: (candidates: AccountId[]): string[] =>
+      candidates.map((accountId): string =>
+        accountId.toString()
+      )
+  }],
+  'query.elections.candidateCount',
+  'query.elections.desiredSeats',
+  'query.elections.termDuration',
+  'query.elections.voteCount'
+)(Overview);

+ 16 - 0
packages/app-council/src/Overview/types.ts

@@ -0,0 +1,16 @@
+// Copyright 2017-2019 @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 { BlockNumber } from '@polkadot/types';
+
+import BN from 'bn.js';
+
+export interface ElectionsInfo {
+  members: [string, BlockNumber][];
+  candidates: string[];
+  candidateCount: BN;
+  desiredSeats: BN;
+  termDuration: BN;
+  voteCount: BN;
+}

+ 10 - 10
packages/app-collective/src/index.tsx → packages/app-council/src/index.tsx

@@ -10,17 +10,17 @@ import { Route, Switch } from 'react-router';
 import { Tabs } from '@polkadot/ui-app';
 
 import Overview from './Overview';
-import Proposals from './Proposals';
+import Motions from './Motions';
 import translate from './translate';
 
 type Props = AppProps & BareProps & I18nProps;
 
-interface State {
-  tabs: TabItem[];
-}
+type State = {
+  tabs: Array<TabItem>
+};
 
 class App extends React.PureComponent<Props, State> {
-  public constructor (props: Props) {
+  constructor (props: Props) {
     super(props);
 
     const { t } = props;
@@ -30,17 +30,17 @@ class App extends React.PureComponent<Props, State> {
         {
           isRoot: true,
           name: 'overview',
-          text: t('Collective overview')
+          text: t('Council overview')
         },
         {
-          name: 'proposals',
-          text: t('Proposals')
+          name: 'motions',
+          text: t('Motions')
         }
       ]
     };
   }
 
-  public render (): React.ReactNode {
+  render () {
     const { basePath } = this.props;
     const { tabs } = this.state;
 
@@ -53,7 +53,7 @@ class App extends React.PureComponent<Props, State> {
           />
         </header>
         <Switch>
-          <Route path={`${basePath}/proposals`} component={Proposals} />
+          <Route path={`${basePath}/motions`} component={Motions} />
           <Route component={Overview} />
         </Switch>
       </main>

+ 2 - 2
packages/app-collective/src/translate.ts → packages/app-council/src/translate.ts

@@ -1,7 +1,7 @@
-// Copyright 2017-2019 @polkadot/app-collective authors & contributors
+// Copyright 2017-2019 @polkadot/app-council 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 { withTranslation } from 'react-i18next';
 
-export default withTranslation(['collective', 'ui']);
+export default withTranslation(['council', 'ui']);

+ 2 - 2
packages/app-treasury/src/Overview/Approve.tsx

@@ -79,8 +79,8 @@ class Approve extends TxModal<Props, State> {
 
     return (
       <Dropdown
-        help={t('Propose a majority collective proposal to either approve or reject this spend proposal')}
-        label={t('proposed collective action')}
+        help={t('Propose a majority council motion to either approve or reject this spend proposal')}
+        label={t('proposed council action')}
         options={this.approveOptions()}
         onChange={this.onChangeApproving}
         value={isApproving}

+ 1 - 1
packages/app-treasury/src/Overview/Proposals.tsx

@@ -84,7 +84,7 @@ class ProposalsBase extends React.PureComponent<Props> {
   onRespond = () => {
     const { history } = this.props;
 
-    history.push('/collective/proposals');
+    history.push('/council/motions');
   }
 
   private onPopulateProposal = () => {

+ 4 - 4
packages/apps-routing/src/collective.ts → packages/apps-routing/src/council.ts

@@ -4,20 +4,20 @@
 
 import { Routes } from './types';
 
-import Collective from '@polkadot/app-collective';
+import Council from '@polkadot/app-council';
 
 export default ([
   {
-    Component: Collective,
+    Component: Council,
     display: {
       needsApi: [
         'query.elections.candidates'
       ]
     },
     i18n: {
-      defaultValue: 'Collective'
+      defaultValue: 'Council'
     },
     icon: 'building',
-    name: 'collective'
+    name: 'council'
   }
 ] as Routes);

+ 3 - 3
packages/apps-routing/src/index.ts

@@ -10,7 +10,7 @@ import template from './123code';
 import accounts from './accounts';
 import addressbook from './addressbook';
 import contracts from './contracts';
-import collective from './collective';
+import council from './council';
 import dashboard from './dashboard';
 import democracy from './democracy';
 import explorer from './explorer';
@@ -35,7 +35,7 @@ const routes: Routes = appSettings.uiMode === 'light'
     null,
     staking,
     democracy,
-    collective,
+    council,
     // TODO Not sure about the inclusion of treasury & parachains here
     null,
     settings,
@@ -50,7 +50,7 @@ const routes: Routes = appSettings.uiMode === 'light'
     null,
     staking,
     democracy,
-    collective,
+    council,
     treasury,
     parachains,
     null,

+ 1 - 0
packages/ui-app/src/Labelled.tsx

@@ -52,6 +52,7 @@ const Wrapper = styled.div`
     .labelExtra {
       position: absolute;
       text-align: left;
+      text-transform: lowercase;
       top: 0.5rem;
       z-index: 1;
     }

+ 7 - 7
packages/ui-app/src/Voting.tsx

@@ -22,7 +22,7 @@ type Props = I18nProps & TxModalProps & {
   allAccounts?: SubjectInfo;
   hash?: string;
   idNumber: BN | number;
-  isCollective: boolean;
+  isCouncil: boolean;
   proposal?: Proposal | null;
   preContent?: React.ReactNode;
 };
@@ -36,25 +36,25 @@ class Voting extends TxModal<Props, State> {
   public state: State;
 
   headerText = () => {
-    const { isCollective, t } = this.props;
+    const { isCouncil, t } = this.props;
 
-    return t(isCollective ? 'Vote on collective proposal' : 'Vote on proposal');
+    return t(isCouncil ? 'Vote on council proposal' : 'Vote on proposal');
   }
 
   accountLabel = () => this.props.t('Vote with account');
   accountHelp = () => this.props.t('Select the account you wish to vote with. You can approve "aye" or deny "nay" the proposal.');
 
   txMethod = () => {
-    const { isCollective } = this.props;
+    const { isCouncil } = this.props;
 
-    return isCollective ? 'collective.vote' : 'democracy.vote';
+    return isCouncil ? 'collective.vote' : 'democracy.vote';
   }
 
   txParams = () => {
-    const { hash, idNumber, isCollective } = this.props;
+    const { hash, idNumber, isCouncil } = this.props;
     const { voteValue } = this.state;
 
-    return isCollective
+    return isCouncil
       ? [hash!, idNumber, voteValue]
       : [idNumber, voteValue];
   }

+ 1 - 1
packages/ui-params/src/Params.css

@@ -6,7 +6,7 @@
   border-left: 0.25rem solid #f2f2f2;
 
   label {
-    text-transform: none;
+    text-transform: none !important;
     font-family: monospace;
   }
 

+ 2 - 2
tsconfig.json

@@ -11,8 +11,8 @@
       "@polkadot/app-address-book/*": [ "packages/app-address-book/src/*" ],
       "@polkadot/app-contracts": [ "packages/app-contracts/src" ],
       "@polkadot/app-contracts/*": [ "packages/app-contracts/src/*" ],
-      "@polkadot/app-collective": [ "packages/app-collective/src" ],
-      "@polkadot/app-collective/*": [ "packages/app-collective/src/*" ],
+      "@polkadot/app-council": [ "packages/app-council/src" ],
+      "@polkadot/app-council/*": [ "packages/app-council/src/*" ],
       "@polkadot/app-dashboard": [ "packages/app-dashboard/src" ],
       "@polkadot/app-dashboard/*": [ "packages/app-dashboard/src/*" ],
       "@polkadot/app-democracy": [ "packages/app-democracy/src" ],