Skip to content

Commit

Permalink
Merge pull request Expensify#55528 from software-mansion-labs/use-ony…
Browse files Browse the repository at this point in the history
…x/auth-screens

Migrate AuthScreens to useOnyx
  • Loading branch information
deetergp authored Jan 23, 2025
2 parents fc199fa + 1a79d00 commit fd66e86
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 68 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,7 @@ const CONST = {
CLOUDFRONT_URL,
EMPTY_ARRAY,
EMPTY_OBJECT,
EMPTY_STRING: '',
DEFAULT_NUMBER_ID: 0,
USE_EXPENSIFY_URL,
EXPENSIFY_URL,
Expand Down
89 changes: 43 additions & 46 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {findFocusedRoute} from '@react-navigation/native';
import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
import {NativeModules, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {withOnyx} from 'react-native-onyx';
import Onyx, {useOnyx} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener';
import ComposeProviders from '@components/ComposeProviders';
Expand Down Expand Up @@ -60,6 +60,7 @@ import SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import beforeRemoveReportOpenedFromSearchRHP from './beforeRemoveReportOpenedFromSearchRHP';
import CENTRAL_PANE_SCREENS from './CENTRAL_PANE_SCREENS';
Expand All @@ -77,17 +78,6 @@ import RightModalNavigator from './Navigators/RightModalNavigator';
import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator';
import useRootNavigatorOptions from './useRootNavigatorOptions';

type AuthScreensProps = {
/** Session of currently logged in user */
session: OnyxEntry<OnyxTypes.Session>;

/** The report ID of the last opened public room as anonymous user */
lastOpenedPublicRoomID: OnyxEntry<string>;

/** The last Onyx update ID was applied to the client */
initialLastUpdateIDAppliedToClient: OnyxEntry<number>;
};

const loadReportAttachments = () => require<ReactComponentModule>('../../../pages/home/report/ReportAttachments').default;
const loadValidateLoginPage = () => require<ReactComponentModule>('../../../pages/ValidateLoginPage').default;
const loadLogOutPreviousUserPage = () => require<ReactComponentModule>('../../../pages/LogOutPreviousUserPage').default;
Expand Down Expand Up @@ -239,7 +229,10 @@ const modalScreenListenersWithCancelSearch = {
},
};

function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) {
function AuthScreens() {
const [session] = useOnyx(ONYXKEYS.SESSION);
const [lastOpenedPublicRoomID, lastOpenedPublicRoomIDStatus] = useOnyx(ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID);
const [initialLastUpdateIDAppliedToClient, initialLastUpdateIDAppliedToClientStatus] = useOnyx(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT);
const theme = useTheme();
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
Expand All @@ -251,6 +244,10 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie

const modal = useRef<OnyxTypes.Modal>({});
const {isOnboardingCompleted} = useOnboardingFlowRouter();
const isLastOpenedPublicRoomIDLoading = isLoadingOnyxValue(lastOpenedPublicRoomIDStatus);
const isInitialLastUpdateIDAppliedToClientLoading = isLoadingOnyxValue(initialLastUpdateIDAppliedToClientStatus);
const isLastOpenedPublicRoomIDLoadedRef = useRef(false);
const isInitialLastUpdateIDAppliedToClientLoadedRef = useRef(false);

// On HybridApp we need to prevent flickering during transition to OldDot
const shouldRenderOnboardingExclusivelyOnHybridApp = useMemo(() => {
Expand All @@ -276,6 +273,37 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
};
}, [theme]);

useEffect(() => {
if (isLastOpenedPublicRoomIDLoading || isLastOpenedPublicRoomIDLoadedRef.current) {
return;
}

isLastOpenedPublicRoomIDLoadedRef.current = true;
if (lastOpenedPublicRoomID) {
// Re-open the last opened public room if the user logged in from a public room link
Report.openLastOpenedPublicRoom(lastOpenedPublicRoomID);
}
}, [isLastOpenedPublicRoomIDLoading, lastOpenedPublicRoomID]);

useEffect(() => {
if (isInitialLastUpdateIDAppliedToClientLoading || isInitialLastUpdateIDAppliedToClientLoadedRef.current) {
return;
}

isInitialLastUpdateIDAppliedToClientLoadedRef.current = true;
// In Hybrid App we decide to call one of those method when booting ND and we don't want to duplicate calls
if (!NativeModules.HybridAppModule) {
// If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app
// or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp().
if (SessionUtils.didUserLogInDuringSession()) {
App.openApp();
} else {
Log.info('[AuthScreens] Sending ReconnectApp');
App.reconnectApp(initialLastUpdateIDAppliedToClient);
}
}
}, [initialLastUpdateIDAppliedToClient, isInitialLastUpdateIDAppliedToClientLoading]);

useEffect(() => {
const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS;
const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH;
Expand All @@ -296,28 +324,12 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
PusherConnectionManager.init();
initializePusher();

// In Hybrid App we decide to call one of those method when booting ND and we don't want to duplicate calls
if (!NativeModules.HybridAppModule) {
// If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app
// or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp().
if (SessionUtils.didUserLogInDuringSession()) {
App.openApp();
} else {
Log.info('[AuthScreens] Sending ReconnectApp');
App.reconnectApp(initialLastUpdateIDAppliedToClient);
}
}

PriorityMode.autoSwitchToFocusMode();

App.setUpPoliciesAndNavigate(session);

App.redirectThirdPartyDesktopSignIn();

if (lastOpenedPublicRoomID) {
// Re-open the last opened public room if the user logged in from a public room link
Report.openLastOpenedPublicRoom(lastOpenedPublicRoomID);
}
Download.clearDownloads();

const unsubscribeOnyxModal = onyxSubscribe({
Expand Down Expand Up @@ -643,20 +655,5 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie

AuthScreens.displayName = 'AuthScreens';

const AuthScreensMemoized = memo(AuthScreens, () => true);

// Migration to useOnyx cause re-login if logout from deeplinked report in desktop app
// Further analysis required and more details can be seen here:
// https://github.com/Expensify/App/issues/50560
// eslint-disable-next-line
export default withOnyx<AuthScreensProps, AuthScreensProps>({
session: {
key: ONYXKEYS.SESSION,
},
lastOpenedPublicRoomID: {
key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID,
},
initialLastUpdateIDAppliedToClient: {
key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
},
})(AuthScreensMemoized);
// This memo is needed because <AuthScreens> is one of the main components in the app and navigation root and is relevant for the app performance.
export default memo(AuthScreens);
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {isCentralPaneName, isOnboardingFlowName} from '@libs/NavigationUtils';
import * as Welcome from '@userActions/Welcome';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import syncBrowserHistory from './syncBrowserHistory';

Expand Down Expand Up @@ -40,13 +41,8 @@ function insertRootRoute(state: State<RootStackParamList>, routeToInsert: Naviga
}

function compareAndAdaptState(state: StackNavigationState<RootStackParamList>) {
// If the state of the last path is not defined the getPathFromState won't work correctly.
if (!state?.routes.at(-1)?.state) {
return;
}

// We need to be sure that the bottom tab state is defined.
const topmostBottomTabRoute = getTopmostBottomTabRoute(state);
const topmostBottomTabRoute = getTopmostBottomTabRoute(state) ?? {name: SCREENS.HOME};
const isNarrowLayout = getIsNarrowLayout();

// This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle.
Expand All @@ -61,7 +57,9 @@ function compareAndAdaptState(state: StackNavigationState<RootStackParamList>) {
// We will generate a template state and compare the current state with it.
// If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state.
const pathFromCurrentState = getPathFromState(state, linkingConfig.config);
const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config);
// If the state of the bottom tab has not been fully initialized, the generated path must be adjusted
const adjustedPath = pathFromCurrentState === `/${ROUTES.ROOT}` ? `/${ROUTES.REPORT}` : pathFromCurrentState;
const {adaptedState: templateState} = getAdaptedStateFromPath(adjustedPath, linkingConfig.config);

if (!templateState) {
return;
Expand Down
13 changes: 12 additions & 1 deletion src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {LinkingOptions} from '@react-navigation/native';
import type {RootStackParamList} from '@navigation/types';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ROUTES from '@src/ROUTES';
import type {Screen} from '@src/SCREENS';
Expand Down Expand Up @@ -30,7 +31,17 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route,
[SCREENS.TRANSACTION_RECEIPT]: ROUTES.TRANSACTION_RECEIPT.route,
[SCREENS.WORKSPACE_JOIN_USER]: ROUTES.WORKSPACE_JOIN_USER.route,
[SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route,
[SCREENS.REPORT]: {
path: ROUTES.REPORT_WITH_ID.route,
// If params are defined, but reportID is explicitly undefined, we will get the url /r/undefined.
// We want to avoid that situation, so we will return an empty string instead.
parse: {
reportID: (reportID: string | undefined) => reportID ?? CONST.EMPTY_STRING,
},
stringify: {
reportID: (reportID: string | undefined) => reportID ?? CONST.EMPTY_STRING,
},
},
[SCREENS.SETTINGS.PROFILE.ROOT]: {
path: ROUTES.SETTINGS_PROFILE,
exact: true,
Expand Down
18 changes: 4 additions & 14 deletions src/libs/actions/Session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {HybridAppRoute, Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import type Credentials from '@src/types/onyx/Credentials';
import type Session from '@src/types/onyx/Session';
import type {AutoAuthState} from '@src/types/onyx/Session';
Expand Down Expand Up @@ -826,20 +825,11 @@ function clearSignInData() {
}

/**
* Reset all current params of the Home route
* Reset navigation state after logout
*/
function resetHomeRouteParams() {
function resetNavigationState() {
Navigation.isNavigationReady().then(() => {
const routes = navigationRef.current?.getState()?.routes;
const homeRoute = routes?.find((route) => route.name === SCREENS.HOME);

const emptyParams: Record<string, undefined> = {};
Object.keys(homeRoute?.params ?? {}).forEach((paramKey) => {
emptyParams[paramKey] = undefined;
});

Navigation.setParams(emptyParams, homeRoute?.key ?? '');
Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false);
navigationRef.resetRoot(navigationRef.getRootState());
});
}

Expand All @@ -858,7 +848,7 @@ function cleanupSession() {
PersistedRequests.clear();
NetworkConnection.clearReconnectionCallbacks();
SessionUtils.resetDidUserLogInDuringSession();
resetHomeRouteParams();
resetNavigationState();
clearCache().then(() => {
Log.info('Cleared all cache data', true, {}, true);
});
Expand Down

0 comments on commit fd66e86

Please sign in to comment.