diff --git a/packages/page-staking/src/Actions/Account/SetControllerAccount.tsx b/packages/page-staking/src/Actions/Account/SetControllerAccount.tsx index 7a950e29b0..91b4e079a9 100644 --- a/packages/page-staking/src/Actions/Account/SetControllerAccount.tsx +++ b/packages/page-staking/src/Actions/Account/SetControllerAccount.tsx @@ -2,108 +2,76 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ApiProps } from '@polkadot/react-api/types'; -import { I18nProps } from '@polkadot/react-components/types'; +import React, { useState } from 'react'; +import { Icon, InputAddress, Modal, TxButton } from '@polkadot/react-components'; -import React from 'react'; -import { Icon, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components'; -import { withApi, withMulti } from '@polkadot/react-api/hoc'; +import { useTranslation } from '../../translate'; +import InputValidationController from './InputValidationController'; -import translate from '../../translate'; -import InputValidationController from '../Account/InputValidationController'; - -interface Props extends ApiProps, I18nProps { +interface Props { defaultControllerId: string; isValidating?: boolean; onClose: () => void; stashId: string; } -interface State { - controllerError: string | null; - controllerId: string | null; +function SetControllerAccount ({ defaultControllerId, isValidating, onClose, stashId }: Props): React.ReactElement { + const { t } = useTranslation(); + const [, setControllerError] = useState(null); + const [controllerId, setControllerId] = useState(null); + + return ( + + + {isValidating && ( +
+
+ + {t('Warning - Changing the controller while validating will modify the associated session account. It is advised to stop validating before changing the controller account.')} +
+
+ )} + + + +
+ + + +
+ ); } -class SetControllerAccount extends TxComponent { - constructor (props: Props) { - super(props); - - this.state = { - controllerError: null, - controllerId: null - }; - } - - public render (): React.ReactNode { - const { defaultControllerId, isValidating, onClose, stashId, t } = this.props; - const { controllerId } = this.state; - const canSubmit = !!controllerId; - - return ( - - - {isValidating && ( -
-
- - {t('Warning - Changing the controller while validating will modify the associated session account. It is advised to stop validating before changing the controller account.')} -
-
- )} - - - -
- - - -
- ); - } - - private onChangeController = (controllerId: string | null): void => { - this.setState({ controllerId }); - } - - private onControllerError = (controllerError: string | null): void => { - this.setState({ controllerError }); - } -} - -export default withMulti( - SetControllerAccount, - translate, - withApi -); +export default React.memo(SetControllerAccount); diff --git a/packages/page-staking/src/Actions/Account/SetRewardDestination.tsx b/packages/page-staking/src/Actions/Account/SetRewardDestination.tsx index bc4a8532c6..bd1a99a830 100644 --- a/packages/page-staking/src/Actions/Account/SetRewardDestination.tsx +++ b/packages/page-staking/src/Actions/Account/SetRewardDestination.tsx @@ -2,68 +2,28 @@ // 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/react-components/types'; +import React, { useState } from 'react'; +import { Dropdown, InputAddress, Modal, TxButton } from '@polkadot/react-components'; -import React from 'react'; -import { Dropdown, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components'; -import { withMulti } from '@polkadot/react-api/hoc'; - -import translate from '../../translate'; +import { useTranslation } from '../../translate'; import { rewardDestinationOptions } from '../constants'; -interface Props extends I18nProps { +interface Props { defaultDestination?: number; controllerId: string; onClose: () => void; } -interface State { - destination: number; -} +function SetRewardDestination ({ controllerId, defaultDestination, onClose }: Props): React.ReactElement { + const { t } = useTranslation(); + const [destination, setDestination] = useState(0); -class SetRewardDestination extends TxComponent { - constructor (props: Props) { - super(props); - - this.state = { - destination: 0 - }; - } - - public render (): React.ReactNode { - const { controllerId, onClose, t } = this.props; - const { destination } = this.state; - const canSubmit = !!controllerId; - - return ( - - {this.renderContent()} - - - - - ); - } - - private renderContent (): React.ReactNode { - const { controllerId, defaultDestination, t } = this.props; - const { destination } = this.state; - - return ( + return ( + { defaultValue={defaultDestination} help={t('The destination account for any payments as either a nominator or validator')} label={t('payment destination')} - onChange={this.onChangeDestination} + onChange={setDestination} options={rewardDestinationOptions} value={destination} /> - ); - } - - private onChangeDestination = (destination: number): void => { - this.setState({ destination }); - } + + + + + ); } -export default withMulti( - SetRewardDestination, - translate -); +export default React.memo(SetRewardDestination); diff --git a/packages/page-staking/src/Actions/Account/Unbond.tsx b/packages/page-staking/src/Actions/Account/Unbond.tsx index f43044e101..f2bec9b4a5 100644 --- a/packages/page-staking/src/Actions/Account/Unbond.tsx +++ b/packages/page-staking/src/Actions/Account/Unbond.tsx @@ -2,93 +2,39 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -/* eslint-disable @typescript-eslint/camelcase */ - import { AccountId, StakingLedger } from '@polkadot/types/interfaces'; -import { I18nProps } from '@polkadot/react-components/types'; -import { ApiProps } from '@polkadot/react-api/types'; import BN from 'bn.js'; -import React from 'react'; +import React, { useState } from 'react'; +import { Trans } from 'react-i18next'; import styled from 'styled-components'; -import { Option } from '@polkadot/types'; -import { AddressInfo, InputAddress, InputBalance, Modal, TxButton, TxComponent } from '@polkadot/react-components'; -import { withCalls, withApi, withMulti } from '@polkadot/react-api/hoc'; +import { AddressInfo, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/react-components'; +import { BlockToTime } from '@polkadot/react-query'; +import { formatNumber } from '@polkadot/util'; -import translate from '../../translate'; +import { useTranslation } from '../../translate'; +import useUnbondDuration from '../useUnbondDuration'; -interface Props extends I18nProps, ApiProps { +interface Props { + className?: string; controllerId?: AccountId | null; - isOpen: boolean; onClose: () => void; + stakingLedger?: StakingLedger; stashId: string; - staking_ledger?: Option; } -interface State { - maxBalance?: BN; - maxUnbond?: BN; -} +function Unbond ({ className, controllerId, onClose, stakingLedger, stashId }: Props): React.ReactElement { + const { t } = useTranslation(); + const duration = useUnbondDuration(); + const [maxBalance] = useState(stakingLedger?.active.unwrap() || null); + const [maxUnbond, setMaxUnbond] = useState(null); -const BalanceWrapper = styled.div` - & > div { - justify-content: flex-end; - - & .column { - flex: 0; - } - } -`; - -class Unbond extends TxComponent { - public state: State = {}; - - public componentDidUpdate (prevProps: Props): void { - const { staking_ledger } = this.props; - - if (staking_ledger !== prevProps.staking_ledger) { - this.setMaxBalance(); - } - } - - public render (): React.ReactNode { - const { controllerId, isOpen, onClose, t } = this.props; - const { maxUnbond } = this.state; - const canSubmit = !!maxUnbond && maxUnbond.gtn(0); - - if (!isOpen) { - return null; - } - - return ( - - {this.renderContent()} - - - - - ); - } - - private renderContent (): React.ReactNode { - const { controllerId, stashId, t } = this.props; - const { maxBalance } = this.state; - - return ( + return ( + { isDisabled label={t('controller account')} /> - +
- +
+ {duration?.gtn(0) && ( +
+ Once unbonded, funds will only be available for withdrawal in ({formatNumber(duration)} blocks) +
+ )}
- ); - } - - private nextState (newState: Partial): void { - this.setState((prevState: State): State => { - const { maxUnbond = prevState.maxUnbond, maxBalance = prevState.maxBalance } = newState; - - return { - maxBalance, - maxUnbond - }; - }); - } - - private setMaxBalance = (): void => { - const { staking_ledger } = this.props; - - if (!staking_ledger || staking_ledger.isNone) { - return; - } - - const { active } = staking_ledger.unwrap(); - - this.nextState({ - maxBalance: active.unwrap() - }); - } - - private onChangeValue = (maxUnbond?: BN): void => { - this.nextState({ maxUnbond }); - } + + + +
+ ); } -export default withMulti( - Unbond, - translate, - withApi, - withCalls( - ['query.staking.ledger', { paramName: 'controllerId' }] - ) -); +export default React.memo(styled(Unbond)` + article.warning > div { + display: inline-block; + } + + .staking--Unbond--max > div { + justify-content: flex-end; + + & .column { + flex: 0; + } + } +`); diff --git a/packages/page-staking/src/Actions/Account/Validate.tsx b/packages/page-staking/src/Actions/Account/Validate.tsx index e8344e6f94..2d3ca3e8c1 100644 --- a/packages/page-staking/src/Actions/Account/Validate.tsx +++ b/packages/page-staking/src/Actions/Account/Validate.tsx @@ -2,82 +2,41 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ApiProps } from '@polkadot/react-api/types'; -import { I18nProps } from '@polkadot/react-components/types'; - import BN from 'bn.js'; -import React from 'react'; -import { withApi, withMulti } from '@polkadot/react-api/hoc'; -import { InputAddress, InputNumber, Modal, TxButton, TxComponent } from '@polkadot/react-components'; +import React, { useCallback, useState } from 'react'; +import { InputAddress, InputNumber, Modal, TxButton } from '@polkadot/react-components'; -import translate from '../../translate'; +import { useTranslation } from '../../translate'; -interface Props extends ApiProps, I18nProps { +interface Props { controllerId: string; - isOpen: boolean; onClose: () => void; stashId: string; } -interface State { - commission: BN; -} - const COMM_MUL = new BN(10000000); const MAX_COMM = new BN(100); +const ZERO = new BN(0); -class Validate extends TxComponent { - public state: State = { - commission: new BN(0) - }; +function Validate ({ controllerId, onClose, stashId }: Props): React.ReactElement { + const { t } = useTranslation(); + const [prefs, setPrefs] = useState({ commission: ZERO }); - public render (): React.ReactNode { - const { isOpen, t } = this.props; + const _setCommission = useCallback( + (commission?: BN) => setPrefs({ commission: (commission || ZERO).mul(COMM_MUL) }), + [] + ); - if (!isOpen) { - return null; - } - - return ( - - {this.renderContent()} - {this.renderButtons()} - - ); - } - - private renderButtons (): React.ReactNode { - const { controllerId, onClose, t } = this.props; - const { commission } = this.state; - - return ( - - - - ); - } - - private renderContent (): React.ReactNode { - const { controllerId, stashId, t } = this.props; - - return ( + return ( + @@ -93,20 +52,23 @@ class Validate extends TxComponent { isZeroable label={t('reward commission percentage')} maxValue={MAX_COMM} - onChange={this.onChangeCommission} - onEnter={this.sendTx} + onChange={_setCommission} /> - ); - } - - private onChangeCommission = (commission?: BN): void => { - commission && this.setState({ commission: commission.mul(COMM_MUL) }); - } + + + + + ); } -export default withMulti( - Validate, - translate, - withApi -); +export default React.memo(Validate); diff --git a/packages/page-staking/src/Actions/Account/index.tsx b/packages/page-staking/src/Actions/Account/index.tsx index 99fd629ae0..25ce85070d 100644 --- a/packages/page-staking/src/Actions/Account/index.tsx +++ b/packages/page-staking/src/Actions/Account/index.tsx @@ -97,7 +97,7 @@ function Account ({ allStashes, className, isInElection, isOwnStash, next, onUpd const validateInfo = useCall(api.query.staking.validators, [stashId]); const balancesAll = useCall(api.derive.balances.all as any, [stashId]); const stakingAccount = useCall(api.derive.staking.account as any, [stashId]); - const [{ controllerId, destination, destinationId, hexSessionIdNext, hexSessionIdQueue, isLoading, isOwnController, isStashNominating, isStashValidating, nominees, sessionIds, validatorPrefs }, setStakeState] = useState({ controllerId: null, destinationId: 0, hexSessionIdNext: null, hexSessionIdQueue: null, isLoading: true, isOwnController: false, isStashNominating: false, isStashValidating: false, sessionIds: [] }); + const [{ controllerId, destination, destinationId, hexSessionIdNext, hexSessionIdQueue, isLoading, isOwnController, isStashNominating, isStashValidating, nominees, sessionIds, stakingLedger }, setStakeState] = useState({ controllerId: null, destinationId: 0, hexSessionIdNext: null, hexSessionIdQueue: null, isLoading: true, isOwnController: false, isStashNominating: false, isStashValidating: false, sessionIds: [] }); const [activeNoms, setActiveNoms] = useState([]); const inactiveNoms = useInactives(stashId, nominees); const [isBondExtraOpen, toggleBondExtra] = useToggle(); @@ -146,19 +146,21 @@ function Account ({ allStashes, className, isInElection, isOwnStash, next, onUpd validators={validators} /> )} - - + {isUnbondOpen && ( + + )} + {isValidateOpen && controllerId && ( + + )} {isBondExtraOpen && ( )} - {isSetControllerOpen && ( + {isSetControllerOpen && controllerId && ( (api.derive.session?.eraLength as any, []); + const [duration, setDuration] = useState(); + + useEffect((): void => { + eraLength && setDuration( + eraLength.mul(api.consts.staking?.bondingDuration) + ); + }, [api, eraLength]); + + return duration; +} diff --git a/packages/react-components/src/LinkExternal.tsx b/packages/react-components/src/LinkExternal.tsx index c2eba33187..5d8c3195c8 100644 --- a/packages/react-components/src/LinkExternal.tsx +++ b/packages/react-components/src/LinkExternal.tsx @@ -83,7 +83,7 @@ export default React.memo(styled(LinkExternal)` > div { display: block; - whitespace: nowrap; + white-space: nowrap; > span+span { margin-left: 0.3rem; diff --git a/packages/react-components/src/StakingUnbonding.tsx b/packages/react-components/src/StakingUnbonding.tsx index 9e5260dc65..d8229208e4 100644 --- a/packages/react-components/src/StakingUnbonding.tsx +++ b/packages/react-components/src/StakingUnbonding.tsx @@ -74,8 +74,14 @@ function StakingUnbonding ({ className, stakingInfo }: Props): React.ReactElemen } export default React.memo(styled(StakingUnbonding)` + white-space: nowrap; + i.icon { margin-left: 0.25rem; margin-right: 0; } + + .ui--FormatBalance { + display: inline-block; + } `);