From 7c01d82bbc3e5b749cb45758b915af0254d0100b Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 10 Jan 2024 23:10:50 +0700 Subject: [PATCH 01/16] migrate to ts --- src/CONST.ts | 4 +- src/components/AddPaymentMethodMenu.js | 13 +- src/components/KYCWall/index.js | 3 +- src/libs/CardUtils.ts | 10 +- src/libs/PaymentUtils.ts | 2 +- src/libs/actions/BankAccounts.ts | 2 +- src/libs/actions/PaymentMethods.ts | 14 +- ...entMethodList.js => PaymentMethodList.tsx} | 214 +++++++----------- ...lletEmptyState.js => WalletEmptyState.tsx} | 10 +- .../{CardDetails.js => CardDetails.tsx} | 67 +++--- .../{WalletPage.js => WalletPage.tsx} | 163 +++++++------ .../{index.native.js => index.native.tsx} | 0 .../Wallet/WalletPage/{index.js => index.tsx} | 0 src/pages/settings/Wallet/WalletPage/types.ts | 31 +++ .../Wallet/WalletPage/walletPagePropTypes.js | 52 ----- src/types/onyx/AccountData.ts | 2 + src/types/onyx/Card.ts | 4 +- src/types/onyx/index.ts | 2 + 18 files changed, 271 insertions(+), 322 deletions(-) rename src/pages/settings/Wallet/{PaymentMethodList.js => PaymentMethodList.tsx} (73%) rename src/pages/settings/Wallet/{WalletEmptyState.js => WalletEmptyState.tsx} (87%) rename src/pages/settings/Wallet/WalletPage/{CardDetails.js => CardDetails.tsx} (75%) rename src/pages/settings/Wallet/WalletPage/{WalletPage.js => WalletPage.tsx} (87%) rename src/pages/settings/Wallet/WalletPage/{index.native.js => index.native.tsx} (100%) rename src/pages/settings/Wallet/WalletPage/{index.js => index.tsx} (100%) create mode 100644 src/pages/settings/Wallet/WalletPage/types.ts delete mode 100644 src/pages/settings/Wallet/WalletPage/walletPagePropTypes.js diff --git a/src/CONST.ts b/src/CONST.ts index c6849db630f2..c0eecf6858e3 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1350,7 +1350,9 @@ const CONST = { CLOSED: 6, STATE_SUSPENDED: 7, }, - ACTIVE_STATES: [2, 3, 4, 7], + get ACTIVE_STATES() { + return [2, 3, 4, 7]; + }, }, AVATAR_ROW_SIZE: { DEFAULT: 4, diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 4abe5655e307..a936b0efdfa1 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -122,11 +122,8 @@ AddPaymentMethodMenu.propTypes = propTypes; AddPaymentMethodMenu.defaultProps = defaultProps; AddPaymentMethodMenu.displayName = 'AddPaymentMethodMenu'; -export default compose( - withWindowDimensions, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(AddPaymentMethodMenu); +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, +})(AddPaymentMethodMenu); diff --git a/src/components/KYCWall/index.js b/src/components/KYCWall/index.js index 49329c73d474..87f1496a494a 100644 --- a/src/components/KYCWall/index.js +++ b/src/components/KYCWall/index.js @@ -2,12 +2,13 @@ import React from 'react'; import BaseKYCWall from './BaseKYCWall'; import {defaultProps, propTypes} from './kycWallPropTypes'; -function KYCWall(props) { +function KYCWall({children, ...props}) { return ( ); } diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index d71ad9c2629a..bc18808886e2 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -29,7 +29,10 @@ function getMonthFromExpirationDateString(expirationDateString: string) { * @param cardID * @returns boolean */ -function isExpensifyCard(cardID: number) { +function isExpensifyCard(cardID?: number) { + if (!cardID) { + return false; + } const card = allCards[cardID]; if (!card) { return false; @@ -49,7 +52,10 @@ function isCorporateCard(cardID: number) { * @param cardID * @returns string in format % - %. */ -function getCardDescription(cardID: number) { +function getCardDescription(cardID?: number) { + if (!cardID) { + return ''; + } const card = allCards[cardID]; if (!card) { return ''; diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts index dd35d0df5cfb..60dac04a09ac 100644 --- a/src/libs/PaymentUtils.ts +++ b/src/libs/PaymentUtils.ts @@ -40,7 +40,7 @@ function getPaymentMethodDescription(accountType: AccountType, account: BankAcco /** * Get the PaymentMethods list */ -function formatPaymentMethods(bankAccountList: Record, fundList: Record, styles: ThemeStyles): PaymentMethod[] { +function formatPaymentMethods(bankAccountList: Record, fundList: Record | Fund[], styles: ThemeStyles): PaymentMethod[] { const combinedPaymentMethods: PaymentMethod[] = []; Object.values(bankAccountList).forEach((bankAccount) => { diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index f7b7ec89c670..1ce6bc38191f 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -50,7 +50,7 @@ function setPlaidEvent(eventName: string) { /** * Open the personal bank account setup flow, with an optional exitReportID to redirect to once the flow is finished. */ -function openPersonalBankAccountSetupView(exitReportID: string) { +function openPersonalBankAccountSetupView(exitReportID?: string) { clearPlaid().then(() => { if (exitReportID) { Onyx.merge(ONYXKEYS.PERSONAL_BANK_ACCOUNT, {exitReportID}); diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index a7ae54f46416..6614d3516253 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -71,10 +71,10 @@ function openWalletPage() { } function getMakeDefaultPaymentOnyxData( - bankAccountID: number, - fundID: number, - previousPaymentMethod: PaymentMethod, - currentPaymentMethod: PaymentMethod, + bankAccountID: number | null, + fundID: number | null, + previousPaymentMethod?: PaymentMethod, + currentPaymentMethod?: PaymentMethod, isOptimisticData = true, ): OnyxUpdate[] { const onyxData: OnyxUpdate[] = [ @@ -130,10 +130,10 @@ function getMakeDefaultPaymentOnyxData( * Sets the default bank account or debit card for an Expensify Wallet * */ -function makeDefaultPaymentMethod(bankAccountID: number, fundID: number, previousPaymentMethod: PaymentMethod, currentPaymentMethod: PaymentMethod) { +function makeDefaultPaymentMethod(bankAccountID: number | null, fundID: number | null, previousPaymentMethod?: PaymentMethod, currentPaymentMethod?: PaymentMethod) { type MakeDefaultPaymentMethodParams = { - bankAccountID: number; - fundID: number; + bankAccountID: number | null; + fundID: number | null; }; const parameters: MakeDefaultPaymentMethodParams = { diff --git a/src/pages/settings/Wallet/PaymentMethodList.js b/src/pages/settings/Wallet/PaymentMethodList.tsx similarity index 73% rename from src/pages/settings/Wallet/PaymentMethodList.js rename to src/pages/settings/Wallet/PaymentMethodList.tsx index 06bd8afa6140..9cceaa60c10c 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.js +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -1,15 +1,17 @@ import {FlashList} from '@shopify/flash-list'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useCallback, useMemo} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import React, {ReactElement, Ref, useCallback, useMemo} from 'react'; +import {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; +import {TupleToUnion, ValueOf} from 'type-fest'; import _ from 'underscore'; import bankAccountPropTypes from '@components/bankAccountPropTypes'; import Button from '@components/Button'; import cardPropTypes from '@components/cardPropTypes'; import FormAlertWrapper from '@components/FormAlertWrapper'; import getBankIcon from '@components/Icon/BankIcons'; +import {BankName} from '@components/Icon/BankIconsUtils'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -28,112 +30,91 @@ import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import assignedCardPropTypes from './assignedCardPropTypes'; +import {AccountData, BankAccountList, Card, CardList, FundList, UserWallet} from '@src/types/onyx'; +import PaymentMethod from '@src/types/onyx/PaymentMethod'; -const propTypes = { - /** What to do when a menu item is pressed */ - onPress: PropTypes.func.isRequired, +const FILTER_TYPES = [CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, ''] as const; +const ACTION_PAYMENT_METHOD_TYPES = [...Object.values(CONST.PAYMENT_METHODS), ''] as const; +type PaymentMethodListOnyxProps = { /** List of bank accounts */ - bankAccountList: PropTypes.objectOf(bankAccountPropTypes), + bankAccountList: OnyxEntry; /** List of assigned cards */ - cardList: PropTypes.objectOf(assignedCardPropTypes), + cardList: OnyxEntry; /** 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, + fundList: OnyxEntry; /** Are we loading payment methods? */ - isLoadingPaymentMethods: PropTypes.bool, - - /** Type to filter the payment Method list */ - filterType: PropTypes.oneOf([CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, '']), + isLoadingPaymentMethods: OnyxEntry; /** User wallet props */ - userWallet: PropTypes.shape({ - /** The ID of the linked account */ - walletLinkedAccountID: PropTypes.number, - - /** The type of the linked account (debitCard or bankAccount) */ - walletLinkedAccountType: PropTypes.string, - }), + userWallet: OnyxEntry; +}; +type PaymentMethodListProps = PaymentMethodListOnyxProps & { /** Type of active/highlighted payment method */ - actionPaymentMethodType: PropTypes.oneOf([..._.values(CONST.PAYMENT_METHODS), '']), + actionPaymentMethodType?: TupleToUnion; /** ID of active/highlighted payment method */ - activePaymentMethodID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + activePaymentMethodID?: string | number; /** ID of selected payment method */ - selectedMethodID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + selectedMethodID?: string | number; /** Content for the FlatList header component */ - listHeaderComponent: PropTypes.func, + listHeaderComponent?: ReactElement; /** Callback for whenever FlatList component size changes */ - onListContentSizeChange: PropTypes.func, + onListContentSizeChange?: () => void; /** Should menu items be selectable with a checkbox */ - shouldShowSelectedState: PropTypes.bool, + shouldShowSelectedState?: boolean; /** React ref being forwarded to the PaymentMethodList Button */ - buttonRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + buttonRef?: Ref; /** To enable/disable scrolling */ - shouldEnableScroll: PropTypes.bool, + shouldEnableScroll?: boolean; /** List container style */ - style: stylePropTypes, + style?: StyleProp; + + /** Type to filter the payment Method list */ + filterType?: TupleToUnion; + /** Whether the add bank account button should be shown on the list */ + shouldShowAddBankAccount?: boolean; + + /** Whether the add Payment button be shown on the list */ + shouldShowAddPaymentMethodButton?: boolean; + + /** Whether the assigned cards should be shown on the list */ + shouldShowAssignedCards?: boolean; + + /** Whether the empty list message should be shown when the list is empty */ + shouldShowEmptyListMessage?: boolean; + + /** What to do when a menu item is pressed */ + onPress: (event?: GestureResponderEvent | KeyboardEvent, accountType?: string, accountData?: AccountData, isDefault?: boolean, methodID?: number) => void | Promise; }; -const defaultProps = { - bankAccountList: {}, - cardList: {}, - fundList: null, - userWallet: { - walletLinkedAccountID: 0, - walletLinkedAccountType: '', - }, - isLoadingPaymentMethods: true, - shouldShowAddBankAccount: true, - shouldShowAddPaymentMethodButton: true, - shouldShowAssignedCards: false, - shouldShowEmptyListMessage: true, - filterType: '', - actionPaymentMethodType: '', - activePaymentMethodID: '', - selectedMethodID: '', - listHeaderComponent: null, - buttonRef: () => {}, - onListContentSizeChange: () => {}, - shouldEnableScroll: true, - style: {}, - shouldShowSelectedState: false, +type PaymentMethodItem = PaymentMethod & { + onPress?: (e: GestureResponderEvent | KeyboardEvent | undefined) => void; + canDismissError?: boolean; + disabled?: boolean; + shouldShowRightIcon?: boolean; + interactive?: boolean; + brickRoadIndicator?: ValueOf; }; -/** - * Dismisses the error on the payment method - * @param {Object} item - */ -function dismissError(item) { +function dismissError(item: PaymentMethod) { const isBankAccount = item.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT; const paymentList = isBankAccount ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST; const paymentID = isBankAccount ? lodashGet(item, ['accountData', 'bankAccountID'], '') : lodashGet(item, ['accountData', 'fundID'], ''); if (!paymentID) { - Log.info('Unable to clear payment method error: ', item); + Log.info('Unable to clear payment method error: ', undefined, item); return; } @@ -150,12 +131,7 @@ function dismissError(item) { } } -/** - * @param {Array} filteredPaymentMethods - * @param {Boolean} isDefault - * @returns {Boolean} - */ -function shouldShowDefaultBadge(filteredPaymentMethods, isDefault = false) { +function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefault = false) { if (!isDefault) { return false; } @@ -167,45 +143,35 @@ function shouldShowDefaultBadge(filteredPaymentMethods, isDefault = false) { return defaultablePaymentMethodCount > 1; } -/** - * @param {String} actionPaymentMethodType - * @param {String|Number} activePaymentMethodID - * @param {String} paymentMethod - * @return {Boolean} - */ -function isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod) { +function isPaymentMethodActive(actionPaymentMethodType: string, activePaymentMethodID: string | number, paymentMethod: PaymentMethod) { return paymentMethod.accountType === actionPaymentMethodType && paymentMethod.methodID === activePaymentMethodID; } -/** - * @param {Object} item - * @returns {String} - */ -function keyExtractor(item) { - return item.key; +function keyExtractor(item: PaymentMethod) { + return item.key || ''; } function PaymentMethodList({ - actionPaymentMethodType, - activePaymentMethodID, - bankAccountList, - buttonRef, - cardList, - fundList, - filterType, - isLoadingPaymentMethods, - onPress, - shouldShowSelectedState, - shouldShowAddPaymentMethodButton, - shouldShowAddBankAccount, - shouldShowEmptyListMessage, - shouldShowAssignedCards, - selectedMethodID, + actionPaymentMethodType = '', + activePaymentMethodID = '', + bankAccountList = {}, + buttonRef = () => {}, + cardList = {}, + fundList = {}, + filterType = '', listHeaderComponent, - onListContentSizeChange, - shouldEnableScroll, - style, -}) { + isLoadingPaymentMethods = true, + onPress, + shouldShowSelectedState = false, + shouldShowAddPaymentMethodButton = true, + shouldShowAddBankAccount = true, + shouldShowEmptyListMessage = true, + shouldShowAssignedCards = false, + selectedMethodID = '', + onListContentSizeChange = () => {}, + shouldEnableScroll = true, + style = {}, +}: PaymentMethodListProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -215,7 +181,7 @@ function PaymentMethodList({ if (shouldShowAssignedCards) { const assignedCards = _.chain(cardList) // Filter by physical, active cards associated with a domain - .filter((card) => !card.isVirtual && card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state)) + .filter((card) => !card.isVirtual && card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0)) .sortBy((card) => !CardUtils.isExpensifyCard(card.cardID)) .value(); @@ -223,15 +189,15 @@ function PaymentMethodList({ return _.map(assignedCards, (card) => { const isExpensifyCard = CardUtils.isExpensifyCard(card.cardID); - const icon = getBankIcon({bankName: card.bank, isCard: true, styles}); + const icon = getBankIcon({bankName: card.bank as BankName, isCard: true, styles}); // In the case a user has been assigned multiple physical Expensify Cards under one domain, display the Card with PAN const expensifyCardDescription = numberPhysicalExpensifyCards > 1 ? CardUtils.getCardDescription(card.cardID) : translate('walletPage.expensifyCard'); return { - key: card.cardID, + key: card.cardID.toString(), title: isExpensifyCard ? expensifyCardDescription : card.cardName, description: card.domainName, - onPress: isExpensifyCard ? () => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(card.domainName)) : () => {}, + onPress: isExpensifyCard ? () => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(card.domainName ?? '')) : () => {}, shouldShowRightIcon: isExpensifyCard, interactive: isExpensifyCard, canDismissError: isExpensifyCard, @@ -245,8 +211,8 @@ function PaymentMethodList({ const paymentCardList = fundList || {}; // 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, styles); + const filteredCardList = _.filter(paymentCardList, (card) => !!card.accountData?.additionalData?.isP2PDebitCard); + let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, filteredCardList, styles); if (!_.isEmpty(filterType)) { combinedPaymentMethods = _.filter(combinedPaymentMethods, (paymentMethod) => paymentMethod.accountType === filterType); @@ -261,10 +227,9 @@ function PaymentMethodList({ combinedPaymentMethods = _.map(combinedPaymentMethods, (paymentMethod) => { const isMethodActive = isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod); - return { ...paymentMethod, - onPress: (e) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.isDefault, paymentMethod.methodID), + onPress: (e: GestureResponderEvent) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.isDefault, paymentMethod.methodID), wrapperStyle: isMethodActive ? [StyleUtils.getButtonBackgroundColorStyle(CONST.BUTTON_STATES.PRESSED)] : null, disabled: paymentMethod.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, }; @@ -296,14 +261,9 @@ function PaymentMethodList({ /** * Create a menuItem for each passed paymentMethod - * - * @param {Object} params - * @param {Object} params.item - * - * @return {React.Component} */ const renderItem = useCallback( - ({item}) => ( + ({item}: {item: PaymentMethodItem}) => ( dismissError(item)} pendingAction={item.pendingAction} @@ -321,7 +281,7 @@ function PaymentMethodList({ iconHeight={item.iconHeight || item.iconSize} iconWidth={item.iconWidth || item.iconSize} iconStyles={item.iconStyles} - badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : null} + badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : undefined} wrapperStyle={styles.paymentMethod} shouldShowRightIcon={item.shouldShowRightIcon} shouldShowSelectedState={shouldShowSelectedState} @@ -340,7 +300,7 @@ function PaymentMethodList({ ({ bankAccountList: { key: ONYXKEYS.BANK_ACCOUNT_LIST, }, diff --git a/src/pages/settings/Wallet/WalletEmptyState.js b/src/pages/settings/Wallet/WalletEmptyState.tsx similarity index 87% rename from src/pages/settings/Wallet/WalletEmptyState.js rename to src/pages/settings/Wallet/WalletEmptyState.tsx index 7a3a9e9ce6b7..4ef9488368cb 100644 --- a/src/pages/settings/Wallet/WalletEmptyState.js +++ b/src/pages/settings/Wallet/WalletEmptyState.tsx @@ -11,9 +11,8 @@ import Navigation from '@libs/Navigation/Navigation'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -const propTypes = { - /** The function that is called when a menu item is pressed */ - onAddPaymentMethod: PropTypes.func.isRequired, +type WalletEmptyStateProps = { + onAddPaymentMethod: () => void; }; const WALLET_FEATURES = [ @@ -31,7 +30,7 @@ const WALLET_FEATURES = [ }, ]; -function WalletEmptyState({onAddPaymentMethod}) { +function WalletEmptyState({onAddPaymentMethod}: WalletEmptyStateProps) { const theme = useTheme(); const {translate} = useLocalize(); return ( @@ -58,7 +57,4 @@ function WalletEmptyState({onAddPaymentMethod}) { ); } -WalletEmptyState.displayName = 'WalletEmptyState'; -WalletEmptyState.propTypes = propTypes; - export default WalletEmptyState; diff --git a/src/pages/settings/Wallet/WalletPage/CardDetails.js b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx similarity index 75% rename from src/pages/settings/Wallet/WalletPage/CardDetails.js rename to src/pages/settings/Wallet/WalletPage/CardDetails.tsx index b51c34e89d17..09a7d937053b 100644 --- a/src/pages/settings/Wallet/WalletPage/CardDetails.js +++ b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayToggle'; @@ -14,50 +14,39 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {PrivatePersonalDetails} from '@src/types/onyx'; -const propTypes = { +const defaultPrivatePersonalDetails = { + address: { + street: '', + street2: '', + city: '', + state: '', + zip: '', + country: '', + }, +}; + +type CardDetailsOnyxProps = { + /** User's private personal details */ + privatePersonalDetails: OnyxEntry; +}; + +type CardDetailsProps = CardDetailsOnyxProps & { /** Card number */ - pan: PropTypes.string, + pan?: string; /** Card expiration date */ - expiration: PropTypes.string, + expiration?: string; /** 3 digit code */ - cvv: PropTypes.string, - - /** User's private personal details */ - privatePersonalDetails: PropTypes.shape({ - /** User's home address */ - address: PropTypes.shape({ - street: PropTypes.string, - city: PropTypes.string, - state: PropTypes.string, - zip: PropTypes.string, - country: PropTypes.string, - }), - }), + cvv?: string; /** Domain name */ - domain: PropTypes.string.isRequired, -}; - -const defaultProps = { - pan: '', - expiration: '', - cvv: '', - privatePersonalDetails: { - address: { - street: '', - street2: '', - city: '', - state: '', - zip: '', - country: '', - }, - }, + domain: string; }; -function CardDetails({pan, expiration, cvv, privatePersonalDetails, domain}) { +function CardDetails({pan = '', expiration = '', cvv = '', privatePersonalDetails = defaultPrivatePersonalDetails, domain}: CardDetailsProps) { const styles = useThemeStyles(); usePrivatePersonalDetails(); const {translate} = useLocalize(); @@ -79,6 +68,8 @@ function CardDetails({pan, expiration, cvv, privatePersonalDetails, domain}) { tooltipTextChecked={translate('reportActionContextMenu.copied')} icon={Expensicons.Copy} onPress={handleCopyToClipboard} + accessible={false} + text="" /> } @@ -96,7 +87,7 @@ function CardDetails({pan, expiration, cvv, privatePersonalDetails, domain}) { /> ({ privatePersonalDetails: { key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, }, diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.js b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx similarity index 87% rename from src/pages/settings/Wallet/WalletPage/WalletPage.js rename to src/pages/settings/Wallet/WalletPage/WalletPage.tsx index bf547bc4bd10..0463008cf7cb 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.js +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -1,7 +1,9 @@ import lodashGet from 'lodash/get'; -import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; +import React, {Ref, useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; import {ActivityIndicator, Dimensions, ScrollView, View} from 'react-native'; +import {GestureResponderEvent} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import {TupleToUnion} from 'type-fest'; import _ from 'underscore'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; import Button from '@components/Button'; @@ -20,6 +22,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import WalletSection from '@components/WalletSection'; import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -35,27 +38,46 @@ import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {defaultProps, propTypes} from './walletPagePropTypes'; +import {AccountData, BankAccount} from '@src/types/onyx'; +import PaymentMethod from '@src/types/onyx/PaymentMethod'; +import IconAsset from '@src/types/utils/IconAsset'; +import {WalletPageOnyxProps, WalletPageProps} from './types'; + +const ACTION_PAYMENT_METHOD_TYPES = [...Object.values(CONST.PAYMENT_METHODS), ''] as const; + +type PaymentMethodState = { + isSelectedPaymentMethodDefault: boolean; + selectedPaymentMethod: AccountData; + formattedSelectedPaymentMethod: { + title: string; + icon?: IconAsset; + description?: string; + type?: string; + }; + methodID: string | number; + selectedPaymentMethodType: string; +}; -function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethods, network, shouldListenForResize, userWallet, walletTerms}) { +function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadingPaymentMethods = true, shouldListenForResize = false, userWallet, walletTerms = {}}: WalletPageProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); + const network = useNetwork(); const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); const [shouldShowAddPaymentMenu, setShouldShowAddPaymentMenu] = useState(false); const [shouldShowDefaultDeleteMenu, setShouldShowDefaultDeleteMenu] = useState(false); const [shouldShowLoadingSpinner, setShouldShowLoadingSpinner] = useState(false); - const [paymentMethod, setPaymentMethod] = useState({ + const [paymentMethod, setPaymentMethod] = useState({ isSelectedPaymentMethodDefault: false, selectedPaymentMethod: {}, formattedSelectedPaymentMethod: { title: '', }, - methodID: null, - selectedPaymentMethodType: null, + methodID: '', + selectedPaymentMethodType: '', }); const addPaymentMethodAnchorRef = useRef(null); - const paymentMethodButtonRef = useRef(null); + const paymentMethodButtonRef = useRef(null); const [anchorPosition, setAnchorPosition] = useState({ anchorPositionHorizontal: 0, anchorPositionVertical: 0, @@ -66,7 +88,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod const hasBankAccount = !_.isEmpty(bankAccountList) || !_.isEmpty(fundList); const hasWallet = !_.isEmpty(userWallet); - const hasActivatedWallet = _.contains([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM], userWallet.tierName); + const hasActivatedWallet = _.contains([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM], userWallet?.tierName); const hasAssignedCard = !_.isEmpty(cardList); const shouldShowEmptyState = !hasBankAccount && !hasWallet && !hasAssignedCard; @@ -77,7 +99,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod // In order to prevent a loop, only update state of the spinner if there is a change const showLoadingSpinner = isLoadingPaymentMethods || false; if (showLoadingSpinner !== shouldShowLoadingSpinner) { - setShouldShowLoadingSpinner(isLoadingPaymentMethods && !network.isOffline); + setShouldShowLoadingSpinner(!!isLoadingPaymentMethods && !network.isOffline); } }, [isLoadingPaymentMethods, network.isOffline, shouldShowLoadingSpinner]); @@ -121,8 +143,8 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod formattedSelectedPaymentMethod: { title: '', }, - methodID: null, - selectedPaymentMethodType: null, + methodID: '', + selectedPaymentMethodType: '', }); }, [setPaymentMethod]); @@ -135,7 +157,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod * @param {Boolean} isDefault * @param {String|Number} methodID */ - const paymentMethodPressed = (nativeEvent, accountType, account, isDefault, methodID) => { + const paymentMethodPressed = (nativeEvent?: GestureResponderEvent | KeyboardEvent, accountType?: string, account?: AccountData, isDefault?: boolean, methodID?: string | number) => { if (shouldShowAddPaymentMenu) { setShouldShowAddPaymentMenu(false); return; @@ -145,32 +167,34 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod setShouldShowDefaultDeleteMenu(false); return; } - paymentMethodButtonRef.current = nativeEvent.currentTarget; + paymentMethodButtonRef.current = nativeEvent?.currentTarget as HTMLElement; // The delete/default menu if (accountType) { - let formattedSelectedPaymentMethod; + let formattedSelectedPaymentMethod = { + title: '', + }; if (accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { formattedSelectedPaymentMethod = { - title: account.addressName, - icon: account.icon, + title: account?.addressName ?? '', + icon: account?.icon, description: PaymentUtils.getPaymentMethodDescription(accountType, account), type: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, }; } else if (accountType === CONST.PAYMENT_METHODS.DEBIT_CARD) { formattedSelectedPaymentMethod = { - title: account.addressName, - icon: account.icon, + title: account?.addressName ?? '', + icon: account?.icon, description: PaymentUtils.getPaymentMethodDescription(accountType, account), type: CONST.PAYMENT_METHODS.DEBIT_CARD, }; } setPaymentMethod({ - isSelectedPaymentMethodDefault: isDefault, - selectedPaymentMethod: account, + isSelectedPaymentMethodDefault: !!isDefault, + selectedPaymentMethod: account || {}, selectedPaymentMethodType: accountType, formattedSelectedPaymentMethod, - methodID, + methodID: methodID ?? '', }); setShouldShowDefaultDeleteMenu(true); setMenuPosition(); @@ -189,10 +213,8 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod /** * Navigate to the appropriate payment type addition screen - * - * @param {String} paymentType */ - const addPaymentMethodTypePressed = (paymentType) => { + const addPaymentMethodTypePressed = (paymentType: string) => { hideAddPaymentMenu(); if (paymentType === CONST.PAYMENT_METHODS.DEBIT_CARD) { @@ -220,14 +242,14 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod const makeDefaultPaymentMethod = useCallback(() => { const paymentCardList = fundList || {}; // Find the previous default payment method so we can revert if the MakeDefaultPaymentMethod command errors - const paymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList, paymentCardList, styles); + const paymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList || {}, paymentCardList, styles); - const previousPaymentMethod = _.find(paymentMethods, (method) => method.isDefault); + const previousPaymentMethod = _.find(paymentMethods, (method) => !!method.isDefault); const currentPaymentMethod = _.find(paymentMethods, (method) => method.methodID === paymentMethod.methodID); if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { - PaymentMethods.makeDefaultPaymentMethod(paymentMethod.selectedPaymentMethod.bankAccountID, null, previousPaymentMethod, currentPaymentMethod); + PaymentMethods.makeDefaultPaymentMethod(paymentMethod.selectedPaymentMethod.bankAccountID || null, null, previousPaymentMethod, currentPaymentMethod); } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { - PaymentMethods.makeDefaultPaymentMethod(null, paymentMethod.selectedPaymentMethod.fundID, previousPaymentMethod, currentPaymentMethod); + PaymentMethods.makeDefaultPaymentMethod(null, paymentMethod.selectedPaymentMethod.fundID || null, previousPaymentMethod, currentPaymentMethod); } }, [ paymentMethod.methodID, @@ -240,19 +262,19 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod ]); const deletePaymentMethod = useCallback(() => { - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { - BankAccounts.deletePaymentBankAccount(paymentMethod.selectedPaymentMethod.bankAccountID); - } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { - PaymentMethods.deletePaymentCard(paymentMethod.selectedPaymentMethod.fundID); + const bankAccountID = paymentMethod.selectedPaymentMethod.bankAccountID; + const fundID = paymentMethod.selectedPaymentMethod.fundID; + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && bankAccountID) { + BankAccounts.deletePaymentBankAccount(bankAccountID); + } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD && fundID) { + PaymentMethods.deletePaymentCard(fundID); } }, [paymentMethod.selectedPaymentMethod.bankAccountID, paymentMethod.selectedPaymentMethod.fundID, paymentMethod.selectedPaymentMethodType]); /** * Navigate to the appropriate page after completing the KYC flow, depending on what initiated it - * - * @param {String} source */ - const navigateToWalletOrTransferBalancePage = (source) => { + const navigateToWalletOrTransferBalancePage = (source: string) => { Navigation.navigate(source === CONST.KYC_WALL_SOURCE.ENABLE_WALLET ? ROUTES.SETTINGS_WALLET : ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE); }; @@ -306,9 +328,9 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod // We should reset selected payment method state values and close corresponding modals if the selected payment method is deleted let shouldResetPaymentMethodData = false; - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && _.isEmpty(bankAccountList[paymentMethod.methodID])) { + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && _.isEmpty(bankAccountList?.[paymentMethod.methodID])) { shouldResetPaymentMethodData = true; - } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD && _.isEmpty(fundList[paymentMethod.methodID])) { + } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD && _.isEmpty(fundList?.[paymentMethod.methodID])) { shouldResetPaymentMethodData = true; } if (shouldResetPaymentMethodData) { @@ -344,7 +366,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod style={styles.flex1} contentContainerStyle={styles.flex1} onClose={PaymentMethods.clearWalletError} - errors={userWallet.errors} + errors={userWallet?.errors} errorRowStyles={[styles.ph6]} > {hasWallet && ( @@ -363,7 +385,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod ) : ( navigateToWalletOrTransferBalancePage(source)} - onSelectPaymentMethod={(selectedPaymentMethod) => { + onSuccessfulKYC={(_iouPaymentType: string, source: string) => navigateToWalletOrTransferBalancePage(source)} + onSelectPaymentMethod={(selectedPaymentMethod: string) => { if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return; } @@ -388,7 +410,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod source={hasActivatedWallet ? CONST.KYC_WALL_SOURCE.TRANSFER_BALANCE : CONST.KYC_WALL_SOURCE.ENABLE_WALLET} shouldIncludeDebitCard={hasActivatedWallet} > - {(triggerKYCFlow, buttonRef) => { + {(triggerKYCFlow: (e: GestureResponderEvent | KeyboardEvent | undefined) => void, buttonRef: Ref) => { if (shouldShowLoadingSpinner) { return null; } @@ -463,7 +485,6 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod shouldEnableScroll={false} onPress={paymentMethodPressed} style={styles.mt5} - isAddPaymentMenuActive={shouldShowAddPaymentMenu} actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} @@ -480,7 +501,6 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod shouldShowAddPaymentMethodButton={false} shouldShowEmptyListMessage={false} onPress={paymentMethodPressed} - isAddPaymentMenuActive={shouldShowAddPaymentMenu} actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} @@ -502,7 +522,7 @@ function WalletPage({bankAccountList, cardList, fundList, isLoadingPaymentMethod anchorRef={paymentMethodButtonRef} > {!showConfirmDeleteModal && ( - + {isPopoverBottomMount && ( addPaymentMethodTypePressed(method)} + onItemSelected={(method: string) => addPaymentMethodTypePressed(method)} anchorRef={addPaymentMethodAnchorRef} /> ); } -WalletPage.propTypes = propTypes; -WalletPage.defaultProps = defaultProps; WalletPage.displayName = 'WalletPage'; -export default compose( - withNetwork(), - withOnyx({ - cardList: { - key: ONYXKEYS.CARD_LIST, - }, - walletTransfer: { - key: ONYXKEYS.WALLET_TRANSFER, - }, - userWallet: { - key: ONYXKEYS.USER_WALLET, - }, - bankAccountList: { - key: ONYXKEYS.BANK_ACCOUNT_LIST, - }, - fundList: { - key: ONYXKEYS.FUND_LIST, - }, - walletTerms: { - key: ONYXKEYS.WALLET_TERMS, - }, - isLoadingPaymentMethods: { - key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS, - }, - }), -)(WalletPage); +export default withOnyx({ + cardList: { + key: ONYXKEYS.CARD_LIST, + }, + walletTransfer: { + key: ONYXKEYS.WALLET_TRANSFER, + }, + userWallet: { + key: ONYXKEYS.USER_WALLET, + }, + bankAccountList: { + key: ONYXKEYS.BANK_ACCOUNT_LIST, + }, + fundList: { + key: ONYXKEYS.FUND_LIST, + }, + walletTerms: { + key: ONYXKEYS.WALLET_TERMS, + }, + isLoadingPaymentMethods: { + key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS, + }, +})(WalletPage); diff --git a/src/pages/settings/Wallet/WalletPage/index.native.js b/src/pages/settings/Wallet/WalletPage/index.native.tsx similarity index 100% rename from src/pages/settings/Wallet/WalletPage/index.native.js rename to src/pages/settings/Wallet/WalletPage/index.native.tsx diff --git a/src/pages/settings/Wallet/WalletPage/index.js b/src/pages/settings/Wallet/WalletPage/index.tsx similarity index 100% rename from src/pages/settings/Wallet/WalletPage/index.js rename to src/pages/settings/Wallet/WalletPage/index.tsx diff --git a/src/pages/settings/Wallet/WalletPage/types.ts b/src/pages/settings/Wallet/WalletPage/types.ts new file mode 100644 index 000000000000..731587f86f39 --- /dev/null +++ b/src/pages/settings/Wallet/WalletPage/types.ts @@ -0,0 +1,31 @@ +import {OnyxEntry} from 'react-native-onyx'; +import {BankAccountList, Beta, Card, CardList, Fund, FundList, Network, UserWallet, WalletTerms, WalletTransfer} from '@src/types/onyx'; + +type WalletPageOnyxProps = { + /** Wallet balance transfer props */ + walletTransfer: OnyxEntry; + + /** The user's wallet account */ + userWallet: OnyxEntry; + + /** List of bank accounts */ + bankAccountList: OnyxEntry; + + /** List of user's cards */ + fundList: OnyxEntry; + + /** Information about the user accepting the terms for payments */ + walletTerms: OnyxEntry; + + cardList: OnyxEntry; + + /** Are we loading payment methods? */ + isLoadingPaymentMethods: OnyxEntry; +}; + +type WalletPageProps = WalletPageOnyxProps & { + /** Listen for window resize event on web and desktop. */ + shouldListenForResize?: boolean; +}; + +export type {WalletPageOnyxProps, WalletPageProps}; diff --git a/src/pages/settings/Wallet/WalletPage/walletPagePropTypes.js b/src/pages/settings/Wallet/WalletPage/walletPagePropTypes.js deleted file mode 100644 index 23bdfe99b086..000000000000 --- a/src/pages/settings/Wallet/WalletPage/walletPagePropTypes.js +++ /dev/null @@ -1,52 +0,0 @@ -import PropTypes from 'prop-types'; -import bankAccountPropTypes from '@components/bankAccountPropTypes'; -import cardPropTypes from '@components/cardPropTypes'; -import networkPropTypes from '@components/networkPropTypes'; -import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes'; -import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes'; -import walletTransferPropTypes from '@pages/settings/Wallet/walletTransferPropTypes'; - -const propTypes = { - /** Wallet balance transfer props */ - walletTransfer: walletTransferPropTypes, - - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - - /** Are we loading payment methods? */ - isLoadingPaymentMethods: PropTypes.bool, - - /** Listen for window resize event on web and desktop. */ - shouldListenForResize: PropTypes.bool, - - /** The user's wallet account */ - userWallet: userWalletPropTypes, - - /** Information about the network */ - network: networkPropTypes.isRequired, - - /** List of bank accounts */ - bankAccountList: PropTypes.objectOf(bankAccountPropTypes), - - /** List of user's cards */ - fundList: PropTypes.objectOf(cardPropTypes), - - /** Information about the user accepting the terms for payments */ - walletTerms: walletTermsPropTypes, -}; - -const defaultProps = { - walletTransfer: { - shouldShowSuccess: false, - }, - betas: [], - isLoadingPaymentMethods: true, - shouldListenForResize: false, - userWallet: {}, - bankAccountList: {}, - cardList: {}, - fundList: null, - walletTerms: {}, -}; - -export {propTypes, defaultProps}; diff --git a/src/types/onyx/AccountData.ts b/src/types/onyx/AccountData.ts index 88511eec6864..124a006ff57c 100644 --- a/src/types/onyx/AccountData.ts +++ b/src/types/onyx/AccountData.ts @@ -51,6 +51,8 @@ type AccountData = { /** Any error message to show */ errors?: OnyxCommon.Errors; + + fundID?: number; }; export default AccountData; diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts index e3b025ff5a2f..68acd88aa120 100644 --- a/src/types/onyx/Card.ts +++ b/src/types/onyx/Card.ts @@ -33,5 +33,7 @@ type TCardDetails = { }; }; +type CardList = Record; + export default Card; -export type {TCardDetails}; +export type {TCardDetails, CardList}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 7bd9c321be5e..d881379f7e05 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -5,6 +5,7 @@ import type BankAccount from './BankAccount'; import type Beta from './Beta'; import type BlockedFromConcierge from './BlockedFromConcierge'; import type Card from './Card'; +import type {CardList} from './Card'; import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; @@ -74,6 +75,7 @@ export type { Beta, BlockedFromConcierge, Card, + CardList, Credentials, Currency, CustomStatusDraft, From dba03e1ecc55504615c99ea610e83d0052a0e73b Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 11 Jan 2024 15:19:06 +0700 Subject: [PATCH 02/16] fix type error --- src/components/AddPaymentMethodMenu.js | 12 +- src/components/KYCWall/index.js | 5 +- src/components/Modal/index.android.tsx | 3 +- src/components/Modal/index.ios.tsx | 3 +- src/components/Modal/index.tsx | 3 +- src/components/Modal/types.ts | 74 ++++++------ src/components/Popover/index.tsx | 12 +- src/components/Popover/types.ts | 13 +-- src/components/PopoverProvider/types.ts | 2 +- src/components/PopoverWithoutOverlay/types.ts | 2 +- src/libs/actions/PaymentMethods.ts | 8 +- .../settings/Wallet/PaymentMethodList.tsx | 92 +++++++-------- .../settings/Wallet/WalletEmptyState.tsx | 1 - .../Wallet/WalletPage/CardDetails.tsx | 10 +- .../settings/Wallet/WalletPage/WalletPage.tsx | 107 +++++++++--------- src/pages/settings/Wallet/WalletPage/types.ts | 4 +- 16 files changed, 166 insertions(+), 185 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index a936b0efdfa1..033fb8765b6f 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -1,19 +1,17 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import useLocalize from '@hooks/useLocalize'; -import compose from '@libs/compose'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import iouReportPropTypes from '@pages/iouReportPropTypes'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { withOnyx } from 'react-native-onyx'; +import _ from 'underscore'; import * as Expensicons from './Icon/Expensicons'; import PopoverMenu from './PopoverMenu'; import refPropTypes from './refPropTypes'; -import withWindowDimensions from './withWindowDimensions'; const propTypes = { /** Should the component be visible? */ diff --git a/src/components/KYCWall/index.js b/src/components/KYCWall/index.js index 87f1496a494a..e3a0d5e82cdc 100644 --- a/src/components/KYCWall/index.js +++ b/src/components/KYCWall/index.js @@ -8,8 +8,9 @@ function KYCWall({children, ...props}) { // eslint-disable-next-line react/jsx-props-no-spreading {...props} shouldListenForResize - children={children} - /> + > + {children} + ); } diff --git a/src/components/Modal/index.android.tsx b/src/components/Modal/index.android.tsx index 4d7ae128a114..86a1fd272185 100644 --- a/src/components/Modal/index.android.tsx +++ b/src/components/Modal/index.android.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {AppState} from 'react-native'; -import withWindowDimensions from '@components/withWindowDimensions'; import ComposerFocusManager from '@libs/ComposerFocusManager'; import BaseModal from './BaseModal'; import type BaseModalProps from './types'; @@ -28,4 +27,4 @@ function Modal({useNativeDriver = true, ...rest}: BaseModalProps) { } Modal.displayName = 'Modal'; -export default withWindowDimensions(Modal); +export default Modal; diff --git a/src/components/Modal/index.ios.tsx b/src/components/Modal/index.ios.tsx index cbe58a071d7d..b26ba6cd0f89 100644 --- a/src/components/Modal/index.ios.tsx +++ b/src/components/Modal/index.ios.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import withWindowDimensions from '@components/withWindowDimensions'; import BaseModal from './BaseModal'; import type BaseModalProps from './types'; @@ -15,4 +14,4 @@ function Modal({children, ...rest}: BaseModalProps) { } Modal.displayName = 'Modal'; -export default withWindowDimensions(Modal); +export default Modal; diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index 56f3c76a8879..71c0fe47ffca 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -1,5 +1,4 @@ import React, {useState} from 'react'; -import withWindowDimensions from '@components/withWindowDimensions'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import StatusBar from '@libs/StatusBar'; @@ -55,4 +54,4 @@ function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = ( } Modal.displayName = 'Modal'; -export default withWindowDimensions(Modal); +export default Modal; diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index 0fed37ffea8b..caba945cad30 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -1,7 +1,6 @@ import type {ViewStyle} from 'react-native'; import type {ModalProps} from 'react-native-modal'; import type {ValueOf} from 'type-fest'; -import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; import type CONST from '@src/CONST'; type PopoverAnchorPosition = { @@ -11,57 +10,56 @@ type PopoverAnchorPosition = { left?: number; }; -type BaseModalProps = WindowDimensionsProps & - Partial & { - /** Decides whether the modal should cover fullscreen. FullScreen modal has backdrop */ - fullscreen?: boolean; +type BaseModalProps = Partial & { + /** Decides whether the modal should cover fullscreen. FullScreen modal has backdrop */ + fullscreen?: boolean; - /** Should we close modal on outside click */ - shouldCloseOnOutsideClick?: boolean; + /** Should we close modal on outside click */ + shouldCloseOnOutsideClick?: boolean; - /** Should we announce the Modal visibility changes? */ - shouldSetModalVisibility?: boolean; + /** Should we announce the Modal visibility changes? */ + shouldSetModalVisibility?: boolean; - /** Callback method fired when the user requests to close the modal */ - onClose: (ref?: React.RefObject) => void; + /** Callback method fired when the user requests to close the modal */ + onClose: (ref?: React.RefObject) => void; - /** State that determines whether to display the modal or not */ - isVisible: boolean; + /** State that determines whether to display the modal or not */ + isVisible: boolean; - /** Callback method fired when the user requests to submit the modal content. */ - onSubmit?: () => void; + /** Callback method fired when the user requests to submit the modal content. */ + onSubmit?: () => void; - /** Callback method fired when the modal is hidden */ - onModalHide?: () => void; + /** Callback method fired when the modal is hidden */ + onModalHide?: () => void; - /** Callback method fired when the modal is shown */ - onModalShow?: () => void; + /** Callback method fired when the modal is shown */ + onModalShow?: () => void; - /** Style of modal to display */ - type?: ValueOf; + /** Style of modal to display */ + type?: ValueOf; - /** The anchor position of a popover modal. Has no effect on other modal types. */ - popoverAnchorPosition?: PopoverAnchorPosition; + /** The anchor position of a popover modal. Has no effect on other modal types. */ + popoverAnchorPosition?: PopoverAnchorPosition; - outerStyle?: ViewStyle; + outerStyle?: ViewStyle; - /** Whether the modal should go under the system statusbar */ - statusBarTranslucent?: boolean; + /** Whether the modal should go under the system statusbar */ + statusBarTranslucent?: boolean; - /** Whether the modal should avoid the keyboard */ - avoidKeyboard?: boolean; + /** Whether the modal should avoid the keyboard */ + avoidKeyboard?: boolean; - /** Modal container styles */ - innerContainerStyle?: ViewStyle; + /** Modal container styles */ + innerContainerStyle?: ViewStyle; - /** - * Whether the modal should hide its content while animating. On iOS, set to true - * if `useNativeDriver` is also true, to avoid flashes in the UI. - * - * See: https://github.com/react-native-modal/react-native-modal/pull/116 - * */ - hideModalContentWhileAnimating?: boolean; - }; + /** + * Whether the modal should hide its content while animating. On iOS, set to true + * if `useNativeDriver` is also true, to avoid flashes in the UI. + * + * See: https://github.com/react-native-modal/react-native-modal/pull/116 + * */ + hideModalContentWhileAnimating?: boolean; +}; export default BaseModalProps; export type {PopoverAnchorPosition}; diff --git a/src/components/Popover/index.tsx b/src/components/Popover/index.tsx index 762e79fab63c..e1cd18ba4767 100644 --- a/src/components/Popover/index.tsx +++ b/src/components/Popover/index.tsx @@ -3,32 +3,32 @@ import {createPortal} from 'react-dom'; import Modal from '@components/Modal'; import {PopoverContext} from '@components/PopoverProvider'; import PopoverWithoutOverlay from '@components/PopoverWithoutOverlay'; -import withWindowDimensions from '@components/withWindowDimensions'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; -import type {PopoverWithWindowDimensionsProps} from './types'; +import type {PopoverProps} from './types'; /* * This is a convenience wrapper around the Modal component for a responsive Popover. * On small screen widths, it uses BottomDocked modal type, and a Popover type on wide screen widths. */ -function Popover(props: PopoverWithWindowDimensionsProps) { +function Popover(props: PopoverProps) { const { isVisible, onClose, - isSmallScreenWidth, fullscreen, animationInTiming = CONST.ANIMATED_TRANSITION, onLayout, animationOutTiming, disableAnimation = true, - withoutOverlay, + withoutOverlay = false, anchorPosition = {}, anchorRef = () => {}, animationIn = 'fadeIn', animationOut = 'fadeOut', } = props; + const {isSmallScreenWidth} = useWindowDimensions(); const withoutOverlayRef = useRef(null); const {close, popover} = React.useContext(PopoverContext); @@ -106,4 +106,4 @@ function Popover(props: PopoverWithWindowDimensionsProps) { Popover.displayName = 'Popover'; -export default withWindowDimensions(Popover); +export default Popover; diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 3d1f95822e6a..551756ed706c 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -1,7 +1,6 @@ import type {ValueOf} from 'type-fest'; import type {PopoverAnchorPosition} from '@components/Modal/types'; import type BaseModalProps from '@components/Modal/types'; -import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; import type CONST from '@src/CONST'; type AnchorAlignment = { @@ -22,16 +21,16 @@ type PopoverProps = BaseModalProps & { anchorPosition?: PopoverAnchorPosition; /** The anchor alignment of the popover */ - anchorAlignment: AnchorAlignment; + anchorAlignment?: AnchorAlignment; /** The anchor ref of the popover */ - anchorRef: React.RefObject; + anchorRef?: React.RefObject; /** Whether disable the animations */ - disableAnimation: boolean; + disableAnimation?: boolean; /** Whether we don't want to show overlay */ - withoutOverlay: boolean; + withoutOverlay?: boolean; /** The dimensions of the popover */ popoverDimensions?: PopoverDimensions; @@ -46,6 +45,4 @@ type PopoverProps = BaseModalProps & { children: React.ReactNode; }; -type PopoverWithWindowDimensionsProps = PopoverProps & WindowDimensionsProps; - -export type {PopoverProps, PopoverWithWindowDimensionsProps, AnchorAlignment}; +export type {PopoverProps, AnchorAlignment}; diff --git a/src/components/PopoverProvider/types.ts b/src/components/PopoverProvider/types.ts index ffd0087cd5ff..acc01fd74427 100644 --- a/src/components/PopoverProvider/types.ts +++ b/src/components/PopoverProvider/types.ts @@ -12,7 +12,7 @@ type PopoverContextValue = { type AnchorRef = { ref: React.RefObject; close: (anchorRef?: React.RefObject) => void; - anchorRef: React.RefObject; + anchorRef?: React.RefObject; onOpenCallback?: () => void; onCloseCallback?: () => void; }; diff --git a/src/components/PopoverWithoutOverlay/types.ts b/src/components/PopoverWithoutOverlay/types.ts index ff4f73fd4114..fd42bf7d8e42 100644 --- a/src/components/PopoverWithoutOverlay/types.ts +++ b/src/components/PopoverWithoutOverlay/types.ts @@ -13,7 +13,7 @@ type PopoverWithoutOverlayProps = ChildrenProps & }; /** The anchor ref of the popover */ - anchorRef: React.RefObject; + anchorRef?: React.RefObject; /** A react-native-animatable animation timing for the modal display animation */ animationInTiming?: number; diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index 6614d3516253..c152a968f030 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -83,7 +83,7 @@ function getMakeDefaultPaymentOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.USER_WALLET, value: { - walletLinkedAccountID: bankAccountID || fundID, + walletLinkedAccountID: bankAccountID ?? fundID, walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, // Only clear the error if this is optimistic data. If this is failure data, we do not want to clear the error that came from the server. errors: null, @@ -93,7 +93,7 @@ function getMakeDefaultPaymentOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.USER_WALLET, value: { - walletLinkedAccountID: bankAccountID || fundID, + walletLinkedAccountID: bankAccountID ?? fundID, walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, }, }, @@ -320,7 +320,7 @@ type PaymentListKey = typeof ONYXKEYS.BANK_ACCOUNT_LIST | typeof ONYXKEYS.FUND_L * @param paymentListKey The onyx key for the provided payment method * @param paymentMethodID */ -function clearDeletePaymentMethodError(paymentListKey: PaymentListKey, paymentMethodID: string) { +function clearDeletePaymentMethodError(paymentListKey: PaymentListKey, paymentMethodID: number) { Onyx.merge(paymentListKey, { [paymentMethodID]: { pendingAction: null, @@ -334,7 +334,7 @@ function clearDeletePaymentMethodError(paymentListKey: PaymentListKey, paymentMe * @param paymentListKey The onyx key for the provided payment method * @param paymentMethodID */ -function clearAddPaymentMethodError(paymentListKey: PaymentListKey, paymentMethodID: string) { +function clearAddPaymentMethodError(paymentListKey: PaymentListKey, paymentMethodID: number) { Onyx.merge(paymentListKey, { [paymentMethodID]: null, }); diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 9cceaa60c10c..e7c6ba37ed9f 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -1,17 +1,7 @@ -import {FlashList} from '@shopify/flash-list'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {ReactElement, Ref, useCallback, useMemo} from 'react'; -import {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; -import {OnyxEntry, withOnyx} from 'react-native-onyx'; -import {TupleToUnion, ValueOf} from 'type-fest'; -import _ from 'underscore'; -import bankAccountPropTypes from '@components/bankAccountPropTypes'; import Button from '@components/Button'; -import cardPropTypes from '@components/cardPropTypes'; import FormAlertWrapper from '@components/FormAlertWrapper'; import getBankIcon from '@components/Icon/BankIcons'; -import {BankName} from '@components/Icon/BankIconsUtils'; +import type { BankName } from '@components/Icon/BankIconsUtils'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -24,17 +14,26 @@ import * as CardUtils from '@libs/CardUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import * as PaymentUtils from '@libs/PaymentUtils'; -import stylePropTypes from '@styles/stylePropTypes'; -import variables from '@styles/variables'; -import * as PaymentMethods from '@userActions/PaymentMethods'; +import { FlashList } from '@shopify/flash-list'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {AccountData, BankAccountList, Card, CardList, FundList, UserWallet} from '@src/types/onyx'; -import PaymentMethod from '@src/types/onyx/PaymentMethod'; +import type { AccountData, BankAccountList, CardList, FundList } from '@src/types/onyx'; +import type PaymentMethod from '@src/types/onyx/PaymentMethod'; +import type IconAsset from '@src/types/utils/IconAsset'; +import variables from '@styles/variables'; +import * as PaymentMethods from '@userActions/PaymentMethods'; +import type { ReactElement, Ref } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import type { GestureResponderEvent, StyleProp, ViewStyle } from 'react-native'; +import { View } from 'react-native'; +import type { OnyxEntry } from 'react-native-onyx'; +import { withOnyx } from 'react-native-onyx'; +import type { TupleToUnion, ValueOf } from 'type-fest'; +import _ from 'lodash'; +import type { RenderSuggestionMenuItemProps } from '@components/AutoCompleteSuggestions/types'; const FILTER_TYPES = [CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, ''] as const; -const ACTION_PAYMENT_METHOD_TYPES = [...Object.values(CONST.PAYMENT_METHODS), ''] as const; type PaymentMethodListOnyxProps = { /** List of bank accounts */ @@ -48,14 +47,11 @@ type PaymentMethodListOnyxProps = { /** Are we loading payment methods? */ isLoadingPaymentMethods: OnyxEntry; - - /** User wallet props */ - userWallet: OnyxEntry; }; type PaymentMethodListProps = PaymentMethodListOnyxProps & { /** Type of active/highlighted payment method */ - actionPaymentMethodType?: TupleToUnion; + actionPaymentMethodType?: string; /** ID of active/highlighted payment method */ activePaymentMethodID?: string | number; @@ -96,7 +92,14 @@ type PaymentMethodListProps = PaymentMethodListOnyxProps & { shouldShowEmptyListMessage?: boolean; /** What to do when a menu item is pressed */ - onPress: (event?: GestureResponderEvent | KeyboardEvent, accountType?: string, accountData?: AccountData, isDefault?: boolean, methodID?: number) => void | Promise; + onPress: ( + event?: GestureResponderEvent | KeyboardEvent, + accountType?: string, + accountData?: AccountData, + icon?: IconAsset, + isDefault?: boolean, + methodID?: number, + ) => void; }; type PaymentMethodItem = PaymentMethod & { @@ -111,7 +114,7 @@ type PaymentMethodItem = PaymentMethod & { function dismissError(item: PaymentMethod) { const isBankAccount = item.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT; const paymentList = isBankAccount ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST; - const paymentID = isBankAccount ? lodashGet(item, ['accountData', 'bankAccountID'], '') : lodashGet(item, ['accountData', 'fundID'], ''); + const paymentID = isBankAccount ? item.accountData?.bankAccountID ?? '' : item.accountData?.fundID ?? ''; if (!paymentID) { Log.info('Unable to clear payment method error: ', undefined, item); @@ -136,9 +139,8 @@ function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefau return false; } - const defaultablePaymentMethodCount = _.filter( - filteredPaymentMethods, - (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, + const defaultablePaymentMethodCount = filteredPaymentMethods.filter( + (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ?? method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, ).length; return defaultablePaymentMethodCount > 1; } @@ -148,7 +150,7 @@ function isPaymentMethodActive(actionPaymentMethodType: string, activePaymentMet } function keyExtractor(item: PaymentMethod) { - return item.key || ''; + return item.key ?? ''; } function PaymentMethodList({ @@ -181,13 +183,13 @@ function PaymentMethodList({ if (shouldShowAssignedCards) { const assignedCards = _.chain(cardList) // Filter by physical, active cards associated with a domain - .filter((card) => !card.isVirtual && card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0)) + .filter((card) => !card.isVirtual && !!card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0)) .sortBy((card) => !CardUtils.isExpensifyCard(card.cardID)) .value(); - const numberPhysicalExpensifyCards = _.filter(assignedCards, (card) => CardUtils.isExpensifyCard(card.cardID)).length; + const numberPhysicalExpensifyCards = assignedCards.filter((card) => CardUtils.isExpensifyCard(card.cardID)).length; - return _.map(assignedCards, (card) => { + return assignedCards.map((card) => { const isExpensifyCard = CardUtils.isExpensifyCard(card.cardID); const icon = getBankIcon({bankName: card.bank as BankName, isCard: true, styles}); @@ -202,34 +204,33 @@ function PaymentMethodList({ interactive: isExpensifyCard, canDismissError: isExpensifyCard, errors: card.errors, - brickRoadIndicator: card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN || card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL ? 'error' : null, + brickRoadIndicator: card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN ?? card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL ? 'error' : null, ...icon, }; }); } - const paymentCardList = fundList || {}; + const paymentCardList = fundList ?? {}; // 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); + const filteredCardList = Object.values(paymentCardList).filter((card) => !!card.accountData?.additionalData?.isP2PDebitCard); let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, filteredCardList, styles); if (!_.isEmpty(filterType)) { - combinedPaymentMethods = _.filter(combinedPaymentMethods, (paymentMethod) => paymentMethod.accountType === filterType); + combinedPaymentMethods = combinedPaymentMethods.filter((paymentMethod) => paymentMethod.accountType === filterType); } if (!isOffline) { - combinedPaymentMethods = _.filter( - combinedPaymentMethods, - (paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(paymentMethod.errors), + combinedPaymentMethods = combinedPaymentMethods.filter( + (paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ?? !_.isEmpty(paymentMethod.errors), ); } - combinedPaymentMethods = _.map(combinedPaymentMethods, (paymentMethod) => { + combinedPaymentMethods = combinedPaymentMethods.map((paymentMethod) => { const isMethodActive = isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod); return { ...paymentMethod, - onPress: (e: GestureResponderEvent) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.isDefault, paymentMethod.methodID), + onPress: (e: GestureResponderEvent) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.icon, paymentMethod.isDefault, paymentMethod.methodID), wrapperStyle: isMethodActive ? [StyleUtils.getButtonBackgroundColorStyle(CONST.BUTTON_STATES.PRESSED)] : null, disabled: paymentMethod.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, }; @@ -240,8 +241,6 @@ function PaymentMethodList({ /** * Render placeholder when there are no payments methods - * - * @return {React.Component} */ const renderListEmptyComponent = () => {translate('paymentMethodList.addFirstPaymentMethod')}; @@ -263,7 +262,7 @@ function PaymentMethodList({ * Create a menuItem for each passed paymentMethod */ const renderItem = useCallback( - ({item}: {item: PaymentMethodItem}) => ( + ({item}: RenderSuggestionMenuItemProps) => ( dismissError(item)} pendingAction={item.pendingAction} @@ -278,8 +277,8 @@ function PaymentMethodList({ icon={item.icon} disabled={item.disabled} displayInDefaultIconColor - iconHeight={item.iconHeight || item.iconSize} - iconWidth={item.iconWidth || item.iconSize} + iconHeight={item.iconHeight ?? item.iconSize} + iconWidth={item.iconWidth ?? item.iconSize} iconStyles={item.iconStyles} badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : undefined} wrapperStyle={styles.paymentMethod} @@ -317,7 +316,7 @@ function PaymentMethodList({ text={translate('paymentMethodList.addPaymentMethod')} icon={Expensicons.CreditCard} onPress={onPress} - isDisabled={isLoadingPaymentMethods || isFormOffline} + isDisabled={isLoadingPaymentMethods ?? isFormOffline} style={[styles.mh4, styles.buttonCTA]} iconStyles={[styles.buttonCTAIcon]} key="addPaymentMethodButton" @@ -348,7 +347,4 @@ export default withOnyx({ isLoadingPaymentMethods: { key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS, }, - userWallet: { - key: ONYXKEYS.USER_WALLET, - }, })(PaymentMethodList); diff --git a/src/pages/settings/Wallet/WalletEmptyState.tsx b/src/pages/settings/Wallet/WalletEmptyState.tsx index 4ef9488368cb..4060a3695b92 100644 --- a/src/pages/settings/Wallet/WalletEmptyState.tsx +++ b/src/pages/settings/Wallet/WalletEmptyState.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import Button from '@components/Button'; import FeatureList from '@components/FeatureList'; diff --git a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx index 09a7d937053b..a21172da2832 100644 --- a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx +++ b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx @@ -1,7 +1,7 @@ -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import {OnyxEntry, withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import { withOnyx} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayToggle'; @@ -14,7 +14,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {PrivatePersonalDetails} from '@src/types/onyx'; +import type {PrivatePersonalDetails} from '@src/types/onyx'; const defaultPrivatePersonalDetails = { address: { @@ -46,7 +46,7 @@ type CardDetailsProps = CardDetailsOnyxProps & { domain: string; }; -function CardDetails({pan = '', expiration = '', cvv = '', privatePersonalDetails = defaultPrivatePersonalDetails, domain}: CardDetailsProps) { +function CardDetails({pan = '', expiration = '', cvv = '', privatePersonalDetails, domain}: CardDetailsProps) { const styles = useThemeStyles(); usePrivatePersonalDetails(); const {translate} = useLocalize(); @@ -87,7 +87,7 @@ function CardDetails({pan = '', expiration = '', cvv = '', privatePersonalDetail /> { // In order to prevent a loop, only update state of the spinner if there is a change - const showLoadingSpinner = isLoadingPaymentMethods || false; + const showLoadingSpinner = isLoadingPaymentMethods ?? false; if (showLoadingSpinner !== shouldShowLoadingSpinner) { setShouldShowLoadingSpinner(!!isLoadingPaymentMethods && !network.isOffline); } @@ -107,8 +103,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi /** * Set position of the payment menu - * - * @param {Object} position */ const setMenuPosition = useCallback(() => { if (!paymentMethodButtonRef.current) { @@ -150,14 +144,15 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi /** * Display the delete/default menu, or the add payment method menu - * - * @param {Object} nativeEvent - * @param {String} accountType - * @param {String} account - * @param {Boolean} isDefault - * @param {String|Number} methodID */ - const paymentMethodPressed = (nativeEvent?: GestureResponderEvent | KeyboardEvent, accountType?: string, account?: AccountData, isDefault?: boolean, methodID?: string | number) => { + const paymentMethodPressed = ( + nativeEvent?: GestureResponderEvent | KeyboardEvent, + accountType?: string, + account?: AccountData, + icon?: IconAsset, + isDefault?: boolean, + methodID?: string | number, + ) => { if (shouldShowAddPaymentMenu) { setShouldShowAddPaymentMenu(false); return; @@ -171,27 +166,27 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi // The delete/default menu if (accountType) { - let formattedSelectedPaymentMethod = { + let formattedSelectedPaymentMethod: FormattedSelectedPaymentMethod = { title: '', }; if (accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { formattedSelectedPaymentMethod = { title: account?.addressName ?? '', - icon: account?.icon, + icon, description: PaymentUtils.getPaymentMethodDescription(accountType, account), type: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, }; } else if (accountType === CONST.PAYMENT_METHODS.DEBIT_CARD) { formattedSelectedPaymentMethod = { title: account?.addressName ?? '', - icon: account?.icon, + icon, description: PaymentUtils.getPaymentMethodDescription(accountType, account), type: CONST.PAYMENT_METHODS.DEBIT_CARD, }; } setPaymentMethod({ isSelectedPaymentMethodDefault: !!isDefault, - selectedPaymentMethod: account || {}, + selectedPaymentMethod: account ?? {}, selectedPaymentMethodType: accountType, formattedSelectedPaymentMethod, methodID: methodID ?? '', @@ -222,7 +217,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi return; } - if (paymentType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || paymentType === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { + if (paymentType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ?? paymentType === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { BankAccounts.openPersonalBankAccountSetupView(); return; } @@ -232,7 +227,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi /** * Hide the default / delete modal - * @param {boolean} shouldClearSelectedData - Clear selected payment method data if true */ const hideDefaultDeleteMenu = useCallback(() => { setShouldShowDefaultDeleteMenu(false); @@ -240,16 +234,16 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi }, [setShouldShowDefaultDeleteMenu, setShowConfirmDeleteModal]); const makeDefaultPaymentMethod = useCallback(() => { - const paymentCardList = fundList || {}; + const paymentCardList = fundList ?? {}; // Find the previous default payment method so we can revert if the MakeDefaultPaymentMethod command errors - const paymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList || {}, paymentCardList, styles); + const paymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, paymentCardList, styles); - const previousPaymentMethod = _.find(paymentMethods, (method) => !!method.isDefault); - const currentPaymentMethod = _.find(paymentMethods, (method) => method.methodID === paymentMethod.methodID); + const previousPaymentMethod = paymentMethods.find((method) => !!method.isDefault); + const currentPaymentMethod = paymentMethods.find((method) => method.methodID === paymentMethod.methodID); if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { - PaymentMethods.makeDefaultPaymentMethod(paymentMethod.selectedPaymentMethod.bankAccountID || null, null, previousPaymentMethod, currentPaymentMethod); + PaymentMethods.makeDefaultPaymentMethod(paymentMethod.selectedPaymentMethod.bankAccountID ?? null, null, previousPaymentMethod, currentPaymentMethod); } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { - PaymentMethods.makeDefaultPaymentMethod(null, paymentMethod.selectedPaymentMethod.fundID || null, previousPaymentMethod, currentPaymentMethod); + PaymentMethods.makeDefaultPaymentMethod(null, paymentMethod.selectedPaymentMethod.fundID ?? null, previousPaymentMethod, currentPaymentMethod); } }, [ paymentMethod.methodID, @@ -346,7 +340,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi !(paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && paymentMethod.selectedPaymentMethod.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS); // Determines whether or not the modal popup is mounted from the bottom of the screen instead of the side mount on Web or Desktop screens - const isPopoverBottomMount = anchorPosition.anchorPositionTop === 0 || isSmallScreenWidth; + const isPopoverBottomMount = anchorPosition.anchorPositionTop === 0 ?? isSmallScreenWidth; const alertTextStyle = [styles.inlineSystemMessage, styles.flexShrink1]; const alertViewStyle = [styles.flexRow, styles.alignItemsCenter, styles.w100, styles.ph5]; @@ -395,9 +389,10 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi )} navigateToWalletOrTransferBalancePage(source)} onSelectPaymentMethod={(selectedPaymentMethod: string) => { - if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { + if (hasActivatedWallet ?? selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return; } // To allow upgrading to a gold wallet, continue with the KYC flow after adding a bank account @@ -488,7 +483,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} + onListContentSizeChange={shouldShowAddPaymentMenu ?? shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} /> ) : null} @@ -504,7 +499,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} + onListContentSizeChange={shouldShowAddPaymentMenu ?? shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} shouldEnableScroll={false} style={styles.mt5} /> @@ -525,7 +520,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi {isPopoverBottomMount && ( Date: Thu, 11 Jan 2024 15:24:39 +0700 Subject: [PATCH 03/16] resolve conflict --- src/pages/settings/Wallet/PaymentMethodList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index f318b77f8a0a..71c995363666 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -296,7 +296,7 @@ function PaymentMethodList({ return ( <> - + Date: Thu, 11 Jan 2024 15:29:21 +0700 Subject: [PATCH 04/16] lint --- src/components/AddPaymentMethodMenu.js | 10 ++--- .../settings/Wallet/PaymentMethodList.tsx | 39 ++++++++----------- .../Wallet/WalletPage/CardDetails.tsx | 2 +- .../settings/Wallet/WalletPage/WalletPage.tsx | 28 ++++++------- 4 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 033fb8765b6f..803b7f2cdabe 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -1,14 +1,14 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import useLocalize from '@hooks/useLocalize'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import iouReportPropTypes from '@pages/iouReportPropTypes'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { withOnyx } from 'react-native-onyx'; -import _ from 'underscore'; import * as Expensicons from './Icon/Expensicons'; import PopoverMenu from './PopoverMenu'; import refPropTypes from './refPropTypes'; diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 71c995363666..c8dcee62988e 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -1,7 +1,17 @@ +import {FlashList} from '@shopify/flash-list'; +import _ from 'lodash'; +import type {ReactElement, Ref} from 'react'; +import React, {useCallback, useMemo} from 'react'; +import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import type {TupleToUnion, ValueOf} from 'type-fest'; +import type {RenderSuggestionMenuItemProps} from '@components/AutoCompleteSuggestions/types'; import Button from '@components/Button'; import FormAlertWrapper from '@components/FormAlertWrapper'; import getBankIcon from '@components/Icon/BankIcons'; -import type { BankName } from '@components/Icon/BankIconsUtils'; +import type {BankName} from '@components/Icon/BankIconsUtils'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -14,24 +24,14 @@ import * as CardUtils from '@libs/CardUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import * as PaymentUtils from '@libs/PaymentUtils'; -import { FlashList } from '@shopify/flash-list'; +import variables from '@styles/variables'; +import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type { AccountData, BankAccountList, CardList, FundList } from '@src/types/onyx'; +import type {AccountData, BankAccountList, CardList, FundList} from '@src/types/onyx'; import type PaymentMethod from '@src/types/onyx/PaymentMethod'; import type IconAsset from '@src/types/utils/IconAsset'; -import variables from '@styles/variables'; -import * as PaymentMethods from '@userActions/PaymentMethods'; -import type { ReactElement, Ref } from 'react'; -import React, { useCallback, useMemo } from 'react'; -import type { GestureResponderEvent, StyleProp, ViewStyle } from 'react-native'; -import { View } from 'react-native'; -import type { OnyxEntry } from 'react-native-onyx'; -import { withOnyx } from 'react-native-onyx'; -import type { TupleToUnion, ValueOf } from 'type-fest'; -import _ from 'lodash'; -import type { RenderSuggestionMenuItemProps } from '@components/AutoCompleteSuggestions/types'; const FILTER_TYPES = [CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, ''] as const; @@ -92,14 +92,7 @@ type PaymentMethodListProps = PaymentMethodListOnyxProps & { shouldShowEmptyListMessage?: boolean; /** What to do when a menu item is pressed */ - onPress: ( - event?: GestureResponderEvent | KeyboardEvent, - accountType?: string, - accountData?: AccountData, - icon?: IconAsset, - isDefault?: boolean, - methodID?: number, - ) => void; + onPress: (event?: GestureResponderEvent | KeyboardEvent, accountType?: string, accountData?: AccountData, icon?: IconAsset, isDefault?: boolean, methodID?: number) => void; }; type PaymentMethodItem = PaymentMethod & { @@ -296,7 +289,7 @@ function PaymentMethodList({ return ( <> - + { // In order to prevent a loop, only update state of the spinner if there is a change From cb70663a543eaee30f6f0a0302e740b8f5a70d5f Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 15 Jan 2024 16:51:24 +0700 Subject: [PATCH 05/16] change ?? to || --- src/libs/actions/PaymentMethods.ts | 6 +++-- .../settings/Wallet/PaymentMethodList.tsx | 18 ++++++++++----- .../settings/Wallet/WalletEmptyState.tsx | 3 +++ .../Wallet/WalletPage/CardDetails.tsx | 3 ++- .../settings/Wallet/WalletPage/WalletPage.tsx | 23 +++++++++++-------- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index c152a968f030..24899087c46d 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -83,7 +83,8 @@ function getMakeDefaultPaymentOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.USER_WALLET, value: { - walletLinkedAccountID: bankAccountID ?? fundID, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + walletLinkedAccountID: bankAccountID || fundID, walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, // Only clear the error if this is optimistic data. If this is failure data, we do not want to clear the error that came from the server. errors: null, @@ -93,7 +94,8 @@ function getMakeDefaultPaymentOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.USER_WALLET, value: { - walletLinkedAccountID: bankAccountID ?? fundID, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + walletLinkedAccountID: bankAccountID || fundID, walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, }, }, diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index c8dcee62988e..db04bfb9f183 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -133,7 +133,8 @@ function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefau } const defaultablePaymentMethodCount = filteredPaymentMethods.filter( - (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ?? method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, ).length; return defaultablePaymentMethodCount > 1; } @@ -197,7 +198,8 @@ function PaymentMethodList({ interactive: isExpensifyCard, canDismissError: isExpensifyCard, errors: card.errors, - brickRoadIndicator: card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN ?? card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL ? 'error' : null, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + brickRoadIndicator: card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN || card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL ? 'error' : null, ...icon, }; }); @@ -215,7 +217,8 @@ function PaymentMethodList({ if (!isOffline) { combinedPaymentMethods = combinedPaymentMethods.filter( - (paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ?? !_.isEmpty(paymentMethod.errors), + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + (paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(paymentMethod.errors), ); } @@ -270,8 +273,10 @@ function PaymentMethodList({ icon={item.icon} disabled={item.disabled} displayInDefaultIconColor - iconHeight={item.iconHeight ?? item.iconSize} - iconWidth={item.iconWidth ?? item.iconSize} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + iconHeight={item.iconHeight || item.iconSize} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + iconWidth={item.iconWidth || item.iconSize} iconStyles={item.iconStyles} badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : undefined} wrapperStyle={styles.paymentMethod} @@ -309,7 +314,8 @@ function PaymentMethodList({ text={translate('paymentMethodList.addPaymentMethod')} icon={Expensicons.CreditCard} onPress={onPress} - isDisabled={isLoadingPaymentMethods ?? isFormOffline} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + isDisabled={isLoadingPaymentMethods || isFormOffline} style={[styles.mh4, styles.buttonCTA]} iconStyles={[styles.buttonCTAIcon]} key="addPaymentMethodButton" diff --git a/src/pages/settings/Wallet/WalletEmptyState.tsx b/src/pages/settings/Wallet/WalletEmptyState.tsx index 4060a3695b92..bfec7fa6314b 100644 --- a/src/pages/settings/Wallet/WalletEmptyState.tsx +++ b/src/pages/settings/Wallet/WalletEmptyState.tsx @@ -11,6 +11,7 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; type WalletEmptyStateProps = { + /** The function that is called when a menu item is pressed */ onAddPaymentMethod: () => void; }; @@ -56,4 +57,6 @@ function WalletEmptyState({onAddPaymentMethod}: WalletEmptyStateProps) { ); } +WalletEmptyState.displayName = 'WalletEmptyState'; + export default WalletEmptyState; diff --git a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx index 2732e817ae47..ce2dbc6b2cb5 100644 --- a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx +++ b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx @@ -87,7 +87,8 @@ function CardDetails({pan = '', expiration = '', cvv = '', privatePersonalDetail /> navigateToWalletOrTransferBalancePage(source)} onSelectPaymentMethod={(selectedPaymentMethod: string) => { - if (hasActivatedWallet ?? selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return; } // To allow upgrading to a gold wallet, continue with the KYC flow after adding a bank account @@ -483,7 +486,8 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - onListContentSizeChange={shouldShowAddPaymentMenu ?? shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} /> ) : null} @@ -499,7 +503,8 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - onListContentSizeChange={shouldShowAddPaymentMenu ?? shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} shouldEnableScroll={false} style={styles.mt5} /> @@ -520,7 +525,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi {isPopoverBottomMount && ( Date: Fri, 19 Jan 2024 16:02:16 +0700 Subject: [PATCH 06/16] clean code --- src/pages/settings/Wallet/PaymentMethodList.tsx | 1 + src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index db04bfb9f183..48f6e1b671f4 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -79,6 +79,7 @@ type PaymentMethodListProps = PaymentMethodListOnyxProps & { /** Type to filter the payment Method list */ filterType?: TupleToUnion; + /** Whether the add bank account button should be shown on the list */ shouldShowAddBankAccount?: boolean; diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 0a24e7da9d81..230ad920171d 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -13,6 +13,7 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import KYCWall from '@components/KYCWall'; +import {Source, TransferMethod} from '@components/KYCWall/types'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Popover from '@components/Popover'; @@ -38,7 +39,6 @@ import ROUTES from '@src/ROUTES'; import type {AccountData} from '@src/types/onyx'; import type IconAsset from '@src/types/utils/IconAsset'; import type {WalletPageOnyxProps, WalletPageProps} from './types'; -import { Source, TransferMethod } from '@components/KYCWall/types'; type FormattedSelectedPaymentMethod = { title: string; @@ -408,7 +408,10 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi source={hasActivatedWallet ? CONST.KYC_WALL_SOURCE.TRANSFER_BALANCE : CONST.KYC_WALL_SOURCE.ENABLE_WALLET} shouldIncludeDebitCard={hasActivatedWallet} > - {(triggerKYCFlow: (event: SyntheticEvent, iouPaymentType: TransferMethod) => void, buttonRef: ForwardedRef) => { + {( + triggerKYCFlow: (event: SyntheticEvent, iouPaymentType: TransferMethod) => void, + buttonRef: ForwardedRef, + ) => { if (shouldShowLoadingSpinner) { return null; } From 5f6ee9c528d133f78b5e50fdc2b2c13d9862d045 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 22 Jan 2024 16:26:12 +0700 Subject: [PATCH 07/16] change BaseKYCWall type --- src/components/KYCWall/BaseKYCWall.tsx | 5 +++-- src/components/KYCWall/types.ts | 6 +++--- src/components/Popover/types.ts | 2 +- src/pages/settings/Wallet/PaymentMethodList.tsx | 2 +- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 10 +++++----- src/types/onyx/WalletTerms.ts | 5 ++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 04c8397bc33b..15f9b295325e 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -2,6 +2,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import type {SyntheticEvent} from 'react'; import {Dimensions} from 'react-native'; import type {EmitterSubscription, NativeTouchEvent} from 'react-native'; +import type {GestureResponderEvent} from 'react-native-modal'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; @@ -146,7 +147,7 @@ function KYCWall({ * */ const continueAction = useCallback( - (event?: SyntheticEvent, iouPaymentType?: TransferMethod) => { + (event?: GestureResponderEvent | KeyboardEvent | SyntheticEvent, iouPaymentType?: TransferMethod) => { const currentSource = walletTerms?.source ?? source; /** @@ -161,7 +162,7 @@ function KYCWall({ } // Use event target as fallback if anchorRef is null for safety - const targetElement = anchorRef.current ?? (event?.nativeEvent.target as HTMLDivElement); + const targetElement = anchorRef.current ?? ((event as SyntheticEvent)?.nativeEvent.target as HTMLDivElement); transferBalanceButtonRef.current = targetElement; diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index 8a654cfc25d8..68374834e254 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -1,5 +1,5 @@ -import type {ForwardedRef, SyntheticEvent} from 'react'; -import type {NativeTouchEvent} from 'react-native'; +import type {ForwardedRef} from 'react'; +import type {GestureResponderEvent} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; @@ -67,7 +67,7 @@ type KYCWallProps = { onSuccessfulKYC: (currentSource?: Source, iouPaymentType?: TransferMethod) => void; /** Children to build the KYC */ - children: (continueAction: (event: SyntheticEvent, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; + children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; }; export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect, Source}; diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index bdc5ae493771..7a8b8d6a7f1f 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -34,7 +34,7 @@ type PopoverProps = BaseModalProps & disableAnimation?: boolean; /** Whether we don't want to show overlay */ - withoutOverlay: boolean; + withoutOverlay?: boolean; /** The dimensions of the popover */ popoverDimensions?: PopoverDimensions; diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 48f6e1b671f4..c1fb1bbd8253 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -128,7 +128,7 @@ function dismissError(item: PaymentMethod) { } } -function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefault = false) { +function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefault = false): boolean { if (!isDefault) { return false; } diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 230ad920171d..d1823beddef4 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -1,7 +1,7 @@ import _ from 'lodash'; -import type {ForwardedRef, Ref, RefObject, SyntheticEvent} from 'react'; +import type {ForwardedRef, RefObject} from 'react'; import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; -import type {GestureResponderEvent, NativeTouchEvent} from 'react-native'; +import type {GestureResponderEvent} from 'react-native'; import {ActivityIndicator, Dimensions, ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; @@ -13,7 +13,7 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import KYCWall from '@components/KYCWall'; -import {Source, TransferMethod} from '@components/KYCWall/types'; +import type {Source, TransferMethod} from '@components/KYCWall/types'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Popover from '@components/Popover'; @@ -409,7 +409,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi shouldIncludeDebitCard={hasActivatedWallet} > {( - triggerKYCFlow: (event: SyntheticEvent, iouPaymentType: TransferMethod) => void, + triggerKYCFlow: (event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: TransferMethod) => void, buttonRef: ForwardedRef, ) => { if (shouldShowLoadingSpinner) { @@ -522,7 +522,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi top: anchorPosition.anchorPositionTop, right: anchorPosition.anchorPositionRight, }} - anchorRef={paymentMethodButtonRef} + anchorRef={paymentMethodButtonRef as RefObject} > {!showConfirmDeleteModal && ( diff --git a/src/types/onyx/WalletTerms.ts b/src/types/onyx/WalletTerms.ts index f0563310859a..c2653cae0f97 100644 --- a/src/types/onyx/WalletTerms.ts +++ b/src/types/onyx/WalletTerms.ts @@ -1,5 +1,4 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; +import type {Source} from '@components/KYCWall/types'; import type * as OnyxCommon from './OnyxCommon'; type WalletTerms = { @@ -10,7 +9,7 @@ type WalletTerms = { chatReportID?: string; /** The source that triggered the KYC wall */ - source?: ValueOf; + source?: Source; /** Loading state to provide feedback when we are waiting for a request to finish */ isLoading?: boolean; From d700d8db166245a5057f8d935dafa8606badbc35 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 24 Jan 2024 17:13:57 +0700 Subject: [PATCH 08/16] resolve conflict --- src/components/KYCWall/types.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index 2dc12b32ead4..dc038e998694 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -67,11 +67,7 @@ type KYCWallProps = { onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; /** Children to build the KYC */ -<<<<<<< HEAD - children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; -======= children: (continueAction: (event: GestureResponderEvent | KeyboardEvent | undefined, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; ->>>>>>> main }; export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect, Source}; From 7deab6a55225f700aede985b0edb3532add49664 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 24 Jan 2024 17:41:13 +0700 Subject: [PATCH 09/16] clean code --- src/CONST.ts | 7 ++++--- src/components/KYCWall/types.ts | 2 +- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 264c10b79921..7e5efb2a07a8 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -37,6 +37,9 @@ const keyInputRightArrow = KeyCommand?.constants?.keyInputRightArrow ?? 'keyInpu // describes if a shortcut key can cause navigation const KEYBOARD_SHORTCUT_NAVIGATION_TYPE = 'NAVIGATION_SHORTCUT'; +// Explicit type annotation is required +const cardActiveStates: number[] = [2, 3, 4, 7] + const CONST = { ANDROID_PACKAGE_NAME, ANIMATED_TRANSITION: 300, @@ -1377,9 +1380,7 @@ const CONST = { CLOSED: 6, STATE_SUSPENDED: 7, }, - get ACTIVE_STATES() { - return [2, 3, 4, 7]; - }, + ACTIVE_STATES: cardActiveStates }, AVATAR_ROW_SIZE: { DEFAULT: 4, diff --git a/src/components/KYCWall/types.ts b/src/components/KYCWall/types.ts index dc038e998694..5c4b78edd2b1 100644 --- a/src/components/KYCWall/types.ts +++ b/src/components/KYCWall/types.ts @@ -67,7 +67,7 @@ type KYCWallProps = { onSuccessfulKYC: (iouPaymentType?: TransferMethod, currentSource?: Source) => void; /** Children to build the KYC */ - children: (continueAction: (event: GestureResponderEvent | KeyboardEvent | undefined, method: TransferMethod) => void, anchorRef: ForwardedRef) => void; + children: (continueAction: (event?: GestureResponderEvent | KeyboardEvent | undefined, method?: TransferMethod) => void, anchorRef: ForwardedRef) => void; }; export type {AnchorPosition, KYCWallProps, PaymentMethod, TransferMethod, DomRect, Source}; diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index d1823beddef4..09f847ddf490 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -393,7 +393,7 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi navigateToWalletOrTransferBalancePage(source)} + onSuccessfulKYC={(_iouPaymentType?: TransferMethod, source?: Source) => navigateToWalletOrTransferBalancePage(source)} onSelectPaymentMethod={(selectedPaymentMethod: string) => { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { From d33d249b09a30ec98242241872de8ac718d24903 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 24 Jan 2024 17:42:34 +0700 Subject: [PATCH 10/16] type error --- src/CONST.ts | 2 +- src/components/KYCWall/BaseKYCWall.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 7e5efb2a07a8..f8ce9689a494 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -38,7 +38,7 @@ const keyInputRightArrow = KeyCommand?.constants?.keyInputRightArrow ?? 'keyInpu const KEYBOARD_SHORTCUT_NAVIGATION_TYPE = 'NAVIGATION_SHORTCUT'; // Explicit type annotation is required -const cardActiveStates: number[] = [2, 3, 4, 7] +const cardActiveStates: number[] = [2, 3, 4, 7]; const CONST = { ANDROID_PACKAGE_NAME, diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 89cceadc0fb0..b2d979a33fcb 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -243,7 +243,6 @@ function KYCWall({ return ( <> setShouldShowAddPaymentMenu(false)} From 082b1a83ba11996308ae55001879f0096630fe4d Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 25 Jan 2024 15:37:52 +0700 Subject: [PATCH 11/16] lint fix --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index d3f712c77e1f..d2422088d1fb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1387,7 +1387,7 @@ const CONST = { CLOSED: 6, STATE_SUSPENDED: 7, }, - ACTIVE_STATES: cardActiveStates + ACTIVE_STATES: cardActiveStates, }, AVATAR_ROW_SIZE: { DEFAULT: 4, From f0871a0e6d9a688000c12a5c9830eb154a3a0673 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 1 Feb 2024 17:09:57 +0700 Subject: [PATCH 12/16] lint fix --- src/pages/settings/Wallet/PaymentMethodList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index ed776ffc213f..15c97a82989a 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -30,8 +30,8 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {AccountData, BankAccountList, CardList, FundList} from '@src/types/onyx'; -import {BankIcon} from '@src/types/onyx/Bank'; -import {Errors} from '@src/types/onyx/OnyxCommon'; +import type {BankIcon} from '@src/types/onyx/Bank'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; import type PaymentMethod from '@src/types/onyx/PaymentMethod'; import type IconAsset from '@src/types/utils/IconAsset'; From 358c1be66d4230ec5eb50c512b27fba6c524e98a Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 5 Feb 2024 23:32:37 +0700 Subject: [PATCH 13/16] fix: remove unnecessary disable lint --- src/pages/settings/Wallet/WalletPage/CardDetails.tsx | 3 +-- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx index ce2dbc6b2cb5..77458384c214 100644 --- a/src/pages/settings/Wallet/WalletPage/CardDetails.tsx +++ b/src/pages/settings/Wallet/WalletPage/CardDetails.tsx @@ -16,10 +16,9 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {PrivatePersonalDetails} from '@src/types/onyx'; -const defaultPrivatePersonalDetails = { +const defaultPrivatePersonalDetails: PrivatePersonalDetails = { address: { street: '', - street2: '', city: '', state: '', zip: '', diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 87038b163ad7..1f369b1f6999 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -84,7 +84,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi }); const [showConfirmDeleteModal, setShowConfirmDeleteModal] = useState(false); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const hasBankAccount = !_.isEmpty(bankAccountList) || !_.isEmpty(fundList); const hasWallet = !_.isEmpty(userWallet); const hasActivatedWallet = ([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM] as string[]).includes(userWallet?.tierName ?? ''); @@ -219,7 +218,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi Navigation.navigate(ROUTES.SETTINGS_ADD_DEBIT_CARD); return; } - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (paymentType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || paymentType === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { BankAccounts.openPersonalBankAccountSetupView(); return; @@ -343,7 +341,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi !(paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && paymentMethod.selectedPaymentMethod.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS); // Determines whether or not the modal popup is mounted from the bottom of the screen instead of the side mount on Web or Desktop screens - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const isPopoverBottomMount = anchorPosition.anchorPositionTop === 0 || isSmallScreenWidth; const alertTextStyle = [styles.inlineSystemMessage, styles.flexShrink1]; const alertViewStyle = [styles.flexRow, styles.alignItemsCenter, styles.w100, styles.ph5]; @@ -401,7 +398,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi // eslint-disable-next-line @typescript-eslint/naming-convention onSuccessfulKYC={(_iouPaymentType?: TransferMethod, source?: Source) => navigateToWalletOrTransferBalancePage(source)} onSelectPaymentMethod={(selectedPaymentMethod: string) => { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return; } @@ -495,7 +491,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} /> @@ -513,7 +508,6 @@ function WalletPage({bankAccountList = {}, cardList = {}, fundList = {}, isLoadi actionPaymentMethodType={shouldShowDefaultDeleteMenu ? paymentMethod.selectedPaymentMethodType : ''} activePaymentMethodID={shouldShowDefaultDeleteMenu ? getSelectedPaymentMethodID() : ''} buttonRef={addPaymentMethodAnchorRef} - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing onListContentSizeChange={shouldShowAddPaymentMenu || shouldShowDefaultDeleteMenu ? setMenuPosition : () => {}} shouldEnableScroll={false} style={styles.mt5} From 57d806a0fdc631a3bbbc23b12c75ee4853afe66b Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 5 Feb 2024 23:35:30 +0700 Subject: [PATCH 14/16] fix: remove unnecessary disable lint --- src/pages/settings/Wallet/PaymentMethodList.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 15c97a82989a..63c9dfabe151 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -140,7 +140,6 @@ function shouldShowDefaultBadge(filteredPaymentMethods: PaymentMethod[], isDefau } const defaultablePaymentMethodCount = filteredPaymentMethods.filter( - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, ).length; return defaultablePaymentMethodCount > 1; @@ -205,7 +204,6 @@ function PaymentMethodList({ interactive: isExpensifyCard, canDismissError: isExpensifyCard, errors: card.errors, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing brickRoadIndicator: card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN || card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR @@ -227,7 +225,6 @@ function PaymentMethodList({ if (!isOffline) { combinedPaymentMethods = combinedPaymentMethods.filter( - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(paymentMethod.errors), ); } From 2633478b6748f7c1450f330fe33c927ef4c6bf51 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 5 Feb 2024 23:51:42 +0700 Subject: [PATCH 15/16] typecheck fix --- src/pages/settings/Wallet/WalletEmptyState.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Wallet/WalletEmptyState.tsx b/src/pages/settings/Wallet/WalletEmptyState.tsx index 13a85a1ffb42..42d24d3c1e04 100644 --- a/src/pages/settings/Wallet/WalletEmptyState.tsx +++ b/src/pages/settings/Wallet/WalletEmptyState.tsx @@ -48,6 +48,7 @@ function WalletEmptyState({onAddPaymentMethod}: WalletEmptyStateProps) { > Date: Tue, 20 Feb 2024 16:22:31 +0700 Subject: [PATCH 16/16] fix: lint --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index f87fec0ae8ab..08eb51059848 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ "es2022.object", "es2022.string", "ES2021.Intl", - "ES2023.Array", + "ES2023.Array" ], "allowJs": true, "checkJs": false,