From e59c9ec7140586abcfb0267947a1412e98f5bf2a Mon Sep 17 00:00:00 2001 From: Szymon Lesisz Date: Thu, 11 Oct 2018 13:06:16 +0200 Subject: [PATCH] refacotred modals components --- src/components/modals/Container.js | 55 ++++ .../modals/confirm/Address/index.js | 13 +- src/components/modals/confirm/SignTx/index.js | 26 +- .../modals/confirm/UnverifiedAddress/index.js | 49 ++-- .../modals/device/Duplicate/index.js | 51 ++-- src/components/modals/device/Forget/index.js | 28 +- .../modals/device/Remember/index.js | 36 ++- .../modals/device/WalletType/index.js | 33 ++- .../modals/external/NemWallet/index.js | 41 +-- src/components/modals/index.js | 243 +++++++++--------- .../modals/passphrase/Passphrase/index.js | 30 ++- .../modals/passphrase/Type/index.js | 43 ++-- src/components/modals/pin/Invalid/index.js | 26 +- src/components/modals/pin/Pin/index.js | 28 +- src/views/Wallet/index.js | 2 +- 15 files changed, 440 insertions(+), 264 deletions(-) create mode 100644 src/components/modals/Container.js diff --git a/src/components/modals/Container.js b/src/components/modals/Container.js new file mode 100644 index 00000000..62944a43 --- /dev/null +++ b/src/components/modals/Container.js @@ -0,0 +1,55 @@ +/* @flow */ +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; + +import ModalActions from 'actions/ModalActions'; +import ReceiveActions from 'actions/ReceiveActions'; + +import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; +import type { State, Dispatch } from 'flowtype'; + +import Modal from './index'; + +type OwnProps = { } + +type StateProps = { + modal: $ElementType, + accounts: $ElementType, + devices: $ElementType, + connect: $ElementType, + selectedAccount: $ElementType, + sendForm: $ElementType, + receive: $ElementType, + localStorage: $ElementType, + wallet: $ElementType, +} + +type DispatchProps = { + modalActions: typeof ModalActions, + receiveActions: typeof ReceiveActions, +} + +export type Props = StateProps & DispatchProps; + +const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ + modal: state.modal, + accounts: state.accounts, + devices: state.devices, + connect: state.connect, + selectedAccount: state.selectedAccount, + sendForm: state.sendForm, + receive: state.receive, + localStorage: state.localStorage, + wallet: state.wallet, +}); + +const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ + modalActions: bindActionCreators(ModalActions, dispatch), + receiveActions: bindActionCreators(ReceiveActions, dispatch), +}); + +// export default connect(mapStateToProps, mapDispatchToProps)(Modal); +export default withRouter( + connect(mapStateToProps, mapDispatchToProps)(Modal), +); \ No newline at end of file diff --git a/src/components/modals/confirm/Address/index.js b/src/components/modals/confirm/Address/index.js index b3b4958f..9581561d 100644 --- a/src/components/modals/confirm/Address/index.js +++ b/src/components/modals/confirm/Address/index.js @@ -1,13 +1,16 @@ /* @flow */ import React from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; -import H3 from 'components/Heading'; + import colors from 'config/colors'; -import P from 'components/Paragraph'; import { FONT_SIZE } from 'config/variables'; -import type { Props } from '../../index'; +import H3 from 'components/Heading'; +import P from 'components/Paragraph'; + +import type { Props } from '../../Container'; const Wrapper = styled.div` width: 390px; @@ -49,4 +52,8 @@ const ConfirmAddress = (props: Props) => { ); }; +ConfirmAddress.propTypes = { + selectedAccount: PropTypes.object.isRequired, +}; + export default ConfirmAddress; \ No newline at end of file diff --git a/src/components/modals/confirm/SignTx/index.js b/src/components/modals/confirm/SignTx/index.js index 2e51d2d2..4668979f 100644 --- a/src/components/modals/confirm/SignTx/index.js +++ b/src/components/modals/confirm/SignTx/index.js @@ -1,16 +1,24 @@ /* @flow */ import React from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + +import icons from 'config/icons'; import colors from 'config/colors'; +import { LINE_HEIGHT } from 'config/variables'; + import P from 'components/Paragraph'; import Icon from 'components/Icon'; -import icons from 'config/icons'; import { H3 } from 'components/Heading'; -import { LINE_HEIGHT } from 'config/variables'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + sendForm: $ElementType; +} const Wrapper = styled.div` width: 390px; @@ -40,9 +48,6 @@ const Label = styled.div` `; const ConfirmSignTx = (props: Props) => { - if (props.modal.context !== CONTEXT_DEVICE) return null; - const { device } = props.modal; - const { amount, address, @@ -54,7 +59,7 @@ const ConfirmSignTx = (props: Props) => {
-

