Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add notifications onboarding wizard #9263

Merged
merged 40 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1c5219e
chore: add all translations necessary to notifications feature
Apr 16, 2024
2897805
Merge branch 'main' into feat/notifications-translations
Jonathansoufer Apr 16, 2024
fd25dd0
chore: re-organize OnboardingWizard screens
Apr 16, 2024
f9820d8
chore: add translations for onboarding wizard
Apr 16, 2024
789d313
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 16, 2024
a83b505
chore: add bell icon on navBar
Apr 16, 2024
c461806
chore: fix bad translations usage
Apr 16, 2024
1d2d617
chore: fix navBar alignment on android
Apr 16, 2024
ccb11b1
chore: updates snapshot
Apr 16, 2024
eebc4ca
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 16, 2024
cbd9181
chore: fix e2e tests
Apr 16, 2024
e92e1dc
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 16, 2024
1e299ae
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 17, 2024
559959d
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 17, 2024
a45bd08
chore: updates snapshot
Apr 18, 2024
ad6f55f
Merge branch 'main' into feat/notifications-onboarding-wizard
Apr 18, 2024
874614d
chore: replaces testing lib from enzyme to @testing-library
Apr 18, 2024
dc87f1f
chore: refactored to FC
Apr 18, 2024
357e4e0
chore: refactor metrics
Apr 18, 2024
7638520
chore: refactor to FC
Apr 18, 2024
a671483
chore: removed unused props
Apr 18, 2024
a1db401
chore: refactor getBackButtonBehavior
Apr 18, 2024
c0f2737
chore: refactor wizard flow to add a senventh page
Apr 18, 2024
ec468f3
chore: remove unecessary prop
Apr 18, 2024
78a679e
chore: add seventh step
Apr 18, 2024
19c6258
chore: updates snapshot
Apr 18, 2024
b89e523
Merge branch 'main' into feat/notifications-onboarding-wizard
Apr 18, 2024
bae05ea
chore: updates tests
Apr 18, 2024
b444788
chore: add seventh step awareness
Apr 18, 2024
a0f5c55
chore: refactor style
Apr 18, 2024
6026e41
chore: updates snapshot
Apr 18, 2024
0298f2c
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 18, 2024
403c952
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 19, 2024
6a598a3
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 19, 2024
a9d8cd4
chore: fix e2e onboarding tests
Apr 19, 2024
ad8f16f
chore: adds missing method for e2e
Apr 19, 2024
4b3084f
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 19, 2024
658f369
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 22, 2024
9c44a71
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 23, 2024
5b01fbc
Merge branch 'main' into feat/notifications-onboarding-wizard
Jonathansoufer Apr 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) && (
<OnboardingWizard navigation={navigation} coachmarkRef={tabBarRef} />
),
[navigation, wizardStep],
Expand Down
31 changes: 22 additions & 9 deletions app/components/UI/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,17 @@ const styles = StyleSheet.create({
paddingVertical: Device.isAndroid() ? 14 : 8,
},
infoButton: {
paddingRight: Device.isAndroid() ? 22 : 18,
paddingRight: Device.isAndroid() ? 0 : 18,
marginTop: 5,
},
disabled: {
opacity: 0.3,
},
leftButtonContainer: {
marginRight: 12,
flexDirection: 'row',
alignItems: 'flex-end',
},
optinHeaderLeft: {
flexDirection: 'row',
alignItems: 'center',
Expand Down Expand Up @@ -981,14 +986,22 @@ export function getWalletNavbarOptions(
/>
),
headerRight: () => (
<ButtonIcon
variant={ButtonIconVariants.Primary}
onPress={openQRScanner}
iconName={IconName.Scan}
style={styles.infoButton}
size={IconSize.Xl}
testID={WalletViewSelectorsIDs.WALLET_SCAN_BUTTON}
/>
<View style={styles.leftButtonContainer}>
<ButtonIcon
Jonathansoufer marked this conversation as resolved.
Show resolved Hide resolved
variant={ButtonIconVariants.Primary}
iconName={IconName.Notification}
style={styles.infoButton}
size={IconSize.Xl}
/>
<ButtonIcon
variant={ButtonIconVariants.Primary}
onPress={openQRScanner}
iconName={IconName.Scan}
style={styles.infoButton}
size={IconSize.Xl}
testID={WalletViewSelectorsIDs.WALLET_SCAN_BUTTON}
/>
</View>
),
headerStyle: innerStyles.headerStyle,
headerTintColor: themeColors.primary.default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ exports[`Coachmark should render correctly 1`] = `
}
>
1
/5
/6
</Text>
</View>
<TouchableOpacity
Expand Down
2 changes: 1 addition & 1 deletion app/components/UI/OnboardingWizard/Coachmark/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export default class Coachmark extends PureComponent {
<View style={styles.progress}>
<View style={styles.progessContainer}>
{currentStep !== 0 && (
<Text style={styles.stepCounter}>{currentStep}/5</Text>
<Text style={styles.stepCounter}>{currentStep}/6</Text>
)}
</View>

Expand Down
2 changes: 1 addition & 1 deletion app/components/UI/OnboardingWizard/Step1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
});

Expand Down
179 changes: 73 additions & 106 deletions app/components/UI/OnboardingWizard/Step2/index.js
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -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 (
<View style={dynamicOnboardingStyles.contentContainer}>
Expand All @@ -132,36 +97,38 @@ class Step2 extends PureComponent {
);
};

render() {
return (
<View style={styles.main}>
<View
style={[
styles.coachmarkContainer,
{
top: this.state.coachmarkTop,
},
]}
>
<Coachmark
title={strings('onboarding_wizard_new.step2.title')}
content={this.content()}
onNext={this.onNext}
onBack={this.onBack}
topIndicatorPosition={'topCenter'}
currentStep={1}
onClose={this.onClose}
/>
</View>
return (
<View style={styles.main}>
<View
style={[
styles.coachmarkContainer,
{
top: coachmarkTop,
},
]}
>
<Coachmark
title={strings('onboarding_wizard_new.step2.title')}
content={content()}
onNext={onNext}
onBack={onBack}
topIndicatorPosition={'topCenter'}
currentStep={1}
onClose={onCloseStep}
/>
</View>
);
}
}
</View>
);
};

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);
13 changes: 4 additions & 9 deletions app/components/UI/OnboardingWizard/Step3/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -27,6 +27,9 @@ const styles = StyleSheet.create({
},
coachmarkContainer: {
position: 'absolute',
left: 0,
right: 0,
marginHorizontal: 16,
},
});

Expand All @@ -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;
Expand All @@ -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]);
Expand Down Expand Up @@ -109,8 +106,6 @@ const Step3 = ({ setOnboardingWizardStep, coachmarkRef, onClose }) => {
styles.coachmarkContainer,
{
top: coachmarkTop,
left: coachmarkLeft,
right: coachmarkRight,
},
]}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ exports[`Step4 should render correctly 1`] = `
}
}
>
<Component />
<Component
coachmarkRef={Object {}}
/>
</ContextProvider>
`;
Loading
Loading