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

Migrated user welcome modal #53225

Merged
merged 29 commits into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5e64eaf
add the migrated modal
ishpaul777 Nov 25, 2024
204bcc2
Merge branch 'main' into migrated-user-welcome-modal
ishpaul777 Nov 27, 2024
78ecc38
migrate-modal
ishpaul777 Nov 27, 2024
f2fc885
refactor: update animation handling and improve MenuItem rendering
ishpaul777 Nov 28, 2024
c9a2d9a
feat: add contentContainerStyles prop to FeatureTrainingModal and upd…
ishpaul777 Nov 28, 2024
8b41e2e
Merge branch 'Expensify:main' into migrated-user-welcome-modal
ishpaul777 Nov 28, 2024
01323e8
Merge branch 'Expensify:main' into migrated-user-welcome-modal
ishpaul777 Nov 29, 2024
349253c
Add modalInnerContainerStyle prop to FeatureTrainingModal and update …
ishpaul777 Dec 3, 2024
a1f2ea1
Add animationInnerContainerStyle and animationOuterContainerStyle pro…
ishpaul777 Dec 3, 2024
2d54669
Merge branch 'Expensify:main' into migrated-user-welcome-modal
ishpaul777 Dec 3, 2024
4e937b6
resolve conflict
ishpaul777 Dec 3, 2024
b9cac98
resolve conflict after merge
ishpaul777 Dec 3, 2024
0ef0a17
resolve conflict after merge
ishpaul777 Dec 3, 2024
3708788
fix animations
ishpaul777 Dec 3, 2024
839f0b8
refactor MigratedUserWelcomeModal: remove unused responsive layout ho…
ishpaul777 Dec 4, 2024
2c6a5be
refactor FeatureTrainingModal: remove shouldRenderAnimation prop and …
ishpaul777 Dec 4, 2024
4860fca
put this behind beta
ishpaul777 Dec 5, 2024
13dba9a
refactor dismissProductTrainingElement
ishpaul777 Dec 5, 2024
835e8d1
fix typo
ishpaul777 Dec 5, 2024
a1eaba1
Update src/ONYXKEYS.ts
ishpaul777 Dec 5, 2024
63e04a7
Update src/libs/actions/Welcome/index.ts
ishpaul777 Dec 5, 2024
d5a67d5
Update src/libs/actions/Welcome/index.ts
ishpaul777 Dec 5, 2024
5db4193
Rename nudgeMigrationWelcomeModal to migratedUserWelcomeModal
ishpaul777 Dec 5, 2024
69e5559
Add CONST migratedUserWelcomeModal
ishpaul777 Dec 5, 2024
041deab
Add DismissProductTrainingParams type and update API parameters
ishpaul777 Dec 5, 2024
0b3ef8d
add padding to modal container
ishpaul777 Dec 6, 2024
2e67ea4
Refactor MenuItem and MigratedUserWelcomeModal components to use Icon…
ishpaul777 Dec 6, 2024
ba2f51b
translations fix
ishpaul777 Dec 6, 2024
4575829
Fix typo in CONST
ishpaul777 Dec 8, 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ const CONST = {
COMBINED_TRACK_SUBMIT: 'combinedTrackSubmit',
CATEGORY_AND_TAG_APPROVERS: 'categoryAndTagApprovers',
PER_DIEM: 'newDotPerDiem',
PRODUCT_TRAINING: 'productTraining',
},
BUTTON_STATES: {
DEFAULT: 'default',
Expand Down Expand Up @@ -6372,6 +6373,8 @@ const CONST = {
HYBRID_APP: {
REORDERING_REACT_NATIVE_ACTIVITY_TO_FRONT: 'reorderingReactNativeActivityToFront',
},

MIGRTED_USER_WELCOME_MODAL: 'migratedUserWelcomeModal',
ishpaul777 marked this conversation as resolved.
Show resolved Hide resolved
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand Down
1 change: 1 addition & 0 deletions src/NAVIGATORS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export default {
FEATURE_TRANING_MODAL_NAVIGATOR: 'FeatureTrainingModalNavigator',
WELCOME_VIDEO_MODAL_NAVIGATOR: 'WelcomeVideoModalNavigator',
EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator',
MIGRATED_USER_MODAL_NAVIGATOR: 'MigratedUserModalNavigator',
FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator',
} as const;
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ const ONYXKEYS = {
// Stores onboarding last visited path
ONBOARDING_LAST_VISITED_PATH: 'onboardingLastVisitedPath',

// Object containing names/timestamps of dismissed product training elements (Modal, Tooltip, etc.)
NVP_DISMISSED_PRODUCT_TRAINING: 'nvp_dismissedProductTraining',

// Max width supported for HTML <canvas> element
MAX_CANVAS_WIDTH: 'maxCanvasWidth',

Expand Down Expand Up @@ -1023,6 +1026,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP]: boolean;
[ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record<string, string>;
[ONYXKEYS.CONCIERGE_REPORT_ID]: string;
[ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING]: OnyxTypes.DismissedProductTraining;
};
type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping;

Expand Down
1 change: 1 addition & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ const ROUTES = {
},
WELCOME_VIDEO_ROOT: 'onboarding/welcome-video',
EXPLANATION_MODAL_ROOT: 'onboarding/explanation',
MIGRATED_USER_WELCOME_MODAL: 'onboarding/migrated-user-welcome',

TRANSACTION_RECEIPT: {
route: 'r/:reportID/transaction/:transactionID/receipt',
Expand Down
4 changes: 4 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@ const SCREENS = {
ROOT: 'Explanation_Modal_Root',
},

MIGRATED_USER_WELCOME_MODAL: {
ROOT: 'MigratedUserWelcomeModal_Root',
},

I_KNOW_A_TEACHER: 'I_Know_A_Teacher',
INTRO_SCHOOL_PRINCIPAL: 'Intro_School_Principal',
I_AM_A_TEACHER: 'I_Am_A_Teacher',
Expand Down
76 changes: 65 additions & 11 deletions src/components/FeatureTrainingModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {VideoReadyForDisplayEvent} from 'expo-av';
import React, {useCallback, useEffect, useState} from 'react';
import {View} from 'react-native';
import {InteractionManager, View} from 'react-native';
import type {StyleProp, ViewStyle} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
Expand Down Expand Up @@ -39,6 +40,15 @@ type FeatureTrainingModalProps = {
/** Animation to show when video is unavailable. Useful when app is offline */
animation?: DotLottieAnimation;

/** Style for the inner container of the animation */
animationInnerContainerStyle?: StyleProp<ViewStyle>;

/** Style for the outer container of the animation */
animationOuterContainerStyle?: StyleProp<ViewStyle>;

/** Additional styles for the animation */
animationStyle?: StyleProp<ViewStyle>;

/** URL for the video */
videoURL: string;

Expand Down Expand Up @@ -70,10 +80,25 @@ type FeatureTrainingModalProps = {

/** Link to navigate to when user wants to learn more */
onHelp?: () => void;

/** Children to render */
children?: React.ReactNode;

/** Styles for the content container */
contentInnerContainerStyles?: StyleProp<ViewStyle>;

/** Styles for the content outer container */
contentOuterContainerStyles?: StyleProp<ViewStyle>;

/** Styles for the modal inner container */
modalInnerContainerStyle?: ViewStyle;
};

function FeatureTrainingModal({
animation,
animationStyle,
animationInnerContainerStyle,
animationOuterContainerStyle,
videoURL,
videoAspectRatio: videoAspectRatioProp,
title = '',
Expand All @@ -85,18 +110,26 @@ function FeatureTrainingModal({
onClose = () => {},
helpText = '',
onHelp = () => {},
children,
contentInnerContainerStyles,
contentOuterContainerStyles,
modalInnerContainerStyle,
}: FeatureTrainingModalProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout();
const [isModalVisible, setIsModalVisible] = useState(true);
const [isModalVisible, setIsModalVisible] = useState(false);
const [willShowAgain, setWillShowAgain] = useState(true);
const [videoStatus, setVideoStatus] = useState<VideoStatus>('video');
const [isVideoStatusLocked, setIsVideoStatusLocked] = useState(false);
const [videoAspectRatio, setVideoAspectRatio] = useState(videoAspectRatioProp ?? VIDEO_ASPECT_RATIO);
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {isOffline} = useNetwork();

useEffect(() => {
InteractionManager.runAfterInteractions(() => setIsModalVisible(true));
}, []);

useEffect(() => {
if (isVideoStatusLocked) {
return;
Expand Down Expand Up @@ -133,10 +166,11 @@ function FeatureTrainingModal({
// for the video until it loads. Also, when
// videoStatus === 'animation' it will
// set the same aspect ratio as the video would.
{aspectRatio},
animationInnerContainerStyle,
!!videoURL && {aspectRatio},
]}
>
{videoStatus === 'video' ? (
{!!videoURL && videoStatus === 'video' ? (
<GestureHandlerRootView>
<VideoPlayer
url={videoURL}
Expand All @@ -149,7 +183,7 @@ function FeatureTrainingModal({
/>
</GestureHandlerRootView>
) : (
<View style={[styles.flex1, styles.alignItemsCenter, {aspectRatio}]}>
<View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter, !!videoURL && {aspectRatio}, animationStyle]}>
<Lottie
source={animation ?? LottieAnimations.Hands}
style={styles.h100}
Expand All @@ -161,7 +195,21 @@ function FeatureTrainingModal({
)}
</View>
);
}, [animation, videoURL, videoAspectRatio, videoStatus, shouldUseNarrowLayout, styles]);
}, [
videoAspectRatio,
styles.w100,
styles.onboardingVideoPlayer,
styles.flex1,
styles.alignItemsCenter,
styles.justifyContentCenter,
styles.h100,
videoStatus,
videoURL,
animationStyle,
animation,
shouldUseNarrowLayout,
animationInnerContainerStyle,
]);

const toggleWillShowAgain = useCallback(() => setWillShowAgain((prevWillShowAgain) => !prevWillShowAgain), []);

Expand All @@ -170,8 +218,10 @@ function FeatureTrainingModal({
User.dismissTrackTrainingModal();
}
setIsModalVisible(false);
Navigation.goBack();
onClose?.();
InteractionManager.runAfterInteractions(() => {
Navigation.goBack();
onClose?.();
});
}, [onClose, willShowAgain]);

const closeAndConfirmModal = useCallback(() => {
Expand Down Expand Up @@ -199,16 +249,20 @@ function FeatureTrainingModal({
width: 'auto',
}
: {}),
...modalInnerContainerStyle,
}}
>
<View style={[styles.mh100, onboardingIsMediumOrLargerScreenWidth && styles.welcomeVideoNarrowLayout, safeAreaPaddingBottomStyle]}>
<View style={onboardingIsMediumOrLargerScreenWidth ? {padding: MODAL_PADDING} : {paddingHorizontal: MODAL_PADDING}}>{renderIllustration()}</View>
<View style={[styles.mt5, styles.mh5]}>
<View style={[onboardingIsMediumOrLargerScreenWidth ? {padding: MODAL_PADDING} : {paddingHorizontal: MODAL_PADDING}, animationOuterContainerStyle]}>
{renderIllustration()}
</View>
<View style={[styles.mt5, styles.mh5, contentOuterContainerStyles]}>
{!!title && !!description && (
<View style={[onboardingIsMediumOrLargerScreenWidth ? [styles.gap1, styles.mb8] : [styles.mb10]]}>
<View style={[onboardingIsMediumOrLargerScreenWidth ? [styles.gap1, styles.mb8] : [styles.mb10], contentInnerContainerStyles]}>
<Text style={[styles.textHeadlineH1]}>{title}</Text>
<Text style={styles.textSupporting}>{description}</Text>
{secondaryDescription.length > 0 && <Text style={[styles.textSupporting, styles.mt4]}>{secondaryDescription}</Text>}
{children}
</View>
)}
{shouldShowDismissModalOption && (
Expand Down
4 changes: 4 additions & 0 deletions src/components/Icon/Illustrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import EmailAddress from '@assets/images/simple-illustrations/simple-illustratio
import EmptyState from '@assets/images/simple-illustrations/simple-illustration__empty-state.svg';
import EnvelopeReceipt from '@assets/images/simple-illustrations/simple-illustration__envelopereceipt.svg';
import Filters from '@assets/images/simple-illustrations/simple-illustration__filters.svg';
import Flash from '@assets/images/simple-illustrations/simple-illustration__flash.svg';
import FolderOpen from '@assets/images/simple-illustrations/simple-illustration__folder-open.svg';
import Gears from '@assets/images/simple-illustrations/simple-illustration__gears.svg';
import HandCard from '@assets/images/simple-illustrations/simple-illustration__handcard.svg';
Expand All @@ -105,6 +106,7 @@ import LockOpen from '@assets/images/simple-illustrations/simple-illustration__l
import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg';
import MagnifyingGlassMoney from '@assets/images/simple-illustrations/simple-illustration__magnifyingglass-money.svg';
import Mailbox from '@assets/images/simple-illustrations/simple-illustration__mailbox.svg';
import ExpensifyMobileApp from '@assets/images/simple-illustrations/simple-illustration__mobileapp.svg';
import MoneyReceipts from '@assets/images/simple-illustrations/simple-illustration__money-receipts.svg';
import MoneyBadge from '@assets/images/simple-illustrations/simple-illustration__moneybadge.svg';
import MoneyIntoWallet from '@assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg';
Expand Down Expand Up @@ -290,4 +292,6 @@ export {
StripeCompanyCardDetailLarge,
VisaCompanyCardDetailLarge,
WellsFargoCompanyCardDetailLarge,
Flash,
ExpensifyMobileApp,
};
Loading
Loading