Confirm transaction on { device.label } device

+

Confirm transaction on { props.device.label } device

Details are shown on display

@@ -69,4 +74,9 @@ const ConfirmSignTx = (props: Props) => { ); }; +ConfirmSignTx.propTypes = { + device: PropTypes.object.isRequired, + sendForm: PropTypes.object.isRequired, +}; + export default ConfirmSignTx; \ No newline at end of file diff --git a/src/components/modals/confirm/UnverifiedAddress/index.js b/src/components/modals/confirm/UnverifiedAddress/index.js index 1c933742..992d3325 100644 --- a/src/components/modals/confirm/UnverifiedAddress/index.js +++ b/src/components/modals/confirm/UnverifiedAddress/index.js @@ -1,16 +1,27 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; + +import icons from 'config/icons'; +import colors from 'config/colors'; + import { H2 } from 'components/Heading'; import P from 'components/Paragraph'; -import styled from 'styled-components'; import Icon from 'components/Icon'; -import colors from 'config/colors'; -import icons from 'config/icons'; import Button from 'components/Button'; import Link from 'components/Link'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + account: $ElementType<$ElementType, 'account'>; + showAddress: $ElementType<$ElementType, 'showAddress'>; + showUnverifiedAddress: $ElementType<$ElementType, 'showUnverifiedAddress'>; + onCancel: $ElementType<$ElementType, 'onCancel'>; +} const StyledLink = styled(Link)` position: absolute; @@ -57,24 +68,20 @@ class ConfirmUnverifiedAddress extends PureComponent { } verifyAddress() { - const { account } = this.props.selectedAccount; + const { account, onCancel, showAddress } = this.props; if (!account) return; - this.props.modalActions.onCancel(); - this.props.receiveActions.showAddress(account.addressPath); + onCancel(); + showAddress(account.addressPath); } showUnverifiedAddress() { - this.props.modalActions.onCancel(); - this.props.receiveActions.showUnverifiedAddress(); + const { onCancel, showUnverifiedAddress } = this.props; + onCancel(); + showUnverifiedAddress(); } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - const { device } = this.props.modal; - - const { - onCancel, - } = this.props.modalActions; + const { device, account, onCancel } = this.props; let deviceStatus: string; let claim: string; @@ -97,7 +104,7 @@ class ConfirmUnverifiedAddress extends PureComponent {

{ deviceStatus }

To prevent phishing attacks, you should verify the address on your TREZOR first. { claim } to continue with the verification process. - (!this.props.selectedAccount.account ? this.verifyAddress() : 'false')}>Try again + (!account ? this.verifyAddress() : 'false')}>Try again this.showUnverifiedAddress()}>Show unverified address
@@ -105,4 +112,12 @@ class ConfirmUnverifiedAddress extends PureComponent { } } +ConfirmUnverifiedAddress.propTypes = { + device: PropTypes.object.isRequired, + account: PropTypes.object.isRequired, + showAddress: PropTypes.func.isRequired, + showUnverifiedAddress: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + export default ConfirmUnverifiedAddress; \ No newline at end of file diff --git a/src/components/modals/device/Duplicate/index.js b/src/components/modals/device/Duplicate/index.js index ae9598b7..03e5e007 100644 --- a/src/components/modals/device/Duplicate/index.js +++ b/src/components/modals/device/Duplicate/index.js @@ -1,19 +1,30 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + +import icons from 'config/icons'; +import colors from 'config/colors'; +import { FONT_SIZE } from 'config/variables'; + import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; import Button from 'components/Button'; import Input from 'components/inputs/Input'; -import { getDuplicateInstanceNumber } from 'reducers/utils'; -import { FONT_SIZE } from 'config/variables'; import Icon from 'components/Icon'; -import icons from 'config/icons'; -import colors from 'config/colors'; import Link from 'components/Link'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from 'components/modals/index'; +import { getDuplicateInstanceNumber } from 'reducers/utils'; + +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + devices: $ElementType; + onDuplicateDevice: $ElementType<$ElementType, 'onDuplicateDevice'>; + onCancel: $ElementType<$ElementType, 'onCancel'>; +} type State = { defaultName: string; @@ -63,17 +74,14 @@ const ErrorMessage = styled.div` width: 100%; `; -export default class DuplicateDevice extends PureComponent { +class DuplicateDevice extends PureComponent { constructor(props: Props) { super(props); - if (props.modal.context !== CONTEXT_DEVICE) return; - const { device } = props.modal; - - const instance = getDuplicateInstanceNumber(props.devices, device); + const instance = getDuplicateInstanceNumber(props.devices, props.device); this.state = { - defaultName: `${device.label} (${instance.toString()})`, + defaultName: `${props.device.label} (${instance.toString()})`, instance, instanceName: null, isUsed: false, @@ -115,16 +123,12 @@ export default class DuplicateDevice extends PureComponent { keyboardHandler: (event: KeyboardEvent) => void; submit() { - if (this.props.modal.context !== CONTEXT_DEVICE) return; const extended: Object = { instanceName: this.state.instanceName, instance: this.state.instance }; - this.props.modalActions.onDuplicateDevice({ ...this.props.modal.device, ...extended }); + this.props.onDuplicateDevice({ ...this.props.device, ...extended }); } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - - const { device } = this.props.modal; - const { onCancel } = this.props.modalActions; + const { device, onCancel } = this.props; const { defaultName, instanceName, @@ -168,4 +172,13 @@ export default class DuplicateDevice extends PureComponent { ); } -} \ No newline at end of file +} + +DuplicateDevice.propTypes = { + device: PropTypes.object.isRequired, + devices: PropTypes.array.isRequired, + onDuplicateDevice: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + +export default DuplicateDevice; \ No newline at end of file diff --git a/src/components/modals/device/Forget/index.js b/src/components/modals/device/Forget/index.js index 13ac34bf..d20702ca 100644 --- a/src/components/modals/device/Forget/index.js +++ b/src/components/modals/device/Forget/index.js @@ -1,13 +1,21 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; import Button from 'components/Button'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + onForgetSingleDevice: $ElementType<$ElementType, 'onForgetSingleDevice'>; + onCancel: $ElementType<$ElementType, 'onCancel'>; +} const Wrapper = styled.div` width: 360px; @@ -48,25 +56,27 @@ class ForgetDevice extends PureComponent { keyboardHandler: (event: KeyboardEvent) => void; forget() { - if (this.props.modal.context !== CONTEXT_DEVICE) return; - this.props.modalActions.onForgetSingleDevice(this.props.modal.device); + this.props.onForgetSingleDevice(this.props.device); } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - const { device } = this.props.modal; - const { onCancel } = this.props.modalActions; return ( -

Forget { device.instanceLabel }?

+

Forget { this.props.device.instanceLabel }?

Forgetting only removes the device from the list on the left, your coins are still safe and you can access them by reconnecting your TREZOR again. this.forget()}>Forget - Don't forget + Don't forget
); } } +ForgetDevice.propTypes = { + device: PropTypes.object.isRequired, + onForgetSingleDevice: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + export default ForgetDevice; \ No newline at end of file diff --git a/src/components/modals/device/Remember/index.js b/src/components/modals/device/Remember/index.js index e0aab298..937e04bc 100644 --- a/src/components/modals/device/Remember/index.js +++ b/src/components/modals/device/Remember/index.js @@ -1,13 +1,22 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; import Loader from 'components/Loader'; import Button from 'components/Button'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + instances: ?Array; + onRememberDevice: $ElementType<$ElementType, 'onRememberDevice'>; + onForgetDevice: $ElementType<$ElementType, 'onForgetDevice'>; +} type State = { countdown: number; @@ -48,7 +57,7 @@ const StyledLoader = styled(Loader)` left: 200px; `; -export default class RememberDevice extends PureComponent { +class RememberDevice extends PureComponent { constructor(props: Props) { super(props); @@ -63,8 +72,7 @@ export default class RememberDevice extends PureComponent { // TODO: possible race condition, // device could be already connected but it didn't emit Device.CONNECT event yet window.clearInterval(this.state.ticker); - if (this.props.modal.context !== CONTEXT_DEVICE) return; - this.props.modalActions.onForgetDevice(this.props.modal.device); + this.props.onForgetDevice(this.props.device); } else { this.setState(previousState => ({ countdown: previousState.countdown - 1, @@ -98,14 +106,11 @@ export default class RememberDevice extends PureComponent { keyboardHandler: (event: KeyboardEvent) => void; forget() { - if (this.props.modal.context !== CONTEXT_DEVICE) return; - this.props.modalActions.onForgetDevice(this.props.modal.device); + this.props.onForgetDevice(this.props.device); } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - const { device, instances } = this.props.modal; - const { onRememberDevice } = this.props.modalActions; + const { device, instances, onRememberDevice } = this.props; let { label } = device; const devicePlural: string = instances && instances.length > 1 ? 'devices or to remember them' : 'device or to remember it'; @@ -143,4 +148,13 @@ export default class RememberDevice extends PureComponent { ); } -} \ No newline at end of file +} + +RememberDevice.propTypes = { + device: PropTypes.object.isRequired, + instances: PropTypes.array.isRequired, + onRememberDevice: PropTypes.func.isRequired, + onForgetDevice: PropTypes.func.isRequired, +}; + +export default RememberDevice; \ No newline at end of file diff --git a/src/components/modals/device/WalletType/index.js b/src/components/modals/device/WalletType/index.js index 5f4e44b7..eb11b8a9 100644 --- a/src/components/modals/device/WalletType/index.js +++ b/src/components/modals/device/WalletType/index.js @@ -1,19 +1,28 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; + +import icons from 'config/icons'; +import colors from 'config/colors'; + import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; import Button from 'components/Button'; import Tooltip from 'components/Tooltip'; import Icon from 'components/Icon'; import Link from 'components/Link'; -import colors from 'config/colors'; -import icons from 'config/icons'; import WalletTypeIcon from 'components/images/WalletType'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from 'components/modals/index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + onWalletTypeRequest: $ElementType<$ElementType, 'onWalletTypeRequest'>; + onCancel: $ElementType<$ElementType, 'onCancel'>; +} const Wrapper = styled.div` width: 360px; @@ -89,15 +98,11 @@ class WalletType extends PureComponent { keyboardHandler: (event: KeyboardEvent) => void; changeType(hidden: boolean, state: ?string) { - const { modal } = this.props; - if (modal.context !== CONTEXT_DEVICE) return; - this.props.modalActions.onWalletTypeRequest(modal.device, hidden, state); + this.props.onWalletTypeRequest(this.props.device, hidden, state); } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - const { device } = this.props.modal; - const { onCancel } = this.props.modalActions; + const { device, onCancel } = this.props; return ( @@ -110,7 +115,7 @@ class WalletType extends PureComponent { /> )} - Change wallet type for { device.instanceLabel } + { device.state ? 'Change' : 'Select' } wallet type for { device.instanceLabel }
@@ -148,4 +153,10 @@ class WalletType extends PureComponent { } } +WalletType.propTypes = { + device: PropTypes.object.isRequired, + onWalletTypeRequest: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + export default WalletType; \ No newline at end of file diff --git a/src/components/modals/external/NemWallet/index.js b/src/components/modals/external/NemWallet/index.js index a461e5c5..8d5fbdfe 100644 --- a/src/components/modals/external/NemWallet/index.js +++ b/src/components/modals/external/NemWallet/index.js @@ -11,7 +11,11 @@ import Link from 'components/Link'; import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; -import type { Props } from 'components/modals/index'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + onCancel: $ElementType<$ElementType, 'onCancel'>; +} const Wrapper = styled.div` width: 360px; @@ -26,24 +30,21 @@ const StyledLink = styled(Link)` top: 10px; `; -const Confirmation = (props: Props) => { - const { onCancel } = props.modalActions; - return ( - - - - -
- -

NEM Wallet

-

If you enter a wrong passphrase, you will not unlock the desired hidden wallet.

-
-
- ); -}; +const Confirmation = (props: Props) => ( + + + + +
+ +

NEM Wallet

+

If you enter a wrong passphrase, you will not unlock the desired hidden wallet.

+
+
+); export default Confirmation; \ No newline at end of file diff --git a/src/components/modals/index.js b/src/components/modals/index.js index 890a271e..54e37ae8 100644 --- a/src/components/modals/index.js +++ b/src/components/modals/index.js @@ -1,67 +1,39 @@ /* @flow */ + import * as React from 'react'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { withRouter } from 'react-router-dom'; +import { CSSTransition } from 'react-transition-group'; + import styled from 'styled-components'; import colors from 'config/colors'; -import { CSSTransition } from 'react-transition-group'; import { UI } from 'trezor-connect'; - -import ModalActions from 'actions/ModalActions'; -import ReceiveActions from 'actions/ReceiveActions'; - import * as MODAL from 'actions/constants/modal'; import * as RECEIVE from 'actions/constants/receive'; import * as CONNECT from 'actions/constants/TrezorConnect'; -import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; -import type { State, Dispatch } from 'flowtype'; +// device context import Pin from 'components/modals/pin/Pin'; import InvalidPin from 'components/modals/pin/Invalid'; - import Passphrase from 'components/modals/passphrase/Passphrase'; import PassphraseType from 'components/modals/passphrase/Type'; - import ConfirmSignTx from 'components/modals/confirm/SignTx'; import ConfirmUnverifiedAddress from 'components/modals/confirm/UnverifiedAddress'; - import ForgetDevice from 'components/modals/device/Forget'; import RememberDevice from 'components/modals/device/Remember'; import DuplicateDevice from 'components/modals/device/Duplicate'; import WalletType from 'components/modals/device/WalletType'; +// external context import NemWallet from 'components/modals/external/NemWallet'; -type OwnProps = { } - -type StateProps = { - modal: $ElementType, - accounts: $ElementType, - devices: $ElementType, - connect: $ElementType, - selectedAccount: $ElementType, - sendForm: $ElementType, - receive: $ElementType, - localStorage: $ElementType, - wallet: $ElementType, -} - -type DispatchProps = { - modalActions: typeof ModalActions, - receiveActions: typeof ReceiveActions, -} - -export type Props = StateProps & DispatchProps; +import type { Props } from './Container'; const Fade = (props: { children: React.Node}) => ( - { props.children } + >{ props.children } ); @@ -88,85 +60,124 @@ const ModalWindow = styled.div` text-align: center; `; -class Modal extends React.PureComponent { - render() { - if (this.props.modal.context === MODAL.CONTEXT_NONE) return null; - - const { windowType } = this.props.modal; - let component = null; - switch (windowType) { - case UI.REQUEST_PIN: - component = (); - break; - case UI.INVALID_PIN: - component = (); - break; - case UI.REQUEST_PASSPHRASE: - component = (); - break; - case 'ButtonRequest_SignTx': - component = (); - break; - case 'ButtonRequest_PassphraseType': - component = (); - break; - case RECEIVE.REQUEST_UNVERIFIED: - component = (); - break; - - case CONNECT.REMEMBER_REQUEST: - component = (); - break; - - case CONNECT.FORGET_REQUEST: - component = (); - break; - - case CONNECT.TRY_TO_DUPLICATE: - component = (); - break; - - case CONNECT.REQUEST_WALLET_TYPE: - component = (); - break; - - case 'xem': - component = (); - break; - default: - component = null; - } - - return ( - - - - { component } - - - - ); +// get modal component with device context +const getDeviceContextModal = (props: Props) => { + const { modal, modalActions } = props; + if (modal.context !== MODAL.CONTEXT_DEVICE) return null; + + switch (modal.windowType) { + case UI.REQUEST_PIN: + return ( + ); + + case UI.INVALID_PIN: + return ; + + case UI.REQUEST_PASSPHRASE: + return ( + ); + + case 'ButtonRequest_PassphraseType': + return ; + + case 'ButtonRequest_SignTx': + return ; + + case RECEIVE.REQUEST_UNVERIFIED: + return ( + ); + + case CONNECT.REMEMBER_REQUEST: + return ( + ); + + case CONNECT.FORGET_REQUEST: + return ( + ); + + case CONNECT.TRY_TO_DUPLICATE: + return ( + ); + + case CONNECT.REQUEST_WALLET_TYPE: + return ( + ); + + default: + return null; } -} - -const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ - modal: state.modal, - accounts: state.accounts, - devices: state.devices, - connect: state.connect, - selectedAccount: state.selectedAccount, - sendForm: state.sendForm, - receive: state.receive, - localStorage: state.localStorage, - wallet: state.wallet, -}); - -const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ - modalActions: bindActionCreators(ModalActions, dispatch), - receiveActions: bindActionCreators(ReceiveActions, dispatch), -}); - -// export default connect(mapStateToProps, mapDispatchToProps)(Modal); -export default withRouter( - connect(mapStateToProps, mapDispatchToProps)(Modal), -); +}; + +// get modal component with external context +const getExternalContextModal = (props: Props) => { + const { modal, modalActions } = props; + if (modal.context !== MODAL.CONTEXT_EXTERNAL_WALLET) return null; + + switch (modal.windowType) { + case 'xem': + return (); + default: + return null; + } +}; + +// modal container component +const Modal = (props: Props) => { + const { modal } = props; + if (modal.context === MODAL.CONTEXT_NONE) return null; + + let component = null; + switch (modal.context) { + case MODAL.CONTEXT_DEVICE: + component = getDeviceContextModal(props); + break; + case MODAL.CONTEXT_EXTERNAL_WALLET: + component = getExternalContextModal(props); + break; + default: + break; + } + + return ( + + + + { component } + + + + ); +}; + +export default Modal; diff --git a/src/components/modals/passphrase/Passphrase/index.js b/src/components/modals/passphrase/Passphrase/index.js index 1a397175..79137762 100644 --- a/src/components/modals/passphrase/Passphrase/index.js +++ b/src/components/modals/passphrase/Passphrase/index.js @@ -1,16 +1,25 @@ /* @flow */ import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + import colors from 'config/colors'; import { FONT_SIZE, TRANSITION } from 'config/variables'; + import { H2 } from 'components/Heading'; import P from 'components/Paragraph'; import Checkbox from 'components/Checkbox'; import Button from 'components/Button'; import Input from 'components/inputs/Input'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + selectedDevice: ?TrezorDevice; + onPassphraseSubmit: $ElementType<$ElementType, 'onPassphraseSubmit'>; +} type State = { deviceLabel: string, @@ -80,13 +89,10 @@ const LinkButton = styled(Button)` class Passphrase extends PureComponent { constructor(props: Props) { super(props); - - if (props.modal.context !== CONTEXT_DEVICE) return; - const { device } = props.modal; + const { device, selectedDevice } = props; // Check if this device is already known // if device is already known then only one input is presented - const { selectedDevice } = props.wallet; let deviceLabel = device.label; let shouldShowSingleInput = false; if (selectedDevice && selectedDevice.path === device.path) { @@ -104,8 +110,6 @@ class Passphrase extends PureComponent { }; } - state: State; - componentDidMount() { this.passphraseInput.focus(); @@ -179,7 +183,7 @@ class Passphrase extends PureComponent { } submitPassphrase(shouldLeavePassphraseBlank: boolean = false) { - const { onPassphraseSubmit } = this.props.modalActions; + const { onPassphraseSubmit } = this.props; const passphrase = this.state.passphraseInputValue; // Reset state so same passphrase isn't filled when the modal will be visible again @@ -203,8 +207,6 @@ class Passphrase extends PureComponent { } render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - return (

Enter {this.state.deviceLabel} passphrase

@@ -273,4 +275,10 @@ class Passphrase extends PureComponent { } } +Passphrase.propTypes = { + device: PropTypes.object.isRequired, + selectedDevice: PropTypes.object.isRequired, + onPassphraseSubmit: PropTypes.func.isRequired, +}; + export default Passphrase; \ No newline at end of file diff --git a/src/components/modals/passphrase/Type/index.js b/src/components/modals/passphrase/Type/index.js index bccdcb51..ce659800 100644 --- a/src/components/modals/passphrase/Type/index.js +++ b/src/components/modals/passphrase/Type/index.js @@ -1,15 +1,21 @@ /* @flow */ import React from 'react'; -import Icon from 'components/Icon'; -import colors from 'config/colors'; -import icons from 'config/icons'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + +import icons from 'config/icons'; +import colors from 'config/colors'; + +import Icon from 'components/Icon'; import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from 'components/modals/index'; +import type { TrezorDevice } from 'flowtype'; + +type Props = { + device: TrezorDevice; +} const Wrapper = styled.div` width: 360px; @@ -18,19 +24,18 @@ const Wrapper = styled.div` const Header = styled.div``; -const Confirmation = (props: Props) => { - if (props.modal.context !== CONTEXT_DEVICE) return null; - const { device } = props.modal; - - return ( - -
- -

Complete the action on { device.label } device

-

If you enter a wrong passphrase, you will not unlock the desired hidden wallet.

-
-
- ); +const PassphraseType = (props: Props) => ( + +
+ +

Complete the action on { props.device.label } device

+

If you enter a wrong passphrase, you will not unlock the desired hidden wallet.

+
+
+); + +PassphraseType.propTypes = { + device: PropTypes.object.isRequired, }; -export default Confirmation; \ No newline at end of file +export default PassphraseType; \ No newline at end of file diff --git a/src/components/modals/pin/Invalid/index.js b/src/components/modals/pin/Invalid/index.js index 71b81d5e..e69d7554 100644 --- a/src/components/modals/pin/Invalid/index.js +++ b/src/components/modals/pin/Invalid/index.js @@ -1,27 +1,31 @@ /* @flow */ import React from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; + import { H3 } from 'components/Heading'; import P from 'components/Paragraph'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; -import type { Props } from '../../index'; +import type { TrezorDevice } from 'flowtype'; + +type Props = { + device: TrezorDevice; +} const Wrapper = styled.div` padding: 24px 48px; `; -const InvalidPin = (props: Props) => { - if (props.modal.context !== CONTEXT_DEVICE) return null; +const InvalidPin = (props: Props) => ( + +

Entered PIN for { props.device.label } is not correct

+

Retrying...

+
+); - const { device } = props.modal; - return ( - -

Entered PIN for { device.label } is not correct

-

Retrying...

-
- ); +InvalidPin.propTypes = { + device: PropTypes.object.isRequired, }; export default InvalidPin; \ No newline at end of file diff --git a/src/components/modals/pin/Pin/index.js b/src/components/modals/pin/Pin/index.js index 1784184e..7a8eed98 100644 --- a/src/components/modals/pin/Pin/index.js +++ b/src/components/modals/pin/Pin/index.js @@ -1,15 +1,24 @@ /* @flow */ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; + import P from 'components/Paragraph'; import { H2 } from 'components/Heading'; -import React, { PureComponent } from 'react'; import Link from 'components/Link'; -import styled from 'styled-components'; import Button from 'components/Button'; -import { CONTEXT_DEVICE } from 'actions/constants/modal'; + +import type { TrezorDevice } from 'flowtype'; + import PinButton from './components/Button'; import PinInput from './components/Input'; -import type { Props } from '../../index'; +import type { Props as BaseProps } from '../../Container'; + +type Props = { + device: TrezorDevice; + onPinSubmit: $ElementType<$ElementType, 'onPinSubmit'>; +} type State = { pin: string; @@ -75,7 +84,7 @@ class Pin extends PureComponent { } keyboardHandler(event: KeyboardEvent): void { - const { onPinSubmit } = this.props.modalActions; + const { onPinSubmit } = this.props; const { pin } = this.state; event.preventDefault(); @@ -133,9 +142,7 @@ class Pin extends PureComponent { keyboardHandler: (event: KeyboardEvent) => void; render() { - if (this.props.modal.context !== CONTEXT_DEVICE) return null; - const { onPinSubmit } = this.props.modalActions; - const { device } = this.props.modal; + const { device, onPinSubmit } = this.props; const { pin } = this.state; return ( @@ -174,4 +181,9 @@ class Pin extends PureComponent { } } +Pin.propTypes = { + device: PropTypes.object.isRequired, + onPinSubmit: PropTypes.func.isRequired, +}; + export default Pin; \ No newline at end of file diff --git a/src/views/Wallet/index.js b/src/views/Wallet/index.js index 48eb27aa..78679df7 100644 --- a/src/views/Wallet/index.js +++ b/src/views/Wallet/index.js @@ -11,7 +11,7 @@ import type { State } from 'flowtype'; import Header from 'components/Header'; import Footer from 'components/Footer'; -import ModalContainer from 'components/modals'; +import ModalContainer from 'components/modals/Container'; import AppNotifications from 'components/notifications/App'; import ContextNotifications from 'components/notifications/Context';