diff --git a/src/pages/inbox/AccountManagerBanner.tsx b/src/pages/inbox/AccountManagerBanner.tsx
index aca7344274ee..7e54ba010b42 100644
--- a/src/pages/inbox/AccountManagerBanner.tsx
+++ b/src/pages/inbox/AccountManagerBanner.tsx
@@ -6,7 +6,6 @@ import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import Navigation from '@libs/Navigation/Navigation';
-import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils';
import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils';
import {getParticipantsAccountIDsForDisplay, isConciergeChatReport} from '@libs/ReportUtils';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -23,16 +22,15 @@ function AccountManagerBanner({reportID}: AccountManagerBannerProps) {
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportID)}`);
const [accountManagerReportID] = useOnyx(ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID);
const [accountManagerReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(accountManagerReportID)}`);
- const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
+ const accountManagerAccountID = getParticipantsAccountIDsForDisplay(accountManagerReport, false, true)?.at(0) ?? -1;
+ const [participantPersonalDetail] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {
+ selector: (details) => details?.[accountManagerAccountID],
+ });
const [isBannerVisible, setIsBannerVisible] = useState(true);
if (!accountManagerReportID || !isConciergeChatReport(report) || !isBannerVisible) {
return null;
}
-
- const participants = getParticipantsAccountIDsForDisplay(accountManagerReport, false, true);
- const participantPersonalDetails = getPersonalDetailsForAccountIDs([participants?.at(0) ?? -1], personalDetails);
- const participantPersonalDetail = Object.values(participantPersonalDetails).at(0);
const displayName = getDisplayNameOrDefault(participantPersonalDetail);
const login = participantPersonalDetail?.login;
const chatWithAccountManagerText = displayName && login ? translate('common.chatWithAccountManager', `${displayName} (${login})`) : '';
diff --git a/src/pages/inbox/ReportNotFoundGuard.tsx b/src/pages/inbox/ReportNotFoundGuard.tsx
index c5ce99b3becf..861a421fb93b 100644
--- a/src/pages/inbox/ReportNotFoundGuard.tsx
+++ b/src/pages/inbox/ReportNotFoundGuard.tsx
@@ -1,6 +1,7 @@
import {useRoute} from '@react-navigation/native';
import type {ReactNode} from 'react';
import React, {useEffect} from 'react';
+import type {OnyxEntry} from 'react-native-onyx';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
@@ -15,23 +16,31 @@ import {getParentReportActionDeletionStatus} from '@libs/TransactionNavigationUt
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {isLoadingInitialReportActionsSelector} from '@src/selectors/ReportMetaData';
+import type * as OnyxTypes from '@src/types/onyx';
type ReportNotFoundGuardProps = {
children: ReactNode;
};
+/**
+ * Two-level gate: the outer guard subscribes to lightweight keys to determine
+ * whether the report clearly exists. When it does (and the report is not a
+ * transaction thread), children render directly without the cost of
+ * parentReportMetadata / useParentReportAction subscriptions.
+ *
+ * The inner gate mounts only when the "not found" path is plausible:
+ * the report is missing, the path is invalid, or the report is a transaction
+ * thread whose parent action may have been deleted.
+ */
// eslint-disable-next-line rulesdir/no-negated-variables
function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
- const styles = useThemeStyles();
const route = useRoute();
const routeParams = route.params as {reportID?: string} | undefined;
const reportIDFromRoute = getNonEmptyStringOnyxID(routeParams?.reportID);
const {isOffline} = useNetwork();
- const {shouldUseNarrowLayout} = useResponsiveLayout();
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`);
- const [parentReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.parentReportID}`);
const [userLeavingStatus = false] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${reportIDFromRoute}`);
const [isLoadingInitialReportActions = true] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {
selector: isLoadingInitialReportActionsSelector,
@@ -40,9 +49,81 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
const [deleteTransactionNavigateBackUrl] = useOnyx(ONYXKEYS.NVP_DELETE_TRANSACTION_NAVIGATE_BACK_URL);
- const parentReportAction = useParentReportAction(report);
const reportID = report?.reportID;
const isOptimisticDelete = report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED;
+ const isInvalidReportPath = !!routeParams?.reportID && !isValidReportIDFromPath(routeParams.reportID);
+ const isLoading = isLoadingApp !== false || isLoadingReportData || (!isOffline && !!isLoadingInitialReportActions);
+ const mayBeTransactionThread = isReportTransactionThread(report);
+
+ // Fast path: skip the expensive inner guard (parentReportMetadata, useParentReportAction)
+ // when we can determine shouldShowNotFoundPage is definitely false.
+ //
+ // shouldShowNotFoundPage is false when:
+ // - deleteTransactionNavigateBackUrl is set (always suppresses not-found), OR
+ // - path is valid AND report is not a transaction thread AND (still loading OR report exists)
+ const reportClearlyExists = !!reportID || isOptimisticDelete || userLeavingStatus;
+ const canSkipInnerGuard = !!deleteTransactionNavigateBackUrl || (!isInvalidReportPath && !mayBeTransactionThread && (isLoading || reportClearlyExists));
+ if (canSkipInnerGuard) {
+ return children;
+ }
+
+ return (
+
+ {children}
+
+ );
+}
+
+type ReportNotFoundInnerGuardProps = {
+ report: OnyxEntry;
+ reportIDFromPath: string | undefined;
+ reportID: string | undefined;
+ isOptimisticDelete: boolean;
+ isInvalidReportPath: boolean;
+ isLoading: boolean;
+ isLoadingApp: OnyxEntry;
+ isLoadingReportData: boolean;
+ isLoadingInitialReportActions: boolean;
+ isOffline: boolean;
+ userLeavingStatus: boolean;
+ deleteTransactionNavigateBackUrl: OnyxEntry;
+ children: ReactNode;
+};
+
+// eslint-disable-next-line rulesdir/no-negated-variables
+function ReportNotFoundInnerGuard({
+ report,
+ reportIDFromPath,
+ reportID,
+ isOptimisticDelete,
+ isInvalidReportPath,
+ isLoading,
+ isLoadingApp,
+ isLoadingReportData,
+ isLoadingInitialReportActions,
+ isOffline,
+ userLeavingStatus,
+ deleteTransactionNavigateBackUrl,
+ children,
+}: ReportNotFoundInnerGuardProps) {
+ const styles = useThemeStyles();
+ const {shouldUseNarrowLayout} = useResponsiveLayout();
+
+ const [parentReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.parentReportID}`);
+ const parentReportAction = useParentReportAction(report);
const {isParentActionMissingAfterLoad, isParentActionDeleted} = getParentReportActionDeletionStatus({
parentReportID: report?.parentReportID,
@@ -53,8 +134,6 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
});
const isDeletedTransactionThread = isReportTransactionThread(report) && (isParentActionDeleted || isParentActionMissingAfterLoad);
- const isInvalidReportPath = !!routeParams?.reportID && !isValidReportIDFromPath(routeParams.reportID);
- const isLoading = isLoadingApp !== false || isLoadingReportData || (!isOffline && !!isLoadingInitialReportActions);
const reportExists = !!reportID || (!isDeletedTransactionThread && isOptimisticDelete) || userLeavingStatus;
// eslint-disable-next-line rulesdir/no-negated-variables
@@ -73,7 +152,7 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
reportID,
isOptimisticDelete,
userLeavingStatus,
- reportIDFromPath: routeParams?.reportID,
+ reportIDFromPath,
deleteTransactionNavigateBackUrl,
isDeletedTransactionThread,
isParentActionDeleted,
@@ -88,7 +167,7 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
reportID,
isOptimisticDelete,
userLeavingStatus,
- routeParams?.reportID,
+ reportIDFromPath,
deleteTransactionNavigateBackUrl,
isDeletedTransactionThread,
isParentActionDeleted,