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
6 changes: 5 additions & 1 deletion src/libs/actions/PaymentMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,11 @@ function hasPaymentMethodError(bankList: OnyxEntry<BankAccountList>, fundList: O
return Object.values(combinedPaymentMethods).some((item) => Object.keys(item.errors ?? {}).length);
}

type PaymentListKey = typeof ONYXKEYS.BANK_ACCOUNT_LIST | typeof ONYXKEYS.FUND_LIST;
type PaymentListKey =
| typeof ONYXKEYS.BANK_ACCOUNT_LIST
| typeof ONYXKEYS.FUND_LIST
| typeof ONYXKEYS.CARD_LIST
| `${typeof ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${string}_${typeof CONST.EXPENSIFY_CARD.BANK}`;

/**
* Clears the error for the specified payment item
Expand Down
41 changes: 33 additions & 8 deletions src/pages/settings/Wallet/PaymentMethodList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import type {Errors} from '@src/types/onyx/OnyxCommon';
import type PaymentMethod from '@src/types/onyx/PaymentMethod';
import type {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';

type PaymentMethodListProps = {
/** Type of active/highlighted payment method */
Expand Down Expand Up @@ -117,9 +118,15 @@ type PaymentMethodItem = PaymentMethod & {
errors?: Errors;
iconRight?: React.FC<SvgProps>;
isMethodActive?: boolean;
cardID?: number;
} & BankIcon;

