diff --git a/src/commands/index.js b/src/commands/index.js index 86ae1ad5..6d7cb04b 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 isDashboardOpen from 'commands/isDashboardOpen' import libcoreGetVersion from 'commands/libcoreGetVersion' import libcoreScanAccounts from 'commands/libcoreScanAccounts' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' @@ -37,6 +38,7 @@ const all: Array> = [ installMcu, installOsuFirmware, isCurrencyAppOpened, + isDashboardOpen, libcoreGetVersion, libcoreScanAccounts, libcoreSignAndBroadcast, diff --git a/src/commands/isDashboardOpen.js b/src/commands/isDashboardOpen.js new file mode 100644 index 00000000..2a33ff22 --- /dev/null +++ b/src/commands/isDashboardOpen.js @@ -0,0 +1,19 @@ +// @flow + +import { createCommand, Command } from 'helpers/ipc' +import { fromPromise } from 'rxjs/observable/fromPromise' +import { withDevice } from 'helpers/deviceAccess' + +import isDashboardOpen from '../helpers/devices/isDashboardOpen' + +type Input = { + devicePath: string, +} + +type Result = boolean + +const cmd: Command = createCommand('isDashboardOpen', ({ devicePath }) => + fromPromise(withDevice(devicePath)(transport => isDashboardOpen(transport))), +) + +export default cmd diff --git a/src/commands/listApps.js b/src/commands/listApps.js index d9b542b5..c497111c 100644 --- a/src/commands/listApps.js +++ b/src/commands/listApps.js @@ -13,7 +13,7 @@ type Input = * type Result = * const cmd: Command = createCommand('listApps', () => - /* { targetId } */ fromPromise(listApps()), + /* { targetId } */ fromPromise(listApps(/* targetId */)), ) export default cmd diff --git a/src/components/EnsureDeviceApp/index.js b/src/components/EnsureDeviceApp/index.js index 6b237512..e21fdd3e 100644 --- a/src/components/EnsureDeviceApp/index.js +++ b/src/components/EnsureDeviceApp/index.js @@ -10,6 +10,7 @@ import { getDevices } from 'reducers/devices' import type { State as StoreState } from 'reducers/index' import getAddress from 'commands/getAddress' import isCurrencyAppOpened from 'commands/isCurrencyAppOpened' +import isDashboardOpen from 'commands/isDashboardOpen' import { CHECK_APP_INTERVAL_WHEN_VALID, CHECK_APP_INTERVAL_WHEN_INVALID } from 'config/constants' @@ -139,11 +140,11 @@ class EnsureDeviceApp extends PureComponent { throw new Error(`${currency.name} app is not opened on the device`) } } else { - // TODO: real check if user is on the device dashboard - if (!deviceSelected) { - throw new Error('No device') + const isDashboard = isDashboardOpen.send({ devicePath: deviceSelected.path }).toPromise() + + if (!isDashboard) { + throw new Error(`dashboard is not opened`) } - await sleep(1) // WTF } this.handleStatusChange(this.state.deviceStatus, 'success') diff --git a/src/components/ManagerPage/AppSearchBar.js b/src/components/ManagerPage/AppSearchBar.js new file mode 100644 index 00000000..8d38b4f6 --- /dev/null +++ b/src/components/ManagerPage/AppSearchBar.js @@ -0,0 +1,106 @@ +// @flow +import React, { PureComponent } from 'react' +import styled from 'styled-components' + +import Box from 'components/base/Box' +import Search from 'components/base/Search' + +import SearchIcon from 'icons/Search' +import CrossIcon from 'icons/Cross' + +type LedgerApp = { + name: string, + version: string, + icon: string, + app: Object, + bolos_version: { + min: number, + max: number, + }, +} + +type Props = { + list: Array, + children: (list: Array) => React$Node, +} + +type State = { + query: string, + focused: boolean, +} + +const SearchBarWrapper = styled(Box).attrs({ + horizontal: true, + borderRadius: 4, +})` + height: 42px; + width: 100%; + margin: 0 0 20px 0; + background-color: white; + padding: 0 13px; +` + +const Input = styled.input` + width: 100%; + border: 0; + margin: 0 13px; + flex: 1; + outline: none; + background: transparent; + color: black; + font-family: 'Open Sans'; + font-weight: 600; +` + +class AppSearchBar extends PureComponent { + state = { + query: '', + focused: false, + } + + handleChange = (e: any) => this.setState({ query: e.target.value }) + + handleFocus = (bool: boolean) => () => this.setState({ focused: bool }) + + reset = () => { + const { input } = this + this.setState(state => ({ ...state, query: '' }), () => input && input.focus()) + } + + input = null + + render() { + const { children, list } = this.props + const { query, focused } = this.state + + const color = focused ? 'black' : 'grey' + + return ( + + + + (this.input = c)} + type="text" + value={query} + onChange={this.handleChange} + onFocus={this.handleFocus(true)} + onBlur={this.handleFocus(false)} + /> + {!!query && } + + children(items)} + /> + + ) + } +} + +export default AppSearchBar diff --git a/src/components/ManagerPage/AppsList.js b/src/components/ManagerPage/AppsList.js index 74c3f85c..5930b5e8 100644 --- a/src/components/ManagerPage/AppsList.js +++ b/src/components/ManagerPage/AppsList.js @@ -14,6 +14,7 @@ import Modal, { ModalBody } from 'components/base/Modal' import type { Device, T } from 'types/common' import ManagerApp from './ManagerApp' +import AppSearchBar from './AppSearchBar' const List = styled(Box).attrs({ horizontal: true, @@ -72,7 +73,7 @@ class AppsList extends PureComponent { async fetchAppList() { try { - // const { targetId } = this.props + // const { targetId } = this.props // TODO: REUSE THIS WHEN SERVER IS UP const appsList = CACHED_APPS || (await listApps.send().toPromise()) CACHED_APPS = appsList if (!this._unmounted) { @@ -116,19 +117,25 @@ class AppsList extends PureComponent { handleCloseModal = () => this.setState({ status: 'idle' }) renderList() { - const { status, error } = this.state + const { status, error, appsList } = this.state return ( - - {this.state.appsList.map(c => ( - - ))} + + + {items => ( + + {items.map(c => ( + + ))} + + )} + ( @@ -150,7 +157,7 @@ class AppsList extends PureComponent { )} /> - + ) } @@ -159,7 +166,7 @@ class AppsList extends PureComponent { return ( - + {t('manager:allApps')} {this.renderList()} diff --git a/src/components/ManagerPage/EnsureDashboard.js b/src/components/ManagerPage/EnsureDashboard.js index 51e6ff86..96c9e4ca 100644 --- a/src/components/ManagerPage/EnsureDashboard.js +++ b/src/components/ManagerPage/EnsureDashboard.js @@ -1,9 +1,9 @@ // @flow -import React, { PureComponent, Fragment } from 'react' -import { translate } from 'react-i18next' +import { PureComponent } from 'react' import isEqual from 'lodash/isEqual' -import type { Device, T } from 'types/common' +import type { Node } from 'react' +import type { Device } from 'types/common' import getDeviceInfo from 'commands/getDeviceInfo' @@ -14,18 +14,19 @@ type DeviceInfo = { mcu: boolean, } +type Error = { + message: string, + stack: string, +} + type Props = { - t: T, - device: Device, - children: Function, + device: ?Device, + children: (deviceInfo: ?DeviceInfo, error: ?Error) => Node, } type State = { deviceInfo: ?DeviceInfo, - error: ?{ - message: string, - stack: string, - }, + error: ?Error, } class EnsureDashboard extends PureComponent { @@ -74,19 +75,10 @@ class EnsureDashboard extends PureComponent { render() { const { deviceInfo, error } = this.state - const { children, t } = this.props - - if (deviceInfo) { - return children(deviceInfo) - } + const { children } = this.props - return error ? ( - - {error.message} - {t('manager:erros:noDashboard')} - - ) : null + return children(deviceInfo, error) } } -export default translate()(EnsureDashboard) +export default EnsureDashboard diff --git a/src/components/ManagerPage/EnsureDevice.js b/src/components/ManagerPage/EnsureDevice.js index 9dcee989..3327c781 100644 --- a/src/components/ManagerPage/EnsureDevice.js +++ b/src/components/ManagerPage/EnsureDevice.js @@ -1,39 +1,28 @@ // @flow -import React, { PureComponent } from 'react' +import { PureComponent } from 'react' import { connect } from 'react-redux' -import { translate } from 'react-i18next' -import { compose } from 'redux' -import type { Device, T } from 'types/common' +import type { Node } from 'react' +import type { Device } from 'types/common' -import { getCurrentDevice, getDevices } from 'reducers/devices' - -const mapStateToProps = state => ({ - device: getCurrentDevice(state), - nbDevices: getDevices(state).length, -}) +import { getCurrentDevice } from 'reducers/devices' type Props = { - t: T, - device: ?Device, - nbDevices: number, - children: Function, + device: Device, + children: (device: Device) => Node, } type State = {} class EnsureDevice extends PureComponent { - static defaultProps = { - device: null, - } - render() { - const { device, nbDevices, children, t } = this.props - return device ? children(device, nbDevices) : {t('manager:errors.noDevice')} + const { device, children } = this.props + return children(device) } } -export default compose( - translate(), - connect(mapStateToProps), -)(EnsureDevice) +const mapStateToProps = state => ({ + device: getCurrentDevice(state), +}) + +export default connect(mapStateToProps)(EnsureDevice) diff --git a/src/components/ManagerPage/EnsureGenuine.js b/src/components/ManagerPage/EnsureGenuine.js index a08c6876..2de56aeb 100644 --- a/src/components/ManagerPage/EnsureGenuine.js +++ b/src/components/ManagerPage/EnsureGenuine.js @@ -1,36 +1,36 @@ // @flow -import React, { PureComponent, Fragment } from 'react' -import { translate } from 'react-i18next' +import { PureComponent } from 'react' import isEqual from 'lodash/isEqual' import type { Node } from 'react' -import type { Device, T } from 'types/common' +import type { Device } from 'types/common' import getIsGenuine from 'commands/getIsGenuine' +type Error = { + message: string, + stack: string, +} + type Props = { - t: T, - device: Device, - children: Node, + device: ?Device, + children: (isGenuine: ?boolean, error: ?Error) => Node, } type State = { - genuine: boolean, - error: ?{ - message: string, - stack: string, - }, + genuine: ?boolean, + error: ?Error, } class EnsureGenuine extends PureComponent { static defaultProps = { - children: null, + children: () => null, firmwareInfo: null, } state = { error: null, - genuine: false, + genuine: null, } componentDidMount() { @@ -68,19 +68,10 @@ class EnsureGenuine extends PureComponent { render() { const { error, genuine } = this.state - const { children, t } = this.props - - if (genuine) { - return children - } + const { children } = this.props - return error ? ( - - {error.message} - {t('manager:errors.noGenuine')} - - ) : null + return children(genuine, error) } } -export default translate()(EnsureGenuine) +export default EnsureGenuine diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js index 772dfc4c..de7d4046 100644 --- a/src/components/ManagerPage/FirmwareUpdate.js +++ b/src/components/ManagerPage/FirmwareUpdate.js @@ -12,6 +12,7 @@ import installOsuFirmware from 'commands/installOsuFirmware' import Box, { Card } from 'components/base/Box' import Button from 'components/base/Button' +import Text from 'components/base/Text' let CACHED_LATEST_FIRMWARE = null @@ -97,12 +98,11 @@ class FirmwareUpdate extends PureComponent { return ( - - {t('manager:firmwareUpdate')} - - {`${t('manager:latestFirmware')}: ${latestFirmware.name}`} + {`${t('manager:latestFirmware')}: ${ + latestFirmware.name + }`} diff --git a/src/components/ManagerPage/ManagerApp.js b/src/components/ManagerPage/ManagerApp.js index d4680a5c..36988230 100644 --- a/src/components/ManagerPage/ManagerApp.js +++ b/src/components/ManagerPage/ManagerApp.js @@ -6,27 +6,29 @@ import { translate } from 'react-i18next' import type { T } from 'types/common' +import Trash from 'icons/Trash' + import Box from 'components/base/Box' import Text from 'components/base/Text' import Button from 'components/base/Button' const Container = styled(Box).attrs({ - align: 'center', + horizontal: true, m: 3, p: 4, boxShadow: 0, + borderRadius: 4, flow: 3, })` - width: 156px; - height: 186px; + width: 342px; background: white; line-height: normal; ` const AppIcon = styled.img` display: block; - width: 50px; - height: 50px; + width: 36px; + height: 36px; ` const AppName = styled(Box).attrs({ @@ -36,7 +38,6 @@ const AppName = styled(Box).attrs({ })` display: block; width: 115px; - text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -48,16 +49,16 @@ type Props = { version: string, icon: string, onInstall: Function, - // onUninstall: Function, + onUninstall: Function, } function ManagerApp(props: Props) { - const { name, version, icon, onInstall, t } = props + const { name, version, icon, onInstall, onUninstall, t } = props const iconUrl = `https://api.ledgerwallet.com/update/assets/icons/${icon}` return ( - + {name} {version} @@ -66,6 +67,9 @@ function ManagerApp(props: Props) { + ) } diff --git a/src/components/ManagerPage/Workflow.js b/src/components/ManagerPage/Workflow.js new file mode 100644 index 00000000..971970fa --- /dev/null +++ b/src/components/ManagerPage/Workflow.js @@ -0,0 +1,249 @@ +// @flow + +import React, { PureComponent } from 'react' +import styled from 'styled-components' +import { Trans, translate } from 'react-i18next' +import isNull from 'lodash/isNull' + +import type { Node } from 'react' +import type { Device, T } from 'types/common' + +import { i } from 'helpers/staticPath' +import Box from 'components/base/Box' +import Space from 'components/base/Space' +import Spinner from 'components/base/Spinner' +import Text from 'components/base/Text' + +import IconCheck from 'icons/Check' +import IconExclamationCircle from 'icons/ExclamationCircle' +import IconUsb from 'icons/Usb' +import IconHome from 'icons/Home' + +import EnsureDevice from './EnsureDevice' +import EnsureDashboard from './EnsureDashboard' +import EnsureGenuine from './EnsureGenuine' + +type DeviceInfo = { + targetId: number | string, + version: string, + final: boolean, + mcu: boolean, +} + +type Error = { + message: string, + stack: string, +} + +type Props = { + t: T, + renderMcuUpdate: (deviceInfo: DeviceInfo) => Node, + renderFinalUpdate: (deviceInfo: DeviceInfo) => Node, + renderDashboard: (device: Device, deviceInfo: DeviceInfo) => Node, + renderError: (dashboardError: ?Error, genuineError: ?Error) => Node, +} +type State = {} + +const Step = styled(Box).attrs({ + borderRadius: 1, + justifyContent: 'center', + fontSize: 4, +})` + border: 1px solid + ${p => + p.validated + ? p.theme.colors.wallet + : p.hasErrors + ? p.theme.colors.alertRed + : p.theme.colors.fog}; +` + +const StepIcon = styled(Box).attrs({ + alignItems: 'center', + justifyContent: 'center', +})` + width: 64px; +` + +const StepContent = styled(Box).attrs({ + color: 'dark', + horizontal: true, + alignItems: 'center', +})` + height: 60px; + line-height: 1.2; + + strong { + font-weight: 600; + } +` + +const StepCheck = ({ checked, hasErrors }: { checked: ?boolean, hasErrors?: boolean }) => ( + + {checked ? ( + + + + ) : hasErrors ? ( + + + + ) : ( + + )} + +) + +StepCheck.defaultProps = { + hasErrors: false, +} + +const WrapperIconCurrency = styled(Box).attrs({ + alignItems: 'center', + justifyContent: 'center', +})` + border: 1px solid ${p => p.theme.colors[p.color]}; + border-radius: 8px; + height: 24px; + width: 24px; +` + +class Workflow extends PureComponent { + render() { + const { renderDashboard, renderFinalUpdate, renderMcuUpdate, renderError, t } = this.props + return ( + + {(device: Device) => ( + + {(deviceInfo: ?DeviceInfo, dashboardError: ?Error) => ( + + {(isGenuine: ?boolean, genuineError: ?Error) => { + if (dashboardError || genuineError) { + return renderError ? ( + renderError(dashboardError, genuineError) + ) : ( +
+ {dashboardError && {dashboardError.message}} + {genuineError && {genuineError.message}} +
+ ) + } + + if (deviceInfo && deviceInfo.mcu) { + return renderMcuUpdate(deviceInfo) + } + + if (deviceInfo && deviceInfo.final) { + return renderFinalUpdate(deviceInfo) + } + + if (isGenuine && deviceInfo && device && !dashboardError && !genuineError) { + return renderDashboard(device, deviceInfo) + } + + return ( + + + + connect your device + + {t('manager:plugYourDevice:title')} + + + {t('manager:plugYourDevice:desc')} + + + + {/* DEVICE CHECK */} + + + + + + + + {'Connect your '} + Ledger device + {' to your computer and enter your '} + PIN code + {' on your device'} + + + + + + + {/* DASHBOARD CHECK */} + + + + + + + + + + {'Go to the '} + {'dashboard'} + {' on your device'} + + + + + + + {/* GENUINE CHECK */} + + + + + + + + + + {'Confirm '} + {'authentication'} + {' on your device'} + + + + + + + + ) + }} +
+ )} +
+ )} +
+ ) + } +} + +export default translate()(Workflow) diff --git a/src/components/ManagerPage/index.js b/src/components/ManagerPage/index.js index f09557d0..7c819be5 100644 --- a/src/components/ManagerPage/index.js +++ b/src/components/ManagerPage/index.js @@ -1,62 +1,82 @@ // @flow -// import React, { Fragment } from 'react' -import React from 'react' -// import { translate } from 'react-i18next' +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' import type { Node } from 'react' -// import type { T, Device } from 'types/common' -import type { Device } from 'types/common' +import type { T, Device } from 'types/common' + +import Box from 'components/base/Box' +import Text from 'components/base/Text' import AppsList from './AppsList' -// import DeviceInfos from './DeviceInfos' -// import FirmwareUpdate from './FirmwareUpdate' -import EnsureDevice from './EnsureDevice' -// import EnsureDashboard from './EnsureDashboard' -// import EnsureGenuine from './EnsureGenuine' - -// type DeviceInfo = { -// targetId: number | string, -// version: string, -// final: boolean, -// mcu: boolean, -// } - -// type Props = { -// t: T, -// } - -// const ManagerPage = ({ t }: Props): Node => ( -// -// {(device: Device) => ( -// -// {(deviceInfo: DeviceInfo) => ( -// -// {deviceInfo.mcu && bootloader mode } -// {deviceInfo.final && osu mode } -// {!deviceInfo.mcu && -// !deviceInfo.final && ( -// -// -// -// -// )} -// -// )} -// -// )} -// -// ) - -const ManagerPage = (): Node => ( - {(device: Device) => } -) - -export default ManagerPage +import FirmwareUpdate from './FirmwareUpdate' +import Workflow from './Workflow' + +type DeviceInfo = { + targetId: number | string, + version: string, + final: boolean, + mcu: boolean, +} + +type Error = { + message: string, + stack: string, +} + +type Props = { + t: T, +} + +type State = { + modalOpen: boolean, +} + +class ManagerPage extends PureComponent { + render(): Node { + const { t } = this.props + return ( + { + if (dashboardError) return Dashboard Error: {dashboardError.message} + if (genuineError) return Genuine Error: {genuineError.message} + return Error + }} + renderFinalUpdate={(deviceInfo: DeviceInfo) => ( +

