diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 1838ae63dd3ec..0a92e711133ed 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -21,14 +21,15 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {isValidDraftComment} from '@libs/DraftCommentUtils'; import getPlatform from '@libs/getPlatform'; import Log from '@libs/Log'; -import {getIOUReportIDOfLastAction, getLastMessageTextForReport, hasReportErrors} from '@libs/OptionsListUtils'; +import {getIOUReportIDOfLastAction, getLastMessageTextForReport} from '@libs/OptionsListUtils'; import {getOneTransactionThreadReportID, getOriginalMessage, getSortedReportActionsForDisplay, isMoneyRequestAction} from '@libs/ReportActionsUtils'; -import {canUserPerformWriteAction, getReportAttributes} from '@libs/ReportUtils'; +import {canUserPerformWriteAction} from '@libs/ReportUtils'; import isProductTrainingElementDismissed from '@libs/TooltipUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, Report} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import OptionRowLHNData from './OptionRowLHNData'; import OptionRowRendererComponent from './OptionRowRendererComponent'; @@ -69,19 +70,19 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio return undefined; } const firstReportWithGBRorRBR = data.find((report) => { - const itemReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]; + const itemReportErrors = reportAttributes?.[report.reportID]?.reportErrors; if (!report) { return false; } - if (hasReportErrors(report, itemReportActions)) { + if (!isEmptyObject(itemReportErrors)) { return true; } - const hasGBR = getReportAttributes(report.reportID, reportAttributes)?.requiresAttention; + const hasGBR = reportAttributes?.[report.reportID]?.requiresAttention; return hasGBR; }); return firstReportWithGBRorRBR?.reportID; - }, [isGBRorRBRTooltipDismissed, data, reportActions, reportAttributes]); + }, [isGBRorRBRTooltipDismissed, data, reportAttributes]); // When the first item renders we want to call the onFirstItemRendered callback. // At this point in time we know that the list is actually displaying items. diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index 94f691529fdb7..d01b69a7ad86b 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -45,7 +45,6 @@ function OptionRowLHNData({ reportAttributes, oneTransactionThreadReport, reportNameValuePairs, - reportActions, personalDetails, preferredLocale: preferredLocale ?? CONST.LOCALES.DEFAULT, policy, diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index cb382d4f4cc9f..6f2b0f862f1bc 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -9,6 +9,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Beta, Policy, Report, ReportAction, ReportActions, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {Comment} from '@src/types/onyx/Transaction'; import {getLinkedTransactionID} from './ReportActionsUtils'; import {getReasonAndReportActionThatRequiresAttention, reasonForReportToBeInOptionList, shouldDisplayViolationsRBRInLHN} from './ReportUtils'; @@ -1379,8 +1380,16 @@ type RBRReasonAndReportAction = { /** * Gets the report action that is causing the RBR to show up in LHN */ -function getReasonAndReportActionForRBRInLHNRow(report: Report, reportActions: OnyxEntry, hasViolations: boolean, isArchivedReport = false): RBRReasonAndReportAction | null { - const {reason, reportAction} = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(report, reportActions, hasViolations, transactionViolations, isArchivedReport) ?? {}; +function getReasonAndReportActionForRBRInLHNRow( + report: Report, + reportActions: OnyxEntry, + transactions: OnyxCollection, + hasViolations: boolean, + reportErrors: Errors, + isArchivedReport = false, +): RBRReasonAndReportAction | null { + const {reason, reportAction} = + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(report, reportActions, hasViolations, reportErrors, transactions, transactionViolations, isArchivedReport) ?? {}; if (reason) { return {reason: `debug.reasonRBR.${reason}`, reportAction}; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index c3556f9e944e3..e33a10e03da67 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -27,6 +27,7 @@ import type { Report, ReportAction, ReportActions, + ReportAttributesDerivedValue, ReportNameValuePairs, TransactionViolation, } from '@src/types/onyx'; @@ -88,7 +89,6 @@ import { import { canUserPerformWriteAction, formatReportLastMessageText, - getAllReportErrors, getChatByParticipants, getChatRoomSubtitle, getDeletedParentActionMessageForChatReport, @@ -451,6 +451,12 @@ Onyx.connect({ callback: (value) => (nvpDismissedProductTraining = value), }); +let reportAttributesDerivedValue: ReportAttributesDerivedValue['reports'] | undefined; +Onyx.connect({ + key: ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, + callback: (value) => (reportAttributesDerivedValue = value?.reports), +}); + /** * @param defaultValues {login: accountID} In workspace invite page, when new user is added we pass available data to opt in * @returns Returns avatar data for a list of user accountIDs @@ -846,20 +852,10 @@ function getLastMessageTextForReport( return lastMessageTextFromReport || (report?.lastMessageText ?? ''); } -function hasReportErrors(report: Report, reportActions: OnyxEntry) { - return !isEmptyObject(getAllReportErrors(report, reportActions)); -} - /** * Creates a report list option */ -function createOption( - accountIDs: number[], - personalDetails: OnyxInputOrEntry, - report: OnyxInputOrEntry, - reportActions: ReportActions, - config?: PreviewConfig, -): OptionData { +function createOption(accountIDs: number[], personalDetails: OnyxInputOrEntry, report: OnyxInputOrEntry, config?: PreviewConfig): OptionData { const {showChatPreviewLine = false, forcePolicyNamePreview = false, showPersonalDetails = false, selected, isSelected, isDisabled} = config ?? {}; const result: OptionData = { text: undefined, @@ -919,8 +915,8 @@ function createOption( result.shouldShowSubscript = shouldReportShowSubscript(report); result.isPolicyExpenseChat = reportUtilsIsPolicyExpenseChat(report); result.isOwnPolicyExpenseChat = report.isOwnPolicyExpenseChat ?? false; - result.allReportErrors = getAllReportErrors(report, reportActions); - result.brickRoadIndicator = hasReportErrors(report, reportActions) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; + result.allReportErrors = reportAttributesDerivedValue?.[report.reportID]?.reportErrors ?? {}; + result.brickRoadIndicator = !isEmptyObject(result.allReportErrors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.pendingAction = report.pendingFields ? report.pendingFields.addWorkspaceRoom ?? report.pendingFields.createChat : undefined; result.ownerAccountID = report.ownerAccountID; result.reportID = report.reportID; @@ -999,16 +995,10 @@ function getReportOption(participant: Participant): OptionData { const report = getReportOrDraftReport(participant.reportID); const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); - const option = createOption( - visibleParticipantAccountIDs, - allPersonalDetails ?? {}, - !isEmptyObject(report) ? report : undefined, - {}, - { - showChatPreviewLine: false, - forcePolicyNamePreview: false, - }, - ); + const option = createOption(visibleParticipantAccountIDs, allPersonalDetails ?? {}, !isEmptyObject(report) ? report : undefined, { + showChatPreviewLine: false, + forcePolicyNamePreview: false, + }); // Update text & alternateText because createOption returns workspace name only if report is owned by the user if (option.isSelfDM) { @@ -1043,16 +1033,10 @@ function getReportOption(participant: Participant): OptionData { function getReportDisplayOption(report: OnyxEntry, unknownUserDetails: OnyxEntry): OptionData { const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); - const option = createOption( - visibleParticipantAccountIDs, - allPersonalDetails ?? {}, - !isEmptyObject(report) ? report : undefined, - {}, - { - showChatPreviewLine: false, - forcePolicyNamePreview: false, - }, - ); + const option = createOption(visibleParticipantAccountIDs, allPersonalDetails ?? {}, !isEmptyObject(report) ? report : undefined, { + showChatPreviewLine: false, + forcePolicyNamePreview: false, + }); // Update text & alternateText because createOption returns workspace name only if report is owned by the user if (option.isSelfDM) { @@ -1084,16 +1068,10 @@ function getPolicyExpenseReportOption(participant: Participant | OptionData): Op .filter(([, reportParticipant]) => reportParticipant && !isHiddenForCurrentUser(reportParticipant.notificationPreference)) .map(([accountID]) => Number(accountID)); - const option = createOption( - visibleParticipantAccountIDs, - allPersonalDetails ?? {}, - !isEmptyObject(expenseReport) ? expenseReport : null, - {}, - { - showChatPreviewLine: false, - forcePolicyNamePreview: false, - }, - ); + const option = createOption(visibleParticipantAccountIDs, allPersonalDetails ?? {}, !isEmptyObject(expenseReport) ? expenseReport : null, { + showChatPreviewLine: false, + forcePolicyNamePreview: false, + }); // Update text & alternateText because createOption returns workspace name only if report is owned by the user option.text = getPolicyName({report: expenseReport}); @@ -1222,7 +1200,7 @@ function processReport( reportMapEntry, reportOption: { item: report, - ...createOption(accountIDs, personalDetails, report, {}), + ...createOption(accountIDs, personalDetails, report), }, }; } @@ -1248,13 +1226,9 @@ function createOptionList(personalDetails: OnyxEntry, repor const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => ({ item: personalDetail, - ...createOption( - [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - personalDetails, - reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - {}, - {showPersonalDetails: true}, - ), + ...createOption([personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], personalDetails, reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], { + showPersonalDetails: true, + }), })); return { @@ -1268,7 +1242,7 @@ function createOptionFromReport(report: Report, personalDetails: OnyxEntry, reportActions: OnyxEntry< return allReportErrors; } -function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveViolations: boolean, transactionViolations: OnyxCollection) { - const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {}; - const allReportErrors = getAllReportErrors(report, reportActions) ?? {}; +function hasReportErrorsOtherThanFailedReceipt( + report: Report, + doesReportHaveViolations: boolean, + transactionViolations: OnyxCollection, + reportAttributes?: ReportAttributesDerivedValue['reports'], +) { + const allReportErrors = reportAttributes?.[report?.reportID]?.reportErrors ?? {}; const transactionReportActions = getAllReportActions(report.reportID); const oneTransactionThreadReportID = getOneTransactionThreadReportID(report.reportID, transactionReportActions, undefined); let doesTransactionThreadReportHasViolations = false; @@ -10785,16 +10789,6 @@ function findReportIDForAction(action?: ReportAction): string | undefined { }) ?.replace(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}`, ''); } - -function getReportAttributes(reportID: string | undefined, reportAttributes?: ReportAttributesDerivedValue['reports']) { - const attributes = reportAttributes ?? reportAttributesDerivedValue; - - if (!reportID || !attributes?.[reportID]) { - return; - } - return attributes[reportID]; -} - export { addDomainToShortMention, completeShortMention, @@ -11173,7 +11167,6 @@ export { isAllowedToSubmitDraftExpenseReport, findReportIDForAction, isWorkspaceEligibleForReportChange, - getReportAttributes, navigateOnDeleteExpense, }; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index c0882ef5a823b..c4287291fd335 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -8,6 +8,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, ReportActions, ReportAttributesDerivedValue, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx'; import type Beta from '@src/types/onyx/Beta'; import type {ReportAttributes} from '@src/types/onyx/DerivedValues'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; import type Policy from '@src/types/onyx/Policy'; import type PriorityMode from '@src/types/onyx/PriorityMode'; import type Report from '@src/types/onyx/Report'; @@ -68,14 +69,12 @@ import { canUserPerformWriteAction as canUserPerformWriteActionUtil, formatReportLastMessageText, getAllReportActionsErrorsAndReportActionThatRequiresAttention, - getAllReportErrors, getChatRoomSubtitle, getDisplayNameForParticipant, getDisplayNamesWithTooltips, getIcons, getParticipantsAccountIDsForDisplay, getPolicyName, - getReportAttributes, getReportDescription, getReportName, getReportNameValuePairs, @@ -164,18 +163,6 @@ Onyx.connect({ }, }); -let allTransactions: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.TRANSACTION, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - return; - } - allTransactions = Object.fromEntries(Object.entries(value).filter(([, transaction]) => !!transaction)); - }, -}); - function compareStringDates(a: string, b: string): 0 | 1 | -1 { if (a < b) { return -1; @@ -230,7 +217,7 @@ function getOrderedReportIDs( const doesReportHaveViolations = shouldDisplayViolationsRBRInLHN(report, transactionViolations); const isHidden = isHiddenForCurrentUser(report); const isFocused = report.reportID === currentReportId; - const hasErrorsOtherThanFailedReceipt = hasReportErrorsOtherThanFailedReceipt(report, doesReportHaveViolations, transactionViolations); + const hasErrorsOtherThanFailedReceipt = hasReportErrorsOtherThanFailedReceipt(report, doesReportHaveViolations, transactionViolations, reportAttributes); const isReportInAccessible = report?.errorFields?.notFound; if (isOneTransactionThread(report.reportID, report.parentReportID, parentReportAction)) { return; @@ -251,7 +238,7 @@ function getOrderedReportIDs( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing report.isPinned || (!isInFocusMode && isArchivedReport(reportNameValuePairs)) || - getReportAttributes(report.reportID, reportAttributes)?.requiresAttention; + reportAttributes?.[report?.reportID]?.requiresAttention; if (isHidden && !shouldOverrideHidden) { return; } @@ -300,7 +287,7 @@ function getOrderedReportIDs( const isPinned = report?.isPinned ?? false; const rNVPs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; - if (isPinned || getReportAttributes(report?.reportID, reportAttributes)?.requiresAttention) { + if (isPinned || reportAttributes?.[report?.reportID]?.requiresAttention) { pinnedAndGBRReports.push(miniReport); } else if (report?.hasErrorsOtherThanFailedReceipt) { errorReports.push(miniReport); @@ -352,11 +339,13 @@ function getReasonAndReportActionThatHasRedBrickRoad( report: Report, reportActions: OnyxEntry, hasViolations: boolean, + reportErrors: Errors, + transactions: OnyxCollection, transactionViolations?: OnyxCollection, isReportArchived = false, ): ReasonAndReportActionThatHasRedBrickRoad | null { const {reportAction} = getAllReportActionsErrorsAndReportActionThatRequiresAttention(report, reportActions); - const errors = getAllReportErrors(report, reportActions); + const errors = reportErrors; const hasErrors = Object.keys(errors).length !== 0; if (isReportArchived) { @@ -385,7 +374,7 @@ function getReasonAndReportActionThatHasRedBrickRoad( const transactionThreadReportID = getOneTransactionThreadReportID(report.reportID, reportActions ?? []); if (transactionThreadReportID) { const transactionID = getTransactionID(transactionThreadReportID); - const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (hasReceiptError(transaction)) { return { reason: CONST.RBR_REASONS.HAS_ERRORS, @@ -393,7 +382,7 @@ function getReasonAndReportActionThatHasRedBrickRoad( } } const transactionID = getTransactionID(report.reportID); - const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (isTransactionThread(parentReportAction) && hasReceiptError(transaction)) { return { reason: CONST.RBR_REASONS.HAS_ERRORS, @@ -407,10 +396,12 @@ function shouldShowRedBrickRoad( report: Report, reportActions: OnyxEntry, hasViolations: boolean, + reportErrors: Errors, + transactions: OnyxCollection, transactionViolations?: OnyxCollection, isReportArchived = false, ) { - return !!getReasonAndReportActionThatHasRedBrickRoad(report, reportActions, hasViolations, transactionViolations, isReportArchived); + return !!getReasonAndReportActionThatHasRedBrickRoad(report, reportActions, hasViolations, reportErrors, transactions, transactionViolations, isReportArchived); } /** @@ -421,7 +412,6 @@ function getOptionData({ reportAttributes, oneTransactionThreadReport, reportNameValuePairs, - reportActions, personalDetails, preferredLocale, policy, @@ -432,7 +422,6 @@ function getOptionData({ report: OnyxEntry; oneTransactionThreadReport: OnyxEntry; reportNameValuePairs: OnyxEntry; - reportActions: OnyxEntry; personalDetails: OnyxEntry; preferredLocale: DeepValueOf; policy: OnyxEntry | undefined; @@ -451,7 +440,7 @@ function getOptionData({ const result: OptionData = { text: '', alternateText: undefined, - allReportErrors: getAllReportErrors(report, reportActions), + allReportErrors: reportAttributes?.reportErrors, brickRoadIndicator: null, tooltipText: null, subtitle: undefined, diff --git a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts index 99c2d344b6260..4a63376d167f7 100644 --- a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts +++ b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts @@ -34,12 +34,12 @@ export default createOnyxDerivedValueConfig({ ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, ONYXKEYS.COLLECTION.REPORT_ACTIONS, ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, - ONYXKEYS.PERSONAL_DETAILS_LIST, ONYXKEYS.COLLECTION.TRANSACTION, + ONYXKEYS.PERSONAL_DETAILS_LIST, ONYXKEYS.COLLECTION.POLICY, ONYXKEYS.COLLECTION.REPORT_METADATA, ], - compute: ([reports, preferredLocale, transactionViolations, reportActions, reportNameValuePairs], {currentValue, sourceValues, areAllConnectionsSet}) => { + compute: ([reports, preferredLocale, transactionViolations, reportActions, reportNameValuePairs, transactions], {currentValue, sourceValues, areAllConnectionsSet}) => { if (!areAllConnectionsSet) { return { reports: {}, @@ -110,7 +110,7 @@ export default createOnyxDerivedValueConfig({ } const reportActionsList = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]; - const {hasAnyViolations, requiresAttention, isReportArchived} = generateReportAttributes({ + const {hasAnyViolations, requiresAttention, isReportArchived, reportErrors} = generateReportAttributes({ report, reportActions, transactionViolations, @@ -119,7 +119,7 @@ export default createOnyxDerivedValueConfig({ let brickRoadStatus; // if report has errors or violations, show red dot - if (SidebarUtils.shouldShowRedBrickRoad(report, reportActionsList, hasAnyViolations, transactionViolations, !!isReportArchived)) { + if (SidebarUtils.shouldShowRedBrickRoad(report, reportActionsList, hasAnyViolations, reportErrors, transactions, transactionViolations, !!isReportArchived)) { brickRoadStatus = CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR; } // if report does not have error, check if it should show green dot @@ -132,6 +132,7 @@ export default createOnyxDerivedValueConfig({ isEmpty: generateIsEmptyReport(report), brickRoadStatus, requiresAttention, + reportErrors, }; return acc; diff --git a/src/pages/Debug/Report/DebugReportPage.tsx b/src/pages/Debug/Report/DebugReportPage.tsx index 33d5f6f197b46..e1ea9d98bfb04 100644 --- a/src/pages/Debug/Report/DebugReportPage.tsx +++ b/src/pages/Debug/Report/DebugReportPage.tsx @@ -53,7 +53,12 @@ function DebugReportPage({ const theme = useTheme(); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {canBeMissing: true}); const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {canBeMissing: true}); + const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true}); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); + const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, { + selector: (attributes) => attributes?.reports?.[reportID], + canBeMissing: true, + }); const transactionID = DebugUtils.getTransactionID(report, reportActions); const isReportArchived = useReportIsArchived(reportID); @@ -66,7 +71,8 @@ function DebugReportPage({ const shouldDisplayReportViolations = isReportOwner(report) && hasReportViolations(reportID); const hasViolations = !!shouldDisplayViolations || shouldDisplayReportViolations; const {reason: reasonGBR, reportAction: reportActionGBR} = DebugUtils.getReasonAndReportActionForGBRInLHNRow(report) ?? {}; - const {reason: reasonRBR, reportAction: reportActionRBR} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(report, reportActions, hasViolations, isReportArchived) ?? {}; + const {reason: reasonRBR, reportAction: reportActionRBR} = + DebugUtils.getReasonAndReportActionForRBRInLHNRow(report, reportActions, transactions, hasViolations, reportAttributes?.reportErrors ?? {}, isReportArchived) ?? {}; const hasRBR = !!reasonRBR; const hasGBR = !hasRBR && !!reasonGBR; const reasonLHN = DebugUtils.getReasonForShowingRowInLHN(report, hasRBR); @@ -114,7 +120,7 @@ function DebugReportPage({ : undefined, }, ]; - }, [report, reportActions, reportID, transactionViolations, translate, isReportArchived]); + }, [report, transactionViolations, reportID, reportActions, transactions, reportAttributes?.reportErrors, isReportArchived, translate]); const DebugDetailsTab = useCallback( () => ( diff --git a/src/types/onyx/DerivedValues.ts b/src/types/onyx/DerivedValues.ts index b6be510580509..1a396e81fb4c8 100644 --- a/src/types/onyx/DerivedValues.ts +++ b/src/types/onyx/DerivedValues.ts @@ -1,5 +1,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; +import type {Errors} from './OnyxCommon'; /** * The attributes of a report. @@ -21,6 +22,10 @@ type ReportAttributes = { * Whether the report requires attention from current user. */ requiresAttention: boolean; + /** + * The errors of the report. + */ + reportErrors: Errors; }; /** diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index d844185cd4bc9..a4691a84e4381 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -8,7 +8,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, TransactionViolation} from '@src/types/onyx'; import type Policy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; -import type ReportAction from '@src/types/onyx/ReportAction'; import createCollection from '../utils/collections/createCollection'; import createPersonalDetails from '../utils/collections/personalDetails'; import createRandomPolicy from '../utils/collections/policies'; @@ -34,11 +33,6 @@ const allReports = createCollection( REPORTS_COUNT, ); -const reportActions = createCollection( - (item) => `${item.reportActionID}`, - (index) => createRandomReportAction(index), -); - const personalDetails = createCollection( (item) => item.accountID, (index) => createPersonalDetails(index), @@ -85,7 +79,6 @@ describe('SidebarUtils', () => { report, reportAttributes: undefined, reportNameValuePairs, - reportActions, personalDetails, preferredLocale, policy, diff --git a/tests/unit/DebugUtilsTest.ts b/tests/unit/DebugUtilsTest.ts index eb1d3aa5abb70..245195ef5cc74 100644 --- a/tests/unit/DebugUtilsTest.ts +++ b/tests/unit/DebugUtilsTest.ts @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx'; import DateUtils from '@libs/DateUtils'; import type {ObjectType} from '@libs/DebugUtils'; import DebugUtils from '@libs/DebugUtils'; +import {getAllReportErrors} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Report, ReportAction, ReportActions, Transaction} from '@src/types/onyx'; @@ -1107,7 +1108,9 @@ describe('DebugUtils', () => { reportID: '1', }, undefined, + {}, false, + {}, ) ?? {}; expect(reportAction).toBeUndefined(); }); @@ -1158,7 +1161,9 @@ describe('DebugUtils', () => { // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style MOCK_REPORTS[`${ONYXKEYS.COLLECTION.REPORT}1`] as Report, undefined, + {}, false, + {}, ) ?? {}; expect(reportAction).toBe(undefined); }); @@ -1217,7 +1222,8 @@ describe('DebugUtils', () => { accountID: 12345, }, }); - const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, false) ?? {}; + const reportErrors = getAllReportErrors(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS); + const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, {}, false, reportErrors) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTIONS['3']); }); }); @@ -1275,7 +1281,8 @@ describe('DebugUtils', () => { accountID: 12345, }, }); - const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, false) ?? {}; + const reportErrors = getAllReportErrors(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS); + const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, {}, false, reportErrors) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTIONS['3']); }); }); @@ -1334,7 +1341,8 @@ describe('DebugUtils', () => { accountID: 12345, }, }); - const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_CHAT_REPORT, MOCK_CHAT_REPORT_ACTIONS, false) ?? {}; + const reportErrors = getAllReportErrors(MOCK_CHAT_REPORT, MOCK_CHAT_REPORT_ACTIONS); + const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_CHAT_REPORT, MOCK_CHAT_REPORT_ACTIONS, {}, false, reportErrors) ?? {}; expect(reportAction).toMatchObject(MOCK_CHAT_REPORT_ACTIONS['1']); }); it('returns correct report action which is a split bill and has an error', async () => { @@ -1396,7 +1404,8 @@ describe('DebugUtils', () => { accountID: 12345, }, }); - const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_CHAT_REPORT, MOCK_REPORT_ACTIONS, false) ?? {}; + const reportErrors = getAllReportErrors(MOCK_CHAT_REPORT, MOCK_REPORT_ACTIONS); + const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_CHAT_REPORT, MOCK_REPORT_ACTIONS, {}, false, reportErrors) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTIONS['3']); }); it("returns undefined if there's no report action is a report preview or a split bill", async () => { @@ -1452,7 +1461,8 @@ describe('DebugUtils', () => { accountID: 12345, }, }); - const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, false) ?? {}; + const reportErrors = getAllReportErrors(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS); + const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(MOCK_IOU_REPORT, MOCK_REPORT_ACTIONS, {}, false, reportErrors) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTIONS['3']); }); }); @@ -1498,42 +1508,44 @@ describe('DebugUtils', () => { ], }, }; + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); const {reportAction} = DebugUtils.getReasonAndReportActionForRBRInLHNRow( { reportID: '1', }, MOCK_REPORT_ACTIONS, + {}, false, + reportErrors, ) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTIONS['1']); }); }); describe('reason', () => { it('returns correct reason when there are errors', () => { - const {reason} = - DebugUtils.getReasonAndReportActionForRBRInLHNRow( - { - reportID: '1', - }, - { - [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: { - reportActionID: '1', - actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, - created: '2024-09-20 13:11:11.122', - message: [ - { - type: 'TEXT', - text: 'Hello world!', - }, - ], - errors: { - randomError: 'Something went wrong', - }, + const mockedReport = { + reportID: '1', + }; + const mockedReportActions = { + [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: { + reportActionID: '1', + actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, + created: '2024-09-20 13:11:11.122', + message: [ + { + type: 'TEXT', + text: 'Hello world!', }, + ], + errors: { + randomError: 'Something went wrong', }, - false, - ) ?? {}; + }, + }; + + const reportErrors = getAllReportErrors(mockedReport, mockedReportActions); + const {reason} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(mockedReport, mockedReportActions, {}, false, reportErrors) ?? {}; expect(reason).toBe('debug.reasonRBR.hasErrors'); }); it('returns correct reason when there are violations', () => { @@ -1543,7 +1555,9 @@ describe('DebugUtils', () => { reportID: '1', }, undefined, + {}, true, + {}, ) ?? {}; expect(reason).toBe('debug.reasonRBR.hasViolations'); }); @@ -1554,7 +1568,9 @@ describe('DebugUtils', () => { reportID: '1', }, undefined, + {}, true, + {}, true, ) ?? {}; expect(reason).toBe(undefined); @@ -1593,7 +1609,7 @@ describe('DebugUtils', () => { }, ], }); - const {reason} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(report, {}, false) ?? {}; + const {reason} = DebugUtils.getReasonAndReportActionForRBRInLHNRow(report, {}, {}, false, {}) ?? {}; expect(reason).toBe('debug.reasonRBR.hasTransactionThreadViolations'); }); }); diff --git a/tests/unit/OnyxDerivedTest.ts b/tests/unit/OnyxDerivedTest.ts index dcb70563db360..f9f257716b2f7 100644 --- a/tests/unit/OnyxDerivedTest.ts +++ b/tests/unit/OnyxDerivedTest.ts @@ -1,8 +1,11 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import Onyx from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; import initOnyxDerivedValues from '@userActions/OnyxDerived'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {ReportActions} from '@src/types/onyx/ReportAction'; +import createRandomReport from '../utils/collections/reports'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; jest.mock('@components/ConfirmedRoute.tsx'); @@ -70,5 +73,149 @@ describe('OnyxDerived', () => { locale: 'es', }); }); + + describe('reportErrors', () => { + it('returns empty errors when no errors exist', async () => { + const report = createRandomReport(1); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); + await waitForBatchedUpdates(); + + const derivedReportAttributes = await OnyxUtils.get(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); + expect(derivedReportAttributes?.reports[report.reportID].reportErrors).toEqual({}); + }); + + it('combines report error fields with report action errors', async () => { + const report = { + ...createRandomReport(1), + errorFields: { + field1: { + '1234567890': 'Error message 1', + }, + }, + }; + + const reportActions: ReportActions = { + '1': { + reportActionID: '1', + actionName: 'ADDCOMMENT', + created: '2024-01-01', + message: [{html: 'some content', text: 'some content', type: 'text'}], + errors: { + field2: { + '1234567891': 'Error message 2', + }, + }, + }, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, reportActions); + + await waitForBatchedUpdates(); + + const derivedReportAttributes = await OnyxUtils.get(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); + + await waitForBatchedUpdates(); + + expect(derivedReportAttributes?.reports[report.reportID].reportErrors).toEqual({ + '1234567890': 'Error message 1', + '1234567891': 'Error message 2', + }); + }); + + it('handles multiple error sources', async () => { + const report = { + ...createRandomReport(1), + errorFields: { + field1: { + '1234567890': 'Error message 1', + }, + field2: { + '1234567891': 'Error message 2', + }, + }, + }; + + const reportActions: ReportActions = { + '1': { + reportActionID: '1', + actionName: 'ADDCOMMENT', + created: '2024-01-01', + message: [{html: 'some content', text: 'some content', type: 'text'}], + errors: { + field3: { + '1234567892': 'Error message 3', + }, + }, + }, + '2': { + reportActionID: '2', + actionName: 'ADDCOMMENT', + created: '2024-01-01', + message: [{html: 'some content', text: 'some content', type: 'text'}], + errors: { + field4: { + '1234567893': 'Error message 4', + }, + }, + }, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, reportActions); + await waitForBatchedUpdates(); + + const derivedReportAttributes = await OnyxUtils.get(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); + expect(derivedReportAttributes?.reports[report.reportID].reportErrors).toEqual({ + '1234567890': 'Error message 1', + '1234567891': 'Error message 2', + '1234567892': 'Error message 3', + '1234567893': 'Error message 4', + }); + }); + + it('handles empty error objects in sources', async () => { + const report = { + ...createRandomReport(1), + errorFields: { + field1: {}, + field2: { + '1234567890': 'Error message 1', + }, + }, + }; + + const reportActions: ReportActions = { + '1': { + reportActionID: '1', + actionName: 'ADDCOMMENT', + created: '2024-01-01', + message: [{html: 'some content', text: 'some content', type: 'text'}], + errors: {}, + }, + '2': { + reportActionID: '2', + actionName: 'ADDCOMMENT', + created: '2024-01-01', + message: [{html: 'some content', text: 'some content', type: 'text'}], + errors: { + field3: { + '1234567891': 'Error message 2', + }, + }, + }, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, reportActions); + await waitForBatchedUpdates(); + + const derivedReportAttributes = await OnyxUtils.get(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); + expect(derivedReportAttributes?.reports[report.reportID].reportErrors).toEqual({ + '1234567890': 'Error message 1', + '1234567891': 'Error message 2', + }); + }); + }); }); }); diff --git a/tests/unit/SidebarTest.ts b/tests/unit/SidebarTest.ts index 0b9611e9a9006..b81d86309ffca 100644 --- a/tests/unit/SidebarTest.ts +++ b/tests/unit/SidebarTest.ts @@ -1,6 +1,7 @@ import {screen} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import DateUtils from '@libs/DateUtils'; +import initOnyxDerivedValues from '@userActions/OnyxDerived'; import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -22,12 +23,14 @@ const TEST_USER_ACCOUNT_ID = 1; const TEST_USER_LOGIN = 'email1@test.com'; describe('Sidebar', () => { - beforeAll(() => + beforeAll(() => { Onyx.init({ keys: ONYXKEYS, evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], - }), - ); + }); + + initOnyxDerivedValues(); + }); beforeEach(() => { // Wrap Onyx each onyx action with waitForBatchedUpdates diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 3df324f59dd30..6b75676712c0b 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -5,11 +5,12 @@ import Onyx from 'react-native-onyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import DateUtils from '@libs/DateUtils'; import {getReportActionMessageText} from '@libs/ReportActionsUtils'; +import {getAllReportErrors} from '@libs/ReportUtils'; import SidebarUtils from '@libs/SidebarUtils'; import initOnyxDerivedValues from '@userActions/OnyxDerived'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Policy, Report, ReportAction, ReportActions, TransactionViolation, TransactionViolations} from '@src/types/onyx'; +import type {Policy, Report, ReportAction, ReportActions, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx'; import type {ReportCollectionDataSet} from '@src/types/onyx/Report'; import type {TransactionViolationsCollectionDataSet} from '@src/types/onyx/TransactionViolation'; import createRandomPolicy from '../utils/collections/policies'; @@ -66,6 +67,10 @@ describe('SidebarUtils', () => { reportID: MOCK_REPORT.reportID, }; + const MOCK_TRANSACTIONS = { + [`${ONYXKEYS.COLLECTION.TRANSACTION}${MOCK_TRANSACTION.transactionID}` as const]: MOCK_TRANSACTION, + } as OnyxCollection; + const MOCK_TRANSACTION_VIOLATIONS: TransactionViolationsCollectionDataSet = { [`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${MOCK_TRANSACTION.transactionID}` as const]: [ { @@ -94,6 +99,8 @@ describe('SidebarUtils', () => { MOCK_REPORT, MOCK_REPORT_ACTIONS, false, + {}, + MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS as OnyxCollection, isReportArchived.current, ) ?? {}; @@ -111,10 +118,21 @@ describe('SidebarUtils', () => { }, }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const {reason} = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current) ?? {}; + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); + const {reason} = + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ) ?? {}; expect(reason).toBe(CONST.RBR_REASONS.HAS_ERRORS); }); @@ -124,11 +142,21 @@ describe('SidebarUtils', () => { reportID: '1', }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const {reason} = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, true, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current) ?? {}; + const {reason} = + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + true, + {}, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ) ?? {}; expect(reason).toBe(CONST.RBR_REASONS.HAS_VIOLATIONS); }); @@ -155,11 +183,22 @@ describe('SidebarUtils', () => { }, }, }; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const {reason} = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current) ?? {}; + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); + const {reason} = + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ) ?? {}; expect(reason).toBe(CONST.RBR_REASONS.HAS_ERRORS); }); @@ -174,11 +213,21 @@ describe('SidebarUtils', () => { }, }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; - + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const {reason} = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current) ?? {}; + const {reason} = + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ) ?? {}; expect(reason).toBe(CONST.RBR_REASONS.HAS_ERRORS); }); @@ -206,12 +255,21 @@ describe('SidebarUtils', () => { // eslint-disable-next-line @typescript-eslint/naming-convention '1': MOCK_REPORT_ACTION, }; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; - + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); const {reportAction} = - SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current) ?? {}; + SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ) ?? {}; expect(reportAction).toMatchObject(MOCK_REPORT_ACTION); }); @@ -221,11 +279,20 @@ describe('SidebarUtils', () => { reportID: '1', }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + {}, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ); expect(result).toBeNull(); }); @@ -244,7 +311,6 @@ describe('SidebarUtils', () => { report: MOCK_REPORT_PINNED, reportAttributes: undefined, reportNameValuePairs: {}, - reportActions: {}, personalDetails: {}, preferredLocale: CONST.LOCALES.DEFAULT, policy: undefined, @@ -255,7 +321,6 @@ describe('SidebarUtils', () => { report: MOCK_REPORT_UNPINNED, reportAttributes: undefined, reportNameValuePairs: {}, - reportActions: {}, personalDetails: {}, preferredLocale: CONST.LOCALES.DEFAULT, policy: undefined, @@ -299,11 +364,20 @@ describe('SidebarUtils', () => { // eslint-disable-next-line @typescript-eslint/naming-convention '1': MOCK_REPORT_ACTION, }; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + {}, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ); expect(result).toBeNull(); }); @@ -341,6 +415,10 @@ describe('SidebarUtils', () => { reportID: MOCK_REPORT.reportID, }; + const MOCK_TRANSACTIONS = { + [`${ONYXKEYS.COLLECTION.TRANSACTION}${MOCK_TRANSACTION.transactionID}` as const]: MOCK_TRANSACTION, + } as OnyxCollection; + const MOCK_TRANSACTION_VIOLATIONS: TransactionViolationsCollectionDataSet = { [`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${MOCK_TRANSACTION.transactionID}` as const]: [ { @@ -367,6 +445,8 @@ describe('SidebarUtils', () => { MOCK_REPORT, MOCK_REPORT_ACTIONS, false, + {}, + MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS as OnyxCollection, isReportArchived.current, ); @@ -405,6 +485,10 @@ describe('SidebarUtils', () => { reportID: MOCK_REPORT.reportID, }; + const MOCK_TRANSACTIONS = { + [`${ONYXKEYS.COLLECTION.TRANSACTION}${MOCK_TRANSACTION.transactionID}` as const]: MOCK_TRANSACTION, + } as OnyxCollection; + const MOCK_TRANSACTION_VIOLATIONS: TransactionViolationsCollectionDataSet = { [`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${MOCK_TRANSACTION.transactionID}` as const]: [ { @@ -430,6 +514,8 @@ describe('SidebarUtils', () => { MOCK_REPORT, MOCK_REPORT_ACTIONS, false, + {}, + MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS as OnyxCollection, isReportArchived.current, ); @@ -447,10 +533,19 @@ describe('SidebarUtils', () => { }, }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; - + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ); expect(result).toBe(true); }); @@ -460,10 +555,11 @@ describe('SidebarUtils', () => { reportID: '1', }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, true, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, true, {}, MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); expect(result).toBe(true); }); @@ -490,10 +586,19 @@ describe('SidebarUtils', () => { }, }, }; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; - + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ); expect(result).toBe(true); }); @@ -508,10 +613,19 @@ describe('SidebarUtils', () => { }, }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; - + const reportErrors = getAllReportErrors(MOCK_REPORT, MOCK_REPORT_ACTIONS); const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad( + MOCK_REPORT, + MOCK_REPORT_ACTIONS, + false, + reportErrors, + MOCK_TRANSACTIONS, + MOCK_TRANSACTION_VIOLATIONS, + isReportArchived.current, + ); expect(result).toBe(true); }); @@ -521,10 +635,11 @@ describe('SidebarUtils', () => { reportID: '1', }; const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, {}, MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); expect(result).toBe(false); }); @@ -541,11 +656,12 @@ describe('SidebarUtils', () => { // This report with reportID 5 is already archived from previous tests // where we set reportNameValuePairs with private_isArchived const MOCK_REPORT_ACTIONS: OnyxEntry = {}; + const MOCK_TRANSACTIONS = {}; const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection = {}; // Simulate how components determind if a report is archived by using this hook const {result: isReportArchived} = renderHook(() => useReportIsArchived(MOCK_REPORT?.reportID)); - const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); + const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, {}, MOCK_TRANSACTIONS, MOCK_TRANSACTION_VIOLATIONS, isReportArchived.current); expect(result).toBe(false); }); @@ -617,7 +733,6 @@ describe('SidebarUtils', () => { const result = SidebarUtils.getOptionData({ report, - reportActions, reportAttributes: undefined, reportNameValuePairs: {}, personalDetails: {}, @@ -676,7 +791,6 @@ describe('SidebarUtils', () => { const result = SidebarUtils.getOptionData({ report, - reportActions, reportAttributes: undefined, reportNameValuePairs: {}, personalDetails: {}, @@ -720,7 +834,6 @@ describe('SidebarUtils', () => { report, reportAttributes: undefined, reportNameValuePairs, - reportActions: {}, personalDetails: {}, preferredLocale, policy, @@ -756,7 +869,6 @@ describe('SidebarUtils', () => { report, reportAttributes: undefined, reportNameValuePairs, - reportActions: {}, personalDetails: LHNTestUtils.fakePersonalDetails, preferredLocale, policy, @@ -789,7 +901,6 @@ describe('SidebarUtils', () => { report, reportAttributes: undefined, reportNameValuePairs, - reportActions: {}, personalDetails: {}, preferredLocale, policy, @@ -826,7 +937,6 @@ describe('SidebarUtils', () => { report, reportAttributes: undefined, reportNameValuePairs, - reportActions: {}, personalDetails: {}, preferredLocale, policy, @@ -892,7 +1002,6 @@ describe('SidebarUtils', () => { const result = SidebarUtils.getOptionData({ report, reportAttributes: undefined, - reportActions, reportNameValuePairs: {}, personalDetails: {}, policy: undefined, @@ -935,7 +1044,6 @@ describe('SidebarUtils', () => { const result = SidebarUtils.getOptionData({ report, reportAttributes: undefined, - reportActions, reportNameValuePairs: {}, personalDetails: {}, policy: undefined,