function dismissError(item: PaymentMethod) {
function dismissError(item: PaymentMethodItem) {
if (item.cardID) {
PaymentMethods.clearDeletePaymentMethodError(ONYXKEYS.CARD_LIST, item.cardID);
return;
}

const isBankAccount = item.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT;
const paymentList = isBankAccount ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST;
const paymentID = isBankAccount ? item.accountData?.bankAccountID ?? '' : item.accountData?.fundID ?? '';
Expand Down Expand Up @@ -188,11 +195,14 @@ function PaymentMethodList({
const {isOffline} = useNetwork();

const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated});
const [bankAccountList = {}] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST);
const [bankAccountList = {}, bankAccountListResult] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const isLoadingBankAccountList = isLoadingOnyxValue(bankAccountListResult);
const [cardList = {}, cardListResult] = useOnyx(ONYXKEYS.CARD_LIST);
const isLoadingCardList = isLoadingOnyxValue(cardListResult);
// Temporarily disabled because P2P debit cards are disabled.
// const [fundList = {}] = useOnyx(ONYXKEYS.FUND_LIST);
const [isLoadingPaymentMethods = true] = useOnyx(ONYXKEYS.IS_LOADING_PAYMENT_METHODS);
const [isLoadingPaymentMethods = true, isLoadingPaymentMethodsResult] = useOnyx(ONYXKEYS.IS_LOADING_PAYMENT_METHODS);
const isLoadingPaymentMethodsOnyx = isLoadingOnyxValue(isLoadingPaymentMethodsResult);

const getDescriptionForPolicyDomainCard = (domainName: string): string => {
// A domain name containing a policyID indicates that this is a workspace feed
Expand All @@ -206,7 +216,7 @@ function PaymentMethodList({

const filteredPaymentMethods = useMemo(() => {
if (shouldShowAssignedCards) {
const assignedCards = Object.values(cardList ?? {})
const assignedCards = Object.values(isLoadingCardList ? {} : cardList ?? {})
// Filter by active cards associated with a domain
.filter((card) => !!card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0));
const assignedCardsSorted = lodashSortBy(assignedCards, (card) => !CardUtils.isExpensifyCard(card.cardID));
Expand Down Expand Up @@ -255,6 +265,7 @@ function PaymentMethodList({
title: card?.nameValuePairs?.cardTitle || card.bank,
description: getDescriptionForPolicyDomainCard(card.domainName),
onPress: () => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(String(card.cardID))),
cardID: card.cardID,
isGroupedCardDomain: !isAdminIssuedVirtualCard,
shouldShowRightIcon: true,
interactive: true,
Expand All @@ -275,7 +286,7 @@ function PaymentMethodList({
// const paymentCardList = fundList ?? {};
// const filteredCardList = Object.values(paymentCardList).filter((card) => !!card.accountData?.additionalData?.isP2PDebitCard);
const filteredCardList = {};
let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, filteredCardList, styles);
let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(isLoadingBankAccountList ? {} : bankAccountList ?? {}, filteredCardList, styles);

if (filterType !== '') {
combinedPaymentMethods = combinedPaymentMethods.filter((paymentMethod) => paymentMethod.accountType === filterType);
Expand Down Expand Up @@ -313,7 +324,21 @@ function PaymentMethodList({
};
});
return combinedPaymentMethods;
}, [shouldShowAssignedCards, bankAccountList, styles, filterType, isOffline, cardList, actionPaymentMethodType, activePaymentMethodID, StyleUtils, shouldShowRightIcon, onPress]);
}, [
shouldShowAssignedCards,
bankAccountList,
styles,
filterType,
isOffline,
cardList,
actionPaymentMethodType,
activePaymentMethodID,
StyleUtils,
shouldShowRightIcon,
onPress,
isLoadingBankAccountList,
isLoadingCardList,
]);

/**
* Render placeholder when there are no payments methods
Expand Down Expand Up @@ -418,7 +443,7 @@ function PaymentMethodList({
icon={Expensicons.CreditCard}
onPress={onPress}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
isDisabled={isLoadingPaymentMethods || isFormOffline}
isDisabled={isLoadingPaymentMethods || isFormOffline || isLoadingPaymentMethodsOnyx}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dominictb Why do we need isLoadingPaymentMethodsOnyx? isLoadingPaymentMethods should do the work here, right or am i missing something?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dominictb Same thing for the isLoadingCardList and isLoadingBankAccountList, do we really need that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need isLoadingPaymentMethodsOnyx? isLoadingPaymentMethods should do the work here, right or am i missing something?

The || isLoadingPaymentMethodsOnyx was added in this commit to remove withOnyx. Previously, when using withOnyx, isLoadingPaymentMethods had a default value of true. So, when switching to useOnyx, we needed to include || isLoadingPaymentMethodsOnyx wherever isLoadingPaymentMethods is used to ensure everything continues to function correctly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same approach should be applied in the case isLoadingCardList and isLoadingBankAccountList. When using withOnyx, isLoadingCardList has default value is {}. So we need to use const assignedCards = Object.values(isLoadingCardList ? {} : cardList ?? {}).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the details @dominictb.

I noticed an issue on the Expensify cards page within the workspaces—pressing the close icon doesn’t clear the error message. Although it's not related to the current issue but we had fixed a similar problem here in this PR.so, Just to confirm, @dominictb @cead22 should we address it as part of this task, or create a separate bug for it?

card-error-doesnt-go-away.mov

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Coming in here as assigned - if it's going to be a pretty similar solution let's knock it out in this PR as well. I realize it's a different page but still card-related error I guess, and if we already have done the work we need to adjust, let's do it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, Let's do this.

@dominictb We need to add the onClose here and set the errors null like we do in the clearDeletePaymentMethodError

<OfflineWithFeedback
key={`${item.nameValuePairs?.cardTitle}_${index}`}

Onyx.merge(paymentListKey, {
    [paymentMethodID]: {
        pendingAction: null,
        errors: null,
    },
});

style={[styles.mh4, styles.buttonCTA]}
key="addPaymentMethodButton"
success
Expand Down
30 changes: 6 additions & 24 deletions src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
Expand All @@ -18,32 +17,22 @@ import * as Card from '@userActions/Card';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {ReportVirtualCardFraudForm} from '@src/types/form';
import type {Card as OnyxCard} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

type ReportVirtualCardFraudPageOnyxProps = {
/** Form data propTypes */
formData: OnyxEntry<ReportVirtualCardFraudForm>;

/** Card list propTypes */
cardList: OnyxEntry<Record<string, OnyxCard>>;
};

type ReportVirtualCardFraudPageProps = ReportVirtualCardFraudPageOnyxProps & StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD>;
type ReportVirtualCardFraudPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD>;

function ReportVirtualCardFraudPage({
route: {
params: {cardID = ''},
},
cardList,
formData,
}: ReportVirtualCardFraudPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST);
const [formData] = useOnyx(ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD);

const virtualCard = cardList?.[cardID];
const virtualCardError = ErrorUtils.getLatestErrorMessage(virtualCard?.errors ?? {});
const virtualCardError = ErrorUtils.getLatestErrorMessage(virtualCard);

const prevIsLoading = usePrevious(formData?.isLoading);

Expand Down Expand Up @@ -85,11 +74,4 @@ function ReportVirtualCardFraudPage({

ReportVirtualCardFraudPage.displayName = 'ReportVirtualCardFraudPage';

export default withOnyx<ReportVirtualCardFraudPageProps, ReportVirtualCardFraudPageOnyxProps>({
cardList: {
key: ONYXKEYS.CARD_LIST,
},
formData: {
key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
},
})(ReportVirtualCardFraudPage);
export default ReportVirtualCardFraudPage;
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CardUtils from '@libs/CardUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import Navigation from '@navigation/Navigation';
import type {FullScreenNavigatorParamList} from '@navigation/types';
import * as PaymentMethods from '@userActions/PaymentMethods';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand All @@ -44,6 +46,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList}: WorkspaceExpensifyCa
const policyID = route.params.policyID;
const policy = usePolicy(policyID);
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID);

const policyCurrency = useMemo(() => policy?.outputCurrency ?? CONST.CURRENCY.USD, [policy]);

Expand Down Expand Up @@ -79,6 +82,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList}: WorkspaceExpensifyCa
pendingAction={item.pendingAction}
errorRowStyles={styles.ph5}
errors={item.errors}
onClose={() => PaymentMethods.clearDeletePaymentMethodError(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`, item.cardID)}
>
<PressableWithFeedback
role={CONST.ROLE.BUTTON}
Expand All @@ -97,7 +101,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList}: WorkspaceExpensifyCa
</PressableWithFeedback>
</OfflineWithFeedback>
),
[personalDetails, policyCurrency, policyID, styles],
[personalDetails, policyCurrency, policyID, workspaceAccountID, styles],
);

const renderListHeader = useCallback(() => <WorkspaceCardListHeader policyID={policyID} />, [policyID]);
Expand Down