From 2e99d95d5ef0e223b3b011f14b7ca54baf2bc534 Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Wed, 27 Mar 2024 16:36:44 +0100 Subject: [PATCH 001/242] Add explanation modal --- src/NAVIGATORS.ts | 1 + src/ROUTES.ts | 1 + src/SCREENS.ts | 4 + src/components/ExplanationModal.tsx | 47 +++++ src/components/OnboardingWelcomeVideo.tsx | 155 +--------------- src/components/TestToolMenu.tsx | 4 +- src/components/WelcomeVideoModal.tsx | 167 ++++++++++++++++++ src/languages/en.ts | 5 + src/languages/es.ts | 5 + .../Navigation/AppNavigator/AuthScreens.tsx | 6 + .../Navigators/ExplanationModalNavigator.tsx | 28 +++ src/libs/Navigation/linkingConfig/config.ts | 8 + src/libs/Navigation/types.ts | 6 + 13 files changed, 287 insertions(+), 150 deletions(-) create mode 100644 src/components/ExplanationModal.tsx create mode 100644 src/components/WelcomeVideoModal.tsx create mode 100644 src/libs/Navigation/AppNavigator/Navigators/ExplanationModalNavigator.tsx diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index f199d2841ec0..9473be1c0ab5 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -9,5 +9,6 @@ export default { RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', ONBOARDING_MODAL_NAVIGATOR: 'OnboardingModalNavigator', WELCOME_VIDEO_MODAL_NAVIGATOR: 'WelcomeVideoModalNavigator', + EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', } as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2ac4f61622be..9b4e3c050497 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -671,6 +671,7 @@ const ROUTES = { ONBOARDING_PERSONAL_DETAILS: 'onboarding/personal-details', ONBOARDING_PURPOSE: 'onboarding/purpose', WELCOME_VIDEO_ROOT: 'onboarding/welcome-video', + EXPLANATION_MODAL_ROOT: 'onboarding/explanation', TRANSACTION_RECEIPT: { route: 'r/:reportID/transaction/:transactionID/receipt', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 7e6716b024b1..7ab9f70ce988 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -288,6 +288,10 @@ const SCREENS = { ROOT: 'Welcome_Video_Root', }, + EXPLANATION_MODAL: { + ROOT: 'Explanation_Modal_Root', + }, + I_KNOW_A_TEACHER: 'I_Know_A_Teacher', INTRO_SCHOOL_PRINCIPAL: 'Intro_School_Principal', I_AM_A_TEACHER: 'I_Am_A_Teacher', diff --git a/src/components/ExplanationModal.tsx b/src/components/ExplanationModal.tsx new file mode 100644 index 000000000000..733af013403a --- /dev/null +++ b/src/components/ExplanationModal.tsx @@ -0,0 +1,47 @@ +import React, { useEffect, useState } from 'react'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as Welcome from '@userActions/Welcome'; +import ROUTES from '@src/ROUTES'; +import variables from '@styles/variables'; +import Text from './Text'; +import WelcomeVideoModal from './WelcomeVideoModal'; + +function ExplanationModal() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const [shouldNavigateToOnboarding, setShouldNavigateToOnboarding] = useState(false); + + useEffect(() => { + Welcome.isOnboardingFlowCompleted({ + onNotCompleted: () => { + setShouldNavigateToOnboarding(true); + }, + }); + }, []); + + const onClose = () => { + // Small delay purely due to design considerations. + setTimeout(() => { + Navigation.goBack(); + if (shouldNavigateToOnboarding) { + // Uncomment once Stage 1 Onboarding Flow is ready + // Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS) + Navigation.navigate(ROUTES.ONBOARD) + } + }, variables.welcomeVideoDelay); + } + + return ( + + {/* TO DO: Add proper translations and text content */} + {translate('onboarding.explanationModal.title')} + {translate('onboarding.explanationModal.description1')} + {translate('onboarding.explanationModal.description2')} + + ); +} + +ExplanationModal.displayName = 'ExplanationModal'; +export default ExplanationModal; diff --git a/src/components/OnboardingWelcomeVideo.tsx b/src/components/OnboardingWelcomeVideo.tsx index 2b41bda3889f..cdd82d09f5c8 100644 --- a/src/components/OnboardingWelcomeVideo.tsx +++ b/src/components/OnboardingWelcomeVideo.tsx @@ -1,166 +1,25 @@ -import type {VideoReadyForDisplayEvent} from 'expo-av'; -import React, {useCallback, useEffect, useState} from 'react'; -import {View} from 'react-native'; +import React from 'react'; import useLocalize from '@hooks/useLocalize'; -import useNetwork from '@hooks/useNetwork'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import variables from '@styles/variables'; -import CONST from '@src/CONST'; -import Button from './Button'; -import Lottie from './Lottie'; -import LottieAnimations from './LottieAnimations'; -import Modal from './Modal'; -import SafeAreaConsumer from './SafeAreaConsumer'; import Text from './Text'; -import VideoPlayer from './VideoPlayer'; - -// Aspect ratio and height of the video. -// Useful before video loads to reserve space. -const VIDEO_ASPECT_RATIO = 1280 / 960; - -const MODAL_PADDING = variables.spacing2; - -type VideoLoadedEventType = { - srcElement: { - videoWidth: number; - videoHeight: number; - }; -}; - -type VideoPlaybackStatusEventType = { - isLoaded: boolean; -}; - -type VideoStatus = 'video' | 'animation'; +import WelcomeVideoModal from './WelcomeVideoModal'; function OnboardingWelcomeVideo() { const {translate} = useLocalize(); const styles = useThemeStyles(); - const [isModalVisible, setIsModalVisible] = useState(true); - const {shouldUseNarrowLayout} = useOnboardingLayout(); - const [welcomeVideoStatus, setWelcomeVideoStatus] = useState('video'); - const [isWelcomeVideoStatusLocked, setIsWelcomeVideoStatusLocked] = useState(false); - const [isVideoLoaded, setIsVideoLoaded] = useState(false); - const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO); - const {isOffline} = useNetwork(); - - useEffect(() => { - if (isWelcomeVideoStatusLocked) { - return; - } - - if (isOffline) { - setWelcomeVideoStatus('animation'); - } else if (!isOffline && isVideoLoaded) { - setWelcomeVideoStatus('video'); - setIsWelcomeVideoStatusLocked(true); - } - }, [isOffline, isVideoLoaded, isWelcomeVideoStatusLocked]); - const closeModal = useCallback(() => { - setIsModalVisible(false); + const onClose = () => { Navigation.goBack(); - }, []); - - const setAspectRatio = (event: VideoReadyForDisplayEvent | VideoLoadedEventType | undefined) => { - if (!event) { - return; - } - - if ('naturalSize' in event) { - setVideoAspectRatio(event.naturalSize.width / event.naturalSize.height); - } else { - setVideoAspectRatio(event.srcElement.videoWidth / event.srcElement.videoHeight); - } - }; - - const setVideoStatus = useCallback((event: VideoPlaybackStatusEventType) => { - setIsVideoLoaded(event.isLoaded); - }, []); - - const getWelcomeVideo = () => { - const aspectRatio = videoAspectRatio || VIDEO_ASPECT_RATIO; - - return ( - - {welcomeVideoStatus === 'video' ? ( - - ) : ( - - - - )} - - ); }; return ( - - {({safeAreaPaddingBottomStyle}) => ( - - - {getWelcomeVideo()} - - - {translate('onboarding.welcomeVideo.title')} - {translate('onboarding.welcomeVideo.description')} - -