From 0bc19ad7452b632a2ba600bb5de19aebe61df406 Mon Sep 17 00:00:00 2001 From: Jakub Korytko Date: Mon, 14 Apr 2025 11:37:37 +0200 Subject: [PATCH 1/5] Clean-up reports mockData & storybook config --- .storybook/webpack.config.ts | 7 +- .storybook/webpackMockPaths.ts | 11 + __mocks__/reportData/actions.ts | 89 +++++ __mocks__/reportData/personalDetails.ts | 68 ++++ __mocks__/reportData/reports.ts | 104 +++++ __mocks__/reportData/transactions.ts | 79 ++++ __mocks__/reportData/violations.ts | 38 ++ .../MoneyRequestReportPreview.stories.tsx | 30 +- .../TransactionPreviewContent.stories.tsx | 34 +- src/stories/mockData/transactions.ts | 354 ------------------ tests/ui/MoneyRequestReportPreview.test.tsx | 13 +- tests/unit/libs/MoneyRequestReportUtils.ts | 17 +- 12 files changed, 441 insertions(+), 403 deletions(-) create mode 100644 .storybook/webpackMockPaths.ts create mode 100644 __mocks__/reportData/actions.ts create mode 100644 __mocks__/reportData/personalDetails.ts create mode 100644 __mocks__/reportData/reports.ts create mode 100644 __mocks__/reportData/transactions.ts create mode 100644 __mocks__/reportData/violations.ts delete mode 100644 src/stories/mockData/transactions.ts diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts index fc94d7e07bea2..581f9231129be 100644 --- a/.storybook/webpack.config.ts +++ b/.storybook/webpack.config.ts @@ -8,6 +8,7 @@ import dotenv from 'dotenv'; import path from 'path'; import {DefinePlugin} from 'webpack'; import type {Configuration, RuleSetRule} from 'webpack'; +import webpackMockPaths from './webpackMockPaths'; type CustomWebpackConfig = { resolve: { @@ -54,11 +55,7 @@ const webpackConfig = ({config}: {config: Configuration}) => { } config.resolve.alias = { - 'react-native-config': 'react-web-config', - 'react-native$': 'react-native-web', - '@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.ts'), - '@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'), - '@libs/TransactionPreviewUtils': path.resolve(__dirname, '../src/libs/__mocks__/TransactionPreviewUtils.ts'), + ...webpackMockPaths, ...custom.resolve.alias, }; diff --git a/.storybook/webpackMockPaths.ts b/.storybook/webpackMockPaths.ts new file mode 100644 index 0000000000000..78a6b8dbda908 --- /dev/null +++ b/.storybook/webpackMockPaths.ts @@ -0,0 +1,11 @@ +import path from 'path'; + +/* eslint-disable @typescript-eslint/naming-convention */ +export default { + 'react-native-config': 'react-web-config', + 'react-native$': 'react-native-web', + '@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.ts'), + '@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'), + '@libs/TransactionPreviewUtils': path.resolve(__dirname, '../src/libs/__mocks__/TransactionPreviewUtils.ts'), +}; +/* eslint-enable @typescript-eslint/naming-convention */ diff --git a/__mocks__/reportData/actions.ts b/__mocks__/reportData/actions.ts new file mode 100644 index 0000000000000..795dbc1617936 --- /dev/null +++ b/__mocks__/reportData/actions.ts @@ -0,0 +1,89 @@ +import CONST from '@src/CONST'; +import type {OriginalMessageIOU, ReportAction} from '@src/types/onyx'; + +const usersIDs = [15593135, 51760358, 26502375]; +const amount = 10402; +const currency = CONST.CURRENCY.USD; + +const REPORT_R98765 = { + IOUReportID: 'IOU_REPORT_ID_R98765', + IOUTransactionID: 'TRANSACTION_ID_R98765', + reportActionID: 'REPORT_ACTION_ID_R98765', + childReportID: 'CHILD_REPORT_ID_R98765', +}; + +const REPORT_R14932 = { + IOUReportID: 'IOU_REPORT_ID_R14932', + IOUTransactionID: 'TRANSACTION_ID_R14932', + reportActionID: 'REPORT_ACTION_ID_R14932', + childReportID: 'CHILD_REPORT_ID_R14932', +}; + +const originalMessageR14932: OriginalMessageIOU = { + currency, + amount, + IOUReportID: REPORT_R14932.IOUReportID, + IOUTransactionID: REPORT_R14932.IOUTransactionID, + participantAccountIDs: usersIDs, + type: CONST.IOU.TYPE.CREATE, + lastModified: '2025-02-14 08:12:05.165', + comment: '', +}; + +const message = [ + { + type: CONST.REPORT.MESSAGE.TYPE.COMMENT, + html: '$0.01 expense', + text: '$0.01 expense', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + deleted: '', + }, +]; + +const person = [ + { + type: 'TEXT', + style: 'strong', + text: 'John Smith', + }, +]; + +const actionR14932: ReportAction = { + person, + message, + reportActionID: REPORT_R14932.reportActionID, + childReportID: REPORT_R14932.childReportID, + originalMessage: originalMessageR14932, + actorAccountID: usersIDs.at(0), + actionName: CONST.REPORT.ACTIONS.TYPE.IOU, + childType: CONST.REPORT.TYPE.CHAT, + childReportName: 'Expense #R14932', + created: '2025-02-14 08:12:05.165', +}; + +const originalMessageR98765: OriginalMessageIOU = { + amount, + currency, + IOUReportID: REPORT_R98765.IOUReportID, + IOUTransactionID: REPORT_R98765.IOUTransactionID, + participantAccountIDs: usersIDs, + type: CONST.IOU.TYPE.CREATE, + comment: '', + lastModified: '2025-02-20 08:10:05.165', +}; + +const actionR98765: ReportAction = { + message, + person, + reportActionID: REPORT_R98765.reportActionID, + childReportID: REPORT_R98765.childReportID, + originalMessage: originalMessageR98765, + actorAccountID: usersIDs.at(0), + childType: CONST.REPORT.TYPE.CHAT, + actionName: CONST.REPORT.ACTIONS.TYPE.IOU, + created: '2025-02-14 08:12:05.165', +}; + +export {actionR14932, actionR98765}; diff --git a/__mocks__/reportData/personalDetails.ts b/__mocks__/reportData/personalDetails.ts new file mode 100644 index 0000000000000..b3c6179497f6c --- /dev/null +++ b/__mocks__/reportData/personalDetails.ts @@ -0,0 +1,68 @@ +import type {PersonalDetailsList} from '@src/types/onyx'; + +const usersIDs = [15593135, 51760358, 26502375] as const; + +const personalDetails: PersonalDetailsList = { + [usersIDs[0]]: { + accountID: usersIDs[0], + avatar: '@assets/images/avatars/user/default-avatar_1.svg', + firstName: 'John', + lastName: 'Smith', + status: { + clearAfter: '', + emojiCode: '🚲', + text: '0% cycling in Canary islands', + }, + displayName: 'John Smith', + login: 'johnsmith@mail.com', + pronouns: '__predefined_heHimHis', + timezone: { + automatic: true, + selected: 'Europe/Luxembourg', + }, + phoneNumber: '11111111', + validated: true, + }, + [usersIDs[1]]: { + accountID: usersIDs[1], + avatar: '@assets/images/avatars/user/default-avatar_2.svg', + firstName: 'Ted', + lastName: 'Kowalski', + status: { + clearAfter: '', + emojiCode: '🚲', + text: '0% cycling in Canary islands', + }, + displayName: 'Ted Kowalski', + login: 'tedkowalski@mail.com', + pronouns: '__predefined_heHimHis', + timezone: { + automatic: true, + selected: 'Europe/Warsaw', + }, + phoneNumber: '22222222', + validated: true, + }, + [usersIDs[2]]: { + accountID: usersIDs[2], + avatar: '@assets/images/avatars/user/default-avatar_3.svg', + firstName: 'Jane', + lastName: 'Doe', + status: { + clearAfter: '', + emojiCode: '🚲', + text: '0% cycling in Canary islands', + }, + displayName: 'Jane Doe', + login: 'janedoe@mail.com', + pronouns: '__predefined_sheHerHers', + timezone: { + automatic: true, + selected: 'Europe/London', + }, + phoneNumber: '33333333', + validated: true, + }, +}; + +export default personalDetails; diff --git a/__mocks__/reportData/reports.ts b/__mocks__/reportData/reports.ts new file mode 100644 index 0000000000000..59f5e0759e5a3 --- /dev/null +++ b/__mocks__/reportData/reports.ts @@ -0,0 +1,104 @@ +import CONST from '@src/CONST'; +import type {Report} from '@src/types/onyx'; + +const usersIDs = [15593135, 51760358, 26502375]; +const amount = 10402; +const currency = CONST.CURRENCY.USD; + +const REPORT_ID_R14932 = 'REPORT_ID_R14932'; +const CHAT_REPORT_ID_R14932 = 'CHAT_REPORT_ID_R14932'; +const IOU_REPORT_ID_R14932 = 'IOU_REPORT_ID_R14932'; +const PARENT_REPORT_ACTION_ID_R14932 = 'PARENT_ACTION_ID_R14932'; +const PARENT_REPORT_ID_R14932 = 'PARENT_REPORT_ID_R14932'; +const LAST_MESSAGE_R14932 = 'LAST_MESSAGE_R14932'; + +const participants = usersIDs.reduce((prev, userID) => { + return { + [userID]: { + notificationPreference: 'always', + }, + }; +}, {}); + +const iouReportR14932: Report = { + currency, + participants, + total: amount, + unheldTotal: amount, + chatReportID: CHAT_REPORT_ID_R14932, + lastMessageHtml: LAST_MESSAGE_R14932, + lastMessageText: LAST_MESSAGE_R14932, + parentReportActionID: PARENT_REPORT_ACTION_ID_R14932, + parentReportID: PARENT_REPORT_ID_R14932, + reportID: REPORT_ID_R14932, + lastActorAccountID: usersIDs.at(0), + ownerAccountID: usersIDs.at(0), + managerID: usersIDs.at(1), + permissions: [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE], + policyID: CONST.POLICY.ID_FAKE, + reportName: CONST.REPORT.ACTIONS.TYPE.IOU, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + type: CONST.REPORT.TYPE.EXPENSE, + writeCapability: CONST.REPORT.WRITE_CAPABILITIES.ALL, + lastActionType: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, + chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + hasOutstandingChildRequest: false, + hasOutstandingChildTask: false, + hasParentAccess: true, + isCancelledIOU: false, + isOwnPolicyExpenseChat: false, + isPinned: false, + isWaitingOnBankAccount: false, + lastReadTime: '2025-03-07 07:23:39.335', + lastVisibleActionCreated: '2025-03-07 07:23:39.335', + lastVisibleActionLastModified: '2025-03-07 07:23:39.335', + lastReadSequenceNumber: 0, + unheldNonReimbursableTotal: 0, + nonReimbursableTotal: 0, + errorFields: {}, + welcomeMessage: '', + description: '', + oldPolicyName: '', +}; + +const chatReportR14932: Report = { + currency, + participants, + lastMessageText: LAST_MESSAGE_R14932, + reportID: REPORT_ID_R14932, + iouReportID: IOU_REPORT_ID_R14932, + lastActorAccountID: usersIDs.at(0), + ownerAccountID: usersIDs.at(0), + managerID: usersIDs.at(1), + total: amount, + unheldTotal: amount, + chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + policyID: CONST.POLICY.ID_FAKE, + reportName: CONST.REPORT.DEFAULT_REPORT_NAME, + lastActionType: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, + writeCapability: CONST.REPORT.WRITE_CAPABILITIES.ALL, + permissions: [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE], + type: CONST.REPORT.TYPE.CHAT, + lastMessageHtml: ` `, + lastReadTime: '2025-03-11 08:51:38.736', + lastVisibleActionCreated: '2025-03-11 08:47:56.654', + lastVisibleActionLastModified: '2025-03-11 08:47:56.654', + hasOutstandingChildRequest: false, + hasOutstandingChildTask: false, + isCancelledIOU: false, + isOwnPolicyExpenseChat: false, + isPinned: false, + isWaitingOnBankAccount: false, + lastReadSequenceNumber: 0, + unheldNonReimbursableTotal: 0, + stateNum: 0, + statusNum: 0, + nonReimbursableTotal: 0, + errorFields: {}, + description: '', + oldPolicyName: '', + welcomeMessage: '', +}; + +export {chatReportR14932, iouReportR14932}; diff --git a/__mocks__/reportData/transactions.ts b/__mocks__/reportData/transactions.ts new file mode 100644 index 0000000000000..4dc0cfdd19021 --- /dev/null +++ b/__mocks__/reportData/transactions.ts @@ -0,0 +1,79 @@ +import CONST from '@src/CONST'; +import type {Transaction} from '@src/types/onyx'; + +const amount = 10402; +const currency = CONST.CURRENCY.USD; +const REPORT_ID_R14932 = 'REPORT_ID_R14932'; +const TRANSACTION_ID_R14932 = 'TRANSACTION_ID_R14932'; +const REPORT_ID_R98765 = 'REPORT_ID_R98765'; +const TRANSACTION_ID_R98765 = 'TRANSACTION_ID_R98765'; + +const receiptR14932 = { + state: CONST.IOU.RECEIPT_STATE.OPEN, + source: 'mockData/eReceiptBGs/eReceiptBG_pink.png', +}; + +const transactionR14932: Transaction = { + amount, + currency, + cardName: CONST.EXPENSE.TYPE.CASH_CARD_NAME, + transactionID: TRANSACTION_ID_R14932, + reportID: REPORT_ID_R14932, + status: CONST.TRANSACTION.STATUS.POSTED, + receipt: receiptR14932, + merchant: 'Acme', + filename: 'test.html', + created: '2025-02-14', + inserted: '2025-02-14 08:12:19', + billable: false, + managedCard: false, + reimbursable: true, + hasEReceipt: true, + cardID: 0, + modifiedAmount: 0, + originalAmount: 0, + comment: {}, + bank: '', + cardNumber: '', + category: '', + modifiedCreated: '', + modifiedCurrency: '', + modifiedMerchant: '', + originalCurrency: '', + parentTransactionID: '', + posted: '', + tag: '', +}; + +const transactionR98765: Transaction = { + currency, + amount, + transactionID: TRANSACTION_ID_R98765, + reportID: REPORT_ID_R98765, + status: CONST.TRANSACTION.STATUS.POSTED, + cardName: CONST.EXPENSE.TYPE.CASH_CARD_NAME, + created: '2025-02-14', + inserted: '2025-02-14 08:12:19', + merchant: 'Acme', + reimbursable: true, + hasEReceipt: true, + managedCard: false, + billable: false, + modifiedAmount: 0, + cardID: 0, + originalAmount: 0, + comment: {}, + bank: '', + cardNumber: '', + category: '', + filename: '', + modifiedCreated: '', + modifiedCurrency: '', + modifiedMerchant: '', + originalCurrency: '', + parentTransactionID: '', + posted: '', + tag: '', +}; + +export {transactionR14932, transactionR98765}; diff --git a/__mocks__/reportData/violations.ts b/__mocks__/reportData/violations.ts new file mode 100644 index 0000000000000..f1fce6ed8021d --- /dev/null +++ b/__mocks__/reportData/violations.ts @@ -0,0 +1,38 @@ +import CONST from '@src/CONST'; +import type {TransactionViolations} from '@src/types/onyx'; +import type {ReceiptErrors} from '@src/types/onyx/Transaction'; + +const RECEIPT_ERRORS_ID_R14932 = 1201421; +const RECEIPT_ERRORS_TRANSACTION_ID_R14932 = 'IOU_TRANSACTION_ID_R14932'; + +const violationsR14932: TransactionViolations = [ + { + name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION, + type: CONST.VIOLATION_TYPES.VIOLATION, + showInReview: true, + }, + { + name: CONST.VIOLATIONS.MISSING_CATEGORY, + type: CONST.VIOLATION_TYPES.VIOLATION, + showInReview: true, + }, + { + name: CONST.VIOLATIONS.FIELD_REQUIRED, + type: CONST.VIOLATION_TYPES.VIOLATION, + showInReview: true, + }, +]; + +const receiptErrorsR14932: ReceiptErrors = { + [RECEIPT_ERRORS_ID_R14932]: { + source: CONST.POLICY.ID_FAKE, + filename: CONST.POLICY.ID_FAKE, + action: CONST.POLICY.ID_FAKE, + retryParams: { + transactionID: RECEIPT_ERRORS_TRANSACTION_ID_R14932, + source: CONST.POLICY.ID_FAKE, + }, + }, +}; + +export {receiptErrorsR14932, violationsR14932}; diff --git a/src/stories/MoneyRequestReportPreview.stories.tsx b/src/stories/MoneyRequestReportPreview.stories.tsx index 33858c3840ffe..83071369dbbf6 100644 --- a/src/stories/MoneyRequestReportPreview.stories.tsx +++ b/src/stories/MoneyRequestReportPreview.stories.tsx @@ -14,7 +14,11 @@ import sizing from '@styles/utils/sizing'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; import type {Transaction} from '@src/types/onyx'; -import {action, chatReport, iouReport, personalDetails, receiptErrors, transaction, violations} from './mockData/transactions'; +import {actionR14932} from '../../__mocks__/reportData/actions'; +import personalDetails from '../../__mocks__/reportData/personalDetails'; +import {chatReportR14932, iouReportR14932} from '../../__mocks__/reportData/reports'; +import {transactionR14932} from '../../__mocks__/reportData/transactions'; +import {receiptErrorsR14932, violationsR14932} from '../../__mocks__/reportData/violations'; /** * We use the Component Story Format for writing stories. Follow the docs here: @@ -23,25 +27,25 @@ import {action, chatReport, iouReport, personalDetails, receiptErrors, transacti */ const mockTransactionsMedium = Array.from({length: 2}).map((item, index) => { - return {...transaction, transactionID: `${index}`}; + return {...transactionR14932, transactionID: `${transactionR14932.transactionID}${index}`}; }); const mockTransactionsBig = Array.from({length: 12}).map((item, index) => { - return {...transaction, transactionID: `${index}`}; + return {...transactionR14932, transactionID: `${transactionR14932.transactionID}${index}`}; }); const style = getMoneyRequestReportPreviewStyle(false); const mockRenderItem: ListRenderItem = ({item}) => ( undefined} offlineWithFeedbackOnClose={() => undefined} onPreviewPressed={() => {}} @@ -114,12 +118,12 @@ export default { }, }, args: { - action, - chatReport, + action: actionR14932, + chatReport: chatReportR14932, policy: undefined, - iouReport, + iouReport: iouReportR14932, transactions: mockTransactionsMedium, - violations, + violations: violationsR14932, invoiceReceiverPersonalDetail: undefined, invoiceReceiverPolicy: undefined, renderItem: mockRenderItem, @@ -162,7 +166,7 @@ DarkTheme.parameters = { }; OneTransaction.args = { - transactions: [transaction], + transactions: [transactionR14932], }; ManyTransactions.parameters = { @@ -172,7 +176,7 @@ ManyTransactions.parameters = { HasErrors.args = { transactions: mockTransactionsMedium.map((t) => ({ ...t, - errors: receiptErrors, + errors: receiptErrorsR14932, })), }; diff --git a/src/stories/TransactionPreviewContent.stories.tsx b/src/stories/TransactionPreviewContent.stories.tsx index df08d7e8ec662..2044013675408 100644 --- a/src/stories/TransactionPreviewContent.stories.tsx +++ b/src/stories/TransactionPreviewContent.stories.tsx @@ -9,12 +9,16 @@ import ThemeStylesProvider from '@components/ThemeStylesProvider'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; -import {action, chatReport, iouReport, personalDetails, transaction, violations} from './mockData/transactions'; +import {actionR14932} from '../../__mocks__/reportData/actions'; +import personalDetails from '../../__mocks__/reportData/personalDetails'; +import {chatReportR14932, iouReportR14932} from '../../__mocks__/reportData/reports'; +import {transactionR14932} from '../../__mocks__/reportData/transactions'; +import {violationsR14932} from '../../__mocks__/reportData/violations'; const veryLongString = 'W'.repeat(1000); const veryBigNumber = Number('9'.repeat(12)); const modifiedTransaction = ({category, tag, merchant = '', amount = 1000, hold = false}: {category?: string; tag?: string; merchant?: string; amount?: number; hold?: boolean}) => ({ - ...transaction, + ...transactionR14932, category, tag, merchant, @@ -23,8 +27,8 @@ const modifiedTransaction = ({category, tag, merchant = '', amount = 1000, hold hold: hold ? 'true' : undefined, }, }); -const iouReportWithModifiedType = (type: string) => ({...iouReport, type}); -const actionWithModifiedPendingAction = (pendingAction: PendingAction) => ({...action, pendingAction}); +const iouReportWithModifiedType = (type: string) => ({...iouReportR14932, type}); +const actionWithModifiedPendingAction = (pendingAction: PendingAction) => ({...actionR14932, pendingAction}); const disabledProperties = [ 'onPreviewPressed', @@ -66,19 +70,19 @@ const transactionsMap = { const violationsMap = { None: [], - Duplicate: [violations.at(0)], - 'Missing Category': [violations.at(1)], - 'Field Required': [violations.at(2)], + Duplicate: [violationsR14932.at(0)], + 'Missing Category': [violationsR14932.at(1)], + 'Field Required': [violationsR14932.at(2)], }; const actionMap = { 'Pending delete': actionWithModifiedPendingAction(CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE), - 'No pending action': action, + 'No pending action': actionR14932, }; const iouReportMap = { IOU: iouReportWithModifiedType(CONST.REPORT.TYPE.IOU), - 'Normal report': iouReport, + 'Normal report': iouReportR14932, }; /* eslint-enable @typescript-eslint/naming-convention */ @@ -93,13 +97,13 @@ const story: Meta = { title: 'Components/TransactionPreview', component: TransactionPreviewContent, args: { - action, + action: actionR14932, isWhisper: false, isHovered: false, - chatReport, + chatReport: chatReportR14932, personalDetails, - iouReport, - transaction, + iouReport: iouReportR14932, + transaction: transactionR14932, violations: [], showContextMenu: () => undefined, offlineWithFeedbackOnClose(): void {}, @@ -112,7 +116,7 @@ const story: Meta = { walletTermsErrors: undefined, routeName: SCREENS.TRANSACTION_DUPLICATE.REVIEW, shouldHideOnDelete: false, - wrapperStyle: {width: 256}, + wrapperStyle: {width: 303}, }, argTypes: { ...disabledProperties, @@ -166,7 +170,7 @@ KeepButtonCategoriesAndTag.args = { KeepButtonRBRCategoriesAndTag.args = { ...KeepButtonCategoriesAndTag.args, - violations, + violations: violationsR14932, transaction: modifiedTransaction({...storiesTransactionData, hold: true}), }; diff --git a/src/stories/mockData/transactions.ts b/src/stories/mockData/transactions.ts deleted file mode 100644 index b228c404edba8..0000000000000 --- a/src/stories/mockData/transactions.ts +++ /dev/null @@ -1,354 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import CONST from '@src/CONST'; -import type {OriginalMessageIOU, PersonalDetailsList, Report, ReportAction, Transaction, TransactionViolations} from '@src/types/onyx'; -import type {ReceiptErrors} from '@src/types/onyx/Transaction'; - -const amount = 1000; -const currency = CONST.CURRENCY.USD; - -const REPORT_ID_456 = 'R98765'; -const REPORT_ID_111 = '1111111111111111'; - -const personalDetails: PersonalDetailsList = { - 11111111: { - accountID: 11111111, - avatar: '@assets/images/avatars/user/default-avatar_1.svg', - firstName: 'John', - lastName: 'Smith', - status: { - clearAfter: '', - emojiCode: '🚲', - text: '0% cycling in Canary islands', - }, - displayName: 'John Smith', - login: 'johnsmith@mail.com', - pronouns: '__predefined_heHimHis', - timezone: { - automatic: true, - selected: 'Europe/Luxembourg', - }, - phoneNumber: '11111111', - validated: true, - }, - 22222222: { - accountID: 22222222, - avatar: '@assets/images/avatars/user/default-avatar_2.svg', - firstName: 'Ted', - lastName: 'Kowalski', - status: { - clearAfter: '', - emojiCode: '🚲', - text: '0% cycling in Canary islands', - }, - displayName: 'Ted Kowalski', - login: 'tedkowalski@mail.com', - pronouns: '__predefined_heHimHis', - timezone: { - automatic: true, - selected: 'Europe/Warsaw', - }, - phoneNumber: '22222222', - validated: true, - }, - 33333333: { - accountID: 33333333, - avatar: '@assets/images/avatars/user/default-avatar_3.svg', - firstName: 'Jane', - lastName: 'Doe', - status: { - clearAfter: '', - emojiCode: '🚲', - text: '0% cycling in Canary islands', - }, - displayName: 'Jane Doe', - login: 'janedoe@mail.com', - pronouns: '__predefined_sheHerHers', - timezone: { - automatic: true, - selected: 'Europe/London', - }, - phoneNumber: '33333333', - validated: true, - }, -}; - -const iouReport: Report = { - chatReportID: REPORT_ID_111, - chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, - currency, - description: '', - errorFields: {}, - hasOutstandingChildRequest: false, - hasOutstandingChildTask: false, - hasParentAccess: true, - isCancelledIOU: false, - isOwnPolicyExpenseChat: false, - isPinned: false, - isWaitingOnBankAccount: false, - lastActionType: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, - lastActorAccountID: 11111111, - lastMessageHtml: 'abc', - lastMessageText: 'abc', - lastReadSequenceNumber: 0, - lastReadTime: '2025-03-07 07:23:39.335', - lastVisibleActionCreated: '2025-03-07 07:23:39.335', - lastVisibleActionLastModified: '2025-03-07 07:23:39.335', - managerID: 22222222, - nonReimbursableTotal: 0, - oldPolicyName: '', - ownerAccountID: 11111111, - parentReportActionID: '1111111111111111111', - parentReportID: '1111111111111111', - participants: { - '11111111': { - notificationPreference: 'always', - }, - '22222222': { - notificationPreference: 'always', - }, - '33333333': { - notificationPreference: 'always', - }, - }, - permissions: [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE], - policyID: CONST.POLICY.ID_FAKE, - reportID: '1111111111111111', - reportName: 'IOU', - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - statusNum: CONST.REPORT.STATUS_NUM.OPEN, - total: 112298, - // type: CONST.REPORT.TYPE.IOU, - type: CONST.REPORT.TYPE.EXPENSE, - unheldNonReimbursableTotal: 0, - unheldTotal: 112298, - welcomeMessage: '', - writeCapability: CONST.REPORT.WRITE_CAPABILITIES.ALL, -}; - -const chatReport: Report = { - chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, - currency, - description: '', - errorFields: {}, - hasOutstandingChildRequest: false, - hasOutstandingChildTask: false, - isCancelledIOU: false, - isOwnPolicyExpenseChat: false, - isPinned: false, - isWaitingOnBankAccount: false, - lastActionType: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, - lastActorAccountID: 11111111, - lastMessageHtml: ' ', - lastMessageText: 'Test abc', - lastReadSequenceNumber: 0, - lastReadTime: '2025-03-11 08:51:38.736', - lastVisibleActionCreated: '2025-03-11 08:47:56.654', - lastVisibleActionLastModified: '2025-03-11 08:47:56.654', - nonReimbursableTotal: 0, - oldPolicyName: '', - ownerAccountID: 11111111, - participants: { - '11111111': { - notificationPreference: 'always', - }, - '22222222': { - notificationPreference: 'always', - }, - '33333333': { - notificationPreference: 'always', - }, - }, - permissions: ['read', 'write'], - policyID: CONST.POLICY.ID_FAKE, - reportID: REPORT_ID_111, - reportName: 'Chat Report', - stateNum: 0, - statusNum: 0, - total: 100, - type: 'chat', - unheldNonReimbursableTotal: 0, - unheldTotal: 0, - welcomeMessage: '', - writeCapability: CONST.REPORT.WRITE_CAPABILITIES.ALL, - iouReportID: REPORT_ID_111, - managerID: 0, -}; - -const transaction: Transaction = { - amount, - bank: '', - billable: false, - cardID: 0, - cardName: 'Cash Expense', - cardNumber: '', - category: '', - comment: {}, - created: '2025-02-14', - currency, - filename: 'test.html', - inserted: '2025-02-14 08:12:19', - managedCard: false, - merchant: 'Acme', - modifiedAmount: 0, - modifiedCreated: '', - modifiedCurrency: '', - modifiedMerchant: '', - originalAmount: 0, - originalCurrency: '', - parentTransactionID: '', - posted: '', - receipt: { - state: CONST.IOU.RECEIPT_STATE.OPEN, - source: 'mockData/eReceiptBGs/eReceiptBG_pink.png', - }, - reimbursable: true, - reportID: '1111111111111111', - status: CONST.TRANSACTION.STATUS.POSTED, - tag: '', - transactionID: '1111111111111111111', - hasEReceipt: true, -}; - -const fakeTransaction456: Transaction = { - amount, - transactionID: 'trsx456', - bank: '', - billable: false, - cardID: 0, - cardName: 'Cash Expense', - cardNumber: '', - category: '', - comment: {}, - created: '2025-02-14', - currency, - filename: '', - inserted: '2025-02-14 08:12:19', - managedCard: false, - merchant: 'Acme', - modifiedAmount: 0, - modifiedCreated: '', - modifiedCurrency: '', - modifiedMerchant: '', - originalAmount: 0, - originalCurrency: '', - parentTransactionID: '', - posted: '', - reimbursable: true, - reportID: '111111111111111', - status: CONST.TRANSACTION.STATUS.POSTED, - tag: '', - hasEReceipt: true, -}; - -const violations: TransactionViolations = [ - { - name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION, - type: CONST.VIOLATION_TYPES.VIOLATION, - showInReview: true, - }, - { - name: CONST.VIOLATIONS.MISSING_CATEGORY, - type: CONST.VIOLATION_TYPES.VIOLATION, - showInReview: true, - }, - { - name: CONST.VIOLATIONS.FIELD_REQUIRED, - type: CONST.VIOLATION_TYPES.VIOLATION, - showInReview: true, - }, -]; - -const originalMessage: OriginalMessageIOU = { - IOUReportID: '1111111111111111', - IOUTransactionID: '590639150582440369', - amount, - comment: '', - currency, - lastModified: '2025-02-14 08:12:05.165', - participantAccountIDs: [11111111, 22222222], - type: 'create', -}; - -const fakeOriginalMessage456: OriginalMessageIOU = { - IOUReportID: 'rep456', - IOUTransactionID: 'trsx456', - amount, - comment: '', - currency, - lastModified: '2025-02-20 08:10:05.165', - participantAccountIDs: [11111111, 22222222], - type: 'create', -}; - -const action: ReportAction = { - reportActionID: '1111111111111111111', - message: [ - { - type: CONST.REPORT.MESSAGE.TYPE.COMMENT, - html: '$0.01 expense', - text: '$0.01 expense', - isEdited: false, - whisperedTo: [], - isDeletedParentAction: false, - deleted: '', - }, - ], - actionName: CONST.REPORT.ACTIONS.TYPE.IOU, - originalMessage, - childReportID: REPORT_ID_111, - childReportName: 'Expense #123456789', - created: '2025-02-14 08:12:05.165', - actorAccountID: 11111111, - childType: 'chat', - person: [ - { - type: 'TEXT', - style: 'strong', - text: 'John Smith', - }, - ], -}; - -const receiptErrors: ReceiptErrors = { - '1201421': { - source: 'fake', - filename: 'fake', - action: 'fake', - retryParams: { - transactionID: '1111111111111111111', - source: 'fake', - }, - }, -}; - -/* eslint-enable @typescript-eslint/naming-convention */ - -const fakeAction456: ReportAction = { - reportActionID: 'ra456', - message: [ - { - type: CONST.REPORT.MESSAGE.TYPE.COMMENT, - html: '$0.01 expense', - text: '$0.01 expense', - isEdited: false, - whisperedTo: [], - isDeletedParentAction: false, - deleted: '', - }, - ], - actionName: 'IOU', - originalMessage: fakeOriginalMessage456, - childReportID: REPORT_ID_456, - created: '2025-02-14 08:12:05.165', - actorAccountID: 11111111, - childType: 'chat', - person: [ - { - type: 'TEXT', - style: 'strong', - text: 'John Smith', - }, - ], -}; - -export {personalDetails, iouReport, chatReport, transaction, violations, action, fakeAction456, fakeTransaction456, receiptErrors}; diff --git a/tests/ui/MoneyRequestReportPreview.test.tsx b/tests/ui/MoneyRequestReportPreview.test.tsx index 925dc3d64f4bb..f8be907b2d43c 100644 --- a/tests/ui/MoneyRequestReportPreview.test.tsx +++ b/tests/ui/MoneyRequestReportPreview.test.tsx @@ -19,19 +19,16 @@ import CONST from '@src/CONST'; import * as ReportActionUtils from '@src/libs/ReportActionsUtils'; import * as ReportUtils from '@src/libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import { - action as mockAction, - chatReport as mockChatReport, - iouReport as mockIOUReport, - transaction as mockTransaction, - violations as mockViolations, -} from '@src/stories/mockData/transactions'; import type {Report, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx'; +import {actionR14932 as mockAction} from '../../__mocks__/reportData/actions'; +import {chatReportR14932 as mockChatReport, iouReportR14932 as mockIOUReport} from '../../__mocks__/reportData/reports'; +import {transactionR14932 as mockTransaction} from '../../__mocks__/reportData/transactions'; +import {violationsR14932 as mockViolations} from '../../__mocks__/reportData/violations'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; -const mockSecondTransactionID = `${mockTransaction.transactionID.substring(0, mockTransaction.transactionID.length - 1)}2`; +const mockSecondTransactionID = `${mockTransaction.transactionID}2`; jest.mock('@react-navigation/native'); diff --git a/tests/unit/libs/MoneyRequestReportUtils.ts b/tests/unit/libs/MoneyRequestReportUtils.ts index b2ad6b80c476c..c8eafb6c8f935 100644 --- a/tests/unit/libs/MoneyRequestReportUtils.ts +++ b/tests/unit/libs/MoneyRequestReportUtils.ts @@ -1,30 +1,31 @@ import {getThreadReportIDsForTransactions} from '@libs/MoneyRequestReportUtils'; -import {fakeAction456, action as fakeReportAction, transaction as fakeTransaction, fakeTransaction456} from '@src/stories/mockData/transactions'; import type {ReportAction, Transaction} from '@src/types/onyx'; +import {actionR14932, actionR98765} from '../../../__mocks__/reportData/actions'; +import {transactionR14932, transactionR98765} from '../../../__mocks__/reportData/transactions'; describe('getThreadReportIDsForTransactions', () => { test('returns empty list for no transactions', () => { - const result = getThreadReportIDsForTransactions([fakeReportAction], []); + const result = getThreadReportIDsForTransactions([actionR14932], []); expect(result).toEqual([]); }); test('returns empty list for transactions but no reportActions', () => { - const result = getThreadReportIDsForTransactions([], [fakeTransaction]); + const result = getThreadReportIDsForTransactions([], [transactionR14932]); expect(result).toEqual([]); }); test('returns list of reportIDs for transactions which have matching reportActions', () => { - const reportActions = [fakeReportAction, fakeAction456] satisfies ReportAction[]; - const transactions = [{...fakeTransaction, transactionID: '590639150582440369'}, {...fakeTransaction456}] satisfies Transaction[]; + const reportActions = [actionR14932, actionR98765] satisfies ReportAction[]; + const transactions = [{...transactionR14932}, {...transactionR98765}] satisfies Transaction[]; const result = getThreadReportIDsForTransactions(reportActions, transactions); - expect(result).toEqual(['1111111111111111', 'R98765']); + expect(result).toEqual(['CHILD_REPORT_ID_R14932', 'CHILD_REPORT_ID_R98765']); }); test('returns empty list for transactions which have no matching reportActions', () => { // fakeAction456 has originalMessage with undefined id, so cannot be mapped - const reportActions = [{...fakeAction456, originalMessage: {}}] satisfies ReportAction[]; - const transactions = [{...fakeTransaction, transactionID: '590639150582440369'}, {...fakeTransaction456}] satisfies Transaction[]; + const reportActions = [{...actionR98765, originalMessage: {}}] satisfies ReportAction[]; + const transactions = [{...transactionR14932}, {...transactionR98765}] satisfies Transaction[]; const result = getThreadReportIDsForTransactions(reportActions, transactions); expect(result).toEqual([]); From 420cbac57aea6663d33c597163dbacdf02d4509e Mon Sep 17 00:00:00 2001 From: Jakub Korytko Date: Mon, 14 Apr 2025 12:18:20 +0200 Subject: [PATCH 2/5] Add docs to useNewTableReportViewActionRenderConditionals --- src/libs/ReportActionsUtils.ts | 20 +++++++++++++++++++ .../home/report/PureReportActionItem.tsx | 13 +----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 4026c77d066ad..10007b7b04b4c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -5,6 +5,7 @@ import isEmpty from 'lodash/isEmpty'; import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; +import usePrevious from '@hooks/usePrevious'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -1130,6 +1131,24 @@ function isMessageDeleted(reportAction: OnyxInputOrEntry): boolean return getReportActionMessage(reportAction)?.isDeletedParentAction ?? false; } +/** + * Simple hook to check whether the PureReportActionItem should return item based on whether the ReportPreview was recently deleted and the PureReportActionItem has not yet unloaded + */ +function useNewTableReportViewActionRenderConditionals({childMoneyRequestCount, childVisibleActionCount, pendingAction, actionName}: ReportAction) { + const previousChildMoneyRequestCount = usePrevious(childMoneyRequestCount); + + const isActionAReportPreview = actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; + const isActionInUpdateState = pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; + const reportsCount = childMoneyRequestCount; + const previousReportsCount = previousChildMoneyRequestCount ?? 0; + const commentsCount = childVisibleActionCount ?? 0; + + const isEmptyPreviewWithComments = reportsCount === 0 && commentsCount > 0 && previousReportsCount > 0; + + // We only want to remove the item if the ReportPreview has comments but no reports, so we avoid having a PureReportActionItem with no ReportPreview but only comments + return !(isActionAReportPreview && isActionInUpdateState && isEmptyPreviewWithComments); +} + /** * Returns the number of expenses associated with a report preview */ @@ -2412,6 +2431,7 @@ export { isMemberChangeAction, isExportIntegrationAction, isMessageDeleted, + useNewTableReportViewActionRenderConditionals, isModifiedExpenseAction, isMoneyRequestAction, isNotifiableReportAction, diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 02a8f3587bdd2..1252eeece309c 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -108,6 +108,7 @@ import { isTripPreview, isUnapprovedAction, isWhisperActionTargetedToOthers, + useNewTableReportViewActionRenderConditionals, } from '@libs/ReportActionsUtils'; import { canWriteInReport, @@ -337,18 +338,6 @@ type PureReportActionItemProps = { const emptyHTML = ; const isEmptyHTML = ({props: {html}}: T): boolean => typeof html === 'string' && html.length === 0; -const useNewTableReportViewActionRenderConditionals = ({childMoneyRequestCount, childVisibleActionCount, pendingAction, actionName}: OnyxTypes.ReportAction) => { - const previousChildMoneyRequestCount = usePrevious(childMoneyRequestCount); - - return !( - actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && - pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE && - childMoneyRequestCount === 0 && - (childVisibleActionCount ?? 0) > 0 && - (previousChildMoneyRequestCount ?? 0) > 0 - ); -}; - /** * This is a pure version of ReportActionItem, used in ReportActionList and Search result chat list items. * Since the search result has a separate Onyx key under the 'snapshot_' prefix, we should not connect this component with Onyx. From 53f3911ba30d7f4e8760272516665e7e3605b961 Mon Sep 17 00:00:00 2001 From: Jakub Korytko Date: Mon, 14 Apr 2025 12:41:47 +0200 Subject: [PATCH 3/5] Fix self-dm not deleting when deleted before accepting Concierge --- src/pages/home/report/PureReportActionItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 1252eeece309c..2eda3183539a8 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -793,7 +793,7 @@ function PureReportActionItem({ // Table Report View does not display these components as separate messages, except for self-DM if (canUseTableReportView && report?.type === CONST.REPORT.TYPE.CHAT) { - if (report.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM) { + if (report.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM && !isDeletedAction(action)) { children = ( Date: Mon, 14 Apr 2025 12:56:07 +0200 Subject: [PATCH 4/5] Address 59430 follow-up comments --- .../VideoPlayerContexts/PlaybackContext.tsx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/components/VideoPlayerContexts/PlaybackContext.tsx b/src/components/VideoPlayerContexts/PlaybackContext.tsx index 33076b5521a15..ab415f718c84b 100644 --- a/src/components/VideoPlayerContexts/PlaybackContext.tsx +++ b/src/components/VideoPlayerContexts/PlaybackContext.tsx @@ -30,7 +30,15 @@ function isMoneyRequestReportRouteWithReportIDInParams(route: SearchRoute): rout return !!route && !!route.params && route.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT && 'reportID' in route.params; } -function findUrlInReportOrAncestorAttachments(currentReport: OnyxEntry, url: string | null): string | undefined { +/** + * Searches recursively through a report and its ancestor reports to find a specified URL in their attachments. + * The search continues up the ancestry chain until the URL is found or there are no more ancestors. + * + * @param currentReport - The current report entry, potentially containing the URL. + * @param url - The URL to be located in the report or its ancestors' attachments. + * @returns The report ID where the URL is found, or undefined if not found. + */ +function findURLInReportOrAncestorAttachments(currentReport: OnyxEntry, url: string | null): string | undefined { const {parentReportID, reportID} = currentReport ?? {}; const reportActions = getAllReportActions(reportID); @@ -45,7 +53,7 @@ function findUrlInReportOrAncestorAttachments(currentReport: OnyxEntry, if (parentReportID) { const parentReport = getReportOrDraftReport(parentReportID); - return findUrlInReportOrAncestorAttachments(parentReport, url); + return findURLInReportOrAncestorAttachments(parentReport, url); } return undefined; @@ -121,11 +129,11 @@ function PlaybackContextProvider({children}: ChildrenProps) { // Used for /attachment route const topMostReport = getReportOrDraftReport(Navigation.getTopmostReportId()); - const reportIDFromUrlParams = new URLSearchParams(Navigation.getActiveRoute()).get('reportID') ?? undefined; - const attachmentReportID = Navigation.getActiveRouteWithoutParams() === `/${ROUTES.ATTACHMENTS.route}` ? prevCurrentReportID ?? reportIDFromUrlParams : undefined; - const reportIDWithUrl = isChatThread(topMostReport) ? findUrlInReportOrAncestorAttachments(topMostReport, url) : undefined; + const reportIDFromURLParams = new URLSearchParams(Navigation.getActiveRoute()).get('reportID') ?? undefined; + const attachmentReportID = Navigation.getActiveRouteWithoutParams() === `/${ROUTES.ATTACHMENTS.route}` ? prevCurrentReportID ?? reportIDFromURLParams : undefined; + const reportIDWithUrl = isChatThread(topMostReport) ? findURLInReportOrAncestorAttachments(topMostReport, url) : undefined; - // - if it is a chat thread, use chat thread ID or any ascentor ID since the video could have originally been sent on report many levels up + // - if it is a chat thread, use chat thread ID or any ancestor ID since the video could have originally been sent on report many levels up // - report ID in which we are currently, if it is not a chat thread // - if it is an attachment route, then we take report ID from the URL params const currentPlayReportID = [attachmentReportID, reportIDWithUrl, currentReportID].find((id) => id !== undefined); From 744d141d9e8b6147181169c949fc712959dedfa6 Mon Sep 17 00:00:00 2001 From: Jakub Korytko Date: Tue, 15 Apr 2025 07:39:51 +0200 Subject: [PATCH 5/5] Add missing changes after merge conflict --- .../PlaybackContext/index.tsx | 4 ++-- .../playbackContextReportIDUtils.ts | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/VideoPlayerContexts/PlaybackContext/index.tsx b/src/components/VideoPlayerContexts/PlaybackContext/index.tsx index 74641f5579d13..f39a9621475b9 100644 --- a/src/components/VideoPlayerContexts/PlaybackContext/index.tsx +++ b/src/components/VideoPlayerContexts/PlaybackContext/index.tsx @@ -5,7 +5,7 @@ import {getReportOrDraftReport, isChatThread} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import type {ProtectedCurrentRouteReportID} from './playbackContextReportIDUtils'; -import {findUrlInReportOrAncestorAttachments, getCurrentRouteReportID, NO_REPORT_ID, NO_REPORT_ID_IN_PARAMS, normalizeReportID} from './playbackContextReportIDUtils'; +import {findURLInReportOrAncestorAttachments, getCurrentRouteReportID, NO_REPORT_ID, NO_REPORT_ID_IN_PARAMS, normalizeReportID} from './playbackContextReportIDUtils'; import type {OriginalParent, PlaybackContext, PlaybackContextValues} from './types'; import usePlaybackContextVideoRefs from './usePlaybackContextVideoRefs'; @@ -39,7 +39,7 @@ function PlaybackContextProvider({children}: ChildrenProps) { const isReportAChatThread = isChatThread(report); let reportIDtoSet; if (isReportAChatThread) { - reportIDtoSet = findUrlInReportOrAncestorAttachments(report, url) ?? NO_REPORT_ID; + reportIDtoSet = findURLInReportOrAncestorAttachments(report, url) ?? NO_REPORT_ID; } else { reportIDtoSet = reportID; } diff --git a/src/components/VideoPlayerContexts/PlaybackContext/playbackContextReportIDUtils.ts b/src/components/VideoPlayerContexts/PlaybackContext/playbackContextReportIDUtils.ts index 5d85d039263fc..25cfd4b8f6a0f 100644 --- a/src/components/VideoPlayerContexts/PlaybackContext/playbackContextReportIDUtils.ts +++ b/src/components/VideoPlayerContexts/PlaybackContext/playbackContextReportIDUtils.ts @@ -32,9 +32,9 @@ type RouteWithReportIDInParams = T & {params: ReportDetailsNavigatorParamList const getCurrentRouteReportID: (url: string) => string | ProtectedCurrentRouteReportID = (url): string | typeof NO_REPORT_ID_IN_PARAMS | typeof NO_REPORT_ID => { const route = Navigation.getActiveRouteWithoutParams() as ActiveRoute; const focusedRoute = findFocusedRoute(getStateFromPath(route)); - const reportIDFromUrlParams = new URLSearchParams(Navigation.getActiveRoute()).get('reportID'); + const reportIDFromURLParams = new URLSearchParams(Navigation.getActiveRoute()).get('reportID'); - const focusedRouteReportID = hasReportIdInRouteParams(focusedRoute) ? focusedRoute.params.reportID : reportIDFromUrlParams; + const focusedRouteReportID = hasReportIdInRouteParams(focusedRoute) ? focusedRoute.params.reportID : reportIDFromURLParams; if (!focusedRouteReportID) { return NO_REPORT_ID_IN_PARAMS; @@ -42,7 +42,7 @@ const getCurrentRouteReportID: (url: string) => string | ProtectedCurrentRouteRe const report = getReportOrDraftReport(focusedRouteReportID); const isFocusedRouteAChatThread = isChatThread(report); - const firstReportThatHasURLInAttachments = findUrlInReportOrAncestorAttachments(report, url); + const firstReportThatHasURLInAttachments = findURLInReportOrAncestorAttachments(report, url); return isFocusedRouteAChatThread ? firstReportThatHasURLInAttachments : focusedRouteReportID; }; @@ -53,7 +53,15 @@ function hasReportIdInRouteParams(route: SearchRoute): route is RouteWithReportI return !!route && !!route.params && !!screensWithReportID.find((screen) => screen === route.name) && 'reportID' in route.params; } -function findUrlInReportOrAncestorAttachments(currentReport: OnyxEntry, url: string | null): string | typeof NO_REPORT_ID { +/** + * Searches recursively through a report and its ancestor reports to find a specified URL in their attachments. + * The search continues up the ancestry chain until the URL is found or there are no more ancestors. + * + * @param currentReport - The current report entry, potentially containing the URL. + * @param url - The URL to be located in the report or its ancestors' attachments. + * @returns The report ID where the URL is found, or undefined if not found. + */ +function findURLInReportOrAncestorAttachments(currentReport: OnyxEntry, url: string | null): string | typeof NO_REPORT_ID { const {parentReportID, reportID} = currentReport ?? {}; const reportActions = getAllReportActions(reportID); @@ -68,11 +76,11 @@ function findUrlInReportOrAncestorAttachments(currentReport: OnyxEntry, if (parentReportID) { const parentReport = getReportOrDraftReport(parentReportID); - return findUrlInReportOrAncestorAttachments(parentReport, url); + return findURLInReportOrAncestorAttachments(parentReport, url); } return NO_REPORT_ID; } -export {NO_REPORT_ID, NO_REPORT_ID_IN_PARAMS, getCurrentRouteReportID, normalizeReportID, findUrlInReportOrAncestorAttachments}; +export {NO_REPORT_ID, NO_REPORT_ID_IN_PARAMS, getCurrentRouteReportID, normalizeReportID, findURLInReportOrAncestorAttachments}; export type {ProtectedCurrentRouteReportID};