Use derive staking info (#1239)
* use derive.staking.info * tooltip on button & remove unlock comp * merge master fix * duplicate Bonded * translation and lint * comments
This commit is contained in:
parent
e256089cd5
commit
e88e435dde
@ -2,25 +2,25 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { DerivedBalances } from '@polkadot/api-derive/types';
|
||||
import { DerivedBalances, DerivedStaking } from '@polkadot/api-derive/types';
|
||||
import { BareProps, I18nProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withCalls, withMulti } from '@polkadot/ui-api';
|
||||
import { formatBalance, formatNumber } from '@polkadot/util';
|
||||
import { Icon, Tooltip, TxButton } from '@polkadot/ui-app';
|
||||
import { withCalls, withMulti } from '@polkadot/ui-api';
|
||||
|
||||
import translate from './translate';
|
||||
import CryptoType from './CryptoType';
|
||||
import Bonded from './Bonded';
|
||||
import Label from './Label';
|
||||
import Unlocking from './Unlocking';
|
||||
|
||||
type Props = BareProps & I18nProps & {
|
||||
balances_all?: DerivedBalances,
|
||||
children?: React.ReactNode,
|
||||
staking_info?: DerivedStaking,
|
||||
value: string,
|
||||
withBalance?: boolean | { available?: boolean, bonded?: boolean, free?: boolean, locked?: boolean },
|
||||
withBalance?: boolean | { available?: boolean, bonded?: boolean, free?: boolean, redeemable?: boolean, unlocking?: boolean },
|
||||
withExtended?: boolean | { crypto?: boolean, nonce?: boolean }
|
||||
};
|
||||
|
||||
@ -51,9 +51,9 @@ class AddressInfo extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
private renderBalances () {
|
||||
const { balances_all, t, value, withBalance = true } = this.props;
|
||||
const { balances_all, staking_info, t, withBalance = true } = this.props;
|
||||
const balanceDisplay = withBalance === true
|
||||
? { available: true, bonded: true, free: true, locked: true }
|
||||
? { available: true, bonded: true, free: true, redeemable: true, unlocking: true }
|
||||
: withBalance
|
||||
? withBalance
|
||||
: undefined;
|
||||
@ -79,19 +79,28 @@ class AddressInfo extends React.PureComponent<Props> {
|
||||
{balanceDisplay.bonded && (
|
||||
<>
|
||||
<Label label={t('bonded')} />
|
||||
<Bonded
|
||||
className='result'
|
||||
params={value}
|
||||
/>
|
||||
<div className='result'>
|
||||
{staking_info && staking_info.stakingLedger
|
||||
? formatBalance(staking_info.stakingLedger.active)
|
||||
: '0'}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{balanceDisplay.locked && (
|
||||
{balanceDisplay.redeemable && staking_info && staking_info.redeemable && staking_info.redeemable.gtn(0) && (
|
||||
<>
|
||||
<Label label={t('locked')} />
|
||||
<Unlocking
|
||||
className='result'
|
||||
params={value}
|
||||
/>
|
||||
<Label label={t('redeemable')} />
|
||||
<div className='result'>
|
||||
{formatBalance(staking_info.redeemable)}
|
||||
{this.renderRedeemButton()}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{balanceDisplay.unlocking && staking_info && staking_info.unlocking && (
|
||||
<>
|
||||
<Label label={t('unlocking')} />
|
||||
<div className='result'>
|
||||
{this.renderUnlocking()}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@ -130,6 +139,47 @@ class AddressInfo extends React.PureComponent<Props> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderRedeemButton () {
|
||||
const { staking_info, t } = this.props;
|
||||
|
||||
return (staking_info && staking_info.controllerId && (
|
||||
<TxButton
|
||||
accountId={staking_info.controllerId.toString()}
|
||||
className='iconButton'
|
||||
icon='lock'
|
||||
size='small'
|
||||
isPrimary
|
||||
key='unlock'
|
||||
params={[]}
|
||||
tooltip={t('Redeem these funds')}
|
||||
tx='staking.withdrawUnbonded'
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
private renderUnlocking () {
|
||||
const { staking_info, t } = this.props;
|
||||
|
||||
return (
|
||||
staking_info &&
|
||||
staking_info.unlocking &&
|
||||
staking_info.unlocking.map(({ remainingBlocks, value }, index) => (
|
||||
<div key={index}>
|
||||
{formatBalance(value)}
|
||||
<Icon
|
||||
name='info circle'
|
||||
data-tip
|
||||
data-for={`unlocking-trigger-${index}`}
|
||||
/>
|
||||
<Tooltip
|
||||
text={t('{{remainingBlocks}} blocks left', { replace: { remainingBlocks } })}
|
||||
trigger={`unlocking-trigger-${index}`}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
@ -156,11 +206,20 @@ export default withMulti(
|
||||
|
||||
.result {
|
||||
grid-column: 2;
|
||||
|
||||
.iconButton {
|
||||
padding-left: 0!important;
|
||||
}
|
||||
|
||||
i.info.circle.icon {
|
||||
margin-left: .3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['derive.balances.all', { paramName: 'value' }]
|
||||
['derive.balances.all', { paramName: 'value' }],
|
||||
['derive.staking.info', { paramName: 'value' }]
|
||||
)
|
||||
);
|
||||
|
||||
@ -32,7 +32,6 @@ class AddressRow extends AddressSummary {
|
||||
{this.renderBalance()}
|
||||
{this.renderBonded()}
|
||||
{this.renderNonce()}
|
||||
{this.renderUnlocking()}
|
||||
</div>
|
||||
{this.renderTags()}
|
||||
</div>
|
||||
|
||||
@ -21,7 +21,6 @@ import CopyButton from './CopyButton';
|
||||
import IdentityIcon from './IdentityIcon';
|
||||
import NonceDisplay from './Nonce';
|
||||
import translate from './translate';
|
||||
import UnlockingDisplay from './Unlocking';
|
||||
|
||||
export type Props = I18nProps & {
|
||||
accounts_idAndIndex?: [AccountId?, AccountIndex?],
|
||||
@ -43,8 +42,7 @@ export type Props = I18nProps & {
|
||||
withIcon?: boolean,
|
||||
withIndex?: boolean,
|
||||
withNonce?: boolean,
|
||||
withTags?: boolean,
|
||||
withUnlocking?: boolean
|
||||
withTags?: boolean
|
||||
};
|
||||
|
||||
type State = {
|
||||
@ -120,7 +118,6 @@ class AddressSummary extends React.PureComponent<Props, State> {
|
||||
{this.renderBalance()}
|
||||
{this.renderBonded()}
|
||||
{this.renderNonce()}
|
||||
{this.renderUnlocking()}
|
||||
</div>
|
||||
{this.renderTags()}
|
||||
</div>
|
||||
@ -408,24 +405,6 @@ class AddressSummary extends React.PureComponent<Props, State> {
|
||||
return resultingDom;
|
||||
}
|
||||
|
||||
protected renderUnlocking () {
|
||||
const { withUnlocking, t } = this.props;
|
||||
const { address } = this.state;
|
||||
|
||||
if (!withUnlocking || !address) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<UnlockingDisplay
|
||||
className='ui--AddressSummary-available'
|
||||
label={<label>{t('unlock')}</label>}
|
||||
labelRedeem={<label>{t('redeem')}</label>}
|
||||
params={address}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
protected saveName = () => {
|
||||
const { address, name } = this.state;
|
||||
const trimmedName = name.trim();
|
||||
|
||||
@ -43,6 +43,7 @@ type Props = ApiProps & {
|
||||
onSuccess?: TxCallback,
|
||||
onUpdate?: TxCallback,
|
||||
params?: Array<any> | ConstructFn,
|
||||
tooltip?: string,
|
||||
tx?: string,
|
||||
withSpinner?: boolean
|
||||
};
|
||||
@ -60,7 +61,7 @@ class TxButtonInner extends React.PureComponent<InnerProps> {
|
||||
} as State;
|
||||
|
||||
render () {
|
||||
const { accountId, className, icon, iconSize , isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label } = this.props;
|
||||
const { accountId, className, icon, iconSize , isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, tooltip } = this.props;
|
||||
const { isSending } = this.state;
|
||||
const needsAccount = isUnsigned
|
||||
? false
|
||||
@ -69,6 +70,7 @@ class TxButtonInner extends React.PureComponent<InnerProps> {
|
||||
return (
|
||||
<Button
|
||||
className={className}
|
||||
tooltip={tooltip}
|
||||
icon={icon}
|
||||
isBasic={isBasic}
|
||||
isDisabled={isSending || isDisabled || needsAccount}
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app 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 { BareProps } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { AccountId, AccountIndex, Address } from '@polkadot/types';
|
||||
import { Unlocking } from '@polkadot/ui-reactive';
|
||||
|
||||
import { classes } from './util';
|
||||
|
||||
export type Props = BareProps & {
|
||||
bonded?: BN | Array<BN>,
|
||||
label?: React.ReactNode,
|
||||
labelRedeem?: React.ReactNode,
|
||||
params?: AccountId | AccountIndex | Address | string | Uint8Array | null,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
export default class UnlockingDisplay extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { params, className, label, labelRedeem, style } = this.props;
|
||||
return (
|
||||
<Unlocking
|
||||
className={classes('ui--Unlocking', className)}
|
||||
label={label}
|
||||
labelRedeem={labelRedeem}
|
||||
params={params}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -53,7 +53,6 @@ export { default as SummaryBox } from './SummaryBox';
|
||||
export { default as Tabs } from './Tabs';
|
||||
export { default as Tooltip } from './Tooltip';
|
||||
export { default as TxButton } from './TxButton';
|
||||
export { default as Unlocking } from './Unlocking';
|
||||
export { default as TxComponent } from './TxComponent';
|
||||
|
||||
export { default as media } from './media';
|
||||
|
||||
@ -97,22 +97,6 @@ header .ui--Button-Group {
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
button.ui.icon.withDrawUnbonded {
|
||||
padding: 0.3em;
|
||||
margin-left: 0.3em;
|
||||
color: #2e86ab;
|
||||
background: none !important;
|
||||
|
||||
&:hover {
|
||||
color: #fff !important;
|
||||
background-color: #2e86ab !important;
|
||||
}
|
||||
}
|
||||
|
||||
.result-locked > i {
|
||||
margin-left: .3em
|
||||
}
|
||||
|
||||
button.ui.icon.iconButton {
|
||||
padding: 0em .3em .3em .3em !important;
|
||||
color: #2e86ab !important;
|
||||
@ -123,10 +107,6 @@ button.ui.icon.iconButton {
|
||||
right: -2.3em !important;
|
||||
}
|
||||
|
||||
.ui--Unlocking i.info.circle.icon {
|
||||
margin-left: .3em;
|
||||
}
|
||||
|
||||
.editable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-reactive 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, AccountIndex, Address, BlockNumber, Option, StakingLedger, UnlockChunk } from '@polkadot/types';
|
||||
import { BareProps, CallProps } from '@polkadot/ui-api/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { formatBalance } from '@polkadot/util';
|
||||
import { Icon, Tooltip, TxButton } from '@polkadot/ui-app';
|
||||
import { withCalls } from '@polkadot/ui-api';
|
||||
|
||||
type Props = BareProps & CallProps & {
|
||||
chain_bestNumber?: BN,
|
||||
controllerId?: AccountId,
|
||||
label?: React.ReactNode,
|
||||
labelRedeem?: React.ReactNode,
|
||||
params?: AccountId | AccountIndex | Address | string | Uint8Array | null,
|
||||
remainingLabel?: string,
|
||||
staking_ledger?: StakingLedger,
|
||||
session_eraLength?: BN,
|
||||
unlockings?: Array<UnlockChunk>
|
||||
};
|
||||
|
||||
type State = {
|
||||
tooltipOpen: boolean
|
||||
};
|
||||
|
||||
export class UnlockingDisplay extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
tooltipOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, label, unlockings } = this.props;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{
|
||||
unlockings
|
||||
? (
|
||||
<>
|
||||
{this.renderUnlockableSum()}
|
||||
{this.renderLocked()}
|
||||
</>
|
||||
)
|
||||
: <>{label}0</>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private groupByEra (list: UnlockChunk[]) {
|
||||
return list.reduce((map, { era, value }) => {
|
||||
const key = era.toString();
|
||||
|
||||
if (!map[key]) {
|
||||
map[key] = value;
|
||||
} else {
|
||||
map[key] = map[key].add(value);
|
||||
}
|
||||
|
||||
return map;
|
||||
}, {} as { [index: string]: BN });
|
||||
}
|
||||
|
||||
private remainingBlocks (era: BN) {
|
||||
const { chain_bestNumber, session_eraLength } = this.props;
|
||||
|
||||
if (!chain_bestNumber || !session_eraLength || era.lten(0)) {
|
||||
return new BN(0);
|
||||
} else {
|
||||
const remaining = session_eraLength.mul(era).sub(chain_bestNumber);
|
||||
|
||||
return remaining.lten(0) ? new BN(0) : remaining;
|
||||
}
|
||||
}
|
||||
|
||||
private renderLocked () {
|
||||
const { controllerId, label, unlockings } = this.props;
|
||||
const { tooltipOpen } = this.state;
|
||||
|
||||
if (!unlockings || !controllerId) return null;
|
||||
// select the Unlockchunks that can't be unlocked yet.
|
||||
const filteredUnlockings = unlockings.filter((chunk) => this.remainingBlocks(chunk.era).gtn(0));
|
||||
// group the Unlockchunks that have the same era and sum their values
|
||||
const groupedUnlockings = filteredUnlockings.length ? this.groupByEra(filteredUnlockings) : undefined;
|
||||
const result = groupedUnlockings && Object.keys(groupedUnlockings).map((eraString) => (
|
||||
<div key={eraString}>
|
||||
{label}
|
||||
{formatBalance(groupedUnlockings[eraString])}
|
||||
<Icon
|
||||
name='info circle'
|
||||
data-tip
|
||||
data-for={`controlled-trigger${eraString}`}
|
||||
onMouseOver={this.toggleTooltip}
|
||||
onMouseOut={this.toggleTooltip}
|
||||
/>
|
||||
{tooltipOpen && (
|
||||
<Tooltip
|
||||
text={`${this.remainingBlocks(new BlockNumber(eraString))} blocks left`}
|
||||
trigger={`controlled-trigger${eraString}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
));
|
||||
|
||||
return result && result.length
|
||||
? result
|
||||
: <>{label}0</>;
|
||||
}
|
||||
|
||||
private renderUnlockableSum () {
|
||||
const { controllerId, labelRedeem, unlockings } = this.props;
|
||||
|
||||
if (!unlockings || !unlockings[0] || !controllerId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const unlockable = unlockings.filter((chunk) => this.remainingBlocks(chunk.era).eqn(0));
|
||||
const unlockableSum = unlockable.reduce((curr, prev) => {
|
||||
return curr.add(prev.value);
|
||||
}, new BN(0));
|
||||
|
||||
return (
|
||||
unlockableSum.gtn(0)
|
||||
? (
|
||||
<>
|
||||
{labelRedeem}
|
||||
{formatBalance(unlockableSum)}
|
||||
<TxButton
|
||||
accountId={controllerId.toString()}
|
||||
className='withDrawUnbonded'
|
||||
icon='lock'
|
||||
size='small'
|
||||
isPrimary
|
||||
key='unlock'
|
||||
params={[]}
|
||||
tx='staking.withdrawUnbonded'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
: null
|
||||
);
|
||||
}
|
||||
|
||||
private toggleTooltip = () => {
|
||||
this.setState(({ tooltipOpen }) => ({
|
||||
tooltipOpen: !tooltipOpen
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export default withCalls<Props>(
|
||||
['query.staking.bonded', {
|
||||
paramName: 'params',
|
||||
propName: 'controllerId',
|
||||
transform: (value) =>
|
||||
value.unwrapOr(null)
|
||||
}],
|
||||
['query.staking.ledger', {
|
||||
paramName: 'controllerId',
|
||||
propName: 'unlockings',
|
||||
transform: (ledger: Option<StakingLedger>) =>
|
||||
ledger.unwrapOr({ unlocking: null }).unlocking
|
||||
}],
|
||||
'derive.session.eraLength',
|
||||
'derive.chain.bestNumber'
|
||||
)(UnlockingDisplay);
|
||||
@ -16,4 +16,3 @@ export { default as Nonce } from './Nonce';
|
||||
export { default as TimeNow } from './TimeNow';
|
||||
export { default as TimePeriod } from './TimePeriod';
|
||||
export { default as TotalIssuance } from './TotalIssuance';
|
||||
export { default as Unlocking } from './Unlocking';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user