mirror of
https://github.com/trezor/trezor-wallet
synced 2024-12-25 16:38:08 +00:00
Merge branch 'master' into fix-menu-underline
This commit is contained in:
commit
397b757d1e
54
LICENSE
Normal file
54
LICENSE
Normal file
@ -0,0 +1,54 @@
|
||||
TREZOR REFERENCE SOURCE LICENSE (T-RSL)
|
||||
=======================================
|
||||
|
||||
This license governs use of the accompanying software. If you use the software,
|
||||
you accept this license. If you do not accept the license, do not use the
|
||||
software.
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
The terms "reproduce," "reproduction" and "distribution" have the same meaning
|
||||
here as under U.S. copyright law.
|
||||
|
||||
"You" means the licensee of the software.
|
||||
|
||||
"Your company" means the company you worked for when you downloaded the
|
||||
software.
|
||||
|
||||
"Reference use" means use of the software within your company as a reference,
|
||||
in read only form, for the sole purposes of debugging your products,
|
||||
maintaining your products, or enhancing the interoperability of your products
|
||||
with the software, and specifically excludes the right to distribute the
|
||||
software outside of your company.
|
||||
|
||||
"Licensed patents" means any Licensor patent claims which read directly on the
|
||||
software as distributed by the Licensor under this license.
|
||||
|
||||
2. Grant of Rights
|
||||
------------------
|
||||
|
||||
(A) Copyright Grant - Subject to the terms of this license, the Licensor grants
|
||||
you a non-transferable, non-exclusive, worldwide, royalty-free copyright
|
||||
license to reproduce the software for reference use.
|
||||
|
||||
(B) Patent Grant - Subject to the terms of this license, the Licensor grants
|
||||
you a non-transferable, non-exclusive, worldwide, royalty-free patent license
|
||||
under licensed patents for reference use.
|
||||
|
||||
3. Limitations
|
||||
--------------
|
||||
|
||||
(A) No Trademark License - This license does not grant you any rights to use
|
||||
the Licensor's name, logo, or trademarks.
|
||||
|
||||
(B) If you begin patent litigation against the Licensor over patents that you
|
||||
think may apply to the software (including a cross-claim or counterclaim in
|
||||
a lawsuit), your license to the software ends automatically.
|
||||
|
||||
(C) The software is licensed "as-is." You bear the risk of using it. The
|
||||
Licensor gives no express warranties, guarantees or conditions. You may have
|
||||
additional consumer rights under your local laws which this license cannot
|
||||
change. To the extent permitted under your local laws, the Licensor excludes
|
||||
the implied warranties of merchantability, fitness for a particular purpose and
|
||||
non-infringement.
|
@ -5,37 +5,29 @@ import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsUnits from 'ethereumjs-units';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import { push } from 'react-router-redux';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { strip } from 'utils/ethUtils';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
|
||||
import { initialState } from 'reducers/SendFormReducer';
|
||||
import { findAccount } from 'reducers/AccountsReducer';
|
||||
import { findToken } from 'reducers/TokensReducer';
|
||||
import { findDevice } from 'reducers/utils';
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
import { findDevice, getPendingAmount, getPendingNonce } from 'reducers/utils';
|
||||
|
||||
import type {
|
||||
PendingTx,
|
||||
Dispatch,
|
||||
GetState,
|
||||
Action,
|
||||
ThunkAction,
|
||||
AsyncAction,
|
||||
RouterLocationState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
import type { State as AccountState } from 'reducers/SelectedAccountReducer';
|
||||
import type { Web3Instance } from 'reducers/Web3Reducer';
|
||||
import type { Config, Coin } from 'reducers/LocalStorageReducer';
|
||||
import type { Coin } from 'reducers/LocalStorageReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
import type { State, FeeLevel } from 'reducers/SendFormReducer';
|
||||
import type { Account } from 'reducers/AccountsReducer';
|
||||
import type { Props } from 'views/Wallet/views/AccountSend/Container';
|
||||
import * as SessionStorageActions from './SessionStorageActions';
|
||||
import { estimateGas, getGasPrice, pushTx } from './Web3Actions';
|
||||
import { estimateGas, pushTx } from './Web3Actions';
|
||||
|
||||
export type SendTxAction = {
|
||||
type: typeof SEND.TX_COMPLETE,
|
||||
@ -155,7 +147,6 @@ export const calculate = (prevProps: Props, props: Props) => {
|
||||
} = props.selectedAccount;
|
||||
if (!account) return;
|
||||
|
||||
const prevState = prevProps.sendForm;
|
||||
const state = props.sendForm;
|
||||
const isToken: boolean = state.currency !== state.networkSymbol;
|
||||
|
||||
@ -169,7 +160,7 @@ export const calculate = (prevProps: Props, props: Props) => {
|
||||
|
||||
|
||||
if (state.setMax) {
|
||||
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, isToken);
|
||||
const pendingAmount: BigNumber = getPendingAmount(pending, state.currency, isToken);
|
||||
|
||||
if (isToken) {
|
||||
const token: ?Token = findToken(tokens, account.address, state.currency, account.deviceState);
|
||||
@ -277,7 +268,7 @@ export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState):
|
||||
});
|
||||
};
|
||||
|
||||
export const toggleAdvanced = (address: string): Action => ({
|
||||
export const toggleAdvanced = (/* address: string */): Action => ({
|
||||
type: SEND.TOGGLE_ADVANCED,
|
||||
});
|
||||
|
||||
@ -286,7 +277,6 @@ const addressValidation = (): ThunkAction => (dispatch: Dispatch, getState: GetS
|
||||
const {
|
||||
account,
|
||||
network,
|
||||
tokens,
|
||||
} = getState().selectedAccount;
|
||||
if (!account || !network) return;
|
||||
|
||||
@ -310,7 +300,7 @@ const addressValidation = (): ThunkAction => (dispatch: Dispatch, getState: GetS
|
||||
} else {
|
||||
const otherNetworkAccount = savedAccounts[0];
|
||||
const device: ?TrezorDevice = findDevice(getState().devices, otherNetworkAccount.deviceID, otherNetworkAccount.deviceState);
|
||||
const coins = getState().localStorage.config.coins;
|
||||
const { coins } = getState().localStorage.config;
|
||||
const otherNetwork: ?Coin = coins.find(c => c.network === otherNetworkAccount.network);
|
||||
if (device && otherNetwork) {
|
||||
warnings.address = `Looks like it's ${device.instanceLabel} Account #${(otherNetworkAccount.index + 1)} address of ${otherNetwork.name} network`;
|
||||
@ -351,7 +341,7 @@ export const validation = (props: Props): void => {
|
||||
if (state.untouched) return;
|
||||
// valid address
|
||||
if (state.touched.address) {
|
||||
if (state.address.length < 1) {
|
||||
/* if (state.address.length < 1) {
|
||||
errors.address = 'Address is not set';
|
||||
} else if (!EthereumjsUtil.isValidAddress(state.address)) {
|
||||
errors.address = 'Address is not valid';
|
||||
@ -363,6 +353,20 @@ export const validation = (props: Props): void => {
|
||||
} else if (state.infos.address) {
|
||||
infos.address = state.infos.address;
|
||||
}
|
||||
} */
|
||||
|
||||
/* eslint (no-lonely-if) */
|
||||
if (state.address.length < 1) {
|
||||
errors.address = 'Address is not set';
|
||||
} else if (!EthereumjsUtil.isValidAddress(state.address)) {
|
||||
errors.address = 'Address is not valid';
|
||||
} else if (state.warnings.address) {
|
||||
// address warning or info are set in addressValidation ThunkAction
|
||||
// do not override this
|
||||
warnings.address = state.warnings.address;
|
||||
if (state.infos.address) {
|
||||
infos.address = state.infos.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +380,7 @@ export const validation = (props: Props): void => {
|
||||
errors.amount = 'Amount is not a number';
|
||||
} else {
|
||||
let decimalRegExp: RegExp;
|
||||
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, state.currency !== state.networkSymbol);
|
||||
const pendingAmount: BigNumber = getPendingAmount(pending, state.currency, state.currency !== state.networkSymbol);
|
||||
|
||||
if (state.currency !== state.networkSymbol) {
|
||||
const token = findToken(tokens, account.address, state.currency, account.deviceState);
|
||||
@ -612,7 +616,7 @@ export const updateFeeLevels = (): ThunkAction => (dispatch: Dispatch, getState:
|
||||
// update only gasPrice
|
||||
currentState.selectedFeeLevel.gasPrice = currentState.recommendedGasPrice;
|
||||
// leave gas limit as it was
|
||||
gasLimit = currentState.gasLimit;
|
||||
({ gasLimit } = currentState);
|
||||
}
|
||||
|
||||
const feeLevels: Array<FeeLevel> = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel);
|
||||
@ -659,9 +663,8 @@ export const onGasPriceChange = (gasPrice: string): ThunkAction => (dispatch: Di
|
||||
});
|
||||
};
|
||||
|
||||
export const onGasLimitChange = (gasLimit: string, updateFeeLevels: boolean = false): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const onGasLimitChange = (gasLimit: string/* , shouldUpdateFeeLevels: boolean = false */): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const isToken: boolean = currentState.currency !== currentState.networkSymbol;
|
||||
|
||||
const touched = { ...currentState.touched };
|
||||
touched.gasLimit = true;
|
||||
@ -704,34 +707,6 @@ export const onNonceChange = (nonce: string): AsyncAction => async (dispatch: Di
|
||||
});
|
||||
};
|
||||
|
||||
export const onDataChange = (data: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const touched = { ...currentState.touched };
|
||||
touched.data = true;
|
||||
|
||||
const state: State = {
|
||||
...currentState,
|
||||
calculatingGasLimit: true,
|
||||
untouched: false,
|
||||
touched,
|
||||
data,
|
||||
};
|
||||
|
||||
if (currentState.selectedFeeLevel.value !== 'Custom') {
|
||||
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
||||
if (!customLevel) return;
|
||||
state.selectedFeeLevel = customLevel;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: SEND.DATA_CHANGE,
|
||||
state,
|
||||
});
|
||||
|
||||
dispatch(estimateGasPrice());
|
||||
};
|
||||
|
||||
|
||||
const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const {
|
||||
web3,
|
||||
@ -771,6 +746,33 @@ const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState:
|
||||
}
|
||||
};
|
||||
|
||||
export const onDataChange = (data: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const touched = { ...currentState.touched };
|
||||
touched.data = true;
|
||||
|
||||
const state: State = {
|
||||
...currentState,
|
||||
calculatingGasLimit: true,
|
||||
untouched: false,
|
||||
touched,
|
||||
data,
|
||||
};
|
||||
|
||||
if (currentState.selectedFeeLevel.value !== 'Custom') {
|
||||
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
||||
if (!customLevel) return;
|
||||
state.selectedFeeLevel = customLevel;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: SEND.DATA_CHANGE,
|
||||
state,
|
||||
});
|
||||
|
||||
dispatch(estimateGasPrice());
|
||||
};
|
||||
|
||||
export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const {
|
||||
account,
|
||||
@ -806,7 +808,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge
|
||||
txAddress = token.address;
|
||||
}
|
||||
|
||||
const pendingNonce: number = stateUtils.getPendingNonce(pending);
|
||||
const pendingNonce: number = getPendingNonce(pending);
|
||||
const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce;
|
||||
|
||||
console.warn('NONCE', nonce, account.nonce, pendingNonce);
|
||||
|
@ -1,17 +1,11 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import * as SUMMARY from 'actions/constants/summary';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import { resolveAfter } from 'utils/promiseUtils';
|
||||
import { initialState } from 'reducers/SummaryReducer';
|
||||
|
||||
import type {
|
||||
ThunkAction, AsyncAction, Action, GetState, Dispatch,
|
||||
ThunkAction, Action, Dispatch,
|
||||
} from 'flowtype';
|
||||
import type { State } from 'reducers/SummaryReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
|
||||
export type SummaryAction = {
|
||||
type: typeof SUMMARY.INIT,
|
||||
@ -22,7 +16,7 @@ export type SummaryAction = {
|
||||
type: typeof SUMMARY.DETAILS_TOGGLE
|
||||
}
|
||||
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
const state: State = {
|
||||
...initialState,
|
||||
};
|
||||
|
@ -25,10 +25,6 @@ export type TokenAction = {
|
||||
payload: State
|
||||
}
|
||||
|
||||
type SelectOptions = {
|
||||
options?: Array<NetworkToken>
|
||||
}
|
||||
|
||||
|
||||
// action from component <reactSelect>
|
||||
export const load = (input: string, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<any> => {
|
||||
@ -57,6 +53,20 @@ export const load = (input: string, network: string): AsyncAction => async (disp
|
||||
//await resolveAfter(3000);
|
||||
};
|
||||
|
||||
export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const newState: Array<Token> = [...getState().tokens];
|
||||
const token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress);
|
||||
if (token) {
|
||||
token.loaded = true;
|
||||
token.balance = balance;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: TOKEN.SET_BALANCE,
|
||||
payload: newState,
|
||||
});
|
||||
};
|
||||
|
||||
export const add = (token: NetworkToken, account: Account): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.find(w3 => w3.network === account.network);
|
||||
if (!web3instance) return;
|
||||
@ -82,20 +92,6 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => async
|
||||
dispatch(setBalance(token.address, account.address, tokenBalance));
|
||||
};
|
||||
|
||||
export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const newState: Array<Token> = [...getState().tokens];
|
||||
const token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress);
|
||||
if (token) {
|
||||
token.loaded = true;
|
||||
token.balance = balance;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: TOKEN.SET_BALANCE,
|
||||
payload: newState,
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = (token: Token): Action => ({
|
||||
type: TOKEN.REMOVE,
|
||||
token,
|
||||
|
@ -1,10 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import TrezorConnect, {
|
||||
UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT,
|
||||
DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT,
|
||||
} from 'trezor-connect';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
@ -82,6 +79,13 @@ export type TrezorConnectAction = {
|
||||
};
|
||||
|
||||
|
||||
const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
}
|
||||
return a.ts > b.ts ? -1 : 1;
|
||||
});
|
||||
|
||||
export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
// set listeners
|
||||
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
|
||||
@ -112,7 +116,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
|
||||
});
|
||||
|
||||
// $FlowIssue LOCAL not declared
|
||||
window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/';
|
||||
//window.__TREZOR_CONNECT_SRC = 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = 'https://localhost:8088/';
|
||||
@ -133,71 +137,6 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
|
||||
}
|
||||
};
|
||||
|
||||
// called after backend was initialized
|
||||
// set listeners for connect/disconnect
|
||||
export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const handleDeviceConnect = (device: Device) => {
|
||||
dispatch(initConnectedDevice(device));
|
||||
};
|
||||
|
||||
TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
const { devices } = getState();
|
||||
|
||||
const { initialPathname, initialParams } = getState().wallet;
|
||||
|
||||
if (initialPathname) {
|
||||
dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
// pathname: null,
|
||||
// params: null
|
||||
});
|
||||
}
|
||||
|
||||
if (devices.length > 0) {
|
||||
const unacquired: ?TrezorDevice = devices.find(d => d.features);
|
||||
if (unacquired) {
|
||||
dispatch(onSelectDevice(unacquired));
|
||||
} else {
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch(onSelectDevice(firstConnected || latest[0]));
|
||||
|
||||
// TODO
|
||||
if (initialParams) {
|
||||
if (!initialParams.hasOwnProperty('network') && initialPathname !== getState().router.location.pathname) {
|
||||
// dispatch( push(initialPathname) );
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
}
|
||||
return a.ts > b.ts ? -1 : 1;
|
||||
});
|
||||
|
||||
export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
// if (!selected || (selected && selected.state)) {
|
||||
dispatch(onSelectDevice(device));
|
||||
// }
|
||||
// if (device.unacquired && selected && selected.path !== device.path && !selected.connected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// } else if (!selected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// }
|
||||
};
|
||||
|
||||
// selection from Aside dropdown button
|
||||
// after device_connect event
|
||||
// or after acquiring device
|
||||
@ -242,6 +181,62 @@ export const onSelectDevice = (device: TrezorDevice | Device): ThunkAction => (d
|
||||
}
|
||||
};
|
||||
|
||||
export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch/* , getState: GetState */): void => {
|
||||
// const selected = getState().wallet.selectedDevice;
|
||||
// if (!selected || (selected && selected.state)) {
|
||||
dispatch(onSelectDevice(device));
|
||||
// }
|
||||
// if (device.unacquired && selected && selected.path !== device.path && !selected.connected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// } else if (!selected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// }
|
||||
};
|
||||
|
||||
// called after backend was initialized
|
||||
// set listeners for connect/disconnect
|
||||
export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const handleDeviceConnect = (device: Device) => {
|
||||
dispatch(initConnectedDevice(device));
|
||||
};
|
||||
|
||||
TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
const { devices } = getState();
|
||||
|
||||
const { initialPathname, initialParams } = getState().wallet;
|
||||
|
||||
if (initialPathname) {
|
||||
dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
// pathname: null,
|
||||
// params: null
|
||||
});
|
||||
}
|
||||
|
||||
if (devices.length > 0) {
|
||||
const unacquired: ?TrezorDevice = devices.find(d => d.features);
|
||||
if (unacquired) {
|
||||
dispatch(onSelectDevice(unacquired));
|
||||
} else {
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch(onSelectDevice(firstConnected || latest[0]));
|
||||
|
||||
// TODO
|
||||
if (initialParams) {
|
||||
if (!initialParams.hasOwnProperty('network') && initialPathname !== getState().router.location.pathname) {
|
||||
// dispatch( push(initialPathname) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const switchToFirstAvailableDevice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const { devices } = getState();
|
||||
if (devices.length > 0) {
|
||||
@ -388,7 +383,7 @@ export function acquire(): AsyncAction {
|
||||
};
|
||||
}
|
||||
|
||||
export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch): void => {
|
||||
if (device.features) {
|
||||
const devUrl: string = `${device.features.device_id}${device.instance ? `:${device.instance}` : ''}`;
|
||||
dispatch(push(`/device/${devUrl}/settings`));
|
||||
|
@ -3,16 +3,10 @@
|
||||
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
|
||||
import type
|
||||
{
|
||||
Account,
|
||||
Coin,
|
||||
Discovery,
|
||||
Token,
|
||||
Web3Instance,
|
||||
Device,
|
||||
TrezorDevice,
|
||||
RouterLocationState,
|
||||
@ -47,8 +41,8 @@ export type WalletAction = {
|
||||
devices: Array<TrezorDevice>
|
||||
}
|
||||
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const updateOnlineStatus = (event) => {
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
const updateOnlineStatus = () => {
|
||||
dispatch({
|
||||
type: WALLET.ONLINE_STATUS,
|
||||
online: navigator.onLine,
|
||||
@ -72,7 +66,7 @@ export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({
|
||||
// all saved instances will be removed immediately inside DevicesReducer
|
||||
// This method will clear leftovers associated with removed instances from reducers.
|
||||
// (DiscoveryReducer, AccountReducer, TokensReducer)
|
||||
export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => (dispatch: Dispatch): void => {
|
||||
if (!device.features) return;
|
||||
|
||||
const affectedDevices = prevState.devices.filter(d => d.features && device.features
|
||||
|
@ -1,23 +1,19 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import Web3 from 'web3';
|
||||
import HDKey from 'hdkey';
|
||||
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import type { ContractFactory, EstimateGasOptions } from 'web3';
|
||||
import type {
|
||||
ContractFactory,
|
||||
EstimateGasOptions,
|
||||
TransactionStatus,
|
||||
TransactionReceipt,
|
||||
} from 'web3';
|
||||
import type BigNumber from 'bignumber.js';
|
||||
import type { TransactionStatus, TransactionReceipt } from 'web3';
|
||||
import { strip } from 'utils/ethUtils';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
|
||||
import type {
|
||||
Dispatch,
|
||||
GetState,
|
||||
Action,
|
||||
AsyncAction,
|
||||
} from 'flowtype';
|
||||
|
||||
@ -29,15 +25,6 @@ import type { NetworkToken } from 'reducers/LocalStorageReducer';
|
||||
import * as TokenActions from './TokenActions';
|
||||
import * as AccountsActions from './AccountsActions';
|
||||
|
||||
export type Web3Action = {
|
||||
type: typeof WEB3.READY,
|
||||
} | {
|
||||
type: typeof WEB3.CREATE,
|
||||
instance: Web3Instance
|
||||
}
|
||||
| Web3UpdateBlockAction
|
||||
| Web3UpdateGasPriceAction;
|
||||
|
||||
export type Web3UpdateBlockAction = {
|
||||
type: typeof WEB3.BLOCK_UPDATED,
|
||||
network: string,
|
||||
@ -50,6 +37,14 @@ export type Web3UpdateGasPriceAction = {
|
||||
gasPrice: string
|
||||
};
|
||||
|
||||
export type Web3Action = {
|
||||
type: typeof WEB3.READY,
|
||||
} | {
|
||||
type: typeof WEB3.CREATE,
|
||||
instance: Web3Instance
|
||||
}
|
||||
| Web3UpdateBlockAction
|
||||
| Web3UpdateGasPriceAction;
|
||||
|
||||
export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
@ -64,7 +59,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
return;
|
||||
}
|
||||
|
||||
const network = coin.network;
|
||||
const { network } = coin;
|
||||
const urls = coin.backends[0].urls;
|
||||
|
||||
let web3host: string = urls[0];
|
||||
@ -150,7 +145,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
|
||||
//const shh = instance.shh.newIdentity();
|
||||
|
||||
const latestBlockFilter = web3.eth.filter('latest');
|
||||
// const latestBlockFilter = web3.eth.filter('latest');
|
||||
|
||||
const onBlockMined = async (error: ?Error, blockHash: ?string) => {
|
||||
if (error) {
|
||||
@ -186,16 +181,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
}
|
||||
|
||||
const tokens = getState().tokens.filter(t => t.network === network);
|
||||
for (const token of tokens) {
|
||||
dispatch(getTokenBalance(token));
|
||||
}
|
||||
tokens.forEach(token => dispatch(getTokenBalance(token)));
|
||||
|
||||
dispatch(getGasPrice(network));
|
||||
|
||||
const pending = getState().pending.filter(p => p.network === network);
|
||||
for (const tx of pending) {
|
||||
dispatch(getTransactionReceipt(tx));
|
||||
}
|
||||
pending.forEach(pendingTx => dispatch(getTransactionReceipt(pendingTx)));
|
||||
};
|
||||
|
||||
// latestBlockFilter.watch(onBlockMined);
|
||||
@ -220,7 +211,7 @@ export function getGasPrice(network: string): AsyncAction {
|
||||
const index: number = getState().web3.findIndex(w3 => w3.network === network);
|
||||
|
||||
const web3instance = getState().web3[index];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
web3.eth.getGasPrice((error, gasPrice) => {
|
||||
if (!error) {
|
||||
if (web3instance.gasPrice && web3instance.gasPrice.toString() !== gasPrice.toString()) {
|
||||
@ -238,7 +229,7 @@ export function getGasPrice(network: string): AsyncAction {
|
||||
export function getBalance(account: Account): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||
const web3: Web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getBalance(account.address, (error: Error, balance: BigNumber) => {
|
||||
if (!error) {
|
||||
@ -261,7 +252,6 @@ export function getBalance(account: Account): AsyncAction {
|
||||
export function getTokenBalance(token: Token): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === token.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const contract = web3instance.erc20.at(token.address);
|
||||
|
||||
contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => {
|
||||
@ -282,7 +272,7 @@ export function getTokenBalance(token: Token): AsyncAction {
|
||||
export function getNonce(account: Account): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getTransactionCount(account.address, (error: Error, result: number) => {
|
||||
if (!error) {
|
||||
@ -296,7 +286,7 @@ export function getNonce(account: Account): AsyncAction {
|
||||
|
||||
export const getTransactionReceipt = (tx: PendingTx): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getTransaction(tx.id, (error: Error, status: TransactionStatus) => {
|
||||
if (!error && !status) {
|
||||
@ -367,8 +357,8 @@ export const getNonceAsync = (web3: Web3, address: string): Promise<number> => n
|
||||
});
|
||||
|
||||
|
||||
export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise<?NetworkToken> => new Promise((resolve, reject) => {
|
||||
const contract = erc20.at(address, (error, res) => {
|
||||
export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise<?NetworkToken> => new Promise((resolve) => {
|
||||
const contract = erc20.at(address, (error/* , res */) => {
|
||||
// console.warn("callback", error, res)
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import Icon from 'components/Icon';
|
||||
import colors from 'config/colors';
|
||||
import { TRANSITION } from 'config/variables';
|
||||
|
||||
@ -118,9 +117,11 @@ const Button = ({
|
||||
isWhite = false,
|
||||
isWebUsb = false,
|
||||
isTransparent = false,
|
||||
}) => (
|
||||
}) => {
|
||||
const newClassName = isWebUsb ? `${className} trezor-webusb-button` : className;
|
||||
return (
|
||||
<Wrapper
|
||||
className={className}
|
||||
className={newClassName}
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
@ -133,6 +134,7 @@ const Button = ({
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
@ -164,9 +163,9 @@ export const Notification = (props: NProps): React$Element<string> => {
|
||||
|
||||
export const NotificationGroup = (props) => {
|
||||
const { notifications, close } = props;
|
||||
return notifications.map((n, i) => (
|
||||
return notifications.map(n => (
|
||||
<Notification
|
||||
key={i}
|
||||
key={n.title}
|
||||
type={n.type}
|
||||
title={n.title}
|
||||
message={n.message}
|
||||
|
@ -11,11 +11,6 @@ const Wrapper = styled.div`
|
||||
justify-content: flex-start;
|
||||
`;
|
||||
|
||||
const Label = styled.span`
|
||||
padding-bottom: 4px;
|
||||
color: ${colors.TEXT_SECONDARY};
|
||||
`;
|
||||
|
||||
const disabledColor = colors.TEXT_PRIMARY;
|
||||
|
||||
const TextArea = styled.textarea`
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled, { css } from 'styled-components';
|
||||
import styled from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import Icon from 'components/Icon';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
|
@ -8,9 +8,8 @@ import colors from 'config/colors';
|
||||
import icons from 'config/icons';
|
||||
import Button from 'components/Button';
|
||||
import Link from 'components/Link';
|
||||
import { findAccount } from 'reducers/AccountsReducer';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
position: absolute;
|
||||
@ -38,15 +37,6 @@ const StyledButton = styled(Button)`
|
||||
`;
|
||||
|
||||
class ConfirmUnverifiedAddress extends Component<Props> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
this.verifyAddress();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.keyboardHandler = this.keyboardHandler.bind(this);
|
||||
window.addEventListener('keydown', this.keyboardHandler, false);
|
||||
@ -56,6 +46,15 @@ class ConfirmUnverifiedAddress extends Component<Props> {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
}
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
this.verifyAddress();
|
||||
}
|
||||
}
|
||||
|
||||
verifyAddress() {
|
||||
if (!this.props.modal.opened) return;
|
||||
const {
|
||||
|
@ -63,12 +63,12 @@ const ErrorMessage = styled.div`
|
||||
`;
|
||||
|
||||
export default class DuplicateDevice extends Component<Props, State> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
input: ?HTMLInputElement;
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -85,13 +85,6 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13 && !this.state.isUsed) {
|
||||
event.preventDefault();
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
// one time autofocus
|
||||
if (this.input) this.input.focus();
|
||||
@ -115,6 +108,13 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13 && !this.state.isUsed) {
|
||||
event.preventDefault();
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (!this.props.modal.opened) return;
|
||||
const extended: Object = { instanceName: this.state.instanceName, instance: this.state.instance };
|
||||
@ -125,7 +125,7 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
if (!this.props.modal.opened) return null;
|
||||
|
||||
const { device } = this.props.modal;
|
||||
const { onCancel, onDuplicateDevice } = this.props.modalActions;
|
||||
const { onCancel } = this.props.modalActions;
|
||||
const {
|
||||
defaultName,
|
||||
instanceName,
|
||||
|
@ -6,7 +6,7 @@ import P from 'components/Paragraph';
|
||||
import Loader from 'components/Loader';
|
||||
import Button from 'components/Button';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
type State = {
|
||||
countdown: number;
|
||||
@ -77,9 +77,9 @@ export default class RememberDevice extends Component<Props, State> {
|
||||
this.props.modalActions.onForgetDevice(this.props.modal.device);
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
countdown: this.state.countdown - 1,
|
||||
});
|
||||
this.setState(previousState => ({
|
||||
countdown: previousState.countdown - 1,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@ -108,16 +108,16 @@ export default class RememberDevice extends Component<Props, State> {
|
||||
render() {
|
||||
if (!this.props.modal.opened) return null;
|
||||
const { device, instances } = this.props.modal;
|
||||
const { onForgetDevice, onRememberDevice } = this.props.modalActions;
|
||||
const { onRememberDevice } = this.props.modalActions;
|
||||
|
||||
let label = device.label;
|
||||
let { label } = device;
|
||||
const devicePlural: string = instances && instances.length > 1 ? 'devices or to remember them' : 'device or to remember it';
|
||||
if (instances && instances.length > 0) {
|
||||
label = instances.map((instance, index) => {
|
||||
let comma: string = '';
|
||||
if (index > 0) comma = ', ';
|
||||
return (
|
||||
<span key={index}>{ comma }{ instance.instanceLabel }</span>
|
||||
<span key={instance.instanceLabel}>{ comma }{ instance.instanceLabel }</span>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import { CSSTransition } from 'react-transition-group';
|
||||
|
||||
import { UI } from 'trezor-connect';
|
||||
|
||||
import { default as ModalActions } from 'actions/ModalActions';
|
||||
import { default as ReceiveActions } from 'actions/ReceiveActions';
|
||||
import ModalActions from 'actions/ModalActions';
|
||||
import ReceiveActions from 'actions/ReceiveActions';
|
||||
|
||||
import * as RECEIVE from 'actions/constants/receive';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
@ -51,8 +51,6 @@ type DispatchProps = {
|
||||
|
||||
export type Props = StateProps & DispatchProps;
|
||||
|
||||
const duration = 300;
|
||||
|
||||
const Fade = ({ children, ...props }) => (
|
||||
<CSSTransition
|
||||
{...props}
|
||||
@ -125,7 +123,8 @@ class Modal extends Component<Props> {
|
||||
component = (<DuplicateDevice {...this.props} />);
|
||||
break;
|
||||
|
||||
default: null;
|
||||
default:
|
||||
component = null;
|
||||
}
|
||||
|
||||
let ch = null;
|
||||
@ -145,7 +144,7 @@ class Modal extends Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||
modal: state.modal,
|
||||
accounts: state.accounts,
|
||||
devices: state.devices,
|
||||
|
@ -4,14 +4,13 @@ import raf from 'raf';
|
||||
import colors from 'config/colors';
|
||||
import P from 'components/Paragraph';
|
||||
import { FONT_SIZE } from 'config/variables';
|
||||
import { H2 } from 'components/Heading';
|
||||
import Link from 'components/Link';
|
||||
import Checkbox from 'components/Checkbox';
|
||||
import Button from 'components/Button';
|
||||
import Input from 'components/inputs/Input';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 24px 48px;
|
||||
@ -55,14 +54,6 @@ type State = {
|
||||
}
|
||||
|
||||
export default class PinModal extends Component<Props, State> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
passphraseInput: ?HTMLInputElement;
|
||||
|
||||
passphraseRevisionInput: ?HTMLInputElement;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -91,6 +82,15 @@ export default class PinModal extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
passphraseInput: ?HTMLInputElement;
|
||||
|
||||
passphraseRevisionInput: ?HTMLInputElement;
|
||||
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
@ -108,6 +108,7 @@ export default class PinModal extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount(): void {
|
||||
// one time autofocus
|
||||
if (this.passphraseInput) this.passphraseInput.focus();
|
||||
@ -124,15 +125,6 @@ export default class PinModal extends Component<Props, State> {
|
||||
// };
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
// this.passphraseInput.type = 'text';
|
||||
// this.passphraseInput.style.display = 'none';
|
||||
// this.passphraseRevisionInput.type = 'text';
|
||||
// this.passphraseRevisionInput.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
// we don't want to keep password inside "value" attribute,
|
||||
// so we need to replace it thru javascript
|
||||
componentDidUpdate() {
|
||||
@ -164,21 +156,30 @@ export default class PinModal extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
// this.passphraseInput.type = 'text';
|
||||
// this.passphraseInput.style.display = 'none';
|
||||
// this.passphraseRevisionInput.type = 'text';
|
||||
// this.passphraseRevisionInput.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
onPassphraseChange = (input: string, value: string): void => {
|
||||
// https://codepen.io/MiDri/pen/PGqvrO
|
||||
// or
|
||||
// https://github.com/zakangelle/react-password-mask/blob/master/src/index.js
|
||||
if (input === 'passphrase') {
|
||||
this.setState({
|
||||
match: this.state.singleInput || this.state.passphraseRevision === value,
|
||||
this.setState(previousState => ({
|
||||
match: previousState.singleInput || previousState.passphraseRevision === value,
|
||||
passphrase: value,
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
this.setState({
|
||||
match: this.state.passphrase === value,
|
||||
this.setState(previousState => ({
|
||||
match: previousState.passphrase === value,
|
||||
passphraseRevision: value,
|
||||
passphraseRevisionTouched: true,
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import P from 'components/Paragraph';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 24px 48px;
|
||||
|
@ -3,12 +3,11 @@ import P from 'components/Paragraph';
|
||||
import { H2 } from 'components/Heading';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'components/Link';
|
||||
import colors from 'config/colors';
|
||||
import styled from 'styled-components';
|
||||
import PinInput from 'components/inputs/PinInput';
|
||||
import Button from 'components/Button';
|
||||
import PinButton from './components/PinButton';
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
type State = {
|
||||
pin: string;
|
||||
@ -53,7 +52,7 @@ class Pin extends Component<Props, State> {
|
||||
}
|
||||
|
||||
onPinAdd = (input: number): void => {
|
||||
let pin: string = this.state.pin;
|
||||
let { pin } = this.state;
|
||||
if (pin.length < 9) {
|
||||
pin += input;
|
||||
this.setState({
|
||||
@ -63,9 +62,9 @@ class Pin extends Component<Props, State> {
|
||||
}
|
||||
|
||||
onPinBackspace = (): void => {
|
||||
this.setState({
|
||||
pin: this.state.pin.substring(0, this.state.pin.length - 1),
|
||||
});
|
||||
this.setState(previousState => ({
|
||||
pin: previousState.pin.substring(0, previousState.pin.length - 1),
|
||||
}));
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
|
@ -7,11 +7,10 @@ import type {
|
||||
Middleware as ReduxMiddleware,
|
||||
ThunkAction as ReduxThunkAction,
|
||||
AsyncAction as ReduxAsyncAction,
|
||||
ThunkDispatch as ReduxThunkDispatch,
|
||||
PlainDispatch as ReduxPlainDispatch,
|
||||
} from 'redux';
|
||||
|
||||
import type { Reducers, ReducersState } from 'reducers';
|
||||
import type { ReducersState } from 'reducers';
|
||||
|
||||
// Actions
|
||||
import type { SelectedAccountAction } from 'actions/SelectedAccountActions';
|
||||
|
@ -22,7 +22,7 @@ const mergeDevices = (current: TrezorDevice, upcoming: Device | TrezorDevice): T
|
||||
// }
|
||||
// }
|
||||
|
||||
let instanceLabel = current.instanceLabel;
|
||||
let { instanceLabel } = current;
|
||||
if (upcoming.label !== current.label) {
|
||||
instanceLabel = upcoming.label;
|
||||
if (typeof current.instance === 'number') {
|
||||
|
@ -62,9 +62,10 @@ const closeNotification = (state: State, payload: any): State => {
|
||||
|
||||
export default function notification(state: State = initialState, action: Action): State {
|
||||
switch (action.type) {
|
||||
case DEVICE.DISCONNECT:
|
||||
const path: string = action.device.path; // Flow warning
|
||||
case DEVICE.DISCONNECT: {
|
||||
const { path } = action.device; // Flow warning
|
||||
return state.filter(entry => entry.devicePath !== path);
|
||||
}
|
||||
|
||||
case NOTIFICATION.ADD:
|
||||
return addNotification(state, action.payload);
|
||||
|
@ -1,9 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
|
||||
import type { Action } from 'flowtype';
|
||||
import type { SendTxAction } from 'actions/SendFormActions';
|
||||
|
@ -2,11 +2,9 @@
|
||||
|
||||
|
||||
import EthereumjsUnits from 'ethereumjs-units';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
|
||||
import { getFeeLevels } from 'actions/SendFormActions';
|
||||
|
||||
@ -15,6 +13,12 @@ import type {
|
||||
Web3UpdateGasPriceAction,
|
||||
} from 'actions/Web3Actions';
|
||||
|
||||
export type FeeLevel = {
|
||||
label: string;
|
||||
gasPrice: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type State = {
|
||||
+networkName: string;
|
||||
+networkSymbol: string;
|
||||
@ -45,12 +49,6 @@ export type State = {
|
||||
sending: boolean;
|
||||
}
|
||||
|
||||
export type FeeLevel = {
|
||||
label: string;
|
||||
gasPrice: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
|
||||
export const initialState: State = {
|
||||
networkName: '',
|
||||
|
@ -1,9 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { TRANSPORT, DEVICE, UI } from 'trezor-connect';
|
||||
import { TRANSPORT, UI } from 'trezor-connect';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
|
||||
import type { Action } from 'flowtype';
|
||||
|
||||
|
@ -17,7 +17,7 @@ export const getSelectedDevice = (state: State): ?TrezorDevice => {
|
||||
const locationState = state.router.location.state;
|
||||
if (!locationState.device) return undefined;
|
||||
|
||||
const instance: ?number = locationState.deviceInstance ? parseInt(locationState.deviceInstance) : undefined;
|
||||
const instance: ?number = locationState.deviceInstance ? parseInt(locationState.deviceInstance, 10) : undefined;
|
||||
return state.devices.find((d) => {
|
||||
if (!d.features && d.path === locationState.device) {
|
||||
return true;
|
||||
@ -64,14 +64,14 @@ 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);
|
||||
const index: number = parseInt(locationState.account, 10);
|
||||
|
||||
return state.accounts.find(a => a.deviceState === device.state && a.index === index && a.network === locationState.network);
|
||||
};
|
||||
|
||||
export const getSelectedNetwork = (state: State): ?Coin => {
|
||||
const device = state.wallet.selectedDevice;
|
||||
const coins = state.localStorage.config.coins;
|
||||
const { coins } = state.localStorage.config;
|
||||
const locationState = state.router.location.state;
|
||||
if (!device || !locationState.network) return null;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import { JSONRequest, httpRequest } from 'utils/networkUtils';
|
||||
import { httpRequest } from 'utils/networkUtils';
|
||||
import { resolveAfter } from 'utils/promiseUtils';
|
||||
import { READY } from 'actions/constants/localStorage';
|
||||
|
||||
@ -8,7 +8,6 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
|
@ -1,18 +1,13 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as LocalStorageActions from 'actions/LocalStorageActions';
|
||||
import * as WalletActions from 'actions/WalletActions';
|
||||
// import * as WalletActions from 'actions/WalletActions';
|
||||
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as MODAL from 'actions/constants/modal';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as DISCOVERY from 'actions/constants/discovery';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
import { findAccountTokens } from 'reducers/TokensReducer';
|
||||
|
||||
@ -20,14 +15,12 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
|
||||
import type { TrezorDevice } from 'flowtype';
|
||||
import type { Account } from 'reducers/AccountsReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
import type { PendingTx } from 'reducers/PendingTxReducer';
|
||||
|
@ -1,29 +1,23 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import * as LogActions from 'actions/LogActions';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import { OPEN, CLOSE, ADD } from 'actions/constants/log';
|
||||
// import * as STORAGE from 'actions/constants/localStorage';
|
||||
// import * as SEND from 'actions/constants/send';
|
||||
// import { OPEN, CLOSE, ADD } from 'actions/constants/log';
|
||||
import { TRANSPORT, DEVICE } from 'trezor-connect';
|
||||
|
||||
import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
} from 'flowtype';
|
||||
|
||||
const exclude: Array<string> = [
|
||||
ADD, OPEN, CLOSE,
|
||||
STORAGE.READY,
|
||||
SEND.TX_COMPLETE,
|
||||
'web3__create',
|
||||
];
|
||||
// const exclude: Array<string> = [
|
||||
// ADD, OPEN, CLOSE,
|
||||
// STORAGE.READY,
|
||||
// SEND.TX_COMPLETE,
|
||||
// 'web3__create',
|
||||
// ];
|
||||
|
||||
const include: Array<string> = [
|
||||
TRANSPORT.START,
|
||||
|
@ -1,8 +1,5 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
import { LOCATION_CHANGE, push, replace } from 'react-router-redux';
|
||||
import { LOCATION_CHANGE/* , replace */ } from 'react-router-redux';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
import * as NotificationActions from 'actions/NotificationActions';
|
||||
@ -11,12 +8,7 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
ThunkAction,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
RouterLocationState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
@ -51,7 +43,7 @@ const validation = (api: MiddlewareAPI, params: RouterLocationState): boolean =>
|
||||
|
||||
let device: ?TrezorDevice;
|
||||
if (params.hasOwnProperty('deviceInstance')) {
|
||||
device = devices.find(d => d.features && d.features.device_id === params.device && d.instance === parseInt(params.deviceInstance));
|
||||
device = devices.find(d => d.features && d.features.device_id === params.device && d.instance === parseInt(params.deviceInstance, 10));
|
||||
} else {
|
||||
device = devices.find(d => d.path === params.device || (d.features && d.features.device_id === params.device));
|
||||
}
|
||||
@ -61,25 +53,20 @@ const validation = (api: MiddlewareAPI, params: RouterLocationState): boolean =>
|
||||
|
||||
if (params.hasOwnProperty('network')) {
|
||||
const { config } = api.getState().localStorage;
|
||||
const coin = config.coins.find(coin => coin.network === params.network);
|
||||
const coin = config.coins.find(c => c.network === params.network);
|
||||
if (!coin) return false;
|
||||
if (!params.account) return false;
|
||||
}
|
||||
|
||||
if (params.account) {
|
||||
// if (params.account) {
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
let __unloading: boolean = false;
|
||||
|
||||
const LandingURLS: Array<string> = [
|
||||
'/',
|
||||
'/bridge',
|
||||
];
|
||||
|
||||
const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
||||
if (action.type === WALLET.ON_BEFORE_UNLOAD) {
|
||||
__unloading = true;
|
||||
|
@ -1,10 +1,8 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
import TrezorConnect, {
|
||||
TRANSPORT, DEVICE_EVENT, UI_EVENT, UI, DEVICE,
|
||||
import {
|
||||
TRANSPORT, DEVICE,
|
||||
} from 'trezor-connect';
|
||||
import * as TrezorConnectActions from 'actions/TrezorConnectActions';
|
||||
import * as DiscoveryActions from 'actions/DiscoveryActions';
|
||||
@ -13,25 +11,19 @@ import { init as initWeb3 } from 'actions/Web3Actions';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as MODAL from 'actions/constants/modal';
|
||||
|
||||
import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
RouterLocationState,
|
||||
} from 'flowtype';
|
||||
|
||||
const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
||||
const prevState: $ElementType<State, 'connect'> = api.getState().connect;
|
||||
// const prevState: $ElementType<State, 'connect'> = api.getState().connect;
|
||||
const prevModalState: $ElementType<State, 'modal'> = api.getState().modal;
|
||||
const prevRouterState: $ElementType<State, 'router'> = api.getState().router;
|
||||
// const prevRouterState: $ElementType<State, 'router'> = api.getState().router;
|
||||
|
||||
next(action);
|
||||
|
||||
|
17
src/store.js
17
src/store.js
@ -1,19 +1,18 @@
|
||||
/* @flow */
|
||||
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
import { routerMiddleware, push } from 'react-router-redux';
|
||||
import { routerMiddleware } from 'react-router-redux';
|
||||
import thunk from 'redux-thunk';
|
||||
// import createHistory from 'history/createBrowserHistory';
|
||||
// import { useRouterHistory } from 'react-router';
|
||||
import createHistory from 'history/createHashHistory';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import reducers from 'reducers';
|
||||
import services from 'services';
|
||||
|
||||
import Raven from 'raven-js';
|
||||
import RavenMiddleware from 'redux-raven-middleware';
|
||||
|
||||
import type { Action, GetState, Store } from 'flowtype';
|
||||
// import type { Action, GetState, Store } from 'flowtype';
|
||||
|
||||
export const history: History = createHistory({ queryKey: false });
|
||||
|
||||
@ -31,12 +30,12 @@ const middleware = [
|
||||
|
||||
let composedEnhancers: any;
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const excludeLogger = (getState: GetState, action: Action): boolean => {
|
||||
//'@@router/LOCATION_CHANGE'
|
||||
const excluded: Array<string> = ['LOG_TO_EXCLUDE', 'log__add'];
|
||||
const pass: Array<string> = excluded.filter(act => action.type === act);
|
||||
return pass.length === 0;
|
||||
};
|
||||
// const excludeLogger = (getState: GetState, action: Action): boolean => {
|
||||
// //'@@router/LOCATION_CHANGE'
|
||||
// const excluded: Array<string> = ['LOG_TO_EXCLUDE', 'log__add'];
|
||||
// const pass: Array<string> = excluded.filter(act => action.type === act);
|
||||
// return pass.length === 0;
|
||||
// };
|
||||
|
||||
composedEnhancers = compose(
|
||||
applyMiddleware(...middleware, ...services),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RedBox from 'redbox-react';
|
||||
|
||||
class ErrorBoundary extends Component {
|
||||
@ -7,7 +8,7 @@ class ErrorBoundary extends Component {
|
||||
this.state = { hasError: false, error: false };
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
componentDidCatch(error) {
|
||||
this.setState({ hasError: true, error });
|
||||
}
|
||||
|
||||
@ -19,4 +20,8 @@ class ErrorBoundary extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
@ -4,9 +4,9 @@ import BigNumber from 'bignumber.js';
|
||||
|
||||
export const decimalToHex = (dec: number): string => new BigNumber(dec).toString(16);
|
||||
|
||||
export const hexToDecimal = (hex: number): string => {
|
||||
const sanitized: ?string = sanitizeHex(hex);
|
||||
return !sanitized ? 'null' : new BigNumber(sanitized).toString();
|
||||
export const padLeftEven = (hex: string): string => {
|
||||
hex = hex.length % 2 != 0 ? `0${hex}` : hex;
|
||||
return hex;
|
||||
};
|
||||
|
||||
export const sanitizeHex = (hex: number | string): ?string => {
|
||||
@ -16,9 +16,9 @@ export const sanitizeHex = (hex: number | string): ?string => {
|
||||
return `0x${padLeftEven(hex)}`;
|
||||
};
|
||||
|
||||
export const padLeftEven = (hex: string): string => {
|
||||
hex = hex.length % 2 != 0 ? `0${hex}` : hex;
|
||||
return hex;
|
||||
export const hexToDecimal = (hex: number): string => {
|
||||
const sanitized: ?string = sanitizeHex(hex);
|
||||
return !sanitized ? 'null' : new BigNumber(sanitized).toString();
|
||||
};
|
||||
|
||||
export const strip = (str: string): string => {
|
||||
|
@ -28,7 +28,7 @@ export const formatTime = (n: number): string => {
|
||||
}
|
||||
res += ' ';
|
||||
}
|
||||
if (minutes != 0) {
|
||||
if (minutes !== 0) {
|
||||
res += `${minutes} minutes`;
|
||||
}
|
||||
return res;
|
||||
|
@ -1,7 +1,4 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
@ -39,7 +36,7 @@ const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: St
|
||||
devices: state.devices,
|
||||
});
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (/* dispatch: Dispatch */): DispatchProps => ({
|
||||
|
||||
});
|
||||
|
||||
|
@ -89,7 +89,9 @@ class ConnectDevice extends Component<Props> {
|
||||
{this.props.showWebUsb && (
|
||||
<React.Fragment>
|
||||
<P>and</P>
|
||||
<Button isWebUsb>Check for devices</Button>
|
||||
<Button isWebUsb>
|
||||
Check for devices
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Wrapper>
|
||||
|
@ -13,18 +13,18 @@ import P from 'components/Paragraph';
|
||||
import Icon from 'components/Icon';
|
||||
import ICONS from 'config/icons';
|
||||
|
||||
type State = {
|
||||
version: string;
|
||||
target: ?InstallTarget;
|
||||
url: string;
|
||||
}
|
||||
|
||||
type InstallTarget = {
|
||||
id: string;
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
type State = {
|
||||
version: string;
|
||||
target: ?InstallTarget;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// import type { Props } from './index';
|
||||
|
||||
type Props = {
|
||||
|
@ -138,7 +138,7 @@ export default (props: Props) => {
|
||||
)}
|
||||
<P>
|
||||
<LandingFooterTextWrapper>
|
||||
Don't have TREZOR?
|
||||
Don&t have TREZOR?
|
||||
</LandingFooterTextWrapper>
|
||||
<StyledLink
|
||||
href="https://trezor.io/"
|
||||
|
@ -16,7 +16,7 @@ type OwnProps = {
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State/* , own: OwnProps */): StateProps => ({
|
||||
connect: state.connect,
|
||||
accounts: state.accounts,
|
||||
router: state.router,
|
||||
|
@ -4,7 +4,6 @@ import BigNumber from 'bignumber.js';
|
||||
import Icon from 'components/Icon';
|
||||
import colors from 'config/colors';
|
||||
import Loader from 'components/Loader';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled, { css } from 'styled-components';
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
import Tooltip from 'components/Tooltip';
|
||||
|
@ -24,7 +24,7 @@ class DeviceList extends Component {
|
||||
device !== selectedDevice && (
|
||||
<DeviceHeader
|
||||
key={`${device.instanceLabel}`}
|
||||
onClickWrapper={() => this.props.onSelectDevice(device)}
|
||||
onClickWrapper={() => onSelectDevice(device)}
|
||||
onClickIcon={() => this.onDeviceMenuClick({ type: 'forget', label: '' }, device)}
|
||||
icon={(
|
||||
<IconClick onClick={(event) => {
|
||||
|
@ -3,7 +3,6 @@ import React, { Component } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import type { TrezorDevice } from 'flowtype';
|
||||
import DeviceHeader from 'components/DeviceHeader';
|
||||
import Button from 'components/Button';
|
||||
import { isWebUSB } from 'utils/device';
|
||||
import MenuItems from './components/MenuItems';
|
||||
@ -39,6 +38,13 @@ class DeviceMenu extends Component<Props> {
|
||||
this.blurHandler = this.blurHandler.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
window.addEventListener('mousedown', this.mouseDownHandler, false);
|
||||
// window.addEventListener('blur', this.blurHandler, false);
|
||||
const { transport } = this.props.connect;
|
||||
if (transport && transport.version.indexOf('webusb') >= 0) TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { transport } = this.props.connect;
|
||||
if (isWebUSB(transport)) TrezorConnect.renderWebUSBButton();
|
||||
@ -61,17 +67,10 @@ class DeviceMenu extends Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
blurHandler(event: FocusEvent): void {
|
||||
blurHandler(): void {
|
||||
this.props.toggleDeviceDropdown(false);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
window.addEventListener('mousedown', this.mouseDownHandler, false);
|
||||
// window.addEventListener('blur', this.blurHandler, false);
|
||||
const { transport } = this.props.connect;
|
||||
if (transport && transport.version.indexOf('webusb') >= 0) TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
onDeviceMenuClick(item: DeviceMenuItem, device: TrezorDevice): void {
|
||||
if (item.type === 'reload') {
|
||||
this.props.acquireDevice();
|
||||
|
@ -17,11 +17,26 @@ type Props = {
|
||||
|
||||
const AsideWrapper = styled.aside`
|
||||
position: relative;
|
||||
top: 0;
|
||||
width: 320px;
|
||||
min-width: 320px;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
background: ${colors.MAIN};
|
||||
border-right: 1px solid ${colors.DIVIDER};
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
border-right: 1px solid ${colors.DIVIDER};
|
||||
}
|
||||
|
||||
.fixed-bottom {
|
||||
padding-bottom: 60px;
|
||||
.sticky-bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
background: ${colors.MAIN};
|
||||
border-right: 1px solid ${colors.DIVIDER};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StickyContainerWrapper = styled.div`
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import colors from 'config/colors';
|
||||
import Icon from 'components/Icon';
|
||||
import Sticky from 'react-sticky-el';
|
||||
import icons from 'config/icons';
|
||||
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
||||
import styled from 'styled-components';
|
||||
@ -11,6 +12,8 @@ import CoinMenu from './components/CoinMenu';
|
||||
import DeviceMenu from './components/DeviceMenu';
|
||||
import StickyContainer from './components/StickyContainer';
|
||||
|
||||
const Header = styled(DeviceHeader)``;
|
||||
|
||||
const TransitionGroupWrapper = styled(TransitionGroup)`
|
||||
width: 640px;
|
||||
`;
|
||||
@ -21,14 +24,15 @@ const TransitionContentWrapper = styled.div`
|
||||
vertical-align: top;
|
||||
`;
|
||||
|
||||
const StickyBottom = styled.div`
|
||||
const Footer = styled.div`
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
background: ${colors.MAIN};
|
||||
border-right: 1px solid ${colors.DIVIDER};
|
||||
`;
|
||||
|
||||
const MenuWrapper = styled.div`
|
||||
const Body = styled.div`
|
||||
overflow: auto;
|
||||
background: ${colors.LANDING};
|
||||
`;
|
||||
|
||||
@ -40,11 +44,6 @@ const Help = styled.div`
|
||||
width: 319px;
|
||||
padding: 8px 0px;
|
||||
border-top: 1px solid ${colors.DIVIDER};
|
||||
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
}
|
||||
`;
|
||||
|
||||
const A = styled.a`
|
||||
@ -150,14 +149,12 @@ class LeftNavigation extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedDevice } = this.props.wallet;
|
||||
return (
|
||||
<StickyContainer
|
||||
location={this.props.location.pathname}
|
||||
deviceSelection={this.props.deviceDropdownOpened}
|
||||
>
|
||||
{selectedDevice && (
|
||||
<DeviceHeader
|
||||
<Header
|
||||
onClickWrapper={() => this.handleOpen()}
|
||||
device={this.props.wallet.selectedDevice}
|
||||
transport={this.props.connect.transport}
|
||||
@ -165,13 +162,12 @@ class LeftNavigation extends Component {
|
||||
isOpen={this.props.deviceDropdownOpened}
|
||||
{...this.props}
|
||||
/>
|
||||
) }
|
||||
<MenuWrapper>
|
||||
<Body>
|
||||
{this.state.shouldRenderDeviceSelection && <DeviceMenu {...this.props} />}
|
||||
{this.shouldRenderAccounts() && this.getMenuTransition(<AccountMenu {...this.props} />)}
|
||||
{this.shouldRenderCoins() && this.getMenuTransition(<CoinMenu {...this.props} />)}
|
||||
</MenuWrapper>
|
||||
<StickyBottom>
|
||||
</Body>
|
||||
<Footer className="sticky-bottom">
|
||||
<Help>
|
||||
<A
|
||||
href="https://trezor.io/support/"
|
||||
@ -181,7 +177,8 @@ class LeftNavigation extends Component {
|
||||
<Icon size={26} icon={icons.CHAT} color={colors.TEXT_SECONDARY} />Need help?
|
||||
</A>
|
||||
</Help>
|
||||
</StickyBottom>
|
||||
</Footer>
|
||||
<Sticky />
|
||||
</StickyContainer>
|
||||
);
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ const Wrapper = styled.div`
|
||||
class Indicator extends Component<Props, State> {
|
||||
reposition: () => void;
|
||||
|
||||
state: State;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -30,6 +28,8 @@ class Indicator extends Component<Props, State> {
|
||||
this.reposition = this.reposition.bind(this);
|
||||
}
|
||||
|
||||
state: State;
|
||||
|
||||
handleResize() {
|
||||
this.reposition();
|
||||
}
|
||||
@ -43,7 +43,7 @@ class Indicator extends Component<Props, State> {
|
||||
window.removeEventListener('resize', this.reposition, false);
|
||||
}
|
||||
|
||||
componentDidUpdate(newProps: Props) {
|
||||
componentDidUpdate() {
|
||||
this.reposition();
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,8 @@ const StyledNavLink = styled(NavLink)`
|
||||
}
|
||||
`;
|
||||
|
||||
const TopNavigationAccount = (props: any) => {
|
||||
|
||||
const TopNavigationAccount = (props) => {
|
||||
const urlParams = props.match.params;
|
||||
const basePath = `/device/${urlParams.device}/network/${urlParams.network}/account/${urlParams.account}`;
|
||||
|
||||
|
@ -20,13 +20,13 @@ import TopNavigationAccount from './components/TopNavigationAccount';
|
||||
import TopNavigationDeviceSettings from './components/TopNavigationDeviceSettings';
|
||||
|
||||
type WalletContainerProps = {
|
||||
wallet: $ElementType<State, 'wallet'>,
|
||||
// wallet: $ElementType<State, 'wallet'>,
|
||||
children?: React.Node
|
||||
}
|
||||
|
||||
type ContentProps = {
|
||||
children?: React.Node
|
||||
}
|
||||
// type ContentProps = {
|
||||
// children?: React.Node
|
||||
// }
|
||||
|
||||
const AppWrapper = styled.div`
|
||||
position: relative;
|
||||
@ -83,7 +83,7 @@ const Wallet = (props: WalletContainerProps) => (
|
||||
<AppWrapper>
|
||||
<Header />
|
||||
<WalletWrapper>
|
||||
<LeftNavigation />
|
||||
{props.wallet.selectedDevice && <LeftNavigation />}
|
||||
<MainContent>
|
||||
<Navigation>
|
||||
<Route path="/device/:device/network/:network/account/:account" component={TopNavigationAccount} />
|
||||
@ -101,7 +101,7 @@ const Wallet = (props: WalletContainerProps) => (
|
||||
</AppWrapper>
|
||||
);
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, {}, WalletContainerProps> = (state: State, own: {}): WalletContainerProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, {}, WalletContainerProps> = (state: State): WalletContainerProps => ({
|
||||
wallet: state.wallet,
|
||||
});
|
||||
|
||||
|
@ -24,7 +24,7 @@ type DispatchProps = BaseDispatchProps & {
|
||||
|
||||
export type Props = StateProps & BaseStateProps & DispatchProps & BaseDispatchProps;
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||
className: 'receive',
|
||||
selectedAccount: state.selectedAccount,
|
||||
wallet: state.wallet,
|
||||
|
@ -25,6 +25,7 @@ const AddressWrapper = styled.div`
|
||||
padding: 0px 48px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: ${props => (props.isShowingQrCode ? 'column' : 'row')};
|
||||
`;
|
||||
|
||||
const ValueWrapper = styled.div`
|
||||
@ -139,7 +140,9 @@ const AccountReceive = (props: Props) => {
|
||||
<SelectedAccount {...props}>
|
||||
<Wrapper>
|
||||
<StyledH2>Receive Ethereum or tokens</StyledH2>
|
||||
<AddressWrapper>
|
||||
<AddressWrapper
|
||||
isShowingQrCode={addressVerified || addressUnverified}
|
||||
>
|
||||
{isAddressVerifying && (
|
||||
<AddressInfoText>Confirm address on TREZOR</AddressInfoText>
|
||||
)}
|
||||
|
@ -5,7 +5,7 @@ import * as React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { default as SendFormActions } from 'actions/SendFormActions';
|
||||
import SendFormActions from 'actions/SendFormActions';
|
||||
import * as SessionStorageActions from 'actions/SessionStorageActions';
|
||||
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
import type { State, Dispatch } from 'flowtype';
|
||||
@ -29,7 +29,7 @@ export type DispatchProps = BaseDispatchProps & {
|
||||
|
||||
export type Props = StateProps & BaseStateProps & DispatchProps & BaseDispatchProps;
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||
className: 'send-from',
|
||||
selectedAccount: state.selectedAccount,
|
||||
wallet: state.wallet,
|
||||
|
@ -9,7 +9,7 @@ import ScaleText from 'react-scale-text';
|
||||
|
||||
import type { Coin } from 'reducers/LocalStorageReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
import type { Props as BaseProps } from '../Container';
|
||||
import type { Props as BaseProps } from '../../Container';
|
||||
|
||||
type Props = {
|
||||
pending: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'pending'>,
|
||||
|
@ -13,7 +13,7 @@ const constants: Object = Object.freeze({
|
||||
TREZOR_CONNECT_ROOT: path.join(ABSOLUTE_BASE, '../trezor-connect/'),
|
||||
});
|
||||
|
||||
export const TREZOR_CONNECT_ROOT: string = constants.TREZOR_CONNECT_ROOT;
|
||||
export const { TREZOR_CONNECT_ROOT }: { TREZOR_CONNECT_ROOT: string } = constants;
|
||||
export const TREZOR_CONNECT: string = path.join(constants.TREZOR_CONNECT_ROOT, 'src/js/index');
|
||||
export const TREZOR_IFRAME: string = path.join(constants.TREZOR_CONNECT_ROOT, 'src/js/iframe/iframe.js');
|
||||
export const TREZOR_POPUP: string = path.join(constants.TREZOR_CONNECT_ROOT, 'src/js/popup/popup.js');
|
||||
@ -21,10 +21,16 @@ export const TREZOR_WEBUSB: string = path.join(constants.TREZOR_CONNECT_ROOT, 's
|
||||
export const TREZOR_CONNECT_HTML: string = path.join(constants.TREZOR_CONNECT_ROOT, 'src/html/');
|
||||
export const TREZOR_CONNECT_FILES: string = path.join(constants.TREZOR_CONNECT_ROOT, 'src/data/');
|
||||
|
||||
export const BUILD: string = constants.BUILD;
|
||||
export const SRC: string = constants.SRC;
|
||||
export const PORT: string = constants.PORT;
|
||||
export const INDEX: string = constants.INDEX;
|
||||
export const PUBLIC: string = constants.PUBLIC;
|
||||
export const {
|
||||
BUILD,
|
||||
SRC,
|
||||
PORT,
|
||||
INDEX,
|
||||
PUBLIC,
|
||||
}: { BUILD: string, SRC: string, PORT: string, INDEX: string, PUBLIC: string } = constants;
|
||||
// export const SRC: string = constants.SRC;
|
||||
// export const PORT: string = constants.PORT;
|
||||
// export const INDEX: string = constants.INDEX;
|
||||
// export const PUBLIC: string = constants.PUBLIC;
|
||||
|
||||
export default constants;
|
Loading…
Reference in New Issue
Block a user