Add unbond button (#1057)
* don't show 'Bond additionnal' if the stash already bond everything it could * add unbound button * clean up * clean up bis * linting * add comments + some more cleanup * add group active and total * refactor the isOpen props for all modals * conditionnaly call the renderer * revert isOpen changes * add comment regarding the modal loading choice
This commit is contained in:
parent
405dfecd8f
commit
21f76ca0ac
98
packages/app-staking/src/Account/Unbond.tsx
Normal file
98
packages/app-staking/src/Account/Unbond.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
// 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 { AccountId } from '@polkadot/types';
|
||||
import BN from 'bn.js';
|
||||
import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/ui-app';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import React from 'react';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
controllerId?: AccountId | null,
|
||||
isOpen: boolean,
|
||||
onClose: () => void
|
||||
};
|
||||
|
||||
type State = {
|
||||
maxUnbond?: BN
|
||||
};
|
||||
|
||||
class Unbond extends React.PureComponent<Props, State> {
|
||||
state: State = {};
|
||||
|
||||
render () {
|
||||
const { controllerId, isOpen, onClose, t } = this.props;
|
||||
const { maxUnbond } = this.state;
|
||||
const canSubmit = !!maxUnbond && maxUnbond.gtn(0);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='staking--Unbond'
|
||||
dimmer='inverted'
|
||||
open
|
||||
size='small'
|
||||
>
|
||||
{this.renderContent()}
|
||||
<Modal.Actions>
|
||||
<Button.Group>
|
||||
<Button
|
||||
isNegative
|
||||
onClick={onClose}
|
||||
label={t('Cancel')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<TxButton
|
||||
accountId={controllerId && controllerId.toString()}
|
||||
isDisabled={!canSubmit}
|
||||
isPrimary
|
||||
label={t('Unbond')}
|
||||
onClick={onClose}
|
||||
params={[maxUnbond]}
|
||||
tx='staking.unbond'
|
||||
/>
|
||||
</Button.Group>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
private renderContent () {
|
||||
const { controllerId, t } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal.Header>
|
||||
{t('Unbond')}
|
||||
</Modal.Header>
|
||||
<Modal.Content className='ui--signer-Signer-Content'>
|
||||
<InputAddress
|
||||
className='medium'
|
||||
defaultValue={controllerId && controllerId.toString()}
|
||||
isDisabled
|
||||
label={t('controler account')}
|
||||
/>
|
||||
<InputBalance
|
||||
autoFocus
|
||||
className='medium'
|
||||
help={t('The maximum amount to unbond, this is adjusted using the bonded funds on the account.')}
|
||||
label={t('unbond amount')}
|
||||
onChange={this.onChangeValue}
|
||||
/>
|
||||
</Modal.Content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private onChangeValue = (maxUnbond?: BN) => {
|
||||
this.setState({ maxUnbond });
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Unbond);
|
||||
@ -2,23 +2,23 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId, Balance, Exposure, Option, StakingLedger, ValidatorPrefs } from '@polkadot/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { AddressMini, AddressSummary, Button, TxButton } from '@polkadot/ui-app';
|
||||
import { DerivedBalancesMap } from '@polkadot/api-derive/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types';
|
||||
import { AccountFilter, RecentlyOfflineMap } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { AccountId, Exposure, Option, StakingLedger, ValidatorPrefs } from '@polkadot/types';
|
||||
import { AddressMini, AddressSummary, Button, TxButton } from '@polkadot/ui-app';
|
||||
import { withCalls } from '@polkadot/ui-api';
|
||||
|
||||
import { AccountFilter, RecentlyOfflineMap } from '../types';
|
||||
import Bond from './Bond';
|
||||
import BondExtra from './BondExtra';
|
||||
import Nominating from './Nominating';
|
||||
import SessionKey from './SessionKey';
|
||||
import Validating from './Validating';
|
||||
import translate from '../translate';
|
||||
import Unbond from './Unbond';
|
||||
import Validating from './Validating';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
accountId: string,
|
||||
@ -30,11 +30,12 @@ type Props = ApiProps & I18nProps & {
|
||||
recentlyOffline: RecentlyOfflineMap,
|
||||
sessionId?: AccountId | null,
|
||||
stashId?: AccountId | null,
|
||||
freeBalance?: Balance,
|
||||
staking_stakers?: Exposure,
|
||||
staking_nominators?: [Array<AccountId>],
|
||||
staking_validators?: [ValidatorPrefs],
|
||||
stashOptions: Array<KeyringSectionOption>,
|
||||
validators: Array<string>
|
||||
staking_ledger?: StakingLedger
|
||||
};
|
||||
|
||||
type State = {
|
||||
@ -63,12 +64,17 @@ class Account extends React.PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Each component is rendered and gets a `is[Component]Openwill` passed in a `isOpen` props.
|
||||
// These components will be loaded and return null at the first load (because is[Component]Open === false).
|
||||
// This is deliberate in order to display the Component modals in a performant matter later on
|
||||
// because their state will already be loaded.
|
||||
return (
|
||||
<article className='staking--Account'>
|
||||
{this.renderBond()}
|
||||
{this.renderBondExtra()}
|
||||
{this.renderNominating()}
|
||||
{this.renderSessionKey()}
|
||||
{this.renderUnbond()}
|
||||
{this.renderValidating()}
|
||||
<AddressSummary
|
||||
name={name}
|
||||
@ -118,6 +124,19 @@ class Account extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderUnbond () {
|
||||
const { controllerId } = this.props;
|
||||
const { isUnbondOpen } = this.state;
|
||||
|
||||
return (
|
||||
<Unbond
|
||||
controllerId={controllerId}
|
||||
isOpen={isUnbondOpen}
|
||||
onClose={this.toggleUnbond}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderValidating () {
|
||||
const { accountId, stashId, staking_validators } = this.props;
|
||||
const { isValidatingOpen } = this.state;
|
||||
@ -290,7 +309,7 @@ class Account extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
private renderButtons () {
|
||||
const { accountId, controllerId, sessionId, stashId, staking_nominators, staking_validators, t } = this.props;
|
||||
const { accountId, controllerId, sessionId, staking_nominators, staking_validators,stashId, freeBalance, staking_ledger, t } = this.props;
|
||||
const buttons = [];
|
||||
|
||||
if (!stashId) {
|
||||
@ -304,14 +323,31 @@ class Account extends React.PureComponent<Props, State> {
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
buttons.push(
|
||||
// only show a "Bond Additional" button if this stash account actually doesn't bond everything already
|
||||
// staking_ledger.total gives the total amount that can be slashed (any active amount + what is being unlocked)
|
||||
if (freeBalance && staking_ledger && staking_ledger.total && (freeBalance.gt(staking_ledger.total))) {
|
||||
buttons.push(
|
||||
<Button
|
||||
isPrimary
|
||||
key='bond'
|
||||
onClick={this.toggleBondExtra}
|
||||
label={t('Bond Additional')}
|
||||
/>
|
||||
);
|
||||
);
|
||||
}
|
||||
// don't show the `unbond` button if there's nothing to unbond
|
||||
// staking_ledger.active gives the amount that can be unbonded (total - what's being unlocked).
|
||||
if (staking_ledger && staking_ledger.active && staking_ledger.active.gtn(0)) {
|
||||
buttons.length && buttons.push(<Button.Or key='bondAdditional.or' />);
|
||||
buttons.push(
|
||||
<Button
|
||||
isNegative
|
||||
key='unbond'
|
||||
onClick={this.toggleUnbond}
|
||||
label={t('Unbond')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const isNominating = !!staking_nominators && !!staking_nominators[0] && staking_nominators[0].length;
|
||||
@ -394,6 +430,12 @@ class Account extends React.PureComponent<Props, State> {
|
||||
}));
|
||||
}
|
||||
|
||||
private toggleUnbond = () => {
|
||||
this.setState(({ isUnbondOpen }) => ({
|
||||
isUnbondOpen: !isUnbondOpen
|
||||
}));
|
||||
}
|
||||
|
||||
private toggleValidating = () => {
|
||||
this.setState(({ isValidatingOpen }) => ({
|
||||
isValidatingOpen: !isValidatingOpen
|
||||
@ -422,6 +464,15 @@ export default translate(
|
||||
transform: (ledger: Option<StakingLedger>) =>
|
||||
ledger.unwrapOr({ stash: null }).stash
|
||||
}],
|
||||
['query.staking.ledger', {
|
||||
paramName: 'controllerId',
|
||||
transform: (ledger: Option<StakingLedger>) =>
|
||||
ledger.unwrapOr({ stash: null, total: null, active: null })
|
||||
}],
|
||||
['query.balances.freeBalance', {
|
||||
paramName: 'accountId',
|
||||
propName: 'freeBalance'
|
||||
}],
|
||||
['query.staking.stakers', { paramName: 'accountId' }],
|
||||
['query.staking.nominators', { paramName: 'stashId' }],
|
||||
['query.staking.validators', { paramName: 'stashId' }]
|
||||
|
||||
@ -96,7 +96,6 @@ class Accounts extends React.PureComponent<Props, State> {
|
||||
name={name}
|
||||
recentlyOffline={recentlyOffline}
|
||||
stashOptions={this.getStashOptions()}
|
||||
validators={validators}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user