diff --git a/.eslintrc b/.eslintrc index 5c87b414..7c00e41a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,6 +12,7 @@ "jest": true }, "rules": { + "no-use-before-define": 0, "no-plusplus": 0, "class-methods-use-this": 0, "react/require-default-props": 0, diff --git a/src/actions/RouterActions.js b/src/actions/RouterActions.js index 71a66f5f..afa68ebe 100644 --- a/src/actions/RouterActions.js +++ b/src/actions/RouterActions.js @@ -17,7 +17,7 @@ import type { RouterAction } from 'react-router-redux'; /* * Parse url string to RouterLocationState object (key/value) */ -export const pathToParams = (path: string): PayloadAction => (dispatch: Dispatch, getState: GetState): RouterLocationState => { +export const pathToParams = (path: string): PayloadAction => (): RouterLocationState => { // split url into parts const parts: Array = path.split('/').slice(1); const params: RouterLocationState = {}; @@ -34,8 +34,9 @@ export const pathToParams = (path: string): PayloadAction = if (params.hasOwnProperty('device')) { const isClonedDevice: Array = params.device.split(':'); if (isClonedDevice.length > 1) { - params.device = isClonedDevice[0]; - params.deviceInstance = isClonedDevice[1]; + const [device, instance] = isClonedDevice; + params.device = device; + params.deviceInstance = instance; } } return params; @@ -74,22 +75,22 @@ export const paramsValidation = (params: RouterLocationState): PayloadAction => (dispatch: Dispatch, getState: GetState): ?string => { +export const paramsToPath = (params: RouterLocationState): PayloadAction => (): ?string => { // get patterns (fields) from routes and sort them by complexity - const patterns: Array> = routes.map(r => r.fields).sort((a, b) => { - return a.length > b.length ? -1 : 1; - }); + const patterns: Array> = routes.map(r => r.fields).sort((a, b) => (a.length > b.length ? -1 : 1)); // find pattern const keys: Array = Object.keys(params); let patternToUse: ?Array; - for (let pattern of patterns) { + let i: number; + for (i = 0; i < patterns.length; i++) { + const pattern = patterns[i]; const match: Array = keys.filter(key => pattern.indexOf(key) >= 0); if (match.length === pattern.length) { patternToUse = pattern; @@ -99,25 +100,24 @@ export const paramsToPath = (params: RouterLocationState): PayloadAction { + patternToUse.forEach((field) => { if (field === params[field]) { // standalone (odd) fields - url += `/${ field }`; + url += `/${field}`; } else { - url += `/${ field }/${ params[field] }`; + url += `/${field}/${params[field]}`; if (field === 'device') { if (params.hasOwnProperty('deviceInstance')) { - url += `:${ params.deviceInstance }`; + url += `:${params.deviceInstance}`; } } } - }); return url; -} +}; export const getValidUrl = (action: RouterAction): PayloadAction => (dispatch: Dispatch, getState: GetState): string => { const { location } = getState().router; @@ -129,23 +129,22 @@ export const getValidUrl = (action: RouterAction): PayloadAction => (dis const requestedUrl = action.payload.pathname; // Corner case: LOCATION_CHANGE was called but pathname didn't changed (redirect action from RouterService) if (requestedUrl === location.pathname) return requestedUrl; - + // Modal is opened // redirect to previous url if (getState().modal.opened) { // Corner case: modal is opened and currentParams are still valid // example 1 (valid blocking): url changed while passphrase modal opened but device is still connected (we want user to finish this action) // example 2 (invalid blocking): url changes while passphrase modal opened because device disconnect - const currentParams = dispatch( pathToParams(location.pathname) ); - const currentParamsAreValid = dispatch( paramsValidation(currentParams) ); - if (currentParamsAreValid) - return location.pathname; + const currentParams = dispatch(pathToParams(location.pathname)); + const currentParamsAreValid = dispatch(paramsValidation(currentParams)); + if (currentParamsAreValid) { return location.pathname; } } // there are no connected devices or application isn't ready or initialization error occurred // redirect to landing page const shouldBeLandingPage = getState().devices.length < 1 || !getState().wallet.ready || getState().connect.error !== null; - const landingPageUrl = dispatch( isLandingPageUrl(requestedUrl) ); + const landingPageUrl = dispatch(isLandingPageUrl(requestedUrl)); if (shouldBeLandingPage) { return !landingPageUrl ? '/' : requestedUrl; } @@ -157,8 +156,8 @@ export const getValidUrl = (action: RouterAction): PayloadAction => (dis } // Regular url change during application live cycle - const requestedParams = dispatch( pathToParams(requestedUrl) ); - const requestedParamsAreValid: boolean = dispatch( paramsValidation(requestedParams) ); + const requestedParams = dispatch(pathToParams(requestedUrl)); + const requestedParamsAreValid: boolean = dispatch(paramsValidation(requestedParams)); // Requested params are not valid // Neither device or network doesn't exists @@ -167,10 +166,9 @@ export const getValidUrl = (action: RouterAction): PayloadAction => (dis } // Compose valid url from requested params - const composedUrl = dispatch( paramsToPath(requestedParams) ); + const composedUrl = dispatch(paramsToPath(requestedParams)); return composedUrl || location.pathname; -} - +}; /* @@ -212,11 +210,11 @@ export const selectDevice = (device: TrezorDevice | Device): ThunkAction => (dis } const currentParams: RouterLocationState = getState().router.location.state; - const requestedParams = dispatch( pathToParams(url) ); + const requestedParams = dispatch(pathToParams(url)); if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) { - dispatch( goto(url) ); + dispatch(goto(url)); } -} +}; /* * Try to find first available device using order: @@ -230,46 +228,47 @@ export const selectFirstAvailableDevice = (): ThunkAction => (dispatch: Dispatch if (devices.length > 0) { const unacquired = devices.find(d => !d.features); if (unacquired) { - dispatch( selectDevice(unacquired) ); + dispatch(selectDevice(unacquired)); } else { const latest: Array = sortDevices(devices); const firstConnected: ?TrezorDevice = latest.find(d => d.connected); - dispatch( selectDevice(firstConnected || latest[0]) ); + dispatch(selectDevice(firstConnected || latest[0])); } } else { - dispatch( gotoLandingPage() ); + dispatch(gotoLandingPage()); } -} +}; /* * Internal method. redirect to given url */ const goto = (url: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { if (getState().router.location.pathname !== url) { - dispatch( push(url) ); + dispatch(push(url)); } -} +}; /* * Check if requested OR current url is landing page */ -export const isLandingPageUrl = (url?: string): PayloadAction => (dispatch: Dispatch, getState: GetState): boolean => { +export const isLandingPageUrl = ($url?: string): PayloadAction => (dispatch: Dispatch, getState: GetState): boolean => { + let url: ?string = $url; if (typeof url !== 'string') { url = getState().router.location.pathname; } // TODO: add more landing page cases/urls to config.json (like /tools etc) return (url === '/' || url === '/bridge'); -} +}; /* * Try to redirect to landing page */ -export const gotoLandingPage = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { - const isLandingPage = dispatch( isLandingPageUrl() ); +export const gotoLandingPage = (): ThunkAction => (dispatch: Dispatch): void => { + const isLandingPage = dispatch(isLandingPageUrl()); if (!isLandingPage) { - dispatch( goto('/') ); + dispatch(goto('/')); } -} +}; /* * Go to given device settings page @@ -277,7 +276,7 @@ export const gotoLandingPage = (): ThunkAction => (dispatch: Dispatch, getState: export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch): void => { if (device.features) { const devUrl: string = `${device.features.device_id}${device.instance ? `:${device.instance}` : ''}`; - dispatch( goto(`/device/${devUrl}/settings`) ); + dispatch(goto(`/device/${devUrl}/settings`)); } }; @@ -287,19 +286,19 @@ export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispat export const setInitialUrl = (): PayloadAction => (dispatch: Dispatch, getState: GetState): boolean => { const { initialPathname } = getState().wallet; if (typeof initialPathname === 'string' && !dispatch(isLandingPageUrl(initialPathname))) { - const valid = dispatch( getValidUrl({ + const valid = dispatch(getValidUrl({ type: LOCATION_CHANGE, payload: { pathname: initialPathname, - hash: "", - search: "", - state: {} - } - }) ); + hash: '', + search: '', + state: {}, + }, + })); if (valid === initialPathname) { - dispatch( goto(valid) ); + dispatch(goto(valid)); return true; } } return false; -} +}; diff --git a/src/actions/SelectedAccountActions.js b/src/actions/SelectedAccountActions.js index b587efc3..dd54a365 100644 --- a/src/actions/SelectedAccountActions.js +++ b/src/actions/SelectedAccountActions.js @@ -20,8 +20,6 @@ import type { State, } from 'flowtype'; - - export type SelectedAccountAction = { type: typeof ACCOUNT.DISPOSE, } | { @@ -46,7 +44,7 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct } if (prevState.sendForm !== state.sendForm) { - dispatch( SessionStorageActions.save() ); + dispatch(SessionStorageActions.save()); } // handle devices state change (from trezor-connect events or location change) @@ -55,7 +53,6 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct || prevState.discovery !== state.discovery || prevState.tokens !== state.tokens || prevState.pending !== state.pending) { - const account = stateUtils.getSelectedAccount(state); const network = stateUtils.getSelectedNetwork(state); const discovery = stateUtils.getDiscoveryProcess(state); diff --git a/src/actions/TrezorConnectActions.js b/src/actions/TrezorConnectActions.js index 5f44f9cc..7d718906 100644 --- a/src/actions/TrezorConnectActions.js +++ b/src/actions/TrezorConnectActions.js @@ -1,10 +1,9 @@ /* @flow */ import TrezorConnect, { - UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT + DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT, } from 'trezor-connect'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as NOTIFICATION from 'actions/constants/notification'; -import * as WALLET from 'actions/constants/wallet'; import { getDuplicateInstanceNumber } from 'reducers/utils'; import * as RouterActions from 'actions/RouterActions'; @@ -27,7 +26,6 @@ import type { AsyncAction, Device, TrezorDevice, - RouterLocationState, } from 'flowtype'; import * as DiscoveryActions from './DiscoveryActions'; @@ -82,7 +80,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS // set listeners TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => { // post event to reducers - const type: DeviceMessageType = event.type; // assert flow type + const type: DeviceMessageType = event.type; // eslint-disable-line prefer-destructuring dispatch({ type, device: event.payload, @@ -91,7 +89,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS TrezorConnect.on(UI_EVENT, (event: UiMessage): void => { // post event to reducers - const type: UiMessageType = event.type; // assert flow type + const type: UiMessageType = event.type; // eslint-disable-line prefer-destructuring dispatch({ type, payload: event.payload, @@ -100,7 +98,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => { // post event to reducers - const type: TransportMessageType = event.type; // assert flow type + const type: TransportMessageType = event.type; // eslint-disable-line prefer-destructuring dispatch({ type, payload: event.payload, @@ -109,16 +107,17 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS TrezorConnect.on(BLOCKCHAIN_EVENT, (event: BlockchainMessage): void => { // post event to reducers - const type: BlockchainMessageType = event.type; // assert flow type + const type: BlockchainMessageType = event.type; // eslint-disable-line prefer-destructuring dispatch({ type, payload: event.payload, }); }); + /* global LOCAL */ // $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://connect.trezor.io/5/'; + window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/'; // eslint-disable-line no-underscore-dangle + // window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/'; // eslint-disable-line no-underscore-dangle try { await TrezorConnect.init({ @@ -138,9 +137,9 @@ 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 => { +export const postInit = (): ThunkAction => (dispatch: Dispatch): void => { const handleDeviceConnect = (device: Device) => { - dispatch( RouterActions.selectDevice(device) ); + dispatch(RouterActions.selectDevice(device)); }; TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect); @@ -149,12 +148,10 @@ export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetSta TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect); TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); - const { devices } = getState(); - // try to redirect to initial url - if (!dispatch( RouterActions.setInitialUrl() )) { + if (!dispatch(RouterActions.setInitialUrl())) { // if initial redirection fails try to switch to first available device - dispatch( RouterActions.selectFirstAvailableDevice() ) + dispatch(RouterActions.selectFirstAvailableDevice()); } }; @@ -237,7 +234,7 @@ export const coinChanged = (network: ?string): ThunkAction => (dispatch: Dispatc }; export function reload(): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { + return async (): Promise => { }; } diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 6217abe3..6c138e58 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -9,7 +9,6 @@ import type { PayloadAction as ReduxPayloadAction, AsyncAction as ReduxAsyncAction, PromiseAction as ReduxPromiseAction, - ThunkDispatch as ReduxThunkDispatch, PlainDispatch as ReduxPlainDispatch, } from 'redux'; diff --git a/src/reducers/SelectedAccountReducer.js b/src/reducers/SelectedAccountReducer.js index 0500fb13..68fb56d6 100644 --- a/src/reducers/SelectedAccountReducer.js +++ b/src/reducers/SelectedAccountReducer.js @@ -1,6 +1,4 @@ /* @flow */ - - import * as ACCOUNT from 'actions/constants/account'; import type { @@ -14,7 +12,6 @@ import type { export type State = { location?: string; - account: ?Account; network: ?Coin; tokens: Array, diff --git a/src/reducers/WalletReducer.js b/src/reducers/WalletReducer.js index f6715e91..bdcd0d15 100644 --- a/src/reducers/WalletReducer.js +++ b/src/reducers/WalletReducer.js @@ -37,8 +37,8 @@ export default function wallet(state: State = initialState, action: Action): Sta case WALLET.ON_BEFORE_UNLOAD: return { ...state, - unloading: true - } + unloading: true, + }; case WALLET.SET_INITIAL_URL: return { diff --git a/src/services/RouterService.js b/src/services/RouterService.js index bc196ff3..fac7c2b8 100644 --- a/src/services/RouterService.js +++ b/src/services/RouterService.js @@ -7,9 +7,6 @@ import type { MiddlewareAPI, MiddlewareDispatch, Action, - ThunkAction, - RouterLocationState, - TrezorDevice, } from 'flowtype'; /** @@ -25,24 +22,25 @@ const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa } // compose valid url - const validUrl = api.dispatch( RouterActions.getValidUrl(action) ); + const validUrl = api.dispatch(RouterActions.getValidUrl(action)); // override action state (to be stored in RouterReducer) - action.payload.state = api.dispatch( RouterActions.pathToParams(validUrl) ); + const override = action; + override.payload.state = api.dispatch(RouterActions.pathToParams(validUrl)); const redirect = action.payload.pathname !== validUrl; if (redirect) { // override action pathname - action.payload.pathname = validUrl; + override.payload.pathname = validUrl; } // pass action - next(action); + next(override); if (redirect) { // replace invalid url - api.dispatch( replace(validUrl) ); + api.dispatch(replace(validUrl)); } - return action; + return override; }; export default RouterService; \ No newline at end of file diff --git a/src/services/TrezorConnectService.js b/src/services/TrezorConnectService.js index 7f5816e7..c14f0a24 100644 --- a/src/services/TrezorConnectService.js +++ b/src/services/TrezorConnectService.js @@ -1,7 +1,7 @@ /* @flow */ -import TrezorConnect, { - TRANSPORT, DEVICE_EVENT, UI_EVENT, UI, DEVICE, BLOCKCHAIN +import { + TRANSPORT, DEVICE, BLOCKCHAIN, } from 'trezor-connect'; import * as TrezorConnectActions from 'actions/TrezorConnectActions'; import * as DiscoveryActions from 'actions/DiscoveryActions'; @@ -42,7 +42,7 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa api.dispatch(ModalActions.onRememberRequest(prevModalState)); } else if (action.type === CONNECT.FORGET) { //api.dispatch( TrezorConnectActions.forgetDevice(action.device) ); - api.dispatch( RouterActions.selectFirstAvailableDevice() ); + api.dispatch(RouterActions.selectFirstAvailableDevice()); } else if (action.type === CONNECT.FORGET_SINGLE) { if (api.getState().devices.length < 1 && action.device.connected) { // prompt disconnect device info in LandingPage @@ -50,9 +50,9 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa type: CONNECT.DISCONNECT_REQUEST, device: action.device, }); - api.dispatch( RouterActions.gotoLandingPage() ); + api.dispatch(RouterActions.gotoLandingPage()); } else { - api.dispatch( RouterActions.selectFirstAvailableDevice() ); + api.dispatch(RouterActions.selectFirstAvailableDevice()); } } else if (action.type === DEVICE.CONNECT || action.type === DEVICE.CONNECT_UNACQUIRED) { api.dispatch(DiscoveryActions.restore()); @@ -68,7 +68,7 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa } else if (action.type === BLOCKCHAIN.NOTIFICATION) { // api.dispatch(BlockchainActions.onNotification(action.payload)); } else if (action.type === BLOCKCHAIN.ERROR) { - api.dispatch( BlockchainActions.error(action.payload) ); + api.dispatch(BlockchainActions.error(action.payload)); } return action; diff --git a/src/services/WalletService.js b/src/services/WalletService.js index 76719298..ab9f6b95 100644 --- a/src/services/WalletService.js +++ b/src/services/WalletService.js @@ -1,6 +1,4 @@ /* @flow */ - - import { DEVICE } from 'trezor-connect'; import { LOCATION_CHANGE } from 'react-router-redux'; import * as WALLET from 'actions/constants/wallet'; @@ -49,7 +47,7 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa case WALLET.SET_INITIAL_URL: api.dispatch(LocalStorageActions.loadData()); break; - case WALLET.SET_SELECTED_DEVICE: { + case WALLET.SET_SELECTED_DEVICE: if (action.device) { // try to authorize device api.dispatch(TrezorConnectActions.getSelectedDeviceState()); @@ -57,8 +55,7 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa // try select different device api.dispatch(RouterActions.selectFirstAvailableDevice()); } - } - break; + break; case DEVICE.CONNECT: api.dispatch(WalletActions.clearUnavailableDevicesData(prevState, action.device)); break; diff --git a/src/support/routes.js b/src/support/routes.js index ad9cc773..9a921f20 100644 --- a/src/support/routes.js +++ b/src/support/routes.js @@ -10,85 +10,85 @@ export const routes: Array = [ { name: 'landing-home', pattern: '/', - fields: [] + fields: [], }, { name: 'landing-bridge', pattern: '/bridge', - fields: ['bridge'] + fields: ['bridge'], }, { name: 'landing-import', pattern: '/import', - fields: ['import'] + fields: ['import'], }, { name: 'wallet-setting', pattern: '/settings', - fields: ['settings'] + fields: ['settings'], }, { name: 'wallet-acquire', pattern: '/device/:device/acquire', - fields: ['device', 'acquire'] + fields: ['device', 'acquire'], }, { name: 'wallet-unreadable', pattern: '/device/:device/unreadable', - fields: ['device', 'unreadable'] + fields: ['device', 'unreadable'], }, { name: 'wallet-bootloader', pattern: '/device/:device/bootloader', - fields: ['device', 'bootloader'] + fields: ['device', 'bootloader'], }, { name: 'wallet-initialize', pattern: '/device/:device/initialize', - fields: ['device', 'initialize'] + fields: ['device', 'initialize'], }, { name: 'wallet-device-settings', pattern: '/device/:device/settings', - fields: ['device', 'settings'] + fields: ['device', 'settings'], }, { name: 'wallet-dashboard', pattern: '/device/:device', - fields: ['device'] + fields: ['device'], }, { name: 'wallet-account-summary', pattern: '/device/:device/network/:network/account/:account', - fields: ['device', 'network', 'account'] + fields: ['device', 'network', 'account'], }, { name: 'wallet-account-send', pattern: '/device/:device/network/:network/account/:account/send', - fields: ['device', 'network', 'account', 'send'] + fields: ['device', 'network', 'account', 'send'], }, { name: 'wallet-account-send-override', pattern: '/device/:device/network/:network/account/:account/send/override', - fields: ['device', 'network', 'account', 'send'] + fields: ['device', 'network', 'account', 'send'], }, { name: 'wallet-account-receive', pattern: '/device/:device/network/:network/account/:account/receive', - fields: ['device', 'network', 'account', 'receive'] + fields: ['device', 'network', 'account', 'receive'], }, { name: 'wallet-account-signverify', pattern: '/device/:device/network/:network/account/:account/signverify', - fields: ['device', 'network', 'account', 'signverify'] - } + fields: ['device', 'network', 'account', 'signverify'], + }, ]; export const getPattern = (name: string): string => { const entry = routes.find(r => r.name === name); if (!entry) { - console.error(`Route for ${ name } not found`); + console.error(`Route for ${name} not found`); return '/'; } return entry.pattern; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/views/Wallet/components/SelectedAccount/index.js b/src/views/Wallet/components/SelectedAccount/index.js index d1727dd2..65e800f9 100644 --- a/src/views/Wallet/components/SelectedAccount/index.js +++ b/src/views/Wallet/components/SelectedAccount/index.js @@ -30,26 +30,27 @@ const SelectedAccount = (props: Props) => { const { account, discovery, - network + network, } = accountState; // corner case: accountState didn't finish loading state after LOCATION_CHANGE action - if (!network) return (); + if (!network) return (); const blockchain = props.blockchain.find(b => b.name === network.network); if (blockchain && !blockchain.connected) { return ( - { await props.blockchainReconnect(network.network); - } + }, }] - } /> + } + /> ); } diff --git a/src/views/index.js b/src/views/index.js index 7329c128..11fa8bed 100644 --- a/src/views/index.js +++ b/src/views/index.js @@ -30,24 +30,24 @@ const App = () => ( - - - + + + - - - - - - - - - - - - + + + + + + + + + + + +