From 7283a040237609617cd308887459b8fb00895ecb Mon Sep 17 00:00:00 2001 From: meriadec Date: Thu, 15 Mar 2018 15:59:44 +0100 Subject: [PATCH] Refactor Send modal, integrate RequestAmount and RecipientAddress --- src/components/Breadcrumb/index.js | 21 +- src/components/RecipientAddress/index.js | 57 +++--- src/components/RequestAmount/index.js | 10 +- src/components/base/Input/index.js | 5 +- src/components/base/Label.js | 6 +- src/components/base/LabelInfoTooltip/index.js | 24 +++ src/components/base/Tooltip/index.js | 4 +- src/components/modals/Send.js | 179 ------------------ src/components/modals/Send/01-step-amount.js | 73 +++++++ .../modals/Send/02-step-connect-device.js | 7 + .../modals/Send/03-step-verification.js | 7 + .../modals/Send/04-step-confirmation.js | 7 + src/components/modals/Send/Footer.js | 52 +++++ src/components/modals/Send/index.js | 109 +++++++++++ src/icons/InfoCircle.js | 10 + static/i18n/en/send.yml | 22 ++- 16 files changed, 366 insertions(+), 227 deletions(-) create mode 100644 src/components/base/LabelInfoTooltip/index.js delete mode 100644 src/components/modals/Send.js create mode 100644 src/components/modals/Send/01-step-amount.js create mode 100644 src/components/modals/Send/02-step-connect-device.js create mode 100644 src/components/modals/Send/03-step-verification.js create mode 100644 src/components/modals/Send/04-step-confirmation.js create mode 100644 src/components/modals/Send/Footer.js create mode 100644 src/components/modals/Send/index.js create mode 100644 src/icons/InfoCircle.js diff --git a/src/components/Breadcrumb/index.js b/src/components/Breadcrumb/index.js index d91e6655..0f8fd615 100644 --- a/src/components/Breadcrumb/index.js +++ b/src/components/Breadcrumb/index.js @@ -25,13 +25,20 @@ class Breadcrumb extends PureComponent { render() { const { items, currentStep, ...props } = this.props return ( - - {items.map((item, i) => ( - - {item.label} - - ))} - + + + {items.map((item, i) => ( + + {item.label} + + ))} + + ) } } diff --git a/src/components/RecipientAddress/index.js b/src/components/RecipientAddress/index.js index d0d51f96..d2689914 100644 --- a/src/components/RecipientAddress/index.js +++ b/src/components/RecipientAddress/index.js @@ -1,31 +1,32 @@ // @flow -import React, { PureComponent, Fragment } from 'react' +import React, { PureComponent } from 'react' import styled from 'styled-components' import QrReader from 'react-qr-reader' import noop from 'lodash/noop' +import { radii } from 'styles/theme' + import Box from 'components/base/Box' import Input from 'components/base/Input' import IconQrCode from 'icons/QrCode' -const WrapperIcon = ({ onClick }: { onClick: Function }) => ( - - - -) - -const InputAddress = styled(Input).attrs({ - type: 'text', +const Right = styled(Box).attrs({ + bg: 'lightGrey', + px: 3, + align: 'center', + justify: 'center', })` - padding-right: ${p => p.withQrCode && '55px'}; + border-top-right-radius: ${radii[1]}px; + border-bottom-right-radius: ${radii[1]}px; + border-left: 1px solid ${p => p.theme.colors.fog}; ` const WrapperQrCode = styled(Box)` margin-top: 10px; position: absolute; - right: 15px; + right: 0; top: 100%; ` @@ -65,21 +66,25 @@ class RecipientAddress extends PureComponent { return ( - - {withQrCode && ( - - - {qrReaderOpened && ( - - - - )} - - )} + + + {qrReaderOpened && ( + + + + )} + + } + /> ) } diff --git a/src/components/RequestAmount/index.js b/src/components/RequestAmount/index.js index af83c1fe..2e873df0 100644 --- a/src/components/RequestAmount/index.js +++ b/src/components/RequestAmount/index.js @@ -112,11 +112,13 @@ type Props = { value: Object, } +export type DoubleVal = { + left: number, + right: number, +} + type State = { - max: { - left: number, - right: number, - }, + max: DoubleVal, value: { left: string | number, right: string | number, diff --git a/src/components/base/Input/index.js b/src/components/base/Input/index.js index a759f5e1..3cf31bb9 100644 --- a/src/components/base/Input/index.js +++ b/src/components/base/Input/index.js @@ -45,6 +45,7 @@ type Props = { onFocus: Function, renderLeft?: any, renderRight?: any, + containerProps?: Object, } type State = { @@ -93,10 +94,10 @@ class Input extends PureComponent { render() { const { isFocus } = this.state - const { renderLeft, renderRight } = this.props + const { renderLeft, renderRight, containerProps } = this.props return ( - + {renderLeft} + text} style={{ height: 12 }}> + + + + ) +} + +export default LabelInfoTooltip diff --git a/src/components/base/Tooltip/index.js b/src/components/base/Tooltip/index.js index eac95f5f..277224db 100644 --- a/src/components/base/Tooltip/index.js +++ b/src/components/base/Tooltip/index.js @@ -86,10 +86,10 @@ class Tooltip extends PureComponent { _template = undefined render() { - const { children, render } = this.props + const { children, render, ...props } = this.props return ( - (this._node = n)}> + (this._node = n)} {...props}> diff --git a/src/components/modals/Send.js b/src/components/modals/Send.js deleted file mode 100644 index 7ed12705..00000000 --- a/src/components/modals/Send.js +++ /dev/null @@ -1,179 +0,0 @@ -// @flow - -import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' -import get from 'lodash/get' -import { getDefaultUnitByCoinType } from '@ledgerhq/currencies' - -import type { T } from 'types/common' - -import { MODAL_SEND } from 'constants' - -import Box from 'components/base/Box' -import Button from 'components/base/Button' -import Input from 'components/base/Input' -import Label from 'components/base/Label' -import Modal, { ModalBody, ModalTitle, ModalFooter, ModalContent } from 'components/base/Modal' -import Breadcrumb from 'components/Breadcrumb' -import RecipientAddress from 'components/RecipientAddress' -import SelectAccount from 'components/SelectAccount' -import FormattedVal from 'components/base/FormattedVal' - -const Steps = { - '1': ({ t, ...props }: Object) => ( -
) => { - e.preventDefault() - - if (props.canSubmit) { - props.onChangeStep('2') - } - }} - > - - - - - - - - - - - - - - -
- ), - '2': (props: Object) => ( -
-
summary
-
{props.value.amount}
-
to {props.value.address}
-
from {props.value.account.name}
-
- ), -} - -type InputValue = { - account: any, - address: string, - amount: string, -} - -type Step = '1' | '2' - -type State = { - inputValue: InputValue, - step: Step, -} - -type Props = { - t: T, -} - -const defaultState = { - inputValue: { - account: null, - address: '', - amount: '', - }, - step: '1', -} - -class Send extends PureComponent { - state = { - ...defaultState, - } - - getStepProps(data: any) { - const { inputValue, step } = this.state - const { t } = this.props - - const props = (predicate, props, defaults = {}) => (predicate ? props : defaults) - - const account = inputValue.account || get(data, 'account') - - return { - ...props(step === '1', { - canSubmit: account && inputValue.address.trim() !== '' && inputValue.amount.trim() !== '', - onChangeInput: this.handleChangeInput, - value: { - ...inputValue, - account, - }, - }), - ...props(step === '2', { - value: { - ...inputValue, - account, - }, - }), - onChangeStep: this.handleChangeStep, - t, - } - } - - handleChangeInput = (key: $Keys) => (value: $Values) => - this.setState(prev => ({ - inputValue: { - ...prev.inputValue, - [key]: value, - }, - })) - - handleChangeStep = (step: Step) => - this.setState({ - step, - }) - - handleHide = () => - this.setState({ - ...defaultState, - }) - - _steps = [ - 'sendModal:Amount', - 'sendModal:Summary', - 'sendModal:SecureValidation', - 'sendModal:Confirmation', - ].map(v => ({ label: this.props.t(v) })) - - render() { - const { step } = this.state - const { t } = this.props - const Step = Steps[step] - return ( - ( - - {t('send:title')} - - - - - - - - - - - - - - - )} - /> - ) - } -} - -export default translate()(Send) diff --git a/src/components/modals/Send/01-step-amount.js b/src/components/modals/Send/01-step-amount.js new file mode 100644 index 00000000..0ce36919 --- /dev/null +++ b/src/components/modals/Send/01-step-amount.js @@ -0,0 +1,73 @@ +// @flow + +import React, { Fragment } from 'react' + +import type { Account, T } from 'types/common' +import type { DoubleVal } from 'components/RequestAmount' + +import Box from 'components/base/Box' +import SelectAccount from 'components/SelectAccount' +import Label from 'components/base/Label' +import LabelInfoTooltip from 'components/base/LabelInfoTooltip' +import RecipientAddress from 'components/RecipientAddress' +import RequestAmount from 'components/RequestAmount' +import Select from 'components/base/Select' +import Input from 'components/base/Input' + +type Props = { + account: Account | null, + onChange: Function, + recipientAddress: string, + amount: DoubleVal, + t: T, +} + +function StepAmount(props: Props) { + const { onChange, account, recipientAddress, t, amount } = props + + return ( + + + + + + + + + + {account && ( + + + + + + + + + + + + + )} + + ) +} + +export default StepAmount diff --git a/src/components/modals/Send/02-step-connect-device.js b/src/components/modals/Send/02-step-connect-device.js new file mode 100644 index 00000000..ba744f9c --- /dev/null +++ b/src/components/modals/Send/02-step-connect-device.js @@ -0,0 +1,7 @@ +import React from 'react' + +function StepConnectDevice() { + return
step connect device
+} + +export default StepConnectDevice diff --git a/src/components/modals/Send/03-step-verification.js b/src/components/modals/Send/03-step-verification.js new file mode 100644 index 00000000..cb8ea748 --- /dev/null +++ b/src/components/modals/Send/03-step-verification.js @@ -0,0 +1,7 @@ +import React from 'react' + +function StepVerification() { + return
step verification
+} + +export default StepVerification diff --git a/src/components/modals/Send/04-step-confirmation.js b/src/components/modals/Send/04-step-confirmation.js new file mode 100644 index 00000000..95d4bc2b --- /dev/null +++ b/src/components/modals/Send/04-step-confirmation.js @@ -0,0 +1,7 @@ +import React from 'react' + +function StepConfirmation() { + return
step confirmation
+} + +export default StepConfirmation diff --git a/src/components/modals/Send/Footer.js b/src/components/modals/Send/Footer.js new file mode 100644 index 00000000..ae910023 --- /dev/null +++ b/src/components/modals/Send/Footer.js @@ -0,0 +1,52 @@ +// @flow + +import React from 'react' + +import type { T, Account } from 'types/common' +import type { DoubleVal } from 'components/RequestAmount' + +import { ModalFooter } from 'components/base/Modal' +import Box from 'components/base/Box' +import Label from 'components/base/Label' +import FormattedVal from 'components/base/FormattedVal' +import Button from 'components/base/Button' +import Text from 'components/base/Text' + +type Props = { + t: T, + account: Account, + amount: DoubleVal, + onNext: Function, +} + +function Footer({ account, amount, t, onNext }: Props) { + return ( + + + + + + + + {'('} + + + + {')'} + + + + + + + ) +} + +export default Footer diff --git a/src/components/modals/Send/index.js b/src/components/modals/Send/index.js new file mode 100644 index 00000000..098db49e --- /dev/null +++ b/src/components/modals/Send/index.js @@ -0,0 +1,109 @@ +// @flow + +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' +import get from 'lodash/get' + +import type { T, Account } from 'types/common' +import type { DoubleVal } from 'components/RequestAmount' + +import { MODAL_SEND } from 'constants' + +import Breadcrumb from 'components/Breadcrumb' +import Modal, { ModalBody, ModalTitle, ModalContent } from 'components/base/Modal' + +import Footer from './Footer' + +import StepAmount from './01-step-amount' +import StepConnectDevice from './02-step-connect-device' +import StepVerification from './03-step-verification' +import StepConfirmation from './04-step-confirmation' + +type Props = { + t: T, +} + +type State = { + stepIndex: number, + amount: DoubleVal, + account: Account | null, + recipientAddress: string, + fees: number, +} + +const GET_STEPS = t => [ + { label: t('send:steps.amount.title'), Comp: StepAmount }, + { label: t('send:steps.connectDevice.title'), Comp: StepConnectDevice }, + { label: t('send:steps.verification.title'), Comp: StepVerification }, + { label: t('send:steps.confirmation.title'), Comp: StepConfirmation }, +] + +const INITIAL_STATE = { + stepIndex: 0, + account: null, + recipientAddress: '', + amount: { + left: 0, + right: 0, + }, + fees: 0, +} + +class SendModal extends PureComponent { + state = INITIAL_STATE + + _steps = GET_STEPS(this.props.t) + + handleReset = () => this.setState(INITIAL_STATE) + + handleNextStep = () => { + const { stepIndex } = this.state + if (stepIndex >= this._steps.length - 1) { + return + } + this.setState({ stepIndex: stepIndex + 1 }) + } + + createChangeHandler = key => value => this.setState({ [key]: value }) + + renderStep = acc => { + const { stepIndex, account } = this.state + const step = this._steps[stepIndex] + if (!step) { + return null + } + const { Comp } = step + const stepProps = { + ...this.state, + account: account || acc, + } + return + } + + render() { + const { t } = this.props + const { stepIndex, amount, account } = this.state + + return ( + { + const acc = account || get(data, 'account', null) + return ( + + {t('send:title')} + + + {this.renderStep(acc)} + + {acc &&