Skip to content

Commit f61ab52

Browse files
authored
Merge pull request Expensify#64216 from dmkt9/fix/61696
Fix - User is not redirected to IOU report when logging in after deeplink
2 parents ac0e804 + 6848717 commit f61ab52

4 files changed

Lines changed: 52 additions & 15 deletions

File tree

src/Expensify.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {NativeEventSubscription} from 'react-native';
55
import {AppState, Linking, Platform} from 'react-native';
66
import type {OnyxEntry} from 'react-native-onyx';
77
import Onyx from 'react-native-onyx';
8+
import {InitialURLContext} from '@components/InitialURLContextProvider';
89
import ConfirmModal from './components/ConfirmModal';
910
import DeeplinkWrapper from './components/DeeplinkWrapper';
1011
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
@@ -110,7 +111,7 @@ function Expensify() {
110111
usePriorityMode();
111112

112113
const [initialUrl, setInitialUrl] = useState<Route | null>(null);
113-
114+
const {setIsAuthenticatedAtStartup} = useContext(InitialURLContext);
114115
useEffect(() => {
115116
if (isCheckingPublicRoom) {
116117
return;
@@ -206,6 +207,7 @@ function Expensify() {
206207

207208
appStateChangeListener.current = AppState.addEventListener('change', initializeClient);
208209

210+
setIsAuthenticatedAtStartup(isAuthenticated);
209211
// If the app is opened from a deep link, get the reportID (if exists) from the deep link and navigate to the chat report
210212
Linking.getInitialURL().then((url) => {
211213
setInitialUrl(url as Route);

src/components/InitialURLContextProvider.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import type {Route} from '@src/ROUTES';
66
type InitialUrlContextType = {
77
initialURL: Route | null;
88
setInitialURL: React.Dispatch<React.SetStateAction<Route | null>>;
9+
isAuthenticatedAtStartup: boolean;
10+
setIsAuthenticatedAtStartup: React.Dispatch<React.SetStateAction<boolean>>;
911
};
1012

1113
/** Initial url that will be opened when NewDot is embedded into Hybrid App. */
1214
const InitialURLContext = createContext<InitialUrlContextType>({
1315
initialURL: null,
1416
setInitialURL: () => {},
17+
isAuthenticatedAtStartup: false,
18+
setIsAuthenticatedAtStartup: () => {},
1519
});
1620

1721
type InitialURLContextProviderProps = {
@@ -21,6 +25,7 @@ type InitialURLContextProviderProps = {
2125

2226
function InitialURLContextProvider({children}: InitialURLContextProviderProps) {
2327
const [initialURL, setInitialURL] = useState<Route | null>(null);
28+
const [isAuthenticatedAtStartup, setIsAuthenticatedAtStartup] = useState<boolean>(false);
2429

2530
useEffect(() => {
2631
Linking.getInitialURL().then((initURL) => {
@@ -35,8 +40,10 @@ function InitialURLContextProvider({children}: InitialURLContextProviderProps) {
3540
() => ({
3641
initialURL,
3742
setInitialURL,
43+
isAuthenticatedAtStartup,
44+
setIsAuthenticatedAtStartup,
3845
}),
39-
[initialURL],
46+
[initialURL, isAuthenticatedAtStartup],
4047
);
4148

4249
return <InitialURLContext.Provider value={initialUrlContext}>{children}</InitialURLContext.Provider>;

src/libs/Navigation/AppNavigator/AuthScreens.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import type {RouteProp} from '@react-navigation/native';
22
import {useNavigation} from '@react-navigation/native';
3-
import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
3+
import React, {memo, useContext, useEffect, useMemo, useRef, useState} from 'react';
44
import type {OnyxEntry} from 'react-native-onyx';
55
import Onyx, {withOnyx} from 'react-native-onyx';
66
import ComposeProviders from '@components/ComposeProviders';
77
import DelegateNoAccessModalProvider from '@components/DelegateNoAccessModalProvider';
88
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
9+
import {InitialURLContext} from '@components/InitialURLContextProvider';
910
import LockedAccountModalProvider from '@components/LockedAccountModalProvider';
1011
import OptionsListContextProvider from '@components/OptionListContextProvider';
1112
import PriorityModeController from '@components/PriorityModeController';
@@ -38,6 +39,7 @@ import NetworkConnection from '@libs/NetworkConnection';
3839
import onyxSubscribe from '@libs/onyxSubscribe';
3940
import Pusher from '@libs/Pusher';
4041
import PusherConnectionManager from '@libs/PusherConnectionManager';
42+
import {getReportIDFromLink} from '@libs/ReportUtils';
4143
import * as SessionUtils from '@libs/SessionUtils';
4244
import {getSearchParamFromUrl} from '@libs/Url';
4345
import ConnectionCompletePage from '@pages/ConnectionCompletePage';
@@ -242,6 +244,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
242244
const prevIsOnboardingLoading = usePrevious(isOnboardingLoading);
243245
const [shouldShowRequire2FAPage, setShouldShowRequire2FAPage] = useState(!!account?.needsTwoFactorAuthSetup && !account.requiresTwoFactorAuth);
244246
const navigation = useNavigation();
247+
const {initialURL, isAuthenticatedAtStartup, setIsAuthenticatedAtStartup} = useContext(InitialURLContext);
245248

246249
// State to track whether the delegator's authentication is completed before displaying data
247250
const [isDelegatorFromOldDotIsReady, setIsDelegatorFromOldDotIsReady] = useState(false);
@@ -322,6 +325,12 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
322325
setIsDelegatorFromOldDotIsReady(true);
323326
});
324327
} else {
328+
const reportID = getReportIDFromLink(initialURL ?? null);
329+
if (reportID && !isAuthenticatedAtStartup) {
330+
Report.openReport(reportID);
331+
// Don't want to call `openReport` again when logging out and then logging in
332+
setIsAuthenticatedAtStartup(true);
333+
}
325334
App.openApp();
326335
}
327336
} else {

src/libs/actions/Report.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3434,21 +3434,40 @@ function openReportFromDeepLink(
34343434
return;
34353435
}
34363436

3437-
// Check if the report exists in the collection
3438-
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
3439-
// If the report does not exist, navigate to the last accessed report or Concierge chat
3440-
if (reportID && !report) {
3441-
const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID;
3442-
if (lastAccessedReportID) {
3443-
const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID);
3444-
Navigation.navigate(lastAccessedReportRoute);
3437+
const navigateHandler = (reportParam?: OnyxEntry<Report>) => {
3438+
// Check if the report exists in the collection
3439+
const report = reportParam ?? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
3440+
// If the report does not exist, navigate to the last accessed report or Concierge chat
3441+
if (reportID && (!report?.reportID || report.errorFields?.notFound)) {
3442+
const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID;
3443+
if (lastAccessedReportID) {
3444+
const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID);
3445+
Navigation.navigate(lastAccessedReportRoute);
3446+
return;
3447+
}
3448+
navigateToConciergeChat(false, () => true);
34453449
return;
34463450
}
3447-
navigateToConciergeChat(false, () => true);
3448-
return;
3449-
}
34503451

3451-
Navigation.navigate(route as Route);
3452+
Navigation.navigate(route as Route);
3453+
};
3454+
// If we log with deeplink with reportID and data for this report is not available yet,
3455+
// then we will wait for Onyx to completely merge data from OpenReport API with OpenApp API in AuthScreens
3456+
if (reportID && !isAuthenticated && !allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]) {
3457+
const reportConnection = Onyx.connect({
3458+
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
3459+
// eslint-disable-next-line rulesdir/prefer-early-return
3460+
callback: (report) => {
3461+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
3462+
if (report?.errorFields?.notFound || report?.reportID) {
3463+
Onyx.disconnect(reportConnection);
3464+
navigateHandler(report);
3465+
}
3466+
},
3467+
});
3468+
} else {
3469+
navigateHandler();
3470+
}
34523471
};
34533472

34543473
if (isAnonymousUser()) {

0 commit comments

Comments
 (0)