diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8dc1c9967f13..0f7d40f3c7d1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -545,7 +545,7 @@ function getReport(reportID: string | undefined): OnyxEntry | EmptyObjec } /** - * Returns the parentReport if the given report is a thread. + * Returns the parentReport if the given report is a thread */ function getParentReport(report: OnyxEntry | EmptyObject): OnyxEntry | EmptyObject { if (!report?.parentReportID) { @@ -574,6 +574,9 @@ function getRootParentReport(report: OnyxEntry | undefined | EmptyObject return getRootParentReport(!isEmptyObject(parentReport) ? parentReport : null); } +/** + * @deprecated Use withOnyx or Onyx.connect() instead + */ function getPolicy(policyID: string | undefined): Policy | EmptyObject { if (!allPolicies || !policyID) { return {}; @@ -5420,7 +5423,6 @@ export { isSettled, isAllowedToComment, getBankAccountRoute, - getParentReport, getRootParentReport, getReportPreviewMessage, isMoneyRequestReportPendingDeletion, diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 48ab7cce9186..491a75f9c643 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -24,6 +24,7 @@ import type {Icon} from '@src/types/onyx/OnyxCommon'; import type {ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Report from './Report'; type OptimisticReport = Pick; @@ -71,6 +72,13 @@ Onyx.connect({ }, }); +let allReports: OnyxCollection; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (value) => (allReports = value), +}); + /** * Clears out the task info from the store */ @@ -747,6 +755,16 @@ function getParentReportAction(report: OnyxEntry): ReportActio return allReportActions?.[report.parentReportID]?.[report.parentReportActionID] ?? {}; } +/** + * Returns the parentReport if the given report is a thread + */ +function getParentReport(report: OnyxEntry | EmptyObject): OnyxEntry | EmptyObject { + if (!report?.parentReportID) { + return {}; + } + return allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`] ?? {}; +} + /** * Cancels a task by setting the report state to SUBMITTED and status to CLOSED */ @@ -758,7 +776,7 @@ function deleteTask(report: OnyxEntry) { const optimisticCancelReportAction = ReportUtils.buildOptimisticTaskReportAction(report.reportID ?? '', CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED, message); const optimisticReportActionID = optimisticCancelReportAction.reportActionID; const parentReportAction = getParentReportAction(report); - const parentReport = ReportUtils.getParentReport(report); + const parentReport = getParentReport(report); // If the task report is the last visible action in the parent report, we should navigate back to the parent report const shouldDeleteTaskReport = !ReportActionsUtils.doesReportHaveVisibleActions(report.reportID ?? ''); @@ -927,7 +945,7 @@ function canModifyTask(taskReport: OnyxEntry, sessionAccountID return false; } - const parentReport = ReportUtils.getParentReport(taskReport); + const parentReport = getParentReport(taskReport); if (ReportUtils.isArchivedRoom(parentReport)) { return false; } diff --git a/src/pages/FlagCommentPage.tsx b/src/pages/FlagCommentPage.tsx index 216196c17d55..53aac0ce2a8b 100644 --- a/src/pages/FlagCommentPage.tsx +++ b/src/pages/FlagCommentPage.tsx @@ -54,7 +54,7 @@ function getReportID(route: FlagCommentPageNavigationProps['route']) { return route.params.reportID.toString(); } -function FlagCommentPage({parentReportAction, route, report, reportActions}: FlagCommentPageProps) { +function FlagCommentPage({parentReportAction, route, report, parentReport, reportActions}: FlagCommentPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -130,7 +130,7 @@ function FlagCommentPage({parentReportAction, route, report, reportActions}: Fla // Handle threads if needed if (ReportUtils.isChatThread(report) && reportAction?.reportActionID === parentReportAction?.reportActionID) { - reportID = ReportUtils.getParentReport(report)?.reportID; + reportID = parentReport?.reportID; } if (reportAction && ReportUtils.canFlagReportAction(reportAction, reportID)) { diff --git a/src/pages/home/report/withReportAndReportActionOrNotFound.tsx b/src/pages/home/report/withReportAndReportActionOrNotFound.tsx index 3fe43e96266a..73bd3532bfc8 100644 --- a/src/pages/home/report/withReportAndReportActionOrNotFound.tsx +++ b/src/pages/home/report/withReportAndReportActionOrNotFound.tsx @@ -22,6 +22,9 @@ type OnyxProps = { /** The report currently being looked at */ report: OnyxEntry; + /** The parent report if the current report is a thread and it has a parent */ + parentReport: OnyxEntry; + /** The report metadata */ reportMetadata: OnyxEntry; @@ -103,6 +106,9 @@ export default function `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, + parentReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report ? report.parentReportID : '0'}`, + }, reportMetadata: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${route.params.reportID}`, }, diff --git a/tests/actions/EnforceActionExportRestrictions.ts b/tests/actions/EnforceActionExportRestrictions.ts new file mode 100644 index 000000000000..92d96869d02d --- /dev/null +++ b/tests/actions/EnforceActionExportRestrictions.ts @@ -0,0 +1,20 @@ +import * as ReportUtils from '@libs/ReportUtils'; +import * as Task from '@userActions/Task'; + +// There are some methods that are OK to use inside an action file, but should not be exported. These are typically methods that look up and return Onyx data. +// The correct pattern to use is that every file will use it's own withOnyx or Onyx.connect() to access the Onyx data it needs. This prevents data from becoming stale +// and prevents side-effects that you may not be aware of. It also allows each file to access Onyx data in the most performant way. More context can be found in +// https://github.com/Expensify/App/issues/27262 +describe('ReportUtils', () => { + it('does not export getParentReport', () => { + // @ts-expect-error the test is asserting that it's undefined, so the TS error is normal + expect(ReportUtils.getParentReport).toBeUndefined(); + }); +}); + +describe('Task', () => { + it('does not export getParentReport', () => { + // @ts-expect-error the test is asserting that it's undefined, so the TS error is normal + expect(Task.getParentReport).toBeUndefined(); + }); +});