diff --git a/src/components/DeviceConnect/index.js b/src/components/DeviceConnect/index.js
new file mode 100644
index 00000000..54a3994c
--- /dev/null
+++ b/src/components/DeviceConnect/index.js
@@ -0,0 +1,321 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import styled from 'styled-components'
+import { Trans, translate } from 'react-i18next'
+import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
+
+import type { T, Device } from 'types/common'
+
+import noop from 'lodash/noop'
+
+import Box from 'components/base/Box'
+import Spinner from 'components/base/Spinner'
+import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
+import TranslatedError from 'components/TranslatedError'
+
+import IconCheck from 'icons/Check'
+import IconExclamationCircle from 'icons/ExclamationCircle'
+import IconInfoCircle from 'icons/InfoCircle'
+import IconUsb from 'icons/Usb'
+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',
+ 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 ListDevices = styled(Box).attrs({
+ p: 3,
+ pt: 1,
+ flow: 2,
+})``
+
+const DeviceItem = styled(Box).attrs({
+ bg: 'lightGrey',
+ borderRadius: 1,
+ alignItems: 'center',
+ color: 'dark',
+ ff: 'Open Sans|SemiBold',
+ fontSize: 4,
+ horizontal: true,
+ pr: 3,
+ pl: 0,
+})`
+ cursor: pointer;
+ height: 54px;
+`
+const DeviceIcon = styled(Box).attrs({
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: 'graphite',
+})`
+ width: 55px;
+`
+const DeviceSelected = styled(Box).attrs({
+ alignItems: 'center',
+ bg: p => (p.selected ? 'wallet' : 'white'),
+ color: 'white',
+ justifyContent: 'center',
+})`
+ border-radius: 50%;
+ border: 1px solid ${p => (p.selected ? p.theme.colors.wallet : p.theme.colors.fog)};
+ height: 18px;
+ width: 18px;
+`
+
+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 Info = styled(Box).attrs({
+ alignItems: 'center',
+ color: p => (p.hasErrors ? 'alertRed' : 'grey'),
+ flow: 2,
+ fontSize: 3,
+ horizontal: true,
+ ml: 1,
+})`
+ strong {
+ font-weight: 600;
+ }
+`
+
+const StepCheck = ({ checked, hasErrors }: { checked: boolean, hasErrors?: boolean }) => (
+
+ {checked ? (
+
+
+
+ ) : hasErrors ? (
+
+
+
+ ) : (
+
+ )}
+
+)
+
+StepCheck.defaultProps = {
+ hasErrors: false,
+}
+
+type Props = {
+ appOpened: null | 'success' | 'fail',
+ genuineCheckStatus: null | 'success' | 'fail',
+ withGenuineCheck: boolean,
+ currency: CryptoCurrency,
+ devices: Device[],
+ deviceSelected: ?Device,
+ onChangeDevice: Device => void,
+ t: T,
+ error: ?Error,
+}
+
+const emitChangeDevice = props => {
+ const { onChangeDevice, deviceSelected, devices } = props
+
+ if (deviceSelected === null && devices.length > 0) {
+ onChangeDevice(devices[0])
+ }
+}
+
+class DeviceConnect extends PureComponent {
+ static defaultProps = {
+ accountName: null,
+ appOpened: null,
+ devices: [],
+ deviceSelected: null,
+ onChangeDevice: noop,
+ withGenuineCheck: false,
+ }
+
+ componentDidMount() {
+ emitChangeDevice(this.props)
+ }
+
+ componentWillReceiveProps(nextProps) {
+ emitChangeDevice(nextProps)
+ }
+
+ getStepState = stepStatus => ({
+ success: stepStatus === 'success',
+ fail: stepStatus === 'fail',
+ })
+
+ render() {
+ const {
+ deviceSelected,
+ genuineCheckStatus,
+ withGenuineCheck,
+ appOpened,
+ error,
+ currency,
+ t,
+ onChangeDevice,
+ devices,
+ } = this.props
+
+ const appState = this.getStepState(appOpened)
+ const genuineCheckState = this.getStepState(genuineCheckStatus)
+
+ const hasDevice = devices.length > 0
+ const hasMultipleDevices = devices.length > 1
+ // TODO: place custom wording in trans tags into yml file
+ /* eslint-disable react/jsx-no-literals */
+ return (
+
+
+
+
+
+
+
+
+ Connect and unlock your Ledger device
+
+
+
+
+ {hasMultipleDevices && (
+
+
+ {t('app:deviceConnect.step1.choose', { count: devices.length })}
+
+
+ {devices.map(d => {
+ const Icon = IconDevice[d.product.replace(/\s/g, '')]
+ return (
+ onChangeDevice(d)}>
+
+
+
+
+ {`${d.manufacturer} ${d.product}`}
+
+
+
+
+
+
+
+ )
+ })}
+
+
+ )}
+
+
+
+ {currency ? (
+
+
+
+
+
+
+
+
+ {'Open the '}
+ {currency.name}
+ {' app on your device'}
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ {'Navigate to the '}
+ {'dashboard'}
+ {' on your device'}
+
+
+
+
+ )}
+
+
+ {/* GENUINE CHECK */}
+ {/* ------------- */}
+
+ {withGenuineCheck && (
+
+
+
+
+
+
+
+
+
+ {'Allow '}
+ {'Ledger Manager'}
+ {' on your device'}
+
+
+
+
+
+ )}
+
+ {error ? (
+
+
+
+
+
+
+ ) : null}
+
+ )
+ }
+}
+
+export default translate()(DeviceConnect)
diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml
index f9bdde1c..eecb4534 100644
--- a/static/i18n/en/onboarding.yml
+++ b/static/i18n/en/onboarding.yml
@@ -66,8 +66,6 @@ writeSeed:
initialize:
title: Save your recovery phrase
desc: Your device will generate a 24-word recovery phrase to back up your private keys
- #Save the 24-word recovery phrase on your device to back up your private keys
- # Your device will generate a 24-word recovery phrase to back up your private keys
nano:
step1: 'Copy the word displayed below <1><0>Word #10>1> in position 1 on a blank Recovery sheet.'
step2: 'Press the right button to display <1><0>Word #20>1> and repeat the process until all 24 words are copied on the Recovery sheet.' #Recovery sheet