From 9de76638b1b9cdc52898e05fc572b0602d2ca7f5 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 29 Jun 2018 11:33:35 +0200 Subject: [PATCH] Move signTransaction to top level to unsubscribe correctly --- src/components/modals/Send/index.js | 47 ++++++++++++++++- .../modals/Send/steps/03-step-verification.js | 52 ++----------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/components/modals/Send/index.js b/src/components/modals/Send/index.js index edde8903..c0f15263 100644 --- a/src/components/modals/Send/index.js +++ b/src/components/modals/Send/index.js @@ -1,12 +1,14 @@ // @flow import React, { PureComponent } from 'react' +import invariant from 'invariant' import { compose } from 'redux' import { connect } from 'react-redux' import { translate } from 'react-i18next' import { createStructuredSelector } from 'reselect' import type { Account, Operation } from '@ledgerhq/live-common/lib/types' +import { createCustomErrorClass } from 'helpers/errors' import Track from 'analytics/Track' import { updateAccountWithUpdater } from 'actions/accounts' import { MODAL_SEND } from 'config/constants' @@ -29,6 +31,8 @@ import StepConnectDevice, { StepConnectDeviceFooter } from './steps/02-step-conn import StepVerification from './steps/03-step-verification' import StepConfirmation, { StepConfirmationFooter } from './steps/04-step-confirmation' +const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') + type Props = { t: T, device: ?Device, @@ -65,6 +69,7 @@ export type StepProps = DefaultStepProps & { onTransactionError: Error => void, onOperationBroadcasted: Operation => void, onRetry: void => void, + signTransaction: ({ transitionTo: string => void }) => void, } const createSteps = ({ t }: { t: T }) => [ @@ -125,6 +130,14 @@ const INITIAL_STATE = { class SendModal extends PureComponent> { state = INITIAL_STATE STEPS = createSteps({ t: this.props.t }) + _signTransactionSub = null + _isUnmounted = false + + componentWillUnmount() { + if (this._signTransactionSub) { + this._signTransactionSub.unsubscribe() + } + } handleReset = () => this.setState({ ...INITIAL_STATE }) @@ -173,6 +186,37 @@ class SendModal extends PureComponent> { this.setState({ optimisticOperation, error: null }) } + handleSignTransaction = async ({ transitionTo }: { transitionTo: string => void }) => { + const { device } = this.props + const { account, transaction, bridge } = this.state + + invariant(device && account && transaction && bridge, 'signTransaction invalid conditions') + + this._signTransactionSub = bridge + .signAndBroadcast(account, transaction, device.path) + .subscribe({ + next: e => { + switch (e.type) { + case 'signed': { + if (this._isUnmounted) return + transitionTo('confirmation') + break + } + case 'broadcasted': { + this.handleOperationBroadcasted(e.operation) + break + } + default: + } + }, + error: err => { + const error = err.statusCode === 0x6985 ? new UserRefusedOnDevice() : err + this.handleTransactionError(error) + transitionTo('confirmation') + }, + }) + } + render() { const { t, device } = this.props const { @@ -199,9 +243,8 @@ class SendModal extends PureComponent> { onChangeAccount: this.handleChangeAccount, onChangeAppOpened: this.handleChangeAppOpened, onChangeTransaction: this.handleChangeTransaction, - onTransactionError: this.handleTransactionError, onRetry: this.handleRetry, - onOperationBroadcasted: this.handleOperationBroadcasted, + signTransaction: this.handleSignTransaction, } const isModalLocked = stepId === 'verification' diff --git a/src/components/modals/Send/steps/03-step-verification.js b/src/components/modals/Send/steps/03-step-verification.js index 7299ee2c..37ae9a0c 100644 --- a/src/components/modals/Send/steps/03-step-verification.js +++ b/src/components/modals/Send/steps/03-step-verification.js @@ -1,11 +1,9 @@ // @flow -import invariant from 'invariant' import React, { PureComponent } from 'react' import styled from 'styled-components' import { multiline } from 'styles/helpers' -import { createCustomErrorClass } from 'helpers/errors' import TrackPage from 'analytics/TrackPage' import Box from 'components/base/Box' @@ -14,8 +12,6 @@ import DeviceConfirm from 'components/DeviceConfirm' import type { StepProps } from '../index' -export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') - const Container = styled(Box).attrs({ alignItems: 'center', fontSize: 4, pb: 4 })`` const Info = styled(Box).attrs({ ff: 'Open Sans|SemiBold', color: 'dark', mt: 6, mb: 4, px: 5 })` text-align: center; @@ -26,51 +22,13 @@ export default class StepVerification extends PureComponent> { this.signTransaction() } - componentWillUnmount() { - this._isUnmounted = true - if (this._signTransactionSub) { - this._signTransactionSub.unsubscribe() - } - } - - _isUnmounted = false - _signTransactionSub = null - signTransaction = async () => { - const { - device, - account, - transaction, - bridge, - onTransactionError, - transitionTo, - onOperationBroadcasted, - } = this.props - invariant(device && account && transaction && bridge, 'signTransaction invalid conditions') - this._signTransactionSub = bridge - .signAndBroadcast(account, transaction, device.path) - .subscribe({ - next: e => { - switch (e.type) { - case 'signed': { - if (this._isUnmounted) return - transitionTo('confirmation') - break - } - case 'broadcasted': { - onOperationBroadcasted(e.operation) - break - } - default: - } - }, - error: err => { - const error = err.statusCode === 0x6985 ? new UserRefusedOnDevice() : err - onTransactionError(error) - transitionTo('confirmation') - }, - }) + const { transitionTo } = this.props + // TODO: not very good pattern to pass transitionTo... Stepper needs to be + // controlled + this.props.signTransaction({ transitionTo }) } + render() { const { t } = this.props return (