diff --git a/src/bridge/index.js b/src/bridge/index.js index ba9c8968..3ea7fe37 100644 --- a/src/bridge/index.js +++ b/src/bridge/index.js @@ -1,8 +1,5 @@ // @flow import type { Currency } from '@ledgerhq/live-common/lib/types' - -import makeMockBridge from 'bridge/makeMockBridge' - import { WalletBridge } from './types' import LibcoreBridge from './LibcoreBridge' import EthereumJSBridge from './EthereumJSBridge' @@ -15,6 +12,5 @@ export const getBridgeForCurrency = (currency: Currency): WalletBridge => { if (currency.id === 'ripple') { return RippleJSBridge // polyfill js } - return makeMockBridge({}) return LibcoreBridge // libcore for the rest } diff --git a/src/components/base/Input/index.js b/src/components/base/Input/index.js index e246ce10..d2d09747 100644 --- a/src/components/base/Input/index.js +++ b/src/components/base/Input/index.js @@ -69,6 +69,7 @@ type Props = { onBlur: Function, onChange?: Function, onEnter?: Function, + onEsc?: Function, onFocus: Function, renderLeft?: any, renderRight?: any, @@ -108,6 +109,11 @@ class Input extends PureComponent { if (onEnter) { onEnter(e) } + } else if (e.which === 27) { + const { onEsc } = this.props + if (onEsc) { + onEsc(e) + } } } diff --git a/src/components/base/Modal/index.js b/src/components/base/Modal/index.js index af637837..26511ea1 100644 --- a/src/components/base/Modal/index.js +++ b/src/components/base/Modal/index.js @@ -164,6 +164,7 @@ export class Modal extends Component { isOpened={isOpened} onClose={onClose} onHide={onHide} + closeOnEsc={!preventBackdropClick} motionStyle={(spring, isVisible) => ({ opacity: spring(isVisible ? 1 : 0, springConfig), scale: spring(isVisible ? 1 : 0.95, springConfig), diff --git a/src/components/modals/ImportAccounts/AccountRow.js b/src/components/modals/ImportAccounts/AccountRow.js index b68dbd97..b9bb96b7 100644 --- a/src/components/modals/ImportAccounts/AccountRow.js +++ b/src/components/modals/ImportAccounts/AccountRow.js @@ -64,6 +64,8 @@ export default class AccountRow extends PureComponent { handleChangeName = accountNameCopy => this.setState({ accountNameCopy }) + handleReset = () => this.setState({ isEditing: false, accountNameCopy: '' }) + _input = null render() { @@ -81,6 +83,7 @@ export default class AccountRow extends PureComponent { onChange={this.handleChangeName} onClick={this.handlePreventSubmit} onEnter={this.handleSubmitName} + onEsc={this.handleReset} renderRight={ diff --git a/src/components/modals/ImportAccounts/index.js b/src/components/modals/ImportAccounts/index.js index f8267c2c..a721681b 100644 --- a/src/components/modals/ImportAccounts/index.js +++ b/src/components/modals/ImportAccounts/index.js @@ -5,11 +5,12 @@ import { compose } from 'redux' import { connect } from 'react-redux' import { translate } from 'react-i18next' -import type { Currency } from '@ledgerhq/live-common/lib/types' +import type { Currency, Account } from '@ledgerhq/live-common/lib/types' import type { T, Device } from 'types/common' import { getCurrentDevice } from 'reducers/devices' +import { getAccounts } from 'reducers/accounts' import Modal, { ModalContent, ModalTitle, ModalFooter, ModalBody } from 'components/base/Modal' import Box from 'components/base/Box' @@ -20,8 +21,6 @@ import StepConnectDevice, { StepConnectDeviceFooter } from './steps/02-step-conn import StepImport, { StepImportFooter } from './steps/03-step-import' import StepFinish from './steps/04-step-finish' -const { getCryptoCurrencyById } = require('@ledgerhq/live-common/lib/helpers/currencies') - const createSteps = ({ t }: { t: T }) => [ { id: 'chooseCurrency', @@ -60,10 +59,25 @@ const createSteps = ({ t }: { t: T }) => [ type Props = { t: T, currentDevice: ?Device, + existingAccounts: Account[], } type StepId = 'chooseCurrency' | 'connectDevice' | 'import' | 'finish' +type ScanStatus = 'idle' | 'scanning' | 'error' | 'finished' + +type State = { + stepId: StepId, + isAppOpened: boolean, + currency: ?Currency, + + // scan process + scannedAccounts: Account[], + checkedAccountsIds: string[], + scanStatus: ScanStatus, + err: ?Error, +} + export type StepProps = { t: T, currency: ?Currency, @@ -71,22 +85,26 @@ export type StepProps = { isAppOpened: boolean, transitionTo: StepId => void, setState: any => void, -} -type State = { - stepId: StepId, - isAppOpened: boolean, - currency: ?Currency, + // scan process + scannedAccounts: Account[], + existingAccounts: Account[], + checkedAccountsIds: string[], + scanStatus: ScanStatus, + err: ?Error, } const mapStateToProps = state => ({ currentDevice: getCurrentDevice(state), + existingAccounts: getAccounts(state), }) const INITIAL_STATE = { - stepId: 'import', + stepId: 'chooseCurrency', isAppOpened: false, - currency: getCryptoCurrencyById('bitcoin'), + currency: null, + scannedAccounts: [], + checkedAccountsIds: [], } class ImportAccounts extends PureComponent { @@ -104,8 +122,16 @@ class ImportAccounts extends PureComponent { } render() { - const { t, currentDevice } = this.props - const { stepId, currency, isAppOpened } = this.state + const { t, currentDevice, existingAccounts } = this.props + const { + stepId, + currency, + isAppOpened, + scannedAccounts, + checkedAccountsIds, + scanStatus, + err, + } = this.state const stepIndex = this.STEPS.findIndex(s => s.id === stepId) const step = this.STEPS[stepIndex] @@ -120,6 +146,11 @@ class ImportAccounts extends PureComponent { t, currency, currentDevice, + existingAccounts, + scannedAccounts, + checkedAccountsIds, + scanStatus, + err, isAppOpened, transitionTo: this.transitionTo, setState: (...args) => this.setState(...args), diff --git a/src/components/modals/ImportAccounts/steps/03-step-import.js b/src/components/modals/ImportAccounts/steps/03-step-import.js index 5777b48c..c884428e 100644 --- a/src/components/modals/ImportAccounts/steps/03-step-import.js +++ b/src/components/modals/ImportAccounts/steps/03-step-import.js @@ -1,9 +1,6 @@ // @flow import React, { PureComponent } from 'react' -import keyBy from 'lodash/keyBy' - -import type { Account } from '@ledgerhq/live-common/lib/types' import { getBridgeForCurrency } from 'bridge' @@ -16,25 +13,7 @@ import AccountRow from '../AccountRow' import type { StepProps } from '../index' -type Status = 'scanning' | 'error' | 'finished' - -type State = { - status: Status, - err: ?Error, - scannedAccounts: Account[], - checkedAccountsIds: string[], -} - -const INITIAL_STATE = { - status: 'scanning', - err: null, - scannedAccounts: [], - checkedAccountsIds: [], -} - -class StepImport extends PureComponent { - state = INITIAL_STATE - +class StepImport extends PureComponent { componentDidMount() { console.log(`starting import...`) this.startScanAccountsDevice() @@ -48,30 +27,37 @@ class StepImport extends PureComponent { } startScanAccountsDevice() { - const { currency } = this.props - - if (!currency) { - throw new Error('No currency to scan') + const { currency, currentDevice, setState } = this.props + try { + if (!currency) { + throw new Error('No currency to scan') + } + + if (!currentDevice) { + throw new Error('No device') + } + + const bridge = getBridgeForCurrency(currency) + + // TODO: use the real device + const devicePath = currentDevice.path + + setState({ scanStatus: 'scanning' }) + + this.scanSubscription = bridge.scanAccountsOnDevice(currency, devicePath, { + next: account => { + const { scannedAccounts } = this.props + const hasAlreadyBeenScanned = !!scannedAccounts.find(a => account.id === a.id) + if (!hasAlreadyBeenScanned) { + setState({ scannedAccounts: [...scannedAccounts, account] }) + } + }, + complete: () => setState({ scanStatus: 'finished' }), + error: err => setState({ scanStatus: 'error', err }), + }) + } catch (err) { + setState({ scanStatus: 'error', err }) } - - const bridge = getBridgeForCurrency(currency) - - // TODO: use the real device - const devicePath = '' - - this.scanSubscription = bridge.scanAccountsOnDevice(currency, devicePath, { - next: account => { - const { scannedAccounts } = this.state - const hasAlreadyBeenScanned = !!scannedAccounts.find(a => account.id === a.id) - if (!hasAlreadyBeenScanned) { - this.setState({ scannedAccounts: [...scannedAccounts, account] }) - } - }, - complete: () => { - this.setState({ status: 'finished' }) - }, - error: err => this.setState({ status: 'error', err }), - }) } handleRetry = () => { @@ -79,23 +65,33 @@ class StepImport extends PureComponent { this.scanSubscription.unsubscribe() this.scanSubscription = null } - this.setState(INITIAL_STATE) + this.handleResetState() this.startScanAccountsDevice() } + handleResetState = () => { + const { setState } = this.props + setState({ + scanStatus: 'idle', + err: null, + scannedAccounts: [], + checkedAccountsIds: [], + }) + } + handleToggleAccount = account => { - const { checkedAccountsIds } = this.state + const { checkedAccountsIds, setState } = this.props const isChecked = checkedAccountsIds.find(id => id === account.id) !== undefined if (isChecked) { - this.setState({ checkedAccountsIds: checkedAccountsIds.filter(id => id !== account.id) }) + setState({ checkedAccountsIds: checkedAccountsIds.filter(id => id !== account.id) }) } else { - this.setState({ checkedAccountsIds: [...checkedAccountsIds, account.id] }) + setState({ checkedAccountsIds: [...checkedAccountsIds, account.id] }) } } handleAccountUpdate = updatedAccount => { - const { scannedAccounts } = this.state - this.setState({ + const { scannedAccounts, setState } = this.props + setState({ scannedAccounts: scannedAccounts.map(account => { if (account.id !== updatedAccount.id) { return account @@ -106,11 +102,11 @@ class StepImport extends PureComponent { } render() { - const { status, err, scannedAccounts, checkedAccountsIds } = this.state + const { scanStatus, err, scannedAccounts, checkedAccountsIds } = this.props return ( - {err && {err.toString()}} + {err && {err.message}} {scannedAccounts.map(account => { @@ -125,7 +121,7 @@ class StepImport extends PureComponent { /> ) })} - {status === 'scanning' && ( + {scanStatus === 'scanning' && ( { - {['error', 'finished'].includes(status) && ( + {['error', 'finished'].includes(scanStatus) && (