ghost-portal/packages/react-components/src/TxButton.tsx
Marcin Żółkiewski be7e293d28
Expose signed transactions (#2203)
* sign offline WIP

* signing transactions from extrinsics screen

* signing tx from accounts screen

* added translations

* removed unnecessary value

* removed console logs

* removed unused import

* used new signAsync method

* fixed types

* removed unused imports

* added missing translations

* code review changes

* fixed signing with local account

* added sign toggle

* improvements for QR
2020-01-31 16:13:56 +01:00

143 lines
3.7 KiB
TypeScript

// Copyright 2017-2020 @polkadot/app-123code 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 { SubmittableExtrinsic } from '@polkadot/api/promise/types';
import { QueueTx, QueueTxExtrinsicAdd } from './Status/types';
import { TxButtonProps as Props } from './types';
import React from 'react';
import { SubmittableResult } from '@polkadot/api';
import { withApi } from '@polkadot/react-api/hoc';
import { assert, isFunction, isUndefined } from '@polkadot/util';
import Button from './Button';
import { QueueConsumer } from './Status/Context';
interface InjectedProps {
queueExtrinsic: QueueTxExtrinsicAdd;
txqueue: QueueTx[];
}
type InnerProps = Props & InjectedProps;
interface State {
extrinsic?: SubmittableExtrinsic;
isSending: boolean;
}
class TxButtonInner extends React.PureComponent<InnerProps> {
public state: State = {
isSending: false
};
public render (): React.ReactNode {
const { accountId, className, icon, iconSize, innerRef, isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, tooltip } = this.props;
const { isSending } = this.state;
const needsAccount = isUnsigned
? false
: !accountId;
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;
let extrinsic: any;
if (propsExtrinsic) {
extrinsic = propsExtrinsic;
} else {
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
));
}
assert(extrinsic, 'Expected generated extrinsic passed to TxButton');
if (withSpinner) {
this.setState({ isSending: true });
}
queueExtrinsic({
accountId,
extrinsic,
isUnsigned,
txFailedCb: withSpinner ? this.onFailed : onFailed,
txStartCb: onStart,
txSuccessCb: withSpinner ? this.onSuccess : onSuccess,
txUpdateCb: onUpdate
});
onClick && onClick();
}
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);
}
}
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);