From 3c22583af87c06f73f40836a45d6aa6c059db62b Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 3 Oct 2023 19:38:12 -0400 Subject: [PATCH 1/2] OnboardingState=DONE if done; null if undetermined We had this issue (https://github.com/e-mission/e-mission-docs/issues/999) where if the app was exited in the middle of onboarding, and then opened again, this error would show. I found out that this occured because the LabelTab was being rendered for a split second until the onboarding state was still being resolved. It takes some time to determine the onboarding state, and it requires waiting for native calls, which is why `getPendingOnboardingState` in onboardingHelper returns a Promise. But until this promise is resolved, we don't really know if we should show a) onboarding flow or b) the main app with tab navigation. We had been keeping `pendingOnboardingState` as `null` if the onboarding was finished. In this case, there was no 'pending' onboarding state and we would just continue to the main app. But a safer thing to do here is have onboarding state be null **only** if it hasn't been determined yet. If it *has* been determined, then we will explictly mark it with a route of DONE. So if it's DONE we show the main app, if it's something other than DONE, we show the onboarding flow, and if it's null, we can show a big loading spinner while we determine what state we are in. In doing this, we no longer just keep track of *pending* onboarding states - we must always keep track of an onboarding state, whether it is DONE or not. So while making this adjustment, I renamed the variable throughout as simply 'onboardingState'. --- www/js/App.tsx | 58 ++++++++++++++++----------- www/js/onboarding/OnboardingStack.tsx | 16 ++++---- www/js/onboarding/SaveQrPage.tsx | 10 ++--- www/js/onboarding/onboardingHelper.ts | 11 ++--- 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/www/js/App.tsx b/www/js/App.tsx index 1ace61531..628baf21b 100644 --- a/www/js/App.tsx +++ b/www/js/App.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState, createContext, useMemo } from 'react'; import { getAngularService } from './angular-react-helper'; -import { BottomNavigation, Button, useTheme } from 'react-native-paper'; +import { ActivityIndicator, BottomNavigation, useTheme } from 'react-native-paper'; import { useTranslation } from 'react-i18next'; import LabelTab from './diary/LabelTab'; import MetricsTab from './metrics/MetricsTab'; @@ -22,7 +22,8 @@ export const AppContext = createContext({}); const App = () => { const [index, setIndex] = useState(0); - const [pendingOnboardingState, setPendingOnboardingState] = useState(null); + // will remain null while the onboarding state is still being determined + const [onboardingState, setOnboardingState] = useState(null); const [permissionsPopupVis, setPermissionsPopupVis] = useState(false); const appConfig = useAppConfig(); const { colors } = useTheme(); @@ -41,7 +42,7 @@ const App = () => { control: ProfileSettings, }); - const refreshOnboardingState = () => getPendingOnboardingState().then(setPendingOnboardingState); + const refreshOnboardingState = () => getPendingOnboardingState().then(setOnboardingState); useEffect(() => { refreshOnboardingState() }, []); useEffect(() => { @@ -53,32 +54,43 @@ const App = () => { const appContextValue = { appConfig, - pendingOnboardingState, setPendingOnboardingState, refreshOnboardingState, + onboardingState, setOnboardingState, refreshOnboardingState, permissionsPopupVis, setPermissionsPopupVis, } - console.debug('pendingOnboardingState in App', pendingOnboardingState); + console.debug('onboardingState in App', onboardingState); + + let appContent; + if (onboardingState == null) { + // if onboarding state is not yet determined, show a loading spinner + appContent = + } else if (onboardingState?.route == OnboardingRoute.DONE) { + // if onboarding route is DONE, show the main app with navigation between tabs + appContent = ( + + ); + } else { + // if there is an onboarding route that is not DONE, show the onboarding stack + appContent = + } return (<> - {pendingOnboardingState == null ? - - : - - } - { /* if onboarding is done (state == null), or if is in progress but we are past the - consent page (route > CONSENT), the permissions popup can show if needed */ } - {(pendingOnboardingState == null || pendingOnboardingState.route > OnboardingRoute.CONSENT) && + {appContent} + + { /* If we are past the consent page (route > CONSENT), the permissions popup can show if needed. + This also includes if onboarding is DONE altogether (because "DONE" is > "CONSENT") */ } + {(onboardingState && onboardingState.route > OnboardingRoute.CONSENT) && } diff --git a/www/js/onboarding/OnboardingStack.tsx b/www/js/onboarding/OnboardingStack.tsx index 643744ed3..a49bde3ab 100644 --- a/www/js/onboarding/OnboardingStack.tsx +++ b/www/js/onboarding/OnboardingStack.tsx @@ -11,22 +11,22 @@ import { displayErrorMsg } from "../plugin/logger"; const OnboardingStack = () => { - const { pendingOnboardingState } = useContext(AppContext); + const { onboardingState } = useContext(AppContext); - console.debug('pendingOnboardingState in OnboardingStack', pendingOnboardingState); + console.debug('onboardingState in OnboardingStack', onboardingState); - if (pendingOnboardingState.route == OnboardingRoute.WELCOME) { + if (onboardingState.route == OnboardingRoute.WELCOME) { return ; - } else if (pendingOnboardingState.route == OnboardingRoute.SUMMARY) { + } else if (onboardingState.route == OnboardingRoute.SUMMARY) { return ; - } else if (pendingOnboardingState.route == OnboardingRoute.CONSENT) { + } else if (onboardingState.route == OnboardingRoute.CONSENT) { return ; - } else if (pendingOnboardingState.route == OnboardingRoute.SAVE_QR) { + } else if (onboardingState.route == OnboardingRoute.SAVE_QR) { return ; - } else if (pendingOnboardingState.route == OnboardingRoute.SURVEY) { + } else if (onboardingState.route == OnboardingRoute.SURVEY) { return ; } else { - displayErrorMsg('OnboardingStack: unknown route', pendingOnboardingState.route); + displayErrorMsg('OnboardingStack: unknown route', onboardingState.route); } } diff --git a/www/js/onboarding/SaveQrPage.tsx b/www/js/onboarding/SaveQrPage.tsx index 157ff4093..8a3fab92e 100644 --- a/www/js/onboarding/SaveQrPage.tsx +++ b/www/js/onboarding/SaveQrPage.tsx @@ -14,13 +14,13 @@ import { preloadDemoSurveyResponse } from "./SurveyPage"; const SaveQrPage = ({ }) => { const { t } = useTranslation(); - const { pendingOnboardingState, refreshOnboardingState } = useContext(AppContext); + const { onboardingState, refreshOnboardingState } = useContext(AppContext); const { overallStatus } = usePermissionStatus(); useEffect(() => { if (overallStatus == true && !registerUserDone) { logDebug('permissions done, going to log in'); - login(pendingOnboardingState.opcode).then((response) => { + login(onboardingState.opcode).then((response) => { logDebug('login done, refreshing onboarding state'); setRegisterUserDone(true); preloadDemoSurveyResponse(); @@ -63,13 +63,13 @@ const SaveQrPage = ({ }) => { - + - {pendingOnboardingState.opcode} + {onboardingState.opcode} -