diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.tsx similarity index 74% rename from src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js rename to src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.tsx index aedff279f14d..2164dd98a73f 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.tsx @@ -1,8 +1,7 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx/lib/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -11,37 +10,31 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import BankAccount from '@libs/models/BankAccount'; import EnableBankAccount from '@pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount'; -import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Account, ReimbursementAccount} from '@src/types/onyx'; import BankAccountValidationForm from './components/BankAccountValidationForm'; import FinishChatCard from './components/FinishChatCard'; -const propTypes = { - /** Bank account currently in setup */ - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, - - /** Handles back button press */ - onBackButtonPress: PropTypes.func.isRequired, - +type ConnectBankAccountOnyxProps = { /** User's account who is setting up bank account */ - account: PropTypes.shape({ - /** If user has two-factor authentication enabled */ - requiresTwoFactorAuth: PropTypes.bool, - }), + account: OnyxEntry; }; -const defaultProps = { - account: { - requiresTwoFactorAuth: false, - }, +type ConnectBankAccountProps = ConnectBankAccountOnyxProps & { + /** Bank account currently in setup */ + reimbursementAccount: ReimbursementAccount; + + /** Handles back button press */ + onBackButtonPress: () => void; }; -function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) { +function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}: ConnectBankAccountProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const bankAccountState = lodashGet(reimbursementAccount, 'achData.state', ''); + const handleNavigateToConciergeChat = () => Report.navigateToConciergeChat(); + const bankAccountState = reimbursementAccount.achData?.state ?? ''; // If a user tries to navigate directly to the validate page we'll show them the EnableStep if (bankAccountState === BankAccount.STATE.OPEN) { @@ -53,10 +46,10 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) ); } - const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached', false); + const maxAttemptsReached = reimbursementAccount.maxAttemptsReached ?? false; const isBankAccountVerifying = !maxAttemptsReached && bankAccountState === BankAccount.STATE.VERIFYING; const isBankAccountPending = bankAccountState === BankAccount.STATE.PENDING; - const requiresTwoFactorAuth = lodashGet(account, 'requiresTwoFactorAuth', false); + const requiresTwoFactorAuth = account?.requiresTwoFactorAuth ?? false; return ( {translate('connectBankAccountStep.maxAttemptsReached')} {translate('common.please')}{' '} - {translate('common.contactUs')}. + {translate('common.contactUs')}. )} @@ -94,11 +87,9 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) ); } -ConnectBankAccount.propTypes = propTypes; -ConnectBankAccount.defaultProps = defaultProps; ConnectBankAccount.displayName = 'ConnectBankAccount'; -export default withOnyx({ +export default withOnyx({ account: { key: ONYXKEYS.ACCOUNT, }, diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx similarity index 57% rename from src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js rename to src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx index fa06f70ac480..f7b73679bc27 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.tsx @@ -1,59 +1,56 @@ import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ValidationUtils from '@libs/ValidationUtils'; -import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {ReimbursementAccount} from '@src/types/onyx'; +import type {FormValues} from '@src/types/onyx/Form'; import Enable2FACard from './Enable2FACard'; -const propTypes = { - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, - requiresTwoFactorAuth: PropTypes.bool.isRequired, +type BankAccountValidationFormProps = { + /** Bank account currently in setup */ + reimbursementAccount: ReimbursementAccount; + + /** Boolean required to display Enable2FACard component */ + requiresTwoFactorAuth: boolean; }; -/** - * Filter input for validation amount - * Anything that isn't a number is returned as an empty string - * Any dollar amount (e.g. 1.12) will be returned as 112 - * - * @param {String} amount field input - * @returns {String} - */ -const filterInput = (amount) => { - let value = amount ? amount.toString().trim() : ''; - if (value === '' || _.isNaN(Number(value)) || !Math.abs(Str.fromUSDToNumber(value))) { +const getAmountValues = (values: FormValues): Record => ({ + amount1: values?.amount1, + amount2: values?.amount2, + amount3: values?.amount3, +}); + +const filterInput = (amount: string) => { + const value = amount ? amount.trim() : ''; + if (value === '' || Number.isNaN(Number(value)) || !Math.abs(Str.fromUSDToNumber(value, true))) { return ''; } // If the user enters the values in dollars, convert it to the respective cents amount - if (_.contains(value, '.')) { - value = Str.fromUSDToNumber(value); + if (value.includes('.')) { + return Str.fromUSDToNumber(value, true); } return value; }; -/** - * @param {Object} values - form input values passed by the Form component - * @returns {Object} - */ - -const validate = (values) => { - const errors = {}; +const validate = (values: FormValues) => { + const errors: Record = {}; + const amountValues = getAmountValues(values); - _.each(values, (value, key) => { - const filteredValue = typeof value === 'string' ? filterInput(value) : value; - if (ValidationUtils.isRequiredFulfilled(filteredValue)) { + Object.keys(amountValues).forEach((key) => { + const value = amountValues[key]; + const filteredValue = filterInput(value); + if (ValidationUtils.isRequiredFulfilled(filteredValue.toString())) { return; } errors[key] = 'common.error.invalidAmount'; @@ -62,15 +59,12 @@ const validate = (values) => { return errors; }; -function BankAccountValidationForm({requiresTwoFactorAuth, reimbursementAccount}) { +function BankAccountValidationForm({requiresTwoFactorAuth, reimbursementAccount}: BankAccountValidationFormProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - /** - * @param {Object} values - form input values passed by the Form component - */ const submit = useCallback( - (values) => { + (values: FormValues) => { const amount1 = filterInput(values.amount1); const amount2 = filterInput(values.amount2); const amount3 = filterInput(values.amount3); @@ -78,12 +72,15 @@ function BankAccountValidationForm({requiresTwoFactorAuth, reimbursementAccount} const validateCode = [amount1, amount2, amount3].join(','); // Send valid amounts to BankAccountAPI::validateBankAccount in Web-Expensify - const bankAccountID = lodashGet(reimbursementAccount, 'achData.bankAccountID'); - BankAccounts.validateBankAccount(bankAccountID, validateCode); + const bankAccountID = reimbursementAccount?.achData?.bankAccountID; + if (bankAccountID) { + BankAccounts.validateBankAccount(bankAccountID, validateCode); + } }, [reimbursementAccount], ); return ( + // @ts-expect-error TODO: Remove this once Form (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript {translate('connectBankAccountStep.descriptionCTA')} - - - @@ -129,7 +129,6 @@ function BankAccountValidationForm({requiresTwoFactorAuth, reimbursementAccount} ); } -BankAccountValidationForm.propTypes = propTypes; BankAccountValidationForm.displayName = 'BankAccountValidationForm'; export default BankAccountValidationForm; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.tsx similarity index 100% rename from src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js rename to src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.tsx diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.tsx similarity index 80% rename from src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js rename to src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.tsx index e13a64963f36..c2a32f34a5be 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.tsx @@ -1,5 +1,3 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React from 'react'; import {ScrollView} from 'react-native'; import Button from '@components/Button'; @@ -10,21 +8,25 @@ import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; import * as BankAccounts from '@userActions/BankAccounts'; import * as Report from '@userActions/Report'; +import type {ReimbursementAccount} from '@src/types/onyx'; import Enable2FACard from './Enable2FACard'; -const propTypes = { - requiresTwoFactorAuth: PropTypes.bool.isRequired, - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, +type FinishChatCardProps = { + /** Bank account currently in setup */ + reimbursementAccount: ReimbursementAccount; + + /** Boolean required to display Enable2FACard component */ + requiresTwoFactorAuth: boolean; }; -function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount}) { +function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount}: FinishChatCardProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const shouldShowResetModal = lodashGet(reimbursementAccount, 'shouldShowResetModal', false); + const shouldShowResetModal = reimbursementAccount.shouldShowResetModal ?? false; + const handleNavigateToConciergeChat = () => Report.navigateToConciergeChat(); return ( @@ -37,7 +39,7 @@ function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount}) { {translate('connectBankAccountStep.letsChatText')}