UPDATE FINAL FIRMARE (TEMPLATE + ACTION WIP) {deviceInfo.final}

+ )} + renderMcuUpdate={(deviceInfo: DeviceInfo) => ( +

FLASH MCU (TEMPLATE + ACTION WIP) {deviceInfo.mcu}

+ )} + renderDashboard={(device: Device, deviceInfo: DeviceInfo) => ( + + + + {t('manager:title')} + + + {t('manager:subtitle')} + + + + + + + + + + )} + /> + ) + } +} + +export default translate()(ManagerPage) diff --git a/src/components/base/Button/index.js b/src/components/base/Button/index.js index a27c7f22..0f673f4c 100644 --- a/src/components/base/Button/index.js +++ b/src/components/base/Button/index.js @@ -37,12 +37,22 @@ const buttonStyles = { outline: { default: p => ` background: transparent; - border: 1px solid ${p.theme.colors.wallet}; - color: ${p.theme.colors.wallet}; + border: 1px solid ${ + p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet + }; + color: ${ + p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet + }; `, active: p => ` - color: ${darken(p.theme.colors.wallet, 0.1)}; - border-color: ${darken(p.theme.colors.wallet, 0.1)}; + color: ${darken( + p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet, + 0.1, + )}; + border-color: ${darken( + p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet, + 0.1, + )}; `, }, outlineGrey: { diff --git a/src/helpers/devices/getIsGenuine.js b/src/helpers/devices/getIsGenuine.js index a0a8ad3a..0c546e26 100644 --- a/src/helpers/devices/getIsGenuine.js +++ b/src/helpers/devices/getIsGenuine.js @@ -2,4 +2,5 @@ // import type Transport from '@ledgerhq/hw-transport' -export default async (/* transport: Transport<*> */) => new Promise(resolve => resolve(true)) +export default async (/* transport: Transport<*> */) => + new Promise(resolve => setTimeout(() => resolve(true), 1000)) diff --git a/src/helpers/devices/isDashboardOpen.js b/src/helpers/devices/isDashboardOpen.js new file mode 100644 index 00000000..5f5cc619 --- /dev/null +++ b/src/helpers/devices/isDashboardOpen.js @@ -0,0 +1,22 @@ +// @flow + +import type Transport from '@ledgerhq/hw-transport' + +import { getFirmwareInfo } from 'helpers/common' + +type Result = boolean + +export default async (transport: Transport<*>): Promise => { + try { + const { targetId, version } = await getFirmwareInfo(transport) + if (targetId && version) { + return true + } + + return false + } catch (err) { + const error = Error(err.message) + error.stack = err.stack + throw error + } +} diff --git a/src/helpers/firmware/installFinalFirmware.js b/src/helpers/firmware/installFinalFirmware.js index af3410ac..3c46e27d 100644 --- a/src/helpers/firmware/installFinalFirmware.js +++ b/src/helpers/firmware/installFinalFirmware.js @@ -4,17 +4,14 @@ import type Transport from '@ledgerhq/hw-transport' import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common' -type Input = { - firmware: Object, -} - +type Input = Object type Result = * const buildOsuParams = buildParamsFromFirmware('final') -export default async (transport: Transport<*>, data: Input): Result => { +export default async (transport: Transport<*>, firmware: Input): Result => { try { - const osuData = buildOsuParams(data.firmware) + const osuData = buildOsuParams(firmware) await createSocketDialog(transport, '/update/install', osuData) return { success: true } } catch (err) { diff --git a/src/helpers/firmware/installOsuFirmware.js b/src/helpers/firmware/installOsuFirmware.js index fec012c5..5a53fdc0 100644 --- a/src/helpers/firmware/installOsuFirmware.js +++ b/src/helpers/firmware/installOsuFirmware.js @@ -4,18 +4,15 @@ import type Transport from '@ledgerhq/hw-transport' import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common' -type Input = { - devicePath: string, - firmware: Object, -} +type Input = Object type Result = Promise<{ success: boolean, error?: any }> const buildOsuParams = buildParamsFromFirmware('osu') -export default async (transport: Transport<*>, data: Input): Result => { +export default async (transport: Transport<*>, firmware: Input): Result => { try { - const osuData = buildOsuParams(data.firmware) + const osuData = buildOsuParams(firmware) await createSocketDialog(transport, '/update/install', osuData) return { success: true } } catch (err) { diff --git a/src/icons/Trash.js b/src/icons/Trash.js new file mode 100644 index 00000000..a6630967 --- /dev/null +++ b/src/icons/Trash.js @@ -0,0 +1,18 @@ +// @flow + +import React from 'react' + +const path = ( + + + +) + +export default ({ size, ...p }: { size: number }) => ( + + {path} + +) diff --git a/static/i18n/en/manager.yml b/static/i18n/en/manager.yml index f882d5fb..ccbc4011 100644 --- a/static/i18n/en/manager.yml +++ b/static/i18n/en/manager.yml @@ -2,14 +2,16 @@ tabs: apps: Apps device: My device install: Install -allApps: All apps +allApps: Apps +title: Manager +subtitle: Get all your apps here firmwareUpdate: Firmware update -latestFirmware: Latest firmware +latestFirmware: Firmware plugYourDevice: title: Plug your device - desc: Lorem Ipsum is simply dummy text of the printing and typesetting industry’s standard dummy text + desc: Please connect your Ledger device and follow the steps below to access the manager 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 \ No newline at end of file + noDevice: Please make sur your device is connected (TEMPLATE NEEDED) + noDashboard: Please make sure your device is on the dashboard screen (TEMPLATED NEEDED) + noGenuine: You did not approve request on your device or your device is not genuine (TEMPLATE NEEDED) \ No newline at end of file diff --git a/static/images/logos/connectDevice.png b/static/images/logos/connectDevice.png new file mode 100755 index 00000000..ee3e4e2e Binary files /dev/null and b/static/images/logos/connectDevice.png differ