TxButton to functional (#2314)

* TxButton to functional

* bug fix

* Small moves

Co-authored-by: Jaco Greeff <jacogr@gmail.com>
This commit is contained in:
Keith Ingram 2020-03-01 12:55:54 -05:00 committed by GitHub
parent 8c47775ec0
commit 1c8e504457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 68 additions and 191 deletions

View File

@ -108,7 +108,6 @@ class VanityApp extends TxComponent<Props, State> {
? t('Stop generation')
: t('Start generation')
}
ref={this.button}
/>
</Button.Group>
);

View File

@ -57,7 +57,6 @@ class ChangePass extends TxComponent<Props, State> {
isPrimary
label={t('Change')}
onClick={this.doChange}
ref={this.button}
/>
</Modal.Actions>
);

View File

@ -47,7 +47,6 @@ class Import extends TxComponent<Props, State> {
isPrimary
onClick={this.onSave}
label={t('Restore')}
ref={this.button}
/>
</Modal.Actions>
</Modal>

View File

@ -82,7 +82,6 @@ class Upload extends ContractModal<Props, State> {
onFailed={this.toggleBusy(false)}
params={[gasLimit, wasm]}
tx={api.tx.contracts ? 'contracts.putCode' : 'contract.putCode'}
ref={this.button}
withSpinner
/>
);

View File

@ -81,7 +81,6 @@ class Add extends ContractModal<Props, State> {
isPrimary
label={t('Save')}
onClick={this.onAdd}
ref={this.button}
/>
);
}

View File

@ -241,7 +241,6 @@ class Deploy extends ContractModal<Props, State> {
: 'contracts.create' // V2 (old)
: 'contract.create' // V1
}
ref={this.button}
withSpinner
/>
);

View File

