diff --git a/package.json b/package.json index 2b0b41ec..eec2ed76 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@ledgerhq/hw-app-xrp": "^4.12.0", "@ledgerhq/hw-transport": "^4.12.0", "@ledgerhq/hw-transport-node-hid": "^4.12.0", - "@ledgerhq/ledger-core": "^1.3.0", + "@ledgerhq/ledger-core": "1.4.1", "@ledgerhq/live-common": "2.16.1", "axios": "^0.18.0", "babel-runtime": "^6.26.0", diff --git a/src/commands/index.js b/src/commands/index.js index 87da444c..5698f374 100644 --- a/src/commands/index.js +++ b/src/commands/index.js @@ -13,6 +13,7 @@ import installFinalFirmware from 'commands/installFinalFirmware' import installMcu from 'commands/installMcu' import installOsuFirmware from 'commands/installOsuFirmware' import isCurrencyAppOpened from 'commands/isCurrencyAppOpened' +import libcoreGetVersion from 'commands/libcoreGetVersion' import libcoreScanAccounts from 'commands/libcoreScanAccounts' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' import listApps from 'commands/listApps' @@ -35,6 +36,7 @@ const all: Array> = [ installMcu, installOsuFirmware, isCurrencyAppOpened, + libcoreGetVersion, libcoreScanAccounts, libcoreSignAndBroadcast, listApps, diff --git a/src/commands/libcoreGetVersion.js b/src/commands/libcoreGetVersion.js new file mode 100644 index 00000000..052079b3 --- /dev/null +++ b/src/commands/libcoreGetVersion.js @@ -0,0 +1,22 @@ +// @flow + +import { createCommand, Command } from 'helpers/ipc' +import { fromPromise } from 'rxjs/observable/fromPromise' + +type Input = void + +type Result = { stringVersion: string, intVersion: number } + +const cmd: Command = createCommand('libcoreGetVersion', () => + fromPromise( + Promise.resolve().then(() => { + const ledgerCore = require('init-ledger-core')() + const core = new ledgerCore.NJSLedgerCore() + const stringVersion = core.getStringVersion() + const intVersion = core.getIntVersion() + return { stringVersion, intVersion } + }), + ), +) + +export default cmd diff --git a/src/components/CurrentAddress/index.js b/src/components/CurrentAddress/index.js index da14bb32..98ac9bc8 100644 --- a/src/components/CurrentAddress/index.js +++ b/src/components/CurrentAddress/index.js @@ -14,13 +14,11 @@ import { rgba } from 'styles/helpers' import Box from 'components/base/Box' import CopyToClipboard from 'components/base/CopyToClipboard' -import Print from 'components/base/Print' import QRCode from 'components/base/QRCode' import IconCheck from 'icons/Check' import IconCopy from 'icons/Copy' import IconInfoCircle from 'icons/InfoCircle' -import IconPrint from 'icons/Print' import IconShare from 'icons/Share' import IconShield from 'icons/Shield' @@ -214,16 +212,6 @@ class CurrentAddress extends PureComponent { } label="Copy" onClick={copy} /> )} /> - ( - } - label={isLoading ? '...' : 'Print'} - onClick={print} - /> - )} - /> } label="Share" onClick={onShare} /> )} diff --git a/src/components/DashboardPage/EmptyState.js b/src/components/DashboardPage/EmptyState.js new file mode 100644 index 00000000..cb1f2562 --- /dev/null +++ b/src/components/DashboardPage/EmptyState.js @@ -0,0 +1,80 @@ +// @flow + +import React, { PureComponent } from 'react' +import { i } from 'helpers/staticPath' +import styled from 'styled-components' +import { connect } from 'react-redux' +import { compose } from 'redux' +import { translate } from 'react-i18next' +import { push } from 'react-router-redux' + +import { openModal } from 'reducers/modals' +import type { T } from 'types/common' + +import Box from 'components/base/Box' +import Button from 'components/base/Button' + +const mapDispatchToProps = { + openModal, + push, +} + +type Props = { + t: T, + push: Function, + openModal: Function, +} + +class EmptyState extends PureComponent { + handleInstallApp = () => { + const { push } = this.props + const url = '/manager' + push(url) + } + render() { + const { t, openModal } = this.props + + return ( + + emptyState Dashboard logo + + {t('emptyState:dashboard.title')} + {t('emptyState:dashboard.desc')} + + + + + + + ) + } +} + +const Title = styled(Box).attrs({ + ff: 'Museo Sans|Regular', + fontSize: 6, + color: p => p.theme.colors.dark, +})`` + +const Description = styled(Box).attrs({ + ff: 'Open Sans|Regular', + fontSize: 4, + color: p => p.theme.colors.graphite, +})` + margin: 10px auto 25px; +` +export default compose(connect(null, mapDispatchToProps), translate())(EmptyState) diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js index d2894086..34b9aef0 100644 --- a/src/components/DashboardPage/index.js +++ b/src/components/DashboardPage/index.js @@ -28,6 +28,7 @@ import OperationsList from 'components/OperationsList' import AccountCard from './AccountCard' import AccountsOrder from './AccountsOrder' +import EmptyState from './EmptyState' const mapStateToProps = state => ({ accounts: getVisibleAccounts(state), @@ -109,88 +110,93 @@ class DashboardPage extends PureComponent { return ( - - - - - {t(timeFrame)} - - - {totalAccounts > 0 - ? t('dashboard:summary', { count: totalAccounts }) - : t('dashboard:noAccounts')} - - + {totalAccounts > 0 ? ( - - - - {totalAccounts > 0 && ( - - ( - - )} - /> - - - - {t('sidebar:accounts')} + + + + + {t(timeFrame)} + + + {t('dashboard:summary', { count: totalAccounts })} - - - - - {accountsChunk.map((accountsByLine, i) => ( - - {accountsByLine.map( - (account: any, j) => - account === null ? ( - - ) : ( - push(`/account/${account.id}`)} - /> - ), - )} - - ))} + + - push(`/account/${account.id}`)} - accounts={accounts} - title={t('dashboard:recentActivity')} - withAccount - /> - + + ( + + )} + /> + + + + {t('sidebar:accounts')} + + + + + + + {accountsChunk.map((accountsByLine, i) => ( + + {accountsByLine.map( + (account: any, j) => + account === null ? ( + + ) : ( + push(`/account/${account.id}`)} + /> + ), + )} + + ))} + + + push(`/account/${account.id}`)} + accounts={accounts} + title={t('dashboard:recentActivity')} + withAccount + /> + + + ) : ( + )} ) diff --git a/src/components/SideBar/index.js b/src/components/SideBar/index.js index 53b16d26..34a6e2a3 100644 --- a/src/components/SideBar/index.js +++ b/src/components/SideBar/index.js @@ -58,6 +58,7 @@ type Props = { t: T, openModal: Function, updateStatus: UpdateStatus, + accounts: Account[], } const mapStateToProps = state => ({ @@ -71,7 +72,7 @@ const mapDispatchToProps: Object = { class SideBar extends PureComponent { render() { - const { t, openModal, updateStatus } = this.props + const { t, openModal, updateStatus, accounts } = this.props return ( @@ -110,7 +111,11 @@ class SideBar extends PureComponent { - + {accounts.length > 0 ? ( + + ) : ( + {t('emptyState:sidebar.text')} + )} @@ -153,3 +158,11 @@ export default compose( connect(mapStateToProps, mapDispatchToProps, null, { pure: false }), translate(), )(SideBar) + +export const NoAccountsText = styled(Box).attrs({ + ff: 'Open Sans|Regular', + fontSize: 3, + color: p => p.theme.colors.grey, + shrink: true, + mt: 3, +})`` diff --git a/src/renderer/init.js b/src/renderer/init.js index c510f5e9..d4a1ec5d 100644 --- a/src/renderer/init.js +++ b/src/renderer/init.js @@ -6,6 +6,7 @@ import { render } from 'react-dom' import { AppContainer } from 'react-hot-loader' import createHistory from 'history/createHashHistory' import moment from 'moment' +import { delay } from 'helpers/promise' import createStore from 'renderer/createStore' import events from 'renderer/events' @@ -14,6 +15,7 @@ import { fetchAccounts } from 'actions/accounts' import { fetchSettings } from 'actions/settings' import { isLocked } from 'reducers/application' import { getLanguage } from 'reducers/settings' +import libcoreGetVersion from 'commands/libcoreGetVersion' import db from 'helpers/db' import dbMiddleware from 'middlewares/db' @@ -57,6 +59,9 @@ function r(Comp) { } async function init() { + // FIXME IMO init() really should only be for window. any other case is a hack! + const isMainWindow = remote.getCurrentWindow().name === 'MainWindow' + if (!locked) { // Init accounts with defaults if needed db.init('accounts', []) @@ -67,9 +72,19 @@ async function init() { r() // Only init events on MainWindow - if (remote.getCurrentWindow().name === 'MainWindow') { + if (isMainWindow) { events({ store, locked }) + + const libcoreVersion = await Promise.race([ + libcoreGetVersion.send().toPromise(), + delay(10000).then(() => Promise.reject(new Error("timeout: can't load libcore"))), + ]) + console.log('libcore', libcoreVersion) } } -init() +init().catch(e => { + // for now we make the app crash instead of pending forever. later we can render the error OR try to recover, but probably this is unrecoverable cases. + console.error(e) + process.exit(1) +}) diff --git a/static/i18n/en/emptyState.yml b/static/i18n/en/emptyState.yml new file mode 100644 index 00000000..301afbd5 --- /dev/null +++ b/static/i18n/en/emptyState.yml @@ -0,0 +1,8 @@ +sidebar: + text: You don’t have any account for the moment. Press the + button to create an account +dashboard: + title: This is a title, use it with caution + desc: Please create a new account or recover an old account from your Ledger device. + buttons: + addAccount: Add Account + installApp: Install App diff --git a/static/i18n/fr/manager.yml b/static/i18n/fr/manager.yml index d5ce8e4b..b21cd652 100644 --- a/static/i18n/fr/manager.yml +++ b/static/i18n/fr/manager.yml @@ -4,7 +4,13 @@ tabs: device: Mon appareil install: Installer allApps: Toutes les applications +firmwareUpdate: Firmware update +latestFirmware: Latest firmware plugYourDevice: title: Plug your device desc: Lorem Ipsum is simply dummy text of the printing and typesetting industry’s standard dummy text cta: Plug my device +errors: + noDevice: Please make sur your device is connected + noDashboard: Please make sure your device is on the dashboard screen + noGenuine: You did not approve request on your device or your device is not genuine diff --git a/static/images/logos/emptyStateDashboard.png b/static/images/logos/emptyStateDashboard.png new file mode 100644 index 00000000..a82b2dd4 Binary files /dev/null and b/static/images/logos/emptyStateDashboard.png differ diff --git a/yarn.lock b/yarn.lock index ca0637af..ade5cd54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1451,9 +1451,9 @@ dependencies: events "^2.0.0" -"@ledgerhq/ledger-core@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-1.3.0.tgz#2b26d43c4a8973e00e0c6671a2da5183ef0ce229" +"@ledgerhq/ledger-core@1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-1.4.1.tgz#c12d4a9140765731458ff1c68112818948c7f91d" dependencies: "@ledgerhq/hw-app-btc" "^4.7.3" "@ledgerhq/hw-transport-node-hid" "^4.7.6"