From 101cf9b99b04868ba56858d9a8cfd36ad2c1a69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 15 May 2025 12:51:12 +0200 Subject: [PATCH 01/10] offline pattern in the report table view --- .../MoneyRequestReportTransactionList.tsx | 5 +- src/components/TransactionItemRow/index.tsx | 284 +++++++++--------- src/libs/TransactionUtils/index.ts | 10 + tests/unit/TransactionUtilsTest.ts | 20 ++ 4 files changed, 178 insertions(+), 141 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index f77b791ccfc2..d82aa6c4f1e8 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -27,6 +27,7 @@ import {navigationRef} from '@libs/Navigation/Navigation'; import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils'; import {generateReportID, getMoneyRequestSpendBreakdown} from '@libs/ReportUtils'; import {compareValues} from '@libs/SearchUIUtils'; +import {getTransactionPendingAction} from '@libs/TransactionUtils'; import shouldShowTransactionYear from '@libs/TransactionUtils/shouldShowTransactionYear'; import Navigation from '@navigation/Navigation'; import type {ReportsSplitNavigatorParamList} from '@navigation/types'; @@ -96,7 +97,7 @@ function MoneyRequestReportTransactionList({report, transactions, reportActions, const formattedOutOfPocketAmount = convertToDisplayString(reimbursableSpend, report?.currency); const formattedCompanySpendAmount = convertToDisplayString(nonReimbursableSpend, report?.currency); const shouldShowBreakdown = !!nonReimbursableSpend && !!reimbursableSpend; - + const pendingAction = transactions.some((t) => getTransactionPendingAction(t)); const {bind} = useHover(); const {isMouseDownOnInput, setMouseUp} = useMouseContext(); @@ -302,7 +303,7 @@ function MoneyRequestReportTransactionList({report, transactions, reportActions, {hasComments ? translate('common.comments') : ''} {translate('common.total')} - + {convertToDisplayString(totalDisplaySpend, report?.currency)} diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index aaca88fbac54..4443809f7d74 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -3,6 +3,7 @@ import {View} from 'react-native'; import Animated from 'react-native-reanimated'; import Checkbox from '@components/Checkbox'; import type {TransactionWithOptionalHighlight} from '@components/MoneyRequestReportView/MoneyRequestReportTransactionList'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {TableColumnSize} from '@components/Search/types'; import DateCell from '@components/SelectionList/Search/DateCell'; import Text from '@components/Text'; @@ -11,7 +12,7 @@ import useHover from '@hooks/useHover'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getMerchant, getCreated as getTransactionCreated, isPartialMerchant} from '@libs/TransactionUtils'; +import {getMerchant, getCreated as getTransactionCreated, getTransactionPendingAction, isPartialMerchant} from '@libs/TransactionUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import CategoryCell from './DataCells/CategoryCell'; @@ -43,7 +44,7 @@ function TransactionItemRow({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const theme = useTheme(); - + const pendingAction = getTransactionPendingAction(transactionItem); const hasCategoryOrTag = !!transactionItem.category || !!transactionItem.tag; const createdAt = getTransactionCreated(transactionItem); @@ -76,12 +77,103 @@ function TransactionItemRow({ onMouseLeave={bindHover.onMouseLeave} onMouseEnter={bindHover.onMouseEnter} > - {shouldUseNarrowLayout ? ( - - - - {shouldShowCheckbox && ( - + + {shouldUseNarrowLayout ? ( + + + + {shouldShowCheckbox && ( + + { + onCheckboxPress(transactionItem.transactionID); + }} + accessibilityLabel={CONST.ROLE.CHECKBOX} + isChecked={isSelected} + /> + + )} + + + + + + + + + {isMerchantEmpty && ( + + + + )} + + {!isMerchantEmpty && ( + + + + + )} + + + + + {hasCategoryOrTag && ( + + + + + )} + + + + + + + ) : ( + + + + { onCheckboxPress(transactionItem.transactionID); @@ -90,149 +182,63 @@ function TransactionItemRow({ isChecked={isSelected} /> - )} - - - - - + + + + + + + - - + + + + + + + + + + + + + + - {isMerchantEmpty && ( - - - - )} - {!isMerchantEmpty && ( - - - - - )} - - - - - {hasCategoryOrTag && ( - - - - - )} - - - - - - - ) : ( - - - - - { - onCheckboxPress(transactionItem.transactionID); - }} - accessibilityLabel={CONST.ROLE.CHECKBOX} - isChecked={isSelected} - /> - - - - - - - - - - - - - - - - - - - - - - - - + - - - - )} + + )} + ); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index ecdad93934f0..a8603acca2c7 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -44,6 +44,7 @@ import type {IOUType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxInputOrEntry, Policy, RecentWaypoint, Report, ReviewDuplicates, TaxRate, TaxRates, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx'; import type {Attendee} from '@src/types/onyx/IOU'; +import type {PendingAction} from '@src/types/onyx/OnyxCommon'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, Receipt, TransactionChanges, TransactionCustomUnit, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; @@ -1529,6 +1530,14 @@ function shouldShowRTERViolationMessage(transactions?: Transaction[]) { return transactions?.length === 1 && hasPendingUI(transactions?.at(0), getTransactionViolations(transactions?.at(0)?.transactionID, allTransactionViolations)); } + +/** + * Return transactions pending action. + */ +function getTransactionPendingAction(transaction: OnyxEntry): PendingAction { + return transaction?.pendingAction ?? (Object.keys(transaction?.pendingFields ?? {}).length > 0 ? CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE : null); +} + export { buildOptimisticTransaction, calculateTaxAmount, @@ -1625,6 +1634,7 @@ export { isPartialTransaction, isPendingCardOrScanningTransaction, checkIfShouldShowMarkAsCashButton, + getTransactionPendingAction, }; export type {TransactionChanges}; diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 73556a8b8757..ff91901be194 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -484,4 +484,24 @@ describe('TransactionUtils', () => { }); }); }); + describe('getTransactionPendingAction', () => { + it.each([ + ['when pendingAction is null', null, null], + ['when pendingAction is delete', CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE], + ['when pendingAction is add', CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD], + ])('%s', (_description, pendingAction, expected) => { + const transaction = generateTransaction({pendingAction}); + const result = TransactionUtils.getTransactionPendingAction(transaction); + expect(result).toEqual(expected); + }); + it('when pendingAction is update', () => { + const pendingAction = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; + const transaction = generateTransaction({ + pendingFields: {amount: pendingAction}, + pendingAction: null, + }); + const result = TransactionUtils.getTransactionPendingAction(transaction); + expect(result).toEqual(pendingAction); + }); + }); }); From d05d12a550caccbad35e7b5aa3d73546dbaf5670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 15 May 2025 13:12:04 +0200 Subject: [PATCH 02/10] fix prettier --- src/libs/TransactionUtils/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index c3f9b6e89a16..334e6a004b8a 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1533,7 +1533,6 @@ function shouldShowRTERViolationMessage(transactions?: Transaction[]) { return transactions?.length === 1 && hasPendingUI(transactions?.at(0), getTransactionViolations(transactions?.at(0)?.transactionID, allTransactionViolations)); } - /** * Return transactions pending action. */ From 2a31f5285f900b3b641f8bbf287cc3de17c003aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Mon, 19 May 2025 16:22:13 +0200 Subject: [PATCH 03/10] add errors display in the table view --- .../TransactionItemRowRBR.tsx | 48 +++++++++++++++---- src/languages/en.ts | 1 + src/languages/es.ts | 1 + 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index 7370936698d0..a383f850c074 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -1,16 +1,22 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {ViewStyle} from 'react-native'; import {View} from 'react-native'; import Icon from '@components/Icon'; import {DotIndicator} from '@components/Icon/Expensicons'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePaginatedReportActions from '@hooks/usePaginatedReportActions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionViolations from '@hooks/useTransactionViolations'; +import {isReceiptError} from '@libs/ErrorUtils'; +import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import variables from '@styles/variables'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; +import type ReportAction from '@src/types/onyx/ReportAction'; import type Transaction from '@src/types/onyx/Transaction'; +import type {ReceiptErrors} from '@src/types/onyx/Transaction'; function TransactionItemRowRBR({transaction, containerStyles}: {transaction: Transaction; containerStyles?: ViewStyle[]}) { const styles = useThemeStyles(); @@ -18,17 +24,41 @@ function TransactionItemRowRBR({transaction, containerStyles}: {transaction: Tra const {translate} = useLocalize(); const theme = useTheme(); - // Some violations end with a period already so lets make sure the connected messages have only single period between them - // and end with a single dot. - const RBRMessages = transactionViolations - .map((violation) => { + const {sortedAllReportActions: transactionActions} = usePaginatedReportActions(transaction.reportID); + const transactionThreadId = transactionActions ? getIOUActionForTransactionID(transactionActions, transaction.transactionID)?.childReportID : undefined; + const {sortedAllReportActions: transactionThreadActions} = usePaginatedReportActions(transactionThreadId); + const getErrorMessages = useCallback( + (errors: Errors | ReceiptErrors | undefined = {}, errorActions: ReportAction[] | undefined = []): string[] => { + const uniqueMessages = new Set(); + + const addErrorMessages = (rawErrors: unknown) => { + const errorValues = Object.values(rawErrors ?? {}); + for (const error of errorValues) { + const message = isReceiptError(error) ? translate('iou.error.receiptFailureMessageShort') : String(error); + uniqueMessages.add(message); + } + }; + addErrorMessages(errors); + for (const action of errorActions) { + addErrorMessages(action.errors); + } + + return Array.from(uniqueMessages); + }, + [translate], + ); + + const RBRMessages = [ + ...getErrorMessages(transaction?.errors, transactionThreadActions?.filter((e) => !!e.errors) ?? []), + // Some violations end with a period already so lets make sure the connected messages have only single period between them + // and end with a single dot. + ...transactionViolations.map((violation) => { const message = ViolationsUtils.getViolationTranslation(violation, translate); return message.endsWith('.') || transactionViolations.length === 1 ? message : `${message}.`; - }) - .join(' '); - + }), + ].join(' '); return ( - transactionViolations.length > 0 && ( + RBRMessages.length > 0 && ( Date: Wed, 21 May 2025 13:32:55 +0200 Subject: [PATCH 04/10] cleanup RBR component --- .../TransactionItemRowRBR.tsx | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index a383f850c074..d90136866516 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -3,6 +3,7 @@ import type {ViewStyle} from 'react-native'; import {View} from 'react-native'; import Icon from '@components/Icon'; import {DotIndicator} from '@components/Icon/Expensicons'; +import type {LocaleContextProps} from '@components/LocaleContextProvider'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import usePaginatedReportActions from '@hooks/usePaginatedReportActions'; @@ -18,7 +19,34 @@ import type ReportAction from '@src/types/onyx/ReportAction'; import type Transaction from '@src/types/onyx/Transaction'; import type {ReceiptErrors} from '@src/types/onyx/Transaction'; -function TransactionItemRowRBR({transaction, containerStyles}: {transaction: Transaction; containerStyles?: ViewStyle[]}) { +type TransactionItemRowRBRProps = { + transaction: Transaction; + containerStyles?: ViewStyle[]; +}; + +/** + * Extracts unique error messages from errors and actions + */ +const extractErrorMessages = (errors: Errors | ReceiptErrors | undefined, errorActions: ReportAction[] | undefined, translate: LocaleContextProps['translate']): string[] => { + const uniqueMessages = new Set(); + + const addErrorMessages = (rawErrors: unknown) => { + const errorValues = Object.values(rawErrors ?? {}); + for (const error of errorValues) { + + const message = isReceiptError(error) ? translate('iou.error.receiptFailureMessageShort') : String(error); + uniqueMessages.add(message); + } + }; + + addErrorMessages(errors); + for (const action of errorActions ?? []) { + addErrorMessages(action.errors); + } + + return Array.from(uniqueMessages); +}; +function TransactionItemRowRBR({transaction, containerStyles}: TransactionItemRowRBRProps) { const styles = useThemeStyles(); const transactionViolations = useTransactionViolations(transaction?.transactionID); const {translate} = useLocalize(); @@ -28,23 +56,7 @@ function TransactionItemRowRBR({transaction, containerStyles}: {transaction: Tra const transactionThreadId = transactionActions ? getIOUActionForTransactionID(transactionActions, transaction.transactionID)?.childReportID : undefined; const {sortedAllReportActions: transactionThreadActions} = usePaginatedReportActions(transactionThreadId); const getErrorMessages = useCallback( - (errors: Errors | ReceiptErrors | undefined = {}, errorActions: ReportAction[] | undefined = []): string[] => { - const uniqueMessages = new Set(); - - const addErrorMessages = (rawErrors: unknown) => { - const errorValues = Object.values(rawErrors ?? {}); - for (const error of errorValues) { - const message = isReceiptError(error) ? translate('iou.error.receiptFailureMessageShort') : String(error); - uniqueMessages.add(message); - } - }; - addErrorMessages(errors); - for (const action of errorActions) { - addErrorMessages(action.errors); - } - - return Array.from(uniqueMessages); - }, + (errors: Errors | ReceiptErrors | undefined = {}, errorActions: ReportAction[] | undefined = []) => extractErrorMessages(errors, errorActions, translate), [translate], ); From 9edd6c4902b3dab97baa2610b123ae537b0274f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Wed, 21 May 2025 14:49:36 +0200 Subject: [PATCH 05/10] prettier fix --- src/components/TransactionItemRow/TransactionItemRowRBR.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index d90136866516..9d61599937a3 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -33,7 +33,6 @@ const extractErrorMessages = (errors: Errors | ReceiptErrors | undefined, errorA const addErrorMessages = (rawErrors: unknown) => { const errorValues = Object.values(rawErrors ?? {}); for (const error of errorValues) { - const message = isReceiptError(error) ? translate('iou.error.receiptFailureMessageShort') : String(error); uniqueMessages.add(message); } From 9e27901bbb8a610f8f1c2bc00f48c5bbb6e93925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 22 May 2025 10:59:33 +0200 Subject: [PATCH 06/10] update readability v1 --- .../MoneyRequestReportTransactionList.tsx | 9 +++++++-- src/libs/TransactionUtils/index.ts | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 7229df4a7910..f584ddf3f7ae 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -105,7 +105,12 @@ function MoneyRequestReportTransactionList({report, transactions, reportActions, const formattedOutOfPocketAmount = convertToDisplayString(reimbursableSpend, report?.currency); const formattedCompanySpendAmount = convertToDisplayString(nonReimbursableSpend, report?.currency); const shouldShowBreakdown = !!nonReimbursableSpend && !!reimbursableSpend; - const pendingAction = transactions.some((t) => getTransactionPendingAction(t)); + + const pendingChangesOpacity = useMemo(() => { + const pendingAction = transactions.some(getTransactionPendingAction); + return pendingAction && styles.opacitySemiTransparent; + }, [styles.opacitySemiTransparent, transactions]); + const {bind} = useHover(); const {isMouseDownOnInput, setMouseUp} = useMouseContext(); @@ -305,7 +310,7 @@ function MoneyRequestReportTransactionList({report, transactions, reportActions, {hasComments ? translate('common.comments') : ''} {translate('common.total')} - + {convertToDisplayString(totalDisplaySpend, report?.currency)} diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index abea62012058..7754ee26ba1a 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1555,7 +1555,11 @@ function shouldShowRTERViolationMessage(transactions?: Transaction[]) { * Return transactions pending action. */ function getTransactionPendingAction(transaction: OnyxEntry): PendingAction { - return transaction?.pendingAction ?? (Object.keys(transaction?.pendingFields ?? {}).length > 0 ? CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE : null); + if (transaction?.pendingAction) { + return transaction.pendingAction; + } + const hasPendingFields = Object.keys(transaction?.pendingFields ?? {}).length > 0; + return hasPendingFields ? CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE : null; } export { From 7ef0abde4910bb73572283aa18292b9462a75f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 22 May 2025 16:39:39 +0200 Subject: [PATCH 07/10] extractErrorMessages refactor --- .../TransactionItemRowRBR.tsx | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index 9d61599937a3..5022f688762f 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -17,7 +17,7 @@ import variables from '@styles/variables'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type ReportAction from '@src/types/onyx/ReportAction'; import type Transaction from '@src/types/onyx/Transaction'; -import type {ReceiptErrors} from '@src/types/onyx/Transaction'; +import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction'; type TransactionItemRowRBRProps = { transaction: Transaction; @@ -30,21 +30,34 @@ type TransactionItemRowRBRProps = { const extractErrorMessages = (errors: Errors | ReceiptErrors | undefined, errorActions: ReportAction[] | undefined, translate: LocaleContextProps['translate']): string[] => { const uniqueMessages = new Set(); - const addErrorMessages = (rawErrors: unknown) => { - const errorValues = Object.values(rawErrors ?? {}); - for (const error of errorValues) { - const message = isReceiptError(error) ? translate('iou.error.receiptFailureMessageShort') : String(error); - uniqueMessages.add(message); - } - }; + // Combine transaction and action errors + let allErrors: Record = {...(errors ?? {})}; + (errorActions ?? []).forEach((action) => { + allErrors = {...allErrors, ...(action.errors ?? {})}; + }); - addErrorMessages(errors); - for (const action of errorActions ?? []) { - addErrorMessages(action.errors); - } + // Extract error messages + Object.values(allErrors).forEach((errorValue) => { + if (!errorValue) { + return; + } + if (typeof errorValue === 'string') { + uniqueMessages.add(errorValue); + } else if (isReceiptError(errorValue)) { + uniqueMessages.add(translate('iou.error.receiptFailureMessageShort')); + } else { + Object.values(errorValue ?? {}).forEach((nestedErrorValue) => { + if (!nestedErrorValue) { + return; + } + uniqueMessages.add(nestedErrorValue); + }); + } + }); return Array.from(uniqueMessages); }; + function TransactionItemRowRBR({transaction, containerStyles}: TransactionItemRowRBRProps) { const styles = useThemeStyles(); const transactionViolations = useTransactionViolations(transaction?.transactionID); From 12e702c05e093a73d8a4285de593c71800f022e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Fri, 23 May 2025 09:37:10 +0200 Subject: [PATCH 08/10] remove redundant defaults --- .../TransactionItemRowRBR.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index 1d2103991ce9..eeb3104a5f8e 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -27,13 +27,16 @@ type TransactionItemRowRBRProps = { /** * Extracts unique error messages from errors and actions */ -const extractErrorMessages = (errors: Errors | ReceiptErrors | undefined, errorActions: ReportAction[] | undefined, translate: LocaleContextProps['translate']): string[] => { +const extractErrorMessages = (errors: Errors | ReceiptErrors, errorActions: ReportAction[], translate: LocaleContextProps['translate']): string[] => { const uniqueMessages = new Set(); // Combine transaction and action errors - let allErrors: Record = {...(errors ?? {})}; - (errorActions ?? []).forEach((action) => { - allErrors = {...allErrors, ...(action.errors ?? {})}; + let allErrors: Record = {...errors}; + errorActions.forEach((action) => { + if (!action.errors) { + return; + } + allErrors = {...allErrors, ...action.errors}; }); // Extract error messages @@ -46,7 +49,7 @@ const extractErrorMessages = (errors: Errors | ReceiptErrors | undefined, errorA } else if (isReceiptError(errorValue)) { uniqueMessages.add(translate('iou.error.receiptFailureMessageShort')); } else { - Object.values(errorValue ?? {}).forEach((nestedErrorValue) => { + Object.values(errorValue).forEach((nestedErrorValue) => { if (!nestedErrorValue) { return; } @@ -73,7 +76,10 @@ function TransactionItemRowRBR({transaction, containerStyles}: TransactionItemRo ); const RBRMessages = [ - ...getErrorMessages(transaction?.errors, transactionThreadActions?.filter((e) => !!e.errors) ?? []), + ...getErrorMessages( + transaction?.errors, + transactionThreadActions?.filter((e) => !!e.errors), + ), // Some violations end with a period already so lets make sure the connected messages have only single period between them // and end with a single dot. ...transactionViolations.map((violation) => { From f456117d8b40f61964d3d5c27f580a34bfa4e794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 27 May 2025 14:02:02 +0200 Subject: [PATCH 09/10] fix PR comments --- .../MoneyRequestReportTransactionList.tsx | 4 ++-- src/components/TransactionItemRow/TransactionItemRowRBR.tsx | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 947a93853de3..a5f83f231a69 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -123,7 +123,7 @@ function MoneyRequestReportTransactionList({ const formattedCompanySpendAmount = convertToDisplayString(nonReimbursableSpend, report?.currency); const shouldShowBreakdown = !!nonReimbursableSpend && !!reimbursableSpend; - const pendingChangesOpacity = useMemo(() => { + const pendingActionsOpacity = useMemo(() => { const pendingAction = transactions.some(getTransactionPendingAction); return pendingAction && styles.opacitySemiTransparent; }, [styles.opacitySemiTransparent, transactions]); @@ -320,7 +320,7 @@ function MoneyRequestReportTransactionList({ {translate('common.total')} - + {convertToDisplayString(totalDisplaySpend, report?.currency)} diff --git a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx index eeb3104a5f8e..5828fd1ab1cc 100644 --- a/src/components/TransactionItemRow/TransactionItemRowRBR.tsx +++ b/src/components/TransactionItemRow/TransactionItemRowRBR.tsx @@ -20,7 +20,10 @@ import type Transaction from '@src/types/onyx/Transaction'; import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction'; type TransactionItemRowRBRProps = { + /** Transaction item */ transaction: Transaction; + + /** Styles for the RBR messages container */ containerStyles?: ViewStyle[]; }; From e55740a701159da723aa129db68d21d17f8afaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Wed, 28 May 2025 10:24:18 +0200 Subject: [PATCH 10/10] block row interactions when transaction is pending delete --- .../MoneyRequestReportTransactionList.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index a5f83f231a69..2f6c905515d4 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -234,6 +234,7 @@ function MoneyRequestReportTransactionList({ )} {sortedTransactions.map((transaction) => { + const isPendingDelete = getTransactionPendingAction(transaction) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; return (