From 797ceac6ba70fed0e9fb35d22e1c33e9adcd5c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=ABck=20V=C3=A9zien?= Date: Wed, 10 Jan 2018 14:55:28 +0100 Subject: [PATCH] Add currentDevice in reducer devices --- src/actions/devices.js | 65 +++++++++++++++++++++++++++++-------- src/components/Home.js | 16 +++++++-- src/components/Wrapper.js | 31 ++++++------------ src/i18n/en/translation.yml | 2 +- src/main/app.js | 2 +- src/main/ledger.js | 18 ++++++---- src/reducers/devices.js | 43 ++++++++++++++++++++---- src/renderer/i18n.js | 5 +++ src/renderer/initEvents.js | 16 +++++---- src/types/common.js | 5 +++ 10 files changed, 144 insertions(+), 59 deletions(-) diff --git a/src/actions/devices.js b/src/actions/devices.js index d11081ec..3a8f2894 100644 --- a/src/actions/devices.js +++ b/src/actions/devices.js @@ -2,22 +2,59 @@ // eslint-disable import/prefer-default-export -import type { Device } from 'types/common' +import type { Dispatch } from 'redux' -type devicesUpdateType = (Array) => { type: string, payload: Array } -export const devicesUpdate: devicesUpdateType = payload => ({ - type: 'DEVICES_UPDATE', - payload, -}) +import { getDevices } from 'reducers/devices' -type devicesAddType = Device => { type: string, payload: Device } -export const deviceAdd: devicesAddType = payload => ({ - type: 'DEVICE_ADD', - payload, -}) +import type { Device, Devices } from 'types/common' -type devicesRemoveType = Device => { type: string, payload: Device } -export const deviceRemove: devicesRemoveType = payload => ({ - type: 'DEVICE_REMOVE', +type deviceChooseType = (?Device) => { type: string, payload: ?Device } +export const deviceChoose: deviceChooseType = payload => ({ + type: 'DEVICE_CHOOSE', payload, }) + +type deviceChooseFirstType = () => (Dispatch, () => { devices: Devices }) => void +export const deviceChooseFirst: deviceChooseFirstType = () => (dispatch, getState) => { + const devices = getDevices(getState()) + + // If we detect only 1 device, we choose it + if (devices.length === 1) { + dispatch(deviceChoose(devices[0])) + } +} + +type devicesAddType = Device => (Dispatch) => void +export const deviceAdd: devicesAddType = payload => dispatch => { + dispatch({ + type: 'DEVICE_ADD', + payload, + }) + + dispatch(deviceChooseFirst()) +} + +type devicesRemoveType = Device => (Dispatch, () => { devices: Devices }) => void +export const deviceRemove: devicesRemoveType = payload => (dispatch, getState) => { + dispatch({ + type: 'DEVICE_REMOVE', + payload, + }) + + const devices = getDevices(getState()) + + // If we don't detect any device we reset currentDevice + if (devices.length === 0) { + dispatch(deviceChoose(null)) + } +} + +type devicesUpdateType = Devices => (Dispatch) => void +export const devicesUpdate: devicesUpdateType = payload => dispatch => { + dispatch({ + type: 'DEVICES_UPDATE', + payload, + }) + + dispatch(deviceChooseFirst()) +} diff --git a/src/components/Home.js b/src/components/Home.js index b408f4ae..e7494a57 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -5,16 +5,26 @@ import { compose } from 'redux' import { connect } from 'react-redux' import { translate } from 'react-i18next' +import type { MapStateToProps } from 'react-redux' +import type { Devices, T } from 'types/common' + +import { getDevices } from 'reducers/devices' + type Props = { - devices: Array, - t: (string, ?Object) => string, + devices: Devices, + t: T, } +const mapStateToProps: MapStateToProps<*, *, *> = state => ({ + devices: getDevices(state), +}) + class Home extends PureComponent { render() { const { devices, t } = this.props + return
{t('common.connectedDevices', { count: devices.length })}
} } -export default compose(connect(({ devices }: Props): Object => ({ devices })), translate())(Home) +export default compose(connect(mapStateToProps), translate())(Home) diff --git a/src/components/Wrapper.js b/src/components/Wrapper.js index 92025554..902fc036 100644 --- a/src/components/Wrapper.js +++ b/src/components/Wrapper.js @@ -1,34 +1,23 @@ // @flow -import React, { Fragment } from 'react' -import { compose } from 'redux' -import { connect } from 'react-redux' +import React from 'react' import { Route } from 'react-router' import { translate } from 'react-i18next' import Box from 'components/base/Box' -import Overlay from 'components/base/Overlay' import Home from 'components/Home' import SideBar from 'components/SideBar' import TopBar from 'components/TopBar' -const Wrapper = ({ devices, t }: { devices: Array, t: string => string }) => ( - - {devices.length === 0 ? ( - - {t('common.connectDevice')} - - ) : ( - - - - - - - - )} - +const Wrapper = () => ( + + + + + + + ) -export default compose(connect(({ devices }): Object => ({ devices })), translate())(Wrapper) +export default translate()(Wrapper) diff --git a/src/i18n/en/translation.yml b/src/i18n/en/translation.yml index 60aebb64..7c818448 100644 --- a/src/i18n/en/translation.yml +++ b/src/i18n/en/translation.yml @@ -1,6 +1,6 @@ common: ok: Okay cancel: Cancel - connectDevice: Please connect your device connectedDevices: You have {{count}} device connected + connectedDevices_0: You don't have device connected connectedDevices_plural: You have {{count}} devices connected diff --git a/src/main/app.js b/src/main/app.js index 3a8e84e8..59226b37 100644 --- a/src/main/app.js +++ b/src/main/app.js @@ -35,7 +35,7 @@ function createMainWindow() { return window } - +// dsq // Quit application when all windows are closed app.on('window-all-closed', () => { // On macOS it is common for applications to stay open diff --git a/src/main/ledger.js b/src/main/ledger.js index 7d403af1..34d764ef 100644 --- a/src/main/ledger.js +++ b/src/main/ledger.js @@ -41,13 +41,17 @@ const handlers = { }, all: send => send('devices.update', HID.devices().filter(isLedgerDevice)), }, - requestWalletInfos: async (send, { path, wallet }) => { - try { - const publicKey = await getWalletInfos(path, wallet) - send('receiveWalletInfos', { path, publicKey }) - } catch (err) { - send('failWalletInfos', { path, err: err.stack }) - } + wallet: { + infos: { + request: async (send, { path, wallet }) => { + try { + const publicKey = await getWalletInfos(path, wallet) + send('wallet.infos.success', { path, publicKey }) + } catch (err) { + send('wallet.infos.fail', { path, err: err.stack || err }) + } + }, + }, }, } diff --git a/src/reducers/devices.js b/src/reducers/devices.js index 817a21f3..bb3097be 100644 --- a/src/reducers/devices.js +++ b/src/reducers/devices.js @@ -2,13 +2,44 @@ import { handleActions } from 'redux-actions' -const state = [] +import type { Device, Devices } from 'types/common' -const handlers = { - DEVICES_UPDATE: (state, { payload: devices }) => devices, - DEVICE_ADD: (state, { payload: device }) => - [...state, device].filter((v, i, s) => s.findIndex(t => t.path === v.path) === i), - DEVICE_REMOVE: (state, { payload: device }) => state.filter(d => d.path !== device.path), +type stateType = { + currentDevice: ?Device, + devices: Devices, +} +const state = { + currentDevice: null, + devices: [], +} + +const handlers: Object = { + DEVICES_UPDATE: (state: stateType, { payload: devices }: { payload: Devices }) => ({ + ...state, + devices, + }), + DEVICE_ADD: (state: stateType, { payload: device }: { payload: Device }) => ({ + ...state, + devices: [...state.devices, device].filter( + (v, i, s) => s.findIndex(t => t.path === v.path) === i, + ), + }), + DEVICE_REMOVE: (state: stateType, { payload: device }: { payload: Device }) => ({ + ...state, + devices: state.devices.filter(d => d.path !== device.path), + }), + DEVICE_CHOOSE: (state: stateType, { payload: currentDevice }: { payload: Device }) => ({ + ...state, + currentDevice, + }), +} + +export function getCurrentDevice(state: Object) { + return state.devices.currentDevice +} + +export function getDevices(state: Object) { + return state.devices.devices } export default handleActions(handlers, state) diff --git a/src/renderer/i18n.js b/src/renderer/i18n.js index 82f635e3..39129a61 100644 --- a/src/renderer/i18n.js +++ b/src/renderer/i18n.js @@ -16,4 +16,9 @@ i18n.use(Backend).init({ }, }) +i18n.services.pluralResolver.addRule('en', { + numbers: [0, 1, 'plural'], + plurals: n => Number(n >= 2 ? 2 : n), +}) + export default i18n diff --git a/src/renderer/initEvents.js b/src/renderer/initEvents.js index ad8995ad..129388bb 100644 --- a/src/renderer/initEvents.js +++ b/src/renderer/initEvents.js @@ -23,7 +23,7 @@ export default (store: Object) => { update: devices => { store.dispatch(devicesUpdate(devices)) if (devices.length) { - send('requestWalletInfos', { + send('wallet.infos.request', { path: devices[0].path, wallet: 'btc', }) @@ -34,11 +34,15 @@ export default (store: Object) => { add: device => store.dispatch(deviceAdd(device)), remove: device => store.dispatch(deviceRemove(device)), }, - receiveWalletInfos: ({ path, publicKey }) => { - console.log({ path, publicKey }) - }, - failWalletInfos: ({ path, err }) => { - console.log({ path, err }) + wallet: { + infos: { + success: ({ path, publicKey }) => { + console.log({ path, publicKey }) + }, + fail: ({ path, err }) => { + console.log({ path, err }) + }, + }, }, } diff --git a/src/types/common.js b/src/types/common.js index 24f905de..80c1c1bb 100644 --- a/src/types/common.js +++ b/src/types/common.js @@ -3,4 +3,9 @@ export type Device = { vendorId: string, productId: string, + path: string, } + +export type Devices = Array + +export type T = (string, ?Object) => string