Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions __mocks__/reportData/violations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const receiptErrorsR14932: ReceiptErrors = {
source: CONST.POLICY.ID_FAKE,
filename: CONST.POLICY.ID_FAKE,
action: CONST.POLICY.ID_FAKE,
error: CONST.IOU.RECEIPT_ERROR,
retryParams: {
transactionID: RECEIPT_ERRORS_TRANSACTION_ID_R14932,
source: CONST.POLICY.ID_FAKE,
Expand Down
12 changes: 11 additions & 1 deletion src/hooks/useSidebarOrderedReports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import {deepEqual} from 'fast-equals';
import React, {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import Log from '@libs/Log';
import {getTransactionThreadReportID} from '@libs/MergeTransactionUtils';
import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils';
import {isOneTransactionReport} from '@libs/ReportUtils';
import SidebarUtils from '@libs/SidebarUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -117,7 +119,13 @@ function SidebarOrderedReportsContextProvider({
}
}
if (transactionsUpdates) {
for (const key of Object.values(transactionsUpdates ?? {}).map((transaction) => `${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`)) {
// We need to select the report linked to a transaction, to properly recalculate getReceiptUploadErrorReason, which is the expense report if it is isOneTransactionReport
// or the transaction thread report if it is otherwise.
for (const key of Object.values(transactionsUpdates ?? {}).map((transaction) =>
transaction?.reportID && isOneTransactionReport(chatReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction.reportID}`])
? `${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`
: `${ONYXKEYS.COLLECTION.REPORT}${getTransactionThreadReportID(transaction)}`,
)) {
reportsToUpdate.add(key);
}
}
Expand Down Expand Up @@ -188,6 +196,7 @@ function SidebarOrderedReportsContextProvider({
reportNameValuePairs,
reportAttributes,
draftComments: reportsDrafts,
transactions,
});
} else {
Log.info('[useSidebarOrderedReports] building reportsToDisplay from scratch');
Expand All @@ -199,6 +208,7 @@ function SidebarOrderedReportsContextProvider({
priorityMode,
reportsDrafts,
transactionViolations,
transactions,
reportNameValuePairs,
reportAttributes,
);
Expand Down
29 changes: 28 additions & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
getMostRecentActiveDEWApproveFailedAction,
getMostRecentActiveDEWSubmitFailedAction,
getNumberOfMoneyRequests,
getOneTransactionThreadReportAction,
getOneTransactionThreadReportID,
getOriginalMessage,
getRenamedAction,
Expand Down Expand Up @@ -284,6 +285,7 @@
getTaxAmount,
getTaxCode,
getAmount as getTransactionAmount,
getTransactionID,
getWaypoints,
hasMissingSmartscanFields as hasMissingSmartscanFieldsTransactionUtils,
hasNoticeTypeViolation,
Expand Down Expand Up @@ -1012,7 +1014,7 @@
};

let conciergeReportIDOnyxConnect: OnyxEntry<string>;
Onyx.connect({

Check warning on line 1017 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.CONCIERGE_REPORT_ID,
callback: (value) => {
conciergeReportIDOnyxConnect = value;
Expand All @@ -1020,7 +1022,7 @@
});

const defaultAvatarBuildingIconTestID = 'SvgDefaultAvatarBuilding Icon';
Onyx.connect({

Check warning on line 1025 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (value) => {
// When signed out, val is undefined
Expand All @@ -1038,7 +1040,7 @@
let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
let allPersonalDetailLogins: string[];
let currentUserPersonalDetails: OnyxEntry<PersonalDetails>;
Onyx.connect({

Check warning on line 1043 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
if (currentUserAccountID) {
Expand All @@ -1050,7 +1052,7 @@
});

let allReportsDraft: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 1055 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_DRAFT,
waitForCollectionCallback: true,
callback: (value) => (allReportsDraft = value),
Expand All @@ -1059,7 +1061,7 @@
let allPolicies: OnyxCollection<Policy>;
let hasPolicies: boolean;
let policiesArray: Policy[] = [];
Onyx.connect({

Check warning on line 1064 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -1070,7 +1072,7 @@
});

let allPolicyDrafts: OnyxCollection<Policy>;
Onyx.connect({

Check warning on line 1075 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY_DRAFTS,
waitForCollectionCallback: true,
callback: (value) => (allPolicyDrafts = value),
Expand All @@ -1078,7 +1080,7 @@

let allReports: OnyxCollection<Report>;
let reportsByPolicyID: ReportByPolicyMap;
Onyx.connect({

Check warning on line 1083 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -1114,14 +1116,14 @@
});

let betaConfiguration: OnyxEntry<BetaConfiguration> = {};
Onyx.connect({

Check warning on line 1119 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.BETA_CONFIGURATION,
callback: (value) => (betaConfiguration = value ?? {}),
});

let allTransactions: OnyxCollection<Transaction> = {};
let reportsTransactions: Record<string, Transaction[]> = {};
Onyx.connect({

Check warning on line 1126 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -1147,7 +1149,7 @@
});

let allReportActions: OnyxCollection<ReportActions>;
Onyx.connect({

Check warning on line 1152 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand Down Expand Up @@ -9232,11 +9234,34 @@
return allReportErrors;
}

function getReceiptUploadErrorReason(report: Report, chatReport: OnyxEntry<Report>, reportActions: OnyxEntry<ReportActions>, transactions: OnyxCollection<Transaction>) {
const parentReportAction = getReportAction(report?.parentReportID, report?.parentReportActionID);
const transactionThreadReportAction = getOneTransactionThreadReportAction(report, chatReport, reportActions ?? []);
if (transactionThreadReportAction) {
const transactionID = isMoneyRequestAction(transactionThreadReportAction) ? getOriginalMessage(transactionThreadReportAction)?.IOUTransactionID : undefined;
const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
if (hasReceiptError(transaction)) {
return {
reason: CONST.RBR_REASONS.HAS_ERRORS,
};
}
}
const transactionID = getTransactionID(report);
const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
if (isTransactionThread(parentReportAction) && hasReceiptError(transaction)) {
return {
reason: CONST.RBR_REASONS.HAS_ERRORS,
};
}
return null;
}

function hasReportErrorsOtherThanFailedReceipt(
report: Report,
chatReport: OnyxEntry<Report>,
doesReportHaveViolations: boolean,
transactionViolations: OnyxCollection<TransactionViolation[]>,
transactions: OnyxCollection<Transaction>,
reportAttributes?: ReportAttributesDerivedValue['reports'],
) {
const allReportErrors = reportAttributes?.[report?.reportID]?.reportErrors ?? {};
Expand All @@ -9251,7 +9276,8 @@
doesTransactionThreadReportHasViolations ||
doesReportHaveViolations ||
// eslint-disable-next-line @typescript-eslint/no-deprecated
Object.values(allReportErrors).some((error) => error?.[0] !== translateLocal('iou.error.genericSmartscanFailureMessage'))
Object.values(allReportErrors).some((error) => error?.[0] !== translateLocal('iou.error.genericSmartscanFailureMessage')) ||
!!getReceiptUploadErrorReason(report, chatReport, transactionReportActions, transactions)
);
}

Expand Down Expand Up @@ -13232,6 +13258,7 @@
getReportStatusColorStyle,
getMovedActionMessage,
excludeParticipantsForDisplay,
getReceiptUploadErrorReason,
getAncestors,
// This will be fixed as follow up https://github.com/Expensify/App/pull/75357
// eslint-disable-next-line @typescript-eslint/no-deprecated
Expand Down
36 changes: 10 additions & 26 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import {
getInvoiceCompanyWebsiteUpdateMessage,
getLastVisibleMessage,
getMessageOfOldDotReportAction,
getOneTransactionThreadReportAction,
getOriginalMessage,
getPlaidBalanceFailureMessage,
getPolicyChangeLogAddEmployeeMessage,
Expand Down Expand Up @@ -113,12 +112,10 @@ import {
isActionOfType,
isCardIssuedAction,
isInviteOrRemovedAction,
isMoneyRequestAction,
isOldDotReportAction,
isRenamedAction,
isTagModificationAction,
isTaskAction,
isTransactionThread,
} from './ReportActionsUtils';
import type {OptionData} from './ReportUtils';
import {
Expand All @@ -133,6 +130,7 @@ import {
getMovedTransactionMessage,
getParticipantsAccountIDsForDisplay,
getPolicyName,
getReceiptUploadErrorReason,
getReportDescription,
getReportMetadata,
// eslint-disable-next-line @typescript-eslint/no-deprecated
Expand All @@ -142,7 +140,6 @@ import {
getReportSubtitlePrefix,
getUnreportedTransactionMessage,
getWorkspaceNameUpdatedMessage,
hasReceiptError,
hasReportErrorsOtherThanFailedReceipt,
isAdminRoom,
isAnnounceRoom,
Expand Down Expand Up @@ -176,7 +173,6 @@ import {
shouldReportShowSubscript,
} from './ReportUtils';
import {getTaskReportActionMessage} from './TaskUtils';
import {getTransactionID} from './TransactionUtils';

type WelcomeMessage = {phrase1?: string; messageText?: string; messageHtml?: string};

Expand Down Expand Up @@ -208,6 +204,7 @@ function shouldDisplayReportInLHN(
betas: OnyxEntry<Beta[]>,
transactionViolations: OnyxCollection<TransactionViolation[]>,
draftComment: OnyxEntry<string>,
transactions: OnyxCollection<Transaction>,
isReportArchived?: boolean,
reportAttributes?: ReportAttributesDerivedValue['reports'],
) {
Expand All @@ -226,7 +223,7 @@ function shouldDisplayReportInLHN(
const isFocused = report.reportID === currentReportId;
const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`];
const parentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`];
const hasErrorsOtherThanFailedReceipt = hasReportErrorsOtherThanFailedReceipt(report, chatReport, doesReportHaveViolations, transactionViolations, reportAttributes);
const hasErrorsOtherThanFailedReceipt = hasReportErrorsOtherThanFailedReceipt(report, chatReport, doesReportHaveViolations, transactionViolations, transactions, reportAttributes);
const isReportInAccessible = report?.errorFields?.notFound;
if (isOneTransactionThread(report, parentReport, parentReportAction)) {
return {shouldDisplay: false};
Expand Down Expand Up @@ -278,6 +275,7 @@ function getReportsToDisplayInLHN(
priorityMode: OnyxEntry<PriorityMode>,
draftComments: OnyxCollection<string>,
transactionViolations: OnyxCollection<TransactionViolation[]>,
transactions: OnyxCollection<Transaction>,
reportNameValuePairs?: OnyxCollection<ReportNameValuePairs>,
reportAttributes?: ReportAttributesDerivedValue['reports'],
) {
Expand All @@ -300,6 +298,7 @@ function getReportsToDisplayInLHN(
betas,
transactionViolations,
reportDraftComment,
transactions,
isArchivedReport(reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]),
reportAttributes,
);
Expand All @@ -325,6 +324,7 @@ type UpdateReportsToDisplayInLHNProps = {
reportNameValuePairs?: OnyxCollection<ReportNameValuePairs>;
reportAttributes?: ReportAttributesDerivedValue['reports'];
draftComments: OnyxCollection<string>;
transactions: OnyxCollection<Transaction>;
};

function updateReportsToDisplayInLHN({
Expand All @@ -338,6 +338,7 @@ function updateReportsToDisplayInLHN({
reportNameValuePairs,
reportAttributes,
draftComments,
transactions,
}: UpdateReportsToDisplayInLHNProps) {
const displayedReportsCopy = {...displayedReports};
for (const reportID of updatedReportsKeys) {
Expand All @@ -359,6 +360,7 @@ function updateReportsToDisplayInLHN({
betas,
transactionViolations,
reportDraftComment,
transactions,
isArchivedReport(reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`] ?? {}),
reportAttributes,
);
Expand Down Expand Up @@ -618,27 +620,8 @@ function getReasonAndReportActionThatHasRedBrickRoad(
reason: CONST.RBR_REASONS.HAS_VIOLATIONS,
};
}
const parentReportAction = getReportAction(report?.parentReportID, report?.parentReportActionID);
const transactionThreadReportAction = getOneTransactionThreadReportAction(report, chatReport, reportActions ?? []);

if (transactionThreadReportAction) {
const transactionID = isMoneyRequestAction(transactionThreadReportAction) ? getOriginalMessage(transactionThreadReportAction)?.IOUTransactionID : undefined;
const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
if (hasReceiptError(transaction)) {
return {
reason: CONST.RBR_REASONS.HAS_ERRORS,
};
}
}
const transactionID = getTransactionID(report);
const transaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
if (isTransactionThread(parentReportAction) && hasReceiptError(transaction)) {
return {
reason: CONST.RBR_REASONS.HAS_ERRORS,
};
}

return null;
return getReceiptUploadErrorReason(report, chatReport, reportActions, transactions);
}

