From 2bfabbc30d8b48e165ff06224a29be0fdb63b916 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Thu, 14 Jun 2018 15:16:20 +0200 Subject: [PATCH 01/20] fallback to default screen when error happens with device in manager page --- src/components/ManagerPage/Workflow.js | 26 +++++++++++-------- src/components/ManagerPage/WorkflowDefault.js | 26 ++++++++++++------- src/components/ManagerPage/index.js | 12 ++++----- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/components/ManagerPage/Workflow.js b/src/components/ManagerPage/Workflow.js index f2eea510..1b42771f 100644 --- a/src/components/ManagerPage/Workflow.js +++ b/src/components/ManagerPage/Workflow.js @@ -25,13 +25,16 @@ type Props = { renderDefault: ( device: ?Device, deviceInfo: ?DeviceInfo, - dashboardError: ?Error, isGenuine: ?boolean, + error: { + dashboardError: ?Error, + genuineError: ?Error, + }, ) => Node, renderMcuUpdate: (deviceInfo: DeviceInfo) => Node, renderFinalUpdate: (deviceInfo: DeviceInfo) => Node, renderDashboard: (device: Device, deviceInfo: DeviceInfo) => Node, - renderError: (dashboardError: ?Error, genuineError: ?Error) => Node, + renderError?: (dashboardError: ?Error, genuineError: ?Error) => Node, } type State = {} @@ -52,14 +55,12 @@ class Workflow extends PureComponent { {(isGenuine: ?boolean, genuineError: ?Error) => { if (dashboardError || genuineError) { - return renderError ? ( - renderError(dashboardError, genuineError) - ) : ( -
- {dashboardError && {dashboardError.message}} - {genuineError && {genuineError.message}} -
- ) + return renderError + ? renderError(dashboardError, genuineError) + : renderDefault(device, deviceInfo, isGenuine, { + genuineError, + dashboardError, + }) } if (deviceInfo && deviceInfo.mcu) { @@ -74,7 +75,10 @@ class Workflow extends PureComponent { return renderDashboard(device, deviceInfo) } - return renderDefault(device, deviceInfo, dashboardError, isGenuine) + return renderDefault(device, deviceInfo, isGenuine, { + genuineError, + dashboardError, + }) }}
)} diff --git a/src/components/ManagerPage/WorkflowDefault.js b/src/components/ManagerPage/WorkflowDefault.js index 3dea16b3..57be9a21 100644 --- a/src/components/ManagerPage/WorkflowDefault.js +++ b/src/components/ManagerPage/WorkflowDefault.js @@ -8,7 +8,6 @@ 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 Text from 'components/base/Text' import Spinner from 'components/base/Spinner' @@ -97,13 +96,15 @@ type Props = { t: T, device: ?Device, deviceInfo: ?DeviceInfo, - dashboardError: ?Error, + errors: { + dashboardError: ?Error, + genuineError: ?Error, + }, isGenuine: boolean, } -const WorkflowDefault = ({ device, deviceInfo, dashboardError, isGenuine, t }: Props) => ( - - +const WorkflowDefault = ({ device, deviceInfo, errors, isGenuine, t }: Props) => ( + {/* DASHBOARD CHECK */} - + @@ -152,14 +153,21 @@ const WorkflowDefault = ({ device, deviceInfo, dashboardError, isGenuine, t }: P {' on your device'} - + {/* GENUINE CHECK */} diff --git a/src/components/ManagerPage/index.js b/src/components/ManagerPage/index.js index ce8ce62e..67b400ab 100644 --- a/src/components/ManagerPage/index.js +++ b/src/components/ManagerPage/index.js @@ -24,11 +24,6 @@ type Error = { function ManagerPage(): Node { 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}

)} @@ -41,13 +36,16 @@ function ManagerPage(): Node { renderDefault={( device: ?Device, deviceInfo: ?DeviceInfo, - dashboardError: ?Error, isGenuine: ?boolean, + errors: { + dashboardError: ?Error, + genuineError: ?Error, + }, ) => ( )} From f8190addb944c1ac05d6ba54a88ec090cc56acaa Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Thu, 14 Jun 2018 15:44:04 +0200 Subject: [PATCH 02/20] some onboarding changes, minor changes for input password, breadcrumb --- src/components/AccountPage/index.js | 8 ++- src/components/Breadcrumb/Step.js | 8 ++- src/components/Onboarding/helperComponents.js | 5 ++ src/components/Onboarding/steps/Analytics.js | 25 ++----- .../Onboarding/steps/GenuineCheck.js | 68 +++++++++++-------- src/components/Onboarding/steps/Init.js | 5 +- .../Onboarding/steps/SelectDevice.js | 11 ++- .../Onboarding/steps/SelectPIN/index.js | 8 +-- .../Onboarding/steps/SetPassword.js | 10 +-- .../Onboarding/steps/WriteSeed/index.js | 8 +-- src/components/base/InputPassword/index.js | 3 +- src/icons/EyeOff.js | 16 +++++ static/i18n/en/onboarding.yml | 8 +-- 13 files changed, 104 insertions(+), 79 deletions(-) create mode 100644 src/icons/EyeOff.js diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js index 6486ffaf..312c6d35 100644 --- a/src/components/AccountPage/index.js +++ b/src/components/AccountPage/index.js @@ -130,9 +130,11 @@ class AccountPage extends PureComponent { )} t('app:account.settings.title')}> openModal(MODAL_SETTINGS_ACCOUNT, { account })}> - - - +
diff --git a/src/components/Breadcrumb/Step.js b/src/components/Breadcrumb/Step.js index 9460b122..f2a19852 100644 --- a/src/components/Breadcrumb/Step.js +++ b/src/components/Breadcrumb/Step.js @@ -35,7 +35,13 @@ const StepNumber = styled(Box).attrs({ ff: 'Rubik|Regular', })` border-radius: 50%; - border: 1px solid ${p => (['active', 'valid'].includes(p.status) ? colors.wallet : colors.fog)}; + border: 1px solid + ${p => + ['active', 'valid'].includes(p.status) + ? colors.wallet + : p.status === 'error' + ? colors.alertRed + : colors.fog}; font-size: 10px; height: ${RADIUS}px; line-height: 10px; diff --git a/src/components/Onboarding/helperComponents.js b/src/components/Onboarding/helperComponents.js index 49359da5..f2a2986f 100644 --- a/src/components/Onboarding/helperComponents.js +++ b/src/components/Onboarding/helperComponents.js @@ -32,6 +32,11 @@ export const Inner = styled(Box).attrs({ flow: 4, })`` +export const FixedTopContainer = styled(Box).attrs({ + sticky: true, + mt: 170, + backgroundColor: 'red', +})`` // FOOTER export const OnboardingFooter = styled(Box).attrs({ px: 5, diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 7a771da6..40969dc8 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -6,7 +6,7 @@ import { connect } from 'react-redux' import { saveSettings } from 'actions/settings' import Box from 'components/base/Box' import CheckBox from 'components/base/CheckBox' -import { Title, Description } from '../helperComponents' +import { Title, Description, FixedTopContainer } from '../helperComponents' import OnboardingFooter from '../OnboardingFooter' import type { StepProps } from '..' @@ -15,13 +15,11 @@ const mapDispatchToProps = { saveSettings } type State = { analyticsToggle: boolean, - termsConditionsToggle: boolean, sentryLogsToggle: boolean, } const INITIAL_STATE = { analyticsToggle: true, - termsConditionsToggle: false, sentryLogsToggle: true, } @@ -40,9 +38,6 @@ class Analytics extends PureComponent { shareAnalytics: isChecked, }) } - handleTermsToggle = () => { - this.setState({ termsConditionsToggle: !this.state.termsConditionsToggle }) - } handleNavBack = () => { const { savePassword, prevStep } = this.props @@ -52,11 +47,11 @@ class Analytics extends PureComponent { render() { const { nextStep, t } = this.props - const { analyticsToggle, termsConditionsToggle, sentryLogsToggle } = this.state + const { analyticsToggle, sentryLogsToggle } = this.state return ( - - + + {t('onboarding:analytics.title')} {t('onboarding:analytics.desc')} @@ -78,15 +73,6 @@ class Analytics extends PureComponent { - - - {t('onboarding:analytics.termsConditions.title')} - {t('onboarding:analytics.termsConditions.desc')} - - - - - { t={t} nextStep={nextStep} prevStep={this.handleNavBack} - isContinueDisabled={!termsConditionsToggle} /> - + ) } } diff --git a/src/components/Onboarding/steps/GenuineCheck.js b/src/components/Onboarding/steps/GenuineCheck.js index f4452c20..d7fcc5e9 100644 --- a/src/components/Onboarding/steps/GenuineCheck.js +++ b/src/components/Onboarding/steps/GenuineCheck.js @@ -19,7 +19,7 @@ import IconLedgerNanoError from 'icons/illustrations/LedgerNanoError' import IconLedgerBlueError from 'icons/illustrations/LedgerBlueError' import IconCheck from 'icons/Check' -import { Title, Description, IconOptionRow } from '../helperComponents' +import { Title, Description, IconOptionRow, FixedTopContainer } from '../helperComponents' import type { StepProps } from '..' import OnboardingFooter from '../OnboardingFooter' @@ -120,8 +120,8 @@ class GenuineCheck extends PureComponent { } return ( - - + + {t('onboarding:genuineCheck.title')} {t('onboarding:genuineCheck.desc')} @@ -150,11 +150,13 @@ class GenuineCheck extends PureComponent { - this.handleButtonPass(item, 'recoveryStepPass')} - /> + {genuine.pinStepPass && ( + this.handleButtonPass(item, 'recoveryStepPass')} + /> + )} @@ -166,24 +168,26 @@ class GenuineCheck extends PureComponent { {t('onboarding:genuineCheck.steps.step3.title')}
- - {genuine.isDeviceGenuine ? ( - - - - {t('onboarding:genuineCheck.isGenuinePassed')} - - - ) : ( - - )} - + {genuine.recoveryStepPass && ( + + {genuine.isDeviceGenuine ? ( + + + + {t('onboarding:genuineCheck.isGenuinePassed')} + + + ) : ( + + )} + + )} @@ -201,7 +205,7 @@ class GenuineCheck extends PureComponent { onClose={this.handleCloseGenuineCheckModal} onGenuineCheck={this.handleGenuineCheck} /> - + ) } } @@ -249,7 +253,7 @@ export function GenuineCheckFail({ - + ) } } diff --git a/src/components/Onboarding/steps/WriteSeed/index.js b/src/components/Onboarding/steps/WriteSeed/index.js index e0306307..0933233e 100644 --- a/src/components/Onboarding/steps/WriteSeed/index.js +++ b/src/components/Onboarding/steps/WriteSeed/index.js @@ -9,15 +9,15 @@ import OnboardingFooter from '../../OnboardingFooter' import WriteSeedNano from './WriteSeedNano' import WriteSeedBlue from './WriteSeedBlue' import WriteSeedRestore from './WriteSeedRestore' - +import { FixedTopContainer } from '../../helperComponents' import type { StepProps } from '../..' export default (props: StepProps) => { const { nextStep, prevStep, t, onboarding } = props return ( - - + + {onboarding.flowType === 'restoreDevice' ? ( ) : onboarding.isLedgerNano ? ( @@ -34,6 +34,6 @@ export default (props: StepProps) => { nextStep={nextStep} prevStep={prevStep} /> - + ) } diff --git a/src/components/base/InputPassword/index.js b/src/components/base/InputPassword/index.js index 5046821c..b6784878 100644 --- a/src/components/base/InputPassword/index.js +++ b/src/components/base/InputPassword/index.js @@ -14,6 +14,7 @@ import Box from 'components/base/Box' import Input from 'components/base/Input' import IconEye from 'icons/Eye' +import IconEyeOff from 'icons/EyeOff' const InputRight = styled(Box).attrs({ color: 'grey', @@ -99,7 +100,7 @@ class InputPassword extends PureComponent { onChange={this.handleChange} renderRight={ - + {inputType === 'password' ? : } } /> diff --git a/src/icons/EyeOff.js b/src/icons/EyeOff.js new file mode 100644 index 00000000..32ce5294 --- /dev/null +++ b/src/icons/EyeOff.js @@ -0,0 +1,16 @@ +// @flow + +import React from 'react' + +const path = ( + +) + +export default ({ size, ...p }: { size: number }) => ( + + {path} + +) diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index c7705492..7139a669 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -44,14 +44,14 @@ writeSeed: title: Save your recovery phrase desc: Your recovery phrase is formed by 24 words. They will be displayed only once. step1: Press the right button to select the length of your recovery phrase. Press both buttons to confirm. - step2: Select the first letters of Word \#1 by pressing the right or left button. Press both buttons to confirm each letter. - step3: Select Word \#1 from the suggested words. Press both buttons to continue. + step2: 'Select the first letters of Word #1 by pressing the right or left button. Press both buttons to confirm each letter.' + step3: 'Select Word #1 from the suggested words. Press both buttons to continue.' step4: Repeat the process until the last word. nano: title: Save your recovery phrase desc: Your recovery phrase is formed by 24 words. They will be displayed only once. - step1: Copy the first word (Word \#1) in position 1 on the blank Recovery sheet. - step2: Press the right button to display Word \#2 and repeat the process until all 24 words are copied on the Recovery sheet. + step1: 'Copy the first word (Word #1) in position 1 on the blank Recovery sheet.' + step2: 'Press the right button to display Word #2 and repeat the process until all 24 words are copied on the Recovery sheet.' step3: Confirm your recovery phrase press both buttons to validate each word displayed on the screen. blue: title: Save your recovery phrase From f5ca91855044b44d43b07902e9b265ed3cdacd28 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Thu, 14 Jun 2018 15:46:27 +0200 Subject: [PATCH 03/20] remove unused elements --- src/components/Onboarding/steps/GenuineCheck.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Onboarding/steps/GenuineCheck.js b/src/components/Onboarding/steps/GenuineCheck.js index d7fcc5e9..7ab525ba 100644 --- a/src/components/Onboarding/steps/GenuineCheck.js +++ b/src/components/Onboarding/steps/GenuineCheck.js @@ -10,7 +10,7 @@ import type { T } from 'types/common' import { updateGenuineCheck } from 'reducers/onboarding' -import Box, { Card } from 'components/base/Box' +import Box from 'components/base/Box' import Button from 'components/base/Button' import RadioGroup from 'components/base/RadioGroup' import GenuineCheckModal from 'components/GenuineCheckModal' From 2378cd8f195bd9395cdb50c871616a2ec12d753a Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Thu, 14 Jun 2018 15:25:39 +0200 Subject: [PATCH 04/20] add loader in app screen --- src/components/ManagerPage/AppsList.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/ManagerPage/AppsList.js b/src/components/ManagerPage/AppsList.js index 244adb41..fa6d26cb 100644 --- a/src/components/ManagerPage/AppsList.js +++ b/src/components/ManagerPage/AppsList.js @@ -15,6 +15,7 @@ import Modal, { ModalBody } from 'components/base/Modal' import Tooltip from 'components/base/Tooltip' import Text from 'components/base/Text' import Progress from 'components/base/Progress' +import Spinner from 'components/base/Spinner' import ExclamationCircle from 'icons/ExclamationCircle' import Update from 'icons/Update' @@ -178,7 +179,7 @@ class AppsList extends PureComponent { renderList() { const { appsList } = this.state - return ( + return appsList.length > 0 ? ( {items => ( @@ -198,6 +199,10 @@ class AppsList extends PureComponent { {this.renderModal()} + ) : ( + + + ) } From e806d65274d9933d328a3d1addd617434e535326 Mon Sep 17 00:00:00 2001 From: Thibaut Boustany Date: Thu, 14 Jun 2018 14:57:15 +0200 Subject: [PATCH 05/20] `react/jsx-no-literals` eslint rule added --- .eslintrc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.eslintrc b/.eslintrc index d30945b6..b3fcd35b 100644 --- a/.eslintrc +++ b/.eslintrc @@ -54,6 +54,7 @@ "react/jsx-curly-brace-presence": 0, "react/jsx-filename-extension": 0, "react/jsx-no-target-blank": 0, + "react/jsx-no-literals": [1, {"noStrings": true}], "react/prefer-stateless-function": 0, "react/require-default-props": 0, "react/sort-comp": [1, { @@ -73,4 +74,10 @@ "onlyFilesWithFlowAnnotation": true, } }, + "overrides": [{ + "files": [ "*stories.js" ], + "rules": { + "react/jsx-no-literals": 0 + } + }] } From 957420ec427a8e3690de983d1f11d80be649bf2d Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Thu, 14 Jun 2018 16:48:09 +0200 Subject: [PATCH 06/20] pixel push on manager page --- src/components/ManagerPage/AppSearchBar.js | 9 ++++++++- src/components/ManagerPage/AppsList.js | 19 ++++++++++++------- src/components/ManagerPage/Dashboard.js | 4 ++-- src/components/ManagerPage/FirmwareUpdate.js | 2 +- src/components/ManagerPage/ManagerApp.js | 12 ++++++------ src/components/ManagerPage/WorkflowDefault.js | 2 +- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/components/ManagerPage/AppSearchBar.js b/src/components/ManagerPage/AppSearchBar.js index aac4aa75..4dcdd81b 100644 --- a/src/components/ManagerPage/AppSearchBar.js +++ b/src/components/ManagerPage/AppSearchBar.js @@ -42,6 +42,13 @@ const SearchBarWrapper = styled(Box).attrs({ margin: 0 0 20px 0; background-color: white; padding: 0 13px; + + ${p => + p.focused + ? ` + border: 1px solid #6490f1; + ` + : 'border: 1px solid white;'}; ` const Input = styled.input.attrs({ @@ -91,7 +98,7 @@ class AppSearchBar extends PureComponent { return ( - + (this.input = c)} diff --git a/src/components/ManagerPage/AppsList.js b/src/components/ManagerPage/AppsList.js index fa6d26cb..164edaf6 100644 --- a/src/components/ManagerPage/AppsList.js +++ b/src/components/ManagerPage/AppsList.js @@ -16,6 +16,7 @@ import Tooltip from 'components/base/Tooltip' import Text from 'components/base/Text' import Progress from 'components/base/Progress' import Spinner from 'components/base/Spinner' +import Button from 'components/base/Button' import ExclamationCircle from 'icons/ExclamationCircle' import Update from 'icons/Update' @@ -39,7 +40,7 @@ const ICONS_FALLBACK = { } type Status = 'loading' | 'idle' | 'busy' | 'success' | 'error' -type Mode = '' | 'installing' | 'uninstalling' +type Mode = 'home' | 'installing' | 'uninstalling' type LedgerApp = { name: string, @@ -72,7 +73,7 @@ class AppsList extends PureComponent { error: null, appsList: [], app: '', - mode: '', + mode: 'home', } componentDidMount() { @@ -109,7 +110,7 @@ class AppsList extends PureComponent { await installApp.send(data).toPromise() this.setState({ status: 'success', app: '' }) } catch (err) { - this.setState({ status: 'error', error: err.message, app: '', mode: '' }) + this.setState({ status: 'error', error: err.message, app: '', mode: 'home' }) } } @@ -124,11 +125,11 @@ class AppsList extends PureComponent { await uninstallApp.send(data).toPromise() this.setState({ status: 'success', app: '' }) } catch (err) { - this.setState({ status: 'error', error: err.message, app: '', mode: '' }) + this.setState({ status: 'error', error: err.message, app: '', mode: 'home' }) } } - handleCloseModal = () => this.setState({ status: 'idle', mode: '' }) + handleCloseModal = () => this.setState({ status: 'idle', mode: 'home' }) renderModal = () => { const { t } = this.props @@ -153,7 +154,9 @@ class AppsList extends PureComponent {
{'error happened'}
{error} - +
) : status === 'success' ? ( @@ -168,7 +171,9 @@ class AppsList extends PureComponent { { app }, )} - + ) : null} diff --git a/src/components/ManagerPage/Dashboard.js b/src/components/ManagerPage/Dashboard.js index 238a063e..980c97ed 100644 --- a/src/components/ManagerPage/Dashboard.js +++ b/src/components/ManagerPage/Dashboard.js @@ -33,7 +33,7 @@ const Dashboard = ({ device, deviceInfo, t }: Props) => ( {t('app:manager.subtitle')}
- + ( device={device} /> - + diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js index 37ce7967..ef7546bc 100644 --- a/src/components/ManagerPage/FirmwareUpdate.js +++ b/src/components/ManagerPage/FirmwareUpdate.js @@ -102,7 +102,7 @@ class FirmwareUpdate extends PureComponent { const { latestFirmware } = this.state return ( - + diff --git a/src/components/ManagerPage/ManagerApp.js b/src/components/ManagerPage/ManagerApp.js index 475b50d3..410c4044 100644 --- a/src/components/ManagerPage/ManagerApp.js +++ b/src/components/ManagerPage/ManagerApp.js @@ -14,13 +14,14 @@ import Button from 'components/base/Button' const Container = styled(Box).attrs({ horizontal: true, - m: 3, + my: 2, + mx: 3, p: 4, boxShadow: 0, borderRadius: 4, - flow: 3, + flow: 2, })` - width: 342px; + width: calc(50% - 30px); background: white; line-height: normal; ` @@ -37,7 +38,6 @@ const AppName = styled(Box).attrs({ color: 'dark', })` display: block; - width: 115px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -57,8 +57,8 @@ function ManagerApp({ name, version, icon, onInstall, onUninstall, t }: Props) { return ( - - {name} + + {name} {version} diff --git a/src/components/ManagerPage/WorkflowDefault.js b/src/components/ManagerPage/WorkflowDefault.js index 57be9a21..e9af34c6 100644 --- a/src/components/ManagerPage/WorkflowDefault.js +++ b/src/components/ManagerPage/WorkflowDefault.js @@ -118,7 +118,7 @@ const WorkflowDefault = ({ device, deviceInfo, errors, isGenuine, t }: Props) => {t('app:manager.device.desc')} - + {/* DEVICE CHECK */} From a79b900f1f415bc8f794a7959e7e570c436dbdf0 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Thu, 14 Jun 2018 17:16:27 +0200 Subject: [PATCH 07/20] no device screen added to onboarding, minor polishes --- src/components/Onboarding/OnboardingFooter.js | 17 +---- src/components/Onboarding/helperComponents.js | 6 +- src/components/Onboarding/index.js | 2 + src/components/Onboarding/steps/Finish.js | 4 +- .../Onboarding/steps/GenuineCheck.js | 46 +++++------- src/components/Onboarding/steps/Init.js | 19 +++-- src/components/Onboarding/steps/NoDevice.js | 71 +++++++++++++++++++ .../Onboarding/steps/SelectDevice.js | 4 +- .../Onboarding/steps/SetPassword.js | 26 +++---- src/icons/Cart.js | 16 +++++ src/icons/Truck.js | 16 +++++ src/reducers/onboarding.js | 9 +++ static/i18n/en/onboarding.yml | 8 +++ 13 files changed, 169 insertions(+), 75 deletions(-) create mode 100644 src/components/Onboarding/steps/NoDevice.js create mode 100644 src/icons/Cart.js create mode 100644 src/icons/Truck.js diff --git a/src/components/Onboarding/OnboardingFooter.js b/src/components/Onboarding/OnboardingFooter.js index c04eb55f..0bb1bded 100644 --- a/src/components/Onboarding/OnboardingFooter.js +++ b/src/components/Onboarding/OnboardingFooter.js @@ -1,22 +1,11 @@ // @flow import React from 'react' -import styled from 'styled-components' -import { radii } from 'styles/theme' import type { T } from 'types/common' import Button from 'components/base/Button' -import Box from 'components/base/Box' - -const Wrapper = styled(Box).attrs({ - px: 5, - py: 3, -})` - border-top: 1px solid ${p => p.theme.colors.lightFog}; - border-bottom-left-radius: ${radii[1]}px; - border-bottom-right-radius: ${radii[1]}px; -` +import { OnboardingFooterWrapper } from './helperComponents' type Props = { t: T, @@ -33,13 +22,13 @@ const OnboardingFooter = ({ ...props }: Props) => ( - + - + ) export default OnboardingFooter diff --git a/src/components/Onboarding/helperComponents.js b/src/components/Onboarding/helperComponents.js index f2a2986f..a7e93de9 100644 --- a/src/components/Onboarding/helperComponents.js +++ b/src/components/Onboarding/helperComponents.js @@ -38,11 +38,13 @@ export const FixedTopContainer = styled(Box).attrs({ backgroundColor: 'red', })`` // FOOTER -export const OnboardingFooter = styled(Box).attrs({ + +export const OnboardingFooterWrapper = styled(Box).attrs({ px: 5, py: 3, + horizontal: true, })` - border-top: 2px solid ${p => p.theme.colors.lightGrey}; + border-top: 2px solid ${p => p.theme.colors.lightFog}; border-bottom-left-radius: ${radii[1]}px; border-bottom-right-radius: ${radii[1]}px; ` diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js index 70e55334..58ace8cc 100644 --- a/src/components/Onboarding/index.js +++ b/src/components/Onboarding/index.js @@ -27,6 +27,7 @@ import Box from 'components/base/Box' import Start from './steps/Start' import InitStep from './steps/Init' +import NoDeviceStep from './steps/NoDevice' import OnboardingBreadcrumb from './OnboardingBreadcrumb' import SelectDevice from './steps/SelectDevice' import SelectPIN from './steps/SelectPIN/index' @@ -46,6 +47,7 @@ const STEPS = { analytics: Analytics, finish: Finish, start: Start, + noDevice: NoDeviceStep, } const mapStateToProps = state => ({ diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index 21c0423c..c5cbd04c 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -39,8 +39,8 @@ const socialMedia = [ export default (props: StepProps) => { const { finish, t } = props return ( - - + + diff --git a/src/components/Onboarding/steps/GenuineCheck.js b/src/components/Onboarding/steps/GenuineCheck.js index 7ab525ba..5de74d47 100644 --- a/src/components/Onboarding/steps/GenuineCheck.js +++ b/src/components/Onboarding/steps/GenuineCheck.js @@ -4,7 +4,7 @@ import React, { PureComponent, Fragment } from 'react' import { shell } from 'electron' import { connect } from 'react-redux' import styled from 'styled-components' -import { radii, colors } from 'styles/theme' +import { colors } from 'styles/theme' import type { T } from 'types/common' @@ -19,7 +19,13 @@ import IconLedgerNanoError from 'icons/illustrations/LedgerNanoError' import IconLedgerBlueError from 'icons/illustrations/LedgerBlueError' import IconCheck from 'icons/Check' -import { Title, Description, IconOptionRow, FixedTopContainer } from '../helperComponents' +import { + Title, + Description, + IconOptionRow, + FixedTopContainer, + OnboardingFooterWrapper, +} from '../helperComponents' import type { StepProps } from '..' import OnboardingFooter from '../OnboardingFooter' @@ -145,7 +151,7 @@ class GenuineCheck extends PureComponent { - 2. + 2. {t('onboarding:genuineCheck.steps.step2.title')} @@ -164,7 +170,9 @@ class GenuineCheck extends PureComponent { - 3. + + 3. + {t('onboarding:genuineCheck.steps.step3.title')} @@ -250,27 +258,14 @@ export function GenuineCheckFail({ )} - - - - + ) } @@ -285,14 +280,6 @@ export const CardTitle = styled(Box).attrs({ pl: 2, })`` -const Wrapper = styled(Box).attrs({ - px: 5, - py: 3, -})` - border-top: 2px solid ${p => p.theme.colors.lightGrey}; - border-bottom-left-radius: ${radii[1]}px; - border-bottom-right-radius: ${radii[1]}px; -` const CardWrapper = styled(Box).attrs({ horizontal: true, p: 5, @@ -302,6 +289,7 @@ const CardWrapper = styled(Box).attrs({ width: 580px; height: 74px; transition: all ease-in-out 0.2s; + color: ${p => (p.isDisabled ? p.theme.colors.grey : p.theme.colors.black)}; border: ${p => `1px ${p.isDisabled ? 'dashed' : 'solid'} ${p.theme.colors.fog}`}; pointer-events: ${p => (p.isDisabled ? 'none' : 'auto')}; background-color: ${p => (p.isDisabled ? p.theme.colors.lightGrey : p.theme.colors.white)}; diff --git a/src/components/Onboarding/steps/Init.js b/src/components/Onboarding/steps/Init.js index fb3ad7c2..506a0362 100644 --- a/src/components/Onboarding/steps/Init.js +++ b/src/components/Onboarding/steps/Init.js @@ -1,7 +1,6 @@ // @flow import React, { PureComponent } from 'react' -import { shell } from 'electron' import { connect } from 'react-redux' import { colors } from 'styles/theme' @@ -22,7 +21,7 @@ const mapDispatchToProps = { flowType } class Init extends PureComponent { render() { - const { nextStep, t } = this.props + const { t, flowType, jumpStep } = this.props const optionCards = [ { @@ -30,8 +29,8 @@ class Init extends PureComponent { icon: , title: t('onboarding:init.newDevice.title'), onClick: () => { - nextStep() - this.props.flowType('newDevice') + jumpStep('selectDevice') + flowType('newDevice') }, }, { @@ -39,8 +38,8 @@ class Init extends PureComponent { icon: , title: t('onboarding:init.restoreDevice.title'), onClick: () => { - nextStep() - this.props.flowType('restoreDevice') + jumpStep('selectDevice') + flowType('restoreDevice') }, }, { @@ -48,8 +47,8 @@ class Init extends PureComponent { icon: , title: t('onboarding:init.initializedDevice.title'), onClick: () => { - nextStep() - this.props.flowType('initializedDevice') + jumpStep('selectDevice') + flowType('initializedDevice') }, }, { @@ -57,8 +56,8 @@ class Init extends PureComponent { icon: , title: t('onboarding:init.noDevice.title'), onClick: () => { - shell.openExternal('https://www.ledger.fr/') - this.props.flowType('noDevice') + jumpStep('noDevice') + flowType('noDevice') }, }, ] diff --git a/src/components/Onboarding/steps/NoDevice.js b/src/components/Onboarding/steps/NoDevice.js new file mode 100644 index 00000000..f63ad96f --- /dev/null +++ b/src/components/Onboarding/steps/NoDevice.js @@ -0,0 +1,71 @@ +// @flow + +import React, { PureComponent } from 'react' +import { shell } from 'electron' + +import Box from 'components/base/Box' +import IconUser from 'icons/User' +import IconCart from 'icons/Cart' +import IconTruck from 'icons/Truck' +import IconInfoCircle from 'icons/InfoCircle' +import Button from '../../base/Button/index' +import { Title, OnboardingFooterWrapper } from '../helperComponents' +import { OptionFlowCard } from './Init' + +import type { StepProps } from '..' + +class NoDevice extends PureComponent { + render() { + const { t, prevStep } = this.props + + const optionCards = [ + { + key: 'buyNew', + icon: , + title: t('onboarding:noDevice.buyNew.title'), + onClick: () => { + shell.openExternal('https://www.ledgerwallet.com/') + }, + }, + { + key: 'trackOrder', + icon: , + title: t('onboarding:noDevice.trackOrder.title'), + onClick: () => { + shell.openExternal('http://order.ledgerwallet.com/') + }, + }, + { + key: 'learnMore', + icon: , + title: t('onboarding:noDevice.learnMore.title'), + onClick: () => { + shell.openExternal('https://www.ledgerwallet.com/') + }, + }, + ] + + return ( + + + + + + + {t('onboarding:noDevice.title')} + + + {optionCards.map(card => )} + + + + + + + ) + } +} + +export default NoDevice diff --git a/src/components/Onboarding/steps/SelectDevice.js b/src/components/Onboarding/steps/SelectDevice.js index b52d6039..eca85f3e 100644 --- a/src/components/Onboarding/steps/SelectDevice.js +++ b/src/components/Onboarding/steps/SelectDevice.js @@ -32,7 +32,7 @@ class SelectDevice extends PureComponent { } } render() { - const { t, onboarding, prevStep } = this.props + const { t, onboarding, jumpStep } = this.props return ( @@ -68,7 +68,7 @@ class SelectDevice extends PureComponent { horizontal t={t} nextStep={this.handleContinue} - prevStep={prevStep} + prevStep={() => jumpStep('init')} isContinueDisabled={onboarding.isLedgerNano === null} /> diff --git a/src/components/Onboarding/steps/SetPassword.js b/src/components/Onboarding/steps/SetPassword.js index 3c9f9d36..7448d050 100644 --- a/src/components/Onboarding/steps/SetPassword.js +++ b/src/components/Onboarding/steps/SetPassword.js @@ -2,8 +2,7 @@ import React, { PureComponent, Fragment } from 'react' import bcrypt from 'bcryptjs' -import { colors, radii } from 'styles/theme' -import styled from 'styled-components' +import { colors } from 'styles/theme' import { setEncryptionKey } from 'helpers/db' @@ -15,7 +14,13 @@ import IconChevronRight from 'icons/ChevronRight' import PasswordForm from '../../SettingsPage/PasswordForm' import type { StepProps } from '..' -import { Title, Description, DisclaimerBox, FixedTopContainer } from '../helperComponents' +import { + Title, + Description, + DisclaimerBox, + FixedTopContainer, + OnboardingFooterWrapper, +} from '../helperComponents' type State = { currentPassword: string, @@ -117,7 +122,7 @@ class SetPassword extends PureComponent { - + @@ -134,21 +139,10 @@ class SetPassword extends PureComponent { {t('app:common.continue')} - + ) } } export default SetPassword - -const CustomFooter = styled(Box).attrs({ - px: 5, - py: 3, - horizontal: true, - align: 'center', -})` - border-top: 1px solid ${p => p.theme.colors.lightFog}; - border-bottom-left-radius: ${radii[1]}px; - border-bottom-right-radius: ${radii[1]}px; -` diff --git a/src/icons/Cart.js b/src/icons/Cart.js new file mode 100644 index 00000000..2a42bbce --- /dev/null +++ b/src/icons/Cart.js @@ -0,0 +1,16 @@ +// @flow + +import React from 'react' + +const path = ( + +) + +export default ({ size, ...p }: { size: number }) => ( + + {path} + +) diff --git a/src/icons/Truck.js b/src/icons/Truck.js new file mode 100644 index 00000000..d643e3fd --- /dev/null +++ b/src/icons/Truck.js @@ -0,0 +1,16 @@ +// @flow + +import React from 'react' + +const path = ( + +) + +export default ({ size, ...p }: { size: number }) => ( + + {path} + +) diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js index 7655d877..22816556 100644 --- a/src/reducers/onboarding.js +++ b/src/reducers/onboarding.js @@ -57,6 +57,15 @@ const state: OnboardingState = { showBreadcrumb: false, }, }, + { + name: 'noDevice', + external: true, + options: { + showFooter: false, + showBackground: true, + showBreadcrumb: false, + }, + }, { name: 'selectDevice', label: 'Select Device', diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index 7139a669..2fa67577 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -15,6 +15,14 @@ init: noDevice: title: Do not have a Ledger device yet? desc: Please replace it with the final wording once it’s done. +noDevice: + title: Do not have a Ledger device yet? + buyNew: + title: Buy a Ledger device + trackOrder: + title: Track your order + learnMore: + title: Learn about Ledger Live selectDevice: title: To get started, select your device ledgerNanoCard: From 7177136ebaa66a69b0e7432d5caf66dc9b6237e6 Mon Sep 17 00:00:00 2001 From: Thibaut Boustany Date: Thu, 14 Jun 2018 17:17:13 +0200 Subject: [PATCH 08/20] Add missing i18n + ignore eslint false positives --- src/components/AccountPage/index.js | 2 +- src/components/CurrentAddress/index.js | 1 + src/components/DashboardPage/AccountCard.js | 2 +- src/components/DeviceConnect/index.js | 1 + src/components/FeesField/BitcoinKind.js | 14 +++++++---- src/components/MainSideBar/index.js | 25 +++++++++++-------- src/components/Onboarding/helperComponents.js | 2 +- .../Onboarding/steps/GenuineCheck.js | 6 ++--- .../steps/SelectPIN/SelectPINblue.js | 6 ++--- .../steps/SelectPIN/SelectPINnano.js | 8 +++--- .../steps/WriteSeed/WriteSeedBlue.js | 6 ++--- .../steps/WriteSeed/WriteSeedNano.js | 6 ++--- .../steps/WriteSeed/WriteSeedRestore.js | 8 +++--- src/components/RequestAmount/index.js | 2 +- src/components/SettingsPage/index.js | 6 ++++- src/components/ThrowBlock.js | 13 +++++++--- .../base/AccountsList/AccountRow.js | 6 +++-- src/components/base/AccountsList/index.js | 1 + src/components/base/LegacySelect/index.js | 10 +++++--- src/components/base/StepperNumber/index.js | 3 ++- src/components/modals/AddAccounts/index.js | 2 +- .../steps/02-step-connect-device.js | 2 ++ .../AddAccounts/steps/03-step-import.js | 12 ++++----- .../AddAccounts/steps/04-step-finish.js | 6 ++--- src/components/modals/Debug.js | 1 + src/components/modals/OperationDetails.js | 2 +- src/components/modals/Send/Footer.js | 4 +-- static/i18n/en/app.yml | 13 +++++++++- 28 files changed, 105 insertions(+), 65 deletions(-) diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js index 6486ffaf..9abb8b35 100644 --- a/src/components/AccountPage/index.js +++ b/src/components/AccountPage/index.js @@ -143,7 +143,7 @@ class AccountPage extends PureComponent { { {accountName ? ( + {/* eslint-disable-line react/jsx-no-literals */} Address for {accountName} ) : ( diff --git a/src/components/DashboardPage/AccountCard.js b/src/components/DashboardPage/AccountCard.js index 7d89941a..08ffa6fb 100644 --- a/src/components/DashboardPage/AccountCard.js +++ b/src/components/DashboardPage/AccountCard.js @@ -89,7 +89,7 @@ class AccountCard extends PureComponent<{ height={52} hideAxis isInteractive={false} - id={`account-chart-${account.id}`} + id={`account-chart-${account.id}`} /* eslint-disable-line react/jsx-no-literals */ unit={account.unit} /> diff --git a/src/components/DeviceConnect/index.js b/src/components/DeviceConnect/index.js index 679e1162..dcb3014f 100644 --- a/src/components/DeviceConnect/index.js +++ b/src/components/DeviceConnect/index.js @@ -200,6 +200,7 @@ class DeviceConnect extends PureComponent { const hasDevice = devices.length > 0 const hasMultipleDevices = devices.length > 1 + /* eslint-disable react/jsx-no-literals */ return ( diff --git a/src/components/FeesField/BitcoinKind.js b/src/components/FeesField/BitcoinKind.js index be8a8f23..0af0dfbe 100644 --- a/src/components/FeesField/BitcoinKind.js +++ b/src/components/FeesField/BitcoinKind.js @@ -3,6 +3,9 @@ import React, { Component } from 'react' import type { Account } from '@ledgerhq/live-common/lib/types' import styled from 'styled-components' +import { translate } from 'react-i18next' + +import type { T } from 'types/common' import InputCurrency from 'components/base/InputCurrency' import Select from 'components/base/Select' @@ -15,6 +18,7 @@ type Props = { account: Account, feePerByte: number, onChange: number => void, + t: T } type FeeItem = { @@ -104,14 +108,14 @@ class FeesField extends Component< } render() { - const { account, feePerByte, error, onChange } = this.props + const { account, feePerByte, error, onChange, t } = this.props const { items, selectedItem } = this.state const { units } = account.currency const satoshi = units[units.length - 1] return ( - +