Add bonding preferences (#842)

This commit is contained in:
Jaco Greeff 2019-03-26 10:16:59 +01:00 committed by GitHub
parent 6997337f99
commit 9ee5280adb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 237 additions and 96 deletions

View File

@ -13,9 +13,10 @@ import { AccountId, Balance, Option, ValidatorPrefs } from '@polkadot/types';
import { AddressMini, AddressSummary, Button } from '@polkadot/ui-app';
import { withCalls } from '@polkadot/ui-api';
import Bonding from './Bonding';
import Nominating from './Nominating';
import Preferences from './Preferences';
import UnnominateButton from './UnnominateButton';
// import UnnominateButton from './UnnominateButton';
import translate from '../translate';
type Props = ApiProps & I18nProps & {
@ -32,6 +33,7 @@ type Props = ApiProps & I18nProps & {
};
type State = {
isBondingOpen: boolean,
isNominateOpen: boolean,
isPrefsOpen: boolean,
nominee: AccountId | null
@ -39,6 +41,7 @@ type State = {
class Account extends React.PureComponent<Props, State> {
state: State = {
isBondingOpen: false,
isNominateOpen: false,
isPrefsOpen: false,
nominee: null
@ -57,6 +60,7 @@ class Account extends React.PureComponent<Props, State> {
return (
<article className='staking--Account'>
{this.renderBonding()}
{this.renderNominating()}
{this.renderPrefs()}
<AddressSummary
@ -75,6 +79,19 @@ class Account extends React.PureComponent<Props, State> {
);
}
private renderBonding () {
const { accountId } = this.props;
const { isBondingOpen } = this.state;
return (
<Bonding
accountId={accountId}
isOpen={isBondingOpen}
onClose={this.toggleBonding}
/>
);
}
private renderNominee () {
const { balanceArray } = this.props;
const { nominee } = this.state;
@ -117,10 +134,6 @@ class Account extends React.PureComponent<Props, State> {
const { intentions } = this.props;
const { isNominateOpen } = this.state;
if (!isNominateOpen) {
return null;
}
return (
<Nominating
isOpen={isNominateOpen}
@ -135,10 +148,6 @@ class Account extends React.PureComponent<Props, State> {
const { accountId, staking_validatorPreferences } = this.props;
const { isPrefsOpen } = this.state;
if (!isPrefsOpen) {
return null;
}
return (
<Preferences
accountId={accountId}
@ -151,56 +160,68 @@ class Account extends React.PureComponent<Props, State> {
}
private renderButtons () {
const { accountId, intentions, t } = this.props;
const { nominee } = this.state;
const isIntending = intentions.includes(accountId);
const canStake = !isIntending && !nominee;
if (canStake) {
return (
<Button.Group>
<Button
isPrimary
onClick={this.stake}
label={t('Stake')}
/>
<Button.Or />
<Button
isPrimary
onClick={this.toggleNominate}
label={t('Nominate')}
/>
</Button.Group>
);
}
if (nominee) {
return (
<Button.Group>
<UnnominateButton
accountId={accountId || ''}
nominating={nominee}
onClick={this.unnominate}
/>
</Button.Group>
);
}
const { t } = this.props;
return (
<Button.Group>
<Button
isNegative
onClick={this.unstake}
label={t('Unstake')}
/>
<Button.Or />
<Button
isPrimary
onClick={this.togglePrefs}
label={t('Set Prefs')}
onClick={this.toggleBonding}
label={t('Bond')}
/>
</Button.Group>
);
// const { accountId, intentions, t } = this.props;
// const { nominee } = this.state;
// const isIntending = intentions.includes(accountId);
// const canStake = !isIntending && !nominee;
// if (canStake) {
// return (
// <Button.Group>
// <Button
// isPrimary
// onClick={this.stake}
// label={t('Stake')}
// />
// <Button.Or />
// <Button
// isPrimary
// onClick={this.toggleNominate}
// label={t('Nominate')}
// />
// </Button.Group>
// );
// }
// if (nominee) {
// return (
// <Button.Group>
// <UnnominateButton
// accountId={accountId || ''}
// nominating={nominee}
// onClick={this.unnominate}
// />
// </Button.Group>
// );
// }
// return (
// <Button.Group>
// <Button
// isNegative
// onClick={this.unstake}
// label={t('Unstake')}
// />
// <Button.Or />
// <Button
// isPrimary
// onClick={this.togglePrefs}
// label={t('Set Prefs')}
// />
// </Button.Group>
// );
}
private send (extrinsic: SubmittableExtrinsic) {
@ -212,22 +233,6 @@ class Account extends React.PureComponent<Props, State> {
});
}
private toggleNominate = () => {
this.setState(
({ isNominateOpen }: State) => ({
isNominateOpen: !isNominateOpen
})
);
}
private togglePrefs = () => {
this.setState(
({ isPrefsOpen }: State) => ({
isPrefsOpen: !isPrefsOpen
})
);
}
private nominate = (nominee: string) => {
const { api } = this.props;
@ -236,11 +241,11 @@ class Account extends React.PureComponent<Props, State> {
this.toggleNominate();
}
private unnominate = (index: number) => {
const { api } = this.props;
// private unnominate = (index: number) => {
// const { api } = this.props;
this.send(api.tx.staking.unnominate(index));
}
// this.send(api.tx.staking.unnominate(index));
// }
private setPrefs = (prefs: ValidatorPrefs) => {
const { api } = this.props;
@ -250,23 +255,41 @@ class Account extends React.PureComponent<Props, State> {
this.togglePrefs();
}
private stake = () => {
const { api } = this.props;
// private stake = () => {
// const { api } = this.props;
this.send(api.tx.staking.stake());
}
// this.send(api.tx.staking.stake());
// }
private unstake = () => {
const { api } = this.props;
// private unstake = () => {
// const { api } = this.props;
this.send(api.tx.staking.unstake(this.getIntentionIndex()));
}
// this.send(api.tx.staking.unstake(this.getIntentionIndex()));
// }
private getIntentionIndex (): number {
const { accountId, intentions } = this.props;
return intentions.indexOf(accountId);
}
private toggleBonding = () => {
this.setState(({ isBondingOpen }) => ({
isBondingOpen: !isBondingOpen
}));
}
private toggleNominate = () => {
this.setState(({ isNominateOpen }: State) => ({
isNominateOpen: !isNominateOpen
}));
}
private togglePrefs = () => {
this.setState(({ isPrefsOpen }: State) => ({
isPrefsOpen: !isPrefsOpen
}));
}
}
export default translate(

View File

@ -0,0 +1,127 @@
// 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 { I18nProps } from '@polkadot/ui-app/types';
import BN from 'bn.js';
import React from 'react';
import { Button, InputAddress, InputBalance, Modal, TxButton, Dropdown } from '@polkadot/ui-app';
import translate from '../translate';
type Props = I18nProps & {
accountId: string,
isOpen: boolean,
onClose: () => void
};
type State = {
bondValue?: BN,
controller?: string,
destination: number
};
const stashOptions = [
{ text: 'Stash account (increase the amount at stake)', value: 0 },
{ text: 'Stash account (do not increase the amount at stake)', value: 1 },
{ text: 'Controller account', value: 2 }
];
class Bonding extends React.PureComponent<Props, State> {
state: State = {
destination: 0
};
render () {
const { accountId, isOpen, onClose, t } = this.props;
const { bondValue, controller, destination } = this.state;
const canSubmit = !!bondValue && bondValue.gtn(0) && !!controller;
if (!isOpen) {
return null;
}
return (
<Modal
className='staking--Bonding'
dimmer='inverted'
open
size='small'
>
{this.renderContent()}
<Modal.Actions>
<Button.Group>
<Button
isNegative
onClick={onClose}
label={t('Cancel')}
/>
<Button.Or />
<TxButton
accountId={accountId}
isDisabled={!canSubmit}
isPrimary
label={t('Bond')}
onClick={onClose}
params={[controller, bondValue, destination]}
tx='staking.bond'
/>
</Button.Group>
</Modal.Actions>
</Modal>
);
}
private renderContent () {
const { accountId, t } = this.props;
return (
<>
<Modal.Header>
{t('Bonding Preferences')}
</Modal.Header>
<Modal.Content className='ui--signer-Signer-Content'>
<InputAddress
className='medium'
isDisabled
label={t('stash account')}
value={accountId}
/>
<InputAddress
autoFocus
className='medium'
label={t('controller account')}
onChange={this.onChangeController}
/>
<InputBalance
className='medium'
label={t('value bonded')}
onChange={this.onChangeValue}
/>
<Dropdown
className='medium'
defaultValue={0}
label={t('payment destination')}
onChange={this.onChangeDestination}
options={stashOptions}
/>
</Modal.Content>
</>
);
}
private onChangeController = (controller: string) => {
this.setState({ controller });
}
private onChangeDestination = (destination: number) => {
this.setState({ destination });
}
private onChangeValue = (bondValue?: BN) => {
this.setState({ bondValue });
}
}
export default translate(Bonding);

View File

@ -31,7 +31,7 @@ class Nominating extends React.PureComponent<Props, State> {
};
render () {
const { isOpen, style } = this.props;
const { isOpen } = this.props;
if (!isOpen) {
return null;
@ -43,7 +43,6 @@ class Nominating extends React.PureComponent<Props, State> {
dimmer='inverted'
open
size='small'
style={style}
>
{this.renderContent()}
{this.renderButtons()}

View File

@ -43,7 +43,7 @@ class Preferences extends React.PureComponent<Props, State> {
}
render () {
const { isOpen, style } = this.props;
const { isOpen } = this.props;
if (!isOpen) {
return null;
@ -51,11 +51,10 @@ class Preferences extends React.PureComponent<Props, State> {
return (
<Modal
className='staking--Nominating'
className='staking--Preferences'
dimmer='inverted'
open
size='small'
style={style}
>
{this.renderContent()}
{this.renderButtons()}

View File

@ -5,15 +5,13 @@
import { DerivedBalancesMap } from '@polkadot/api-derive/types';
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
import { ApiProps } from '@polkadot/ui-api/types';
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { ComponentProps } from './types';
import React from 'react';
import { Route, Switch } from 'react-router';
import { AccountId, Balance } from '@polkadot/types';
import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
import { withCalls, withMulti, withObservable } from '@polkadot/ui-api';
import { withCalls, withMulti } from '@polkadot/ui-api';
import './index.css';
@ -22,7 +20,6 @@ import Overview from './Overview';
import translate from './translate';
type Props = AppProps & ApiProps & I18nProps & {
allAccounts?: SubjectInfo,
balances?: DerivedBalancesMap,
intentions?: Array<AccountId>,
session_validators?: Array<AccountId>
@ -70,20 +67,14 @@ class App extends React.PureComponent<Props, State> {
}
render () {
const { allAccounts, api } = this.props;
const { tabs } = this.state;
const { basePath } = this.props;
const hasAccounts = allAccounts && Object.keys(allAccounts).length !== 0;
const hidden = hasAccounts && api.tx.staking.stake
? []
: ['actions'];
return (
<main className='staking--App'>
<header>
<Tabs
basePath={basePath}
hidden={hidden}
items={tabs}
/>
</header>
@ -132,7 +123,6 @@ class App extends React.PureComponent<Props, State> {
export default withMulti(
App,
translate,
withObservable(accountObservable.subject, { propName: 'allAccounts' }),
withCalls<Props>(
'query.session.validators',
['query.staking.intentions', { propName: 'intentions' }],

View File

@ -20,6 +20,7 @@ type Props = ApiProps & {
accountId?: string,
isDisabled?: boolean,
label: React.ReactNode,
onClick?: () => any,
onFailed?: TxCallback,
onSuccess?: TxCallback,
onUpdate?: TxCallback,
@ -42,7 +43,7 @@ class TxButtonInner extends React.PureComponent<Props & InjectedProps> {
}
private send = (): void => {
const { accountId, api, onFailed, onSuccess, onUpdate, params, queueExtrinsic, tx } = this.props;
const { accountId, api, onClick, onFailed, onSuccess, onUpdate, params, queueExtrinsic, tx } = this.props;
const [section, method] = tx.split('.');
assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`);
@ -54,6 +55,8 @@ class TxButtonInner extends React.PureComponent<Props & InjectedProps> {
txSuccessCb: onSuccess,
txUpdateCb: onUpdate
});
onClick && onClick();
}
}