Some more additional func conversions (#1692)
* Some more additional func conversions * Create Address functional * Minor cleanups * Adapt ExtrinsicDisplay * Linting updates
This commit is contained in:
parent
aabe4b084e
commit
7415befba2
@ -3,63 +3,45 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { Button, InputAddress, InputBalance, TxButton, TxComponent } from '@polkadot/react-components';
|
||||
import React, { useState } from 'react';
|
||||
import { Button, InputAddress, InputBalance, TxButton } from '@polkadot/react-components';
|
||||
|
||||
import Summary from './Summary';
|
||||
|
||||
interface Props {
|
||||
accountId?: string | null;
|
||||
}
|
||||
interface State {
|
||||
amount?: BN;
|
||||
recipientId?: string | null;
|
||||
}
|
||||
|
||||
export default class Transfer extends TxComponent<Props, State> {
|
||||
public state: State = {};
|
||||
export default function Transfer ({ accountId }: Props): React.ReactElement<Props> {
|
||||
const [amount, setAmount] = useState<BN | undefined | null>(null);
|
||||
const [recipientId, setRecipientId] = useState<string | null>(null);
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { accountId } = this.props;
|
||||
const { amount, recipientId } = this.state;
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>transfer</h1>
|
||||
<div className='ui--row'>
|
||||
<div className='large'>
|
||||
<InputAddress
|
||||
label='recipient address for this transfer'
|
||||
onChange={this.onChangeRecipient}
|
||||
type='all'
|
||||
return (
|
||||
<section>
|
||||
<h1>transfer</h1>
|
||||
<div className='ui--row'>
|
||||
<div className='large'>
|
||||
<InputAddress
|
||||
label='recipient address for this transfer'
|
||||
onChange={setRecipientId}
|
||||
type='all'
|
||||
/>
|
||||
<InputBalance
|
||||
label='amount to transfer'
|
||||
onChange={setAmount}
|
||||
/>
|
||||
<Button.Group>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='send'
|
||||
label='make transfer'
|
||||
params={[recipientId, amount]}
|
||||
tx='balances.transfer'
|
||||
/>
|
||||
<InputBalance
|
||||
label='amount to transfer'
|
||||
onChange={this.onChangeAmount}
|
||||
onEnter={this.sendTx}
|
||||
/>
|
||||
<Button.Group>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='send'
|
||||
label='make transfer'
|
||||
params={[recipientId, amount]}
|
||||
tx='balances.transfer'
|
||||
ref={this.button}
|
||||
/>
|
||||
</Button.Group>
|
||||
</div>
|
||||
<Summary className='small'>Make a transfer from any account you control to another account. Transfer fees and per-transaction fees apply and will be calculated upon submission.</Summary>
|
||||
</Button.Group>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
private onChangeAmount = (amount?: BN): void => {
|
||||
this.setState({ amount });
|
||||
}
|
||||
|
||||
private onChangeRecipient = (recipientId?: string | null): void => {
|
||||
this.setState({ recipientId });
|
||||
}
|
||||
<Summary className='small'>Make a transfer from any account you control to another account. Transfer fees and per-transaction fees apply and will be calculated upon submission.</Summary>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ActionStatus } from '@polkadot/react-components/Status/types';
|
||||
import { ModalProps } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { AddressRow, Button, Input, InputAddress, Modal } from '@polkadot/react-components';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
@ -15,149 +15,50 @@ import translate from '../translate';
|
||||
|
||||
interface Props extends ModalProps, I18nProps {}
|
||||
|
||||
interface State {
|
||||
address: string;
|
||||
isAddressExisting: boolean;
|
||||
isAddressValid: boolean;
|
||||
isNameValid: boolean;
|
||||
isValid: boolean;
|
||||
name: string;
|
||||
tags: string[];
|
||||
}
|
||||
function Create ({ onClose, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
const [{ isNameValid, name }, setName] = useState<{ isNameValid: boolean; name: string }>({ isNameValid: true, name: 'new address' });
|
||||
const [{ address, isAddressExisting, isAddressValid }, setAddress] = useState<{ address: string; isAddressExisting: boolean; isAddressValid: boolean }>({ address: '', isAddressExisting: false, isAddressValid: false });
|
||||
const isValid = isAddressValid && isNameValid;
|
||||
|
||||
class Create extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
address: '',
|
||||
isAddressExisting: false,
|
||||
isAddressValid: false,
|
||||
isNameValid: true,
|
||||
isValid: false,
|
||||
name: 'new address',
|
||||
tags: []
|
||||
};
|
||||
const _onChangeAddress = (input: string): void => {
|
||||
let address = '';
|
||||
let isAddressValid = true;
|
||||
let isAddressExisting = false;
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { t } = this.props;
|
||||
const { address, isAddressValid, isNameValid, isValid, name } = this.state;
|
||||
try {
|
||||
address = keyring.encodeAddress(
|
||||
keyring.decodeAddress(input)
|
||||
);
|
||||
isAddressValid = keyring.isAvailable(address);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
dimmer='inverted'
|
||||
open
|
||||
>
|
||||
<Modal.Header>{t('Add an address')}</Modal.Header>
|
||||
<Modal.Content>
|
||||
<AddressRow
|
||||
defaultName={name}
|
||||
value={address}
|
||||
>
|
||||
<Input
|
||||
autoFocus
|
||||
className='full'
|
||||
help={t('Paste here the address of the contact you want to add to your address book.')}
|
||||
isError={!isAddressValid}
|
||||
label={t('address')}
|
||||
onChange={this.onChangeAddress}
|
||||
onEnter={this.onCommit}
|
||||
value={address}
|
||||
/>
|
||||
<Input
|
||||
className='full'
|
||||
help={t('Type the name of your contact. This name will be used across all the apps. It can be edited later on.')}
|
||||
isError={!isNameValid}
|
||||
label={t('name')}
|
||||
onChange={this.onChangeName}
|
||||
onEnter={this.onCommit}
|
||||
value={name}
|
||||
/>
|
||||
</AddressRow>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='cancel'
|
||||
isNegative
|
||||
onClick={this.onDiscard}
|
||||
label={t('Cancel')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
icon='save'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={this.onCommit}
|
||||
label={t('Save')}
|
||||
/>
|
||||
</Button.Group>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
if (!isAddressValid) {
|
||||
const old = keyring.getAddress(address);
|
||||
|
||||
private nextState (newState: Partial<State>, allowEdit = false): void {
|
||||
this.setState(
|
||||
(prevState: State): State => {
|
||||
let { address = prevState.address, name = prevState.name, tags = prevState.tags } = newState;
|
||||
let isAddressValid = true;
|
||||
let isAddressExisting = false;
|
||||
let newAddress = address;
|
||||
if (old) {
|
||||
const newName = old.meta.name || name;
|
||||
|
||||
try {
|
||||
newAddress = keyring.encodeAddress(
|
||||
keyring.decodeAddress(address)
|
||||
);
|
||||
isAddressValid = keyring.isAvailable(newAddress);
|
||||
isAddressExisting = true;
|
||||
isAddressValid = true;
|
||||
|
||||
if (!isAddressValid) {
|
||||
const old = keyring.getAddress(newAddress);
|
||||
|
||||
if (old) {
|
||||
if (!allowEdit) {
|
||||
name = old.meta.name || name;
|
||||
}
|
||||
|
||||
isAddressExisting = true;
|
||||
isAddressValid = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
isAddressValid = false;
|
||||
setName({ isNameValid: !!newName, name: newName });
|
||||
}
|
||||
|
||||
const isNameValid = !!name;
|
||||
|
||||
return {
|
||||
address: newAddress,
|
||||
isAddressExisting,
|
||||
isAddressValid,
|
||||
isNameValid,
|
||||
isValid: isAddressValid && isNameValid,
|
||||
name,
|
||||
tags
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
isAddressValid = false;
|
||||
}
|
||||
|
||||
private onChangeAddress = (address: string): void => {
|
||||
this.nextState({ address });
|
||||
}
|
||||
|
||||
private onChangeName = (name: string): void => {
|
||||
this.nextState({ name }, true);
|
||||
}
|
||||
|
||||
private onCommit = (): void => {
|
||||
const { onClose, onStatusChange, t } = this.props;
|
||||
const { address, isAddressExisting, isValid, name, tags } = this.state;
|
||||
const status: Partial<ActionStatus> = { action: 'create' };
|
||||
setAddress({ address: address || input, isAddressExisting, isAddressValid });
|
||||
};
|
||||
const _onChangeName = (name: string): void => setName({ isNameValid: !!name, name });
|
||||
const _onCommit = (): void => {
|
||||
const status = { action: 'create' } as ActionStatus;
|
||||
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
keyring.saveAddress(address, { name, genesisHash: keyring.genesisHash, tags });
|
||||
keyring.saveAddress(address, { name, genesisHash: keyring.genesisHash, tags: [] });
|
||||
|
||||
status.account = address;
|
||||
status.status = address ? 'success' : 'error';
|
||||
@ -171,15 +72,62 @@ class Create extends React.PureComponent<Props, State> {
|
||||
status.message = error.message;
|
||||
}
|
||||
|
||||
onStatusChange(status as ActionStatus);
|
||||
onStatusChange(status);
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
private onDiscard = (): void => {
|
||||
const { onClose } = this.props;
|
||||
|
||||
onClose();
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
dimmer='inverted'
|
||||
open
|
||||
>
|
||||
<Modal.Header>{t('Add an address')}</Modal.Header>
|
||||
<Modal.Content>
|
||||
<AddressRow
|
||||
defaultName={name}
|
||||
value={address}
|
||||
>
|
||||
<Input
|
||||
autoFocus
|
||||
className='full'
|
||||
help={t('Paste here the address of the contact you want to add to your address book.')}
|
||||
isError={!isAddressValid}
|
||||
label={t('address')}
|
||||
onChange={_onChangeAddress}
|
||||
onEnter={_onCommit}
|
||||
value={address}
|
||||
/>
|
||||
<Input
|
||||
className='full'
|
||||
help={t('Type the name of your contact. This name will be used across all the apps. It can be edited later on.')}
|
||||
isError={!isNameValid}
|
||||
label={t('name')}
|
||||
onChange={_onChangeName}
|
||||
onEnter={_onCommit}
|
||||
value={name}
|
||||
/>
|
||||
</AddressRow>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='cancel'
|
||||
isNegative
|
||||
onClick={onClose}
|
||||
label={t('Cancel')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
icon='save'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={_onCommit}
|
||||
label={t('Save')}
|
||||
/>
|
||||
</Button.Group>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(Create);
|
||||
|
||||
@ -124,7 +124,7 @@ class Propose extends TxModal<Props, State> {
|
||||
this.setState({ threshold });
|
||||
}
|
||||
|
||||
private onChangeExtrinsic = (method: Call): void => {
|
||||
private onChangeExtrinsic = (method?: Call): void => {
|
||||
if (!method) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ class Propose extends TxComponent<Props, State> {
|
||||
this.nextState({ accountId });
|
||||
}
|
||||
|
||||
private onChangeExtrinsic = (method: Call): void => {
|
||||
private onChangeExtrinsic = (method?: Call): void => {
|
||||
if (!method) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ class Propose extends TxComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private onChangeExtrinsic = (method: Call): void => {
|
||||
private onChangeExtrinsic = (method?: Call): void => {
|
||||
if (!method) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2,125 +2,89 @@
|
||||
// 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 '@polkadot/react-components/types';
|
||||
import { RawParam } from '@polkadot/react-params/types';
|
||||
import { Call } from '@polkadot/types/interfaces';
|
||||
import { CallFunction, TypeDef } from '@polkadot/types/types';
|
||||
import { BareProps } from '@polkadot/react-components/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { RawParam } from '@polkadot/react-params/types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { GenericCall, getTypeDef } from '@polkadot/types';
|
||||
|
||||
import { InputExtrinsic } from '@polkadot/react-components';
|
||||
import Params from '@polkadot/react-params';
|
||||
import { withApi } from '@polkadot/react-api';
|
||||
import { isUndefined } from '@polkadot/util';
|
||||
|
||||
import paramComponents from './Params';
|
||||
|
||||
interface Props extends BareProps, ApiProps {
|
||||
interface Props extends BareProps {
|
||||
defaultValue: CallFunction;
|
||||
isDisabled?: boolean;
|
||||
isError?: boolean;
|
||||
isPrivate?: boolean;
|
||||
label?: React.ReactNode;
|
||||
onChange: (method?: Call) => void;
|
||||
onEnter: () => void;
|
||||
onEnter?: () => void;
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
methodfn: CallFunction;
|
||||
params: { name: string; type: TypeDef }[];
|
||||
values: RawParam[];
|
||||
function getParams ({ meta }: CallFunction): { name: string; type: TypeDef }[] {
|
||||
return GenericCall.filterOrigin(meta).map((arg): { name: string; type: TypeDef } => ({
|
||||
name: arg.name.toString(),
|
||||
type: getTypeDef(arg.type.toString())
|
||||
}));
|
||||
}
|
||||
|
||||
class ExtrinsicDisplay extends React.PureComponent<Props, State> {
|
||||
public state: State;
|
||||
export default function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label, onChange, onEnter, withLabel }: Props): React.ReactElement<Props> {
|
||||
const [extrinsic, setCall] = useState<{ fn: CallFunction; params: { name: string; type: TypeDef }[] }>({ fn: defaultValue, params: getParams(defaultValue) });
|
||||
const [values, setValues] = useState<RawParam[]>([]);
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
useEffect((): void => {
|
||||
setValues([]);
|
||||
}, [extrinsic]);
|
||||
|
||||
this.state = {
|
||||
methodfn: props.defaultValue,
|
||||
params: this.getParams(props.defaultValue),
|
||||
values: []
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { defaultValue, isDisabled, isError, isPrivate, label, onEnter, withLabel } = this.props;
|
||||
const { methodfn: { method, section, meta }, params } = this.state;
|
||||
|
||||
return (
|
||||
<div className='extrinsics--Extrinsic'>
|
||||
<InputExtrinsic
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
isPrivate={isPrivate}
|
||||
label={label}
|
||||
onChange={this.onChangeMethod}
|
||||
withLabel={withLabel}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
<Params
|
||||
key={`${section}.${method}:params` /* force re-render on change */}
|
||||
onChange={this.onChangeValues}
|
||||
onEnter={onEnter}
|
||||
overrides={paramComponents}
|
||||
params={params}
|
||||
/>
|
||||
</div>
|
||||
useEffect((): void => {
|
||||
const isValid = values.reduce((isValid, value): boolean =>
|
||||
isValid &&
|
||||
!isUndefined(value) &&
|
||||
!isUndefined(value.value) &&
|
||||
value.isValid, extrinsic.params.length === values.length
|
||||
);
|
||||
}
|
||||
|
||||
private nextState (newState: Pick< State, never>): void {
|
||||
this.setState(newState, (): void => {
|
||||
const { onChange } = this.props;
|
||||
const { methodfn, params, values } = this.state;
|
||||
let method;
|
||||
|
||||
const isValid = values.reduce((isValid, value): boolean =>
|
||||
isValid &&
|
||||
!isUndefined(value) &&
|
||||
!isUndefined(value.value) &&
|
||||
value.isValid, params.length === values.length
|
||||
);
|
||||
|
||||
let method;
|
||||
|
||||
if (isValid) {
|
||||
try {
|
||||
method = methodfn(
|
||||
...values.map(({ value }): any => value)
|
||||
);
|
||||
} catch (error) {
|
||||
// swallow
|
||||
}
|
||||
if (isValid) {
|
||||
try {
|
||||
method = extrinsic.fn(...values.map(({ value }): any => value));
|
||||
} catch (error) {
|
||||
// swallow
|
||||
}
|
||||
}
|
||||
|
||||
onChange(method);
|
||||
});
|
||||
}
|
||||
onChange(method);
|
||||
}, [extrinsic, values]);
|
||||
|
||||
private onChangeMethod = (methodfn: CallFunction): void => {
|
||||
this.nextState({
|
||||
methodfn,
|
||||
params: this.getParams(methodfn),
|
||||
values: []
|
||||
});
|
||||
}
|
||||
const _onChangeMethod = (fn: CallFunction): void => setCall({ fn, params: getParams(fn) });
|
||||
|
||||
private onChangeValues = (values: RawParam[]): void => {
|
||||
this.nextState({ values });
|
||||
}
|
||||
const { fn: { meta, method, section }, params } = extrinsic;
|
||||
|
||||
private getParams (methodfn: CallFunction): { name: string; type: TypeDef }[] {
|
||||
return GenericCall.filterOrigin(methodfn.meta).map((arg): { name: string; type: TypeDef } => ({
|
||||
name: arg.name.toString(),
|
||||
type: getTypeDef(arg.type.toString())
|
||||
}));
|
||||
}
|
||||
return (
|
||||
<div className='extrinsics--Extrinsic'>
|
||||
<InputExtrinsic
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
isPrivate={isPrivate}
|
||||
label={label}
|
||||
onChange={_onChangeMethod}
|
||||
withLabel={withLabel}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
<Params
|
||||
key={`${section}.${method}:params` /* force re-render on change */}
|
||||
onChange={setValues}
|
||||
onEnter={onEnter}
|
||||
overrides={paramComponents}
|
||||
params={params}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withApi(ExtrinsicDisplay);
|
||||
|
||||
@ -22,8 +22,8 @@ interface Props extends BareProps {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
function onChange ({ onChange }: Props): (_: Call) => void {
|
||||
return function (method: Call): void {
|
||||
function onChange ({ onChange }: Props): (method?: Call) => void {
|
||||
return (method?: Call): void => {
|
||||
onChange && onChange({
|
||||
isValid: !!method,
|
||||
value: method
|
||||
|
||||
Loading…
Reference in New Issue
Block a user