@ -35,7 +35,7 @@ class Selection extends TxComponent<Props, State> {
public render (): React.ReactNode {
const { apiDefaultTxSudo, t } = this.props;
const { isValid, isValidUnsigned, accountId } = this.state;
const extrinsic = this.getExtrinsic() || apiDefaultTxSudo;
const extrinsic = this.getExtrinsic() || apiDefaultTxSudo('0x00');
return (
<div className='extrinsics--Selection'>
@ -64,12 +64,11 @@ class Selection extends TxComponent<Props, State> {
<Button.Or />
<TxButton
accountId={accountId}
icon='sign-in'
isDisabled={!isValid}
isPrimary
label={t('Submit Transaction')}
icon='sign-in'
extrinsic={extrinsic}
ref={this.button}
label={t('Submit Transaction')}
/>
</Button.Group>
</div>

View File

@ -80,7 +80,6 @@ class BondExtra extends TxComponent<Props, State> {
icon='sign-in'
onStart={onClose}
extrinsic={extrinsic}
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -90,7 +90,6 @@ class SetControllerAccount extends TxComponent<Props, State> {
onStart={onClose}
params={[controllerId]}
tx='staking.setController'
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -52,7 +52,6 @@ class SetRewardDestination extends TxComponent<Props, State> {
onStart={onClose}
params={[destination]}
tx={'staking.setPayee'}
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -76,7 +76,6 @@ class Unbond extends TxComponent<Props, State> {
onStart={onClose}
params={[maxUnbond]}
tx='staking.unbond'
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -94,7 +94,6 @@ class Validate extends TxComponent<Props, State> {
onStart={onClose}
params={[{ commission }]}
tx='staking.validate'
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -122,7 +122,6 @@ class NewStake extends TxComponent<Props, State> {
icon='sign-in'
onStart={onClose}
extrinsic={extrinsic}
ref={this.button}
withSpinner
/>
</Modal.Actions>

View File

@ -52,7 +52,6 @@ class Propose extends TxComponent<Props, State> {
tx='sudo.sudo'
isDisabled={!method || !isValid}
params={method ? [createType(registry, 'Proposal', method)] : []}
ref={this.button}
withSpinner
/>
</Button.Group>

View File

@ -2,141 +2,93 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
import { QueueTx, QueueTxExtrinsicAdd } from './Status/types';
import { TxButtonProps as Props } from './types';
import React from 'react';
import React, { useContext } from 'react';
import { SubmittableResult } from '@polkadot/api';
import { withApi } from '@polkadot/react-api/hoc';
import { useApi, useToggle } from '@polkadot/react-hooks';
import { assert, isFunction, isUndefined } from '@polkadot/util';
import Button from './Button';
import { QueueConsumer } from './Status/Context';
import { StatusContext } from './Status';
import { useTranslation } from './translate';
interface InjectedProps {
queueExtrinsic: QueueTxExtrinsicAdd;
txqueue: QueueTx[];
}
export default function TxButton ({ accountId, className, extrinsic: propsExtrinsic, icon, iconSize, isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, onClick, onFailed, onSendRef, onStart, onSuccess, onUpdate, params, tx, tooltip, withSpinner }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { queueExtrinsic } = useContext(StatusContext);
const [isSending, , setIsSending] = useToggle(false);
const needsAccount = !isUnsigned && !accountId;
type InnerProps = Props & InjectedProps;
const _onFailed = (result: SubmittableResult | null): void => {
setIsSending(false);
interface State {
extrinsic?: SubmittableExtrinsic;
isSending: boolean;
}
class TxButtonInner extends React.PureComponent<InnerProps> {
public state: State = {
isSending: false
onFailed && onFailed(result);
};
public render (): React.ReactNode {
const { accountId, className, icon, iconSize, innerRef, isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, tooltip } = this.props;
const _onSuccess = (result: SubmittableResult): void => {
setIsSending(false);
const { isSending } = this.state;
const needsAccount = isUnsigned
? false
: !accountId;
onSuccess && onSuccess(result);
};
return (
<Button
className={className}
tooltip={tooltip}
icon={icon}
isBasic={isBasic}
isDisabled={isSending || isDisabled || needsAccount}
isLoading={isSending}
isNegative={isNegative}
isPrimary={
isUndefined(isPrimary)
? (!isNegative && !isBasic)
: isPrimary
}
label={label}
onClick={this.send}
ref={innerRef}
size={iconSize}
/>
);
}
protected send = (): void => {
const { accountId, api, extrinsic: propsExtrinsic, isUnsigned, onClick, onFailed, onStart, onSuccess, onUpdate, params = [], queueExtrinsic, tx = '', withSpinner = true } = this.props;
const _onSend = (): void => {
let extrinsic: any;
if (propsExtrinsic) {
extrinsic = propsExtrinsic;
} else {
const [section, method] = tx.split('.');
const [section, method] = (tx || '').split('.');
assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`);
extrinsic = api.tx[section][method](...(
isFunction(params)
? params()
: params
: (params || [])
));
}
assert(extrinsic, 'Expected generated extrinsic passed to TxButton');
if (withSpinner) {
this.setState({ isSending: true });
setIsSending(true);
}
queueExtrinsic({
accountId,
accountId: accountId && accountId.toString(),
extrinsic,
isUnsigned,
txFailedCb: withSpinner ? this.onFailed : onFailed,
txFailedCb: withSpinner ? _onFailed : onFailed,
txStartCb: onStart,
txSuccessCb: withSpinner ? this.onSuccess : onSuccess,
txSuccessCb: withSpinner ? _onSuccess : onSuccess,
txUpdateCb: onUpdate
});
onClick && onClick();
};
if (onSendRef) {
onSendRef.current = _onSend;
}
private onFailed = (result: SubmittableResult | null): void => {
const { onFailed } = this.props;
this.setState({ isSending: false });
onFailed && onFailed(result);
}
private onSuccess = (result: SubmittableResult): void => {
const { onSuccess } = this.props;
this.setState({ isSending: false });
onSuccess && onSuccess(result);
}
return (
<Button
className={className}
tooltip={tooltip}
icon={icon || 'check'}
isBasic={isBasic}
isDisabled={isSending || isDisabled || needsAccount}
isLoading={isSending}
isNegative={isNegative}
isPrimary={
isUndefined(isPrimary)
? (!isNegative && !isBasic)
: isPrimary
}
label={label || t('Submit')}
onClick={_onSend}
size={iconSize}
/>
);
}
class TxButton extends React.PureComponent<Props, State> {
protected button: any = React.createRef();
public render (): React.ReactNode {
const { innerRef, ...props } = this.props;
return (
<QueueConsumer>
{({ queueExtrinsic, txqueue }): React.ReactNode => (
<TxButtonInner
{...props}
queueExtrinsic={queueExtrinsic}
txqueue={txqueue}
innerRef={innerRef}
/>
)}
</QueueConsumer>
);
}
protected send = (): void => {
this.button.current.send();
}
}
export default withApi(TxButton);

View File

@ -157,7 +157,6 @@ export default class TxModal<P extends TxModalProps, S extends TxModalState> ext
onFailed={this.onFailed}
onSuccess={this.onSuccess}
params={this.txParams()}
ref={this.button}
tx={this.txMethod()}
/>
);

View File

@ -7,13 +7,14 @@ import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
import { Abi } from '@polkadot/api-contract';
import { ActionStatus } from '@polkadot/react-components/Status/types';
import { InputAddressProps } from '@polkadot/react-components/InputAddress/types';
import { IExtrinsic } from '@polkadot/types/types';
import { ApiProps } from '@polkadot/react-api/types';
import { TxState } from '@polkadot/react-hooks/types';
import { Index } from '@polkadot/types/interfaces';
import { ButtonProps, Button$OnClick, Button$Sizes } from './Button/types';
import { IExtrinsic } from '@polkadot/types/types';
import { AccountId, Index } from '@polkadot/types/interfaces';
import { ButtonProps, Button$Sizes } from './Button/types';
import { TxCallback, TxFailedCallback } from './Status/types';
export type VoidFn = () => void;
export interface BareProps {
className?: string;
style?: Record<string, string | number>;
@ -27,22 +28,6 @@ export interface AppProps {
export type I18nProps = BareProps & WithTranslation;
export type ButtonRef = React.RefObject<React.Component<ButtonProps>>;
// export type FormProps$Ref = React.MutableRefObject<Button$OnClick>;
export interface FormProps {
onCancel: Button$OnClick;
onSubmit: Button$OnClick;
}
// export interface FormProps$Hooks {
// onInputEnterKey: () => void;
// onInputEscapeKey: () => void;
// }
// export interface FormProps extends FormProps$Refs, FormProps$Hooks {}
export type ConstructTxFn = () => any[];
export type TxTrigger = React.ComponentType<TxTriggerProps>;
@ -51,59 +36,39 @@ export interface TxTriggerProps {
onOpen: () => void;
}
export interface TxButtonInterface {
component?: {
current?: {
send: () => void;
};
};
}
export interface TxProps {
extrinsic?: IExtrinsic | SubmittableExtrinsic | null;
tx?: string;
params?: any[] | ConstructTxFn;
}
export interface TxButtonProps extends TxProps, ApiProps {
accountId?: string;
accountNonce?: Index;
export interface TxAccountProps {
className?: string;
icon: string;
iconSize?: Button$Sizes;
innerRef: ButtonRef;
isBasic?: boolean;
isDisabled?: boolean;
isNegative?: boolean;
isPrimary?: boolean;
isUnsigned?: boolean;
label: React.ReactNode;
onClick?: () => any;
onFailed?: TxFailedCallback;
onStart?: () => void;
onSuccess?: TxCallback;
onUpdate?: TxCallback;
tooltip?: string;
withSpinner?: boolean;
filter?: string[];
label?: React.ReactNode;
help?: React.ReactNode;
onChange: (value: string | null) => void;
}
export interface TxButtonNewProps extends TxProps {
accountId?: StringOrNull;
export interface TxButtonProps extends TxProps {
accountId?: AccountId | StringOrNull;
accountNonce?: Index;
className?: string;
icon: string;
icon?: string;
iconSize?: Button$Sizes;
isBasic?: boolean;
isDisabled?: boolean;
isNegative?: boolean;
isPrimary?: boolean;
isUnsigned?: boolean;
label: React.ReactNode;
onClick?: () => any;
label?: React.ReactNode;
onClick?: VoidFn;
onFailed?: TxFailedCallback;
onStart?: () => void;
onSendRef?: React.MutableRefObject<VoidFn | undefined>;
onStart?: VoidFn;
onSuccess?: TxCallback;
onUpdate?: TxCallback;
size?: string;
tooltip?: string;
withSpinner?: boolean;
}

View File

@ -8,7 +8,6 @@ export { default as useAddresses } from './useAddresses';
export { default as useApi } from './useApi';
export { default as useCacheKey } from './useCacheKey';
export { default as useCall } from './useCall';
export { default as useForm } from './useForm';
export { default as useDebounce } from './useDebounce';
export { default as useFavorites } from './useFavorites';
export { default as useIsMountedRef } from './useIsMountedRef';

View File

@ -1,24 +0,0 @@
// Copyright 2017-2020 @polkadot/react-hooks 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 { Button$OnClick } from '@polkadot/react-components/Button/types';
import { FormProps } from '@polkadot/react-components/types';
import { useRef } from 'react';
const EMPTY_CALLBACK = (): void => undefined;
export default function useForm (onSubmit: () => void, onCancel: () => void = EMPTY_CALLBACK): FormProps {
const onCancelRef = useRef<Button$OnClick>(onCancel);
const onSubmitRef = useRef<Button$OnClick>(onSubmit);
return {
onCancel: (): void => {
onCancelRef.current && onCancelRef.current();
},
onSubmit: (): void => {
onSubmitRef.current && onSubmitRef.current();
}
};
}