Browse Source

Merge pull request #228 from meriadec/master

New Send Modal
master
Meriadec Pillet 7 years ago
committed by GitHub
parent
commit
9aa2c93ae7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      src/components/Breadcrumb/index.js
  2. 111
      src/components/DeviceMonit/index.js
  3. 57
      src/components/RecipientAddress/index.js
  4. 10
      src/components/RequestAmount/index.js
  5. 2
      src/components/base/Button/index.js
  6. 53
      src/components/base/CheckBox/index.js
  7. 5
      src/components/base/Input/index.js
  8. 6
      src/components/base/Label.js
  9. 24
      src/components/base/LabelInfoTooltip/index.js
  10. 4
      src/components/base/Tooltip/index.js
  11. 179
      src/components/modals/Send.js
  12. 73
      src/components/modals/Send/01-step-amount.js
  13. 37
      src/components/modals/Send/02-step-connect-device.js
  14. 7
      src/components/modals/Send/03-step-verification.js
  15. 7
      src/components/modals/Send/04-step-confirmation.js
  16. 53
      src/components/modals/Send/Footer.js
  17. 138
      src/components/modals/Send/index.js
  18. 10
      src/icons/InfoCircle.js
  19. 25
      src/internals/usb/wallet/index.js
  20. 6
      src/reducers/devices.js
  21. 22
      static/i18n/en/send.yml
  22. 3
      yarn.lock

21
src/components/Breadcrumb/index.js

@ -25,13 +25,20 @@ class Breadcrumb extends PureComponent<Props> {
render() {
const { items, currentStep, ...props } = this.props
return (
<Wrapper {...props}>
{items.map((item, i) => (
<Step key={i} isActive={i < parseInt(currentStep, 10)} isFirst={i === 0} number={i + 1}>
{item.label}
</Step>
))}
</Wrapper>
<Box {...props}>
<Wrapper>
{items.map((item, i) => (
<Step
key={i}
isActive={i <= parseInt(currentStep, 10)}
isFirst={i === 0}
number={i + 1}
>
{item.label}
</Step>
))}
</Wrapper>
</Box>
)
}
}

111
src/components/DeviceMonit/index.js

@ -0,0 +1,111 @@
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { ipcRenderer } from 'electron'
import { sendEvent } from 'renderer/events'
import { getCurrentDevice } from 'reducers/devices'
import type { Device, Account } from 'types/common'
const mapStateToProps = state => ({
currentDevice: getCurrentDevice(state),
})
type DeviceStatus = 'unconnected' | 'connected' | 'appOpened'
type Props = {
currentDevice: Device | null,
account: Account,
onStatusChange: DeviceStatus => void,
}
type State = {
status: DeviceStatus,
}
class DeviceMonit extends PureComponent<Props, State> {
state = {
status: this.props.currentDevice ? 'connected' : 'unconnected',
}
componentDidMount() {
ipcRenderer.on('msg', this.handleMsgEvent)
if (this.props.currentDevice !== null) {
this.checkAppOpened()
}
}
componentWillReceiveProps(nextProps) {
const { status } = this.state
const { currentDevice } = this.props
const { currentDevice: nextCurrentDevice } = nextProps
if (status === 'unconnected' && !currentDevice && nextCurrentDevice) {
this.handleStatusChange('connected')
}
if (status !== 'unconnected' && !nextCurrentDevice) {
this.handleStatusChange('unconnected')
}
}
componentDidUpdate() {
const { currentDevice } = this.props
if (currentDevice !== null) {
this.checkAppOpened()
} else {
clearTimeout(this._timeout)
}
}
componentWillUnmount() {
ipcRenderer.removeListener('msg', this.handleMsgEvent)
clearTimeout(this._timeout)
}
checkAppOpened = () => {
const { currentDevice, account } = this.props
if (currentDevice === null || account.currency === null) {
return
}
sendEvent('usb', 'wallet.checkIfAppOpened', {
devicePath: currentDevice.path,
accountPath: account.path,
accountAddress: account.address,
})
}
_timeout: any = null
handleStatusChange = status => {
this.setState({ status })
this.props.onStatusChange(status)
}
handleMsgEvent = (e, { type }) => {
if (type === 'wallet.checkIfAppOpened.success') {
this.handleStatusChange('appOpened')
clearTimeout(this._timeout)
}
if (type === 'wallet.checkIfAppOpened.fail') {
this._timeout = setTimeout(this.checkAppOpened, 1e3)
}
}
render() {
const { status } = this.state
return (
<div>
<div>device connected {status !== 'unconnected' ? 'TRUE' : 'FALSE'}</div>
<div>app opened {status === 'appOpened' ? 'TRUE' : 'FALSE'}</div>
</div>
)
}
}
export default connect(mapStateToProps)(DeviceMonit)

57
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 }) => (
<Box color="graphite" style={{ position: 'absolute', right: 15 }}>
<IconQrCode height={30} width={30} style={{ cursor: 'pointer' }} onClick={onClick} />
</Box>
)
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<Props, State> {
return (
<Box relative justifyContent="center">
<InputAddress value={value} withQrCode={withQrCode} onChange={onChange} />
{withQrCode && (
<Fragment>
<WrapperIcon onClick={this.handleClickQrCode} />
{qrReaderOpened && (
<WrapperQrCode>
<QrReader
onScan={this.handleScanQrCode}
onError={noop}
style={{ height: qrCodeSize, width: qrCodeSize }}
/>
</WrapperQrCode>
)}
</Fragment>
)}
<Input
value={value}
withQrCode={withQrCode}
onChange={onChange}
renderRight={
<Right onClick={this.handleClickQrCode}>
<IconQrCode width={16} height={16} />
{qrReaderOpened && (
<WrapperQrCode>
<QrReader
onScan={this.handleScanQrCode}
onError={noop}
style={{ height: qrCodeSize, width: qrCodeSize }}
/>
</WrapperQrCode>
)}
</Right>
}
/>
</Box>
)
}

10
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,

2
src/components/base/Button/index.js

@ -27,7 +27,7 @@ const Base = styled.button.attrs({
outline: none;
&:hover {
background: ${p => (p.primary ? lighten(p.theme.colors.wallet, 0.05) : '')};
background: ${p => (p.disabled ? '' : p.primary ? lighten(p.theme.colors.wallet, 0.05) : '')};
}
&:active {

53
src/components/base/CheckBox/index.js

@ -2,47 +2,34 @@
import React from 'react'
import noop from 'lodash/noop'
import styled, { keyframes } from 'styled-components'
import styled from 'styled-components'
import { Tabbable } from 'components/base/Box'
import IconCheck from 'icons/Check'
const bounce = keyframes`
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
`
const Base = styled(Tabbable).attrs({
color: 'white',
alignItems: 'center',
justifyContent: 'center',
bg: p => (p.isChecked ? 'wallet' : 'fog'),
horizontal: true,
align: 'center',
})`
cursor: pointer;
outline: none;
border-radius: 3px;
border: 1px solid transparent;
background-color: ${p => (p.isChecked ? p.theme.colors.wallet : p.theme.colors.white)};
box-shadow: 0 0 0 ${p => (p.isChecked ? 4 : 1)}px
${p => (p.isChecked ? p.theme.colors.lightGrey : p.theme.colors.graphite)};
font-size: 7px;
height: 19px;
width: 19px;
transition: all ease-in 0.1s;
backround: red;
width: 50px;
height: 24px;
border-radius: 16px;
transition: 250ms linear background-color;
&:focus {
border-color: ${p => p.theme.colors.fog};
box-shadow: rgba(0, 0, 0, 0.1) 0 2px 2px;
outline: none;
}
`
const IconWrapper = styled(IconCheck)`
animation: ${bounce} ease-in-out 350ms;
const Ball = styled.div`
width: 22px;
height: 22px;
border-radius: 50%;
background: white;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15);
transition: 250ms ease-in-out transform;
transform: translate3d(${p => (p.isChecked ? '28px' : '0')}, 0, 0);
`
type Props = {
@ -54,7 +41,7 @@ function CheckBox(props: Props) {
const { isChecked, onChange, ...p } = props
return (
<Base isChecked={isChecked} onClick={() => onChange && onChange(!isChecked)} {...p}>
{isChecked && <IconWrapper height={7} width={7} />}
<Ball isChecked={isChecked} />
</Base>
)
}

5
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<Props, State> {
render() {
const { isFocus } = this.state
const { renderLeft, renderRight } = this.props
const { renderLeft, renderRight, containerProps } = this.props
return (
<Container onClick={this.handleClick} isFocus={isFocus} shrink>
<Container onClick={this.handleClick} isFocus={isFocus} shrink {...containerProps}>
{renderLeft}
<Box px={3} grow shrink>
<Base

6
src/components/base/Label.js

@ -1,5 +1,5 @@
import styled from 'styled-components'
import { fontSize, color } from 'styled-system'
import { fontSize, color, alignItems } from 'styled-system'
import fontFamily from 'styles/styled/fontFamily'
@ -7,9 +7,11 @@ export default styled.label.attrs({
fontSize: 3,
ff: 'Museo Sans|Regular',
color: 'grey',
align: 'center',
})`
${alignItems};
${color};
${fontSize};
${fontFamily};
display: block;
display: flex;
`

24
src/components/base/LabelInfoTooltip/index.js

@ -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

4
src/components/base/Tooltip/index.js

@ -86,10 +86,10 @@ class Tooltip extends PureComponent<Props> {
_template = undefined
render() {
const { children, render } = this.props
const { children, render, ...props } = this.props
return (
<Container innerRef={n => (this._node = n)}>
<Container innerRef={n => (this._node = n)} {...props}>
<Template>
<TooltipContainer innerRef={n => (this._template = n)}>{render()}</TooltipContainer>
</Template>

179
src/components/modals/Send.js

@ -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)

73
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 (
<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

37
src/components/modals/Send/02-step-connect-device.js

@ -0,0 +1,37 @@
// @flow
import React from 'react'
import DeviceMonit from 'components/DeviceMonit'
import type { Account } from 'types/common'
type Props = {
account: Account | null,
isDeviceReady: boolean,
onChange: Function,
}
function StepConnectDevice(props: Props) {
const { account, isDeviceReady, onChange } = props
const setReady = onChange('isDeviceReady')
if (!account) {
return null
}
return (
<div>
<DeviceMonit
account={account}
onStatusChange={status => {
if (status === 'appOpened' && !isDeviceReady) {
setReady(true)
}
if (status !== 'appOpened' && isDeviceReady) {
setReady(false)
}
}}
/>
</div>
)
}
export default StepConnectDevice

7
src/components/modals/Send/03-step-verification.js

@ -0,0 +1,7 @@
import React from 'react'
function StepVerification() {
return <div>step verification</div>
}
export default StepVerification

7
src/components/modals/Send/04-step-confirmation.js

@ -0,0 +1,7 @@
import React from 'react'
function StepConfirmation() {
return <div>step confirmation</div>
}
export default StepConfirmation

53
src/components/modals/Send/Footer.js

@ -0,0 +1,53 @@
// @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,
canNext: boolean,
}
function Footer({ account, amount, t, onNext, canNext }: 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} disabled={!canNext}>
{'Next'}
</Button>
</ModalFooter>
)
}
export default Footer

138
src/components/modals/Send/index.js

@ -0,0 +1,138 @@
// @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,
isDeviceReady: boolean,
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,
isDeviceReady: false,
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)
canNext = account => {
const { stepIndex } = this.state
// informations
if (stepIndex === 0) {
const { amount, recipientAddress } = this.state
return !!amount.left && !!recipientAddress && !!account
}
// connect device
if (stepIndex === 1) {
const { isDeviceReady } = this.state
return !!isDeviceReady
}
return false
}
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)
const canNext = this.canNext(acc)
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
canNext={canNext}
onNext={this.handleNextStep}
account={acc}
amount={amount}
t={t}
/>
)}
</ModalBody>
)
}}
/>
)
}
}
export default translate()(SendModal)

10
src/icons/InfoCircle.js

@ -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>
)

25
src/internals/usb/wallet/index.js

@ -1,6 +1,7 @@
// @flow
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import Btc from '@ledgerhq/hw-app-btc'
import getAllAccounts, { verifyAddress } from './accounts'
@ -57,4 +58,28 @@ export default (sendEvent: Function) => ({
sendEvent('wallet.verifyAddress.fail')
}
},
checkIfAppOpened: async ({
devicePath,
accountPath,
accountAddress,
segwit = true,
}: {
devicePath: string,
accountPath: string,
accountAddress: string,
segwit: boolean,
}) => {
try {
const transport = await CommNodeHid.open(devicePath)
const btc = new Btc(transport)
const { bitcoinAddress } = await btc.getWalletPublicKey(accountPath, false, segwit)
if (bitcoinAddress === accountAddress) {
sendEvent('wallet.checkIfAppOpened.success')
} else {
throw new Error('Address is different')
}
} catch (err) {
sendEvent('wallet.checkIfAppOpened.fail')
}
},
})

6
src/reducers/devices.js

@ -15,10 +15,8 @@ const state: DevicesState = {
}
function setCurrentDevice(state) {
return {
...state,
currentDevice: state.devices.length === 1 ? state.devices[0] : state.currentDevice,
}
const currentDevice = state.devices.length ? state.devices[state.devices.length - 1] : null
return { ...state, currentDevice }
}
const handlers: Object = {

22
static/i18n/en/send.yml

@ -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

3
yarn.lock

@ -6367,9 +6367,6 @@ ledger-test-library@KhalilBellakrid/ledger-test-library-nodejs#7d37482:
dependencies:
axios "^0.17.1"
bindings "^1.3.0"
electron "^1.8.2"
electron-builder "^20.0.4"
electron-rebuild "^1.7.3"
nan "^2.6.2"
prebuild-install "^2.2.2"

Loading…
Cancel
Save