diff --git a/src/components/Onboarding/OnboardingBreadcrumb.js b/src/components/Onboarding/OnboardingBreadcrumb.js index 8455cb1d..b1505aef 100644 --- a/src/components/Onboarding/OnboardingBreadcrumb.js +++ b/src/components/Onboarding/OnboardingBreadcrumb.js @@ -20,18 +20,31 @@ type Props = { function OnboardingBreadcrumb(props: Props) { const { onboarding, t } = props - const { stepName, genuine } = onboarding + const { stepName, genuine, onboardingRelaunched } = onboarding const isInitializedFlow = onboarding.flowType === 'initializedDevice' - const regularFilteredSteps = onboarding.steps + const regularSteps = onboarding.steps .filter(step => !step.external) .map(step => ({ ...step, label: t(step.label) })) const alreadyInitializedSteps = onboarding.steps - .filter(step => !step.external && step.name !== 'writeSeed' && step.name !== 'selectPIN') + .filter(step => !step.external && !step.options.alreadyInitSkip) .map(step => ({ ...step, label: t(step.label) })) - const filteredSteps = isInitializedFlow ? alreadyInitializedSteps : regularFilteredSteps + const onboardingRelaunchedSteps = onboarding.steps + .filter( + step => + isInitializedFlow + ? !step.options.alreadyInitSkip && !step.external && !step.options.relaunchSkip + : !step.external && !step.options.relaunchSkip, + ) + .map(step => ({ ...step, label: t(step.label) })) + + const filteredSteps = onboardingRelaunched + ? onboardingRelaunchedSteps + : isInitializedFlow + ? alreadyInitializedSteps + : regularSteps const stepIndex = findIndex(filteredSteps, s => s.name === stepName) const genuineStepIndex = findIndex(filteredSteps, s => s.name === 'genuineCheck') diff --git a/src/components/Onboarding/steps/GenuineCheck/index.js b/src/components/Onboarding/steps/GenuineCheck/index.js index d421b561..ae472f9c 100644 --- a/src/components/Onboarding/steps/GenuineCheck/index.js +++ b/src/components/Onboarding/steps/GenuineCheck/index.js @@ -151,7 +151,10 @@ class GenuineCheck extends PureComponent { const { prevStep, onboarding, jumpStep } = this.props onboarding.flowType === 'initializedDevice' ? jumpStep('selectDevice') : prevStep() } - + handleNextStep = () => { + const { onboarding, jumpStep, nextStep } = this.props + onboarding.onboardingRelaunched ? jumpStep('finish') : nextStep() + } renderGenuineFail = () => ( { ) : ( diff --git a/src/components/SettingsPage/LaunchOnboardingBtn.js b/src/components/SettingsPage/LaunchOnboardingBtn.js new file mode 100644 index 00000000..a63ba1b0 --- /dev/null +++ b/src/components/SettingsPage/LaunchOnboardingBtn.js @@ -0,0 +1,50 @@ +// @flow + +import React, { Fragment, PureComponent } from 'react' +import { connect } from 'react-redux' +import { saveSettings } from 'actions/settings' +import { translate } from 'react-i18next' +import type { T } from 'types/common' +import type { SettingsState } from 'reducers/settings' +import type { OnboardingState } from 'reducers/onboarding' +import Track from 'analytics/Track' +import Onboarding from 'components/Onboarding' +import Button from 'components/base/Button/index' +import { relaunchOnboarding } from 'reducers/onboarding' + +const mapDispatchToProps = { + saveSettings, + relaunchOnboarding, +} + +type Props = { + saveSettings: ($Shape) => void, + relaunchOnboarding: ($Shape) => void, + t: T, +} + +class LaunchOnboardingBtn extends PureComponent { + handleLaunchOnboarding = () => { + this.props.saveSettings({ hasCompletedOnboarding: false }) + this.props.relaunchOnboarding({ onboardingRelaunched: true }) + return + } + render() { + const { t } = this.props + return ( + + + + + ) + } +} + +export default translate()( + connect( + null, + mapDispatchToProps, + )(LaunchOnboardingBtn), +) diff --git a/src/components/SettingsPage/sections/Help.js b/src/components/SettingsPage/sections/Help.js index 2f35d122..ac2ae1b1 100644 --- a/src/components/SettingsPage/sections/Help.js +++ b/src/components/SettingsPage/sections/Help.js @@ -13,6 +13,7 @@ import OpenUserDataDirectoryBtn from 'components/OpenUserDataDirectoryBtn' import CleanButton from '../CleanButton' import ResetButton from '../ResetButton' import AboutRowItem from '../AboutRowItem' +import LaunchOnboardingBtn from '../LaunchOnboardingBtn' import { SettingsSection as Section, @@ -57,6 +58,12 @@ class SectionHelp extends PureComponent { > + + + { + ONBOARDING_PREV_STEP: (state: OnboardingState) => { const step = state.steps.find(step => step.name === state.stepName) if (!step) { return state @@ -160,7 +146,7 @@ const handlers = { } return { ...state, stepName: state.steps[index - 1].name, stepIndex: index - 1 } }, - ONBOARDING_JUMP_STEP: (state, { payload: stepName }) => { + ONBOARDING_JUMP_STEP: (state: OnboardingState, { payload: stepName }) => { const step = state.steps.find(step => step.name === stepName) if (!step) { return state @@ -169,25 +155,30 @@ const handlers = { return { ...state, stepName: step.name, stepIndex: index } }, - UPDATE_GENUINE_CHECK: (state, { payload: obj }) => ({ + UPDATE_GENUINE_CHECK: (state: OnboardingState, { payload: obj }) => ({ ...state, genuine: { ...state.genuine, ...obj, }, }), - ONBOARDING_SET_FLOW_TYPE: (state, { payload: flowType }) => ({ + ONBOARDING_SET_FLOW_TYPE: (state: OnboardingState, { payload: flowType }) => ({ ...state, flowType, }), - ONBOARDING_SET_DEVICE_TYPE: (state, { payload: isLedgerNano }) => ({ + ONBOARDING_SET_DEVICE_TYPE: (state: OnboardingState, { payload: isLedgerNano }) => ({ ...state, isLedgerNano, }), + ONBOARDING_RELAUNCH: ( + state: OnboardingState, + { payload: onboardingRelaunched }: { payload: $Shape }, + ) => ({ ...initialState, ...onboardingRelaunched }), } -export default handleActions(handlers, state) +export default handleActions(handlers, initialState) +export const relaunchOnboarding = createAction('ONBOARDING_RELAUNCH') export const nextStep = createAction('ONBOARDING_NEXT_STEP') export const prevStep = createAction('ONBOARDING_PREV_STEP') export const jumpStep = createAction('ONBOARDING_JUMP_STEP') diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 73a966eb..4f799169 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -7,6 +7,7 @@ common: confirm: Confirm cancel: Cancel delete: Delete + launch: Launch continue: Continue learnMore: Learn more skipThisStep: Skip this step @@ -359,6 +360,8 @@ settings: analyticsDesc: Enable analytics of anonymous data to help Ledger improve the user experience. This includes the operating system, language, firmware versions and the number of added accounts. reportErrors: Report bugs reportErrorsDesc: Share anonymous usage and diagnostics data to help improve Ledger products, services and security features. + launchOnboarding: Onboarding + launchOnboardingDesc: Launch again the onboarding to add a new device to the Ledger Live application about: desc: Information about Ledger Live, terms and conditions, and privacy policy. help: