diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/ReportPreviewHeader.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/ReportPreviewHeader.tsx index e065af642c5d..4f4e7a3a2992 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/ReportPreviewHeader.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/ReportPreviewHeader.tsx @@ -66,9 +66,6 @@ function ReportPreviewHeader() { [translate, numberOfRequests], ); - // A cancelled payment is a report level event and it isn't surfaced by the status badge, so we show it next to the expense count. - const supportingText = iouReport?.isCancelledIOU ? `${translate('iou.canceled')} ${CONST.DOT_SEPARATOR} ${expenseCount}` : expenseCount; - const reportStateNum = iouReport?.stateNum ?? action?.childStateNum; const reportStatusNum = iouReport?.statusNum ?? action?.childStatusNum; @@ -84,6 +81,11 @@ function ReportPreviewHeader() { const shouldShowReportStatus = !!reportStatus && !!expenseCount; + // The badge can't express a cancelled payment, so it sits next to the expense count - unless the badge already reads "Approved", + // which is the state cancelling returns an approving workspace to. + const isApprovedReport = reportStateNum === CONST.REPORT.STATE_NUM.APPROVED && reportStatusNum === CONST.REPORT.STATUS_NUM.APPROVED; + const supportingText = iouReport?.isCancelledIOU && !isApprovedReport ? `${translate('iou.canceled')} ${CONST.DOT_SEPARATOR} ${expenseCount}` : expenseCount; + const reportStatusColorStyle = useMemo(() => getReportStatusColorStyle(theme, reportStateNum, reportStatusNum), [reportStateNum, reportStatusNum, theme]); const reportStatusTooltip = useMemo( diff --git a/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx b/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx index da0f404b93ff..abe103137a48 100644 --- a/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx +++ b/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx @@ -2,7 +2,6 @@ import MultiAccountAvatar from '@components/Avatar/connected/MultiAccountAvatar' import Button from '@components/ButtonComposed'; import Icon from '@components/Icon'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import {ReportPreviewDataContext} from '@components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContext'; import ReportActionItemImages from '@components/ReportActionItem/ReportActionItemImages'; import UserInfoCellsWithArrow from '@components/Search/SearchList/ListItem/UserInfoCellsWithArrow'; import Text from '@components/Text'; @@ -46,7 +45,7 @@ import {cardByIdSelector} from '@src/selectors/Card'; import {getStableReportSelector} from '@src/selectors/Report'; import truncate from 'lodash/truncate'; -import React, {useContext, useMemo} from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; import Animated from 'react-native-reanimated'; @@ -135,11 +134,6 @@ function TransactionPreviewContent({ const {shouldShowRBR, shouldShowMerchant, shouldShowSplitShare, shouldShowCategory, shouldShowSkeleton, shouldShowDescription} = conditionals; - // Raw useContext (not the useReportPreviewData slice hook, which throws when absent): a missing provider means this is a - // standalone preview with no report header to carry the status, so the preview has to report a cancelled payment itself. - const isInsideReportPreview = !!useContext(ReportPreviewDataContext); - const shouldShowCanceledStatus = !isInsideReportPreview; - const isIOUActionType = isMoneyRequestAction(action); const canEdit = isIOUActionType && canEditMoneyRequest(action, transaction, isChatReportArchived, report, policy, reportActions); const companyCardPageURL = `${environmentURL}/${ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(report?.policyID)}`; @@ -169,13 +163,12 @@ function TransactionPreviewContent({ dateFnsLocale, ...transactionPreviewCommonArguments, shouldShowRBR, - shouldShowCanceledStatus, violationMessage, reportActions, originalTransaction, convertToDisplayString, }), - [transactionPreviewCommonArguments, shouldShowRBR, shouldShowCanceledStatus, violationMessage, reportActions, originalTransaction, convertToDisplayString, dateFnsLocale], + [transactionPreviewCommonArguments, shouldShowRBR, violationMessage, reportActions, originalTransaction, convertToDisplayString, dateFnsLocale], ); const getTranslatedText = (item: TranslationPathOrText) => (item.translationPath ? translate(item.translationPath) : (item.text ?? '')); diff --git a/src/libs/TransactionPreviewUtils.ts b/src/libs/TransactionPreviewUtils.ts index 8933f4e71166..7fee7d14525e 100644 --- a/src/libs/TransactionPreviewUtils.ts +++ b/src/libs/TransactionPreviewUtils.ts @@ -210,7 +210,6 @@ function getTransactionPreviewTextAndTranslationPaths({ transactionDetails, isBillSplit, shouldShowRBR, - shouldShowCanceledStatus, violationMessage, reportActions, originalTransaction, @@ -225,8 +224,6 @@ function getTransactionPreviewTextAndTranslationPaths({ transactionDetails: Partial; isBillSplit: boolean; shouldShowRBR: boolean; - /** Whether a cancelled payment has to be reported on this line, because the enclosing surface doesn't show it anywhere else */ - shouldShowCanceledStatus: boolean; violationMessage?: string; reportActions?: OnyxTypes.ReportActions; originalTransaction?: OnyxEntry; @@ -329,18 +326,15 @@ function getTransactionPreviewTextAndTranslationPaths({ previewDateText = {text: date}; } - // Paid, Approved, Review required and the hold message are intentionally omitted here because the report status badge and the - // RBR row already show them, so repeating them on this line is noise. Canceled is the exception: it can't be derived from - // stateNum/statusNum, so surfaces without their own report status badge have to report it here. + // Paid, Approved, Review required, Canceled and the hold message are omitted here: the status badge, the preview header and the + // RBR row already show them. const previewStatusText: TranslationPathOrText[] = []; if (isPending(transaction)) { previewStatusText.push({translationPath: 'iou.pending'}); } - if (shouldShowCanceledStatus && iouReport?.isCancelledIOU) { - previewStatusText.push({translationPath: 'iou.canceled'}); - } else if (hasPendingRTERViolation(violations)) { + if (hasPendingRTERViolation(violations)) { previewStatusText.push({translationPath: 'iou.pendingMatch'}); } @@ -394,7 +388,7 @@ function createTransactionPreviewConditionals({ currentUserAccountID: number; reportActions?: OnyxTypes.ReportActions; }) { - const {amount: requestAmount, comment: requestComment, merchant, tag, category} = transactionDetails; + const {amount: requestAmount, comment: requestComment, merchant, category} = transactionDetails; const requestMerchant = truncate(merchant, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH}); const description = truncate(StringUtils.lineBreaksToSpaces(requestComment), {length: CONST.REQUEST_PREVIEW.MAX_LENGTH}); @@ -416,7 +410,6 @@ function createTransactionPreviewConditionals({ const isFullyApproved = isApproved && !isSettlementOrApprovalPartial; const shouldShowSkeleton = isEmptyObject(transaction) && !isMessageDeleted(action) && !isDeletedAction(action) && action?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; - const shouldShowTag = !!tag && isReportAPolicyExpenseChat; const categoryForDisplay = isCategoryMissing(category) ? '' : category; @@ -450,7 +443,6 @@ function createTransactionPreviewConditionals({ return { shouldShowSkeleton, - shouldShowTag, shouldShowRBR, shouldShowCategory, shouldShowKeepButton, diff --git a/tests/ui/MoneyRequestReportPreview.test.tsx b/tests/ui/MoneyRequestReportPreview.test.tsx index 443126b30bb0..79e0e3ec05bd 100644 --- a/tests/ui/MoneyRequestReportPreview.test.tsx +++ b/tests/ui/MoneyRequestReportPreview.test.tsx @@ -180,8 +180,9 @@ const getTransactionDisplayAmountAndMetadataText = (transaction: Transaction) => const created = getFormattedCreated(transaction); const date = DateUtils.formatWithUTCTimeZone(created, DateUtils.doesDateBelongToAPastYear(created) ? CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT : CONST.DATE.MONTH_DAY_ABBR_FORMAT, undefined); const isTransactionMadeWithCard = isManagedCardTransaction(transaction); - // The date leads the supporting line, which can also carry the category and the report status. - const transactionSupportingText = new RegExp(`^${date}`); + // These transactions have no category and no status, so the date is the whole supporting line. Asserted exactly, so an + // unexpected category or status can't slip through. + const transactionSupportingText = date; const transactionTypeText = isTransactionMadeWithCard ? TestHelper.translateLocal('iou.card') : TestHelper.translateLocal('iou.cash'); const transactionDisplayAmount = TestHelper.convertToDisplayString(-transaction.amount, transaction.currency); return {transactionSupportingText, transactionTypeText, transactionDisplayAmount}; diff --git a/tests/unit/TransactionPreviewUtils.test.ts b/tests/unit/TransactionPreviewUtils.test.ts index 06abc3eb869c..d611e3064c1a 100644 --- a/tests/unit/TransactionPreviewUtils.test.ts +++ b/tests/unit/TransactionPreviewUtils.test.ts @@ -54,7 +54,6 @@ const basicProps = { transactionDetails: {}, isBillSplit: false, shouldShowRBR: false, - shouldShowCanceledStatus: false, isReportAPolicyExpenseChat: false, areThereDuplicates: false, currentUserEmail: '', @@ -256,18 +255,12 @@ describe('TransactionPreviewUtils', () => { expect(result.displayAmountText.text).toEqual(convertAmountToDisplayString(modifiedAmount, currency)); }); - it('does not show the canceled status inside a report preview, because the preview header already shows it', () => { - const functionArgs = {...basicProps, iouReport: {...basicProps.iouReport, isCancelledIOU: true}, originalTransaction: undefined, shouldShowCanceledStatus: false}; + it('does not show the canceled status, because it is reported at the report level instead', () => { + const functionArgs = {...basicProps, iouReport: {...basicProps.iouReport, isCancelledIOU: true}, originalTransaction: undefined}; const result = getTransactionPreviewTextAndTranslationPaths(functionArgs); expect(result.previewStatusText).toEqual([]); }); - it('shows the canceled status in a standalone preview, because nothing else on that surface reports it', () => { - const functionArgs = {...basicProps, iouReport: {...basicProps.iouReport, isCancelledIOU: true}, originalTransaction: undefined, shouldShowCanceledStatus: true}; - const result = getTransactionPreviewTextAndTranslationPaths(functionArgs); - expect(result.previewStatusText).toContainEqual({translationPath: 'iou.canceled'}); - }); - it('does not show the approved status when the report is approved, because it is redundant with the report status badge', () => { const functionArgs = { ...basicProps, @@ -538,12 +531,6 @@ describe('TransactionPreviewUtils', () => { expect(result.shouldShowDescription).toBeFalsy(); }); - it("should show tag if it's a policy expense chat and tag is present", () => { - const functionArgs = {...basicProps, isReportAPolicyExpenseChat: true, transactionDetails: {tag: 'Transport'}}; - const result = createTransactionPreviewConditionals(functionArgs); - expect(result.shouldShowTag).toBeTruthy(); - }); - it('should correctly show violation message if there are multiple violations', () => { const functionArgs = { ...basicProps,