Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletions src/pages/inbox/report/PureReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import TextLink from '@components/TextLink';
import UnreadActionIndicator from '@components/UnreadActionIndicator';
import useConfirmModal from '@hooks/useConfirmModal';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useEnvironment from '@hooks/useEnvironment';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
Expand All @@ -53,7 +52,6 @@ import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {cleanUpMoneyRequest} from '@libs/actions/IOU/DeleteMoneyRequest';
import {isPersonalCardBrokenConnection} from '@libs/CardUtils';
import {isChronosOOOListAction} from '@libs/ChronosUtils';
import ControlSelection from '@libs/ControlSelection';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
Expand All @@ -70,7 +68,6 @@ import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils';
import {isPolicyAdmin} from '@libs/PolicyUtils';
import {
extractLinksFromMessageHtml,
getCardConnectionBrokenMessage,
getChangedApproverActionMessage,
getCompanyCardConnectionBrokenMessage,
getIntegrationSyncFailedMessage,
Expand Down Expand Up @@ -141,6 +138,7 @@ import type * as OnyxTypes from '@src/types/onyx';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import {isEmptyObject, isEmptyValueObject} from '@src/types/utils/EmptyObject';
import ApprovalFlowContent, {isApprovalFlowAction} from './actionContents/ApprovalFlowContent';
import CardBrokenConnectionContent from './actionContents/CardBrokenConnectionContent';
import ChatMessageContent from './actionContents/ChatMessageContent';
import ConfirmWhisperContent from './actionContents/ConfirmWhisperContent';
import FraudAlertContent from './actionContents/FraudAlertContent';
Expand Down Expand Up @@ -270,9 +268,6 @@ type PureReportActionItemProps = {
/** Whether the room is a chronos report */
isChronosReport?: boolean;

/** All cards */
cardList?: OnyxTypes.CardList;

/** Function to toggle emoji reaction */
toggleEmojiReaction?: (
reportID: string | undefined,
Expand Down Expand Up @@ -391,7 +386,6 @@ function PureReportActionItem({
iouReportOfLinkedReport,
emojiReactions,
linkedTransactionRouteError,
cardList,
isUserValidated,
parentReport,
personalDetails,
Expand Down Expand Up @@ -453,7 +447,6 @@ function PureReportActionItem({

const isHarvestCreatedExpenseReport = isHarvestCreatedExpenseReportUtils(reportNameValuePairsOrigin, reportNameValuePairsOriginalID);
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Eye']);
const {environmentURL} = useEnvironment();

const [childReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(action.childReportID)}`);
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.chatReportID)}`);
Expand Down Expand Up @@ -1062,16 +1055,7 @@ function PureReportActionItem({
/>
);
} else if (isCardBrokenConnectionAction(action)) {
const message = getOriginalMessage(action);
const cardID = message?.cardID;
const cardName = message?.cardName;
const card = cardID ? cardList?.[cardID] : undefined;
const connectionLink = cardID && isPersonalCardBrokenConnection(card) ? `${environmentURL}/${ROUTES.SETTINGS_WALLET_PERSONAL_CARD_DETAILS.getRoute(String(cardID))}` : undefined;
children = (
<ReportActionItemBasicMessage message="">
<RenderHTML html={`<comment>${getCardConnectionBrokenMessage(card, cardName, translate, connectionLink)}</comment>`} />
</ReportActionItemBasicMessage>
);
children = <CardBrokenConnectionContent action={action} />;
} else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION)) {
children = <ExportIntegration action={action} />;
} else if (isRenamedAction(action)) {
Expand Down Expand Up @@ -1507,7 +1491,6 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => {
deepEqual(prevProps.taskReport, nextProps.taskReport) &&
prevProps.shouldHighlight === nextProps.shouldHighlight &&
deepEqual(prevProps.bankAccountList, nextProps.bankAccountList) &&
deepEqual(prevProps.cardList, nextProps.cardList) &&
prevProps.reportNameValuePairsOrigin === nextProps.reportNameValuePairsOrigin &&
prevProps.reportNameValuePairsOriginalID === nextProps.reportNameValuePairsOriginalID &&
prevProps.reportMetadata?.pendingExpenseAction === nextProps.reportMetadata?.pendingExpenseAction
Expand Down
2 changes: 0 additions & 2 deletions src/pages/inbox/report/ReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ function ReportActionItem({
const [iouReportOfLinkedReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${iouReportOfLinkedReportID}`);

const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`);
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST);
const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID);
const transactionsOnIOUReport = useReportTransactions(iouReport?.reportID);
Expand Down Expand Up @@ -130,7 +129,6 @@ function ReportActionItem({
draftMessage={draftMessage}
iouReport={iouReport}
taskReport={taskReport}
cardList={cardList}
linkedReport={linkedReport}
iouReportOfLinkedReport={iouReportOfLinkedReport}
emojiReactions={emojiReactions}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {cardByIdSelector} from '@selectors/Card';
import React from 'react';
import RenderHTML from '@components/RenderHTML';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import {isPersonalCardBrokenConnection} from '@libs/CardUtils';
import {getCardConnectionBrokenMessage, getOriginalMessage} from '@libs/ReportActionsUtils';
import ReportActionItemBasicMessage from '@pages/inbox/report/ReportActionItemBasicMessage';
import type CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {ReportAction} from '@src/types/onyx';

type CardBrokenConnectionContentProps = {
action: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.PERSONAL_CARD_CONNECTION_BROKEN>;
};

function CardBrokenConnectionContent({action}: CardBrokenConnectionContentProps) {
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();

const message = getOriginalMessage(action);
const cardID = message?.cardID;
const cardName = message?.cardName;

const [card] = useOnyx(ONYXKEYS.CARD_LIST, {selector: cardByIdSelector(String(cardID))});

const connectionLink = cardID && isPersonalCardBrokenConnection(card) ? `${environmentURL}/${ROUTES.SETTINGS_WALLET_PERSONAL_CARD_DETAILS.getRoute(String(cardID))}` : undefined;

return (
<ReportActionItemBasicMessage message="">
<RenderHTML html={`<comment>${getCardConnectionBrokenMessage(card, cardName, translate, connectionLink)}</comment>`} />
</ReportActionItemBasicMessage>
);
}

CardBrokenConnectionContent.displayName = 'CardBrokenConnectionContent';

export default CardBrokenConnectionContent;
59 changes: 59 additions & 0 deletions tests/ui/PureReportActionItemTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,65 @@ describe('PureReportActionItem', () => {
expect(screen.getByText(assertion)).toBeOnTheScreen();
});

it('isCardBrokenConnectionAction falls back to card.cardName from CARD_LIST when originalMessage has no cardName', async () => {
const CARD_ID_KEY = '100';

await act(async () => {
await Onyx.merge(ONYXKEYS.CARD_LIST, {
[CARD_ID_KEY]: {cardID: 100, cardName: 'Onyx Card'},
});
});
await waitForBatchedUpdatesWithAct();

const action = createReportAction(CONST.REPORT.ACTIONS.TYPE.PERSONAL_CARD_CONNECTION_BROKEN, {cardID: 100});
renderItemWithAction(action);
await waitForBatchedUpdatesWithAct();

expect(screen.getByText(/Onyx Card/)).toBeOnTheScreen();
});

it('isCardBrokenConnectionAction renders tappable bank login link for personal broken connection', async () => {
const CARD_ID_KEY = '100';

(openLink as jest.Mock).mockClear();
await act(async () => {
await Onyx.merge(ONYXKEYS.CARD_LIST, {
[CARD_ID_KEY]: {cardID: 100, cardName: 'Broken Card', lastScrapeResult: 401},
});
});
await waitForBatchedUpdatesWithAct();

const action = createReportAction(CONST.REPORT.ACTIONS.TYPE.PERSONAL_CARD_CONNECTION_BROKEN, {cardID: 100, cardName: 'Broken Card'});
renderItemWithAction(action);
await waitForBatchedUpdatesWithAct();

const bankLoginLink = screen.getByText('Log into your bank');
fireEvent.press(bankLoginLink);

expect(openLink).toHaveBeenCalledTimes(1);
expect(openLink).toHaveBeenCalledWith(expect.stringContaining('settings/wallet/personal-card/100'), expect.anything(), expect.anything());
});

it('isCardBrokenConnectionAction renders no tappable link when card connection is not broken', async () => {
const CARD_ID_KEY = '100';

(openLink as jest.Mock).mockClear();
await act(async () => {
Comment thread
LukasMod marked this conversation as resolved.
await Onyx.merge(ONYXKEYS.CARD_LIST, {
[CARD_ID_KEY]: {cardID: 100, cardName: 'Healthy Card', lastScrapeResult: 200},
});
});
await waitForBatchedUpdatesWithAct();

const action = createReportAction(CONST.REPORT.ACTIONS.TYPE.PERSONAL_CARD_CONNECTION_BROKEN, {cardID: 100, cardName: 'Healthy Card'});
renderItemWithAction(action);
await waitForBatchedUpdatesWithAct();

expect(screen.getByText(/Healthy Card/)).toBeOnTheScreen();
expect(screen.getByText(/Log into your bank/)).toBeOnTheScreen();
expect(screen.queryAllByRole('link', {name: /Log into your bank/i})).toHaveLength(0);
});

// isActionableJoinRequest renders ReportActionItemBasicMessage inside a View wrapper
it('isActionableJoinRequest renders join request message', async () => {
const action = createReportAction(CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST, {});
Expand Down
Loading