Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 74 additions & 23 deletions src/pages/inbox/ReportNotFoundGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,22 @@ type ReportNotFoundGuardProps = {
children: ReactNode;
};

/**
* The outer guard subscribes to lightweight keys and handles
* all "obvious" not-found cases (invalid path, report missing after load).
*
*/
Comment on lines +23 to +27

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* Two-level gate: the outer guard subscribes to lightweight keys and handles
* all "obvious" not-found cases (invalid path, report missing after load).
*
* The inner gate mounts only for transaction threads, where the expensive
* parentReportMetadata / useParentReportAction subscriptions are needed to
* detect whether the parent action was deleted.
*/
/**
* The outer guard subscribes to lightweight keys and handles
* all "obvious" not-found cases (invalid path, report missing after load).
*
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment for the inner gate has already been commented on below. Don't need to mention it twice

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Removed the inner gate description from the outer guard comment.

// eslint-disable-next-line rulesdir/no-negated-variables
function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
const styles = useThemeStyles();
const route = useRoute();
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
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,
Expand All @@ -40,31 +44,19 @@ 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 {isParentActionMissingAfterLoad, isParentActionDeleted} = getParentReportActionDeletionStatus({
parentReportID: report?.parentReportID,
parentReportActionID: report?.parentReportActionID,
parentReportAction,
parentReportMetadata,
isOffline,
});
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;
const reportExists = !!reportID || isOptimisticDelete || userLeavingStatus;

// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = !deleteTransactionNavigateBackUrl && (isDeletedTransactionThread || isInvalidReportPath || (!isLoading && !reportExists));
const shouldShowNotFoundPage = !deleteTransactionNavigateBackUrl && (isInvalidReportPath || (!isLoading && !reportExists));

useEffect(() => {
if (!shouldShowNotFoundPage) {
return;
}

Log.info('[ReportScreen] Displaying NotFound Page', false, {
isLoadingApp,
isLoadingReportData,
Expand All @@ -75,9 +67,6 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
userLeavingStatus,
reportIDFromPath: routeParams?.reportID,
deleteTransactionNavigateBackUrl,
isDeletedTransactionThread,
isParentActionDeleted,
isParentActionMissingAfterLoad,
});
}, [
shouldShowNotFoundPage,
Expand All @@ -90,11 +79,73 @@ function ReportNotFoundGuard({children}: ReportNotFoundGuardProps) {
userLeavingStatus,
routeParams?.reportID,
deleteTransactionNavigateBackUrl,
isDeletedTransactionThread,
isParentActionDeleted,
isParentActionMissingAfterLoad,
]);

if (shouldShowNotFoundPage) {
return (
<FullPageNotFoundView
shouldShow
subtitleKey="notFound.noAccess"
subtitleStyle={[styles.textSupporting]}
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={Navigation.goBack}
shouldShowLink={false}
shouldDisplaySearchRouter
>
{children}
</FullPageNotFoundView>
);
}

if (!deleteTransactionNavigateBackUrl && isReportTransactionThread(report)) {
return <ReportNotFoundInnerGuard reportIDFromPath={routeParams?.reportID}>{children}</ReportNotFoundInnerGuard>;
}

return children;
}

type ReportNotFoundInnerGuardProps = {
reportIDFromPath: string | undefined;
children: ReactNode;
};

/**
* Inner guard for transaction threads only. Subscribes to the expensive
* parentReportMetadata and parentReportAction to detect deleted parent actions.
*/
// eslint-disable-next-line rulesdir/no-negated-variables
function ReportNotFoundInnerGuard({reportIDFromPath, children}: ReportNotFoundInnerGuardProps) {
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {isOffline} = useNetwork();

const reportIDFromRoute = getNonEmptyStringOnyxID(reportIDFromPath);

const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`);
const [parentReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.parentReportID}`);
const parentReportAction = useParentReportAction(report);

const {isParentActionMissingAfterLoad, isParentActionDeleted} = getParentReportActionDeletionStatus({
parentReportID: report?.parentReportID,
parentReportActionID: report?.parentReportActionID,
parentReportAction,
parentReportMetadata,
isOffline,
});
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = isParentActionDeleted || isParentActionMissingAfterLoad;

useEffect(() => {
if (!shouldShowNotFoundPage) {
return;
}
Log.info('[ReportScreen] Displaying NotFound Page (deleted transaction thread)', false, {
reportIDFromPath,
isParentActionDeleted,
isParentActionMissingAfterLoad,
});
}, [shouldShowNotFoundPage, reportIDFromPath, isParentActionDeleted, isParentActionMissingAfterLoad]);

return (
<FullPageNotFoundView
shouldShow={shouldShowNotFoundPage}
Expand Down
Loading