meriadec
7 years ago
16 changed files with 366 additions and 227 deletions
@ -0,0 +1,24 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
|
|||
import Box from 'components/base/Box' |
|||
import Tooltip from 'components/base/Tooltip' |
|||
import IconInfoCircle from 'icons/InfoCircle' |
|||
|
|||
type Props = { |
|||
text: string, |
|||
} |
|||
|
|||
function LabelInfoTooltip(props: Props) { |
|||
const { text, ...p } = props |
|||
return ( |
|||
<Box {...p}> |
|||
<Tooltip render={() => text} style={{ height: 12 }}> |
|||
<IconInfoCircle width={12} height={12} /> |
|||
</Tooltip> |
|||
</Box> |
|||
) |
|||
} |
|||
|
|||
export default LabelInfoTooltip |
@ -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) => ( |
|||
<form |
|||
onSubmit={(e: SyntheticEvent<HTMLFormElement>) => { |
|||
e.preventDefault() |
|||
|
|||
if (props.canSubmit) { |
|||
props.onChangeStep('2') |
|||
} |
|||
}} |
|||
> |
|||
<Box flow={4}> |
|||
<Box flow={1}> |
|||
<Label>Account to debit</Label> |
|||
<SelectAccount onChange={props.onChangeInput('account')} value={props.value.account} /> |
|||
</Box> |
|||
<Box flow={1}> |
|||
<Label>Recipient address</Label> |
|||
<RecipientAddress onChange={props.onChangeInput('address')} value={props.value.address} /> |
|||
</Box> |
|||
<Box flow={1}> |
|||
<Label>Amount</Label> |
|||
<Input onChange={props.onChangeInput('amount')} value={props.value.amount} /> |
|||
</Box> |
|||
</Box> |
|||
</form> |
|||
), |
|||
'2': (props: Object) => ( |
|||
<div> |
|||
<div>summary</div> |
|||
<div>{props.value.amount}</div> |
|||
<div>to {props.value.address}</div> |
|||
<div>from {props.value.account.name}</div> |
|||
</div> |
|||
), |
|||
} |
|||
|
|||
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<Props, State> { |
|||
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<InputValue>) => (value: $Values<InputValue>) => |
|||
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 ( |
|||
<Modal |
|||
name={MODAL_SEND} |
|||
onHide={this.handleHide} |
|||
render={({ data, onClose }) => ( |
|||
<ModalBody onClose={onClose}> |
|||
<ModalTitle>{t('send:title')}</ModalTitle> |
|||
<ModalContent> |
|||
<Box mb={6} mt={2}> |
|||
<Breadcrumb currentStep={step} items={this._steps} /> |
|||
</Box> |
|||
<Step {...this.getStepProps(data)} /> |
|||
</ModalContent> |
|||
<ModalFooter horizontal align="center"> |
|||
<Box grow> |
|||
<Label>{'Total spent'}</Label> |
|||
<FormattedVal |
|||
color="dark" |
|||
val={15496420404} |
|||
unit={getDefaultUnitByCoinType(0)} |
|||
showCode |
|||
/> |
|||
</Box> |
|||
<Button primary>{'Next'}</Button> |
|||
</ModalFooter> |
|||
</ModalBody> |
|||
)} |
|||
/> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default translate()(Send) |
@ -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 ( |
|||
<Box flow={4}> |
|||
<Box flow={1}> |
|||
<Label>{t('send:steps.amount.selectAccountDebit')}</Label> |
|||
<SelectAccount onChange={onChange('account')} value={account} /> |
|||
</Box> |
|||
<Box flow={1}> |
|||
<Label> |
|||
<span>{t('send:steps.amount.recipientAddress')}</span> |
|||
<LabelInfoTooltip ml={1} text={t('send:steps.amount.recipientAddress')} /> |
|||
</Label> |
|||
<RecipientAddress |
|||
withQrCode |
|||
value={recipientAddress} |
|||
onChange={onChange('recipientAddress')} |
|||
/> |
|||
</Box> |
|||
{account && ( |
|||
<Fragment> |
|||
<Box flow={1}> |
|||
<Label>{t('send:steps.amount.amount')}</Label> |
|||
<RequestAmount account={account} onChange={onChange('amount')} value={amount} /> |
|||
</Box> |
|||
<Box flow={1}> |
|||
<Label> |
|||
<span>{t('send:steps.amount.fees')}</span> |
|||
<LabelInfoTooltip ml={1} text={t('send:steps.amount.fees')} /> |
|||
</Label> |
|||
<Box horizontal flow={5}> |
|||
<Select |
|||
placeholder="Choose a chess player..." |
|||
items={[{ key: 'custom', name: 'Custom' }]} |
|||
value={{ key: 'custom', name: 'Custom' }} |
|||
renderSelected={item => item.name} |
|||
onChange={onChange('fees')} |
|||
/> |
|||
<Input containerProps={{ grow: true }} /> |
|||
</Box> |
|||
</Box> |
|||
</Fragment> |
|||
)} |
|||
</Box> |
|||
) |
|||
} |
|||
|
|||
export default StepAmount |
@ -0,0 +1,7 @@ |
|||
import React from 'react' |
|||
|
|||
function StepConnectDevice() { |
|||
return <div>step connect device</div> |
|||
} |
|||
|
|||
export default StepConnectDevice |
@ -0,0 +1,7 @@ |
|||
import React from 'react' |
|||
|
|||
function StepVerification() { |
|||
return <div>step verification</div> |
|||
} |
|||
|
|||
export default StepVerification |
@ -0,0 +1,7 @@ |
|||
import React from 'react' |
|||
|
|||
function StepConfirmation() { |
|||
return <div>step confirmation</div> |
|||
} |
|||
|
|||
export default StepConfirmation |
@ -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 ( |
|||
<ModalFooter horizontal align="center"> |
|||
<Box grow> |
|||
<Label>{t('send:totalSpent')}</Label> |
|||
<Box horizontal flow={2} align="center"> |
|||
<FormattedVal |
|||
color="dark" |
|||
val={amount.left * 10 ** account.unit.magnitude} |
|||
unit={account.unit} |
|||
showCode |
|||
/> |
|||
<Box horizontal align="center"> |
|||
<Text ff="Rubik" fontSize={3}> |
|||
{'('} |
|||
</Text> |
|||
<FormattedVal color="grey" fontSize={3} val={amount.right} fiat="USD" showCode /> |
|||
<Text ff="Rubik" fontSize={3}> |
|||
{')'} |
|||
</Text> |
|||
</Box> |
|||
</Box> |
|||
</Box> |
|||
<Button primary onClick={onNext}> |
|||
{'Next'} |
|||
</Button> |
|||
</ModalFooter> |
|||
) |
|||
} |
|||
|
|||
export default Footer |
@ -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<Props, State> { |
|||
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 <Comp onChange={this.createChangeHandler} {...stepProps} {...this.props} /> |
|||
} |
|||
|
|||
render() { |
|||
const { t } = this.props |
|||
const { stepIndex, amount, account } = this.state |
|||
|
|||
return ( |
|||
<Modal |
|||
name={MODAL_SEND} |
|||
onHide={this.handleReset} |
|||
render={({ data, onClose }) => { |
|||
const acc = account || get(data, 'account', null) |
|||
return ( |
|||
<ModalBody onClose={onClose}> |
|||
<ModalTitle>{t('send:title')}</ModalTitle> |
|||
<ModalContent> |
|||
<Breadcrumb mb={6} mt={2} currentStep={stepIndex} items={this._steps} /> |
|||
{this.renderStep(acc)} |
|||
</ModalContent> |
|||
{acc && <Footer onNext={this.handleNextStep} account={acc} amount={amount} t={t} />} |
|||
</ModalBody> |
|||
) |
|||
}} |
|||
/> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default translate()(SendModal) |
@ -0,0 +1,10 @@ |
|||
import React from 'react' |
|||
|
|||
export default props => ( |
|||
<svg viewBox="0 0 16 16" {...props}> |
|||
<path |
|||
fill="currentColor" |
|||
d="M8 .25a7.751 7.751 0 0 0 0 15.5A7.75 7.75 0 1 0 8 .25zm0 14A6.246 6.246 0 0 1 1.75 8 6.248 6.248 0 0 1 8 1.75 6.248 6.248 0 0 1 14.25 8 6.246 6.246 0 0 1 8 14.25zM8 3.687a1.312 1.312 0 1 1 0 2.625 1.312 1.312 0 0 1 0-2.625zm1.75 7.938a.375.375 0 0 1-.375.375h-2.75a.375.375 0 0 1-.375-.375v-.75c0-.207.168-.375.375-.375H7v-2h-.375a.375.375 0 0 1-.375-.375v-.75c0-.207.168-.375.375-.375h2c.207 0 .375.168.375.375V10.5h.375c.207 0 .375.168.375.375v.75z" |
|||
/> |
|||
</svg> |
|||
) |
@ -1,5 +1,17 @@ |
|||
title: Send |
|||
Amount: Amount |
|||
Summary: Summary |
|||
SecureValidation: Secure validation |
|||
Confirmation: Confirmation |
|||
title: Send funds |
|||
totalSpent: Total spent |
|||
steps: |
|||
amount: |
|||
title: Informations |
|||
selectAccountDebit: Select an account to debit |
|||
recipientAddress: Recipient address |
|||
amount: Amount |
|||
max: Max |
|||
fees: Fees |
|||
advancedOptions: Advanced options |
|||
connectDevice: |
|||
title: Connect device |
|||
verification: |
|||
title: Verification |
|||
confirmation: |
|||
title: Confirmation |
|||
|
Loading…
Reference in new issue