From 833c013fc2d8fa840579208bcc5a0963f4632a17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <gaetan.renaudeau@ledger.fr>
Date: Mon, 16 Jul 2018 15:21:20 +0200
Subject: [PATCH 1/2] Fixes #1152

---
 src/components/Onboarding/index.js              | 17 +++++------------
 src/components/OnboardingOrElse.js              | 11 +++++++----
 .../SettingsPage/LaunchOnboardingBtn.js         | 12 ++----------
 src/components/layout/Default.js                |  8 ++++----
 src/reducers/onboarding.js                      | 12 ++++++++----
 5 files changed, 26 insertions(+), 34 deletions(-)

diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js
index 18a172be..7c489606 100644
--- a/src/components/Onboarding/index.js
+++ b/src/components/Onboarding/index.js
@@ -20,6 +20,7 @@ import {
   updateGenuineCheck,
   isLedgerNano,
   flowType,
+  relaunchOnboarding,
 } from 'reducers/onboarding'
 import { getCurrentDevice } from 'reducers/devices'
 
@@ -66,6 +67,7 @@ const mapDispatchToProps = {
   jumpStep,
   unlock,
   openModal,
+  relaunchOnboarding,
 }
 
 type Props = {
@@ -80,6 +82,7 @@ type Props = {
   getCurrentDevice: Function,
   unlock: Function,
   openModal: string => void,
+  relaunchOnboarding: boolean => void,
 }
 
 export type StepProps = {
@@ -103,6 +106,7 @@ class Onboarding extends PureComponent<Props> {
   getDeviceInfo = () => this.props.getCurrentDevice
   finish = () => {
     this.props.saveSettings({ hasCompletedOnboarding: true })
+    this.props.relaunchOnboarding(false)
     setTimeout(() => {
       this.props.openModal(MODAL_DISCLAIMER)
     }, MODAL_DISCLAIMER_DELAY)
@@ -118,18 +122,7 @@ class Onboarding extends PureComponent<Props> {
   }
 
   render() {
-    const {
-      hasCompletedOnboarding,
-      onboarding,
-      prevStep,
-      nextStep,
-      jumpStep,
-      settings,
-      t,
-    } = this.props
-    if (hasCompletedOnboarding) {
-      return null
-    }
+    const { onboarding, prevStep, nextStep, jumpStep, settings, t } = this.props
 
     const StepComponent = STEPS[onboarding.stepName]
     const step = onboarding.steps[onboarding.stepIndex]
diff --git a/src/components/OnboardingOrElse.js b/src/components/OnboardingOrElse.js
index f82a9418..6b7ce709 100644
--- a/src/components/OnboardingOrElse.js
+++ b/src/components/OnboardingOrElse.js
@@ -4,25 +4,28 @@ import React, { PureComponent } from 'react'
 import { connect } from 'react-redux'
 import { createStructuredSelector } from 'reselect'
 import { hasCompletedOnboardingSelector } from 'reducers/settings'
+import { onboardingRelaunchedSelector } from 'reducers/onboarding'
 import Onboarding from './Onboarding'
 
 type Props = {
   hasCompletedOnboarding: boolean,
+  onboardingRelaunched: boolean,
   children: *,
 }
 
 class OnboardingOrElse extends PureComponent<Props> {
   render() {
-    const { hasCompletedOnboarding, children } = this.props
-    if (hasCompletedOnboarding) {
-      return children
+    const { hasCompletedOnboarding, onboardingRelaunched, children } = this.props
+    if (!hasCompletedOnboarding || onboardingRelaunched) {
+      return <Onboarding />
     }
-    return <Onboarding />
+    return children
   }
 }
 
 export default connect(
   createStructuredSelector({
     hasCompletedOnboarding: hasCompletedOnboardingSelector,
+    onboardingRelaunched: onboardingRelaunchedSelector,
   }),
 )(OnboardingOrElse)
diff --git a/src/components/SettingsPage/LaunchOnboardingBtn.js b/src/components/SettingsPage/LaunchOnboardingBtn.js
index a63ba1b0..1d6174c7 100644
--- a/src/components/SettingsPage/LaunchOnboardingBtn.js
+++ b/src/components/SettingsPage/LaunchOnboardingBtn.js
@@ -2,32 +2,24 @@
 
 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<SettingsState>) => void,
-  relaunchOnboarding: ($Shape<OnboardingState>) => void,
+  relaunchOnboarding: boolean => void,
   t: T,
 }
 
 class LaunchOnboardingBtn extends PureComponent<Props> {
   handleLaunchOnboarding = () => {
-    this.props.saveSettings({ hasCompletedOnboarding: false })
-    this.props.relaunchOnboarding({ onboardingRelaunched: true })
-    return <Onboarding />
+    this.props.relaunchOnboarding(true)
   }
   render() {
     const { t } = this.props
diff --git a/src/components/layout/Default.js b/src/components/layout/Default.js
index 7e426ce0..5d70f1db 100644
--- a/src/components/layout/Default.js
+++ b/src/components/layout/Default.js
@@ -88,8 +88,8 @@ class Default extends Component<Props> {
         <ExportLogsBtn hookToShortcut />
         <Track mandatory onMount event="App Starts" />
 
-        <OnboardingOrElse>
-          <IsUnlocked>
+        <IsUnlocked>
+          <OnboardingOrElse>
             {Object.entries(modals).map(([name, ModalComponent]: [string, any]) => (
               <ModalComponent key={name} />
             ))}
@@ -119,8 +119,8 @@ class Default extends Component<Props> {
             <KeyboardContent sequence="BJBJBJ">
               <PerfIndicator />
             </KeyboardContent>
-          </IsUnlocked>
-        </OnboardingOrElse>
+          </OnboardingOrElse>
+        </IsUnlocked>
       </Fragment>
     )
   }
diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js
index 4785cd19..44fc65d0 100644
--- a/src/reducers/onboarding.js
+++ b/src/reducers/onboarding.js
@@ -2,6 +2,7 @@
 
 import { SKIP_ONBOARDING } from 'config/constants'
 import { handleActions, createAction } from 'redux-actions'
+import type { State } from '.'
 
 type Step = {
   name: string,
@@ -170,14 +171,17 @@ const handlers = {
     ...state,
     isLedgerNano,
   }),
-  ONBOARDING_RELAUNCH: (
-    state: OnboardingState,
-    { payload: onboardingRelaunched }: { payload: $Shape<OnboardingState> },
-  ) => ({ ...initialState, ...onboardingRelaunched }),
+  ONBOARDING_RELAUNCH: (state: OnboardingState, { payload: onboardingRelaunched }) => ({
+    ...initialState,
+    onboardingRelaunched,
+  }),
 }
 
 export default handleActions(handlers, initialState)
 
+export const onboardingRelaunchedSelector = (s: State): ?boolean =>
+  s.onboarding.onboardingRelaunched
+
 export const relaunchOnboarding = createAction('ONBOARDING_RELAUNCH')
 export const nextStep = createAction('ONBOARDING_NEXT_STEP')
 export const prevStep = createAction('ONBOARDING_PREV_STEP')

From 462a82be6b0878d2557052d33b166dca6a94b402 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <gaetan.renaudeau@ledger.fr>
Date: Mon, 16 Jul 2018 15:47:40 +0200
Subject: [PATCH 2/2] Fixes #1146

---
 src/components/Onboarding/index.js | 41 +++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js
index 7c489606..11510a8a 100644
--- a/src/components/Onboarding/index.js
+++ b/src/components/Onboarding/index.js
@@ -5,6 +5,7 @@ import { compose } from 'redux'
 import { translate } from 'react-i18next'
 import { connect } from 'react-redux'
 import styled from 'styled-components'
+import IconCross from 'icons/Cross'
 
 import type { T } from 'types/common'
 import type { OnboardingState } from 'reducers/onboarding'
@@ -21,6 +22,7 @@ import {
   isLedgerNano,
   flowType,
   relaunchOnboarding,
+  onboardingRelaunchedSelector,
 } from 'reducers/onboarding'
 import { getCurrentDevice } from 'reducers/devices'
 
@@ -55,6 +57,7 @@ const STEPS = {
 
 const mapStateToProps = state => ({
   hasCompletedOnboarding: state.settings.hasCompletedOnboarding,
+  onboardingRelaunched: onboardingRelaunchedSelector(state),
   onboarding: state.onboarding,
   settings: state.settings,
   getCurrentDevice: getCurrentDevice(state),
@@ -73,6 +76,7 @@ const mapDispatchToProps = {
 type Props = {
   t: T,
   hasCompletedOnboarding: boolean,
+  onboardingRelaunched: boolean,
   saveSettings: Function,
   onboarding: OnboardingState,
   settings: SettingsState,
@@ -102,8 +106,30 @@ export type StepProps = {
   flowType: Function,
 }
 
+const CloseContainer = styled(Box).attrs({
+  p: 4,
+  color: 'fog',
+})`
+  cursor: pointer;
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 1;
+
+  &:hover {
+    color: ${p => p.theme.colors.grey};
+  }
+
+  &:active {
+    color: ${p => p.theme.colors.dark};
+  }
+`
+
 class Onboarding extends PureComponent<Props> {
   getDeviceInfo = () => this.props.getCurrentDevice
+  cancelRelaunch = () => {
+    this.props.relaunchOnboarding(false)
+  }
   finish = () => {
     this.props.saveSettings({ hasCompletedOnboarding: true })
     this.props.relaunchOnboarding(false)
@@ -122,7 +148,15 @@ class Onboarding extends PureComponent<Props> {
   }
 
   render() {
-    const { onboarding, prevStep, nextStep, jumpStep, settings, t } = this.props
+    const {
+      onboarding,
+      prevStep,
+      nextStep,
+      jumpStep,
+      settings,
+      t,
+      onboardingRelaunched,
+    } = this.props
 
     const StepComponent = STEPS[onboarding.stepName]
     const step = onboarding.steps[onboarding.stepIndex]
@@ -152,6 +186,11 @@ class Onboarding extends PureComponent<Props> {
     return (
       <Container>
         {step.options.showBreadcrumb && <OnboardingBreadcrumb />}
+        {onboardingRelaunched ? (
+          <CloseContainer onClick={this.cancelRelaunch}>
+            <IconCross size={16} />
+          </CloseContainer>
+        ) : null}
         <StepContainer>
           <StepComponent {...stepProps} />
         </StepContainer>