Browse Source

Merge pull request #587 from valpinkman/refactor/connection-workflow

Refactor/connection workflow
master
Valentin D. Pinkman 7 years ago
committed by GitHub
parent
commit
3a2898de4d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      src/components/DeviceConnect/index.js
  2. 49
      src/components/GenuineCheckModal/index.js
  3. 6
      src/components/ManagerPage/index.js
  4. 9
      src/components/Onboarding/steps/GenuineCheck.js
  5. 15
      src/components/TriggerOnMount/index.js
  6. 0
      src/components/Workflow/EnsureDashboard.js
  7. 0
      src/components/Workflow/EnsureDevice.js
  8. 3
      src/components/Workflow/EnsureGenuine.js
  9. 172
      src/components/Workflow/WorkflowDefault.js
  10. 4
      src/components/Workflow/WorkflowWithIcon.js
  11. 16
      src/components/Workflow/index.js
  12. 2
      src/components/modals/Debug.js

13
src/components/DeviceConnect/index.js

@ -22,6 +22,8 @@ import IconHome from 'icons/Home'
import * as IconDevice from 'icons/device'
// TODO: CHECK IF COMPONENT CAN BE REMOVED
const Step = styled(Box).attrs({
borderRadius: 1,
justifyContent: 'center',
@ -147,7 +149,10 @@ type Props = {
deviceSelected: ?Device,
onChangeDevice: Device => void,
t: T,
error: ?Error,
errors: ?{
genuineError: ?Error,
dashboardError: ?Error,
},
}
const emitChangeDevice = props => {
@ -187,7 +192,7 @@ class DeviceConnect extends PureComponent<Props> {
genuineCheckStatus,
withGenuineCheck,
appOpened,
error,
errors,
currency,
t,
onChangeDevice,
@ -304,11 +309,11 @@ class DeviceConnect extends PureComponent<Props> {
</Step>
)}
{appState.fail ? (
{errors && (errors.genuineError || errors.dashboardError) ? (
<Info hasErrors>
<IconInfoCircle size={12} />
<Box shrink selectable>
<TranslatedError error={error} />
<TranslatedError error={errors.genuineError || errors.dashboardError} />
</Box>
</Info>
) : null}

49
src/components/GenuineCheckModal/index.js

@ -1,26 +1,16 @@
// @flow
import logger from 'logger'
import React, { PureComponent } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import type { T, Device } from 'types/common'
import type { T } from 'types/common'
import { getCurrentDevice } from 'reducers/devices'
import DeviceConnect from 'components/DeviceConnect'
import EnsureDeviceApp from 'components/EnsureDeviceApp'
import Modal, { ModalBody, ModalTitle, ModalContent } from 'components/base/Modal'
const mapStateToProps = state => ({
currentDevice: getCurrentDevice(state),
})
import Workflow from 'components/Workflow'
import WorkflowDefault from 'components/Workflow/WorkflowDefault'
type Props = {
t: T,
currentDevice: ?Device,
onGenuineCheck: (isGenuine: boolean) => void,
}
@ -28,33 +18,23 @@ type State = {}
class GenuineCheck extends PureComponent<Props, State> {
renderBody = ({ onClose }) => {
const { t, currentDevice, onGenuineCheck } = this.props
const { t, onGenuineCheck } = this.props
// TODO: use the real devices list. for now we force choosing only
// the current device because we don't handle multi device in MVP
const reducedDevicesList = currentDevice ? [currentDevice] : []
return (
<ModalBody onClose={onClose}>
<ModalTitle>{t('app:genuinecheck.modal.title')}</ModalTitle>
<ModalContent>
<EnsureDeviceApp
deviceSelected={currentDevice}
withGenuineCheck
onGenuineCheck={onGenuineCheck}
onStatusChange={status => {
logger.log(`status changed to ${status}`)
}}
render={({ appStatus, genuineCheckStatus, deviceSelected, error }) => (
<DeviceConnect
appOpened={
appStatus === 'success' ? 'success' : appStatus === 'fail' ? 'fail' : null
}
withGenuineCheck
genuineCheckStatus={genuineCheckStatus}
devices={reducedDevicesList}
deviceSelected={deviceSelected}
error={error}
<Workflow
onGenuineCheck={isGenuine => onGenuineCheck(isGenuine)}
renderDefault={(device, deviceInfo, isGenuine, errors) => (
<WorkflowDefault
device={device}
deviceInfo={deviceInfo}
isGenuine={isGenuine}
errors={errors} // TODO: FIX ERRORS
/>
)}
/>
@ -69,7 +49,4 @@ class GenuineCheck extends PureComponent<Props, State> {
}
}
export default compose(
connect(mapStateToProps),
translate(),
)(GenuineCheck)
export default translate()(GenuineCheck)

6
src/components/ManagerPage/index.js

@ -6,8 +6,8 @@ import React from 'react'
import type { Node } from 'react'
import type { Device } from 'types/common'
import Workflow from './Workflow'
import WorkflowDefault from './WorkflowDefault'
import Workflow from 'components/Workflow'
import WorkflowWithIcon from 'components/Workflow/WorkflowWithIcon'
import Dashboard from './Dashboard'
type DeviceInfo = {
@ -43,7 +43,7 @@ function ManagerPage(): Node {
genuineError: ?Error,
},
) => (
<WorkflowDefault
<WorkflowWithIcon
device={device}
deviceInfo={deviceInfo}
errors={errors}

9
src/components/Onboarding/steps/GenuineCheck.js

@ -87,14 +87,15 @@ class GenuineCheck extends PureComponent<StepProps, State> {
}
handleOpenGenuineCheckModal = () => this.setState({ isGenuineCheckModalOpened: true })
handleCloseGenuineCheckModal = () => this.setState({ isGenuineCheckModalOpened: false })
handleCloseGenuineCheckModal = (cb?: Function) =>
this.setState(state => ({ ...state, isGenuineCheckModalOpened: false }), () => cb && cb())
handleGenuineCheck = async isGenuine => {
await new Promise(r => setTimeout(r, 1e3)) // let's wait a bit before closing modal
this.handleCloseGenuineCheckModal()
handleGenuineCheck = isGenuine => {
this.handleCloseGenuineCheckModal(() => {
this.props.updateGenuineCheck({
isDeviceGenuine: isGenuine,
})
})
}
redoGenuineCheck = () => {

15
src/components/TriggerOnMount/index.js

@ -0,0 +1,15 @@
// @flow
import { PureComponent } from 'react'
type Props = {
callback: () => void,
}
class TriggerOnMount extends PureComponent<Props> {
componentDidMount() {
const { callback } = this.props
callback()
}
}
export default TriggerOnMount

0
src/components/ManagerPage/EnsureDashboard.js → src/components/Workflow/EnsureDashboard.js

0
src/components/ManagerPage/EnsureDevice.js → src/components/Workflow/EnsureDevice.js

3
src/components/ManagerPage/EnsureGenuine.js → src/components/Workflow/EnsureGenuine.js

@ -2,7 +2,6 @@
import { PureComponent } from 'react'
import isEqual from 'lodash/isEqual'
import type { Node } from 'react'
import type { Device } from 'types/common'
import getIsGenuine from 'commands/getIsGenuine'
@ -20,7 +19,7 @@ type DeviceInfos = {
type Props = {
device: ?Device,
infos: ?DeviceInfos,
children: (isGenuine: ?boolean, error: ?Error) => Node,
children: (isGenuine: ?boolean, error: ?Error) => *,
}
type State = {

172
src/components/Workflow/WorkflowDefault.js

@ -0,0 +1,172 @@
// @flow
/* eslint-disable react/jsx-no-literals */
import React from 'react'
import { Trans, translate } from 'react-i18next'
import styled from 'styled-components'
import isNull from 'lodash/isNull'
import type { Device } from 'types/common'
import Box from 'components/base/Box'
import Spinner from 'components/base/Spinner'
import IconCheck from 'icons/Check'
import IconExclamationCircle from 'icons/ExclamationCircle'
import IconUsb from 'icons/Usb'
import IconHome from 'icons/Home'
const Step = styled(Box).attrs({
borderRadius: 1,
justifyContent: 'center',
fontSize: 4,
})`
border: 1px solid
${p =>
p.validated
? p.theme.colors.wallet
: p.hasErrors
? p.theme.colors.alertRed
: p.theme.colors.fog};
`
const StepIcon = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
})`
width: 64px;
`
const StepContent = styled(Box).attrs({
color: 'dark',
horizontal: true,
alignItems: 'center',
})`
height: 60px;
line-height: 1.2;
strong {
font-weight: 600;
}
`
const WrapperIconCurrency = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
})`
border: 1px solid ${p => p.theme.colors[p.color]};
border-radius: 8px;
height: 24px;
width: 24px;
`
const StepCheck = ({ checked, hasErrors }: { checked: boolean, hasErrors?: boolean }) => (
<Box pr={5}>
{checked ? (
<Box color="wallet">
<IconCheck size={16} />
</Box>
) : hasErrors ? (
<Box color="alertRed">
<IconExclamationCircle size={16} />
</Box>
) : (
<Spinner size={16} />
)}
</Box>
)
StepCheck.defaultProps = {
hasErrors: false,
}
type DeviceInfo = {
targetId: number | string,
version: string,
final: boolean,
mcu: boolean,
}
type Error = {
message: string,
stack: string,
}
type Props = {
// t: T,
device: ?Device,
deviceInfo: ?DeviceInfo,
errors: {
dashboardError: ?Error,
genuineError: ?Error,
},
isGenuine: boolean,
}
const WorkflowDefault = ({ device, deviceInfo, errors, isGenuine }: Props) => (
<Box flow={4} ff="Open Sans">
<Step validated={!!device}>
<StepContent>
<StepIcon>
<IconUsb size={36} />
</StepIcon>
<Box grow shrink>
<Trans i18nKey="app:deviceConnect.step1.connect" parent="div">
Connect your <strong>Ledger device</strong> to your computer and enter your{' '}
<strong>PIN code</strong> on your device
</Trans>
</Box>
<StepCheck checked={!!device} />
</StepContent>
</Step>
<Step validated={!!device && !!deviceInfo} hasErrors={!!device && !!errors.dashboardError}>
<StepContent>
<StepIcon>
<WrapperIconCurrency>
<IconHome size={12} />
</WrapperIconCurrency>
</StepIcon>
<Box grow shrink>
<Trans i18nKey="deviceConnect:dashboard.open" parent="div">
{'Go to the '}
<strong>{'dashboard'}</strong>
{' on your device'}
</Trans>
</Box>
<StepCheck
checked={!!device && !!deviceInfo}
hasErrors={!!device && !!errors.dashboardError}
/>
</StepContent>
</Step>
{/* GENUINE CHECK */}
{/* ------------- */}
<Step
validated={(!!device && !isNull(isGenuine) && isGenuine && !errors.genuineError) || undefined}
hasErrors={(!!device && !isNull(isGenuine) && !isGenuine) || errors.genuineError || undefined}
>
<StepContent>
<StepIcon>
<WrapperIconCurrency>
<IconCheck size={12} />
</WrapperIconCurrency>
</StepIcon>
<Box grow shrink>
<Trans i18nKey="deviceConnect:stepGenuine.open" parent="div">
{'Confirm '}
<strong>{'authentication'}</strong>
{' on your device'}
</Trans>
</Box>
<StepCheck
checked={!!device && !isNull(isGenuine) && isGenuine}
hasErrors={(!!device && !isNull(isGenuine) && !isGenuine) || undefined}
/>
</StepContent>
</Step>
</Box>
)
export default translate()(WorkflowDefault)

4
src/components/ManagerPage/WorkflowDefault.js → src/components/Workflow/WorkflowWithIcon.js

@ -105,7 +105,7 @@ type Props = {
isGenuine: boolean,
}
const WorkflowDefault = ({ device, deviceInfo, errors, isGenuine, t }: Props) => (
const WorkflowWithIcon = ({ device, deviceInfo, errors, isGenuine, t }: Props) => (
<Box align="center" justify="center" sticky>
<Box align="center" style={{ maxWidth: 460, padding: '0 10px' }}>
<img
@ -194,4 +194,4 @@ const WorkflowDefault = ({ device, deviceInfo, errors, isGenuine, t }: Props) =>
</Box>
)
export default translate()(WorkflowDefault)
export default translate()(WorkflowWithIcon)

16
src/components/ManagerPage/Workflow.js → src/components/Workflow/index.js

@ -31,9 +31,10 @@ type Props = {
genuineError: ?Error,
},
) => Node,
renderMcuUpdate: (deviceInfo: DeviceInfo) => Node,
renderFinalUpdate: (deviceInfo: DeviceInfo) => Node,
renderDashboard: (device: Device, deviceInfo: DeviceInfo) => Node,
renderMcuUpdate?: (deviceInfo: DeviceInfo) => Node,
renderFinalUpdate?: (deviceInfo: DeviceInfo) => Node,
renderDashboard?: (device: Device, deviceInfo: DeviceInfo, isGenuine: boolean) => Node,
onGenuineCheck?: (isGenuine: boolean) => void,
renderError?: (dashboardError: ?Error, genuineError: ?Error) => Node,
}
type State = {}
@ -46,6 +47,7 @@ class Workflow extends PureComponent<Props, State> {
renderMcuUpdate,
renderError,
renderDefault,
onGenuineCheck,
} = this.props
return (
<EnsureDevice>
@ -63,16 +65,18 @@ class Workflow extends PureComponent<Props, State> {
})
}
if (deviceInfo && deviceInfo.mcu) {
if (deviceInfo && deviceInfo.mcu && renderMcuUpdate) {
return renderMcuUpdate(deviceInfo)
}
if (deviceInfo && deviceInfo.final) {
if (deviceInfo && deviceInfo.final && renderFinalUpdate) {
return renderFinalUpdate(deviceInfo)
}
if (isGenuine && deviceInfo && device && !dashboardError && !genuineError) {
return renderDashboard(device, deviceInfo)
if (onGenuineCheck) onGenuineCheck(isGenuine)
if (renderDashboard) return renderDashboard(device, deviceInfo, isGenuine)
}
return renderDefault(device, deviceInfo, isGenuine, {

2
src/components/modals/Debug.js

@ -7,7 +7,7 @@ import Modal, { ModalBody, ModalTitle, ModalContent } from 'components/base/Moda
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import Input from 'components/base/Input'
import EnsureDevice from 'components/ManagerPage/EnsureDevice'
import EnsureDevice from 'components/Workflow/EnsureDevice'
import { getDerivations } from 'helpers/derivations'
import getAddress from 'commands/getAddress'
import testInterval from 'commands/testInterval'

Loading…
Cancel
Save