diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index ac8f1ad3..ee59d816 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -1,13 +1,8 @@ /* @flow */ import * as ACCOUNT from 'actions/constants/account'; -import * as NOTIFICATION from 'actions/constants/notification'; -import type { Action, AsyncAction, TrezorDevice, Network, Dispatch, GetState } from 'flowtype'; +import type { Action } from 'flowtype'; import type { Account, State } from 'reducers/AccountsReducer'; -import * as BlockchainActions from 'actions/ethereum/BlockchainActions'; -import * as LocalStorageActions from 'actions/LocalStorageActions'; -import TrezorConnect from 'trezor-connect'; -import { toDecimalAmount } from 'utils/formatUtils'; export type AccountAction = | { @@ -23,119 +18,3 @@ export const update = (account: Account): Action => ({ type: ACCOUNT.UPDATE, payload: account, }); - -export const importAddress = ( - address: string, - network: Network, - device: ?TrezorDevice -): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { - if (!device) return; - - let payload; - const index = getState().accounts.filter( - a => - a.imported === true && - a.network === network.shortcut && - device && - a.deviceState === device.state - ).length; - - try { - if (network.type === 'ethereum') { - const account = await dispatch( - BlockchainActions.discoverAccount(device, address, network.shortcut) - ); - - const empty = account.nonce <= 0 && account.balance === '0'; - payload = { - imported: true, - index, - network: network.shortcut, - deviceID: device.features ? device.features.device_id : '0', - deviceState: device.state || '0', - accountPath: account.path || [], - descriptor: account.descriptor, - - balance: account.balance, - availableBalance: account.balance, - block: account.block, - transactions: account.transactions, - empty, - - networkType: 'ethereum', - nonce: account.nonce, - }; - dispatch({ - type: ACCOUNT.CREATE, - payload, - }); - dispatch(LocalStorageActions.setImportedAccount(payload)); - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'success', - title: 'The account has been successfully imported', - cancelable: true, - }, - }); - } else if (network.type === 'ripple') { - const response = await TrezorConnect.rippleGetAccountInfo({ - account: { - descriptor: address, - }, - coin: network.shortcut, - }); - - // handle TREZOR response error - if (!response.success) { - throw new Error(response.payload.error); - } - - const account = response.payload; - const empty = account.sequence <= 0 && account.balance === '0'; - - payload = { - imported: true, - index, - network: network.shortcut, - deviceID: device.features ? device.features.device_id : '0', - deviceState: device.state || '0', - accountPath: account.path || [], - descriptor: account.descriptor, - - balance: toDecimalAmount(account.balance, network.decimals), - availableBalance: toDecimalAmount(account.availableBalance, network.decimals), - block: account.block, - transactions: account.transactions, - empty, - - networkType: 'ripple', - sequence: account.sequence, - reserve: toDecimalAmount(account.reserve, network.decimals), - }; - dispatch({ - type: ACCOUNT.CREATE, - payload, - }); - dispatch(LocalStorageActions.setImportedAccount(payload)); - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'success', - title: 'The account has been successfully imported', - cancelable: true, - }, - }); - } - } catch (error) { - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Import account error', - message: error.message, - cancelable: true, - }, - }); - } -}; diff --git a/src/actions/ImportAccountActions.js b/src/actions/ImportAccountActions.js new file mode 100644 index 00000000..ff6c24fe --- /dev/null +++ b/src/actions/ImportAccountActions.js @@ -0,0 +1,153 @@ +/* @flow */ + +import * as ACCOUNT from 'actions/constants/account'; +import * as IMPORT from 'actions/constants/importAccount'; +import * as NOTIFICATION from 'actions/constants/notification'; +import type { AsyncAction, TrezorDevice, Network, Dispatch, GetState } from 'flowtype'; +import * as BlockchainActions from 'actions/ethereum/BlockchainActions'; +import * as LocalStorageActions from 'actions/LocalStorageActions'; +import TrezorConnect from 'trezor-connect'; +import { toDecimalAmount } from 'utils/formatUtils'; + +export type ImportAccountAction = + | { + type: typeof IMPORT.START, + } + | { + type: typeof IMPORT.SUCCESS, + } + | { + type: typeof IMPORT.FAIL, + error: ?string, + }; + +export const importAddress = ( + address: string, + network: Network, + device: ?TrezorDevice +): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + if (!device) return; + + dispatch({ + type: IMPORT.START, + }); + + let payload; + const index = getState().accounts.filter( + a => + a.imported === true && + a.network === network.shortcut && + device && + a.deviceState === device.state + ).length; + + try { + if (network.type === 'ethereum') { + const account = await dispatch( + BlockchainActions.discoverAccount(device, address, network.shortcut) + ); + + const empty = account.nonce <= 0 && account.balance === '0'; + payload = { + imported: true, + index, + network: network.shortcut, + deviceID: device.features ? device.features.device_id : '0', + deviceState: device.state || '0', + accountPath: account.path || [], + descriptor: account.descriptor, + + balance: account.balance, + availableBalance: account.balance, + block: account.block, + transactions: account.transactions, + empty, + + networkType: 'ethereum', + nonce: account.nonce, + }; + dispatch({ + type: ACCOUNT.CREATE, + payload, + }); + dispatch({ + type: IMPORT.SUCCESS, + }); + dispatch(LocalStorageActions.setImportedAccount(payload)); + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'success', + title: 'The account has been successfully imported', + cancelable: true, + }, + }); + } else if (network.type === 'ripple') { + const response = await TrezorConnect.rippleGetAccountInfo({ + account: { + descriptor: address, + }, + coin: network.shortcut, + }); + + // handle TREZOR response error + if (!response.success) { + throw new Error(response.payload.error); + } + + const account = response.payload; + const empty = account.sequence <= 0 && account.balance === '0'; + + payload = { + imported: true, + index, + network: network.shortcut, + deviceID: device.features ? device.features.device_id : '0', + deviceState: device.state || '0', + accountPath: account.path || [], + descriptor: account.descriptor, + + balance: toDecimalAmount(account.balance, network.decimals), + availableBalance: toDecimalAmount(account.availableBalance, network.decimals), + block: account.block, + transactions: account.transactions, + empty, + + networkType: 'ripple', + sequence: account.sequence, + reserve: toDecimalAmount(account.reserve, network.decimals), + }; + dispatch({ + type: ACCOUNT.CREATE, + payload, + }); + dispatch({ + type: IMPORT.SUCCESS, + }); + dispatch(LocalStorageActions.setImportedAccount(payload)); + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'success', + title: 'The account has been successfully imported', + cancelable: true, + }, + }); + } + } catch (error) { + dispatch({ + type: IMPORT.FAIL, + error: error.message, + }); + + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Import account error', + message: error.message, + cancelable: true, + }, + }); + } +}; diff --git a/src/actions/constants/importAccount.js b/src/actions/constants/importAccount.js new file mode 100644 index 00000000..ac5fd498 --- /dev/null +++ b/src/actions/constants/importAccount.js @@ -0,0 +1,5 @@ +/* @flow */ + +export const START: 'import__account__start' = 'import__account__start'; +export const SUCCESS: 'import__account__success' = 'import__account__success'; +export const FAIL: 'import__account__fail' = 'import__account__fail'; diff --git a/src/flowtype/index.js b/src/flowtype/index.js index be8638cf..f7b26df4 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -32,6 +32,7 @@ import type { TokenAction } from 'actions/TokenActions'; import type { TrezorConnectAction } from 'actions/TrezorConnectActions'; import type { WalletAction } from 'actions/WalletActions'; import type { Web3Action } from 'actions/Web3Actions'; +import type { ImportAccountAction } from 'actions/ImportAccountActions'; import type { FiatRateAction } from 'services/CoingeckoService'; // this service has no action file, all is written inside one file import type { @@ -142,7 +143,8 @@ export type Action = | TrezorConnectAction | WalletAction | Web3Action - | FiatRateAction; + | FiatRateAction + | ImportAccountAction; export type State = ReducersState; diff --git a/src/reducers/ImportAccountReducer.js b/src/reducers/ImportAccountReducer.js new file mode 100644 index 00000000..7ecd5e59 --- /dev/null +++ b/src/reducers/ImportAccountReducer.js @@ -0,0 +1,43 @@ +/* @flow */ + +import * as IMPORT from 'actions/constants/importAccount'; + +import type { Action } from 'flowtype'; + +export type ImportState = { + loading: boolean, + error: ?string, +}; + +export const initialState: ImportState = { + loading: false, + error: null, +}; + +export default (state: ImportState = initialState, action: Action): ImportState => { + switch (action.type) { + case IMPORT.START: + return { + ...state, + loading: true, + error: null, + }; + + case IMPORT.SUCCESS: + return { + ...state, + loading: false, + error: null, + }; + + case IMPORT.FAIL: + return { + ...state, + loading: false, + error: action.error, + }; + + default: + return state; + } +}; diff --git a/src/reducers/index.js b/src/reducers/index.js index e51fb473..4b89da1b 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -10,6 +10,7 @@ import notifications from 'reducers/NotificationReducer'; import modal from 'reducers/ModalReducer'; import web3 from 'reducers/Web3Reducer'; import accounts from 'reducers/AccountsReducer'; +import importAccount from 'reducers/ImportAccountReducer'; import selectedAccount from 'reducers/SelectedAccountReducer'; import sendFormEthereum from 'reducers/SendFormEthereumReducer'; import sendFormRipple from 'reducers/SendFormRippleReducer'; @@ -31,6 +32,7 @@ const reducers = { notifications, modal, web3, + importAccount, accounts, selectedAccount, sendFormEthereum, diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 1f185f71..3e2674ae 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -88,7 +88,7 @@ const Col = styled.div` display: flex; flex: 1; flex-direction: column; -` +`; const RightCol = styled(Col)` justify-content: center; diff --git a/src/views/Wallet/views/Import/Container.js b/src/views/Wallet/views/Import/Container.js index 1759aa51..c5987d90 100644 --- a/src/views/Wallet/views/Import/Container.js +++ b/src/views/Wallet/views/Import/Container.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import * as AccountsAction from 'actions/AccountsActions'; +import * as ImportAccountActions from 'actions/ImportAccountActions'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; import type { TrezorDevice, Config, State, Dispatch } from 'flowtype'; @@ -10,12 +10,13 @@ import ImportView from './index'; export type StateProps = { device: ?TrezorDevice, + importAccount: $ElementType, config: Config, children?: React.Node, }; type DispatchProps = { - importAddress: typeof AccountsAction.importAddress, + importAddress: typeof ImportAccountActions.importAddress, }; type OwnProps = {}; @@ -27,12 +28,13 @@ const mapStateToProps: MapStateToProps = ( ): StateProps => ({ config: state.localStorage.config, device: state.wallet.selectedDevice, + importAccount: state.importAccount, }); const mapDispatchToProps: MapDispatchToProps = ( dispatch: Dispatch ): DispatchProps => ({ - importAddress: bindActionCreators(AccountsAction.importAddress, dispatch), + importAddress: bindActionCreators(ImportAccountActions.importAddress, dispatch), }); export default connect( diff --git a/src/views/Wallet/views/Import/index.js b/src/views/Wallet/views/Import/index.js index 4216a1ba..0ba3f79c 100644 --- a/src/views/Wallet/views/Import/index.js +++ b/src/views/Wallet/views/Import/index.js @@ -83,7 +83,9 @@ const Import = (props: Props) => {