From c9e86eacb2d3fe26d3224930746d725c812f0a60 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 5 Nov 2025 02:01:04 +0500 Subject: [PATCH 1/5] remove Onyx.connect from openReportFromDeepLink and move this function to Link.ts --- src/libs/actions/Link.ts | 191 ++++++++++++++++++++++++++++++++++++- src/libs/actions/Report.ts | 184 +---------------------------------- 2 files changed, 191 insertions(+), 184 deletions(-) diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index 477cf71bab6d7..921d0dbaeaf6b 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -1,25 +1,45 @@ +import {findFocusedRoute} from '@react-navigation/native'; +import {InteractionManager} from 'react-native'; import Onyx from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import * as API from '@libs/API'; import type {GenerateSpotnanaTokenParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types'; import asyncOpenURL from '@libs/asyncOpenURL'; import * as Environment from '@libs/Environment/Environment'; +import isPublicScreenRoute from '@libs/isPublicScreenRoute'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName'; +import normalizePath from '@libs/Navigation/helpers/normalizePath'; +import shouldOpenOnAdminRoom from '@libs/Navigation/helpers/shouldOpenOnAdminRoom'; import Navigation from '@libs/Navigation/Navigation'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {NetworkStatus} from '@libs/NetworkConnection'; +import {findLastAccessedReport, getReportIDFromLink, getRouteFromLink} from '@libs/ReportUtils'; +import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import * as Url from '@libs/Url'; import addTrailingForwardSlash from '@libs/UrlUtils'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn} from './Session'; +import type {Account} from '@src/types/onyx'; +import type {Report} from '@src/types/onyx'; +import {doneCheckingPublicRoom, navigateToConciergeChat, openReport} from './Report'; +import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn, waitForUserSignIn} from './Session'; +import {isOnboardingFlowCompleted, setOnboardingErrorMessage} from './Welcome'; +import {OnboardingCompanySize, OnboardingPurpose, startOnboardingFlow} from './Welcome/OnboardingFlow'; let isNetworkOffline = false; -// Use connectWithoutView since this is to open an external link and doesn't affect any UI +let networkStatus: NetworkStatus; + Onyx.connectWithoutView({ key: ONYXKEYS.NETWORK, - callback: (value) => (isNetworkOffline = value?.isOffline ?? false), + callback: (value) => { + isNetworkOffline = value?.isOffline ?? false; + networkStatus = value?.networkStatus ?? CONST.NETWORK.NETWORK_STATUS.UNKNOWN; + }, }); let currentUserEmail = ''; @@ -33,6 +53,14 @@ Onyx.connectWithoutView({ }, }); +let account: OnyxEntry; +Onyx.connectWithoutView({ + key: ONYXKEYS.ACCOUNT, + callback: (value) => { + account = value; + }, +}); + function buildOldDotURL(url: string, shortLivedAuthToken?: string): Promise { const hashIndex = url.lastIndexOf('#'); const hasHashParams = hashIndex !== -1; @@ -196,6 +224,160 @@ function openLink(href: string, environmentURL: string, isAttachment = false) { openExternalLink(href); } +function openReportFromDeepLink( + url: string, + currentOnboardingPurposeSelected: OnyxEntry, + currentOnboardingCompanySize: OnyxEntry, + onboardingInitialPath: OnyxEntry, + reports: OnyxCollection, + isAuthenticated: boolean, +) { + const reportID = getReportIDFromLink(url); + + if (reportID && !isAuthenticated) { + // Call the OpenReport command to check in the server if it's a public room. If so, we'll open it as an anonymous user + openReport(reportID, '', [], undefined, '0', true); + + // Show the sign-in page if the app is offline + if (networkStatus === CONST.NETWORK.NETWORK_STATUS.OFFLINE) { + doneCheckingPublicRoom(); + } + } else { + // If we're not opening a public room (no reportID) or the user is authenticated, we unblock the UI (hide splash screen) + doneCheckingPublicRoom(); + } + + let route = getRouteFromLink(url); + + // Bing search results still link to /signin when searching for “Expensify”, but the /signin route no longer exists in our repo, so we redirect it to the home page to avoid showing a Not Found page. + if (normalizePath(route) === CONST.SIGNIN_ROUTE) { + route = ''; + } + + // If we are not authenticated and are navigating to a public screen, we don't want to navigate again to the screen after sign-in/sign-up + if (!isAuthenticated && isPublicScreenRoute(route)) { + return; + } + + // If the route is the transition route, we don't want to navigate and start the onboarding flow + if (route?.includes(ROUTES.TRANSITION_BETWEEN_APPS)) { + return; + } + + // Navigate to the report after sign-in/sign-up. + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(() => { + waitForUserSignIn().then(() => { + const connection = Onyx.connectWithoutView({ + key: ONYXKEYS.NVP_ONBOARDING, + callback: (val) => { + if (!val && !isAnonymousUser()) { + return; + } + + Navigation.waitForProtectedRoutes().then(() => { + if (route && isAnonymousUser() && !canAnonymousUserAccessRoute(route)) { + signOutAndRedirectToSignIn(true); + return; + } + + // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, + // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, + // which is already called when AuthScreens mounts. + if (!CONFIG.IS_HYBRID_APP && url && new URL(url).searchParams.get('exitTo') === ROUTES.WORKSPACE_NEW) { + return; + } + + const handleDeeplinkNavigation = () => { + // We want to disconnect the connection so it won't trigger the deeplink again + // every time the data is changed, for example, when re-login. + Onyx.disconnect(connection); + + const state = navigationRef.getRootState(); + const currentFocusedRoute = findFocusedRoute(state); + + if (isOnboardingFlowName(currentFocusedRoute?.name)) { + setOnboardingErrorMessage('onboarding.purpose.errorBackButton'); + return; + } + + if (shouldSkipDeepLinkNavigation(route)) { + return; + } + + // Navigation for signed users is handled by react-navigation. + if (isAuthenticated) { + return; + } + + const navigateHandler = (reportParam?: OnyxEntry) => { + // Check if the report exists in the collection + const report = reportParam ?? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + // If the report does not exist, navigate to the last accessed report or Concierge chat + if (reportID && (!report?.reportID || report.errorFields?.notFound)) { + const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID; + if (lastAccessedReportID) { + const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID); + Navigation.navigate(lastAccessedReportRoute); + return; + } + navigateToConciergeChat(false, () => true); + return; + } + + // If the last route is an RHP, we want to replace it so it won't be covered by the full-screen navigator. + const forceReplace = navigationRef.getRootState().routes.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; + Navigation.navigate(route as Route, {forceReplace}); + }; + // If we log with deeplink with reportID and data for this report is not available yet, + // then we will wait for Onyx to completely merge data from OpenReport API with OpenApp API in AuthScreens + if ( + reportID && + !isAuthenticated && + (!reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || !reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) + ) { + const reportConnection = Onyx.connectWithoutView({ + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + // eslint-disable-next-line rulesdir/prefer-early-return + callback: (report) => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (report?.errorFields?.notFound || report?.reportID) { + Onyx.disconnect(reportConnection); + navigateHandler(report); + } + }, + }); + } else { + navigateHandler(); + } + }; + + if (isAnonymousUser()) { + handleDeeplinkNavigation(); + return; + } + // We need skip deeplinking if the user hasn't completed the guided setup flow. + isOnboardingFlowCompleted({ + onNotCompleted: () => + startOnboardingFlow({ + onboardingValuesParam: val, + hasAccessiblePolicies: !!account?.hasAccessibleDomainPolicies, + isUserFromPublicDomain: !!account?.isFromPublicDomain, + currentOnboardingPurposeSelected, + currentOnboardingCompanySize, + onboardingInitialPath, + onboardingValues: val, + }), + onCompleted: handleDeeplinkNavigation, + onCanceled: handleDeeplinkNavigation, + }); + }); + }, + }); + }); + }); +} + function buildURLWithAuthToken(url: string, shortLivedAuthToken?: string) { const authTokenParam = shortLivedAuthToken ? `shortLivedAuthToken=${shortLivedAuthToken}` : ''; const emailParam = `email=${encodeURIComponent(currentUserEmail)}`; @@ -251,4 +433,5 @@ export { openExternalLinkWithToken, getTravelDotLink, buildOldDotURL, + openReportFromDeepLink, }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6eda7a55e80af..b8ec82b4f8932 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1,4 +1,3 @@ -import {findFocusedRoute} from '@react-navigation/native'; import {format as timezoneFormat, toZonedTime} from 'date-fns-tz'; import {Str} from 'expensify-common'; import isEmpty from 'lodash/isEmpty'; @@ -72,17 +71,12 @@ import type EnvironmentType from '@libs/Environment/getEnvironment/types'; import {getMicroSecondOnyxErrorWithTranslationKey, getMicroSecondTranslationErrorWithTranslationKey} from '@libs/ErrorUtils'; import fileDownload from '@libs/fileDownload'; import HttpUtils from '@libs/HttpUtils'; -import isPublicScreenRoute from '@libs/isPublicScreenRoute'; import Log from '@libs/Log'; import {isEmailPublicDomain} from '@libs/LoginUtils'; import {getMovedReportID} from '@libs/ModifiedExpenseMessage'; -import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName'; import type {LinkToOptions} from '@libs/Navigation/helpers/linkTo/types'; -import normalizePath from '@libs/Navigation/helpers/normalizePath'; -import shouldOpenOnAdminRoom from '@libs/Navigation/helpers/shouldOpenOnAdminRoom'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import Navigation from '@libs/Navigation/Navigation'; import enhanceParameters from '@libs/Network/enhanceParameters'; -import type {NetworkStatus} from '@libs/NetworkConnection'; import NetworkConnection from '@libs/NetworkConnection'; import {buildNextStepNew} from '@libs/NextStepUtils'; import LocalNotification from '@libs/Notification/LocalNotification'; @@ -137,7 +131,6 @@ import { getPolicyExpenseChat, getReportFieldKey, getReportFieldsByPolicyID, - getReportIDFromLink, getReportLastMessage, getReportLastVisibleActionCreated, getReportMetadata, @@ -146,7 +139,6 @@ import { getReportPreviewMessage, getReportTransactions, getReportViolations, - getRouteFromLink, getTitleReportField, hasOutstandingChildRequest, isChatThread as isChatThreadReportUtils, @@ -168,7 +160,6 @@ import { } from '@libs/ReportUtils'; import {getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; import type {ArchivedReportsIDSet} from '@libs/SearchUIUtils'; -import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import playSound, {SOUNDS} from '@libs/Sound'; import {isOnHold} from '@libs/TransactionUtils'; import addTrailingForwardSlash from '@libs/UrlUtils'; @@ -176,9 +167,7 @@ import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; import type {OnboardingAccounting} from '@src/CONST'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { @@ -224,9 +213,9 @@ import { resolveEditCommentWithNewAddCommentRequest, resolveOpenReportDuplicationConflictAction, } from './RequestConflictUtils'; -import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn, waitForUserSignIn} from './Session'; -import {isOnboardingFlowCompleted, onServerDataReady, setOnboardingErrorMessage} from './Welcome'; -import {getOnboardingMessages, startOnboardingFlow} from './Welcome/OnboardingFlow'; +import {isAnonymousUser} from './Session'; +import {onServerDataReady} from './Welcome'; +import {getOnboardingMessages} from './Welcome/OnboardingFlow'; import type {OnboardingCompanySize, OnboardingMessage} from './Welcome/OnboardingFlow'; type SubscriberCallback = (isFromCurrentUser: boolean, reportAction: ReportAction | undefined) => void; @@ -336,12 +325,10 @@ Onyx.connect({ }); let isNetworkOffline = false; -let networkStatus: NetworkStatus; Onyx.connect({ key: ONYXKEYS.NETWORK, callback: (value) => { isNetworkOffline = value?.isOffline ?? false; - networkStatus = value?.networkStatus ?? CONST.NETWORK.NETWORK_STATUS.UNKNOWN; }, }); @@ -353,14 +340,6 @@ Onyx.connect({ }, }); -let account: OnyxEntry = {}; -Onyx.connect({ - key: ONYXKEYS.ACCOUNT, - callback: (value) => { - account = value ?? {}; - }, -}); - const draftNoteMap: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT, @@ -3501,160 +3480,6 @@ function doneCheckingPublicRoom() { Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); } -function openReportFromDeepLink( - url: string, - currentOnboardingPurposeSelected: OnyxEntry, - currentOnboardingCompanySize: OnyxEntry, - onboardingInitialPath: OnyxEntry, - reports: OnyxCollection, - isAuthenticated: boolean, -) { - const reportID = getReportIDFromLink(url); - - if (reportID && !isAuthenticated) { - // Call the OpenReport command to check in the server if it's a public room. If so, we'll open it as an anonymous user - openReport(reportID, '', [], undefined, '0', true); - - // Show the sign-in page if the app is offline - if (networkStatus === CONST.NETWORK.NETWORK_STATUS.OFFLINE) { - doneCheckingPublicRoom(); - } - } else { - // If we're not opening a public room (no reportID) or the user is authenticated, we unblock the UI (hide splash screen) - doneCheckingPublicRoom(); - } - - let route = getRouteFromLink(url); - - // Bing search results still link to /signin when searching for “Expensify”, but the /signin route no longer exists in our repo, so we redirect it to the home page to avoid showing a Not Found page. - if (normalizePath(route) === CONST.SIGNIN_ROUTE) { - route = ''; - } - - // If we are not authenticated and are navigating to a public screen, we don't want to navigate again to the screen after sign-in/sign-up - if (!isAuthenticated && isPublicScreenRoute(route)) { - return; - } - - // If the route is the transition route, we don't want to navigate and start the onboarding flow - if (route?.includes(ROUTES.TRANSITION_BETWEEN_APPS)) { - return; - } - - // Navigate to the report after sign-in/sign-up. - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - waitForUserSignIn().then(() => { - const connection = Onyx.connect({ - key: ONYXKEYS.NVP_ONBOARDING, - callback: (val) => { - if (!val && !isAnonymousUser()) { - return; - } - - Navigation.waitForProtectedRoutes().then(() => { - if (route && isAnonymousUser() && !canAnonymousUserAccessRoute(route)) { - signOutAndRedirectToSignIn(true); - return; - } - - // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, - // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, - // which is already called when AuthScreens mounts. - if (!CONFIG.IS_HYBRID_APP && url && new URL(url).searchParams.get('exitTo') === ROUTES.WORKSPACE_NEW) { - return; - } - - const handleDeeplinkNavigation = () => { - // We want to disconnect the connection so it won't trigger the deeplink again - // every time the data is changed, for example, when re-login. - Onyx.disconnect(connection); - - const state = navigationRef.getRootState(); - const currentFocusedRoute = findFocusedRoute(state); - - if (isOnboardingFlowName(currentFocusedRoute?.name)) { - setOnboardingErrorMessage('onboarding.purpose.errorBackButton'); - return; - } - - if (shouldSkipDeepLinkNavigation(route)) { - return; - } - - // Navigation for signed users is handled by react-navigation. - if (isAuthenticated) { - return; - } - - const navigateHandler = (reportParam?: OnyxEntry) => { - // Check if the report exists in the collection - const report = reportParam ?? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - // If the report does not exist, navigate to the last accessed report or Concierge chat - if (reportID && (!report?.reportID || report.errorFields?.notFound)) { - const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID; - if (lastAccessedReportID) { - const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID); - Navigation.navigate(lastAccessedReportRoute); - return; - } - navigateToConciergeChat(false, () => true); - return; - } - - // If the last route is an RHP, we want to replace it so it won't be covered by the full-screen navigator. - const forceReplace = navigationRef.getRootState().routes.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; - Navigation.navigate(route as Route, {forceReplace}); - }; - // If we log with deeplink with reportID and data for this report is not available yet, - // then we will wait for Onyx to completely merge data from OpenReport API with OpenApp API in AuthScreens - if ( - reportID && - !isAuthenticated && - (!reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || !reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) - ) { - const reportConnection = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - // eslint-disable-next-line rulesdir/prefer-early-return - callback: (report) => { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (report?.errorFields?.notFound || report?.reportID) { - Onyx.disconnect(reportConnection); - navigateHandler(report); - } - }, - }); - } else { - navigateHandler(); - } - }; - - if (isAnonymousUser()) { - handleDeeplinkNavigation(); - return; - } - // We need skip deeplinking if the user hasn't completed the guided setup flow. - isOnboardingFlowCompleted({ - onNotCompleted: () => - startOnboardingFlow({ - onboardingValuesParam: val, - hasAccessiblePolicies: !!account?.hasAccessibleDomainPolicies, - isUserFromPublicDomain: !!account?.isFromPublicDomain, - currentOnboardingPurposeSelected, - currentOnboardingCompanySize, - onboardingInitialPath, - onboardingValues: val, - }), - onCompleted: handleDeeplinkNavigation, - onCanceled: handleDeeplinkNavigation, - }); - }); - }, - }); - }); - }); -} - function getCurrentUserAccountID(): number { return currentUserAccountID; } @@ -6215,7 +6040,6 @@ export { clearCreateChatError, notifyNewAction, openReport, - openReportFromDeepLink, openRoomMembersPage, readNewestAction, markAllMessagesAsRead, From fa1d764be0aab7b49758b48fc017b570be01e6b2 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 5 Nov 2025 02:02:45 +0500 Subject: [PATCH 2/5] chore: update import path for openReportFromDeepLink --- src/Expensify.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 65227bac9d888..985053d32dc53 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -6,6 +6,7 @@ import type {NativeEventSubscription} from 'react-native'; import {AppState, Linking, Platform} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; +import {openReportFromDeepLink} from '@libs/actions/Link'; import ConfirmModal from './components/ConfirmModal'; import DeeplinkWrapper from './components/DeeplinkWrapper'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; @@ -241,7 +242,7 @@ function Expensify() { Linking.getInitialURL().then((url) => { setInitialUrl(url as Route); if (url) { - Report.openReportFromDeepLink(url, currentOnboardingPurposeSelected, currentOnboardingCompanySize, onboardingInitialPath, allReports, isAuthenticated); + openReportFromDeepLink(url, currentOnboardingPurposeSelected, currentOnboardingCompanySize, onboardingInitialPath, allReports, isAuthenticated); } else { Report.doneCheckingPublicRoom(); } @@ -250,7 +251,7 @@ function Expensify() { // Open chat report from a deep link (only mobile native) linkingChangeListener.current = Linking.addEventListener('url', (state) => { const isCurrentlyAuthenticated = hasAuthToken(); - Report.openReportFromDeepLink(state.url, currentOnboardingPurposeSelected, currentOnboardingCompanySize, onboardingInitialPath, allReports, isCurrentlyAuthenticated); + openReportFromDeepLink(state.url, currentOnboardingPurposeSelected, currentOnboardingCompanySize, onboardingInitialPath, allReports, isCurrentlyAuthenticated); }); if (CONFIG.IS_HYBRID_APP) { HybridAppModule.onURLListenerAdded(); From 1eb8b86d8b715fef309c5c194a1337353c2c2b90 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 5 Nov 2025 03:03:21 +0500 Subject: [PATCH 3/5] update max-warnings to 128 and fix lint --- package.json | 2 +- src/libs/actions/Link.ts | 6 +++--- src/libs/actions/Report.ts | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index beee1aea9991f..f884a4a362d6f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "test:debug": "TZ=utc NODE_OPTIONS='--inspect-brk --experimental-vm-modules' jest --runInBand", "perf-test": "NODE_OPTIONS=--experimental-vm-modules npx reassure", "typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc", - "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=131 --cache --cache-location=node_modules/.cache/eslint", + "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=128 --cache --cache-location=node_modules/.cache/eslint", "lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 ./scripts/lintChanged.sh", "lint-watch": "npx eslint-watch --watch --changed", "shellcheck": "./scripts/shellCheck.sh", diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index 921d0dbaeaf6b..ba9bb5d505555 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -24,12 +24,12 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type {Account} from '@src/types/onyx'; -import type {Report} from '@src/types/onyx'; +import type {Account, Report} from '@src/types/onyx'; import {doneCheckingPublicRoom, navigateToConciergeChat, openReport} from './Report'; import {canAnonymousUserAccessRoute, isAnonymousUser, signOutAndRedirectToSignIn, waitForUserSignIn} from './Session'; import {isOnboardingFlowCompleted, setOnboardingErrorMessage} from './Welcome'; -import {OnboardingCompanySize, OnboardingPurpose, startOnboardingFlow} from './Welcome/OnboardingFlow'; +import {startOnboardingFlow} from './Welcome/OnboardingFlow'; +import type {OnboardingCompanySize, OnboardingPurpose} from './Welcome/OnboardingFlow'; let isNetworkOffline = false; let networkStatus: NetworkStatus; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b8ec82b4f8932..0e6ecc2afcc10 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -171,7 +171,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { - Account, IntroSelected, InvitedEmailsToAccountIDs, NewGroupChatDraft, From 9c6cb9008a15a6026cae2fb882aad0e36f309e4c Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 5 Nov 2025 11:50:33 +0500 Subject: [PATCH 4/5] add comments for connectWithoutView usage --- src/libs/actions/Link.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index ba9bb5d505555..f94d07337edb2 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -33,7 +33,7 @@ import type {OnboardingCompanySize, OnboardingPurpose} from './Welcome/Onboardin let isNetworkOffline = false; let networkStatus: NetworkStatus; - +// Use connectWithoutView since this is to open an external link and doesn't affect any UI Onyx.connectWithoutView({ key: ONYXKEYS.NETWORK, callback: (value) => { @@ -54,6 +54,7 @@ Onyx.connectWithoutView({ }); let account: OnyxEntry; +// Use connectWithoutView to subscribe to account data without affecting UI Onyx.connectWithoutView({ key: ONYXKEYS.ACCOUNT, callback: (value) => { @@ -268,6 +269,7 @@ function openReportFromDeepLink( // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { waitForUserSignIn().then(() => { + // Subscribe to onboarding data using connectWithoutView to determine if user has completed the onboarding flow without affecting UI const connection = Onyx.connectWithoutView({ key: ONYXKEYS.NVP_ONBOARDING, callback: (val) => { From 1c7a794e87c574fa35818f0c095248790cb6fd00 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 6 Nov 2025 01:39:12 +0500 Subject: [PATCH 5/5] fix: replace alias import with relative path for openReportFromDeepLink --- src/Expensify.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 985053d32dc53..6b04ead6ca617 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -6,7 +6,6 @@ import type {NativeEventSubscription} from 'react-native'; import {AppState, Linking, Platform} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import {openReportFromDeepLink} from '@libs/actions/Link'; import ConfirmModal from './components/ConfirmModal'; import DeeplinkWrapper from './components/DeeplinkWrapper'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; @@ -25,6 +24,7 @@ import usePriorityMode from './hooks/usePriorityChange'; import {updateLastRoute} from './libs/actions/App'; import {disconnect} from './libs/actions/Delegate'; import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; +import {openReportFromDeepLink} from './libs/actions/Link'; import * as Report from './libs/actions/Report'; import {hasAuthToken} from './libs/actions/Session'; import * as User from './libs/actions/User';