function shouldShowRedBrickRoad(
Expand Down Expand Up @@ -1284,4 +1267,5 @@ export default {
shouldShowRedBrickRoad,
getReportsToDisplayInLHN,
updateReportsToDisplayInLHN,
shouldDisplayReportInLHN,
};
3 changes: 3 additions & 0 deletions src/types/onyx/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ type ReceiptError = {

/** Parameters required to retry the failed action */
retryParams: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt;

/** The type of receipt error */
error: typeof CONST.IOU.RECEIPT_ERROR;
};

/** Collection of receipt errors, indexed by a UNIX timestamp of when the error occurred */
Expand Down
4 changes: 2 additions & 2 deletions tests/perf-test/SidebarUtils.perf-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ describe('SidebarUtils', () => {

test('[SidebarUtils] getReportsToDisplayInLHN on 15k reports for default priorityMode', async () => {
await waitForBatchedUpdates();
await measureFunction(() => SidebarUtils.getReportsToDisplayInLHN(currentReportId, allReports, mockedBetas, policies, CONST.PRIORITY_MODE.DEFAULT, {}, transactionViolations));
await measureFunction(() => SidebarUtils.getReportsToDisplayInLHN(currentReportId, allReports, mockedBetas, policies, CONST.PRIORITY_MODE.DEFAULT, {}, transactionViolations, {}));
});

test('[SidebarUtils] getReportsToDisplayInLHN on 15k reports for GSD priorityMode', async () => {
await waitForBatchedUpdates();
await measureFunction(() => SidebarUtils.getReportsToDisplayInLHN(currentReportId, allReports, mockedBetas, policies, CONST.PRIORITY_MODE.GSD, {}, transactionViolations));
await measureFunction(() => SidebarUtils.getReportsToDisplayInLHN(currentReportId, allReports, mockedBetas, policies, CONST.PRIORITY_MODE.GSD, {}, transactionViolations, {}));
});
});
Loading
Loading