From eb74bd0b8860aebee2d67c6faf6df5cf444f0764 Mon Sep 17 00:00:00 2001
From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com>
Date: Tue, 23 Apr 2024 17:40:57 +0100
Subject: [PATCH] feat: add notifications onboarding wizard (#9263)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## **Description**
This PR implements a new step on the onboarding wizard to teach users
about notifications feature.
## **Related issues**
N/A
## **Manual testing steps**
Install a fresh app and accept the tour at beginning.
## **Screenshots/Recordings**
https://github.com/MetaMask/metamask-mobile/assets/44679989/ff6273cb-613c-4b4d-afe8-99fb63d5445f
### **After**
![Screenshot 2024-04-16 at 17 37
21](https://github.com/MetaMask/metamask-mobile/assets/44679989/faf5526d-a0e5-4c92-8dd4-fa65c08573a9)
## **Pre-merge author checklist**
- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
---
.../components/Navigation/TabBar/TabBar.tsx | 3 +-
app/components/UI/Navbar/index.js | 4 +-
.../__snapshots__/index.test.tsx.snap | 2 +-
.../UI/OnboardingWizard/Coachmark/index.js | 2 +-
.../UI/OnboardingWizard/Step1/index.js | 2 +-
.../UI/OnboardingWizard/Step2/index.js | 179 +++++-------
.../UI/OnboardingWizard/Step3/index.js | 13 +-
.../Step4/__snapshots__/index.test.tsx.snap | 4 +-
.../UI/OnboardingWizard/Step4/index.js | 108 +++----
.../UI/OnboardingWizard/Step4/index.test.tsx | 12 +-
.../UI/OnboardingWizard/Step5/index.js | 68 ++---
.../UI/OnboardingWizard/Step6/index.js | 57 ++--
.../UI/OnboardingWizard/Step6/index.test.tsx | 2 +-
.../Step7/__snapshots__/index.test.tsx.snap | 274 ++++++++++++++++++
.../UI/OnboardingWizard/Step7/index.js | 130 +++++++++
.../UI/OnboardingWizard/Step7/index.test.tsx | 10 +
app/components/UI/OnboardingWizard/index.js | 22 +-
app/components/Views/BrowserTab/index.js | 2 +-
app/components/Views/Wallet/index.tsx | 2 +-
app/core/Analytics/MetaMetrics.events.ts | 7 +-
e2e/pages/modals/OnboardingWizardModal.js | 11 +-
e2e/specs/wallet/start-exploring.spec.js | 9 +-
.../Modals/OnboardingWizardModal.js | 11 +
.../Components/OnboardingWizard.testIds.js | 3 +
24 files changed, 660 insertions(+), 277 deletions(-)
create mode 100644 app/components/UI/OnboardingWizard/Step7/__snapshots__/index.test.tsx.snap
create mode 100644 app/components/UI/OnboardingWizard/Step7/index.js
create mode 100644 app/components/UI/OnboardingWizard/Step7/index.test.tsx
diff --git a/app/component-library/components/Navigation/TabBar/TabBar.tsx b/app/component-library/components/Navigation/TabBar/TabBar.tsx
index ba51d756b88..c9658dab766 100644
--- a/app/component-library/components/Navigation/TabBar/TabBar.tsx
+++ b/app/component-library/components/Navigation/TabBar/TabBar.tsx
@@ -34,13 +34,12 @@ const TabBar = ({ state, descriptors, navigation }: TabBarProps) => {
* Current onboarding wizard step
*/
const wizardStep = useSelector((reduxState: any) => reduxState.wizard.step);
-
/**
* Return current step of onboarding wizard if not step 5 nor 0
*/
const renderOnboardingWizard = useCallback(
() =>
- [4, 5].includes(wizardStep) && (
+ [4, 5, 6].includes(wizardStep) && (
),
[navigation, wizardStep],
diff --git a/app/components/UI/Navbar/index.js b/app/components/UI/Navbar/index.js
index 3a6578f622f..d9e53a1f99f 100644
--- a/app/components/UI/Navbar/index.js
+++ b/app/components/UI/Navbar/index.js
@@ -90,13 +90,15 @@ const styles = StyleSheet.create({
paddingVertical: Device.isAndroid() ? 14 : 8,
},
infoButton: {
+ paddingRight: Device.isAndroid() ? 0 : 18,
+
marginTop: 5,
},
disabled: {
opacity: 0.3,
},
leftButtonContainer: {
- marginRight: Device.isAndroid() ? 22 : 12,
+ marginRight: 12,
flexDirection: 'row',
alignItems: 'flex-end',
},
diff --git a/app/components/UI/OnboardingWizard/Coachmark/__snapshots__/index.test.tsx.snap b/app/components/UI/OnboardingWizard/Coachmark/__snapshots__/index.test.tsx.snap
index c1844d8a260..9d504f204a5 100644
--- a/app/components/UI/OnboardingWizard/Coachmark/__snapshots__/index.test.tsx.snap
+++ b/app/components/UI/OnboardingWizard/Coachmark/__snapshots__/index.test.tsx.snap
@@ -159,7 +159,7 @@ exports[`Coachmark should render correctly 1`] = `
}
>
1
- /5
+ /6
{currentStep !== 0 && (
- {currentStep}/5
+ {currentStep}/6
)}
diff --git a/app/components/UI/OnboardingWizard/Step1/index.js b/app/components/UI/OnboardingWizard/Step1/index.js
index cc3ee2ab591..f711969658a 100644
--- a/app/components/UI/OnboardingWizard/Step1/index.js
+++ b/app/components/UI/OnboardingWizard/Step1/index.js
@@ -29,7 +29,7 @@ const styles = StyleSheet.create({
position: 'absolute',
left: 0,
right: 0,
- bottom: Device.isIphoneX() ? 80 : Device.isIos() ? 40 : 60,
+ bottom: Device.isIphoneX() ? 80 : Device.isIos() ? 40 : 64,
},
});
diff --git a/app/components/UI/OnboardingWizard/Step2/index.js b/app/components/UI/OnboardingWizard/Step2/index.js
index 3bce98fe7d9..2e4f0a8ba6f 100644
--- a/app/components/UI/OnboardingWizard/Step2/index.js
+++ b/app/components/UI/OnboardingWizard/Step2/index.js
@@ -1,19 +1,20 @@
-import React, { PureComponent } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Platform, StyleSheet, Text, View } from 'react-native';
-import Coachmark from '../Coachmark';
import setOnboardingWizardStep from '../../../../actions/wizard';
import { strings } from '../../../../../locales/i18n';
+import Coachmark from '../Coachmark';
+
import onboardingStyles from './../styles';
import {
MetaMetricsEvents,
ONBOARDING_WIZARD_STEP_DESCRIPTION,
} from '../../../../core/Analytics';
-import { mockTheme, ThemeContext } from '../../../../util/theme';
+import { useTheme } from '../../../../util/theme';
import generateTestId from '../../../../../wdio/utils/generateTestId';
import { ONBOARDING_WIZARD_SECOND_STEP_CONTENT_ID } from '../../../../../wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds';
-import { withMetricsAwareness } from '../../../../components/hooks/useMetrics';
+import { useMetrics } from '../../../hooks/useMetrics';
const styles = StyleSheet.create({
main: {
@@ -27,95 +28,59 @@ const styles = StyleSheet.create({
},
});
-class Step2 extends PureComponent {
- static propTypes = {
- /**
- * Dispatch set onboarding wizard step
- */
- setOnboardingWizardStep: PropTypes.func,
- /**
- * Coachmark ref to get position
- */
- coachmarkRef: PropTypes.object,
- /**
- * Callback called when closing step
- */
- onClose: PropTypes.func,
- /**
- * Metrics injected by withMetricsAwareness HOC
- */
- metrics: PropTypes.object,
- };
-
- state = {
- coachmarkTop: 0,
- };
+const Step2 = ({ setOnboardingWizardStep, coachmarkRef, onClose }) => {
+ const { colors } = useTheme();
+ const { trackEvent } = useMetrics();
- componentDidMount = () => {
- this.getPosition(this.props.coachmarkRef.yourAccountRef);
- };
+ const [coachmarkTop, setCoachmarkTop] = useState(0);
- /**
- * If component ref defined, calculate its position and position coachmark accordingly
- */
- getPosition = (ref) => {
- ref &&
- ref.current &&
- ref.current.measure((fx, fy, width, height, px, py) => {
- this.setState({
- coachmarkTop: py + height,
- });
- });
- };
+ const handleLayout = useCallback(() => {
+ const yourAccRef = coachmarkRef.yourAccountRef?.current;
+ if (!yourAccRef) return;
- /**
- * Dispatches 'setOnboardingWizardStep' with next step
- */
- onNext = () => {
- const { setOnboardingWizardStep } = this.props;
- setOnboardingWizardStep && setOnboardingWizardStep(3);
- this.props.metrics.trackEvent(
- MetaMetricsEvents.ONBOARDING_TOUR_STEP_COMPLETED,
- {
- tutorial_step_count: 2,
- tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[2],
+ yourAccRef.measure(
+ (
+ accActionsFx,
+ accActionsFy,
+ accActionsWidth,
+ accActionsHeight,
+ accActionsPageX,
+ accActionsPageY,
+ ) => {
+ const top = accActionsHeight + accActionsPageY;
+ setCoachmarkTop(top);
},
);
+ }, [coachmarkRef.yourAccountRef]);
+
+ useEffect(() => {
+ handleLayout();
+ }, [handleLayout]);
+
+ const onNext = () => {
+ setOnboardingWizardStep && setOnboardingWizardStep(3);
+ trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_COMPLETED, {
+ tutorial_step_count: 2,
+ tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[2],
+ });
};
- /**
- * Dispatches 'setOnboardingWizardStep' with back step
- */
- onBack = () => {
- const { setOnboardingWizardStep } = this.props;
+ const onBack = () => {
setOnboardingWizardStep && setOnboardingWizardStep(1);
- this.props.metrics.trackEvent(
- MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED,
- {
- tutorial_step_count: 2,
- tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[2],
- },
- );
+ trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED, {
+ tutorial_step_count: 2,
+ tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[2],
+ });
};
- getOnboardingStyles = () => {
- const colors = this.context.colors || mockTheme.colors;
- return onboardingStyles(colors);
- };
+ const getOnboardingStyles = () => onboardingStyles(colors);
- /**
- * Calls props 'onClose'
- */
- onClose = () => {
- const { onClose } = this.props;
+ const onCloseStep = () => {
onClose && onClose(false);
};
- /**
- * Returns content for this step
- */
- content = () => {
- const dynamicOnboardingStyles = this.getOnboardingStyles();
+ const content = () => {
+ const dynamicOnboardingStyles = getOnboardingStyles();
return (
@@ -132,36 +97,38 @@ class Step2 extends PureComponent {
);
};
- render() {
- return (
-
-
-
-
+ return (
+
+
+
- );
- }
-}
+
+ );
+};
+
+Step2.propTypes = {
+ setOnboardingWizardStep: PropTypes.func,
+ coachmarkRef: PropTypes.object,
+ onClose: PropTypes.func,
+};
const mapDispatchToProps = (dispatch) => ({
setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)),
});
-Step2.contextType = ThemeContext;
-
-export default connect(null, mapDispatchToProps)(withMetricsAwareness(Step2));
+export default connect(null, mapDispatchToProps)(Step2);
diff --git a/app/components/UI/OnboardingWizard/Step3/index.js b/app/components/UI/OnboardingWizard/Step3/index.js
index 700ed3d9be0..6b1327e0d41 100644
--- a/app/components/UI/OnboardingWizard/Step3/index.js
+++ b/app/components/UI/OnboardingWizard/Step3/index.js
@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
-import { Dimensions, Platform, StyleSheet, Text, View } from 'react-native';
+import { Platform, StyleSheet, Text, View } from 'react-native';
import Coachmark from '../Coachmark';
import setOnboardingWizardStep from '../../../../actions/wizard';
import { strings } from '../../../../../locales/i18n';
@@ -27,6 +27,9 @@ const styles = StyleSheet.create({
},
coachmarkContainer: {
position: 'absolute',
+ left: 0,
+ right: 0,
+ marginHorizontal: 16,
},
});
@@ -35,8 +38,6 @@ const Step3 = ({ setOnboardingWizardStep, coachmarkRef, onClose }) => {
const { trackEvent } = useMetrics();
const [coachmarkTop, setCoachmarkTop] = useState(0);
- const [coachmarkLeft, setCoachmarkLeft] = useState(0);
- const [coachmarkRight, setCoachmarkRight] = useState(0);
const handleLayout = useCallback(() => {
const accActionsRef = coachmarkRef.accountActionsRef?.current;
@@ -52,11 +53,7 @@ const Step3 = ({ setOnboardingWizardStep, coachmarkRef, onClose }) => {
accActionsPageY,
) => {
const top = accActionsHeight + accActionsPageY;
- const right =
- Dimensions.get('window').width - (accActionsPageX + accActionsWidth);
setCoachmarkTop(top);
- setCoachmarkLeft(accActionsPageX);
- setCoachmarkRight(right);
},
);
}, [coachmarkRef.accountActionsRef]);
@@ -109,8 +106,6 @@ const Step3 = ({ setOnboardingWizardStep, coachmarkRef, onClose }) => {
styles.coachmarkContainer,
{
top: coachmarkTop,
- left: coachmarkLeft,
- right: coachmarkRight,
},
]}
>
diff --git a/app/components/UI/OnboardingWizard/Step4/__snapshots__/index.test.tsx.snap b/app/components/UI/OnboardingWizard/Step4/__snapshots__/index.test.tsx.snap
index b4e2d1c97bb..c074699512a 100644
--- a/app/components/UI/OnboardingWizard/Step4/__snapshots__/index.test.tsx.snap
+++ b/app/components/UI/OnboardingWizard/Step4/__snapshots__/index.test.tsx.snap
@@ -32,6 +32,8 @@ exports[`Step4 should render correctly 1`] = `
}
}
>
-
+
`;
diff --git a/app/components/UI/OnboardingWizard/Step4/index.js b/app/components/UI/OnboardingWizard/Step4/index.js
index 2973c67361f..5abe521348d 100644
--- a/app/components/UI/OnboardingWizard/Step4/index.js
+++ b/app/components/UI/OnboardingWizard/Step4/index.js
@@ -1,11 +1,14 @@
import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
-import { Dimensions, Platform, StyleSheet, Text, View } from 'react-native';
-import Coachmark from '../Coachmark';
+import { Platform, StyleSheet, Text, View } from 'react-native';
import setOnboardingWizardStep from '../../../../actions/wizard';
import { strings } from '../../../../../locales/i18n';
-import onboardingStyles from './../styles';
+import Coachmark from '../Coachmark';
+
+import Device from '../../../../util/device';
+
+import onboardingStyles from '../styles';
import {
MetaMetricsEvents,
ONBOARDING_WIZARD_STEP_DESCRIPTION,
@@ -13,7 +16,8 @@ import {
import { useTheme } from '../../../../util/theme';
import generateTestId from '../../../../../wdio/utils/generateTestId';
import { ONBOARDING_WIZARD_FOURTH_STEP_CONTENT_ID } from '../../../../../wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds';
-import { useMetrics } from '../../../../components/hooks/useMetrics';
+
+import { useMetrics } from '../../../hooks/useMetrics';
const styles = StyleSheet.create({
main: {
@@ -23,32 +27,25 @@ const styles = StyleSheet.create({
position: 'absolute',
left: 0,
right: 0,
+ marginHorizontal: 16,
},
- coachmark: { marginHorizontal: 16 },
});
-const Step4 = (props) => {
- const { setOnboardingWizardStep, onClose } = props;
- const { trackEvent } = useMetrics();
+const Step4 = ({ setOnboardingWizardStep, onClose }) => {
const { colors } = useTheme();
- const dynamicOnboardingStyles = onboardingStyles(colors);
- const [coachmarkBottom, setCoachmarkBottom] = useState();
-
- const getCoachmarkPosition = useCallback(() => {
- props?.coachmarkRef?.current?.measure(
- (x, y, width, heigh, pageX, pageY) => {
- setCoachmarkBottom(Dimensions.get('window').height - pageY);
- },
- );
- }, [props?.coachmarkRef]);
+ const { trackEvent } = useMetrics();
+
+ const [coachmarkTop, setCoachmarkTop] = useState(0);
+
+ const handleLayout = useCallback(() => {
+ const top = Device.isIphoneX() ? 80 : Device.isIos() ? 64 : 60;
+ setCoachmarkTop(top);
+ }, []);
useEffect(() => {
- getCoachmarkPosition();
- }, [getCoachmarkPosition]);
+ handleLayout();
+ }, [handleLayout]);
- /**
- * Dispatches 'setOnboardingWizardStep' with next step
- */
const onNext = () => {
setOnboardingWizardStep && setOnboardingWizardStep(5);
trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_COMPLETED, {
@@ -57,9 +54,6 @@ const Step4 = (props) => {
});
};
- /**
- * Dispatches 'setOnboardingWizardStep' with back step
- */
const onBack = () => {
setOnboardingWizardStep && setOnboardingWizardStep(3);
trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED, {
@@ -68,26 +62,29 @@ const Step4 = (props) => {
});
};
- /**
- * Calls props 'onClose'
- */
- const handleOnClose = () => {
+ const getOnboardingStyles = () => onboardingStyles(colors);
+
+ const onCloseStep = () => {
onClose && onClose(false);
};
- /**
- * Returns content for this step
- */
- const content = () => (
-
-
- {strings('onboarding_wizard_new.step4.content1')}
-
-
- );
+ const content = () => {
+ const dynamicOnboardingStyles = getOnboardingStyles();
+
+ return (
+
+
+ {strings('onboarding_wizard_new.step4.content1')}
+
+
+ );
+ };
return (
@@ -95,7 +92,7 @@ const Step4 = (props) => {
style={[
styles.coachmarkContainer,
{
- bottom: coachmarkBottom,
+ top: coachmarkTop,
},
]}
>
@@ -104,33 +101,22 @@ const Step4 = (props) => {
content={content()}
onNext={onNext}
onBack={onBack}
- style={styles.coachmark}
- bottomIndicatorPosition={'bottomCenter'}
+ topIndicatorPosition={'topRight'}
currentStep={3}
- onClose={handleOnClose}
+ onClose={onCloseStep}
/>
);
};
-const mapDispatchToProps = (dispatch) => ({
- setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)),
-});
-
Step4.propTypes = {
- /**
- * Dispatch set onboarding wizard step
- */
setOnboardingWizardStep: PropTypes.func,
- /**
- * Callback called when closing step
- */
onClose: PropTypes.func,
- /**
- * coachmark ref to get position
- */
- coachmarkRef: PropTypes.object,
};
+const mapDispatchToProps = (dispatch) => ({
+ setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)),
+});
+
export default connect(null, mapDispatchToProps)(Step4);
diff --git a/app/components/UI/OnboardingWizard/Step4/index.test.tsx b/app/components/UI/OnboardingWizard/Step4/index.test.tsx
index 5d484d0ba58..3aa4a51e59b 100644
--- a/app/components/UI/OnboardingWizard/Step4/index.test.tsx
+++ b/app/components/UI/OnboardingWizard/Step4/index.test.tsx
@@ -1,17 +1,23 @@
import React from 'react';
+import Step4 from '.';
import { shallow } from 'enzyme';
-import Step4 from './';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
+import initialBackgroundState from '../../../../util/test/initial-background-state.json';
const mockStore = configureMockStore();
-const store = mockStore({});
+const initialState = {
+ engine: {
+ backgroundState: initialBackgroundState,
+ },
+};
+const store = mockStore(initialState);
describe('Step4', () => {
it('should render correctly', () => {
const wrapper = shallow(
-
+
,
);
expect(wrapper).toMatchSnapshot();
diff --git a/app/components/UI/OnboardingWizard/Step5/index.js b/app/components/UI/OnboardingWizard/Step5/index.js
index 9f2450dd66b..2cba5e8eeff 100644
--- a/app/components/UI/OnboardingWizard/Step5/index.js
+++ b/app/components/UI/OnboardingWizard/Step5/index.js
@@ -2,51 +2,55 @@ import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Dimensions, Platform, StyleSheet, Text, View } from 'react-native';
-import { colors as importedColors } from '../../../../styles/common';
import Coachmark from '../Coachmark';
import setOnboardingWizardStep from '../../../../actions/wizard';
import { strings } from '../../../../../locales/i18n';
-import onboardingStyles from './../styles';
+import onboardingStyles from '../styles';
import {
MetaMetricsEvents,
ONBOARDING_WIZARD_STEP_DESCRIPTION,
} from '../../../../core/Analytics';
import { useTheme } from '../../../../util/theme';
-import { createBrowserNavDetails } from '../../../Views/Browser';
import generateTestId from '../../../../../wdio/utils/generateTestId';
import { ONBOARDING_WIZARD_FIFTH_STEP_CONTENT_ID } from '../../../../../wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds';
-import { useMetrics } from '../../../../components/hooks/useMetrics';
+import { useMetrics } from '../../../hooks/useMetrics';
-const WIDTH = Dimensions.get('window').width;
const styles = StyleSheet.create({
main: {
flex: 1,
- backgroundColor: importedColors.transparent,
- marginLeft: 16,
- },
- some: {
- width: WIDTH - 32,
},
coachmarkContainer: {
position: 'absolute',
left: 0,
right: 0,
+ marginHorizontal: 16,
},
});
const Step5 = (props) => {
- const { navigation, setOnboardingWizardStep, onClose } = props;
+ const { setOnboardingWizardStep, onClose } = props;
const { trackEvent } = useMetrics();
const { colors } = useTheme();
const dynamicOnboardingStyles = onboardingStyles(colors);
- const [coachmarkBottom, setCoachmarkBottom] = useState();
+ const [coachmarkBottom, setCoachmarkBottom] = useState(50);
+
+ const getCoachmarkPosition = useCallback(() => {
+ props?.coachmarkRef?.current?.measure(
+ (x, y, width, heigh, pageX, pageY) => {
+ setCoachmarkBottom(Dimensions.get('window').height - pageY);
+ },
+ );
+ }, [props?.coachmarkRef]);
+
+ useEffect(() => {
+ getCoachmarkPosition();
+ }, [getCoachmarkPosition]);
/**
* Dispatches 'setOnboardingWizardStep' with next step
*/
const onNext = () => {
setOnboardingWizardStep && setOnboardingWizardStep(6);
- navigation && navigation.navigate(...createBrowserNavDetails());
trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_COMPLETED, {
tutorial_step_count: 5,
tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[5],
@@ -54,13 +58,10 @@ const Step5 = (props) => {
};
/**
- * Dispatches 'setOnboardingWizardStep' with next step
+ * Dispatches 'setOnboardingWizardStep' with back step
*/
const onBack = () => {
- navigation && navigation.navigate('WalletView');
- setTimeout(() => {
- setOnboardingWizardStep && setOnboardingWizardStep(4);
- }, 1);
+ setOnboardingWizardStep && setOnboardingWizardStep(4);
trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED, {
tutorial_step_count: 5,
tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[5],
@@ -88,30 +89,23 @@ const Step5 = (props) => {
);
- const getCoachmarkPosition = useCallback(() => {
- props?.coachmarkRef?.current?.measure(
- (x, y, width, heigh, pageX, pageY) => {
- setCoachmarkBottom(Dimensions.get('window').height - pageY);
- },
- );
- }, [props?.coachmarkRef]);
-
- useEffect(() => {
- getCoachmarkPosition();
- }, [getCoachmarkPosition]);
-
return (
-
+
@@ -124,10 +118,6 @@ const mapDispatchToProps = (dispatch) => ({
});
Step5.propTypes = {
- /**
- * Object that represents the navigator
- */
- navigation: PropTypes.object,
/**
* Dispatch set onboarding wizard step
*/
@@ -137,7 +127,7 @@ Step5.propTypes = {
*/
onClose: PropTypes.func,
/**
- * ref
+ * coachmark ref to get position
*/
coachmarkRef: PropTypes.object,
};
diff --git a/app/components/UI/OnboardingWizard/Step6/index.js b/app/components/UI/OnboardingWizard/Step6/index.js
index 4a7fbf3c413..6acd9e7da2b 100644
--- a/app/components/UI/OnboardingWizard/Step6/index.js
+++ b/app/components/UI/OnboardingWizard/Step6/index.js
@@ -1,65 +1,59 @@
-import React, { useEffect, useState } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Platform, StyleSheet, Text, View } from 'react-native';
+import Device from '../../../../util/device';
import Coachmark from '../Coachmark';
import setOnboardingWizardStep from '../../../../actions/wizard';
import { strings } from '../../../../../locales/i18n';
-import onboardingStyles from './../styles';
-import Device from '../../../../util/device';
+import { createBrowserNavDetails } from '../../../Views/Browser';
+
+import onboardingStyles from '../styles';
import {
MetaMetricsEvents,
ONBOARDING_WIZARD_STEP_DESCRIPTION,
} from '../../../../core/Analytics';
import { useTheme } from '../../../../util/theme';
-import Routes from '../../../../constants/navigation/Routes';
import generateTestId from '../../../../../wdio/utils/generateTestId';
import { ONBOARDING_WIZARD_SIXTH_STEP_CONTENT_ID } from '../../../../../wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds';
-import { useMetrics } from '../../../../components/hooks/useMetrics';
+import { useMetrics } from '../../../hooks/useMetrics';
const styles = StyleSheet.create({
main: {
flex: 1,
},
coachmarkContainer: {
- flex: 1,
position: 'absolute',
+ alignSelf: 'center',
left: 0,
right: 0,
marginHorizontal: 16,
+ bottom: Device.isIphoneX() ? 80 : Device.isIos() ? 40 : 64,
},
});
const Step6 = (props) => {
const { setOnboardingWizardStep, onClose, navigation } = props;
const { trackEvent } = useMetrics();
-
- const [ready, setReady] = useState(false);
- const [coachmarkTop, setCoachmarkTop] = useState(0);
const { colors } = useTheme();
const dynamicOnboardingStyles = onboardingStyles(colors);
/**
- * If component ref defined, calculate its position and position coachmark accordingly
+ * Dispatches 'setOnboardingWizardStep' with next step
*/
- const getPosition = () => {
- const position = Device.isAndroid() ? 280 : Device.isIphoneX() ? 320 : 280;
- setCoachmarkTop(position);
- setReady(true);
+ const onNext = () => {
+ setOnboardingWizardStep && setOnboardingWizardStep(7);
+ navigation && navigation.navigate(...createBrowserNavDetails());
+ trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_COMPLETED, {
+ tutorial_step_count: 6,
+ tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[6],
+ });
};
- useEffect(() => {
- // As we're changing the view on this step, we have to make sure Browser is rendered
- setTimeout(() => {
- getPosition();
- }, 1200);
- }, []);
-
/**
- * Dispatches 'setOnboardingWizardStep' with back step
+ * Dispatches 'setOnboardingWizardStep' with next step
*/
const onBack = () => {
- navigation?.navigate?.(Routes.WALLET.HOME);
setOnboardingWizardStep && setOnboardingWizardStep(5);
trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED, {
tutorial_step_count: 6,
@@ -68,9 +62,9 @@ const Step6 = (props) => {
};
/**
- * Calls props onClose
+ * Calls props 'onClose'
*/
- const triggerOnClose = () => {
+ const handleOnClose = () => {
onClose && onClose(false);
};
@@ -88,19 +82,18 @@ const Step6 = (props) => {
);
- if (!ready) return null;
-
return (
-
+
@@ -121,7 +114,7 @@ Step6.propTypes = {
*/
setOnboardingWizardStep: PropTypes.func,
/**
- * Callback to call when closing
+ * Callback called when closing step
*/
onClose: PropTypes.func,
};
diff --git a/app/components/UI/OnboardingWizard/Step6/index.test.tsx b/app/components/UI/OnboardingWizard/Step6/index.test.tsx
index 07ea0ad77e8..a097d7067f2 100644
--- a/app/components/UI/OnboardingWizard/Step6/index.test.tsx
+++ b/app/components/UI/OnboardingWizard/Step6/index.test.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { shallow } from 'enzyme';
-import Step6 from './';
+import Step6 from '.';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
diff --git a/app/components/UI/OnboardingWizard/Step7/__snapshots__/index.test.tsx.snap b/app/components/UI/OnboardingWizard/Step7/__snapshots__/index.test.tsx.snap
new file mode 100644
index 00000000000..f08de91d1ff
--- /dev/null
+++ b/app/components/UI/OnboardingWizard/Step7/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,274 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Step7 should render correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ Using the browser
+
+
+
+
+
+
+
+ Search for sites by keyword or enter a URL. Have fun out there!
+
+
+
+
+
+ 6
+ /6
+
+
+
+
+ Got it
+
+
+
+
+
+
+
+`;
diff --git a/app/components/UI/OnboardingWizard/Step7/index.js b/app/components/UI/OnboardingWizard/Step7/index.js
new file mode 100644
index 00000000000..60e910e0c82
--- /dev/null
+++ b/app/components/UI/OnboardingWizard/Step7/index.js
@@ -0,0 +1,130 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { Platform, StyleSheet, Text, View } from 'react-native';
+import Coachmark from '../Coachmark';
+import setOnboardingWizardStep from '../../../../actions/wizard';
+import { strings } from '../../../../../locales/i18n';
+import onboardingStyles from '../styles';
+import Routes from '../../../../constants/navigation/Routes';
+
+import Device from '../../../../util/device';
+import {
+ MetaMetricsEvents,
+ ONBOARDING_WIZARD_STEP_DESCRIPTION,
+} from '../../../../core/Analytics';
+import { useTheme } from '../../../../util/theme';
+
+import generateTestId from '../../../../../wdio/utils/generateTestId';
+import { ONBOARDING_WIZARD_SEVENTH_STEP_CONTENT_ID } from '../../../../../wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds';
+import { useMetrics } from '../../../hooks/useMetrics';
+
+const styles = StyleSheet.create({
+ main: {
+ flex: 1,
+ },
+ coachmarkContainer: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ marginHorizontal: 16,
+ },
+});
+
+const Step7 = (props) => {
+ const { setOnboardingWizardStep, onClose, navigation } = props;
+ const { trackEvent } = useMetrics();
+
+ const [ready, setReady] = useState(false);
+ const [coachmarkTop, setCoachmarkTop] = useState(0);
+ const { colors } = useTheme();
+ const dynamicOnboardingStyles = onboardingStyles(colors);
+
+ /**
+ * If component ref defined, calculate its position and position coachmark accordingly
+ */
+ const getPosition = () => {
+ const position = Device.isAndroid() ? 280 : Device.isIphoneX() ? 320 : 280;
+ setCoachmarkTop(position);
+ setReady(true);
+ };
+
+ useEffect(() => {
+ getPosition();
+ }, []);
+
+ /**
+ * Dispatches 'setOnboardingWizardStep' with back step
+ */
+ const onBack = () => {
+ navigation?.navigate?.(Routes.WALLET.HOME);
+ setTimeout(() => {
+ setOnboardingWizardStep && setOnboardingWizardStep(6);
+ }, 1);
+ trackEvent(MetaMetricsEvents.ONBOARDING_TOUR_STEP_REVISITED, {
+ tutorial_step_count: 7,
+ tutorial_step_name: ONBOARDING_WIZARD_STEP_DESCRIPTION[7],
+ });
+ };
+
+ /**
+ * Calls props onClose
+ */
+ const triggerOnClose = () => {
+ navigation?.navigate?.(Routes.WALLET.HOME);
+ onClose && onClose(false);
+ };
+
+ /**
+ * Returns content for this step
+ */
+ const content = () => (
+
+
+ {strings('onboarding_wizard_new.step7.content1')}
+
+
+ );
+
+ if (!ready) return null;
+
+ return (
+
+
+
+
+
+ );
+};
+
+const mapDispatchToProps = (dispatch) => ({
+ setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)),
+});
+
+Step7.propTypes = {
+ /**
+ * Object that represents the navigator
+ */
+ navigation: PropTypes.object,
+ /**
+ * Dispatch set onboarding wizard step
+ */
+ setOnboardingWizardStep: PropTypes.func,
+ /**
+ * Callback to call when closing
+ */
+ onClose: PropTypes.func,
+};
+
+export default connect(null, mapDispatchToProps)(Step7);
diff --git a/app/components/UI/OnboardingWizard/Step7/index.test.tsx b/app/components/UI/OnboardingWizard/Step7/index.test.tsx
new file mode 100644
index 00000000000..0789f092857
--- /dev/null
+++ b/app/components/UI/OnboardingWizard/Step7/index.test.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import renderWithProvider from '../../../../util/test/renderWithProvider';
+import Step7 from '.';
+
+describe('Step7', () => {
+ it('should render correctly', () => {
+ const container = renderWithProvider();
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/app/components/UI/OnboardingWizard/index.js b/app/components/UI/OnboardingWizard/index.js
index 97dcd2a8442..fbbbb76e794 100644
--- a/app/components/UI/OnboardingWizard/index.js
+++ b/app/components/UI/OnboardingWizard/index.js
@@ -1,17 +1,20 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet } from 'react-native';
-import { colors as importedColors } from '../../../styles/common';
import { connect } from 'react-redux';
+import DefaultPreference from 'react-native-default-preference';
+import Modal from 'react-native-modal';
+import { colors as importedColors } from '../../../styles/common';
+
import Step1 from './Step1';
import Step2 from './Step2';
import Step3 from './Step3';
import Step4 from './Step4';
import Step5 from './Step5';
import Step6 from './Step6';
+import Step7 from './Step7';
import setOnboardingWizardStep from '../../../actions/wizard';
-import DefaultPreference from 'react-native-default-preference';
-import Modal from 'react-native-modal';
+import Routes from '../../../constants/navigation/Routes';
import { ONBOARDING_WIZARD, EXPLORED } from '../../../constants/storage';
import {
MetaMetricsEvents,
@@ -79,6 +82,8 @@ const OnboardingWizard = (props) => {
const theme = useTheme();
const { trackEvent } = useMetrics();
const styles = createStyles(theme);
+ // eslint-disable-next-line no-console
+ console.log('OnboardingWizard', step);
/**
* Close onboarding wizard setting step to 0 and closing drawer
@@ -121,6 +126,7 @@ const OnboardingWizard = (props) => {
/>
),
6: ,
+ 7: ,
};
return steps[step];
};
@@ -128,13 +134,13 @@ const OnboardingWizard = (props) => {
const getBackButtonBehavior = () => {
if (step === 1) {
return closeOnboardingWizard();
- } else if (step === 5) {
- setOnboardingWizardStep(4);
- navigation.navigate('WalletView');
- drawerRef?.current?.dismissDrawer?.();
} else if (step === 6) {
- drawerRef?.current?.showDrawer?.();
setOnboardingWizardStep(5);
+ navigation.navigate(Routes.WALLET.HOME);
+ drawerRef?.current?.dismissDrawer?.();
+ } else if (step === 7) {
+ drawerRef?.current?.showDrawer?.();
+ setOnboardingWizardStep(6);
}
return setOnboardingWizardStep(step - 1);
};
diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js
index 61fc1c71bbc..2b5cdd8bf4b 100644
--- a/app/components/Views/BrowserTab/index.js
+++ b/app/components/Views/BrowserTab/index.js
@@ -1420,7 +1420,7 @@ export const BrowserTab = (props) => {
*/
const renderOnboardingWizard = () => {
const { wizardStep } = props;
- if ([6].includes(wizardStep)) {
+ if ([7].includes(wizardStep)) {
if (!wizardScrollAdjusted.current) {
setTimeout(() => {
reload();
diff --git a/app/components/Views/Wallet/index.tsx b/app/components/Views/Wallet/index.tsx
index be6a137d57e..ad8ad348703 100644
--- a/app/components/Views/Wallet/index.tsx
+++ b/app/components/Views/Wallet/index.tsx
@@ -378,7 +378,7 @@ const Wallet = ({ navigation }: any) => {
*/
const renderOnboardingWizard = useCallback(
() =>
- [1, 2, 3].includes(wizardStep) && (
+ [1, 2, 3, 4, 5, 6].includes(wizardStep) && (
{
await TestHelpers.delay(3000);
await OnboardingWizardModal.isVisible();
await OnboardingWizardModal.tapTakeTourButton();
+ // Ensure step 1 is shown correctly
await OnboardingWizardModal.isYourAccountsTutorialStepVisible();
await OnboardingWizardModal.tapGotItButton();
- // Ensure step 3 is shown correctly
+ // Ensure step 2 is shown correctly
await OnboardingWizardModal.isEditAccountNameTutorialStepVisible();
- // await WalletView.editAccountName(ACCOUNT);
await OnboardingWizardModal.tapGotItButton();
await WalletView.isAccountNameCorrect(ACCOUNT);
+ // Ensure step 3 is shown correctly
+ await OnboardingWizardModal.isNotificationsTutorialStepVisible();
+ await OnboardingWizardModal.tapGotItButton();
// Ensure step 4 is shown correctly
await OnboardingWizardModal.isMainNavigationTutorialStepVisible();
await OnboardingWizardModal.tapGotItButton();
@@ -105,7 +108,7 @@ describe(SmokeCore('Start Exploring'), () => {
await OnboardingWizardModal.tapGotItButton();
await OnboardingWizardModal.isExploreTheBrowserTutorialStepVisible();
await OnboardingWizardModal.tapGotItButton();
- // Ensure step 6 is shown correctly
+ // Ensure step 7 is shown correctly
await OnboardingWizardModal.isBrowserSearchStepTutorialVisible();
await OnboardingWizardModal.tapGotItButton();
// Check that we are on the Browser page
diff --git a/wdio/screen-objects/Modals/OnboardingWizardModal.js b/wdio/screen-objects/Modals/OnboardingWizardModal.js
index 42588ee0a9d..83baed7a930 100644
--- a/wdio/screen-objects/Modals/OnboardingWizardModal.js
+++ b/wdio/screen-objects/Modals/OnboardingWizardModal.js
@@ -9,6 +9,7 @@ import {
ONBOARDING_WIZARD_STEP_1_NO_THANKS_ID,
ONBOARDING_WIZARD_STEP_1_TAKE_THE_TOUR_ID,
ONBOARDING_WIZARD_THIRD_STEP_CONTENT_ID,
+ ONBOARDING_WIZARD_SEVENTH_STEP_CONTENT_ID,
} from '../testIDs/Components/OnboardingWizard.testIds';
import Selectors from '../../helpers/Selectors';
@@ -67,6 +68,12 @@ class OnboardingWizardModal {
);
}
+ get step7Description() {
+ return Selectors.getElementByPlatform(
+ ONBOARDING_WIZARD_SEVENTH_STEP_CONTENT_ID,
+ );
+ }
+
get onBoardingWizardGotItButton() {
return Selectors.getElementByPlatform(ONBOARDING_WIZARD_NEXT_GOT_IT_BUTTON);
}
@@ -107,6 +114,10 @@ class OnboardingWizardModal {
await expect(await this.step6Description).toBeDisplayed();
}
+ async isStep7ContentDisplayed() {
+ await expect(await this.step7Description).toBeDisplayed();
+ }
+
async tapGotItButton() {
await Gestures.tap(this.onBoardingWizardGotItButton);
}
diff --git a/wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds.js b/wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds.js
index ea2ae8d309f..cde48e52b14 100644
--- a/wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds.js
+++ b/wdio/screen-objects/testIDs/Components/OnboardingWizard.testIds.js
@@ -29,3 +29,6 @@ export const ONBOARDING_WIZARD_FIFTH_STEP_CONTENT_ID =
export const ONBOARDING_WIZARD_SIXTH_STEP_CONTENT_ID =
'onboarding-wizard-step6-content';
+
+ export const ONBOARDING_WIZARD_SEVENTH_STEP_CONTENT_ID =
+ 'onboarding-wizard-step7-content';