From e33a8d30ef6caa70b42000d85b63b36950df7cd0 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Tue, 5 Sep 2023 17:34:19 +0100 Subject: [PATCH 1/2] feat(wallet): add assigned cards tile to wallet # Conflicts: # src/ROUTES.ts # src/languages/en.ts # src/libs/Navigation/AppNavigator/ModalStackNavigators.js # src/libs/Navigation/linkingConfig.js # src/pages/settings/Wallet/PaymentMethodList.js # src/pages/settings/Wallet/WalletPage/BaseWalletPage.js # src/pages/settings/Wallet/assignedCardPropTypes.js add missing translations # Conflicts: # src/languages/es.ts translate title, remove unnecessary useCallback modify comment # Conflicts: # src/pages/settings/Wallet/WalletEmptyState.js add missing type to ROUTES remove unnecessary dependency # Conflicts: # src/pages/settings/Wallet/PaymentMethodList.js remove unused prop chore(wallet): resolve merge conflicts # Conflicts: # src/libs/Navigation/linkingConfig.js # src/pages/settings/Wallet/PaymentMethodList.js # src/pages/settings/Wallet/WalletPage/BaseWalletPage.js # src/pages/settings/Wallet/WalletPage/WalletPage.js fix(wallet): clicking on an expensify card causing app to crash refactor(expensify card): rename card active states constant and import it where needed fix(expensify card): domain cards not getting properly setup because of different name cases fix(wallet): assigned cards section spacing --- src/CONST.ts | 1 + src/languages/en.ts | 3 ++ src/languages/es.ts | 3 ++ src/libs/CardUtils.ts | 4 +- .../settings/Wallet/PaymentMethodList.js | 47 +++++++++++++++++-- .../settings/Wallet/WalletPage/WalletPage.js | 21 +++++++++ .../settings/Wallet/assignedCardPropTypes.js | 7 +-- 7 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index a4f28a9c98c7..9e7b583e90e0 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1243,6 +1243,7 @@ const CONST = { CLOSED: 6, STATE_SUSPENDED: 7, }, + ACTIVE_STATES: [2, 3, 4, 7], }, AVATAR_ROW_SIZE: { DEFAULT: 4, diff --git a/src/languages/en.ts b/src/languages/en.ts index 8c4257dc40f0..2f5d5c3abb3c 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -848,6 +848,9 @@ export default { bankAccounts: 'Bank accounts', addBankAccountToSendAndReceive: 'Add a bank account to send and receive payments directly in the app.', addBankAccount: 'Add bank account', + assignedCards: 'Assigned cards', + assignedCardsDescription: 'These are cards assigned by a Workspace admin to manage company spend.', + expensifyCard: 'Expensify Card', }, cardPage: { expensifyCard: 'Expensify Card', diff --git a/src/languages/es.ts b/src/languages/es.ts index 1d9f71fc5da2..95e616d3a981 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -844,6 +844,9 @@ export default { bankAccounts: 'Cuentas bancarias', addBankAccountToSendAndReceive: 'Añade una cuenta bancaria para enviar y recibir pagos directamente en la aplicación.', addBankAccount: 'Agregar cuenta bancaria', + assignedCards: 'Tarjetas asignadas', + assignedCardsDescription: 'Son tarjetas asignadas por un administrador del Espacio de Trabajo para gestionar los gastos de la empresa.', + expensifyCard: 'Tarjeta Expensify', }, cardPage: { expensifyCard: 'Tarjeta Expensify', diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index e6c7480974ca..8df554dd4dbf 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -73,8 +73,8 @@ function getCompanyCards(cardList: {string: Card}) { */ function getDomainCards(cardList: Record) { // eslint-disable-next-line you-dont-need-lodash-underscore/filter - const activeCards = lodash.filter(cardList, (card) => [2, 3, 4, 7].includes(card.state)); - return lodash.groupBy(activeCards, (card) => card.domainName.toLowerCase()); + const activeCards = lodash.filter(cardList, (card) => (CONST.EXPENSIFY_CARD.ACTIVE_STATES as ReadonlyArray).includes(card.state)); + return lodash.groupBy(activeCards, (card) => card.domainName); } /** diff --git a/src/pages/settings/Wallet/PaymentMethodList.js b/src/pages/settings/Wallet/PaymentMethodList.js index abee54d9fcd4..f34897d9e7c0 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.js +++ b/src/pages/settings/Wallet/PaymentMethodList.js @@ -23,6 +23,10 @@ import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import * as PaymentMethods from '../../../libs/actions/PaymentMethods'; import Log from '../../../libs/Log'; import stylePropTypes from '../../../styles/stylePropTypes'; +import Navigation from '../../../libs/Navigation/Navigation'; +import ROUTES from '../../../ROUTES'; +import getBankIcon from '../../../components/Icon/BankIcons'; +import assignedCardPropTypes from './assignedCardPropTypes'; const propTypes = { /** What to do when a menu item is pressed */ @@ -31,12 +35,21 @@ const propTypes = { /** List of bank accounts */ bankAccountList: PropTypes.objectOf(bankAccountPropTypes), + /** List of assigned cards */ + cardList: PropTypes.objectOf(assignedCardPropTypes), + /** List of user's cards */ fundList: PropTypes.objectOf(cardPropTypes), + /** Whether the add bank account button should be shown on the list */ + shouldShowAddBankAccount: PropTypes.bool, + /** Whether the add Payment button be shown on the list */ shouldShowAddPaymentMethodButton: PropTypes.bool, + /** Whether the assigned cards should be shown on the list */ + shouldShowAssignedCards: PropTypes.bool, + /** Whether the empty list message should be shown when the list is empty */ shouldShowEmptyListMessage: PropTypes.bool, @@ -84,13 +97,16 @@ const propTypes = { const defaultProps = { bankAccountList: {}, + cardList: {}, fundList: null, userWallet: { walletLinkedAccountID: 0, walletLinkedAccountType: '', }, isLoadingPaymentMethods: true, + shouldShowAddBankAccount: true, shouldShowAddPaymentMethodButton: true, + shouldShowAssignedCards: false, shouldShowEmptyListMessage: true, filterType: '', actionPaymentMethodType: '', @@ -161,6 +177,7 @@ function PaymentMethodList({ activePaymentMethodID, bankAccountList, buttonRef, + cardList, fundList, filterType, isLoadingPaymentMethods, @@ -171,13 +188,29 @@ function PaymentMethodList({ shouldEnableScroll, shouldShowSelectedState, shouldShowAddPaymentMethodButton, + shouldShowAddBankAccount, shouldShowEmptyListMessage, + shouldShowAssignedCards, selectedMethodID, style, translate, }) { const filteredPaymentMethods = useMemo(() => { const paymentCardList = fundList || {}; + + if (shouldShowAssignedCards) { + const assignedCards = _.filter(cardList, (card) => CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state)); + return _.map(assignedCards, (card) => { + const icon = getBankIcon(card.bank); + return { + title: translate('walletPage.expensifyCard'), + description: card.domainName, + onPress: () => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(card.domainName)), + ...icon, + }; + }); + } + // Hide any billing cards that are not P2P debit cards for now because you cannot make them your default method, or delete them const filteredCardList = _.filter(paymentCardList, (card) => card.accountData.additionalData.isP2PDebitCard); let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList, filteredCardList); @@ -204,14 +237,14 @@ function PaymentMethodList({ })); return combinedPaymentMethods; - }, [actionPaymentMethodType, activePaymentMethodID, bankAccountList, filterType, network, onPress, fundList]); + }, [fundList, shouldShowAssignedCards, bankAccountList, filterType, network.isOffline, cardList, translate, actionPaymentMethodType, activePaymentMethodID, onPress]); /** * Render placeholder when there are no payments methods * * @return {React.Component} */ - const renderListEmptyComponent = useCallback(() => {translate('paymentMethodList.addFirstPaymentMethod')}, [translate]); + const renderListEmptyComponent = () => {translate('paymentMethodList.addFirstPaymentMethod')}; const renderListFooterComponent = useCallback( () => ( @@ -252,12 +285,13 @@ function PaymentMethodList({ iconWidth={item.iconSize} badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : null} wrapperStyle={styles.paymentMethod} + shouldShowRightIcon={shouldShowAssignedCards} shouldShowSelectedState={shouldShowSelectedState} isSelected={selectedMethodID === item.methodID} /> ), - [filteredPaymentMethods, translate, shouldShowSelectedState, selectedMethodID], + [filteredPaymentMethods, translate, shouldShowAssignedCards, shouldShowSelectedState, selectedMethodID], ); return ( @@ -266,9 +300,9 @@ function PaymentMethodList({ data={filteredPaymentMethods} renderItem={renderItem} keyExtractor={(item) => item.key} - ListEmptyComponent={shouldShowEmptyListMessage ? renderListEmptyComponent(translate) : null} + ListEmptyComponent={shouldShowEmptyListMessage ? renderListEmptyComponent : null} ListHeaderComponent={listHeaderComponent} - ListFooterComponent={renderListFooterComponent} + ListFooterComponent={shouldShowAddBankAccount ? renderListFooterComponent : null} onContentSizeChange={onListContentSizeChange} scrollEnabled={shouldEnableScroll} style={style} @@ -307,6 +341,9 @@ export default compose( bankAccountList: { key: ONYXKEYS.BANK_ACCOUNT_LIST, }, + cardList: { + key: ONYXKEYS.CARD_LIST, + }, fundList: { key: ONYXKEYS.FUND_LIST, }, diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.js b/src/pages/settings/Wallet/WalletPage/WalletPage.js index 4115335bbcd5..ec9ff537189e 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.js +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.js @@ -373,6 +373,27 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen )} + {hasAssignedCard ? ( + + {}} + /> + + ) : null} Date: Fri, 13 Oct 2023 16:05:50 +0100 Subject: [PATCH 2/2] fix(wallet): missing key on assigned card objects --- src/pages/settings/Wallet/PaymentMethodList.js | 1 + src/pages/settings/Wallet/assignedCardPropTypes.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.js b/src/pages/settings/Wallet/PaymentMethodList.js index f34897d9e7c0..2943fa9544ae 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.js +++ b/src/pages/settings/Wallet/PaymentMethodList.js @@ -203,6 +203,7 @@ function PaymentMethodList({ return _.map(assignedCards, (card) => { const icon = getBankIcon(card.bank); return { + key: card.key, title: translate('walletPage.expensifyCard'), description: card.domainName, onPress: () => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(card.domainName)), diff --git a/src/pages/settings/Wallet/assignedCardPropTypes.js b/src/pages/settings/Wallet/assignedCardPropTypes.js index 0f986e8d7d04..e45b57a05d31 100644 --- a/src/pages/settings/Wallet/assignedCardPropTypes.js +++ b/src/pages/settings/Wallet/assignedCardPropTypes.js @@ -10,7 +10,7 @@ const assignedCardPropTypes = PropTypes.shape({ domainName: PropTypes.string, maskedPan: PropTypes.string, isVirtual: PropTypes.bool, - fraud: CONST.EXPENSIFY_CARD.FRAUD_TYPES, + fraud: PropTypes.oneOf([CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN, CONST.EXPENSIFY_CARD.FRAUD_TYPES.USER, CONST.EXPENSIFY_CARD.FRAUD_TYPES.NONE]), cardholderFirstName: PropTypes.string, cardholderLastName: PropTypes.string, });