From 5e23e5ccde5257155217354a2f61887e4ab3b328 Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Sun, 12 Apr 2026 14:09:03 +0530 Subject: [PATCH 1/9] Fixed the condition to check fraud alert action on home screen in time sensitive section --- .../TimeSensitiveSection/hooks/useTimeSensitiveCards.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts index 25c003359010..d18d17342da9 100644 --- a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts +++ b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts @@ -1,5 +1,6 @@ import useOnyx from '@hooks/useOnyx'; import {isCard, isCardPendingActivate, isCardPendingIssue, isCardWithPotentialFraud, isExpensifyCard} from '@libs/CardUtils'; +import {getUnresolvedCardFraudAlertAction} from '@libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card} from '@src/types/onyx'; @@ -19,7 +20,10 @@ function useTimeSensitiveCards() { continue; } - if (isCardWithPotentialFraud(card) && card.nameValuePairs?.possibleFraud?.fraudAlertReportID) { + const fraudAlertReportID = card.nameValuePairs?.possibleFraud?.fraudAlertReportID; + const hasUnresolvedFraudAction = !!fraudAlertReportID && !!getUnresolvedCardFraudAlertAction(String(fraudAlertReportID)); + + if (isCardWithPotentialFraud(card) && !!fraudAlertReportID && hasUnresolvedFraudAction) { cardsWithFraud.push(card); } From 86364cce3bc3b2c8a1b72cb61393b7d6e68f4dd0 Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Mon, 13 Apr 2026 15:02:06 +0530 Subject: [PATCH 2/9] added possible fraud to null in optimistic data and rolling back to previous possible fraud on API failure on fraud action resolution --- src/libs/actions/Card.ts | 36 ++++++++++++++++--- .../inbox/report/PureReportActionItem.tsx | 7 ++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Card.ts b/src/libs/actions/Card.ts index 800de5426f5c..856532af3a30 100644 --- a/src/libs/actions/Card.ts +++ b/src/libs/actions/Card.ts @@ -33,7 +33,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {SpendRuleForm} from '@src/types/form'; import {isSpendRuleCategory} from '@src/types/form/SpendRuleForm'; import type {Card, CompanyCardFeedWithDomainID, Report, Transaction} from '@src/types/onyx'; -import type {CardLimitType, ExpensifyCardDetails, IssueNewCardData, IssueNewCardStep} from '@src/types/onyx/Card'; +import type {CardLimitType, ExpensifyCardDetails, IssueNewCardData, IssueNewCardStep, PossibleFraudData} from '@src/types/onyx/Card'; import type {ExpensifyCardRule, ExpensifyCardRuleFilter} from '@src/types/onyx/ExpensifyCardSettings'; import type {SelectedTimezone} from '@src/types/onyx/PersonalDetails'; import type {ConnectionName} from '@src/types/onyx/Policy'; @@ -1791,7 +1791,13 @@ function deleteExpensifyCardRule(domainAccountID: number, cardRuleID: string, ex * Resolves a fraud alert for a given card. * When the user clicks on the whisper it sets the optimistic data to the resolution and calls the API */ -function resolveFraudAlert(cardID: number | undefined, isFraud: boolean, reportID: string | undefined, reportActionID: string | undefined) { +function resolveFraudAlert( + cardID: number | undefined, + isFraud: boolean, + reportID: string | undefined, + reportActionID: string | undefined, + previousPossibleFraud: PossibleFraudData | null = null, +) { if (!reportID || !reportActionID || !cardID) { Log.hmmm('[resolveFraudAlert] Missing required parameters'); return; @@ -1799,7 +1805,7 @@ function resolveFraudAlert(cardID: number | undefined, isFraud: boolean, reportI const resolution = isFraud ? CONST.CARD_FRAUD_ALERT_RESOLUTION.FRAUD : CONST.CARD_FRAUD_ALERT_RESOLUTION.RECOGNIZED; - const optimisticData: Array> = [ + const optimisticData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, @@ -1812,6 +1818,17 @@ function resolveFraudAlert(cardID: number | undefined, isFraud: boolean, reportI }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.CARD_LIST, + value: { + [cardID]: { + nameValuePairs: { + possibleFraud: null, + }, + }, + }, + }, ]; const successData: Array> = [ @@ -1826,7 +1843,7 @@ function resolveFraudAlert(cardID: number | undefined, isFraud: boolean, reportI }, ]; - const failureData: Array> = [ + const failureData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, @@ -1840,6 +1857,17 @@ function resolveFraudAlert(cardID: number | undefined, isFraud: boolean, reportI }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.CARD_LIST, + value: { + [cardID]: { + nameValuePairs: { + possibleFraud: previousPossibleFraud, + }, + }, + }, + }, ]; const parameters: ResolveFraudAlertParams = { diff --git a/src/pages/inbox/report/PureReportActionItem.tsx b/src/pages/inbox/report/PureReportActionItem.tsx index 893d2b64c1c4..85c17efb94e5 100644 --- a/src/pages/inbox/report/PureReportActionItem.tsx +++ b/src/pages/inbox/report/PureReportActionItem.tsx @@ -1037,12 +1037,14 @@ function PureReportActionItem({ } const cardID = getOriginalMessage(action)?.cardID; + const card = cardID ? cardList?.[cardID] : undefined; + const possibleFraud = card?.nameValuePairs?.possibleFraud ?? null; return [ { text: translate('cardPage.cardFraudAlert.confirmButtonText'), key: `${action.reportActionID}-cardFraudAlert-confirm`, onPress: () => { - resolveFraudAlert(cardID, false, reportID, action?.reportActionID); + resolveFraudAlert(cardID, false, reportID, action?.reportActionID, possibleFraud); }, isPrimary: true, }, @@ -1050,7 +1052,7 @@ function PureReportActionItem({ text: translate('cardPage.cardFraudAlert.reportFraudButtonText'), key: `${action.reportActionID}-cardFraudAlert-reportFraud`, onPress: () => { - resolveFraudAlert(cardID, true, reportID, action?.reportActionID); + resolveFraudAlert(cardID, true, reportID, action?.reportActionID, possibleFraud); }, }, ]; @@ -1160,6 +1162,7 @@ function PureReportActionItem({ activePolicy, report, originalReport, + cardList, personalPolicyID, userBillingGracePeriodEnds, amountOwed, From 264fd2a4b3ce4967166dd79cdbd406d28237744f Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Mon, 13 Apr 2026 15:15:12 +0530 Subject: [PATCH 3/9] added unresolved ACTIONABLE_CARD_FRAUD_ALERT report action in useTimeSensitiveCards hook tests so fraud-card expectations align with new unresolved-action guard --- tests/unit/hooks/useTimeSensitiveCards.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/unit/hooks/useTimeSensitiveCards.test.ts b/tests/unit/hooks/useTimeSensitiveCards.test.ts index 96aa6f405bbd..7a400f241ef0 100644 --- a/tests/unit/hooks/useTimeSensitiveCards.test.ts +++ b/tests/unit/hooks/useTimeSensitiveCards.test.ts @@ -6,6 +6,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card, CardList} from '@src/types/onyx'; import {createRandomExpensifyCard} from '../../utils/collections/card'; +import createRandomReportAction from '../../utils/collections/reportActions'; import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; describe('useTimeSensitiveCards', () => { @@ -178,8 +179,15 @@ describe('useTimeSensitiveCards', () => { possibleFraud: {triggerAmount: 5663, triggerMerchant: 'WAL-MART #2366', currency: 'USD', fraudAlertReportID: 123456}, }); const cardList: CardList = {'1': cardWithFraud}; + const unresolvedFraudAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT, + }; await Onyx.merge(ONYXKEYS.CARD_LIST, cardList); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${cardWithFraud.nameValuePairs?.possibleFraud?.fraudAlertReportID}`, { + [unresolvedFraudAction.reportActionID]: unresolvedFraudAction, + }); await waitForBatchedUpdates(); const {result} = renderHook(() => useTimeSensitiveCards()); @@ -210,8 +218,15 @@ describe('useTimeSensitiveCards', () => { possibleFraud: {triggerAmount: 5663, triggerMerchant: 'WAL-MART #2366', currency: 'USD', fraudAlertReportID: 5230242215684213}, }); const cardList: CardList = {'1': cardWithPendingFraudAlert}; + const unresolvedFraudAction = { + ...createRandomReportAction(2), + actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT, + }; await Onyx.merge(ONYXKEYS.CARD_LIST, cardList); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${cardWithPendingFraudAlert.nameValuePairs?.possibleFraud?.fraudAlertReportID}`, { + [unresolvedFraudAction.reportActionID]: unresolvedFraudAction, + }); await waitForBatchedUpdates(); const {result} = renderHook(() => useTimeSensitiveCards()); From 790f48f80fb82d352961c327fd62f8c9ff525acb Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Tue, 14 Apr 2026 15:12:27 +0530 Subject: [PATCH 4/9] subscribed to report actions in useTimeSensitiveCards to fix fraud card reactivity --- .../hooks/useTimeSensitiveCards.ts | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts index d18d17342da9..4f3baaa3b00e 100644 --- a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts +++ b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts @@ -1,12 +1,33 @@ +import type {OnyxCollection} from 'react-native-onyx'; import useOnyx from '@hooks/useOnyx'; import {isCard, isCardPendingActivate, isCardPendingIssue, isCardWithPotentialFraud, isExpensifyCard} from '@libs/CardUtils'; -import {getUnresolvedCardFraudAlertAction} from '@libs/ReportUtils'; +import {getOriginalMessage, isActionableCardFraudAlert} from '@libs/ReportActionsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Card} from '@src/types/onyx'; +import type {Card, ReportActions} from '@src/types/onyx'; function useTimeSensitiveCards() { const [cards] = useOnyx(ONYXKEYS.CARD_LIST); + const fraudAlertReportIDs = Object.values(cards ?? {}) + .filter((card): card is Card => isCard(card) && isExpensifyCard(card) && isCardWithPotentialFraud(card)) + .map((card) => card.nameValuePairs?.possibleFraud?.fraudAlertReportID) + .filter((id): id is number => !!id); + + // We avoid using `getUnresolvedCardFraudAlertAction` here because it reads report actions from a + // module-level Onyx.connect variable, which is not a React subscription and won't trigger re-renders. + // Instead, we subscribe to ONYXKEYS.COLLECTION.REPORT_ACTIONS via useOnyx with a selector, so that + // this hook re-renders when the relevant report actions are loaded or updated (e.g. fraud resolved). + const fraudActionsSelector = (allReportActions: OnyxCollection) => { + const result: Record = {}; + for (const reportID of fraudAlertReportIDs) { + const actions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}; + result[reportID] = Object.values(actions).some((action) => isActionableCardFraudAlert(action) && !getOriginalMessage(action)?.resolution); + } + return result; + }; + + const [hasUnresolvedFraudByReport] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {selector: fraudActionsSelector}, [fraudActionsSelector]); + const cardsNeedingShippingAddress: Card[] = []; const cardsNeedingActivation: Card[] = []; const cardsWithFraud: Card[] = []; @@ -21,7 +42,7 @@ function useTimeSensitiveCards() { } const fraudAlertReportID = card.nameValuePairs?.possibleFraud?.fraudAlertReportID; - const hasUnresolvedFraudAction = !!fraudAlertReportID && !!getUnresolvedCardFraudAlertAction(String(fraudAlertReportID)); + const hasUnresolvedFraudAction = !!fraudAlertReportID && !!hasUnresolvedFraudByReport?.[fraudAlertReportID]; if (isCardWithPotentialFraud(card) && !!fraudAlertReportID && hasUnresolvedFraudAction) { cardsWithFraud.push(card); From 6aa046d83764f6d85919a4bb55e019eae268cd1e Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Sat, 18 Apr 2026 19:24:31 +0530 Subject: [PATCH 5/9] added unresolved fraud report action for custom -zsh limit card in useTimeSensitiveCards hook test --- tests/unit/hooks/useTimeSensitiveCards.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/unit/hooks/useTimeSensitiveCards.test.ts b/tests/unit/hooks/useTimeSensitiveCards.test.ts index 615cbf02ca85..f50677271119 100644 --- a/tests/unit/hooks/useTimeSensitiveCards.test.ts +++ b/tests/unit/hooks/useTimeSensitiveCards.test.ts @@ -298,8 +298,15 @@ describe('useTimeSensitiveCards', () => { } as Card['nameValuePairs'], }; const cardList: CardList = {'1': zeroLimitFraudCard}; + const unresolvedFraudAction = { + ...createRandomReportAction(3), + actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT, + }; await Onyx.merge(ONYXKEYS.CARD_LIST, cardList); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${zeroLimitFraudCard.nameValuePairs?.possibleFraud?.fraudAlertReportID}`, { + [unresolvedFraudAction.reportActionID]: unresolvedFraudAction, + }); await waitForBatchedUpdates(); const {result} = renderHook(() => useTimeSensitiveCards()); From 465cd7f60d192eddd2a3b9148d39977814673074 Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Sat, 25 Apr 2026 23:14:07 +0530 Subject: [PATCH 6/9] fixed the failing ts and eslint check by looking the fraud alert possibleFraud inside FraudAlertContent --- src/pages/inbox/report/PureReportActionItem.tsx | 3 --- .../inbox/report/actionContents/FraudAlertContent.tsx | 9 ++++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/inbox/report/PureReportActionItem.tsx b/src/pages/inbox/report/PureReportActionItem.tsx index b8af437340a3..2ff47fc8cf9d 100644 --- a/src/pages/inbox/report/PureReportActionItem.tsx +++ b/src/pages/inbox/report/PureReportActionItem.tsx @@ -968,13 +968,10 @@ function PureReportActionItem({ ); } else if (isActionableCardFraudAlert(action)) { - const cardID = getOriginalMessage(action)?.cardID; - const possibleFraud = cardID ? (cardList?.[cardID]?.nameValuePairs?.possibleFraud ?? null) : null; children = ( ); } else if (isActionableJoinRequest(action)) { diff --git a/src/pages/inbox/report/actionContents/FraudAlertContent.tsx b/src/pages/inbox/report/actionContents/FraudAlertContent.tsx index 1fc9a59d8392..a992ff4b3314 100644 --- a/src/pages/inbox/report/actionContents/FraudAlertContent.tsx +++ b/src/pages/inbox/report/actionContents/FraudAlertContent.tsx @@ -1,27 +1,30 @@ +import {cardByIdSelector} from '@selectors/Card'; import React from 'react'; import {View} from 'react-native'; import type {ActionableItem} from '@components/ReportActionItem/ActionableItemButtons'; import ActionableItemButtons from '@components/ReportActionItem/ActionableItemButtons'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import {getActionableCardFraudAlertMessage, getOriginalMessage} from '@libs/ReportActionsUtils'; import ReportActionItemBasicMessage from '@pages/inbox/report/ReportActionItemBasicMessage'; import {resolveFraudAlert} from '@userActions/Card'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction} from '@src/types/onyx'; -import type {PossibleFraudData} from '@src/types/onyx/Card'; type FraudAlertContentProps = { action: ReportAction; reportID: string | undefined; - possibleFraud: PossibleFraudData | null; }; -function FraudAlertContent({action, reportID, possibleFraud}: FraudAlertContentProps) { +function FraudAlertContent({action, reportID}: FraudAlertContentProps) { const {translate, getLocalDateFromDatetime} = useLocalize(); const reportActionID = action?.reportActionID; const originalMessage = getOriginalMessage(action); const cardID = originalMessage?.cardID; + const [card] = useOnyx(ONYXKEYS.CARD_LIST, {selector: cardByIdSelector(String(cardID))}); + const possibleFraud = card?.nameValuePairs?.possibleFraud ?? null; const buttons: ActionableItem[] = originalMessage?.resolution ? [] From 8eb56a437faecc936409aab84a68367a5070e23d Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Sat, 25 Apr 2026 23:25:49 +0530 Subject: [PATCH 7/9] refined the logic for report actions subscription for fraud card tasks --- src/libs/ReportUtils.ts | 7 +++-- .../hooks/useTimeSensitiveCards.ts | 29 ++++--------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index fc3907430a95..bbcb59019c02 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4169,9 +4169,9 @@ type ReasonAndReportActionThatRequiresAttention = { /** * Returns the unresolved card fraud alert action for a given report. */ -function getUnresolvedCardFraudAlertAction(reportID: string): OnyxEntry { - const reportActions = getAllReportActions(reportID); - return Object.values(reportActions).find((action): action is ReportAction => isActionableCardFraudAlert(action) && !getOriginalMessage(action)?.resolution); +function getUnresolvedCardFraudAlertAction(reportID: string, reportActions?: OnyxEntry): OnyxEntry { + const actions = reportActions ?? getAllReportActions(reportID); + return Object.values(actions).find((action): action is ReportAction => isActionableCardFraudAlert(action) && !getOriginalMessage(action)?.resolution); } /** @@ -13694,6 +13694,7 @@ export { hasMissingInvoiceBankAccount, reasonForReportToBeInOptionList, getReasonAndReportActionThatRequiresAttention, + getUnresolvedCardFraudAlertAction, buildOptimisticChangeFieldAction, isPolicyRelatedReport, hasReportErrorsOtherThanFailedReceipt, diff --git a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts index 0a3093e55258..2ccafba79bba 100644 --- a/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts +++ b/src/pages/home/TimeSensitiveSection/hooks/useTimeSensitiveCards.ts @@ -1,32 +1,12 @@ -import type {OnyxCollection} from 'react-native-onyx'; import useOnyx from '@hooks/useOnyx'; import {isCard, isCardPendingActivate, isCardPendingIssue, isCardWithCustomZeroLimit, isCardWithPotentialFraud, isExpensifyCard} from '@libs/CardUtils'; -import {getOriginalMessage, isActionableCardFraudAlert} from '@libs/ReportActionsUtils'; +import {getUnresolvedCardFraudAlertAction} from '@libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Card, ReportActions} from '@src/types/onyx'; +import type {Card} from '@src/types/onyx'; function useTimeSensitiveCards() { const [cards] = useOnyx(ONYXKEYS.CARD_LIST); - - const fraudAlertReportIDs = Object.values(cards ?? {}) - .filter((card): card is Card => isCard(card) && isExpensifyCard(card) && isCardWithPotentialFraud(card)) - .map((card) => card.nameValuePairs?.possibleFraud?.fraudAlertReportID) - .filter((id): id is number => !!id); - - // We avoid using `getUnresolvedCardFraudAlertAction` here because it reads report actions from a - // module-level Onyx.connect variable, which is not a React subscription and won't trigger re-renders. - // Instead, we subscribe to ONYXKEYS.COLLECTION.REPORT_ACTIONS via useOnyx with a selector, so that - // this hook re-renders when the relevant report actions are loaded or updated (e.g. fraud resolved). - const fraudActionsSelector = (allReportActions: OnyxCollection) => { - const result: Record = {}; - for (const reportID of fraudAlertReportIDs) { - const actions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}; - result[reportID] = Object.values(actions).some((action) => isActionableCardFraudAlert(action) && !getOriginalMessage(action)?.resolution); - } - return result; - }; - - const [hasUnresolvedFraudByReport] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {selector: fraudActionsSelector}, [fraudActionsSelector]); + const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); const cardsNeedingShippingAddress: Card[] = []; const cardsNeedingActivation: Card[] = []; @@ -42,7 +22,8 @@ function useTimeSensitiveCards() { } const fraudAlertReportID = card.nameValuePairs?.possibleFraud?.fraudAlertReportID; - const hasUnresolvedFraudAction = !!fraudAlertReportID && !!hasUnresolvedFraudByReport?.[fraudAlertReportID]; + const reportActions = fraudAlertReportID ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fraudAlertReportID}`] : undefined; + const hasUnresolvedFraudAction = !!fraudAlertReportID && !!getUnresolvedCardFraudAlertAction(String(fraudAlertReportID), reportActions); if (isCardWithPotentialFraud(card) && !!fraudAlertReportID && hasUnresolvedFraudAction) { cardsWithFraud.push(card); From b8361d392c1ad6b20e62d53bd643d02859c94ead Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Mon, 27 Apr 2026 13:03:39 +0530 Subject: [PATCH 8/9] added the test case for resolved fraud alert actions hiding stale Home review tasks --- .../unit/hooks/useTimeSensitiveCards.test.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/unit/hooks/useTimeSensitiveCards.test.ts b/tests/unit/hooks/useTimeSensitiveCards.test.ts index f50677271119..a730b0f7a40b 100644 --- a/tests/unit/hooks/useTimeSensitiveCards.test.ts +++ b/tests/unit/hooks/useTimeSensitiveCards.test.ts @@ -198,6 +198,35 @@ describe('useTimeSensitiveCards', () => { expect(result.current.shouldShowReviewCardFraud).toBe(true); }); + it('should not show fraud review when card has possibleFraud data but the fraud action is already resolved as recognized', async () => { + const cardWithResolvedFraudAlert = createRandomExpensifyCard(1, { + state: CONST.EXPENSIFY_CARD.STATE.OPEN, + fraud: CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN, + possibleFraud: {triggerAmount: 5663, triggerMerchant: 'WAL-MART #2366', currency: 'USD', fraudAlertReportID: 123457}, + }); + const cardList: CardList = {'1': cardWithResolvedFraudAlert}; + const baseFraudAction = createRandomReportAction(4); + const resolvedFraudAction = { + ...baseFraudAction, + actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT, + originalMessage: { + ...baseFraudAction.originalMessage, + resolution: CONST.CARD_FRAUD_ALERT_RESOLUTION.RECOGNIZED, + }, + }; + + await Onyx.merge(ONYXKEYS.CARD_LIST, cardList); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${cardWithResolvedFraudAlert.nameValuePairs?.possibleFraud?.fraudAlertReportID}`, { + [resolvedFraudAction.reportActionID]: resolvedFraudAction, + }); + await waitForBatchedUpdates(); + + const {result} = renderHook(() => useTimeSensitiveCards()); + + expect(result.current.cardsWithFraud).toHaveLength(0); + expect(result.current.shouldShowReviewCardFraud).toBe(false); + }); + it('should not show fraud review for cards with fraud type NONE and no possibleFraud data', async () => { const cardWithNoFraud = createRandomExpensifyCard(1, {state: CONST.EXPENSIFY_CARD.STATE.OPEN, fraud: CONST.EXPENSIFY_CARD.FRAUD_TYPES.NONE}); const cardList: CardList = {'1': cardWithNoFraud}; From e1a47854a0e60c3b86cf1f409d1c6cc6f39b3132 Mon Sep 17 00:00:00 2001 From: Uzaifm127 Date: Mon, 27 Apr 2026 13:18:28 +0530 Subject: [PATCH 9/9] fixed eslint: Removed baseFraudAction.originalMessage --- tests/unit/hooks/useTimeSensitiveCards.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/hooks/useTimeSensitiveCards.test.ts b/tests/unit/hooks/useTimeSensitiveCards.test.ts index a730b0f7a40b..475bc3765061 100644 --- a/tests/unit/hooks/useTimeSensitiveCards.test.ts +++ b/tests/unit/hooks/useTimeSensitiveCards.test.ts @@ -210,7 +210,6 @@ describe('useTimeSensitiveCards', () => { ...baseFraudAction, actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT, originalMessage: { - ...baseFraudAction.originalMessage, resolution: CONST.CARD_FRAUD_ALERT_RESOLUTION.RECOGNIZED, }, };