From fc59f538694fb6c96a4e00eb926fe28a95af99ea Mon Sep 17 00:00:00 2001 From: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> Date: Fri, 24 May 2019 13:03:54 +0200 Subject: [PATCH] Send button on account (#1193) * starting point * show all accounts * edit and save a name but remains ugly * actually don't use deriveStateFromProps * fix AdressRow * indentation * upperCase * bring back the index * trim input * change edition l&f * lint * cater for small screens * address comments * lint and alphabetical order * allow viewing and editing tags * better UX when tag editing and styling for no tags * nonce refactoring and show balances * crypto type * styling balances * use css grid * fix address row and creator * with buttons * button styling * locked tooltip * edit button always visible * init * fix conflicts * transfer functionnality * styling the modal * clean up * clean up bis * Transfer dialog enhancements (#1196) * Button/TxButton submit on enter (#1170) * Button/TxButton submit on enter * promise linting * testing ref approach * Add TxComponent to handle submit on enter * remove accountNonce * remove input ref * remove TxButton constructor * remove comment * empty constructor * linting * bug with null ref * linting * [CI Skip] 0.33.0-beta.74 * Redirect correctly when user has no account (#1191) * right link and hide tabs plus buttons primary * fix comments * create highlight * [CI Skip] 0.33.0-beta.75 * Mark ExtrinsicFailed as error (#1190) * Hide edit on injected accounts, Button w/ tooltip (#1192) * Hide edit on injected accounts, Button w/ tooltip * Don't display "add tags" when not isEditable * Indentation * [CI Skip] 0.33.0-beta.76 * Make enable() call to extensions (#1194) * Make enable() call to extensions * It works * Add overlay for injected (prompt) * Use signer from injectedPromise * [CI Skip] 0.33.0-beta.77 * withInjected -> PureComponent (fix new refs) (#1195) * withInjected -> PureComponent (fix new refs) * Consume data from context * Expand injected * Close modal on tx start * align fees * remove blank lines --- packages/app-accounts/src/Account.tsx | 79 ++++-- packages/app-accounts/src/modals/Transfer.tsx | 247 ++++++++++++++++++ packages/ui-app/src/Status/Queue.tsx | 3 +- packages/ui-app/src/Status/types.ts | 2 + packages/ui-app/src/TxButton.tsx | 15 +- packages/ui-app/src/styles/components.css | 1 - packages/ui-signer/src/Modal.tsx | 6 +- 7 files changed, 320 insertions(+), 33 deletions(-) create mode 100644 packages/app-accounts/src/modals/Transfer.tsx diff --git a/packages/app-accounts/src/Account.tsx b/packages/app-accounts/src/Account.tsx index 8529f9cd8d..ba23adc935 100644 --- a/packages/app-accounts/src/Account.tsx +++ b/packages/app-accounts/src/Account.tsx @@ -7,12 +7,14 @@ import { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; import styled from 'styled-components'; -import { AddressSummary, Available, Balance, Bonded, Button, CryptoType, Nonce, Unlocking } from '@polkadot/ui-app'; +import { AddressSummary, Available, Balance, Bonded, Button, CryptoType, Icon, Nonce, Unlocking } from '@polkadot/ui-app'; import keyring from '@polkadot/ui-keyring'; import Backup from './modals/Backup'; import ChangePass from './modals/ChangePass'; import Forgetting from './modals/Forgetting'; +import Transfer from './modals/Transfer'; + import translate from './translate'; type Props = I18nProps & { @@ -23,7 +25,8 @@ type State = { isBackupOpen: boolean, isEditable: boolean, isForgetOpen: boolean, - isPasswordOpen: boolean + isPasswordOpen: boolean, + isTransferOpen: boolean }; const Wrapper = styled.article` @@ -111,7 +114,8 @@ class Account extends React.PureComponent { isBackupOpen: false, isEditable: !(keyring.getAccount(props.address).getMeta().isInjected), isForgetOpen: false, - isPasswordOpen: false + isPasswordOpen: false, + isTransferOpen: false }; } @@ -187,7 +191,7 @@ class Account extends React.PureComponent { private renderModals () { const { address } = this.props; - const { isBackupOpen, isForgetOpen, isPasswordOpen } = this.state; + const { isBackupOpen, isForgetOpen, isPasswordOpen, isTransferOpen } = this.state; if (!address) { return null; @@ -226,6 +230,16 @@ class Account extends React.PureComponent { ); } + if (isTransferOpen) { + modals.push( + + ); + } + return modals; } @@ -253,6 +267,14 @@ class Account extends React.PureComponent { }); } + private toggleTransfer = (): void => { + const { isTransferOpen } = this.state; + + this.setState({ + isTransferOpen: !isTransferOpen + }); + } + private onForget = (): void => { const { address, t } = this.props; @@ -314,32 +336,39 @@ class Account extends React.PureComponent { const { t } = this.props; const { isEditable } = this.state; - if (!isEditable) { - return null; - } - return (
+ {isEditable && ( + <> +
); diff --git a/packages/app-accounts/src/modals/Transfer.tsx b/packages/app-accounts/src/modals/Transfer.tsx new file mode 100644 index 0000000000..58fb1c895e --- /dev/null +++ b/packages/app-accounts/src/modals/Transfer.tsx @@ -0,0 +1,247 @@ +// Copyright 2017-2019 @polkadot/app-accounts 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 { ApiProps } from '@polkadot/ui-api/types'; +import { DerivedFees, DerivedBalances } from '@polkadot/api-derive/types'; +import { I18nProps } from '@polkadot/ui-app/types'; +import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; + +import BN from 'bn.js'; +import React from 'react'; +import styled from 'styled-components'; +import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/ui-app'; +import Checks, { calcSignatureLength } from '@polkadot/ui-signer/Checks'; +import { withApi, withCalls, withMulti } from '@polkadot/ui-api'; +import { ZERO_FEES } from '@polkadot/ui-signer/Checks/constants'; + +import translate from '../translate'; + +type Props = ApiProps & I18nProps & { + address: string, + balances_fees?: DerivedFees, + balances_votingBalance?: DerivedBalances, + onClose: () => void, + system_accountNonce?: BN +}; + +type State = { + amount: BN, + extrinsic: SubmittableExtrinsic | null, + hasAvailable: boolean, + maxBalance?: BN, + recipientId: string | null +}; + +const ZERO = new BN(0); + +const Wrapper = styled.div` + article.padded { + box-shadow: none; + margin: .75rem 15rem; + padding: 0; + } + + label.with-help { + flex-basis: 10rem; + } + + .ui--Labelled-content { + flex: initial; + width: 40em; + } +`; + +class Transfer extends React.PureComponent { + state: State = { + amount: ZERO, + extrinsic: null, + hasAvailable: true, + maxBalance: ZERO, + recipientId: null + }; + + componentDidUpdate (prevProps: Props, prevState: State) { + const { balances_fees } = this.props; + const { extrinsic, recipientId } = this.state; + + const hasLengthChanged = ((extrinsic && extrinsic.encodedLength) || 0) !== ((prevState.extrinsic && prevState.extrinsic.encodedLength) || 0); + + if ((recipientId && prevState.recipientId !== recipientId) || + (balances_fees !== prevProps.balances_fees) || + hasLengthChanged + ) { + this.setMaxBalance(); + } + } + + render () { + return ( + + {this.renderContent()} + {this.renderButtons()} + + ); + } + + private nextState (newState: Partial): void { + this.setState((prevState: State): State => { + const { api } = this.props; + const { amount = prevState.amount, recipientId = prevState.recipientId, hasAvailable = prevState.hasAvailable, maxBalance = prevState.maxBalance } = newState; + const extrinsic = recipientId + ? api.tx.balances.transfer(recipientId, amount) + : null; + + return { + amount, + extrinsic, + hasAvailable, + maxBalance, + recipientId + }; + }); + } + + private renderButtons () { + const { address, onClose, t } = this.props; + const { extrinsic, hasAvailable } = this.state; + + return ( + + +