From 58823e3a81c5f036d94e7f76b54a99601c7d8d13 Mon Sep 17 00:00:00 2001 From: Vasek Mlejnsky Date: Thu, 6 Sep 2018 17:04:28 +0200 Subject: [PATCH 1/8] Fix some eslint errors --- src/actions/SendFormActions.js | 102 ++++++------- src/actions/SummaryActions.js | 10 +- src/actions/TokenActions.js | 32 ++-- src/actions/TrezorConnectActions.js | 137 +++++++++--------- src/actions/WalletActions.js | 12 +- src/actions/Web3Actions.js | 58 +++----- src/components/Button/index.js | 34 +++-- src/components/Notification/index.js | 5 +- src/components/Textarea/index.js | 5 - src/components/inputs/PinInput/index.js | 2 +- .../modals/confirm/UnverifiedAddress/index.js | 21 ++- .../modals/device/Duplicate/index.js | 20 +-- .../modals/device/Remember/index.js | 14 +- src/components/modals/index.js | 13 +- .../modals/passphrase/Passphrase/index.js | 51 +++---- src/components/modals/pin/Invalid/index.js | 2 +- src/components/modals/pin/Pin/index.js | 11 +- src/flowtype/index.js | 3 +- src/reducers/DevicesReducer.js | 2 +- src/reducers/NotificationReducer.js | 5 +- src/reducers/PendingTxReducer.js | 3 - src/reducers/SendFormReducer.js | 14 +- src/reducers/TrezorConnectReducer.js | 5 +- src/reducers/utils/index.js | 6 +- src/services/CoinmarketcapService.js | 3 +- src/services/LocalStorageService.js | 11 +- src/services/LogService.js | 24 ++- src/services/RouterService.js | 23 +-- src/services/TrezorConnectService.js | 16 +- src/store.js | 17 +-- src/support/ErrorBoundary.js | 7 +- src/utils/ethUtils.js | 12 +- src/utils/formatUtils.js | 2 +- src/views/Landing/Container.js | 5 +- .../Landing/components/ConnectDevice/index.js | 4 +- .../Landing/components/InstallBridge/index.js | 12 +- src/views/Landing/index.js | 2 +- .../components/LeftNavigation/Container.js | 2 +- .../components/AccountMenu/index.js | 1 - .../DeviceMenu/components/DeviceList/index.js | 2 +- .../components/DeviceMenu/index.js | 17 +-- .../components/Indicator/index.js | 6 +- .../components/TopNavigationAccount/index.js | 2 +- src/views/Wallet/index.js | 10 +- .../Wallet/views/AccountReceive/Container.js | 2 +- .../Wallet/views/AccountReceive/index.js | 5 +- .../Wallet/views/AccountSend/Container.js | 4 +- .../components/PendingTransactions/index.js | 2 +- webpack/constants.js | 18 ++- 49 files changed, 354 insertions(+), 422 deletions(-) diff --git a/src/actions/SendFormActions.js b/src/actions/SendFormActions.js index 8455eb38..ae2189bd 100644 --- a/src/actions/SendFormActions.js +++ b/src/actions/SendFormActions.js @@ -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 = 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 => { - 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 => { 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 => { + 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 => { 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); diff --git a/src/actions/SummaryActions.js b/src/actions/SummaryActions.js index 3378be06..dfbe7cad 100644 --- a/src/actions/SummaryActions.js +++ b/src/actions/SummaryActions.js @@ -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, }; diff --git a/src/actions/TokenActions.js b/src/actions/TokenActions.js index 46a7772f..bac9ce9d 100644 --- a/src/actions/TokenActions.js +++ b/src/actions/TokenActions.js @@ -25,10 +25,6 @@ export type TokenAction = { payload: State } -type SelectOptions = { - options?: Array -} - // action from component export const load = (input: string, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { @@ -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 => { + const newState: Array = [...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 => { 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 => { - const newState: Array = [...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, diff --git a/src/actions/TrezorConnectActions.js b/src/actions/TrezorConnectActions.js index 528041dd..f4b9925e 100644 --- a/src/actions/TrezorConnectActions.js +++ b/src/actions/TrezorConnectActions.js @@ -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): Array => 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 => { // 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 = 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): Array => 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 = 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 => { 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`)); diff --git a/src/actions/WalletActions.js b/src/actions/WalletActions.js index 8eeea9b2..a4bb0040 100644 --- a/src/actions/WalletActions.js +++ b/src/actions/WalletActions.js @@ -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 } -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 diff --git a/src/actions/Web3Actions.js b/src/actions/Web3Actions.js index 6fa64672..e1c1b73e 100644 --- a/src/actions/Web3Actions.js +++ b/src/actions/Web3Actions.js @@ -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 => { @@ -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 => { 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 => { 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 => { 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 => { 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 => n }); -export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise => new Promise((resolve, reject) => { - const contract = erc20.at(address, (error, res) => { +export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise => new Promise((resolve) => { + const contract = erc20.at(address, (error/* , res */) => { // console.warn("callback", error, res) }); diff --git a/src/components/Button/index.js b/src/components/Button/index.js index c50ae0d2..eb87e626 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -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,21 +117,24 @@ const Button = ({ isWhite = false, isWebUsb = false, isTransparent = false, -}) => ( - - {children} - -); +}) => { + const newClassName = isWebUsb ? `${className} trezor-webusb-button` : className; + return ( + + {children} + + ); +}; Button.propTypes = { children: PropTypes.node.isRequired, diff --git a/src/components/Notification/index.js b/src/components/Notification/index.js index 305beb5d..6654a152 100644 --- a/src/components/Notification/index.js +++ b/src/components/Notification/index.js @@ -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 => { export const NotificationGroup = (props) => { const { notifications, close } = props; - return notifications.map((n, i) => ( + return notifications.map(n => ( { - 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 { 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 { diff --git a/src/components/modals/device/Duplicate/index.js b/src/components/modals/device/Duplicate/index.js index a5339bf4..772867ce 100644 --- a/src/components/modals/device/Duplicate/index.js +++ b/src/components/modals/device/Duplicate/index.js @@ -63,12 +63,12 @@ const ErrorMessage = styled.div` `; export default class DuplicateDevice extends Component { - 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 { }; } - 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 { }); } + 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 { 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, diff --git a/src/components/modals/device/Remember/index.js b/src/components/modals/device/Remember/index.js index a7f698b7..e5803a38 100644 --- a/src/components/modals/device/Remember/index.js +++ b/src/components/modals/device/Remember/index.js @@ -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 { 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 { 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 ( - { comma }{ instance.instanceLabel } + { comma }{ instance.instanceLabel } ); }); } diff --git a/src/components/modals/index.js b/src/components/modals/index.js index 249daec5..cb13f290 100644 --- a/src/components/modals/index.js +++ b/src/components/modals/index.js @@ -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 }) => ( { component = (); break; - default: null; + default: + component = null; } let ch = null; @@ -145,7 +144,7 @@ class Modal extends Component { } } -const mapStateToProps: MapStateToProps = (state: State, own: OwnProps): StateProps => ({ +const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ modal: state.modal, accounts: state.accounts, devices: state.devices, diff --git a/src/components/modals/passphrase/Passphrase/index.js b/src/components/modals/passphrase/Passphrase/index.js index 39e0c119..cbfc3801 100644 --- a/src/components/modals/passphrase/Passphrase/index.js +++ b/src/components/modals/passphrase/Passphrase/index.js @@ -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 { - 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 { }; } + 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 { } } + componentDidMount(): void { // one time autofocus if (this.passphraseInput) this.passphraseInput.focus(); @@ -124,15 +125,6 @@ export default class PinModal extends Component { // }; } - 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 { } } + 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, - }); + })); } } diff --git a/src/components/modals/pin/Invalid/index.js b/src/components/modals/pin/Invalid/index.js index 281965aa..62d86706 100644 --- a/src/components/modals/pin/Invalid/index.js +++ b/src/components/modals/pin/Invalid/index.js @@ -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; diff --git a/src/components/modals/pin/Pin/index.js b/src/components/modals/pin/Pin/index.js index 62a71f99..42a62d9f 100644 --- a/src/components/modals/pin/Pin/index.js +++ b/src/components/modals/pin/Pin/index.js @@ -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 { } 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 { } 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 { diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 56e8c40e..025df015 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -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'; diff --git a/src/reducers/DevicesReducer.js b/src/reducers/DevicesReducer.js index 9c150ecd..f75d991d 100644 --- a/src/reducers/DevicesReducer.js +++ b/src/reducers/DevicesReducer.js @@ -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') { diff --git a/src/reducers/NotificationReducer.js b/src/reducers/NotificationReducer.js index 0ffec17d..0ca86f47 100644 --- a/src/reducers/NotificationReducer.js +++ b/src/reducers/NotificationReducer.js @@ -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); diff --git a/src/reducers/PendingTxReducer.js b/src/reducers/PendingTxReducer.js index 88874502..c6108d74 100644 --- a/src/reducers/PendingTxReducer.js +++ b/src/reducers/PendingTxReducer.js @@ -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'; diff --git a/src/reducers/SendFormReducer.js b/src/reducers/SendFormReducer.js index 65ce1447..df8902e3 100644 --- a/src/reducers/SendFormReducer.js +++ b/src/reducers/SendFormReducer.js @@ -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: '', diff --git a/src/reducers/TrezorConnectReducer.js b/src/reducers/TrezorConnectReducer.js index 16e24057..f6e48630 100644 --- a/src/reducers/TrezorConnectReducer.js +++ b/src/reducers/TrezorConnectReducer.js @@ -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'; diff --git a/src/reducers/utils/index.js b/src/reducers/utils/index.js index 0f83e4f6..b5c0056c 100644 --- a/src/reducers/utils/index.js +++ b/src/reducers/utils/index.js @@ -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; diff --git a/src/services/CoinmarketcapService.js b/src/services/CoinmarketcapService.js index 0b87c34e..af6e914a 100644 --- a/src/services/CoinmarketcapService.js +++ b/src/services/CoinmarketcapService.js @@ -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, diff --git a/src/services/LocalStorageService.js b/src/services/LocalStorageService.js index 2435f839..8bc66798 100644 --- a/src/services/LocalStorageService.js +++ b/src/services/LocalStorageService.js @@ -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'; diff --git a/src/services/LogService.js b/src/services/LogService.js index 492eee4f..aa7337b4 100644 --- a/src/services/LogService.js +++ b/src/services/LogService.js @@ -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 = [ - ADD, OPEN, CLOSE, - STORAGE.READY, - SEND.TX_COMPLETE, - 'web3__create', -]; +// const exclude: Array = [ +// ADD, OPEN, CLOSE, +// STORAGE.READY, +// SEND.TX_COMPLETE, +// 'web3__create', +// ]; const include: Array = [ TRANSPORT.START, diff --git a/src/services/RouterService.js b/src/services/RouterService.js index b40a60f2..db3157cd 100644 --- a/src/services/RouterService.js +++ b/src/services/RouterService.js @@ -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 = [ - '/', - '/bridge', -]; - const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => { if (action.type === WALLET.ON_BEFORE_UNLOAD) { __unloading = true; diff --git a/src/services/TrezorConnectService.js b/src/services/TrezorConnectService.js index 978ff2bd..f69f5b13 100644 --- a/src/services/TrezorConnectService.js +++ b/src/services/TrezorConnectService.js @@ -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 = api.getState().connect; + // const prevState: $ElementType = api.getState().connect; const prevModalState: $ElementType = api.getState().modal; - const prevRouterState: $ElementType = api.getState().router; + // const prevRouterState: $ElementType = api.getState().router; next(action); diff --git a/src/store.js b/src/store.js index ad9549dc..b69d1243 100644 --- a/src/store.js +++ b/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 = ['LOG_TO_EXCLUDE', 'log__add']; - const pass: Array = excluded.filter(act => action.type === act); - return pass.length === 0; - }; + // const excludeLogger = (getState: GetState, action: Action): boolean => { + // //'@@router/LOCATION_CHANGE' + // const excluded: Array = ['LOG_TO_EXCLUDE', 'log__add']; + // const pass: Array = excluded.filter(act => action.type === act); + // return pass.length === 0; + // }; composedEnhancers = compose( applyMiddleware(...middleware, ...services), diff --git a/src/support/ErrorBoundary.js b/src/support/ErrorBoundary.js index b72cf451..3ee198de 100644 --- a/src/support/ErrorBoundary.js +++ b/src/support/ErrorBoundary.js @@ -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; \ No newline at end of file diff --git a/src/utils/ethUtils.js b/src/utils/ethUtils.js index be1c889a..7b8ad313 100644 --- a/src/utils/ethUtils.js +++ b/src/utils/ethUtils.js @@ -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 => { diff --git a/src/utils/formatUtils.js b/src/utils/formatUtils.js index ef331969..982c9afb 100644 --- a/src/utils/formatUtils.js +++ b/src/utils/formatUtils.js @@ -28,7 +28,7 @@ export const formatTime = (n: number): string => { } res += ' '; } - if (minutes != 0) { + if (minutes !== 0) { res += `${minutes} minutes`; } return res; diff --git a/src/views/Landing/Container.js b/src/views/Landing/Container.js index 90b22630..da89a4b0 100644 --- a/src/views/Landing/Container.js +++ b/src/views/Landing/Container.js @@ -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: St devices: state.devices, }); -const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ +const mapDispatchToProps: MapDispatchToProps = (/* dispatch: Dispatch */): DispatchProps => ({ }); diff --git a/src/views/Landing/components/ConnectDevice/index.js b/src/views/Landing/components/ConnectDevice/index.js index f5612ffa..443b49ae 100644 --- a/src/views/Landing/components/ConnectDevice/index.js +++ b/src/views/Landing/components/ConnectDevice/index.js @@ -89,7 +89,9 @@ class ConnectDevice extends Component { {this.props.showWebUsb && (

and

- +
)} diff --git a/src/views/Landing/components/InstallBridge/index.js b/src/views/Landing/components/InstallBridge/index.js index 79f66aca..ecf72ebf 100644 --- a/src/views/Landing/components/InstallBridge/index.js +++ b/src/views/Landing/components/InstallBridge/index.js @@ -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 = { diff --git a/src/views/Landing/index.js b/src/views/Landing/index.js index 86a6a912..ed2dd87b 100644 --- a/src/views/Landing/index.js +++ b/src/views/Landing/index.js @@ -138,7 +138,7 @@ export default (props: Props) => { )}

- Don't have TREZOR? + Don&t have TREZOR? = (state: State, own: OwnProps): StateProps => ({ +const mapStateToProps: MapStateToProps = (state: State/* , own: OwnProps */): StateProps => ({ connect: state.connect, accounts: state.accounts, router: state.router, diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 93e7427e..879ea222 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -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'; diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js index 2f4f48cc..faca2a75 100644 --- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js @@ -24,7 +24,7 @@ class DeviceList extends Component { device !== selectedDevice && ( this.props.onSelectDevice(device)} + onClickWrapper={() => onSelectDevice(device)} onClickIcon={() => this.onDeviceMenuClick({ type: 'forget', label: '' }, device)} icon={( { diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js index 14a88007..4d50fba5 100644 --- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js @@ -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 { 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 { } } - 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(); diff --git a/src/views/Wallet/components/TopNavigationAccount/components/Indicator/index.js b/src/views/Wallet/components/TopNavigationAccount/components/Indicator/index.js index f73ee264..e3c40e90 100644 --- a/src/views/Wallet/components/TopNavigationAccount/components/Indicator/index.js +++ b/src/views/Wallet/components/TopNavigationAccount/components/Indicator/index.js @@ -15,8 +15,6 @@ const Wrapper = styled.div` class Indicator extends Component { reposition: () => void; - state: State; - constructor(props: Props) { super(props); @@ -30,6 +28,8 @@ class Indicator extends Component { this.reposition = this.reposition.bind(this); } + state: State; + handleResize() { this.reposition(); } @@ -43,7 +43,7 @@ class Indicator extends Component { window.removeEventListener('resize', this.reposition, false); } - componentDidUpdate(newProps: Props) { + componentDidUpdate() { this.reposition(); } diff --git a/src/views/Wallet/components/TopNavigationAccount/index.js b/src/views/Wallet/components/TopNavigationAccount/index.js index 25034591..f1299834 100644 --- a/src/views/Wallet/components/TopNavigationAccount/index.js +++ b/src/views/Wallet/components/TopNavigationAccount/index.js @@ -37,7 +37,7 @@ 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}`; diff --git a/src/views/Wallet/index.js b/src/views/Wallet/index.js index b05906cc..23674f79 100644 --- a/src/views/Wallet/index.js +++ b/src/views/Wallet/index.js @@ -20,13 +20,13 @@ import TopNavigationAccount from './components/TopNavigationAccount'; import TopNavigationDeviceSettings from './components/TopNavigationDeviceSettings'; type WalletContainerProps = { - wallet: $ElementType, + // wallet: $ElementType, children?: React.Node } -type ContentProps = { - children?: React.Node -} +// type ContentProps = { +// children?: React.Node +// } const AppWrapper = styled.div` position: relative; @@ -101,7 +101,7 @@ const Wallet = (props: WalletContainerProps) => ( ); -const mapStateToProps: MapStateToProps = (state: State, own: {}): WalletContainerProps => ({ +const mapStateToProps: MapStateToProps = (state: State): WalletContainerProps => ({ wallet: state.wallet, }); diff --git a/src/views/Wallet/views/AccountReceive/Container.js b/src/views/Wallet/views/AccountReceive/Container.js index 934deaee..5695877b 100644 --- a/src/views/Wallet/views/AccountReceive/Container.js +++ b/src/views/Wallet/views/AccountReceive/Container.js @@ -24,7 +24,7 @@ type DispatchProps = BaseDispatchProps & { export type Props = StateProps & BaseStateProps & DispatchProps & BaseDispatchProps; -const mapStateToProps: MapStateToProps = (state: State, own: OwnProps): StateProps => ({ +const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ className: 'receive', selectedAccount: state.selectedAccount, wallet: state.wallet, diff --git a/src/views/Wallet/views/AccountReceive/index.js b/src/views/Wallet/views/AccountReceive/index.js index 9b19c53c..412f9229 100644 --- a/src/views/Wallet/views/AccountReceive/index.js +++ b/src/views/Wallet/views/AccountReceive/index.js @@ -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) => { Receive Ethereum or tokens - + {isAddressVerifying && ( Confirm address on TREZOR )} diff --git a/src/views/Wallet/views/AccountSend/Container.js b/src/views/Wallet/views/AccountSend/Container.js index 8acc99a9..847bac63 100644 --- a/src/views/Wallet/views/AccountSend/Container.js +++ b/src/views/Wallet/views/AccountSend/Container.js @@ -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: State, own: OwnProps): StateProps => ({ +const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ className: 'send-from', selectedAccount: state.selectedAccount, wallet: state.wallet, diff --git a/src/views/Wallet/views/AccountSend/components/PendingTransactions/index.js b/src/views/Wallet/views/AccountSend/components/PendingTransactions/index.js index 7346824c..30b71781 100644 --- a/src/views/Wallet/views/AccountSend/components/PendingTransactions/index.js +++ b/src/views/Wallet/views/AccountSend/components/PendingTransactions/index.js @@ -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, 'pending'>, diff --git a/webpack/constants.js b/webpack/constants.js index 51e911d6..21e67444 100644 --- a/webpack/constants.js +++ b/webpack/constants.js @@ -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; \ No newline at end of file From 160210890fef5a9d21b6dc7baf179f9de2eeb01f Mon Sep 17 00:00:00 2001 From: Vladimir Volek Date: Mon, 10 Sep 2018 16:03:09 +0200 Subject: [PATCH 2/8] Better handling of menu rendering --- .../Wallet/components/LeftNavigation/index.js | 19 ++++++++----------- src/views/Wallet/index.js | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/views/Wallet/components/LeftNavigation/index.js b/src/views/Wallet/components/LeftNavigation/index.js index 07e643a8..ec78bd74 100644 --- a/src/views/Wallet/components/LeftNavigation/index.js +++ b/src/views/Wallet/components/LeftNavigation/index.js @@ -150,22 +150,19 @@ class LeftNavigation extends Component { } render() { - const { selectedDevice } = this.props.wallet; return ( - {selectedDevice && ( - this.handleOpen()} - device={this.props.wallet.selectedDevice} - transport={this.props.connect.transport} - devices={this.props.devices} - isOpen={this.props.deviceDropdownOpened} - {...this.props} - /> - ) } + this.handleOpen()} + device={this.props.wallet.selectedDevice} + transport={this.props.connect.transport} + devices={this.props.devices} + isOpen={this.props.deviceDropdownOpened} + {...this.props} + /> {this.state.shouldRenderDeviceSelection && } {this.shouldRenderAccounts() && this.getMenuTransition()} diff --git a/src/views/Wallet/index.js b/src/views/Wallet/index.js index 23674f79..e84feef3 100644 --- a/src/views/Wallet/index.js +++ b/src/views/Wallet/index.js @@ -83,7 +83,7 @@ const Wallet = (props: WalletContainerProps) => (

- + {props.wallet.selectedDevice && } From 278835581180cdbfb71c879bfd283d9c5a779e01 Mon Sep 17 00:00:00 2001 From: Vladimir Volek Date: Mon, 10 Sep 2018 16:29:30 +0200 Subject: [PATCH 3/8] Fixed header and footer using sticky --- package.json | 1 + .../components/StickyContainer/index.js | 165 ------------------ .../Wallet/components/LeftNavigation/index.js | 56 +++--- yarn.lock | 20 ++- 4 files changed, 48 insertions(+), 194 deletions(-) delete mode 100644 src/views/Wallet/components/LeftNavigation/components/StickyContainer/index.js diff --git a/package.json b/package.json index 4001c4d8..bec06b31 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "react-router-redux": "next", "react-scale-text": "^1.2.2", "react-select": "2.0.0", + "react-sticky-el": "^1.0.20", "react-transition-group": "^2.2.1", "redbox-react": "^1.6.0", "redux": "4.0.0", diff --git a/src/views/Wallet/components/LeftNavigation/components/StickyContainer/index.js b/src/views/Wallet/components/LeftNavigation/components/StickyContainer/index.js deleted file mode 100644 index 8ed8c9e1..00000000 --- a/src/views/Wallet/components/LeftNavigation/components/StickyContainer/index.js +++ /dev/null @@ -1,165 +0,0 @@ -/* @flow */ - - -// https://github.com/KyleAMathews/react-headroom/blob/master/src/shouldUpdate.js - -import * as React from 'react'; -import raf from 'raf'; -import { getViewportHeight, getScrollY } from 'utils/windowUtils'; -import styled from 'styled-components'; -import colors from 'config/colors'; - -type Props = { - location: string, - deviceSelection: boolean, - children?: React.Node, -} - -const AsideWrapper = styled.aside` - position: relative; - width: 320px; - min-width: 320px; - overflow-x: hidden; - background: ${colors.MAIN}; - border-right: 1px solid ${colors.DIVIDER}; -`; - -const StickyContainerWrapper = styled.div` - position: relative; - top: 0; - width: 320px; - overflow: hidden; -`; - -export default class StickyContainer extends React.PureComponent { - // Class variables. - currentScrollY: number = 0; - - lastKnownScrollY: number = 0; - - topOffset: number = 0; - - firstRender: boolean = false; - - framePending: boolean = false; - - stickToBottom: boolean = false; - - top: number = 0; - - aside: ?HTMLElement; - - wrapper: ?HTMLElement; - - subscribers = []; - - // handleResize = (event: Event) => { - - // } - - shouldUpdate = () => { - const { wrapper, aside }: {wrapper: ?HTMLElement, aside: ?HTMLElement} = this; - if (!wrapper || !aside) return; - const bottom: ?HTMLElement = wrapper.querySelector('.sticky-bottom'); - if (!bottom) return; - - const viewportHeight: number = getViewportHeight(); - const bottomBounds = bottom.getBoundingClientRect(); - const asideBounds = aside.getBoundingClientRect(); - const wrapperBounds = wrapper.getBoundingClientRect(); - const scrollDirection = this.currentScrollY >= this.lastKnownScrollY ? 'down' : 'up'; - const distanceScrolled = Math.abs(this.currentScrollY - this.lastKnownScrollY); - - if (asideBounds.top < 0) { - wrapper.classList.add('fixed'); - let maxTop: number = 1; - if (wrapperBounds.height > viewportHeight) { - const bottomOutOfBounds: boolean = (bottomBounds.bottom <= viewportHeight && scrollDirection === 'down'); - const topOutOfBounds: boolean = (wrapperBounds.top > 0 && scrollDirection === 'up'); - if (!bottomOutOfBounds && !topOutOfBounds) { - this.topOffset += scrollDirection === 'down' ? -distanceScrolled : distanceScrolled; - } - maxTop = viewportHeight - wrapperBounds.height; - } - - if (this.topOffset > 0) this.topOffset = 0; - if (maxTop < 0 && this.topOffset < maxTop) this.topOffset = maxTop; - wrapper.style.top = `${this.topOffset}px`; - } else { - wrapper.classList.remove('fixed'); - wrapper.style.top = '0px'; - this.topOffset = 0; - } - - if (wrapperBounds.height > viewportHeight) { - wrapper.classList.remove('fixed-bottom'); - } else if (wrapper.classList.contains('fixed-bottom')) { - if (bottomBounds.top < wrapperBounds.bottom - bottomBounds.height) { - wrapper.classList.remove('fixed-bottom'); - } - } else if (bottomBounds.bottom < viewportHeight) { - wrapper.classList.add('fixed-bottom'); - } - - aside.style.minHeight = `${wrapperBounds.height}px`; - } - - update = () => { - this.currentScrollY = getScrollY(); - this.shouldUpdate(); - this.framePending = false; - this.lastKnownScrollY = this.currentScrollY; - } - - componentDidMount() { - window.addEventListener('scroll', this.handleScroll); - window.addEventListener('resize', this.handleScroll); - raf(this.update); - } - - componentDidUpdate(prevProps: Props) { - if (this.props.location !== prevProps.location && this.aside) { - const asideBounds = this.aside.getBoundingClientRect(); - if (asideBounds.top < 0) { - window.scrollTo(0, getScrollY() + asideBounds.top); - this.topOffset = 0; - } - raf(this.update); - } else if (this.props.deviceSelection !== prevProps.deviceSelection) { - raf(this.update); - } else if (!this.firstRender) { - raf(this.update); - this.firstRender = true; - } - } - - componentWillUnmount() { - window.removeEventListener('scroll', this.handleScroll); - window.removeEventListener('resize', this.handleScroll); - } - - handleScroll = (/* event: ?Event */) => { - if (!this.framePending) { - this.framePending = true; - raf(this.update); - } - } - - render() { - return ( - { this.aside = node; }} - onScroll={this.handleScroll} - onTouchStart={this.handleScroll} - onTouchMove={this.handleScroll} - onTouchEnd={this.handleScroll} - > - { this.wrapper = node; }} - > - {this.props.children} - - - ); - } -} \ No newline at end of file diff --git a/src/views/Wallet/components/LeftNavigation/index.js b/src/views/Wallet/components/LeftNavigation/index.js index ec78bd74..cf7c38aa 100644 --- a/src/views/Wallet/components/LeftNavigation/index.js +++ b/src/views/Wallet/components/LeftNavigation/index.js @@ -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'; @@ -9,7 +10,17 @@ import DeviceHeader from 'components/DeviceHeader'; import AccountMenu from './components/AccountMenu'; import CoinMenu from './components/CoinMenu'; import DeviceMenu from './components/DeviceMenu'; -import StickyContainer from './components/StickyContainer'; + +const Wrapper = styled.div` + position: relative; + width: 320px; + min-width: 320px; + overflow-x: hidden; + background: ${colors.MAIN}; + border-right: 1px solid ${colors.DIVIDER}; +`; + +const Header = styled(DeviceHeader)``; const TransitionGroupWrapper = styled(TransitionGroup)` width: 640px; @@ -21,14 +32,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 +52,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` @@ -151,24 +158,28 @@ class LeftNavigation extends Component { render() { return ( - - this.handleOpen()} - device={this.props.wallet.selectedDevice} - transport={this.props.connect.transport} - devices={this.props.devices} - isOpen={this.props.deviceDropdownOpened} - {...this.props} - /> - + +
this.handleOpen()} + device={this.props.wallet.selectedDevice} + transport={this.props.connect.transport} + devices={this.props.devices} + isOpen={this.props.deviceDropdownOpened} + {...this.props} + /> + + {this.state.shouldRenderDeviceSelection && } {this.shouldRenderAccounts() && this.getMenuTransition()} {this.shouldRenderCoins() && this.getMenuTransition()} - - + + + + + ); } } diff --git a/yarn.lock b/yarn.lock index 6862c6ee..ef612a90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7728,18 +7728,18 @@ prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, pr loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.6.1: - version "15.6.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" +prop-types@>=15.5.10, prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: - fbjs "^0.8.16" loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.6.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" +prop-types@^15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" dependencies: + fbjs "^0.8.16" loose-envify "^1.3.1" object-assign "^4.1.1" @@ -8066,6 +8066,12 @@ react-select@2.0.0: react-input-autosize "^2.2.1" react-transition-group "^2.2.1" +react-sticky-el@^1.0.20: + version "1.0.20" + resolved "https://registry.yarnpkg.com/react-sticky-el/-/react-sticky-el-1.0.20.tgz#b3c5e7128218633f440dc67aec239d1cd078342d" + dependencies: + prop-types ">=15.5.10" + react-transition-group@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10" From cd8e1a221411d95abd5994211c56b1f770a14bdd Mon Sep 17 00:00:00 2001 From: Vladimir Volek Date: Mon, 10 Sep 2018 16:38:00 +0200 Subject: [PATCH 4/8] Fixed header and footer using sticky 2 --- src/views/Wallet/components/LeftNavigation/index.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/views/Wallet/components/LeftNavigation/index.js b/src/views/Wallet/components/LeftNavigation/index.js index cf7c38aa..47703bf4 100644 --- a/src/views/Wallet/components/LeftNavigation/index.js +++ b/src/views/Wallet/components/LeftNavigation/index.js @@ -12,10 +12,9 @@ import CoinMenu from './components/CoinMenu'; import DeviceMenu from './components/DeviceMenu'; const Wrapper = styled.div` - position: relative; width: 320px; - min-width: 320px; - overflow-x: hidden; + overflow: scroll; + border: 2px solid red; background: ${colors.MAIN}; border-right: 1px solid ${colors.DIVIDER}; `; @@ -159,11 +158,10 @@ class LeftNavigation extends Component { render() { return ( - +
this.handleOpen()} device={this.props.wallet.selectedDevice} @@ -173,12 +171,12 @@ class LeftNavigation extends Component { {...this.props} /> - + {this.state.shouldRenderDeviceSelection && } {this.shouldRenderAccounts() && this.getMenuTransition()} {this.shouldRenderCoins() && this.getMenuTransition()} - +