Browse Source

Merge pull request #386 from NastiaS/polishBranch

Polish branch
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
ea7521147e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/components/Onboarding/OnboardingBreadcrumb.js
  2. 5
      src/components/Onboarding/OnboardingFooter.js
  3. 14
      src/components/Onboarding/index.js
  4. 107
      src/components/Onboarding/steps/Analytics.js
  5. 72
      src/components/Onboarding/steps/GenuineCheck.js
  6. 15
      src/components/Onboarding/steps/Init.js
  7. 16
      src/icons/Recover.js
  8. 25
      src/reducers/onboarding.js
  9. 2
      src/reducers/settings.js
  10. 8
      static/i18n/en/onboarding.yml

4
src/components/Onboarding/OnboardingBreadcrumb.js

@ -18,7 +18,7 @@ type Props = {
function OnboardingBreadcrumb(props: Props) {
const { onboarding } = props
const { stepName, isGenuineFail } = onboarding
const { stepName, genuine } = onboarding
const filteredSteps = onboarding.steps
.filter(step => !step.external)
@ -29,7 +29,7 @@ function OnboardingBreadcrumb(props: Props) {
return (
<Breadcrumb
stepsErrors={isGenuineFail ? [genuineStepIndex] : undefined}
stepsErrors={genuine.isGenuineFail ? [genuineStepIndex] : undefined}
currentStep={stepIndex}
items={filteredSteps}
/>

5
src/components/Onboarding/OnboardingFooter.js

@ -22,14 +22,15 @@ type Props = {
t: T,
nextStep: () => void,
prevStep: () => void,
isContinueDisabled?: boolean,
}
const OnboardingFooter = ({ t, nextStep, prevStep, ...props }: Props) => (
const OnboardingFooter = ({ t, nextStep, prevStep, isContinueDisabled, ...props }: Props) => (
<Wrapper {...props}>
<Button small outline onClick={() => prevStep()}>
{t('common:back')}
</Button>
<Button small primary onClick={() => nextStep()} ml="auto">
<Button disabled={isContinueDisabled} small primary onClick={() => nextStep()} ml="auto">
{t('common:continue')}
</Button>
</Wrapper>

14
src/components/Onboarding/index.js

@ -10,13 +10,7 @@ import type { T } from 'types/common'
import type { OnboardingState } from 'reducers/onboarding'
import { saveSettings } from 'actions/settings'
import {
nextStep,
prevStep,
jumpStep,
setGenuineCheckFail,
isLedgerNano,
} from 'reducers/onboarding'
import { nextStep, prevStep, jumpStep, updateGenuineCheck, isLedgerNano } from 'reducers/onboarding'
import { getCurrentDevice } from 'reducers/devices'
// import { unlock } from 'reducers/application'
@ -80,9 +74,10 @@ export type StepProps = {
nextStep: Function,
jumpStep: Function,
finish: Function,
saveSettings: Function,
// savePassword: Function,
getDeviceInfo: Function,
setGenuineCheckFail: Function,
updateGenuineCheck: Function,
isLedgerNano: Function,
}
@ -116,7 +111,7 @@ class Onboarding extends PureComponent<Props> {
const stepProps: StepProps = {
t,
onboarding,
setGenuineCheckFail,
updateGenuineCheck,
isLedgerNano,
prevStep,
nextStep,
@ -124,6 +119,7 @@ class Onboarding extends PureComponent<Props> {
finish: this.finish,
// savePassword: this.savePassword,
getDeviceInfo: this.getDeviceInfo,
saveSettings,
}
return (

107
src/components/Onboarding/steps/Analytics.js

@ -1,7 +1,9 @@
// @flow
import React from 'react'
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
import { saveSettings } from 'actions/settings'
import Box from 'components/base/Box'
import CheckBox from 'components/base/CheckBox'
@ -10,51 +12,78 @@ import OnboardingFooter from '../OnboardingFooter'
import type { StepProps } from '..'
export default (props: StepProps) => {
const { nextStep, prevStep, t } = props
return (
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:analytics.title')}</Title>
<Description>{t('onboarding:analytics.desc')}</Description>
const mapDispatchToProps = { saveSettings }
<Box mt={5}>
<Container>
<Box justify="center">
<Box horizontal>
<AnalyticsTitle>{t('onboarding:analytics.shareDiagnostics.title')}</AnalyticsTitle>
type State = {
analyticsToggle: boolean,
termsConditionsToggle: boolean,
}
class Analytics extends PureComponent<StepProps, State> {
state = {
analyticsToggle: false,
termsConditionsToggle: false,
}
handleAnalyticsToggle = (isChecked: boolean) => {
this.setState({ analyticsToggle: !this.state.analyticsToggle })
this.props.saveSettings({
shareAnalytics: isChecked,
})
}
handleTermsToggle = () => {
this.setState({ termsConditionsToggle: !this.state.termsConditionsToggle })
}
render() {
const { nextStep, prevStep, t } = this.props
const { analyticsToggle, termsConditionsToggle } = this.state
return (
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:analytics.title')}</Title>
<Description>{t('onboarding:analytics.desc')}</Description>
<Box mt={5}>
<Container>
<Box justify="center" style={{ width: 450 }}>
<Box horizontal>
<AnalyticsTitle>{t('onboarding:analytics.shareAnalytics.title')}</AnalyticsTitle>
</Box>
<AnalyticsText>{t('onboarding:analytics.shareAnalytics.desc')}</AnalyticsText>
</Box>
<AnalyticsText>{t('onboarding:analytics.shareDiagnostics.desc')}</AnalyticsText>
</Box>
<Box alignItems="center" horizontal mx={5}>
<CheckBox isChecked={false} />
</Box>
</Container>
<Container>
<Box justify="center">
<Box horizontal>
<AnalyticsTitle>{t('onboarding:analytics.shareDiagnostics.title')}</AnalyticsTitle>
<Box alignItems="center" horizontal mx={5}>
<CheckBox isChecked={analyticsToggle} onChange={this.handleAnalyticsToggle} />
</Box>
<AnalyticsText>{t('onboarding:analytics.shareDiagnostics.desc')}</AnalyticsText>
</Box>
<Box alignItems="center" horizontal mx={5}>
<CheckBox isChecked={false} />
</Box>
</Container>
</Container>
<Container>
<Box justify="center" style={{ width: 450 }}>
<Box horizontal>
<AnalyticsTitle>{t('onboarding:analytics.termsConditions.title')}</AnalyticsTitle>
</Box>
<AnalyticsText>{t('onboarding:analytics.termsConditions.desc')}</AnalyticsText>
</Box>
<Box alignItems="center" horizontal mx={5}>
<CheckBox isChecked={termsConditionsToggle} onChange={this.handleTermsToggle} />
</Box>
</Container>
</Box>
</Box>
<OnboardingFooter
horizontal
align="center"
flow={2}
t={t}
nextStep={nextStep}
prevStep={prevStep}
isContinueDisabled={!termsConditionsToggle}
/>
</Box>
<OnboardingFooter
horizontal
align="center"
flow={2}
t={t}
nextStep={nextStep}
prevStep={prevStep}
/>
</Box>
)
)
}
}
export default connect(null, mapDispatchToProps)(Analytics)
export const AnalyticsText = styled(Box).attrs({
ff: 'Open Sans|Regular',
fontSize: 3,

72
src/components/Onboarding/steps/GenuineCheck.js

@ -1,13 +1,14 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { shell } from 'electron'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { radii } from 'styles/theme'
import type { T } from 'types/common'
import { setGenuineCheckFail } from 'reducers/onboarding'
import { updateGenuineCheck } from 'reducers/onboarding'
import Box, { Card } from 'components/base/Box'
import Button from 'components/base/Button'
@ -23,25 +24,25 @@ import { Title, Description, IconOptionRow } from '../helperComponents'
import type { StepProps } from '..'
import OnboardingFooter from '../OnboardingFooter'
const mapDispatchToProps = { setGenuineCheckFail }
const mapDispatchToProps = { updateGenuineCheck }
type State = {
pinStepPass: boolean | null,
phraseStepPass: boolean | null,
cachedPinStepButton: string,
cachedPhraseStepButton: string,
cachedRecoveryStepButton: string,
isGenuineCheckModalOpened: boolean,
isDeviceGenuine: boolean,
}
const INITIAL_STATE = {
cachedPinStepButton: '',
cachedRecoveryStepButton: '',
isGenuineCheckModalOpened: false,
}
class GenuineCheck extends PureComponent<StepProps, State> {
state = {
pinStepPass: null,
phraseStepPass: null,
cachedPinStepButton: '',
cachedPhraseStepButton: '',
isGenuineCheckModalOpened: false,
isDeviceGenuine: false,
...INITIAL_STATE,
cachedPinStepButton: this.props.onboarding.genuine.pinStepPass ? 'yes' : '',
cachedRecoveryStepButton: this.props.onboarding.genuine.recoveryStepPass ? 'yes' : '',
}
getButtonLabel() {
@ -61,15 +62,21 @@ class GenuineCheck extends PureComponent<StepProps, State> {
}
handleButtonPass = (item: Object, step: string) => {
this.setState({ [`${step}`]: item.pass })
this.props.updateGenuineCheck({ [`${step}`]: item.pass })
if (step === 'pinStepPass') {
this.setState({ cachedPinStepButton: item.key })
} else {
this.setState({ cachedPhraseStepButton: item.key })
this.setState({ cachedRecoveryStepButton: item.key })
}
if (!item.pass) {
this.props.setGenuineCheckFail(true)
this.setState(INITIAL_STATE)
this.props.updateGenuineCheck({
isGenuineFail: true,
recoveryStepPass: false,
pinStepPass: false,
isDeviceGenuine: false,
})
}
}
@ -79,15 +86,19 @@ class GenuineCheck extends PureComponent<StepProps, State> {
handleGenuineCheck = async isGenuine => {
await new Promise(r => setTimeout(r, 1e3)) // let's wait a bit before closing modal
this.handleCloseGenuineCheckModal()
this.setState({ isDeviceGenuine: isGenuine })
this.props.updateGenuineCheck({
isDeviceGenuine: isGenuine,
})
}
redoGenuineCheck = () => {
this.props.setGenuineCheckFail(false)
this.props.updateGenuineCheck({ isGenuineFail: false })
}
contactSupport = () => {
console.log('contact support coming later')
const contactSupportUrl =
'https://support.ledgerwallet.com/hc/en-us/requests/new?ticket_form_id=248165'
shell.openExternal(contactSupportUrl)
}
renderGenuineFail = () => (
@ -101,16 +112,10 @@ class GenuineCheck extends PureComponent<StepProps, State> {
render() {
const { nextStep, prevStep, t, onboarding } = this.props
const {
pinStepPass,
phraseStepPass,
cachedPinStepButton,
cachedPhraseStepButton,
isGenuineCheckModalOpened,
isDeviceGenuine,
} = this.state
const { genuine } = onboarding
const { cachedPinStepButton, cachedRecoveryStepButton, isGenuineCheckModalOpened } = this.state
if (onboarding.isGenuineFail) {
if (genuine.isGenuineFail) {
return this.renderGenuineFail()
}
@ -137,7 +142,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
</CardWrapper>
</Box>
<Box mt={5}>
<CardWrapper isDisabled={!pinStepPass}>
<CardWrapper isDisabled={!genuine.pinStepPass}>
<Box justify="center">
<Box horizontal>
<IconOptionRow>2.</IconOptionRow>
@ -148,13 +153,13 @@ class GenuineCheck extends PureComponent<StepProps, State> {
<RadioGroup
style={{ margin: '0 30px' }}
items={this.getButtonLabel()}
activeKey={cachedPhraseStepButton}
onChange={item => this.handleButtonPass(item, 'phraseStepPass')}
activeKey={cachedRecoveryStepButton}
onChange={item => this.handleButtonPass(item, 'recoveryStepPass')}
/>
</CardWrapper>
</Box>
<Box mt={5}>
<CardWrapper isDisabled={!phraseStepPass}>
<CardWrapper isDisabled={!genuine.recoveryStepPass}>
<Box justify="center">
<Box horizontal>
<IconOptionRow>3.</IconOptionRow>
@ -166,10 +171,10 @@ class GenuineCheck extends PureComponent<StepProps, State> {
<Button
big
primary
disabled={!phraseStepPass}
disabled={!genuine.recoveryStepPass}
onClick={this.handleOpenGenuineCheckModal}
>
{isDeviceGenuine ? (
{genuine.isDeviceGenuine ? (
<Box horizontal align="center" flow={1}>
<IconCheck size={16} />
<span>{t('onboarding:genuineCheck.buttons.tryAgain')}</span>
@ -189,6 +194,7 @@ class GenuineCheck extends PureComponent<StepProps, State> {
t={t}
nextStep={nextStep}
prevStep={prevStep}
isContinueDisabled={!genuine.isDeviceGenuine}
/>
<GenuineCheckModal
isOpened={isGenuineCheckModalOpened}

15
src/components/Onboarding/steps/Init.js

@ -2,10 +2,15 @@
import React from 'react'
import { shell } from 'electron'
import { colors } from 'styles/theme'
import styled from 'styled-components'
import Box, { Card } from 'components/base/Box'
import IconUser from 'icons/User'
import IconAdd from 'icons/Plus'
import IconRecover from 'icons/Recover'
import IconCheck from 'icons/Check'
import IconExternalLink from 'icons/ExternalLink'
import IconChevronRight from 'icons/ChevronRight'
import { Title } from '../helperComponents'
@ -16,28 +21,28 @@ export default (props: StepProps) => {
const optionCards = [
{
key: 'newDevice',
icon: <IconUser size={22} />,
icon: <IconAdd size={16} />,
title: t('onboarding:init.newDevice.title'),
desc: t('onboarding:init.newDevice.desc'),
onClick: () => nextStep(),
},
{
key: 'restoreDevice',
icon: <IconUser size={22} />,
icon: <IconRecover size={16} />,
title: t('onboarding:init.restoreDevice.title'),
desc: t('onboarding:init.restoreDevice.desc'),
onClick: () => jumpStep('choosePIN'),
},
{
key: 'initializedDevice',
icon: <IconUser size={22} />,
icon: <IconCheck size={16} />,
title: t('onboarding:init.initializedDevice.title'),
desc: t('onboarding:init.initializedDevice.desc'),
onClick: () => jumpStep('choosePIN'),
},
{
key: 'noDevice',
icon: <IconUser size={22} />,
icon: <IconExternalLink size={16} />,
title: t('onboarding:init.noDevice.title'),
desc: t('onboarding:init.noDevice.desc'),
onClick: () => shell.openExternal('https://www.ledger.fr/'),
@ -82,7 +87,7 @@ export function OptionFlowCard({ card }: { card: CardType }) {
}}
onClick={onClick}
>
<Box justify="center" color="grey" style={{ width: 50 }}>
<Box justify="center" style={{ width: 50, color: colors.wallet }}>
{icon}
</Box>
<Box ff="Open Sans|Regular" justify="center" fontSize={4} grow>

16
src/icons/Recover.js

@ -0,0 +1,16 @@
// @flow
import React from 'react'
const path = (
<path
fill="currentColor"
d="M15.65 7.985c.008 4.27-3.475 7.762-7.745 7.765a7.722 7.722 0 0 1-5.2-1.998.375.375 0 0 1-.013-.544l.53-.53a.376.376 0 0 1 .517-.012A6.228 6.228 0 0 0 7.9 14.25 6.247 6.247 0 0 0 14.15 8 6.247 6.247 0 0 0 7.9 1.75a6.23 6.23 0 0 0-4.434 1.845L5 5.108a.375.375 0 0 1-.264.642H.725a.375.375 0 0 1-.375-.375V1.42c0-.333.402-.5.638-.267l1.41 1.39A7.75 7.75 0 0 1 15.65 7.985zm-5.22 2.818l.44-.606a.375.375 0 0 0-.082-.524L8.65 8.118V3.625a.375.375 0 0 0-.375-.375h-.75a.375.375 0 0 0-.375.375v5.257l2.755 2.004a.375.375 0 0 0 .524-.083z"
/>
)
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
{path}
</svg>
)

25
src/reducers/onboarding.js

@ -17,14 +17,24 @@ export type OnboardingState = {
stepIndex: number,
stepName: string, // TODO: specify that the string comes from Steps type
steps: Step[],
isGenuineFail: boolean,
genuine: {
pinStepPass: boolean,
recoveryStepPass: boolean,
isGenuineFail: boolean,
isDeviceGenuine: boolean,
},
isLedgerNano: boolean,
}
const state: OnboardingState = {
stepIndex: 0,
stepName: 'start',
isGenuineFail: false,
genuine: {
pinStepPass: false,
recoveryStepPass: false,
isGenuineFail: false,
isDeviceGenuine: false,
},
isLedgerNano: true,
steps: [
{
@ -143,10 +153,15 @@ const handlers = {
const index = state.steps.indexOf(step)
return { ...state, stepName: step.name, stepIndex: index }
},
ONBOARDING_SET_GENUINE_CHECK_FAIL: (state, { payload: isGenuineFail }) => ({
UPDATE_GENUINE_CHECK: (state, { payload: obj }) => ({
...state,
isGenuineFail,
genuine: {
...state.genuine,
...obj,
},
}),
ONBOARDING_SET_DEVICE_TYPE: (state, { payload: isLedgerNano }) => ({
...state,
isLedgerNano,
@ -158,5 +173,5 @@ export default handleActions(handlers, state)
export const nextStep = createAction('ONBOARDING_NEXT_STEP')
export const prevStep = createAction('ONBOARDING_PREV_STEP')
export const jumpStep = createAction('ONBOARDING_JUMP_STEP')
export const setGenuineCheckFail = createAction('ONBOARDING_SET_GENUINE_CHECK_FAIL')
export const updateGenuineCheck = createAction('UPDATE_GENUINE_CHECK')
export const isLedgerNano = createAction('ONBOARDING_SET_DEVICE_TYPE')

2
src/reducers/settings.js

@ -30,6 +30,7 @@ export type SettingsState = {
},
region: string,
developerMode: boolean,
shareAnalytics: boolean,
}
/* have to check if available for all OS */
@ -69,6 +70,7 @@ const state: SettingsState = {
region,
developerMode: false,
loaded: false,
shareAnalytics: false,
}
function asCryptoCurrency(c: Currency): ?CryptoCurrency {

8
static/i18n/en/onboarding.yml

@ -82,12 +82,12 @@ setPassword:
analytics:
title: Help Ledger to improve its products and services
desc: This is a long text, please replace it with the final wording once it’s done.
Lorem ipsum dolor amet ledger lorem dolor ipsum amet
shareDiagnostics:
title: Share analytics
desc: Help Ledger improve its products and services by automatically sending diagnostics and usage data.
shareData:
shareAnalytics:
title: Share analytics
desc: Help Ledger improve its products and services by automatically sending diagnostics and usage data.
termsConditions:
title: Terms and Conditions
desc: Please accept terms and conditions to proceed
finish:
title: This is the title of the screen. 1 line is the maximum
desc: This is a long text, please replace it with the final wording once it’s done.
Lorem ipsum dolor amet ledger lorem dolor ipsum amet

Loading…
Cancel
Save