From ba50db28812e86c2be72867addf4f4a2f7822574 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 3 Apr 2019 11:54:56 +0200 Subject: [PATCH 01/19] log account creation --- src/services/LogService.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/services/LogService.js b/src/services/LogService.js index ad797e3c..ee9d7d31 100644 --- a/src/services/LogService.js +++ b/src/services/LogService.js @@ -2,6 +2,7 @@ import * as LogActions from 'actions/LogActions'; import { TRANSPORT, DEVICE } from 'trezor-connect'; import * as DISCOVERY from 'actions/constants/discovery'; +import * as ACCOUNT from 'actions/constants/account'; import type { Middleware, MiddlewareAPI, MiddlewareDispatch, Action } from 'flowtype'; @@ -10,6 +11,7 @@ const actions: Array = [ DEVICE.CONNECT, DEVICE.DISCONNECT, DISCOVERY.START, + ACCOUNT.CREATE, ]; /** @@ -40,6 +42,9 @@ const LogService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch case DISCOVERY.START: api.dispatch(LogActions.add('Discovery started', action)); break; + case ACCOUNT.CREATE: + api.dispatch(LogActions.add('Account created', action)); + break; default: break; } From 096f24608dafcd461a24b9426ff42e0320179f6f Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 8 Apr 2019 11:59:07 +0200 Subject: [PATCH 02/19] more responsive pending tx --- src/components/Transaction/index.js | 20 +++++++++++++++---- .../components/PendingTransactions/index.js | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/components/Transaction/index.js b/src/components/Transaction/index.js index b36f2b52..2e035b2a 100644 --- a/src/components/Transaction/index.js +++ b/src/components/Transaction/index.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; - +import { SCREEN_SIZE } from 'config/variables'; import { Link, colors } from 'trezor-ui-components'; import type { Transaction, Network } from 'flowtype'; @@ -17,14 +17,19 @@ const Wrapper = styled.div` padding: 14px 0; display: flex; flex-direction: row; + word-break: break-all; &:last-child { border-bottom: 0px; } + + @media screen and (max-width: ${SCREEN_SIZE.SM}) { + flex-direction: column; + } `; const Addresses = styled.div` - flex: 1; + flex: 1 1 auto; `; const Address = styled.div` @@ -43,9 +48,16 @@ const Date = styled(Link)` line-height: 18px; padding-right: 8px; border-bottom: 0px; + flex: 0 1 auto; + word-break: normal; +`; + +const TransactionHash = styled(Date)` + word-break: break-all; `; const Value = styled.div` + flex: 1 1 auto; padding-left: 8px; white-space: nowrap; text-align: right; @@ -100,9 +112,9 @@ const TransactionItem = ({ tx, network }: Props) => {
{addr}
))} {!tx.blockHeight && ( - + Transaction hash: {tx.hash} - + )} diff --git a/src/views/Wallet/views/Account/Send/components/PendingTransactions/index.js b/src/views/Wallet/views/Account/Send/components/PendingTransactions/index.js index 080a61c8..6d0ab40b 100644 --- a/src/views/Wallet/views/Account/Send/components/PendingTransactions/index.js +++ b/src/views/Wallet/views/Account/Send/components/PendingTransactions/index.js @@ -1,7 +1,7 @@ /* @flow */ import React from 'react'; import styled from 'styled-components'; -import { colors, H5 } from 'trezor-ui-components'; +import { colors, H5, P } from 'trezor-ui-components'; import Transaction from 'components/Transaction'; import type { Network } from 'reducers/LocalStorageReducer'; @@ -18,6 +18,8 @@ const Wrapper = styled.div` border-top: 1px solid ${colors.DIVIDER}; `; +const NoTransactions = styled(P)``; + const PendingTransactions = (props: Props) => { // const pending = props.pending.filter(tx => !tx.rejected).concat(testData); const pending = props.pending.filter(tx => !tx.rejected); @@ -25,6 +27,9 @@ const PendingTransactions = (props: Props) => { return (
Pending transactions
+ {pending.length === 0 && ( + There are no pending transactions + )} {pending.map(tx => ( ))} From 4fc7f5323ebae68749bb7c0a7c48d35b3a721ed0 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 8 Apr 2019 15:11:47 +0200 Subject: [PATCH 03/19] set margin on loader instead of title --- src/views/Wallet/views/Account/Summary/ethereum/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/views/Wallet/views/Account/Summary/ethereum/index.js b/src/views/Wallet/views/Account/Summary/ethereum/index.js index 2788da89..6d1b0d4a 100644 --- a/src/views/Wallet/views/Account/Summary/ethereum/index.js +++ b/src/views/Wallet/views/Account/Summary/ethereum/index.js @@ -94,7 +94,9 @@ const AccountSummary = (props: Props) => { From 4582538917993ca41c860a7dcfc64c4215554897 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 8 Apr 2019 18:15:20 +0200 Subject: [PATCH 04/19] disable sign n verify tab for imported accounts --- src/views/Wallet/components/TopNavigationAccount/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/views/Wallet/components/TopNavigationAccount/index.js b/src/views/Wallet/components/TopNavigationAccount/index.js index b4847f4f..8d2e1951 100644 --- a/src/views/Wallet/components/TopNavigationAccount/index.js +++ b/src/views/Wallet/components/TopNavigationAccount/index.js @@ -90,9 +90,11 @@ class TopNavigationAccount extends React.PureComponent { render() { const { state, pathname } = this.props.router.location; if (!state) return null; - const { network } = this.props.selectedAccount; + const { network, account } = this.props.selectedAccount; if (!network) return null; + const isAccountImported = account && account.imported; + const basePath = `/device/${state.device}/network/${state.network}/account/${ state.account }`; @@ -108,7 +110,7 @@ class TopNavigationAccount extends React.PureComponent { - {network.type === 'ethereum' && ( + {network.type === 'ethereum' && !isAccountImported && ( From 8dd3f95f1fe650c19e253b0610c9715faf2d3480 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 8 Apr 2019 18:30:11 +0200 Subject: [PATCH 05/19] add import tool --- src/actions/AccountsActions.js | 107 +++++++++++++++++- src/actions/DiscoveryActions.js | 16 +++ src/actions/LocalStorageActions.js | 18 +++ .../Context/components/Static/index.js | 35 +++++- src/config/variables.js | 1 + src/reducers/DiscoveryReducer.js | 6 +- src/reducers/utils/index.js | 18 ++- src/support/routes.js | 6 +- src/views/Landing/views/Import/index.js | 28 ----- .../components/AccountMenu/index.js | 83 ++++++++------ .../views/Import/Container.js | 15 ++- src/views/Wallet/views/Import/index.js | 99 ++++++++++++++++ src/views/common.messages.js | 5 + src/views/index.js | 9 +- 14 files changed, 365 insertions(+), 81 deletions(-) delete mode 100644 src/views/Landing/views/Import/index.js rename src/views/{Landing => Wallet}/views/Import/Container.js (69%) create mode 100644 src/views/Wallet/views/Import/index.js diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index ee59d816..267cdb41 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -1,8 +1,13 @@ /* @flow */ import * as ACCOUNT from 'actions/constants/account'; -import type { Action } from 'flowtype'; +import * as NOTIFICATION from 'actions/constants/notification'; +import type { Action, TrezorDevice, Network } 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 = | { @@ -18,3 +23,103 @@ 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 && 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: network.type, + nonce: account.nonce, + }; + } else if (network.type === 'ripple') { + const response = await TrezorConnect.rippleGetAccountInfo({ + account: { + descriptor: address, + }, + coin: network.shortcut, + }); + console.log(response); + + // 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: network.type, + 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/DiscoveryActions.js b/src/actions/DiscoveryActions.js index 22ca82a0..57e97251 100644 --- a/src/actions/DiscoveryActions.js +++ b/src/actions/DiscoveryActions.js @@ -16,6 +16,7 @@ import type { Account, } from 'flowtype'; import type { Discovery, State } from 'reducers/DiscoveryReducer'; +import * as LocalStorageActions from 'actions/LocalStorageActions'; import * as BlockchainActions from './BlockchainActions'; import * as EthereumDiscoveryActions from './ethereum/DiscoveryActions'; import * as RippleDiscoveryActions from './ripple/DiscoveryActions'; @@ -120,6 +121,7 @@ const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean) } if (!discoveryProcess) { + dispatch(addImportedAccounts()); dispatch(begin(device, network)); } else if (discoveryProcess.completed && !ignoreCompleted) { dispatch({ @@ -380,3 +382,17 @@ export const addAccount = (): ThunkAction => (dispatch: Dispatch, getState: GetS if (!selected) return; dispatch(start(selected, getState().router.location.state.network, true)); }; + +export const addImportedAccounts = (): ThunkAction => (dispatch: Dispatch): void => { + // get imported accounts from local storage + const importedAccounts = LocalStorageActions.getImportedAccounts(); + if (importedAccounts) { + // create each account + importedAccounts.forEach(account => { + dispatch({ + type: ACCOUNT.CREATE, + payload: account, + }); + }); + } +}; diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index baf0a171..d4e92466 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -52,6 +52,7 @@ const { STORAGE_PATH } = storageUtils; const KEY_VERSION: string = `${STORAGE_PATH}version`; const KEY_DEVICES: string = `${STORAGE_PATH}devices`; const KEY_ACCOUNTS: string = `${STORAGE_PATH}accounts`; +const KEY_IMPORTED_ACCOUNTS: string = `${STORAGE_PATH}importedAccounts`; const KEY_DISCOVERY: string = `${STORAGE_PATH}discovery`; const KEY_TOKENS: string = `${STORAGE_PATH}tokens`; const KEY_PENDING: string = `${STORAGE_PATH}pending`; @@ -321,3 +322,20 @@ export const setLocalCurrency = (): ThunkAction => ( const { localCurrency } = getState().wallet; storageUtils.set(TYPE, KEY_LOCAL_CURRENCY, JSON.stringify(localCurrency)); }; + +export const setImportedAccount = (account: Account): ThunkAction => (): void => { + const prevImportedAccounts: ?string = JSON.parse(storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS)); + let importedAccounts = [account]; + if (prevImportedAccounts) { + importedAccounts = importedAccounts.concat(prevImportedAccounts); + } + storageUtils.set(TYPE, KEY_IMPORTED_ACCOUNTS, JSON.stringify(importedAccounts)); +}; + +export const getImportedAccounts = (): Array => { + const importedAccounts: ?string = storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS); + if (importedAccounts) { + return JSON.parse(importedAccounts); + } + return importedAccounts; +}; diff --git a/src/components/notifications/Context/components/Static/index.js b/src/components/notifications/Context/components/Static/index.js index 55c71577..ee2a2806 100644 --- a/src/components/notifications/Context/components/Static/index.js +++ b/src/components/notifications/Context/components/Static/index.js @@ -4,20 +4,24 @@ import * as React from 'react'; import { Notification, Link } from 'trezor-ui-components'; import Bignumber from 'bignumber.js'; import { FormattedMessage } from 'react-intl'; +import { withRouter } from 'react-router-dom'; + import l10nCommonMessages from 'views/common.messages'; +import { matchPath } from 'react-router'; +import { getPattern } from 'support/routes'; import l10nMessages from './index.messages'; import type { Props } from '../../index'; -export default (props: Props) => { +export default withRouter((props: Props) => { const { selectedAccount } = props; const { account } = selectedAccount; const { location } = props.router; const notifications: Array = []; - if (!location || !selectedAccount || !account) return null; + if (!location) return null; // Ripple minimum reserve notification - if (account.networkType === 'ripple') { + if (selectedAccount && account && account.networkType === 'ripple') { const { reserve, balance } = account; const bigBalance = new Bignumber(balance); const bigReserve = new Bignumber(reserve); @@ -51,5 +55,28 @@ export default (props: Props) => { } } + // Import tool notification + if (matchPath(location.pathname, { path: getPattern('wallet-import') })) { + notifications.push( + + ); + } + + if (account && account.imported) { + notifications.push( + + ); + } + return {notifications}; -}; +}); diff --git a/src/config/variables.js b/src/config/variables.js index 2bea148b..80eb0c5e 100644 --- a/src/config/variables.js +++ b/src/config/variables.js @@ -39,6 +39,7 @@ export const FONT_SIZE = { H3: '1rem', H4: '0.8571rem', COUNTER: '0.7857rem', + BADGE: '0.7857rem', }; export const FONT_WEIGHT = { diff --git a/src/reducers/DiscoveryReducer.js b/src/reducers/DiscoveryReducer.js index 7dca1bc5..30b42061 100644 --- a/src/reducers/DiscoveryReducer.js +++ b/src/reducers/DiscoveryReducer.js @@ -95,7 +95,11 @@ const complete = (state: State, action: DiscoveryCompleteAction): State => { const accountCreate = (state: State, account: Account): State => { const index: number = findIndex(state, account.network, account.deviceState); const newState: State = [...state]; - newState[index].accountIndex++; + // do not increment index when adding imported account + // imported accounts should not interfere with the index used in discovery proccess. + if (!account.imported) { + newState[index].accountIndex++; + } return newState; }; diff --git a/src/reducers/utils/index.js b/src/reducers/utils/index.js index 473852d0..6528a7b1 100644 --- a/src/reducers/utils/index.js +++ b/src/reducers/utils/index.js @@ -83,10 +83,24 @@ export const getSelectedAccount = (state: State): ?Account => { const locationState = state.router.location.state; if (!device || !locationState.network || !locationState.account) return null; - const index: number = parseInt(locationState.account, 10); - + // imported account index has 'i' prefix + const isImported = /^i\d+$/i.test(locationState.account); + const index: number = isImported + ? parseInt(locationState.account.substr(1), 10) + : parseInt(locationState.account, 10); + + if (isImported) { + return state.accounts.find( + a => + a.imported === true && + a.deviceState === device.state && + a.index === index && + a.network === locationState.network + ); + } return state.accounts.find( a => + a.imported === false && a.deviceState === device.state && a.index === index && a.network === locationState.network diff --git a/src/support/routes.js b/src/support/routes.js index abc46b11..77f84172 100644 --- a/src/support/routes.js +++ b/src/support/routes.js @@ -23,9 +23,9 @@ export const routes: Array = [ fields: ['bridge'], }, { - name: 'landing-import', - pattern: '/import', - fields: ['import'], + name: 'wallet-import', + pattern: '/device/:device/import', + fields: ['device', 'import'], }, { name: 'wallet-settings', diff --git a/src/views/Landing/views/Import/index.js b/src/views/Landing/views/Import/index.js deleted file mode 100644 index 3b689ed0..00000000 --- a/src/views/Landing/views/Import/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/* @flow */ - -import React from 'react'; -import styled from 'styled-components'; -import { Button, Link, Icon, H5, icons, colors } from 'trezor-ui-components'; -import LandingWrapper from 'views/Landing/components/LandingWrapper'; - -const Wrapper = styled.div` - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -`; - -const Import = () => ( - - - -
Import tool is under construction
- - - -
-
-); - -export default Import; diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index b680de05..c54342a3 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -28,8 +28,6 @@ const Text = styled.span` const RowAccountWrapper = styled.div` width: 100%; display: flex; - flex-direction: column; - align-items: flex-start; padding: ${LEFT_NAVIGATION_ROW.PADDING}; font-size: ${FONT_SIZE.BASE}; color: ${colors.TEXT_PRIMARY}; @@ -86,6 +84,21 @@ const DiscoveryLoadingText = styled.span` margin-left: 14px; `; +const Col = styled.div` + display: flex; + flex: 1; + flex-direction: column; +`; + +const Badge = styled.div` + padding: 4px 8px; + background: lightslategray; + color: white; + font-size: ${FONT_SIZE.BADGE}; + border-radius: 3px; + align-self: flex-end; +`; + // TODO: Refactorize deviceStatus & selectedAccounts const AccountMenu = (props: Props) => { const selected = props.wallet.selectedDevice; @@ -105,7 +118,12 @@ const AccountMenu = (props: Props) => { const selectedAccounts = deviceAccounts.map((account, i) => { // const url: string = `${baseUrl}/network/${location.state.network}/account/${i}`; - const url: string = location.pathname.replace(/account+\/([0-9]*)/, `account/${i}`); + let url: string; + if (account.imported) { + url = location.pathname.replace(/account+\/(i?[0-9]*)/, `account/i${account.index}`); + } else { + url = location.pathname.replace(/account+\/(i?[0-9]*)/, `account/${account.index}`); + } let balance: ?string = null; const fiatRates = props.fiat.find(f => f.network === network.shortcut); @@ -125,37 +143,38 @@ const AccountMenu = (props: Props) => { } } - const urlAccountIndex = parseInt(props.router.location.state.account, 10); return ( - + - - - {balance && !props.wallet.hideBalance && ( - - {balance} - {fiatRates && ( - - )} - - )} - {!balance && ( - - - - )} + + + + {balance && !props.wallet.hideBalance && ( + + {balance} + {fiatRates && ( + + )} + + )} + {!balance && ( + + + + )} + + {account.imported && watch-only} diff --git a/src/views/Landing/views/Import/Container.js b/src/views/Wallet/views/Import/Container.js similarity index 69% rename from src/views/Landing/views/Import/Container.js rename to src/views/Wallet/views/Import/Container.js index 5991a397..347d9a82 100644 --- a/src/views/Landing/views/Import/Container.js +++ b/src/views/Wallet/views/Import/Container.js @@ -2,19 +2,20 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import * as RouterActions from 'actions/RouterActions'; +import * as AccountsAction from 'actions/AccountsActions'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; -import type { State, Dispatch } from 'flowtype'; +import type { Device, State, Dispatch } from 'flowtype'; import ImportView from './index'; export type StateProps = { transport: $ElementType<$ElementType, 'transport'>, + device: ?Device, children?: React.Node, }; type DispatchProps = { - selectFirstAvailableDevice: typeof RouterActions.selectFirstAvailableDevice, + importAddress: typeof AccountsAction.importAddress, }; type OwnProps = {}; @@ -24,16 +25,14 @@ export type Props = StateProps & DispatchProps; const mapStateToProps: MapStateToProps = ( state: State ): StateProps => ({ - transport: state.connect.transport, + config: state.localStorage.config, + device: state.wallet.selectedDevice, }); const mapDispatchToProps: MapDispatchToProps = ( dispatch: Dispatch ): DispatchProps => ({ - selectFirstAvailableDevice: bindActionCreators( - RouterActions.selectFirstAvailableDevice, - dispatch - ), + importAddress: bindActionCreators(AccountsAction.importAddress, dispatch), }); export default connect( diff --git a/src/views/Wallet/views/Import/index.js b/src/views/Wallet/views/Import/index.js new file mode 100644 index 00000000..6f821153 --- /dev/null +++ b/src/views/Wallet/views/Import/index.js @@ -0,0 +1,99 @@ +/* @flow */ + +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { FormattedMessage } from 'react-intl'; +import { Select, Button, Input, Link, colors } from 'trezor-ui-components'; +import l10nCommonMessages from 'views/common.messages'; +import type { Props } from './Container'; + +const Wrapper = styled.div` + text-align: left; + flex-direction: column; + display: flex; + padding: 24px; + min-width: 300px; +`; + +const StyledSelect = styled(Select)` + min-width: 100px; +`; + +const InputRow = styled.div` + margin-bottom: 16px; +`; + +const Label = styled.div` + color: ${colors.TEXT_SECONDARY}; + padding-bottom: 10px; +`; + +const ButtonActions = styled.div` + display: flex; + flex-direction: row; + + justify-content: flex-end; +`; + +const ButtonWrapper = styled.div` + & + & { + margin-left: 10px; + } +`; + +const Import = (props: Props) => { + const [selectedNetwork, setSelectedNetwork] = useState(null); + const [address, setAddress] = useState(''); + + const { networks } = props.config; + return ( + // + + + + a.shortcut > b.shortcut) + .map(net => ({ + label: net.shortcut, + value: net, + }))} + onChange={option => setSelectedNetwork(option)} + /> + + + + setAddress(e.target.value)} + type="text" + /> + + + + + + + + + + + + + + // + ); +}; +export default Import; diff --git a/src/views/common.messages.js b/src/views/common.messages.js index 0d0c9f5b..43047d19 100644 --- a/src/views/common.messages.js +++ b/src/views/common.messages.js @@ -16,6 +16,11 @@ const definedMessages: Messages = defineMessages({ defaultMessage: 'Account #{number}', description: 'Used in auto-generated account label', }, + TR_IMPORTED_ACCOUNT_HASH: { + id: 'TR_IMPORTED_ACCOUNT_HASH', + defaultMessage: 'Imported account #{number}', + description: 'Used in auto-generated label for imported accounts', + }, TR_CLEAR: { id: 'TR_CLEAR', defaultMessage: 'Clear', diff --git a/src/views/index.js b/src/views/index.js index be84722a..ecb5b90b 100644 --- a/src/views/index.js +++ b/src/views/index.js @@ -14,7 +14,6 @@ import { getPattern } from 'support/routes'; // landing views import RootView from 'views/Landing/views/Root/Container'; import InstallBridge from 'views/Landing/views/InstallBridge/Container'; -import ImportView from 'views/Landing/views/Import/Container'; // wallet views import WalletContainer from 'views/Wallet'; @@ -23,6 +22,7 @@ import AccountSend from 'views/Wallet/views/Account/Send'; import AccountReceive from 'views/Wallet/views/Account/Receive'; import AccountSignVerify from 'views/Wallet/views/Account/SignVerify/Container'; +import WalletImport from 'views/Wallet/views/Import/Container'; import WalletDashboard from 'views/Wallet/views/Dashboard/Container'; import WalletDeviceSettings from 'views/Wallet/views/DeviceSettings'; import WalletSettings from 'views/Wallet/views/WalletSettings/Container'; @@ -44,11 +44,16 @@ const App = () => ( - + + Date: Mon, 8 Apr 2019 18:30:37 +0200 Subject: [PATCH 06/19] set margin on loader not title --- src/views/Wallet/components/Content/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/views/Wallet/components/Content/index.js b/src/views/Wallet/components/Content/index.js index 4682ffe9..c214cff2 100644 --- a/src/views/Wallet/components/Content/index.js +++ b/src/views/Wallet/components/Content/index.js @@ -40,11 +40,14 @@ const Loading = styled.div` flex-direction: column; `; +const LoaderWrapper = styled.div` + margin-right: 10px; +`; + const Title = styled(H4)` font-size: ${FONT_SIZE.BIGGER}; font-weight: ${FONT_WEIGHT.NORMAL}; color: ${props => (props.type === 'progress' ? colors.TEXT_SECONDARY : '')}; - margin-left: 10px; text-align: center; padding: 0; `; @@ -80,7 +83,11 @@ const Content = ({ className, children, isLoading = false, loader, exceptionPage {isLoading && loader && ( - {loader.type === 'progress' && } + {loader.type === 'progress' && ( + + + + )} {loader.title || ( <FormattedMessage {...l10nMessages.TR_INITIALIZING_ACCOUNTS} /> From 6d76c208861b4f3bfe789cb8f92aa4a888ddfbe0 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Mon, 8 Apr 2019 18:31:45 +0200 Subject: [PATCH 07/19] update UI for the imported accounts --- .../views/Account/Receive/ethereum/index.js | 36 ++++++++++--------- .../views/Account/Receive/ripple/index.js | 36 ++++++++++--------- .../views/Account/Send/ethereum/index.js | 19 +++++----- .../Wallet/views/Account/Send/ripple/index.js | 19 +++++----- .../views/Account/Summary/ripple/index.js | 12 +++++-- 5 files changed, 69 insertions(+), 53 deletions(-) diff --git a/src/views/Wallet/views/Account/Receive/ethereum/index.js b/src/views/Wallet/views/Account/Receive/ethereum/index.js index 406820db..f48436e1 100644 --- a/src/views/Wallet/views/Account/Receive/ethereum/index.js +++ b/src/views/Wallet/views/Account/Receive/ethereum/index.js @@ -95,10 +95,11 @@ const AccountReceive = (props: Props) => { const isAddressVerifying = props.modal.context === CONTEXT_DEVICE && props.modal.windowType === 'ButtonRequest_Address'; - const isAddressHidden = !isAddressVerifying && !addressVerified && !addressUnverified; + const isAddressHidden = + !isAddressVerifying && !addressVerified && !addressUnverified && !account.imported; let address = `${account.descriptor.substring(0, 20)}...`; - if (addressVerified || addressUnverified || isAddressVerifying) { + if (addressVerified || addressUnverified || isAddressVerifying || account.imported) { address = account.descriptor; } @@ -166,7 +167,7 @@ const AccountReceive = (props: Props) => { ) } /> - {!(addressVerified || addressUnverified) && ( + {!(addressVerified || addressUnverified) && !account.imported && ( <ShowAddressButton icon={ICONS.EYE} onClick={() => props.showAddress(account.accountPath)} @@ -176,20 +177,21 @@ const AccountReceive = (props: Props) => { </ShowAddressButton> )} </Row> - {(addressVerified || addressUnverified) && !isAddressVerifying && ( - <QrWrapper> - <Label> - <FormattedMessage {...l10nReceiveMessages.TR_QR_CODE} /> - </Label> - <StyledQRCode - bgColor="#FFFFFF" - fgColor="#000000" - level="Q" - style={{ width: 150 }} - value={account.descriptor} - /> - </QrWrapper> - )} + {((addressVerified || addressUnverified) && !isAddressVerifying) || + (account.imported && ( + <QrWrapper> + <Label> + <FormattedMessage {...l10nReceiveMessages.TR_QR_CODE} /> + </Label> + <StyledQRCode + bgColor="#FFFFFF" + fgColor="#000000" + level="Q" + style={{ width: 150 }} + value={account.descriptor} + /> + </QrWrapper> + ))} </AddressWrapper> </React.Fragment> </Content> diff --git a/src/views/Wallet/views/Account/Receive/ripple/index.js b/src/views/Wallet/views/Account/Receive/ripple/index.js index 93480906..f1b0e8c5 100644 --- a/src/views/Wallet/views/Account/Receive/ripple/index.js +++ b/src/views/Wallet/views/Account/Receive/ripple/index.js @@ -101,10 +101,11 @@ const AccountReceive = (props: Props) => { const isAddressVerifying = props.modal.context === CONTEXT_DEVICE && props.modal.windowType === 'ButtonRequest_Address'; - const isAddressHidden = !isAddressVerifying && !addressVerified && !addressUnverified; + const isAddressHidden = + !isAddressVerifying && !addressVerified && !addressUnverified && !account.imported; let address = `${account.descriptor.substring(0, 20)}...`; - if (addressVerified || addressUnverified || isAddressVerifying) { + if (addressVerified || addressUnverified || isAddressVerifying || account.imported) { address = account.descriptor; } @@ -172,7 +173,7 @@ const AccountReceive = (props: Props) => { ) } /> - {!(addressVerified || addressUnverified) && ( + {!(addressVerified || addressUnverified) && !account.imported && ( <ShowAddressButton onClick={() => props.showAddress(account.accountPath)} isDisabled={device.connected && !discovery.completed} @@ -182,20 +183,21 @@ const AccountReceive = (props: Props) => { </ShowAddressButton> )} </Row> - {(addressVerified || addressUnverified) && !isAddressVerifying && ( - <QrWrapper> - <Label> - <FormattedMessage {...l10nReceiveMessages.TR_QR_CODE} /> - </Label> - <StyledQRCode - bgColor="#FFFFFF" - fgColor="#000000" - level="Q" - style={{ width: 150 }} - value={account.descriptor} - /> - </QrWrapper> - )} + {((addressVerified || addressUnverified) && !isAddressVerifying) || + (account.imported && ( + <QrWrapper> + <Label> + <FormattedMessage {...l10nReceiveMessages.TR_QR_CODE} /> + </Label> + <StyledQRCode + bgColor="#FFFFFF" + fgColor="#000000" + level="Q" + style={{ width: 150 }} + value={account.descriptor} + /> + </QrWrapper> + ))} </AddressWrapper> </React.Fragment> </Content> diff --git a/src/views/Wallet/views/Account/Send/ethereum/index.js b/src/views/Wallet/views/Account/Send/ethereum/index.js index 73fd4000..fe6ebed5 100644 --- a/src/views/Wallet/views/Account/Send/ethereum/index.js +++ b/src/views/Wallet/views/Account/Send/ethereum/index.js @@ -312,7 +312,9 @@ const AccountSend = (props: Props) => { total === '0' || amount.length === 0 || address.length === 0 || - sending; + sending || + account.imported; + let amountText = ''; if (networkSymbol !== currency && amount.length > 0 && !errors.amount) { amountText = `${amount} ${currency.toUpperCase()}`; @@ -516,13 +518,14 @@ const AccountSend = (props: Props) => { </AdvancedForm> )} - {props.selectedAccount.pending.length > 0 && ( - <PendingTransactions - pending={props.selectedAccount.pending} - tokens={props.selectedAccount.tokens} - network={network} - /> - )} + {props.selectedAccount.pending.length > 0 || + (account.imported && ( + <PendingTransactions + pending={props.selectedAccount.pending} + tokens={props.selectedAccount.tokens} + network={network} + /> + ))} </Content> ); }; diff --git a/src/views/Wallet/views/Account/Send/ripple/index.js b/src/views/Wallet/views/Account/Send/ripple/index.js index d3e144d0..c2c2b949 100644 --- a/src/views/Wallet/views/Account/Send/ripple/index.js +++ b/src/views/Wallet/views/Account/Send/ripple/index.js @@ -279,7 +279,9 @@ const AccountSend = (props: Props) => { total === '0' || amount.length === 0 || address.length === 0 || - sending; + sending || + account.imported; + let sendButtonText = <FormattedMessage {...l10nSendMessages.TR_SEND} values={{ amount: '' }} />; if (total !== '0') { sendButtonText = ( @@ -481,13 +483,14 @@ const AccountSend = (props: Props) => { </AdvancedForm> )} - {props.selectedAccount.pending.length > 0 && ( - <PendingTransactions - pending={props.selectedAccount.pending} - tokens={props.selectedAccount.tokens} - network={network} - /> - )} + {props.selectedAccount.pending.length > 0 || + (account.imported && ( + <PendingTransactions + pending={props.selectedAccount.pending} + tokens={props.selectedAccount.tokens} + network={network} + /> + ))} </Content> ); }; diff --git a/src/views/Wallet/views/Account/Summary/ripple/index.js b/src/views/Wallet/views/Account/Summary/ripple/index.js index 3d42bea0..0c9dde3b 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/index.js @@ -44,6 +44,10 @@ const StyledCoinLogo = styled(CoinLogo)` margin-right: 10px; `; +const StyledLink = styled(Link)` + font-size: ${FONT_SIZE.SMALL}; +`; + const AccountSummary = (props: Props) => { const device = props.wallet.selectedDevice; const { account, network, pending, shouldRender } = props.selectedAccount; @@ -69,17 +73,19 @@ const AccountSummary = (props: Props) => { <StyledCoinLogo height={23} network={account.network} /> <AccountTitle> <FormattedMessage - {...l10nCommonMessages.TR_ACCOUNT_HASH} + {...(account.imported + ? l10nCommonMessages.TR_IMPORTED_ACCOUNT_HASH + : l10nCommonMessages.TR_ACCOUNT_HASH)} values={{ number: parseInt(account.index, 10) + 1 }} /> </AccountTitle> </AccountName> {!account.empty && ( - <Link href={explorerLink} isGray> + <StyledLink href={explorerLink} isGray> <FormattedMessage {...l10nSummaryMessages.TR_SEE_FULL_TRANSACTION_HISTORY} /> - </Link> + </StyledLink> )} </AccountHeading> <AccountBalance From 17f63b6d9adbd8b5d457977fce63f930c180062b Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Tue, 9 Apr 2019 14:06:15 +0200 Subject: [PATCH 08/19] remove imported accounts when forgetting device --- src/actions/AccountsActions.js | 2 +- src/actions/LocalStorageActions.js | 19 ++++++++++++++++--- src/services/LocalStorageService.js | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 267cdb41..9e11e333 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -102,7 +102,7 @@ export const importAddress = ( type: ACCOUNT.CREATE, payload, }); - dispatch(LocalStorageActions.setImportedAccount(payload)); + LocalStorageActions.setImportedAccount(payload); dispatch({ type: NOTIFICATION.ADD, payload: { diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index d4e92466..bdde6335 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -323,8 +323,8 @@ export const setLocalCurrency = (): ThunkAction => ( storageUtils.set(TYPE, KEY_LOCAL_CURRENCY, JSON.stringify(localCurrency)); }; -export const setImportedAccount = (account: Account): ThunkAction => (): void => { - const prevImportedAccounts: ?string = JSON.parse(storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS)); +export const setImportedAccount = (account: Account): void => { + const prevImportedAccounts: ?Array<Account> = getImportedAccounts(); let importedAccounts = [account]; if (prevImportedAccounts) { importedAccounts = importedAccounts.concat(prevImportedAccounts); @@ -332,10 +332,23 @@ export const setImportedAccount = (account: Account): ThunkAction => (): void => storageUtils.set(TYPE, KEY_IMPORTED_ACCOUNTS, JSON.stringify(importedAccounts)); }; -export const getImportedAccounts = (): Array<Account> => { +export const getImportedAccounts = (): ?Array<Account> => { const importedAccounts: ?string = storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS); if (importedAccounts) { return JSON.parse(importedAccounts); } return importedAccounts; }; + +export const removeImportedAccounts = (device: TrezorDevice): void => { + const importedAccounts: ?Array<Account> = getImportedAccounts(); + if (!importedAccounts) return; + + const filteredImportedAccounts = importedAccounts.filter( + account => account.deviceState !== device.state + ); + storageUtils.remove(TYPE, KEY_IMPORTED_ACCOUNTS); + filteredImportedAccounts.forEach(account => { + setImportedAccount(account); + }); +}; diff --git a/src/services/LocalStorageService.js b/src/services/LocalStorageService.js index c5d9daf6..09b7ac5f 100644 --- a/src/services/LocalStorageService.js +++ b/src/services/LocalStorageService.js @@ -58,6 +58,10 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar case CONNECT.FORGET: case CONNECT.FORGET_SINGLE: case CONNECT.FORGET_SILENT: + api.dispatch(LocalStorageActions.save()); + LocalStorageActions.removeImportedAccounts(action.device); + break; + case CONNECT.RECEIVE_WALLET_TYPE: case DEVICE.CHANGED: case DEVICE.DISCONNECT: From de7aafa5c387bab0b421b0b5548163ebb2b88475 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Tue, 9 Apr 2019 16:10:49 +0200 Subject: [PATCH 09/19] changed method definitions to ThunkAction, remove all accounts associated to deviceID --- src/actions/AccountsActions.js | 2 +- src/actions/DiscoveryActions.js | 2 +- src/actions/LocalStorageActions.js | 17 ++++++++++------- src/services/LocalStorageService.js | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 9e11e333..267cdb41 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -102,7 +102,7 @@ export const importAddress = ( type: ACCOUNT.CREATE, payload, }); - LocalStorageActions.setImportedAccount(payload); + dispatch(LocalStorageActions.setImportedAccount(payload)); dispatch({ type: NOTIFICATION.ADD, payload: { diff --git a/src/actions/DiscoveryActions.js b/src/actions/DiscoveryActions.js index 57e97251..4ecdcd0f 100644 --- a/src/actions/DiscoveryActions.js +++ b/src/actions/DiscoveryActions.js @@ -385,7 +385,7 @@ export const addAccount = (): ThunkAction => (dispatch: Dispatch, getState: GetS export const addImportedAccounts = (): ThunkAction => (dispatch: Dispatch): void => { // get imported accounts from local storage - const importedAccounts = LocalStorageActions.getImportedAccounts(); + const importedAccounts = dispatch(LocalStorageActions.getImportedAccounts()); if (importedAccounts) { // create each account importedAccounts.forEach(account => { diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index bdde6335..fd801692 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -323,8 +323,8 @@ export const setLocalCurrency = (): ThunkAction => ( storageUtils.set(TYPE, KEY_LOCAL_CURRENCY, JSON.stringify(localCurrency)); }; -export const setImportedAccount = (account: Account): void => { - const prevImportedAccounts: ?Array<Account> = getImportedAccounts(); +export const setImportedAccount = (account: Account): ThunkAction => (dispatch: Dispatch): void => { + const prevImportedAccounts: ?Array<Account> = dispatch(getImportedAccounts()); let importedAccounts = [account]; if (prevImportedAccounts) { importedAccounts = importedAccounts.concat(prevImportedAccounts); @@ -332,7 +332,7 @@ export const setImportedAccount = (account: Account): void => { storageUtils.set(TYPE, KEY_IMPORTED_ACCOUNTS, JSON.stringify(importedAccounts)); }; -export const getImportedAccounts = (): ?Array<Account> => { +export const getImportedAccounts = (): ThunkAction => (): ?Array<Account> => { const importedAccounts: ?string = storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS); if (importedAccounts) { return JSON.parse(importedAccounts); @@ -340,15 +340,18 @@ export const getImportedAccounts = (): ?Array<Account> => { return importedAccounts; }; -export const removeImportedAccounts = (device: TrezorDevice): void => { - const importedAccounts: ?Array<Account> = getImportedAccounts(); +export const removeImportedAccounts = (device: TrezorDevice): ThunkAction => ( + dispatch: Dispatch +): void => { + const importedAccounts: ?Array<Account> = dispatch(getImportedAccounts()); if (!importedAccounts) return; + const deviceId = device.features ? device.features.device_id : null; const filteredImportedAccounts = importedAccounts.filter( - account => account.deviceState !== device.state + account => account.deviceID !== deviceId ); storageUtils.remove(TYPE, KEY_IMPORTED_ACCOUNTS); filteredImportedAccounts.forEach(account => { - setImportedAccount(account); + dispatch(setImportedAccount(account)); }); }; diff --git a/src/services/LocalStorageService.js b/src/services/LocalStorageService.js index 09b7ac5f..018941ba 100644 --- a/src/services/LocalStorageService.js +++ b/src/services/LocalStorageService.js @@ -59,7 +59,7 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar case CONNECT.FORGET_SINGLE: case CONNECT.FORGET_SILENT: api.dispatch(LocalStorageActions.save()); - LocalStorageActions.removeImportedAccounts(action.device); + api.dispatch(LocalStorageActions.removeImportedAccounts(action.device)); break; case CONNECT.RECEIVE_WALLET_TYPE: From 813edd442b033c464aa4c1d86fd150cdfe2f3806 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Tue, 9 Apr 2019 16:33:50 +0200 Subject: [PATCH 10/19] exclude imported accounts when checking if the last account is empty --- .../LeftNavigation/components/AccountMenu/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index c54342a3..a128a475 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -115,6 +115,9 @@ const AccountMenu = (props: Props) => { if (!selected || !network) return null; const deviceAccounts: Accounts = findDeviceAccounts(accounts, selected, location.state.network); + const discoveryAccounts: Accounts = deviceAccounts.filter( + account => account.imported === false + ); const selectedAccounts = deviceAccounts.map((account, i) => { // const url: string = `${baseUrl}/network/${location.state.network}/account/${i}`; @@ -187,7 +190,7 @@ const AccountMenu = (props: Props) => { ); if (discovery && discovery.completed) { - const lastAccount = deviceAccounts[deviceAccounts.length - 1]; + const lastAccount = discoveryAccounts[discoveryAccounts.length - 1]; if (!selected.connected) { discoveryStatus = ( <Tooltip From 715da870a73146bb8e5a7e2cc1c4a6a94431ec98 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Tue, 9 Apr 2019 17:15:01 +0200 Subject: [PATCH 11/19] sort the accounts array --- src/reducers/AccountsReducer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/reducers/AccountsReducer.js b/src/reducers/AccountsReducer.js index e84452c3..14a9b275 100644 --- a/src/reducers/AccountsReducer.js +++ b/src/reducers/AccountsReducer.js @@ -75,6 +75,8 @@ const createAccount = (state: State, account: Account): State => { } const newState: State = [...state]; newState.push(account); + // sort the accounts array so the imported accounts always come before discovered accounts + newState.sort((a, b) => b.imported - a.imported || a.index - b.index); return newState; }; From 27f35b097db575299674209f7c03ed42beb1aff2 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Tue, 9 Apr 2019 23:36:32 +0200 Subject: [PATCH 12/19] refactored getSelectedAccount, createAccount --- src/reducers/AccountsReducer.js | 5 ++++- src/reducers/utils/index.js | 11 +---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/reducers/AccountsReducer.js b/src/reducers/AccountsReducer.js index 14a9b275..304f13a6 100644 --- a/src/reducers/AccountsReducer.js +++ b/src/reducers/AccountsReducer.js @@ -75,8 +75,11 @@ const createAccount = (state: State, account: Account): State => { } const newState: State = [...state]; newState.push(account); + // sort the accounts array so the imported accounts always come before discovered accounts - newState.sort((a, b) => b.imported - a.imported || a.index - b.index); + if (account.imported) { + newState.sort((a, b) => b.imported - a.imported || a.index - b.index); + } return newState; }; diff --git a/src/reducers/utils/index.js b/src/reducers/utils/index.js index 6528a7b1..41422f4c 100644 --- a/src/reducers/utils/index.js +++ b/src/reducers/utils/index.js @@ -89,18 +89,9 @@ export const getSelectedAccount = (state: State): ?Account => { ? parseInt(locationState.account.substr(1), 10) : parseInt(locationState.account, 10); - if (isImported) { - return state.accounts.find( - a => - a.imported === true && - a.deviceState === device.state && - a.index === index && - a.network === locationState.network - ); - } return state.accounts.find( a => - a.imported === false && + a.imported === isImported && a.deviceState === device.state && a.index === index && a.network === locationState.network From bb4a3268f76925dbafdb6cef71cea9308d693787 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Wed, 10 Apr 2019 00:50:34 +0200 Subject: [PATCH 13/19] fix flow --- src/actions/AccountsActions.js | 53 ++++++++++++++-------- src/actions/DiscoveryActions.js | 2 +- src/actions/LocalStorageActions.js | 10 ++-- src/reducers/AccountsReducer.js | 2 +- src/views/Wallet/views/Import/Container.js | 6 +-- src/views/Wallet/views/Import/index.js | 2 +- 6 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 267cdb41..83b705d4 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -2,7 +2,7 @@ import * as ACCOUNT from 'actions/constants/account'; import * as NOTIFICATION from 'actions/constants/notification'; -import type { Action, TrezorDevice, Network } from 'flowtype'; +import type { Action, AsyncAction, TrezorDevice, Network, Dispatch, GetState } from 'flowtype'; import type { Account, State } from 'reducers/AccountsReducer'; import * as BlockchainActions from 'actions/ethereum/BlockchainActions'; import * as LocalStorageActions from 'actions/LocalStorageActions'; @@ -27,13 +27,17 @@ export const update = (account: Account): Action => ({ export const importAddress = ( address: string, network: Network, - device: TrezorDevice + device: ?TrezorDevice ): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => { if (!device) return; let payload; const index = getState().accounts.filter( - a => a.imported === true && a.network === network.shortcut && a.deviceState === device.state + a => + a.imported === true && + a.network === network.shortcut && + device && + a.deviceState === device.state ).length; try { @@ -58,9 +62,22 @@ export const importAddress = ( transactions: account.transactions, empty, - networkType: network.type, + 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: { @@ -93,24 +110,24 @@ export const importAddress = ( transactions: account.transactions, empty, - networkType: network.type, + 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, + }, + }); } - 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, diff --git a/src/actions/DiscoveryActions.js b/src/actions/DiscoveryActions.js index 4ecdcd0f..57e97251 100644 --- a/src/actions/DiscoveryActions.js +++ b/src/actions/DiscoveryActions.js @@ -385,7 +385,7 @@ export const addAccount = (): ThunkAction => (dispatch: Dispatch, getState: GetS export const addImportedAccounts = (): ThunkAction => (dispatch: Dispatch): void => { // get imported accounts from local storage - const importedAccounts = dispatch(LocalStorageActions.getImportedAccounts()); + const importedAccounts = LocalStorageActions.getImportedAccounts(); if (importedAccounts) { // create each account importedAccounts.forEach(account => { diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index fd801692..2a2a2736 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -323,8 +323,8 @@ export const setLocalCurrency = (): ThunkAction => ( storageUtils.set(TYPE, KEY_LOCAL_CURRENCY, JSON.stringify(localCurrency)); }; -export const setImportedAccount = (account: Account): ThunkAction => (dispatch: Dispatch): void => { - const prevImportedAccounts: ?Array<Account> = dispatch(getImportedAccounts()); +export const setImportedAccount = (account: Account): ThunkAction => (): void => { + const prevImportedAccounts: ?Array<Account> = getImportedAccounts(); let importedAccounts = [account]; if (prevImportedAccounts) { importedAccounts = importedAccounts.concat(prevImportedAccounts); @@ -332,18 +332,18 @@ export const setImportedAccount = (account: Account): ThunkAction => (dispatch: storageUtils.set(TYPE, KEY_IMPORTED_ACCOUNTS, JSON.stringify(importedAccounts)); }; -export const getImportedAccounts = (): ThunkAction => (): ?Array<Account> => { +export const getImportedAccounts = (): ?Array<Account> => { const importedAccounts: ?string = storageUtils.get(TYPE, KEY_IMPORTED_ACCOUNTS); if (importedAccounts) { return JSON.parse(importedAccounts); } - return importedAccounts; + return null; }; export const removeImportedAccounts = (device: TrezorDevice): ThunkAction => ( dispatch: Dispatch ): void => { - const importedAccounts: ?Array<Account> = dispatch(getImportedAccounts()); + const importedAccounts: ?Array<Account> = getImportedAccounts(); if (!importedAccounts) return; const deviceId = device.features ? device.features.device_id : null; diff --git a/src/reducers/AccountsReducer.js b/src/reducers/AccountsReducer.js index 304f13a6..3fe36f19 100644 --- a/src/reducers/AccountsReducer.js +++ b/src/reducers/AccountsReducer.js @@ -78,7 +78,7 @@ const createAccount = (state: State, account: Account): State => { // sort the accounts array so the imported accounts always come before discovered accounts if (account.imported) { - newState.sort((a, b) => b.imported - a.imported || a.index - b.index); + newState.sort((a, b) => Number(b.imported) - Number(a.imported) || a.index - b.index); } return newState; }; diff --git a/src/views/Wallet/views/Import/Container.js b/src/views/Wallet/views/Import/Container.js index 347d9a82..1759aa51 100644 --- a/src/views/Wallet/views/Import/Container.js +++ b/src/views/Wallet/views/Import/Container.js @@ -5,12 +5,12 @@ import { bindActionCreators } from 'redux'; import * as AccountsAction from 'actions/AccountsActions'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; -import type { Device, State, Dispatch } from 'flowtype'; +import type { TrezorDevice, Config, State, Dispatch } from 'flowtype'; import ImportView from './index'; export type StateProps = { - transport: $ElementType<$ElementType<State, 'connect'>, 'transport'>, - device: ?Device, + device: ?TrezorDevice, + config: Config, children?: React.Node, }; diff --git a/src/views/Wallet/views/Import/index.js b/src/views/Wallet/views/Import/index.js index 6f821153..4216a1ba 100644 --- a/src/views/Wallet/views/Import/index.js +++ b/src/views/Wallet/views/Import/index.js @@ -54,7 +54,7 @@ const Import = (props: Props) => { <StyledSelect value={selectedNetwork} options={networks - .sort((a, b) => a.shortcut > b.shortcut) + .sort((a, b) => a.shortcut.localeCompare(b.shortcut)) .map(net => ({ label: net.shortcut, value: net, From a35c21603b82fd7ef3dd891486915a575e9d94d3 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Wed, 10 Apr 2019 18:01:32 +0200 Subject: [PATCH 14/19] remove console.log --- src/actions/AccountsActions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 83b705d4..ac8f1ad3 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -85,7 +85,6 @@ export const importAddress = ( }, coin: network.shortcut, }); - console.log(response); // handle TREZOR response error if (!response.success) { From b91c78a09ec73db81f5d199309d7d77cfce4a4af Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Wed, 10 Apr 2019 18:09:54 +0200 Subject: [PATCH 15/19] center watch-only badge --- .../LeftNavigation/components/AccountMenu/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index a128a475..1f185f71 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -88,6 +88,10 @@ const Col = styled.div` display: flex; flex: 1; flex-direction: column; +` + +const RightCol = styled(Col)` + justify-content: center; `; const Badge = styled.div` @@ -177,7 +181,7 @@ const AccountMenu = (props: Props) => { </Text> )} </Col> - <Col>{account.imported && <Badge>watch-only</Badge>}</Col> + <RightCol>{account.imported && <Badge>watch-only</Badge>}</RightCol> </RowAccountWrapper> </Row> </NavLink> From 0f6c9a70eda7cdde945d93656d016386c069dfd3 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Wed, 10 Apr 2019 19:54:07 +0200 Subject: [PATCH 16/19] create separate reducer ImportAccount --- src/actions/AccountsActions.js | 123 +------------- src/actions/ImportAccountActions.js | 153 ++++++++++++++++++ src/actions/constants/importAccount.js | 5 + src/flowtype/index.js | 4 +- src/reducers/ImportAccountReducer.js | 43 +++++ src/reducers/index.js | 2 + .../components/AccountMenu/index.js | 2 +- src/views/Wallet/views/Import/Container.js | 8 +- src/views/Wallet/views/Import/index.js | 4 +- 9 files changed, 216 insertions(+), 128 deletions(-) create mode 100644 src/actions/ImportAccountActions.js create mode 100644 src/actions/constants/importAccount.js create mode 100644 src/reducers/ImportAccountReducer.js 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<void> => { - 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<void> => { + 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<State, 'importAccount'>, config: Config, children?: React.Node, }; type DispatchProps = { - importAddress: typeof AccountsAction.importAddress, + importAddress: typeof ImportAccountActions.importAddress, }; type OwnProps = {}; @@ -27,12 +28,13 @@ const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = ( ): StateProps => ({ config: state.localStorage.config, device: state.wallet.selectedDevice, + importAccount: state.importAccount, }); const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = ( 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) => { <ButtonWrapper> <Button - isDisabled={!selectedNetwork || address === ''} + isDisabled={ + !selectedNetwork || address === '' || props.importAccount.loading + } onClick={() => props.importAddress(address, selectedNetwork.value, props.device) } From 43823607ddcfa00f71560cf62b46cd7f25b56952 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Wed, 10 Apr 2019 23:27:26 +0200 Subject: [PATCH 17/19] show right col only when account is imported --- .../LeftNavigation/components/AccountMenu/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 3e2674ae..0c441fb3 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -181,7 +181,11 @@ const AccountMenu = (props: Props) => { </Text> )} </Col> - <RightCol>{account.imported && <Badge>watch-only</Badge>}</RightCol> + {account.imported && ( + <RightCol> + <Badge>watch-only</Badge> + </RightCol> + )} </RowAccountWrapper> </Row> </NavLink> From 60e7244b7a58aa681ffb844cd431cc9ce95bcbf4 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Thu, 11 Apr 2019 13:18:08 +0200 Subject: [PATCH 18/19] fix flow --- .../notifications/Context/components/Static/index.js | 3 ++- src/views/Wallet/views/Import/Container.js | 4 +++- src/views/Wallet/views/Import/index.js | 6 +++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/notifications/Context/components/Static/index.js b/src/components/notifications/Context/components/Static/index.js index d3890ecd..d14c5aa0 100644 --- a/src/components/notifications/Context/components/Static/index.js +++ b/src/components/notifications/Context/components/Static/index.js @@ -5,6 +5,7 @@ import { Notification, Link } from 'trezor-ui-components'; import Bignumber from 'bignumber.js'; import { FormattedMessage } from 'react-intl'; import { withRouter } from 'react-router-dom'; +import type { ContextRouter } from 'react-router'; import l10nCommonMessages from 'views/common.messages'; import { matchPath } from 'react-router'; @@ -12,7 +13,7 @@ import { getPattern } from 'support/routes'; import l10nMessages from './index.messages'; import type { Props } from '../../index'; -export default withRouter((props: Props) => { +export default withRouter<Props>((props: {| ...Props, ...ContextRouter |}) => { const { selectedAccount } = props; const { account } = selectedAccount; const { location } = props.router; diff --git a/src/views/Wallet/views/Import/Container.js b/src/views/Wallet/views/Import/Container.js index cdc8c9f9..e0ea276f 100644 --- a/src/views/Wallet/views/Import/Container.js +++ b/src/views/Wallet/views/Import/Container.js @@ -3,13 +3,15 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import * as ImportAccountActions from 'actions/ImportAccountActions'; -import type { State, Dispatch } from 'flowtype'; +import type { State, Dispatch, TrezorDevice, Config } from 'flowtype'; import ImportView from './index'; type OwnProps = {| children?: React.Node, |}; export type StateProps = {| + device: ?TrezorDevice, + config: Config, importAccount: $ElementType<State, 'importAccount'>, |}; diff --git a/src/views/Wallet/views/Import/index.js b/src/views/Wallet/views/Import/index.js index 0ba3f79c..f58a8518 100644 --- a/src/views/Wallet/views/Import/index.js +++ b/src/views/Wallet/views/Import/index.js @@ -87,7 +87,11 @@ const Import = (props: Props) => { !selectedNetwork || address === '' || props.importAccount.loading } onClick={() => - props.importAddress(address, selectedNetwork.value, props.device) + props.importAddress( + address, + (selectedNetwork || {}).value, + props.device + ) } > Import From 0416e556eb14a6244cb593ca2adb0e6b2ea4a484 Mon Sep 17 00:00:00 2001 From: slowbackspace <slowbackspace@gmail.com> Date: Thu, 11 Apr 2019 13:22:05 +0200 Subject: [PATCH 19/19] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07b0ed68..7cb10b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ __added__ - Fiat currency switcher - Application settings - Button to copy log to clipboard +- Import tool (for support) - Prettier __updated__