Browse Source

genuine check screen, breadcrumb, disclaimer boxes

master
NastiaS 7 years ago
parent
commit
c1ab2f44d0
  1. 13
      src/components/Onboarding/OnboardingBreadcrumb.js
  2. 3
      src/components/Onboarding/helperComponents.js
  3. 5
      src/components/Onboarding/index.js
  4. 4
      src/components/Onboarding/steps/Analytics.js
  5. 4
      src/components/Onboarding/steps/Finish.js
  6. 220
      src/components/Onboarding/steps/GenuineCheck.js
  7. 4
      src/components/Onboarding/steps/SelectDevice.js
  8. 6
      src/components/Onboarding/steps/SelectPIN.js
  9. 4
      src/components/Onboarding/steps/SetPassword.js
  10. 6
      src/components/Onboarding/steps/WriteSeed.js
  11. 78
      src/icons/onboarding/LedgerNanoError.js
  12. 7
      src/reducers/onboarding.js
  13. 17
      static/i18n/en/onboarding.yml

13
src/components/Onboarding/OnboardingBreadcrumb.js

@ -18,15 +18,22 @@ type Props = {
function OnboardingBreadcrumb(props: Props) {
const { onboarding } = props
const { stepName } = onboarding
const { stepName, isGenuineFail } = onboarding
const filteredSteps = onboarding.steps
.filter(step => !step.external)
.map(step => ({ ...step, label: step.label })) // TODO: translate
const stepIndex = findIndex(filteredSteps, s => s.name === stepName)
return <Breadcrumb currentStep={stepIndex} items={filteredSteps} />
const genuineStepIndex = findIndex(filteredSteps, s => s.name === 'genuineCheck')
return (
<Breadcrumb
stepsErrors={isGenuineFail ? [genuineStepIndex] : undefined}
currentStep={stepIndex}
items={filteredSteps}
/>
)
}
export default connect(mapStateToProps)(OnboardingBreadcrumb)

3
src/components/Onboarding/helperComponents.js

@ -73,7 +73,7 @@ export const IconOptionRow = styled(Box).attrs({
color: 'wallet',
})``
export function DisclaimerBox({ disclaimerNotes }: { disclaimerNotes: any }) {
export function DisclaimerBox({ disclaimerNotes, ...p }: { disclaimerNotes: any }) {
return (
<Box
shrink
@ -84,6 +84,7 @@ export function DisclaimerBox({ disclaimerNotes }: { disclaimerNotes: any }) {
backgroundColor: '#ea2e490c',
border: 'dashed 1px #ea2e49b3',
}}
{...p}
>
<Box
m={3}

5
src/components/Onboarding/index.js

@ -10,7 +10,7 @@ import type { T } from 'types/common'
import type { OnboardingState } from 'reducers/onboarding'
import { saveSettings } from 'actions/settings'
import { nextStep, prevStep, jumpStep } from 'reducers/onboarding'
import { nextStep, prevStep, jumpStep, setGenuineCheckFail } from 'reducers/onboarding'
import { getCurrentDevice } from 'reducers/devices'
// TODO: re-write it without auto lock, fixed width of the password modal, not dynamic titles
@ -69,12 +69,14 @@ type Props = {
export type StepProps = {
t: T,
onboarding: OnboardingState,
prevStep: Function,
nextStep: Function,
jumpStep: Function,
finish: Function,
savePassword: Function,
getDeviceInfo: Function,
setGenuineCheckFail: Function,
}
class Onboarding extends PureComponent<Props> {
@ -107,6 +109,7 @@ class Onboarding extends PureComponent<Props> {
const stepProps: StepProps = {
t,
onboarding,
setGenuineCheckFail,
prevStep,
nextStep,
jumpStep,

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

@ -14,8 +14,8 @@ import type { StepProps } from '..'
export default (props: StepProps) => {
const { nextStep, prevStep, t } = props
return (
<Box sticky>
<Box grow alignItems="center" justifyContent="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:analytics.title')}</Title>
<Description style={{ maxWidth: 714 }}>{t('onboarding:analytics.desc')}</Description>
<DeviceIcon style={{ padding: 15 }}>

4
src/components/Onboarding/steps/Finish.js

@ -39,8 +39,8 @@ const socialMedia = [
export default (props: StepProps) => {
const { finish, t } = props
return (
<Box sticky alignItems="center" justifyContent="center">
<Box align="center" alignItems="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Box color="positiveGreen">
<IconCheckCircle size={44} />
</Box>

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

@ -1,71 +1,122 @@
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { radii } from 'styles/theme'
import type { T } from 'types/common'
import Box from 'components/base/Box'
import { setGenuineCheckFail } from 'reducers/onboarding'
import Box, { Card } from 'components/base/Box'
import Button from 'components/base/Button'
import IconCheck from 'icons/Check'
import IconLedgerNanoError from 'icons/onboarding/LedgerNanoError'
import { Title, Description } from '../helperComponents'
import { Title, Description, IconOptionRow } from '../helperComponents'
import type { StepProps } from '..'
import OnboardingFooter from '../OnboardingFooter'
const mapDispatchToProps = { setGenuineCheckFail }
type State = {
currentDevice: {
manufacturer: string,
release: number,
},
showDeviceInfo: boolean,
showError: boolean,
pinStepPass: boolean | null,
phraseStepPass: boolean | null,
}
// temp checking the release version of the device if connected
class GenuineCheck extends PureComponent<StepProps, State> {
state = {
showDeviceInfo: false,
currentDevice: { manufacturer: 'Unknown', release: 0 },
showError: false,
pinStepPass: null,
phraseStepPass: null,
}
handleCheckDevice = () => {
const currentDeviceInfo = this.props.getDeviceInfo()
if (currentDeviceInfo) {
this.setState({ showError: false, currentDevice: currentDeviceInfo, showDeviceInfo: true })
} else {
this.setState({ showError: true })
handleStepPass = (step: string, pass: boolean | null) => {
this.setState({ [`${step}`]: pass })
if (typeof pass === 'boolean' && !pass) {
this.props.setGenuineCheckFail(true)
}
}
redoGenuineCheck = () => {
this.props.setGenuineCheckFail(false)
}
contactSupport = () => {
console.log('contact support coming later')
}
renderGenuineFail = () => (
<GenuineCheckFail
redoGenuineCheck={this.redoGenuineCheck}
contactSupport={this.contactSupport}
t={this.props.t}
/>
)
render() {
const { nextStep, prevStep, t } = this.props
const { showDeviceInfo, currentDevice, showError } = this.state
const { nextStep, prevStep, t, onboarding } = this.props
const { pinStepPass, phraseStepPass } = this.state
if (onboarding.isGenuineFail) {
return this.renderGenuineFail()
}
return (
<Box sticky>
<Box grow alignItems="center" justifyContent="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:genuineCheck.title')}</Title>
<Description>{t('onboarding:genuineCheck.desc')}</Description>
<Box alignItems="center" justifyContent="center">
<Title>Coming next week</Title>
<Box alignItems="center" justifyContent="center" style={{ padding: '15px' }}>
<Button big primary onClick={() => this.handleCheckDevice()}>
Check your device!
</Button>
{showDeviceInfo && (
<Box>
<Description>
The manufacturer is <b>{currentDevice.manufacturer}</b>
The release number is <b>{currentDevice.release}</b>
</Description>
<Box mt={5}>
<CardWrapper>
<Box justify="center">
<Box horizontal>
<IconOptionRow>1.</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.steps.step1.title')}</CardTitle>
</Box>
<CardDescription>{t('onboarding:genuineCheck.steps.step2.desc')}</CardDescription>
</Box>
{!pinStepPass ? (
<ButtonCombo handleStepPass={this.handleStepPass} step="pinStepPass" />
) : (
<Box alignItems="center">
<IconCheck size={16} />
</Box>
)}
{showError && (
<Box>
<Description color="red">Connect your device please</Description>
</CardWrapper>
</Box>
<Box mt={5}>
<CardWrapper>
<Box justify="center">
<Box horizontal>
<IconOptionRow>2.</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.steps.step2.title')}</CardTitle>
</Box>
<CardDescription>{t('onboarding:genuineCheck.steps.step2.desc')}</CardDescription>
</Box>
{!phraseStepPass ? (
<ButtonCombo handleStepPass={this.handleStepPass} step="phraseStepPass" />
) : (
<Box justify="center">
<IconCheck size={20} />
</Box>
)}
</Box>
</CardWrapper>
</Box>
<Box mt={5}>
<CardWrapper>
<Box justify="center">
<Box horizontal>
<IconOptionRow>3.</IconOptionRow>
<CardTitle>{t('onboarding:genuineCheck.steps.step3.title')}</CardTitle>
</Box>
<CardDescription>{t('onboarding:genuineCheck.steps.step3.desc')}</CardDescription>
</Box>
<Box justify="center" horizontal mx={4}>
<Button big primary>
{t('onboarding:genuineCheck.buttons.genuineCheck')}
</Button>
</Box>
</CardWrapper>
</Box>
</Box>
<OnboardingFooter
@ -81,4 +132,93 @@ class GenuineCheck extends PureComponent<StepProps, State> {
}
}
export default GenuineCheck
export default connect(null, mapDispatchToProps)(GenuineCheck)
export function ButtonCombo({ handleStepPass, step }: { handleStepPass: any, step: string }) {
return (
<Box justify="center" horizontal style={{ margin: '0 20px' }}>
<Button style={{ padding: '0 20px' }} outline onClick={() => handleStepPass(step, true)}>
Yes
</Button>
<Button style={{ padding: '0 20px' }} outline onClick={() => handleStepPass(step, false)}>
No
</Button>
</Box>
)
}
// TODO extract to the separate file
export function GenuineCheckFail({
redoGenuineCheck,
contactSupport,
t,
}: {
redoGenuineCheck: () => void,
contactSupport: () => void,
t: T,
}) {
return (
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:genuineCheck.errorPage.ledgerNano.title')}</Title>
<Description style={{ maxWidth: 527 }}>
{t('onboarding:genuineCheck.errorPage.ledgerNano.desc')}
</Description>
<Box style={{ minWidth: 527 }}>
<IconLedgerNanoError />
</Box>
</Box>
<Wrapper horizontal>
<Button
small
outline
onClick={() => {
redoGenuineCheck()
}}
>
Back
</Button>
<Button
small
danger
onClick={() => {
contactSupport()
}}
ml="auto"
>
{t('onboarding:genuineCheck.buttons.contactSupport')}
</Button>
</Wrapper>
</Box>
)
}
export const CardDescription = styled(Box).attrs({
ff: 'Open Sans|Regular',
fontSize: 4,
textAlign: 'left',
color: 'grey',
})`
max-width: 400px;
`
export const CardTitle = styled(Box).attrs({
ff: 'Open Sans|SemiBold',
fontSize: 4,
textAlign: 'left',
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(Card).attrs({
horizontal: true,
p: 5,
})`
border: 1px solid #d8d8d8;
max-height: 97px;
min-width: 620px;
`

4
src/components/Onboarding/steps/SelectDevice.js

@ -14,8 +14,8 @@ export default (props: StepProps) => {
const { nextStep, t } = props
return (
<Box sticky alignItems="center" justifyContent="center">
<Box align="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:selectDevice.title')}</Title>
<Description style={{ maxWidth: 714 }}>{t('onboarding:selectDevice.desc')}</Description>
<Box>

6
src/components/Onboarding/steps/SelectPIN.js

@ -62,8 +62,8 @@ export default (props: StepProps) => {
},
]
return (
<Box sticky>
<Box grow alignItems="center" justifyContent="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Box align="center" mb={5}>
<Title>{t('onboarding:selectPIN.title')}</Title>
<Description style={{ maxWidth: 527 }}>{t('onboarding:selectPIN.desc')}</Description>
@ -78,7 +78,7 @@ export default (props: StepProps) => {
{steps.map(step => <OptionRow key={step.key} step={step} />)}
</Box>
</Inner>
<DisclaimerBox disclaimerNotes={disclaimerNotes} />
<DisclaimerBox mt={6} disclaimerNotes={disclaimerNotes} />
</Box>
</Box>
<OnboardingFooter

4
src/components/Onboarding/steps/SetPassword.js

@ -49,8 +49,8 @@ class SetPassword extends PureComponent<StepProps, State> {
const { nextStep, prevStep, t } = this.props
const { isPasswordModalOpened, isPasswordEnabled } = this.state
return (
<Box sticky>
<Box grow alignItems="center" justifyContent="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Title>{t('onboarding:setPassword.title')}</Title>
<Description style={{ maxWidth: 714 }}>{t('onboarding:setPassword.desc')}</Description>
<IconSetPassword />

6
src/components/Onboarding/steps/WriteSeed.js

@ -56,8 +56,8 @@ export default (props: StepProps) => {
},
]
return (
<Box sticky>
<Box grow alignItems="center" justifyContent="center">
<Box sticky pt={150}>
<Box grow alignItems="center">
<Box align="center" mb={5}>
<Title>{t('onboarding:writeSeed.title')}</Title>
<Description style={{ maxWidth: 714 }}>{t('onboarding:writeSeed.desc')}</Description>
@ -71,7 +71,7 @@ export default (props: StepProps) => {
{steps.map(step => <OptionRow key={step.key} step={step} />)}
</Box>
</Inner>
<DisclaimerBox disclaimerNotes={disclaimerNotes} />
<DisclaimerBox mt={6} disclaimerNotes={disclaimerNotes} />
</Box>
</Box>
<OnboardingFooter

78
src/icons/onboarding/LedgerNanoError.js

@ -0,0 +1,78 @@
// @flow
import React from 'react'
export default () => (
<svg>
<defs>
<linearGradient id="a" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" />
<stop offset="100%" stopColor="#FFF" />
</linearGradient>
<rect id="b" width="41.711" height="238.384" rx="4" />
<path
id="c"
d="M5.773 5l2.541-2.541a.235.235 0 0 0 0-.332l-.441-.441a.235.235 0 0 0-.332 0L5 4.226l-2.541-2.54a.235.235 0 0 0-.332 0l-.441.441a.235.235 0 0 0 0 .332L4.226 5l-2.54 2.541a.235.235 0 0 0 0 .332l.441.441c.092.092.24.092.332 0L5 5.774l2.541 2.54c.092.092.24.092.332 0l.441-.441a.235.235 0 0 0 0-.332L5.774 5z"
/>
</defs>
<g fill="none" fillRule="evenodd">
<path
stroke="#1D2027"
strokeWidth="2"
d="M127.356 30a1 1 0 0 1-1 1H100.13a5 5 0 0 1-5-5v-8.486a5 5 0 0 1 5-5h26.225a1 1 0 0 1 1 1V30z"
/>
<path stroke="#142533" strokeWidth="2" d="M94.747 24.792H83.818v-6.436h10.93v6.436z" />
<path
stroke="#1D2027"
strokeWidth="2"
d="M127.423 27.287V16.032l6.977.082a1 1 0 0 1 .988 1v9.267a1 1 0 0 1-1.012.988l-6.953-.082z"
/>
<path
fill="url(#a)"
d="M6.836 53.925h1.616v82.65H6.836v-82.65zm5.657 0h1.616v82.65h-1.616v-82.65z"
transform="matrix(0 -1 -1 0 137 32)"
/>
<g transform="rotate(-90 85 -42)">
<rect width="4.492" height="17.12" x="38.336" y="15.505" fill="#142533" rx="2" />
<rect width="4.492" height="17.12" x="38.336" y="70.094" fill="#142533" rx="2" />
<use fill="#FFF" />
<rect
width="39.711"
height="236.384"
x="1"
y="1"
fill="#FCE0E4"
stroke="#142533"
strokeLinejoin="square"
strokeWidth="2"
rx="4"
/>
<rect
width="20.176"
height="61.019"
x="10.767"
y="21.173"
fill="#FFF"
stroke="#EA2E49"
rx="1.6"
/>
<path
fill="#FFF"
stroke="#142533"
strokeWidth="2"
d="M20.856 95.966C9.89 95.966 1 104.856 1 115.822v118.562a3 3 0 0 0 3 3h33.711a3 3 0 0 0 3-3V115.822c0-10.966-8.89-19.856-19.855-19.856z"
/>
<ellipse cx="21.016" cy="116.123" stroke="#EA2E49" rx="10.57" ry="10.644" />
<g transform="translate(16.066 26.884)">
<mask id="d" fill="#fff">
<use xlinkHref="#c" />
</mask>
<use fill="#000" fillRule="nonzero" xlinkHref="#c" />
<g fill="#EA2E49" mask="url(#d)">
<path d="M0 0h10v10H0z" />
</g>
</g>
</g>
</g>
</svg>
)

7
src/reducers/onboarding.js

@ -17,11 +17,13 @@ export type OnboardingState = {
stepIndex: number,
stepName: string, // TODO: specify that the string comes from Steps type
steps: Step[],
isGenuineFail: boolean,
}
const state: OnboardingState = {
stepIndex: 0,
stepName: 'start',
isGenuineFail: false,
steps: [
{
name: 'start',
@ -138,6 +140,10 @@ const handlers = {
const index = state.steps.indexOf(step)
return { ...state, stepName: step.name, stepIndex: index }
},
ONBOARDING_SET_GENUINE_CHECK_FAIL: (state, { payload: isGenuineFail }) => ({
...state,
isGenuineFail,
}),
}
export default handleActions(handlers, state)
@ -145,3 +151,4 @@ 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')

17
static/i18n/en/onboarding.yml

@ -51,6 +51,23 @@ writeSeed:
genuineCheck:
title: Check PIN / Seed / Authenticity
desc: Your Ledger Nano S should now display Your device is now ready. Before getting started, please confirm that
steps:
step1:
title: You alone have chosen your PIN code
desc: This is a long text, please replace it with the final wording once it’s done. Lorem ipsum dolor amet ledger lorem dolor
step2:
title: You alone have initialized your recovery phrase
desc: This is a long text, please replace it with the final wording once it’s done. Lorem ipsum dolor amet ledger lorem dolor
step3:
title: Your device is a genuine Ledger device
desc: This is a long text, please replace it with the final wording once it’s done. Lorem ipsum dolor amet ledger lorem dolor
buttons:
genuineCheck: Genuine check
contactSupport: Contact Support
errorPage:
ledgerNano:
title: Something is wrong with your Ledger Nano S
desc: Your Ledger Nano S should now display Your device is now ready. Before getting started, please confirm that
setPassword:
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