From b4d4e1efa5ceef259cd8990f10f7abf4da8dd60e Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 19 Feb 2024 10:41:40 +0700 Subject: [PATCH 1/6] fix: IOU-Error message remains on IOU report even same error message is dismissed --- src/libs/actions/IOU.ts | 22 +++++++++++++++++-- src/libs/actions/ReportActions.ts | 12 +++++++++- src/pages/home/report/ReportActionItem.js | 8 ++++++- .../report/ReportActionsListItemRenderer.js | 2 ++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3482dd0e30ad..798817f57187 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2984,6 +2984,8 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }); } + const errorKey = DateUtils.getMicroseconds(); + failureData.push( { onyxMethod: Onyx.METHOD.MERGE, @@ -2992,7 +2994,15 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor [reportAction.reportActionID]: { ...reportAction, pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericDeleteFailureMessage'), + errors: { + [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], + }, + relatedErrors: { + [errorKey]: { + reportID: chatReport?.reportID, + reportActionID: reportPreviewAction?.reportActionID, + }, + }, }, }, }, @@ -3014,7 +3024,15 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor [reportPreviewAction?.reportActionID ?? '']: { ...reportPreviewAction, pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericDeleteFailureMessage'), + errors: { + [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], + }, + relatedErrors: { + [errorKey]: { + reportID: iouReport?.reportID, + reportActionID: reportAction.reportActionID, + }, + }, }, }, }, diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index aad6ae39810a..8c66244ce026 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -6,7 +6,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Report from './Report'; -function clearReportActionErrors(reportID: string, reportAction: ReportAction) { +function clearReportActionErrors(reportID: string, reportAction: ReportAction, key?: string) { const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); if (!reportAction.reportActionID) { @@ -33,6 +33,16 @@ function clearReportActionErrors(reportID: string, reportAction: ReportAction) { return; } + if (key) { + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${originalReportID}`, { + [reportAction.reportActionID]: { + errors: { + [key]: null, + }, + }, + }); + return; + } Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${originalReportID}`, { [reportAction.reportActionID]: { errors: null, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 39a5fcaa4ee0..e4f8d5d90b93 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -762,7 +762,13 @@ function ReportActionItem(props) { /> ReportActions.clearReportActionErrors(props.report.reportID, props.action)} + onClose={() => { + ReportActions.clearReportActionErrors(props.report.reportID, props.action); + Object.keys(props.action.relatedErrors ?? {}).forEach((key) => { + const error = props.action.relatedErrors[key]; + ReportActions.clearReportActionErrors(error.reportID, ReportActionsUtils.getReportAction(error.reportID, error.reportActionID), key); + }); + }} pendingAction={ !_.isUndefined(props.draftMessage) ? null : props.action.pendingAction || (props.action.isOptimisticAction ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : '') } diff --git a/src/pages/home/report/ReportActionsListItemRenderer.js b/src/pages/home/report/ReportActionsListItemRenderer.js index 3fd6ddcef750..5b5fa25f7006 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.js +++ b/src/pages/home/report/ReportActionsListItemRenderer.js @@ -88,6 +88,7 @@ function ReportActionsListItemRenderer({ childReportName: reportAction.childReportName, childManagerAccountID: reportAction.childManagerAccountID, childMoneyRequestCount: reportAction.childMoneyRequestCount, + relatedErrors: reportAction.relatedErrors, }), [ reportAction.actionName, @@ -117,6 +118,7 @@ function ReportActionsListItemRenderer({ reportAction.childReportName, reportAction.childManagerAccountID, reportAction.childMoneyRequestCount, + reportAction.relatedErrors, ], ); From 9d8885aab54173cd10850450e5254fab53020ea2 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 29 Feb 2024 16:31:40 +0700 Subject: [PATCH 2/6] refactor --- src/libs/ErrorUtils.ts | 8 ++-- src/libs/actions/IOU.ts | 30 ++++-------- src/libs/actions/ReportActions.ts | 47 +++++++++++++++++-- src/pages/home/report/ReportActionItem.js | 8 +--- .../report/ReportActionsListItemRenderer.js | 2 - 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 20313ee8912d..56d3a5a422c3 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -40,16 +40,16 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO * Method used to get an error object with microsecond as the key. * @param error - error key or message to be saved */ -function getMicroSecondOnyxError(error: string | null, isTranslated = false): Errors { - return {[DateUtils.getMicroseconds()]: error && [error, {isTranslated}]}; +function getMicroSecondOnyxError(error: string | null, isTranslated = false, errorKey?: number): Errors { + return {[errorKey ?? DateUtils.getMicroseconds()]: error && [error, {isTranslated}]}; } /** * Method used to get an error object with microsecond as the key and an object as the value. * @param error - error key or message to be saved */ -function getMicroSecondOnyxErrorObject(error: Errors): ErrorFields { - return {[DateUtils.getMicroseconds()]: error}; +function getMicroSecondOnyxErrorObject(error: Errors, errorKey?: number): ErrorFields { + return {[errorKey ?? DateUtils.getMicroseconds()]: error}; } // We can assume that if error is a string, it has already been translated because it is server error diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e1096a1e13b5..00957ac7c184 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -379,10 +379,10 @@ function resetMoneyRequestInfo(id = '') { } /** Helper function to get the receipt error for money requests, or the generic error if there's no receipt */ -function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorFields { +function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true, errorKey?: number): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest - ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') - : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}); + ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage', false, errorKey) + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}, errorKey); } function needsToBeManuallySubmitted(iouReport: OnyxTypes.Report) { @@ -652,6 +652,8 @@ function buildOnyxDataForMoneyRequest( }, ); + const errorKey = DateUtils.getMicroseconds(); + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -707,7 +709,7 @@ function buildOnyxDataForMoneyRequest( [chatCreatedAction.reportActionID]: { // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), + errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, [reportPreviewAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError(null), @@ -718,7 +720,7 @@ function buildOnyxDataForMoneyRequest( created: reportPreviewAction.created, // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), + errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, }), }, @@ -732,7 +734,7 @@ function buildOnyxDataForMoneyRequest( [iouCreatedAction.reportActionID]: { // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), + errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, [iouAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError(null), @@ -742,7 +744,7 @@ function buildOnyxDataForMoneyRequest( [iouAction.reportActionID]: { // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), + errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, }), }, @@ -752,7 +754,7 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.reportID}`, value: { [transactionThreadCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage', false, errorKey), }, }, }, @@ -3142,12 +3144,6 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor errors: { [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], }, - relatedErrors: { - [errorKey]: { - reportID: chatReport?.reportID, - reportActionID: reportPreviewAction?.reportActionID, - }, - }, }, }, }, @@ -3172,12 +3168,6 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor errors: { [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], }, - relatedErrors: { - [errorKey]: { - reportID: iouReport?.reportID, - reportActionID: reportAction.reportActionID, - }, - }, }, }, }, diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index 8c66244ce026..da0460a5ec69 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -6,7 +6,39 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Report from './Report'; -function clearReportActionErrors(reportID: string, reportAction: ReportAction, key?: string) { +type IgnoreDirection = 'parent' | 'child'; + +/** + * +ignore: undefined means we want to check both parent and children report actions +ignore: parent | child means we want to ignore check parent | child report actions because we already check them before + */ +function clearAllRelatedReportActionErrors(reportID: string, reportAction: ReportAction | null, ignore?: IgnoreDirection, keys?: string[]) { + const errorKeys = keys || Object.keys(reportAction?.errors ?? {}); + if (!reportAction || errorKeys.length === 0) { + return; + } + + clearReportActionErrors(reportID, reportAction, keys); + + const report = ReportUtils.getReport(reportID); + if (report?.parentReportID && report?.parentReportActionID && ignore !== 'parent') { + const parentReportAction = ReportActionUtils.getReportAction(report.parentReportID, report.parentReportActionID); + const parentErrorKeys = Object.keys(parentReportAction?.errors ?? {}).filter((err) => errorKeys.includes(err)); + + clearAllRelatedReportActionErrors(report.parentReportID, parentReportAction, 'child', parentErrorKeys); + } + + if (reportAction.childReportID && ignore !== 'child') { + const childActions = ReportActionUtils.getAllReportActions(reportAction.childReportID); + Object.values(childActions).forEach((action) => { + const childErrorKeys = Object.keys(action.errors ?? {}).filter((err) => errorKeys.includes(err)); + clearAllRelatedReportActionErrors(reportAction.childReportID ?? '', action, 'parent', childErrorKeys); + }); + } +} + +function clearReportActionErrors(reportID: string, reportAction: ReportAction, keys?: string[]) { const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); if (!reportAction.reportActionID) { @@ -33,12 +65,16 @@ function clearReportActionErrors(reportID: string, reportAction: ReportAction, k return; } - if (key) { + if (keys) { + const errors: Record = {}; + + keys.forEach((key) => { + errors[key] = null; + }); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${originalReportID}`, { [reportAction.reportActionID]: { - errors: { - [key]: null, - }, + errors, }, }); return; @@ -53,4 +89,5 @@ function clearReportActionErrors(reportID: string, reportAction: ReportAction, k export { // eslint-disable-next-line import/prefer-default-export clearReportActionErrors, + clearAllRelatedReportActionErrors, }; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 20ff91730163..099ad0673596 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -788,13 +788,7 @@ function ReportActionItem(props) { /> { - ReportActions.clearReportActionErrors(props.report.reportID, props.action); - Object.keys(props.action.relatedErrors ?? {}).forEach((key) => { - const error = props.action.relatedErrors[key]; - ReportActions.clearReportActionErrors(error.reportID, ReportActionsUtils.getReportAction(error.reportID, error.reportActionID), key); - }); - }} + onClose={() => ReportActions.clearAllRelatedReportActionErrors(props.report.reportID, props.action)} pendingAction={ !_.isUndefined(props.draftMessage) ? null : props.action.pendingAction || (props.action.isOptimisticAction ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : '') } diff --git a/src/pages/home/report/ReportActionsListItemRenderer.js b/src/pages/home/report/ReportActionsListItemRenderer.js index ebd3964d582c..bc8e6a94359f 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.js +++ b/src/pages/home/report/ReportActionsListItemRenderer.js @@ -91,7 +91,6 @@ function ReportActionsListItemRenderer({ childReportName: reportAction.childReportName, childManagerAccountID: reportAction.childManagerAccountID, childMoneyRequestCount: reportAction.childMoneyRequestCount, - relatedErrors: reportAction.relatedErrors, }), [ reportAction.actionName, @@ -121,7 +120,6 @@ function ReportActionsListItemRenderer({ reportAction.childReportName, reportAction.childManagerAccountID, reportAction.childMoneyRequestCount, - reportAction.relatedErrors, ], ); From c0725644186075e13f7b23fec4abec420e17d1b3 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 7 Mar 2024 16:39:59 +0700 Subject: [PATCH 3/6] refactor code --- src/libs/actions/ReportActions.ts | 66 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index da0460a5ec69..112b0db3440b 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -8,36 +8,6 @@ import * as Report from './Report'; type IgnoreDirection = 'parent' | 'child'; -/** - * -ignore: undefined means we want to check both parent and children report actions -ignore: parent | child means we want to ignore check parent | child report actions because we already check them before - */ -function clearAllRelatedReportActionErrors(reportID: string, reportAction: ReportAction | null, ignore?: IgnoreDirection, keys?: string[]) { - const errorKeys = keys || Object.keys(reportAction?.errors ?? {}); - if (!reportAction || errorKeys.length === 0) { - return; - } - - clearReportActionErrors(reportID, reportAction, keys); - - const report = ReportUtils.getReport(reportID); - if (report?.parentReportID && report?.parentReportActionID && ignore !== 'parent') { - const parentReportAction = ReportActionUtils.getReportAction(report.parentReportID, report.parentReportActionID); - const parentErrorKeys = Object.keys(parentReportAction?.errors ?? {}).filter((err) => errorKeys.includes(err)); - - clearAllRelatedReportActionErrors(report.parentReportID, parentReportAction, 'child', parentErrorKeys); - } - - if (reportAction.childReportID && ignore !== 'child') { - const childActions = ReportActionUtils.getAllReportActions(reportAction.childReportID); - Object.values(childActions).forEach((action) => { - const childErrorKeys = Object.keys(action.errors ?? {}).filter((err) => errorKeys.includes(err)); - clearAllRelatedReportActionErrors(reportAction.childReportID ?? '', action, 'parent', childErrorKeys); - }); - } -} - function clearReportActionErrors(reportID: string, reportAction: ReportAction, keys?: string[]) { const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); @@ -86,8 +56,34 @@ function clearReportActionErrors(reportID: string, reportAction: ReportAction, k }); } -export { - // eslint-disable-next-line import/prefer-default-export - clearReportActionErrors, - clearAllRelatedReportActionErrors, -}; +/** + * +ignore: undefined means we want to check both parent and children report actions +ignore: parent or child means we want to ignore check parent or child report actions because we already check them before + */ +function clearAllRelatedReportActionErrors(reportID: string, reportAction: ReportAction | null, ignore?: IgnoreDirection, keys?: string[]) { + const errorKeys = keys ?? Object.keys(reportAction?.errors ?? {}); + if (!reportAction || errorKeys.length === 0) { + return; + } + + clearReportActionErrors(reportID, reportAction, keys); + + const report = ReportUtils.getReport(reportID); + if (report?.parentReportID && report?.parentReportActionID && ignore !== 'parent') { + const parentReportAction = ReportActionUtils.getReportAction(report.parentReportID, report.parentReportActionID); + const parentErrorKeys = Object.keys(parentReportAction?.errors ?? {}).filter((err) => errorKeys.includes(err)); + + clearAllRelatedReportActionErrors(report.parentReportID, parentReportAction, 'child', parentErrorKeys); + } + + if (reportAction.childReportID && ignore !== 'child') { + const childActions = ReportActionUtils.getAllReportActions(reportAction.childReportID); + Object.values(childActions).forEach((action) => { + const childErrorKeys = Object.keys(action.errors ?? {}).filter((err) => errorKeys.includes(err)); + clearAllRelatedReportActionErrors(reportAction.childReportID ?? '', action, 'parent', childErrorKeys); + }); + } +} + +export {clearReportActionErrors, clearAllRelatedReportActionErrors}; From db0453ab887ed60860a50d180dc8ce1ed8f1f16a Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 22 Mar 2024 10:41:58 +0700 Subject: [PATCH 4/6] add test --- tests/actions/IOUTest.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index d8472dbb1bee..176b0fd4911d 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -744,12 +744,11 @@ describe('actions/IOU', () => { () => new Promise((resolve) => { ReportActions.clearAllRelatedReportActionErrors(iouReportID, iouAction); - ReportActions.clearAllRelatedReportActionErrors(transactionThreadReport.reportID, transactionThreadAction); resolve(); }), ) - // Then the reportAction should be removed from Onyx + // Then the reportAction from chat report should be removed from Onyx .then( () => new Promise((resolve) => { @@ -766,6 +765,23 @@ describe('actions/IOU', () => { }), ) + // Then the reportAction from iou report should be removed from Onyx + .then( + () => + new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, + waitForCollectionCallback: true, + callback: (reportActionsForReport) => { + Onyx.disconnect(connectionID); + iouAction = _.find(reportActionsForReport, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); + expect(iouAction).toBeFalsy(); + resolve(); + }, + }); + }), + ) + // Along with the associated transaction .then( () => From 439ffc9fea8e67a62556525ce6d53f0a3ea87178 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 25 Mar 2024 11:02:38 +0700 Subject: [PATCH 5/6] refactor --- src/libs/actions/ReportActions.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index 6fc8912a3ef8..5866d1be2d89 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -80,7 +80,6 @@ function clearAllRelatedReportActionErrors(reportID: string, reportAction: Repor if (reportAction.childReportID && ignore !== 'child') { const childActions = ReportActionUtils.getAllReportActions(reportAction.childReportID); - console.log('childActions', childActions); Object.values(childActions).forEach((action) => { const childErrorKeys = Object.keys(action.errors ?? {}).filter((err) => errorKeys.includes(err)); clearAllRelatedReportActionErrors(reportAction.childReportID ?? '', action, 'parent', childErrorKeys); @@ -90,6 +89,5 @@ function clearAllRelatedReportActionErrors(reportID: string, reportAction: Repor export { // eslint-disable-next-line import/prefer-default-export - clearReportActionErrors, clearAllRelatedReportActionErrors, }; From 82bb67f77e5c23031eea21caebe18ea92608ec40 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 25 Mar 2024 11:13:10 +0700 Subject: [PATCH 6/6] lint fix --- src/libs/actions/ReportActions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index 5866d1be2d89..66deb8aca065 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -1,5 +1,4 @@ import Onyx from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST';