From 8eb68aaef5890a7055e09d8f3023cd18d4dc9940 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Fri, 25 Aug 2023 02:50:10 +0530 Subject: [PATCH 01/25] Fix LHN display issue for money request via scan --- .../LHNOptionsList/OptionRowLHNData.js | 20 +++++++- src/hooks/useDeepCompareMemo.js | 26 ++++++++++ src/libs/ReportUtils.js | 48 +++++++++++++++++++ .../home/report/ReportActionItemSingle.js | 2 +- 4 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/hooks/useDeepCompareMemo.js diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 21fade6eb942e..acf5a5523b279 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -12,9 +12,12 @@ import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDe import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultProps} from './OptionRowLHN'; import * as Report from '../../libs/actions/Report'; import * as UserUtils from '../../libs/UserUtils'; +import * as ReportUtils from '../../libs/ReportUtils'; + import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; +import useDeepCompareMemo from '../../hooks/useDeepCompareMemo'; const propTypes = { /** If true will disable ever setting the OptionRowLHN to focused */ @@ -75,6 +78,7 @@ function OptionRowLHNData({ preferredLocale, comment, policies, + receiptTransactions, parentReportActions, ...propsToForward }) { @@ -88,6 +92,15 @@ function OptionRowLHNData({ const parentReportAction = parentReportActions[fullReport.parentReportActionID]; const optionItemRef = useRef(); + + const lastTransaction = useMemo(() => { + const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); + const lastTransaction = _.first(transactionsWithReceipts); + return lastTransaction; + }, [fullReport.reportID, receiptTransactions]); + + let memoizedLastTransaction = useDeepCompareMemo(lastTransaction); + const optionItem = useMemo(() => { // Note: ideally we'd have this as a dependent selector in onyx! const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy); @@ -98,7 +111,7 @@ function OptionRowLHNData({ return item; // Listen parentReportAction to update title of thread report when parentReportAction changed // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); + }, [fullReport, memoizedLastTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); useEffect(() => { if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) { @@ -186,6 +199,11 @@ export default React.memo( key: ({fullReport}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fullReport.parentReportID}`, canEvict: false, }, + // Ideally, we aim to access only the last transaction for the current report by listening to changes in reportActions. + // In some scenarios, a transaction might be created after reportActions have been modified. + // This can lead to situations where `lastTransaction` doesn't update and retains the previous value. + // However, performance overhead of this is minimized by using memos inside the component. + receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION}, }), )(OptionRowLHNData), ); diff --git a/src/hooks/useDeepCompareMemo.js b/src/hooks/useDeepCompareMemo.js new file mode 100644 index 0000000000000..ebed9ffdeebec --- /dev/null +++ b/src/hooks/useDeepCompareMemo.js @@ -0,0 +1,26 @@ +import {useRef} from 'react'; +import _ from 'lodash'; + +/** + * Custom hook to memoize a value based on deep comparison. + * Returns the previous value if the current value is deeply equal to the previous one. + * + * @function + * @template T + * @param {T} value - The value to be memoized. + * @returns {T} - The memoized value. Returns the previous value if the current value is deeply equal to the previous one. + * @example + * + * const object = { a: 1, b: 2 }; + * const memoizedObject = useDeepCompareMemo(object); + */ +export default function useDeepCompareMemo(value) { + const ref = useRef(); // Holds the previous value + + // If the new value is not deeply equal to the old value, update the ref + if (!_.isEqual(value, ref.current)) { + ref.current = value; + } + + return ref.current; +} diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6814953500690..798f4b2eec367 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1213,6 +1213,26 @@ function getMoneyRequestReportName(report, policy = undefined) { amount: formattedAmount, }); + // get lastReportActionTransaction + const reportActions = ReportActionsUtils.getAllReportActions(report.reportID); + const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); + const filteredReportActions = _.filter(sortedReportActions, (reportAction) => { + return reportAction.pendingAction !== 'delete'; + }); + const lastReportAction = _.first(filteredReportActions); + const lastReportActionTransaction = TransactionUtils.getLinkedTransaction(lastReportAction); + + // get lastTransaction + // eslint-disable-next-line no-use-before-define + const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); + const lastTransaction = _.first(transactionsWithReceipts); + + const transactionIsLastReportAction = _.isEqual(lastReportActionTransaction, lastTransaction); + + if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { + return Localize.translateLocal('iou.receiptScanning'); + } + if (report.isWaitingOnBankAccount) { return `${payerPaidAmountMesssage} • ${Localize.translateLocal('iou.pending')}`; } @@ -1274,6 +1294,33 @@ function getTransactionsWithReceipts(iouReportID) { ); } +/** + * Gets all sorted transactions on an IOU report with a receipt and whose pending action is not delete + * + * @param {Object|null} iouReportID + * @returns {[Object]} + */ +function getSortedTransactionsWithReceipts(iouReportID) { + const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); + const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); + const filteredSortedReportActions = _.filter(sortedReportActions, (reportAction) => { + return reportAction.pendingAction !== 'delete'; + }); + return _.reduce( + filteredSortedReportActions, + (transactions, action) => { + if (ReportActionsUtils.isMoneyRequestAction(action)) { + const transaction = TransactionUtils.getLinkedTransaction(action); + if (TransactionUtils.hasReceipt(transaction)) { + transactions.push(transaction); + } + } + return transactions; + }, + [], + ); +} + /** * For report previews, we display a "Receipt scan in progress" indicator * instead of the report total only when we have no report total ready to show. This is the case when @@ -3445,4 +3492,5 @@ export { areAllRequestsBeingSmartScanned, getReportPreviewDisplayTransactions, getTransactionsWithReceipts, + getSortedTransactionsWithReceipts, }; diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 80f49f177b6fe..768076e7730b0 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -151,7 +151,7 @@ function ReportActionItemSingle(props) { } showUserDetails(props.action.delegateAccountID ? props.action.delegateAccountID : actorAccountID); } - }, [isWorkspaceActor, props.report.reportID, actorAccountID, props.action.delegateAccountID, props.iouReport, displayAllActors]); + }, [isWorkspaceActor, props.report && props.report.reportID, actorAccountID, props.action.delegateAccountID, props.iouReport && props.iouReport.reportID, displayAllActors]); const shouldDisableDetailPage = useMemo( () => !isWorkspaceActor && ReportUtils.isOptimisticPersonalDetail(props.action.delegateAccountID ? props.action.delegateAccountID : actorAccountID), From 958b1ca33ecd43507c4e0e8361cab351a4892298 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Fri, 25 Aug 2023 04:41:10 +0530 Subject: [PATCH 02/25] Linting fixes --- src/components/LHNOptionsList/OptionRowLHNData.js | 5 ++--- src/libs/ReportUtils.js | 9 +++------ src/pages/home/report/ReportActionItemSingle.js | 9 ++++++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index acf5a5523b279..bd7735be4a144 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -95,11 +95,10 @@ function OptionRowLHNData({ const lastTransaction = useMemo(() => { const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); - const lastTransaction = _.first(transactionsWithReceipts); - return lastTransaction; + return _.first(transactionsWithReceipts); }, [fullReport.reportID, receiptTransactions]); - let memoizedLastTransaction = useDeepCompareMemo(lastTransaction); + const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); const optionItem = useMemo(() => { // Note: ideally we'd have this as a dependent selector in onyx! diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 798f4b2eec367..4022d03da0adb 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1216,9 +1216,8 @@ function getMoneyRequestReportName(report, policy = undefined) { // get lastReportActionTransaction const reportActions = ReportActionsUtils.getAllReportActions(report.reportID); const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - const filteredReportActions = _.filter(sortedReportActions, (reportAction) => { - return reportAction.pendingAction !== 'delete'; - }); + const filteredReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== 'delete'); + const lastReportAction = _.first(filteredReportActions); const lastReportActionTransaction = TransactionUtils.getLinkedTransaction(lastReportAction); @@ -1303,9 +1302,7 @@ function getTransactionsWithReceipts(iouReportID) { function getSortedTransactionsWithReceipts(iouReportID) { const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - const filteredSortedReportActions = _.filter(sortedReportActions, (reportAction) => { - return reportAction.pendingAction !== 'delete'; - }); + const filteredSortedReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== 'delete'); return _.reduce( filteredSortedReportActions, (transactions, action) => { diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 768076e7730b0..d9dcb4446d9be 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -140,18 +140,21 @@ function ReportActionItemSingle(props) { ] : props.action.person; + const reportID = props.report && props.report.reportID; + const iouReportID = props.report && props.report.reportID; + const showActorDetails = useCallback(() => { if (isWorkspaceActor) { - showWorkspaceDetails(props.report.reportID); + showWorkspaceDetails(reportID); } else { // Show participants page IOU report preview if (displayAllActors) { - Navigation.navigate(ROUTES.getReportParticipantsRoute(props.iouReport.reportID)); + Navigation.navigate(ROUTES.getReportParticipantsRoute(iouReportID)); return; } showUserDetails(props.action.delegateAccountID ? props.action.delegateAccountID : actorAccountID); } - }, [isWorkspaceActor, props.report && props.report.reportID, actorAccountID, props.action.delegateAccountID, props.iouReport && props.iouReport.reportID, displayAllActors]); + }, [isWorkspaceActor, reportID, actorAccountID, props.action.delegateAccountID, iouReportID, displayAllActors]); const shouldDisableDetailPage = useMemo( () => !isWorkspaceActor && ReportUtils.isOptimisticPersonalDetail(props.action.delegateAccountID ? props.action.delegateAccountID : actorAccountID), From c735418548076ff00583711c472e6b36ca59a0df Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Fri, 25 Aug 2023 05:07:26 +0530 Subject: [PATCH 03/25] Eslint fixes --- src/components/LHNOptionsList/OptionRowLHNData.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index bd7735be4a144..83d59a24d5e1c 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -96,6 +96,7 @@ function OptionRowLHNData({ const lastTransaction = useMemo(() => { const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); return _.first(transactionsWithReceipts); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [fullReport.reportID, receiptTransactions]); const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); From cc6965e2c95e63781bb7adf89e7cb803c543fe0e Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 30 Aug 2023 14:09:49 +0530 Subject: [PATCH 04/25] Fix LHN subtitle display issue for money request via scan --- .../LHNOptionsList/OptionRowLHNData.js | 20 +++++++- src/libs/ReportActionsUtils.js | 16 ++++++ src/libs/ReportUtils.js | 51 +++++++++++++++++-- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 83d59a24d5e1c..778c918936f16 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -13,6 +13,7 @@ import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultPro import * as Report from '../../libs/actions/Report'; import * as UserUtils from '../../libs/UserUtils'; import * as ReportUtils from '../../libs/ReportUtils'; +import * as ReportActionUtils from '../../libs/ReportActionsUtils'; import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; @@ -93,11 +94,26 @@ function OptionRowLHNData({ const optionItemRef = useRef(); + /** + * If it is an IOU report, you get the last transaction with a receipt. + * Otherwise, if the last message is a reportPreview in a chat, + * you get the last transaction of the IOU report associated with that preview message. + */ + const lastTransaction = useMemo(() => { - const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); + let reportIDLocal = fullReport.reportID; + + // Check if reportIDLocal needs to be updated with the IOU report of the last report action, in case this report is a chat. + const filteredReportActions = ReportActionUtils.getFilteredSortedReportActionsForDisplay(reportActions); + const lastReportAction = _.first(filteredReportActions); + if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { + reportIDLocal = ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction); + } + + const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(reportIDLocal); return _.first(transactionsWithReceipts); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport.reportID, receiptTransactions]); + }, [fullReport.reportID, receiptTransactions, reportActions]); const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index c90efb54785d3..7e17fd80d879e 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -432,6 +432,21 @@ function getSortedReportActionsForDisplay(reportActions) { return getSortedReportActions(filteredReportActions, true); } +/** + * Gets sorted and filtered report actions for display. + * + * First, it sorts the report actions using `getSortedReportActionsForDisplay`. + * Then, it filters out actions that are pending deletion. + * + * @param {Array} reportActions - The array of report actions to filter. + * @returns {Array} - The filtered and sorted array of report actions. + */ +function getFilteredSortedReportActionsForDisplay(reportActions) { + const sortedReportActions = getSortedReportActionsForDisplay(reportActions); + const filteredReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + return filteredReportActions; +} + /** * In some cases, there can be multiple closed report actions in a chat report. * This method returns the last closed report action so we can always show the correct archived report reason. @@ -643,4 +658,5 @@ export { isSplitBillAction, isTaskAction, getAllReportActions, + getFilteredSortedReportActionsForDisplay, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 93469c488635c..851af6f55106b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1237,10 +1237,11 @@ function getMoneyRequestReportName(report, policy = undefined) { amount: formattedAmount, }); + /* === Start - Check for Report Scan === */ + // get lastReportActionTransaction const reportActions = ReportActionsUtils.getAllReportActions(report.reportID); - const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - const filteredReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== 'delete'); + const filteredReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); const lastReportAction = _.first(filteredReportActions); const lastReportActionTransaction = TransactionUtils.getLinkedTransaction(lastReportAction); @@ -1256,6 +1257,8 @@ function getMoneyRequestReportName(report, policy = undefined) { return Localize.translateLocal('iou.receiptScanning'); } + /* === End - Check for Report Scan === */ + if (report.isWaitingOnBankAccount) { return `${payerPaidAmountMesssage} • ${Localize.translateLocal('iou.pending')}`; } @@ -1377,8 +1380,8 @@ function getTransactionsWithReceipts(iouReportID) { */ function getSortedTransactionsWithReceipts(iouReportID) { const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); - const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - const filteredSortedReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== 'delete'); + const filteredSortedReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); + return _.reduce( filteredSortedReportActions, (transactions, action) => { @@ -1394,6 +1397,26 @@ function getSortedTransactionsWithReceipts(iouReportID) { ); } +/** + * Gets all sorted money request reportActions + * + * @param {Object|null} iouReportID + * @returns {[Object]} + */ +function getSortedMoneyRequestActions(iouReportID) { + const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); + const filteredSortedReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); + + return _.reduce( + filteredSortedReportActions, + (transactions, action) => { + if (ReportActionsUtils.isMoneyRequestAction(action)) transactions.push(action); + return transactions; + }, + [], + ); +} + /** * For report previews, we display a "Receipt scan in progress" indicator * instead of the report total only when we have no report total ready to show. This is the case when @@ -1462,6 +1485,25 @@ function getReportPreviewMessage(report, reportAction = {}) { return `approved ${formattedAmount}`; } + /* === Start - Check for Report Scan === */ + + const filteredIouReportActions = getSortedMoneyRequestActions(report.reportID); + const lastIouReportAction = _.first(filteredIouReportActions); + const lastIouReportActionTransaction = TransactionUtils.getLinkedTransaction(lastIouReportAction); + + // get lastTransaction + // eslint-disable-next-line no-use-before-define + const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); + const lastTransaction = _.first(transactionsWithReceipts); + + const transactionIsLastReportAction = _.isEqual(lastIouReportActionTransaction, lastTransaction); + + if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { + return Localize.translateLocal('iou.receiptScanning'); + } + + /* === End - Check for Report Scan === */ + if (isSettled(report.reportID)) { // A settled report preview message can come in three formats "paid ... using Paypal.me", "paid ... elsewhere" or "paid ... using Expensify" let translatePhraseKey = 'iou.paidElsewhereWithAmount'; @@ -3635,4 +3677,5 @@ export { getReportPreviewDisplayTransactions, getTransactionsWithReceipts, getSortedTransactionsWithReceipts, + getSortedMoneyRequestActions, }; From 1c6bb4d9e3efbc8960850c2357828d50f0cf48d8 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 30 Aug 2023 18:05:34 +0530 Subject: [PATCH 05/25] Add lastIOUReportActions dependency to OptionRowLHNData --- .../LHNOptionsList/OptionRowLHNData.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 778c918936f16..506ab44cdbf83 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -81,6 +81,7 @@ function OptionRowLHNData({ policies, receiptTransactions, parentReportActions, + lastIOUReportActions, ...propsToForward }) { const reportID = propsToForward.reportID; @@ -113,7 +114,7 @@ function OptionRowLHNData({ const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(reportIDLocal); return _.first(transactionsWithReceipts); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport.reportID, receiptTransactions, reportActions]); + }, [fullReport.reportID, receiptTransactions, reportActions, lastIOUReportActions]); const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); @@ -220,6 +221,20 @@ export default React.memo( // This can lead to situations where `lastTransaction` doesn't update and retains the previous value. // However, performance overhead of this is minimized by using memos inside the component. receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION}, + lastIOUReportActions: { + key: ({fullReport, reportActions}) => { + let reportIDLocal = fullReport.reportID; + + // Check if reportIDLocal needs to be updated with the IOU report of the last report action, in case this report is a chat. + const filteredReportActions = ReportActionUtils.getFilteredSortedReportActionsForDisplay(reportActions); + const lastReportAction = _.first(filteredReportActions); + if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { + reportIDLocal = ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction); + } + return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportIDLocal}`; + }, + canEvict: false, + }, }), )(OptionRowLHNData), ); From 69b1700a06fa5be6874542b90e45d173485b1475 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 31 Aug 2023 20:29:27 +0530 Subject: [PATCH 06/25] Add ability to show receipt being scanned LHN subtitle for report with iou parent --- src/libs/OptionsListUtils.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 90f12bdfbcce7..6d9536e2ad4f4 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -17,6 +17,7 @@ import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as UserUtils from './UserUtils'; import * as ReportActionUtils from './ReportActionsUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import * as TransactionUtils from './TransactionUtils'; /** * OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can @@ -390,6 +391,11 @@ function getLastMessageTextForReport(report) { lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction); } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getModifiedExpenseMessage(lastReportAction); + + // check if it is an iou thread and if it has any message to show the scanned status + // eslint-disable-next-line no-use-before-define + } else if (isReportTransactionBeingScanned(report)) { + lastMessageTextFromReport = Localize.translateLocal('iou.receiptScanning'); } else { lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; @@ -408,6 +414,31 @@ function getLastMessageTextForReport(report) { return lastMessageTextFromReport; } +/** + * Checks if the given report satisfies the following conditions: + * 1. It is a chat thread. + * 2. Its parent report action is a transaction thread. + * 3. The transaction associated with the parent report action has a receipt. + * 4. The receipt is being scanned. + * 5. The last visible action of the report is either empty or created. + * + * @param {Object} report - The report to be checked. + * + * @returns {boolean} - True if all conditions are met, false otherwise. + */ +function isReportTransactionBeingScanned(report) { + const parentReportAction = ReportActionUtils.getParentReportAction(report); + const transaction = TransactionUtils.getLinkedTransaction(parentReportAction); + + return ( + ReportUtils.isChatThread(report) && + ReportActionUtils.isTransactionThread(parentReportAction) && + TransactionUtils.hasReceipt(transaction) && + TransactionUtils.isReceiptBeingScanned(transaction) && + (_.isEmpty(ReportActionUtils.getLastVisibleAction(report.reportID)) || ReportActionUtils.isCreatedAction(ReportActionUtils.getLastVisibleAction(report.reportID))) + ); +} + /** * Creates a report list option * From 2e8059f49f7e1d65353bf260941880b07e2d007c Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 18:52:44 +0530 Subject: [PATCH 07/25] Display "Receipt is scanning..." only if its the first reportAction --- src/libs/ReportUtils.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f196fc0e54af5..a1679a2b9bfe1 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1250,21 +1250,13 @@ function getMoneyRequestReportName(report, policy = undefined) { /* === Start - Check for Report Scan === */ - // get lastReportActionTransaction - const reportActions = ReportActionsUtils.getAllReportActions(report.reportID); - const filteredReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); - - const lastReportAction = _.first(filteredReportActions); - const lastReportActionTransaction = TransactionUtils.getLinkedTransaction(lastReportAction); - - // get lastTransaction // eslint-disable-next-line no-use-before-define - const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); - const lastTransaction = _.first(transactionsWithReceipts); + const moneyRequestreportActions = getSortedMoneyRequestActions(report.reportID); - const transactionIsLastReportAction = _.isEqual(lastReportActionTransaction, lastTransaction); + const firstReoprtAction = _.last(moneyRequestreportActions); + const firstReportActionTransaction = TransactionUtils.getLinkedTransaction(firstReoprtAction); - if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { + if (!_.isEmpty(firstReportActionTransaction) && TransactionUtils.isReceiptBeingScanned(firstReportActionTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } From 4a4fbcd93a95486207ec3c0237a891d6e83b216b Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 19:38:01 +0530 Subject: [PATCH 08/25] Check if thereAreFollowingManualIOURequests before showing report name as "Receipt being scanned..." --- src/libs/ReportUtils.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c559dec643cbf..278ea39b2e3fb 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1264,7 +1264,9 @@ function getMoneyRequestReportName(report, policy = undefined) { const firstReoprtAction = _.last(moneyRequestreportActions); const firstReportActionTransaction = TransactionUtils.getLinkedTransaction(firstReoprtAction); - if (!_.isEmpty(firstReportActionTransaction) && TransactionUtils.isReceiptBeingScanned(firstReportActionTransaction)) { + const thereAreFollowingManualIOURequests = getMoneyRequestTotal(report) > 0; + + if (!thereAreFollowingManualIOURequests && !_.isEmpty(firstReportActionTransaction) && TransactionUtils.isReceiptBeingScanned(firstReportActionTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } From a772a351e4f81ea76b626c56c4c1403af1ba00c0 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 19:48:39 +0530 Subject: [PATCH 09/25] Fix pretteir diff --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 278ea39b2e3fb..b1f06585d2f9e 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1264,7 +1264,7 @@ function getMoneyRequestReportName(report, policy = undefined) { const firstReoprtAction = _.last(moneyRequestreportActions); const firstReportActionTransaction = TransactionUtils.getLinkedTransaction(firstReoprtAction); - const thereAreFollowingManualIOURequests = getMoneyRequestTotal(report) > 0; + const thereAreFollowingManualIOURequests = getMoneyRequestTotal(report) > 0; if (!thereAreFollowingManualIOURequests && !_.isEmpty(firstReportActionTransaction) && TransactionUtils.isReceiptBeingScanned(firstReportActionTransaction)) { return Localize.translateLocal('iou.receiptScanning'); From bca81161f1d41d683c2def7129c2f5d5ca54b515 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 21:57:16 +0530 Subject: [PATCH 10/25] Don't show "Receipt being scanned..." for Workspace chat view LHN subtitle --- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 9f59e60fbc66d..2872243ffa32f 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -398,7 +398,7 @@ function getLastMessageTextForReport(report) { lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); - lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction); + lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction, false); } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getModifiedExpenseMessage(lastReportAction); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index b1f06585d2f9e..6a225d6af3372 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1479,9 +1479,10 @@ function getTransactionReportName(reportAction) { * * @param {Object} report * @param {Object} [reportAction={}] + * @param {Boolean} [shouldConsiderReceiptBeingScanned=true] * @returns {String} */ -function getReportPreviewMessage(report, reportAction = {}) { +function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceiptBeingScanned = true) { const reportActionMessage = lodashGet(reportAction, 'message[0].html', ''); if (_.isEmpty(report) || !report.reportID) { @@ -1500,19 +1501,21 @@ function getReportPreviewMessage(report, reportAction = {}) { /* === Start - Check for Report Scan === */ - const filteredIouReportActions = getSortedMoneyRequestActions(report.reportID); - const lastIouReportAction = _.first(filteredIouReportActions); - const lastIouReportActionTransaction = TransactionUtils.getLinkedTransaction(lastIouReportAction); + if (shouldConsiderReceiptBeingScanned) { + const filteredIouReportActions = getSortedMoneyRequestActions(report.reportID); + const lastIouReportAction = _.first(filteredIouReportActions); + const lastIouReportActionTransaction = TransactionUtils.getLinkedTransaction(lastIouReportAction); - // get lastTransaction - // eslint-disable-next-line no-use-before-define - const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); - const lastTransaction = _.first(transactionsWithReceipts); + // get lastTransaction + // eslint-disable-next-line no-use-before-define + const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); + const lastTransaction = _.first(transactionsWithReceipts); - const transactionIsLastReportAction = _.isEqual(lastIouReportActionTransaction, lastTransaction); + const transactionIsLastReportAction = _.isEqual(lastIouReportActionTransaction, lastTransaction); - if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { - return Localize.translateLocal('iou.receiptScanning'); + if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { + return Localize.translateLocal('iou.receiptScanning'); + } } /* === End - Check for Report Scan === */ From f018b21a17a674cddccc3bfb5e5ecac9b4398309 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 22:01:54 +0530 Subject: [PATCH 11/25] Don't show "Report is being scanned..." for Exprense Report View's LHN title --- src/libs/ReportUtils.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6a225d6af3372..6f79e8fcefa10 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1256,22 +1256,6 @@ function getMoneyRequestReportName(report, policy = undefined) { amount: formattedAmount, }); - /* === Start - Check for Report Scan === */ - - // eslint-disable-next-line no-use-before-define - const moneyRequestreportActions = getSortedMoneyRequestActions(report.reportID); - - const firstReoprtAction = _.last(moneyRequestreportActions); - const firstReportActionTransaction = TransactionUtils.getLinkedTransaction(firstReoprtAction); - - const thereAreFollowingManualIOURequests = getMoneyRequestTotal(report) > 0; - - if (!thereAreFollowingManualIOURequests && !_.isEmpty(firstReportActionTransaction) && TransactionUtils.isReceiptBeingScanned(firstReportActionTransaction)) { - return Localize.translateLocal('iou.receiptScanning'); - } - - /* === End - Check for Report Scan === */ - if (report.isWaitingOnBankAccount) { return `${payerPaidAmountMesssage} • ${Localize.translateLocal('iou.pending')}`; } From 1392317ab510608e6009509dffdebb2e7ec4b11f Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 22:05:08 +0530 Subject: [PATCH 12/25] Don't show "Receipt is being scanned..." in Request View LHN subtitle --- src/libs/OptionsListUtils.js | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 2872243ffa32f..368bbc2694a65 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -17,7 +17,6 @@ import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as UserUtils from './UserUtils'; import * as ReportActionUtils from './ReportActionsUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; -import * as TransactionUtils from './TransactionUtils'; import * as ErrorUtils from './ErrorUtils'; /** @@ -401,11 +400,6 @@ function getLastMessageTextForReport(report) { lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction, false); } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getModifiedExpenseMessage(lastReportAction); - - // check if it is an iou thread and if it has any message to show the scanned status - // eslint-disable-next-line no-use-before-define - } else if (isReportTransactionBeingScanned(report)) { - lastMessageTextFromReport = Localize.translateLocal('iou.receiptScanning'); } else { lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; @@ -424,31 +418,6 @@ function getLastMessageTextForReport(report) { return lastMessageTextFromReport; } -/** - * Checks if the given report satisfies the following conditions: - * 1. It is a chat thread. - * 2. Its parent report action is a transaction thread. - * 3. The transaction associated with the parent report action has a receipt. - * 4. The receipt is being scanned. - * 5. The last visible action of the report is either empty or created. - * - * @param {Object} report - The report to be checked. - * - * @returns {boolean} - True if all conditions are met, false otherwise. - */ -function isReportTransactionBeingScanned(report) { - const parentReportAction = ReportActionUtils.getParentReportAction(report); - const transaction = TransactionUtils.getLinkedTransaction(parentReportAction); - - return ( - ReportUtils.isChatThread(report) && - ReportActionUtils.isTransactionThread(parentReportAction) && - TransactionUtils.hasReceipt(transaction) && - TransactionUtils.isReceiptBeingScanned(transaction) && - (_.isEmpty(ReportActionUtils.getLastVisibleAction(report.reportID)) || ReportActionUtils.isCreatedAction(ReportActionUtils.getLastVisibleAction(report.reportID))) - ); -} - /** * Creates a report list option * From 59630d60041991056e87692e6b513302a861eb65 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 22:13:27 +0530 Subject: [PATCH 13/25] OptionRowLHNData Dependency cleanup for bca81161f1d41d683c2def7129c2f5d5ca54b515 --- .../LHNOptionsList/OptionRowLHNData.js | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 506ab44cdbf83..feadeaa323900 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -81,7 +81,6 @@ function OptionRowLHNData({ policies, receiptTransactions, parentReportActions, - lastIOUReportActions, ...propsToForward }) { const reportID = propsToForward.reportID; @@ -95,26 +94,13 @@ function OptionRowLHNData({ const optionItemRef = useRef(); - /** - * If it is an IOU report, you get the last transaction with a receipt. - * Otherwise, if the last message is a reportPreview in a chat, - * you get the last transaction of the IOU report associated with that preview message. - */ - const lastTransaction = useMemo(() => { let reportIDLocal = fullReport.reportID; - // Check if reportIDLocal needs to be updated with the IOU report of the last report action, in case this report is a chat. - const filteredReportActions = ReportActionUtils.getFilteredSortedReportActionsForDisplay(reportActions); - const lastReportAction = _.first(filteredReportActions); - if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { - reportIDLocal = ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction); - } - const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(reportIDLocal); return _.first(transactionsWithReceipts); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport.reportID, receiptTransactions, reportActions, lastIOUReportActions]); + }, [fullReport.reportID, receiptTransactions, reportActions]); const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); @@ -221,20 +207,6 @@ export default React.memo( // This can lead to situations where `lastTransaction` doesn't update and retains the previous value. // However, performance overhead of this is minimized by using memos inside the component. receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION}, - lastIOUReportActions: { - key: ({fullReport, reportActions}) => { - let reportIDLocal = fullReport.reportID; - - // Check if reportIDLocal needs to be updated with the IOU report of the last report action, in case this report is a chat. - const filteredReportActions = ReportActionUtils.getFilteredSortedReportActionsForDisplay(reportActions); - const lastReportAction = _.first(filteredReportActions); - if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { - reportIDLocal = ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction); - } - return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportIDLocal}`; - }, - canEvict: false, - }, }), )(OptionRowLHNData), ); From 73bdde1a64631084fc1bc37d3d539e5f7e3a19ff Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 22:22:57 +0530 Subject: [PATCH 14/25] set getReportPreviewMessage's shouldConsiderReceiptBeingScanned param to undefined/ false by default --- src/libs/OptionsListUtils.js | 4 ++-- src/libs/ReportUtils.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 368bbc2694a65..d26ad48430b07 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -394,10 +394,10 @@ function getLastMessageTextForReport(report) { if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { lastMessageTextFromReport = `[${Localize.translateLocal(report.lastMessageTranslationKey || 'common.attachment')}]`; } else if (ReportActionUtils.isMoneyRequestAction(lastReportAction)) { - lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction); + lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction, true); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); - lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction, false); + lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction); } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getModifiedExpenseMessage(lastReportAction); } else { diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6f79e8fcefa10..1c3393793abe8 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1463,10 +1463,10 @@ function getTransactionReportName(reportAction) { * * @param {Object} report * @param {Object} [reportAction={}] - * @param {Boolean} [shouldConsiderReceiptBeingScanned=true] + * @param {Boolean} [shouldConsiderReceiptBeingScanned=false] * @returns {String} */ -function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceiptBeingScanned = true) { +function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceiptBeingScanned) { const reportActionMessage = lodashGet(reportAction, 'message[0].html', ''); if (_.isEmpty(report) || !report.reportID) { From 03e4b3febdacb207a542be90afc8c915f3818177 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 4 Sep 2023 22:23:51 +0530 Subject: [PATCH 15/25] Linting fixes --- src/components/LHNOptionsList/OptionRowLHNData.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index feadeaa323900..e60b5e05e6baa 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -13,7 +13,6 @@ import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultPro import * as Report from '../../libs/actions/Report'; import * as UserUtils from '../../libs/UserUtils'; import * as ReportUtils from '../../libs/ReportUtils'; -import * as ReportActionUtils from '../../libs/ReportActionsUtils'; import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; @@ -95,9 +94,7 @@ function OptionRowLHNData({ const optionItemRef = useRef(); const lastTransaction = useMemo(() => { - let reportIDLocal = fullReport.reportID; - - const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(reportIDLocal); + const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); return _.first(transactionsWithReceipts); // eslint-disable-next-line react-hooks/exhaustive-deps }, [fullReport.reportID, receiptTransactions, reportActions]); From 2b99c3cec7fcd92965b564efdb0cb076876577b2 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 17:16:33 +0530 Subject: [PATCH 16/25] Refactoring - LHN subtitle report scan --- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index d26ad48430b07..a9c319865bbb1 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -394,7 +394,7 @@ function getLastMessageTextForReport(report) { if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { lastMessageTextFromReport = `[${Localize.translateLocal(report.lastMessageTranslationKey || 'common.attachment')}]`; } else if (ReportActionUtils.isMoneyRequestAction(lastReportAction)) { - lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction, true); + lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 1c3393793abe8..8af1ca9108112 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1463,10 +1463,9 @@ function getTransactionReportName(reportAction) { * * @param {Object} report * @param {Object} [reportAction={}] - * @param {Boolean} [shouldConsiderReceiptBeingScanned=false] * @returns {String} */ -function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceiptBeingScanned) { +function getReportPreviewMessage(report, reportAction = {}) { const reportActionMessage = lodashGet(reportAction, 'message[0].html', ''); if (_.isEmpty(report) || !report.reportID) { @@ -1485,19 +1484,10 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip /* === Start - Check for Report Scan === */ - if (shouldConsiderReceiptBeingScanned) { - const filteredIouReportActions = getSortedMoneyRequestActions(report.reportID); - const lastIouReportAction = _.first(filteredIouReportActions); - const lastIouReportActionTransaction = TransactionUtils.getLinkedTransaction(lastIouReportAction); + if (isIOUReport(report) && ReportActionsUtils.isMoneyRequestAction(reportAction)) { + const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); - // get lastTransaction - // eslint-disable-next-line no-use-before-define - const transactionsWithReceipts = getSortedTransactionsWithReceipts(report.reportID); - const lastTransaction = _.first(transactionsWithReceipts); - - const transactionIsLastReportAction = _.isEqual(lastIouReportActionTransaction, lastTransaction); - - if (lastTransaction && transactionIsLastReportAction && TransactionUtils.isReceiptBeingScanned(lastTransaction)) { + if (!_.isEmpty(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } } From b3f15ba969183d84c5ecefa73f1a9c3928d1fb47 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 17:28:36 +0530 Subject: [PATCH 17/25] Refactoring --- src/libs/ReportActionsUtils.js | 16 ---------------- src/libs/ReportUtils.js | 25 ++----------------------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 1f063a221e151..3ed10b865812d 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -434,21 +434,6 @@ function getSortedReportActionsForDisplay(reportActions) { return getSortedReportActions(filteredReportActions, true); } -/** - * Gets sorted and filtered report actions for display. - * - * First, it sorts the report actions using `getSortedReportActionsForDisplay`. - * Then, it filters out actions that are pending deletion. - * - * @param {Array} reportActions - The array of report actions to filter. - * @returns {Array} - The filtered and sorted array of report actions. - */ -function getFilteredSortedReportActionsForDisplay(reportActions) { - const sortedReportActions = getSortedReportActionsForDisplay(reportActions); - const filteredReportActions = _.filter(sortedReportActions, (reportAction) => reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); - return filteredReportActions; -} - /** * In some cases, there can be multiple closed report actions in a chat report. * This method returns the last closed report action so we can always show the correct archived report reason. @@ -660,5 +645,4 @@ export { isSplitBillAction, isTaskAction, getAllReportActions, - getFilteredSortedReportActionsForDisplay, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8af1ca9108112..c998a479b0f17 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1366,10 +1366,10 @@ function getTransactionsWithReceipts(iouReportID) { */ function getSortedTransactionsWithReceipts(iouReportID) { const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); - const filteredSortedReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); + const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); return _.reduce( - filteredSortedReportActions, + sortedReportActions, (transactions, action) => { if (ReportActionsUtils.isMoneyRequestAction(action)) { const transaction = TransactionUtils.getLinkedTransaction(action); @@ -1383,26 +1383,6 @@ function getSortedTransactionsWithReceipts(iouReportID) { ); } -/** - * Gets all sorted money request reportActions - * - * @param {Object|null} iouReportID - * @returns {[Object]} - */ -function getSortedMoneyRequestActions(iouReportID) { - const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); - const filteredSortedReportActions = ReportActionsUtils.getFilteredSortedReportActionsForDisplay(reportActions); - - return _.reduce( - filteredSortedReportActions, - (transactions, action) => { - if (ReportActionsUtils.isMoneyRequestAction(action)) transactions.push(action); - return transactions; - }, - [], - ); -} - /** * For report previews, we display a "Receipt scan in progress" indicator * instead of the report total only when we have no report total ready to show. This is the case when @@ -3670,6 +3650,5 @@ export { getReportPreviewDisplayTransactions, getTransactionsWithReceipts, getSortedTransactionsWithReceipts, - getSortedMoneyRequestActions, hasMissingSmartscanFields, }; From 41e35b63652fad7bea317f5b28ff5b52749212de Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 17:31:18 +0530 Subject: [PATCH 18/25] Bugfix - properly access iouReportID instead of reportID --- src/pages/home/report/ReportActionItemSingle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index ba44efa5f2748..bfbce8aed3363 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -141,7 +141,7 @@ function ReportActionItemSingle(props) { : props.action.person; const reportID = props.report && props.report.reportID; - const iouReportID = props.report && props.report.reportID; + const iouReportID = props.iouReport && props.iouReport.reportID; const showActorDetails = useCallback(() => { if (isWorkspaceActor) { From d9e57a7f12d3a0e6be80599ef83330eb609c4cc7 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 17:46:19 +0530 Subject: [PATCH 19/25] Revert LHN subtitle "Report scan in progress..." to use previous method via function argument for display logic. --- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index a9c319865bbb1..d26ad48430b07 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -394,7 +394,7 @@ function getLastMessageTextForReport(report) { if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { lastMessageTextFromReport = `[${Localize.translateLocal(report.lastMessageTranslationKey || 'common.attachment')}]`; } else if (ReportActionUtils.isMoneyRequestAction(lastReportAction)) { - lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction); + lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(report, lastReportAction, true); } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastReportAction); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c998a479b0f17..ac558cf33be11 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1443,9 +1443,10 @@ function getTransactionReportName(reportAction) { * * @param {Object} report * @param {Object} [reportAction={}] + * @param {Boolean} [shouldConsiderReceiptBeingScanned=false] * @returns {String} */ -function getReportPreviewMessage(report, reportAction = {}) { +function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceiptBeingScanned = false) { const reportActionMessage = lodashGet(reportAction, 'message[0].html', ''); if (_.isEmpty(report) || !report.reportID) { @@ -1464,7 +1465,7 @@ function getReportPreviewMessage(report, reportAction = {}) { /* === Start - Check for Report Scan === */ - if (isIOUReport(report) && ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (shouldConsiderReceiptBeingScanned && ReportActionsUtils.isMoneyRequestAction(reportAction)) { const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); if (!_.isEmpty(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { From cb294a2f2825608dd748a5d4e43f133a30baeaac Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 19:28:59 +0530 Subject: [PATCH 20/25] Refactoring LHN subtitle 'Receipt scan in progress...' --- .../LHNOptionsList/OptionRowLHNData.js | 8 +++--- src/libs/ReportUtils.js | 26 ------------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index e60b5e05e6baa..dbb779670eda6 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -12,7 +12,8 @@ import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDe import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultProps} from './OptionRowLHN'; import * as Report from '../../libs/actions/Report'; import * as UserUtils from '../../libs/UserUtils'; -import * as ReportUtils from '../../libs/ReportUtils'; +import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; +import * as TransactionUtils from '../../libs/TransactionUtils'; import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; @@ -94,8 +95,9 @@ function OptionRowLHNData({ const optionItemRef = useRef(); const lastTransaction = useMemo(() => { - const transactionsWithReceipts = ReportUtils.getSortedTransactionsWithReceipts(fullReport.reportID); - return _.first(transactionsWithReceipts); + const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); + const lastReportAction = _.first(sortedReportActions); + return TransactionUtils.getLinkedTransaction(lastReportAction); // eslint-disable-next-line react-hooks/exhaustive-deps }, [fullReport.reportID, receiptTransactions, reportActions]); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ac558cf33be11..1b58a4d73ce82 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1358,31 +1358,6 @@ function getTransactionsWithReceipts(iouReportID) { return _.filter(allTransactions, (transaction) => TransactionUtils.hasReceipt(transaction)); } -/** - * Gets all sorted transactions on an IOU report with a receipt and whose pending action is not delete - * - * @param {Object|null} iouReportID - * @returns {[Object]} - */ -function getSortedTransactionsWithReceipts(iouReportID) { - const reportActions = ReportActionsUtils.getAllReportActions(iouReportID); - const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - - return _.reduce( - sortedReportActions, - (transactions, action) => { - if (ReportActionsUtils.isMoneyRequestAction(action)) { - const transaction = TransactionUtils.getLinkedTransaction(action); - if (TransactionUtils.hasReceipt(transaction)) { - transactions.push(transaction); - } - } - return transactions; - }, - [], - ); -} - /** * For report previews, we display a "Receipt scan in progress" indicator * instead of the report total only when we have no report total ready to show. This is the case when @@ -3650,6 +3625,5 @@ export { areAllRequestsBeingSmartScanned, getReportPreviewDisplayTransactions, getTransactionsWithReceipts, - getSortedTransactionsWithReceipts, hasMissingSmartscanFields, }; From 55688505e8c8d0c663d9c789d63e55b8fda5e59f Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 20:02:49 +0530 Subject: [PATCH 21/25] Refactoring --- .../LHNOptionsList/OptionRowLHNData.js | 5 +--- src/hooks/useDeepCompareMemo.js | 26 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 src/hooks/useDeepCompareMemo.js diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index dbb779670eda6..2d6ff6fcfb736 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -18,7 +18,6 @@ import * as TransactionUtils from '../../libs/TransactionUtils'; import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; -import useDeepCompareMemo from '../../hooks/useDeepCompareMemo'; const propTypes = { /** If true will disable ever setting the OptionRowLHN to focused */ @@ -101,8 +100,6 @@ function OptionRowLHNData({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [fullReport.reportID, receiptTransactions, reportActions]); - const memoizedLastTransaction = useDeepCompareMemo(lastTransaction); - const optionItem = useMemo(() => { // Note: ideally we'd have this as a dependent selector in onyx! const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy); @@ -113,7 +110,7 @@ function OptionRowLHNData({ return item; // Listen parentReportAction to update title of thread report when parentReportAction changed // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport, memoizedLastTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); + }, [fullReport, lastTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); useEffect(() => { if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) { diff --git a/src/hooks/useDeepCompareMemo.js b/src/hooks/useDeepCompareMemo.js deleted file mode 100644 index ebed9ffdeebec..0000000000000 --- a/src/hooks/useDeepCompareMemo.js +++ /dev/null @@ -1,26 +0,0 @@ -import {useRef} from 'react'; -import _ from 'lodash'; - -/** - * Custom hook to memoize a value based on deep comparison. - * Returns the previous value if the current value is deeply equal to the previous one. - * - * @function - * @template T - * @param {T} value - The value to be memoized. - * @returns {T} - The memoized value. Returns the previous value if the current value is deeply equal to the previous one. - * @example - * - * const object = { a: 1, b: 2 }; - * const memoizedObject = useDeepCompareMemo(object); - */ -export default function useDeepCompareMemo(value) { - const ref = useRef(); // Holds the previous value - - // If the new value is not deeply equal to the old value, update the ref - if (!_.isEqual(value, ref.current)) { - ref.current = value; - } - - return ref.current; -} From 554608198a2f1f5d037484e275f26bfa92870d43 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Tue, 5 Sep 2023 22:29:51 +0530 Subject: [PATCH 22/25] Remove unnecessary comment Co-authored-by: Carlos Martins --- src/libs/ReportUtils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 1b58a4d73ce82..33721d89d5039 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1448,8 +1448,6 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip } } - /* === End - Check for Report Scan === */ - if (isSettled(report.reportID)) { // A settled report preview message can come in three formats "paid ... using Paypal.me", "paid ... elsewhere" or "paid ... using Expensify" let translatePhraseKey = 'iou.paidElsewhereWithAmount'; From ebad276423857eda589db81ec0226236067471d4 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Tue, 5 Sep 2023 22:30:18 +0530 Subject: [PATCH 23/25] Remove unnecessary comment Co-authored-by: Carlos Martins --- src/libs/ReportUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 33721d89d5039..cefc9674bcfc5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1438,7 +1438,6 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip return `approved ${formattedAmount}`; } - /* === Start - Check for Report Scan === */ if (shouldConsiderReceiptBeingScanned && ReportActionsUtils.isMoneyRequestAction(reportAction)) { const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); From f652ef558dd1fea6227c2d33d3e05c63e55d0ae2 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 22:39:04 +0530 Subject: [PATCH 24/25] Prettier linting --- src/libs/ReportUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index cefc9674bcfc5..7390bac47dd1f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1438,7 +1438,6 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip return `approved ${formattedAmount}`; } - if (shouldConsiderReceiptBeingScanned && ReportActionsUtils.isMoneyRequestAction(reportAction)) { const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); From 4811977a3acb278ca1e210601eb521584ba8db95 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 00:02:01 +0530 Subject: [PATCH 25/25] rename lastTransaction to linkedTransaction in OptionRowLHNData --- src/components/LHNOptionsList/OptionRowLHNData.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 2d6ff6fcfb736..4c7bd54efa180 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -93,7 +93,7 @@ function OptionRowLHNData({ const optionItemRef = useRef(); - const lastTransaction = useMemo(() => { + const linkedTransaction = useMemo(() => { const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); const lastReportAction = _.first(sortedReportActions); return TransactionUtils.getLinkedTransaction(lastReportAction); @@ -110,7 +110,7 @@ function OptionRowLHNData({ return item; // Listen parentReportAction to update title of thread report when parentReportAction changed // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport, lastTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); + }, [fullReport, linkedTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction]); useEffect(() => { if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) {