Extrinsic app selection as functional (#2523)

* Extrinsic app selection as functional

* td .ui--Spinner spacing

* Remove staking counter
This commit is contained in:
Jaco Greeff 2020-04-07 08:16:55 +02:00 committed by GitHub
parent 84910c3466
commit a7217bd9d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 227 deletions

View File

@ -4,8 +4,7 @@
import { Route } from './types';
// import Staking from '@polkadot/app-staking';
import Staking, { useCounter } from '@polkadot/app-staking';
import Staking from '@polkadot/app-staking';
const route: Route = {
Component: Staking,
@ -18,8 +17,7 @@ const route: Route = {
defaultValue: 'Staking'
},
icon: 'certificate',
name: 'staking',
useCounter
name: 'staking'
};
export default route;

View File

@ -2,128 +2,67 @@
// 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 { QueueTxExtrinsicAdd } from '@polkadot/react-components/Status/types';
import { ApiProps } from '@polkadot/react-api/types';
import { SubmittableExtrinsic } from '@polkadot/api/types';
import React from 'react';
import { Button, Extrinsic, InputAddress, TxButton, TxComponent } from '@polkadot/react-components';
import { withApi, withMulti } from '@polkadot/react-api/hoc';
import React, { useCallback, useState } from 'react';
import { Button, Extrinsic, InputAddress, TxButton } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import { BalanceFree } from '@polkadot/react-query';
import translate from './translate';
import { useTranslation } from './translate';
interface Props extends ApiProps, I18nProps {
queueExtrinsic: QueueTxExtrinsicAdd;
}
function Selection (): React.ReactElement {
const { t } = useTranslation();
const { apiDefaultTxSudo } = useApi();
const [accountId, setAccountId] = useState<string | null>(null);
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
interface State {
isValid: boolean;
isValidUnsigned: boolean;
method: SubmittableExtrinsic<'promise'> | null;
accountId?: string | null;
}
const _onExtrinsicChange = useCallback(
(method?: SubmittableExtrinsic<'promise'>) =>
setExtrinsic(() => method || null),
[]
);
class Selection extends TxComponent<Props, State> {
public state: State = {
isValid: false,
isValidUnsigned: false,
method: null
};
public render (): React.ReactNode {
const { apiDefaultTxSudo, t } = this.props;
const { accountId, isValid, isValidUnsigned } = this.state;
const extrinsic = this.getExtrinsic() || apiDefaultTxSudo('0x00');
return (
<div className='extrinsics--Selection'>
<InputAddress
label={t('using the selected account')}
labelExtra={
<BalanceFree
label={<label>{t('free balance')}</label>}
params={accountId}
/>
}
onChange={this.onChangeSender}
type='account'
/>
<Extrinsic
defaultValue={apiDefaultTxSudo}
label={t('submit the following extrinsic')}
onChange={this.onChangeExtrinsic}
onEnter={this.sendTx}
/>
<Button.Group>
<TxButton
extrinsic={extrinsic}
icon='sign-in'
isBasic
isDisabled={!isValidUnsigned}
isUnsigned
label={t('Submit Unsigned')}
withSpinner
return (
<div className='extrinsics--Selection'>
<InputAddress
label={t('using the selected account')}
labelExtra={
<BalanceFree
label={<label>{t('free balance')}</label>}
params={accountId}
/>
<Button.Or />
<TxButton
accountId={accountId}
extrinsic={extrinsic}
icon='sign-in'
isDisabled={!isValid}
isPrimary={false}
label={t('Submit Transaction')}
/>
</Button.Group>
</div>
);
}
private nextState (newState: Partial<State>): void {
this.setState(
(prevState: State): State => {
const { method = prevState.method, accountId = prevState.accountId } = newState;
const isValid = !!(
accountId &&
accountId.length &&
method
);
return {
accountId,
isValid,
isValidUnsigned: !!method,
method
};
}
);
}
private onChangeExtrinsic = (method: SubmittableExtrinsic<'promise'> | null = null): void => {
this.nextState({ method });
}
private onChangeSender = (accountId: string | null): void => {
this.nextState({ accountId });
}
private getExtrinsic (): SubmittableExtrinsic<'promise'> | null {
const { api } = this.props;
const { method } = this.state;
if (!method) {
return null;
}
const fn = api.findCall(method.callIndex);
return api.tx[fn.section][fn.method](...method.args);
}
}
onChange={setAccountId}
type='account'
/>
<Extrinsic
defaultValue={apiDefaultTxSudo}
label={t('submit the following extrinsic')}
onChange={_onExtrinsicChange}
/>
<Button.Group>
<TxButton
extrinsic={extrinsic}
icon='sign-in'
isBasic
isDisabled={!extrinsic}
isUnsigned
label={t('Submit Unsigned')}
withSpinner
/>
<Button.Or />
<TxButton
accountId={accountId}
extrinsic={extrinsic}
icon='sign-in'
isDisabled={!extrinsic || !accountId}
isPrimary={false}
label={t('Submit Transaction')}
/>
</Button.Group>
</div>
);
}
export default withMulti(
Selection,
translate,
withApi
);
export default React.memo(Selection);

View File

@ -2,78 +2,59 @@
// 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 { KeyringPair } from '@polkadot/keyring/types';
import React from 'react';
import { AddressRow, Button, Modal, Password, TxComponent } from '@polkadot/react-components';
import React, { useCallback, useEffect, useState } from 'react';
import { AddressRow, Button, Modal, Password } from '@polkadot/react-components';
import translate from './translate';
import { useTranslation } from './translate';
interface Props extends I18nProps {
interface Props {
onClose: () => void;
onUnlock: () => void;
pair: KeyringPair | null;
}
interface State {
address: string;
password: string;
unlockError: string | null;
}
function Unlock ({ onClose, onUnlock, pair }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const [address, setAddress] = useState('');
const [password, setPassword] = useState('');
const [unlockError, setUnlockError] = useState<string | null>(null);
class Unlock extends TxComponent<Props, State> {
public state: State = {
address: '',
password: '',
unlockError: null
};
useEffect((): void => {
setAddress(pair?.address || '');
}, [pair]);
public static getDerivedStateFromProps ({ pair }: Props): Pick<State, never> {
return {
address: (pair && pair.address) || ''
};
useEffect((): void => {
setUnlockError(null);
}, [password]);
const _onUnlock = useCallback(
(): void => {
if (!pair || !pair.isLocked) {
return;
}
try {
pair.decodePkcs8(password);
} catch (error) {
return setUnlockError(error.message);
}
onUnlock();
},
[onUnlock, pair, password]
);
if (!pair) {
return null;
}
public render (): React.ReactNode {
const { pair, t } = this.props;
if (!pair) {
return null;
}
return (
<Modal
className='toolbox--Unlock'
header={t('Unlock account')}
>
{this.renderContent()}
{this.renderActions()}
</Modal>
);
}
private renderActions (): React.ReactNode {
const { t } = this.props;
return (
<Modal.Actions onCancel={this.onCancel}>
<Button
icon='unlock'
isPrimary
label={t('Unlock')}
onClick={this.onUnlock}
ref={this.button}
/>
</Modal.Actions>
);
}
private renderContent (): React.ReactNode {
const { t } = this.props;
const { address, password, unlockError } = this.state;
return (
return (
<Modal
className='toolbox--Unlock'
header={t('Unlock account')}
>
<Modal.Content>
<AddressRow
isInline
@ -86,58 +67,23 @@ class Unlock extends TxComponent<Props, State> {
help={t('The account\'s password specified at the creation of this account.')}
isError={!!unlockError}
label={t('password')}
onChange={this.onChangePassword}
onEnter={this.submit}
onChange={setPassword}
onEnter={_onUnlock}
value={password}
/>
</div>
</AddressRow>
</Modal.Content>
);
}
private unlockAccount (password?: string): string | null {
const { pair } = this.props;
if (!pair || !pair.isLocked) {
return null;
}
try {
pair.decodePkcs8(password);
} catch (error) {
return error.message;
}
return null;
}
private onChangePassword = (password: string): void => {
this.setState({
password,
unlockError: null
});
}
private onCancel = (): void => {
const { onClose } = this.props;
onClose();
}
private onUnlock = (): void => {
const { onUnlock } = this.props;
const { password } = this.state;
const unlockError = this.unlockAccount(password);
if (unlockError) {
this.setState({ unlockError });
return;
}
onUnlock();
}
<Modal.Actions onCancel={onClose}>
<Button
icon='unlock'
isPrimary
label={t('Unlock')}
onClick={_onUnlock}
/>
</Modal.Actions>
</Modal>
);
}
export default translate(Unlock);
export default React.memo(Unlock);

View File

@ -163,7 +163,7 @@ export default React.memo(styled(Table)`
}
.ui--Spinner {
margin: 0.5rem auto;
margin: 0 auto;
.text {
margin-bottom: 0;