From 6c7ca01ae2998fe7d22b1e58b14ef435d8bb93ee Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Wed, 22 Nov 2023 16:08:43 +0100 Subject: [PATCH 1/3] [TS migration] Migrate 'Indicator.js' component --- src/ONYXKEYS.ts | 8 +- src/components/Indicator.js | 129 ----------------------------- src/components/Indicator.tsx | 111 +++++++++++++++++++++++++ src/libs/actions/PaymentMethods.ts | 6 +- src/pages/workspace/withPolicy.tsx | 2 +- src/types/onyx/BankAccount.ts | 4 +- src/types/onyx/Fund.ts | 3 + src/types/onyx/Login.ts | 3 + src/types/onyx/index.ts | 9 +- 9 files changed, 135 insertions(+), 140 deletions(-) delete mode 100644 src/components/Indicator.js create mode 100644 src/components/Indicator.tsx diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 75c284fb9546..23482b2c9fda 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -371,7 +371,7 @@ type OnyxValues = { [ONYXKEYS.COUNTRY_CODE]: number; [ONYXKEYS.COUNTRY]: string; [ONYXKEYS.USER]: OnyxTypes.User; - [ONYXKEYS.LOGIN_LIST]: Record; + [ONYXKEYS.LOGIN_LIST]: OnyxTypes.LoginList; [ONYXKEYS.SESSION]: OnyxTypes.Session; [ONYXKEYS.BETAS]: OnyxTypes.Beta[]; [ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf; @@ -389,8 +389,8 @@ type OnyxValues = { [ONYXKEYS.WALLET_ONFIDO]: OnyxTypes.WalletOnfido; [ONYXKEYS.WALLET_ADDITIONAL_DETAILS]: OnyxTypes.WalletAdditionalDetails; [ONYXKEYS.WALLET_TERMS]: OnyxTypes.WalletTerms; - [ONYXKEYS.BANK_ACCOUNT_LIST]: Record; - [ONYXKEYS.FUND_LIST]: Record; + [ONYXKEYS.BANK_ACCOUNT_LIST]: OnyxTypes.BankAccountList; + [ONYXKEYS.FUND_LIST]: OnyxTypes.FundList; [ONYXKEYS.CARD_LIST]: Record; [ONYXKEYS.WALLET_STATEMENT]: OnyxTypes.WalletStatement; [ONYXKEYS.PERSONAL_BANK_ACCOUNT]: OnyxTypes.PersonalBankAccount; @@ -424,7 +424,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.POLICY_DRAFTS]: OnyxTypes.Policy; [ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory; [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags; - [ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMember; + [ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories; [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMembers; diff --git a/src/components/Indicator.js b/src/components/Indicator.js deleted file mode 100644 index 1f38c1dd89ce..000000000000 --- a/src/components/Indicator.js +++ /dev/null @@ -1,129 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {StyleSheet, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as UserUtils from '@libs/UserUtils'; -import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes'; -import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes'; -import policyMemberPropType from '@pages/policyMemberPropType'; -import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; -import {policyPropTypes} from '@pages/workspace/withPolicy'; -import useTheme from '@styles/themes/useTheme'; -import useThemeStyles from '@styles/useThemeStyles'; -import * as PaymentMethods from '@userActions/PaymentMethods'; -import ONYXKEYS from '@src/ONYXKEYS'; -import bankAccountPropTypes from './bankAccountPropTypes'; -import cardPropTypes from './cardPropTypes'; - -const propTypes = { - /* Onyx Props */ - - /** The employee list of all policies (coming from Onyx) */ - allPolicyMembers: PropTypes.objectOf(PropTypes.objectOf(policyMemberPropType)), - - /** All the user's policies (from Onyx via withFullPolicy) */ - policies: PropTypes.objectOf(policyPropTypes.policy), - - /** List of bank accounts */ - bankAccountList: PropTypes.objectOf(bankAccountPropTypes), - - /** List of user cards */ - fundList: PropTypes.objectOf(cardPropTypes), - - /** The user's wallet (coming from Onyx) */ - userWallet: userWalletPropTypes, - - /** Bank account attached to free plan */ - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes, - - /** Information about the user accepting the terms for payments */ - walletTerms: walletTermsPropTypes, - - /** Login list for the user that is signed in */ - loginList: PropTypes.shape({ - /** Date login was validated, used to show info indicator status */ - validatedDate: PropTypes.string, - - /** Field-specific server side errors keyed by microtime */ - errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)), - }), -}; - -const defaultProps = { - reimbursementAccount: {}, - allPolicyMembers: {}, - policies: {}, - bankAccountList: {}, - fundList: null, - userWallet: {}, - walletTerms: {}, - loginList: {}, -}; - -function Indicator(props) { - const theme = useTheme(); - const styles = useThemeStyles(); - // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and - // those should be cleaned out before doing any error checking - const cleanPolicies = _.pick(props.policies, (policy) => policy); - const cleanAllPolicyMembers = _.pick(props.allPolicyMembers, (policyMembers) => policyMembers); - - const paymentCardList = props.fundList || {}; - - // All of the error & info-checking methods are put into an array. This is so that using _.some() will return - // early as soon as the first error / info condition is returned. This makes the checks very efficient since - // we only care if a single error / info condition exists anywhere. - const errorCheckingMethods = [ - () => !_.isEmpty(props.userWallet.errors), - () => PaymentMethods.hasPaymentMethodError(props.bankAccountList, paymentCardList), - () => _.some(cleanPolicies, PolicyUtils.hasPolicyError), - () => _.some(cleanPolicies, PolicyUtils.hasCustomUnitsError), - () => _.some(cleanAllPolicyMembers, PolicyUtils.hasPolicyMemberError), - () => !_.isEmpty(props.reimbursementAccount.errors), - () => UserUtils.hasLoginListError(props.loginList), - - // Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead) - () => !_.isEmpty(props.walletTerms.errors) && !props.walletTerms.chatReportID, - ]; - const infoCheckingMethods = [() => UserUtils.hasLoginListInfo(props.loginList)]; - const shouldShowErrorIndicator = _.some(errorCheckingMethods, (errorCheckingMethod) => errorCheckingMethod()); - const shouldShowInfoIndicator = !shouldShowErrorIndicator && _.some(infoCheckingMethods, (infoCheckingMethod) => infoCheckingMethod()); - - const indicatorColor = shouldShowErrorIndicator ? theme.danger : theme.success; - const indicatorStyles = [styles.alignItemsCenter, styles.justifyContentCenter, styles.statusIndicator(indicatorColor)]; - - return (shouldShowErrorIndicator || shouldShowInfoIndicator) && ; -} - -Indicator.defaultProps = defaultProps; -Indicator.propTypes = propTypes; -Indicator.displayName = 'Indicator'; - -export default withOnyx({ - allPolicyMembers: { - key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, - }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - bankAccountList: { - key: ONYXKEYS.BANK_ACCOUNT_LIST, - }, - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, - fundList: { - key: ONYXKEYS.FUND_LIST, - }, - userWallet: { - key: ONYXKEYS.USER_WALLET, - }, - walletTerms: { - key: ONYXKEYS.WALLET_TERMS, - }, - loginList: { - key: ONYXKEYS.LOGIN_LIST, - }, -})(Indicator); diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx new file mode 100644 index 000000000000..31c503cb0fb9 --- /dev/null +++ b/src/components/Indicator.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import {StyleSheet, View} from 'react-native'; +import {OnyxCollection, withOnyx} from 'react-native-onyx'; +import {OnyxEntry} from 'react-native-onyx/lib/types'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import * as UserUtils from '@libs/UserUtils'; +import useTheme from '@styles/themes/useTheme'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as PaymentMethods from '@userActions/PaymentMethods'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {BankAccountList, FundList, LoginList, Policy, PolicyMembers, ReimbursementAccount, UserWallet, WalletTerms} from '@src/types/onyx'; + +type CheckingMethod = () => boolean; + +type IndicatorOnyxProps = { + /** The employee list of all policies (coming from Onyx) */ + allPolicyMembers: OnyxCollection; + + /** All the user's policies (from Onyx via withFullPolicy) */ + policies: OnyxCollection; + + /** List of bank accounts */ + bankAccountList: OnyxEntry; + + /** List of user cards */ + fundList: OnyxEntry; + + /** The user's wallet (coming from Onyx) */ + userWallet: OnyxEntry; + + /** Bank account attached to free plan */ + reimbursementAccount: OnyxEntry; + + /** Information about the user accepting the terms for payments */ + walletTerms: OnyxEntry; + + /** Login list for the user that is signed in */ + loginList: OnyxEntry; +}; + +function Indicator({ + reimbursementAccount = {}, + allPolicyMembers = {}, + policies = {}, + bankAccountList = {}, + fundList = {}, + userWallet = null, + walletTerms = {}, + loginList = {}, +}: IndicatorOnyxProps) { + const theme = useTheme(); + const styles = useThemeStyles(); + + // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and + // those should be cleaned out before doing any error checking + const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => !!policy)); + const cleanAllPolicyMembers = Object.fromEntries(Object.entries(allPolicyMembers ?? {}).filter(([, policyMembers]) => !!policyMembers)); + + // All of the error & info-checking methods are put into an array. This is so that using _.some() will return + // early as soon as the first error / info condition is returned. This makes the checks very efficient since + // we only care if a single error / info condition exists anywhere. + const errorCheckingMethods: CheckingMethod[] = [ + () => Object.keys(userWallet?.errors ?? {}).length > 0, + () => PaymentMethods.hasPaymentMethodError(bankAccountList, fundList), + () => Object.values(cleanPolicies).some(PolicyUtils.hasPolicyError), + () => Object.values(cleanPolicies).some(PolicyUtils.hasCustomUnitsError), + () => Object.values(cleanAllPolicyMembers).some(PolicyUtils.hasPolicyMemberError), + () => Object.keys(reimbursementAccount?.errors ?? {}).length > 0, + () => !!loginList && UserUtils.hasLoginListError(loginList), + + // Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead) + () => Object.keys(walletTerms?.errors ?? {}).length > 0 && !walletTerms?.chatReportID, + ]; + const infoCheckingMethods: CheckingMethod[] = [() => !!loginList && UserUtils.hasLoginListInfo(loginList)]; + const shouldShowErrorIndicator = errorCheckingMethods.some((errorCheckingMethod) => errorCheckingMethod()); + const shouldShowInfoIndicator = !shouldShowErrorIndicator && infoCheckingMethods.some((infoCheckingMethod) => infoCheckingMethod()); + + const indicatorColor = shouldShowErrorIndicator ? theme.danger : theme.success; + const indicatorStyles = [styles.alignItemsCenter, styles.justifyContentCenter, styles.statusIndicator(indicatorColor)]; + + return (shouldShowErrorIndicator || shouldShowInfoIndicator) && ; +} + +Indicator.displayName = 'Indicator'; + +export default withOnyx({ + allPolicyMembers: { + key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, + }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, + bankAccountList: { + key: ONYXKEYS.BANK_ACCOUNT_LIST, + }, + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + fundList: { + key: ONYXKEYS.FUND_LIST, + }, + userWallet: { + key: ONYXKEYS.USER_WALLET, + }, + walletTerms: { + key: ONYXKEYS.WALLET_TERMS, + }, + loginList: { + key: ONYXKEYS.LOGIN_LIST, + }, +})(Indicator); diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index bcc5d8142470..50582186e77f 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -1,12 +1,14 @@ import {createRef} from 'react'; import Onyx, {OnyxUpdate} from 'react-native-onyx'; +import {OnyxEntry} from 'react-native-onyx/lib/types'; import {ValueOf} from 'type-fest'; import * as API from '@libs/API'; import * as CardUtils from '@libs/CardUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; -import ONYXKEYS, {OnyxValues} from '@src/ONYXKEYS'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {BankAccountList, FundList} from '@src/types/onyx'; import PaymentMethod from '@src/types/onyx/PaymentMethod'; import {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer'; @@ -303,7 +305,7 @@ function dismissSuccessfulTransferBalancePage() { * Looks through each payment method to see if there is an existing error * */ -function hasPaymentMethodError(bankList: OnyxValues[typeof ONYXKEYS.BANK_ACCOUNT_LIST], fundList: OnyxValues[typeof ONYXKEYS.FUND_LIST]): boolean { +function hasPaymentMethodError(bankList: OnyxEntry, fundList: OnyxEntry): boolean { const combinedPaymentMethods = {...bankList, ...fundList}; return Object.values(combinedPaymentMethods).some((item) => Object.keys(item.errors ?? {}).length); diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 8db093ec24d0..d9b61cf40f05 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -59,7 +59,7 @@ const policyPropTypes = { type WithPolicyOnyxProps = { policy: OnyxEntry; - policyMembers: OnyxEntry; + policyMembers: OnyxEntry; policyDraft: OnyxEntry; policyMembersDraft: OnyxEntry; }; diff --git a/src/types/onyx/BankAccount.ts b/src/types/onyx/BankAccount.ts index 4a7b6dac7387..b606c5bfeed1 100644 --- a/src/types/onyx/BankAccount.ts +++ b/src/types/onyx/BankAccount.ts @@ -30,5 +30,7 @@ type BankAccount = { pendingAction?: OnyxCommon.PendingAction; }; +type BankAccountList = Record; + export default BankAccount; -export type {AccountData}; +export type {AccountData, BankAccountList}; diff --git a/src/types/onyx/Fund.ts b/src/types/onyx/Fund.ts index 4e6cbc695a8d..c5d606b72923 100644 --- a/src/types/onyx/Fund.ts +++ b/src/types/onyx/Fund.ts @@ -36,4 +36,7 @@ type Fund = { pendingAction?: OnyxCommon.PendingAction; }; +type FundList = Record; + export default Fund; +export type {FundList}; diff --git a/src/types/onyx/Login.ts b/src/types/onyx/Login.ts index c770e2f81f90..bcf949eb95e6 100644 --- a/src/types/onyx/Login.ts +++ b/src/types/onyx/Login.ts @@ -17,4 +17,7 @@ type Login = { pendingFields?: OnyxCommon.PendingFields; }; +type LoginList = Record; + export default Login; +export type {LoginList}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 87cf24d6dec7..447d3cffe97d 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -1,6 +1,6 @@ import Account from './Account'; import AccountData from './AccountData'; -import BankAccount from './BankAccount'; +import BankAccount, {BankAccountList} from './BankAccount'; import Beta from './Beta'; import BlockedFromConcierge from './BlockedFromConcierge'; import Card from './Card'; @@ -10,9 +10,9 @@ import CustomStatusDraft from './CustomStatusDraft'; import Download from './Download'; import Form, {AddDebitCardForm, DateOfBirthForm} from './Form'; import FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; -import Fund from './Fund'; +import Fund, {FundList} from './Fund'; import IOU from './IOU'; -import Login from './Login'; +import Login, {LoginList} from './Login'; import MapboxAccessToken from './MapboxAccessToken'; import Modal from './Modal'; import Network from './Network'; @@ -55,6 +55,7 @@ export type { AccountData, AddDebitCardForm, BankAccount, + BankAccountList, Beta, BlockedFromConcierge, Card, @@ -66,8 +67,10 @@ export type { Form, FrequentlyUsedEmoji, Fund, + FundList, IOU, Login, + LoginList, MapboxAccessToken, Modal, Network, From b760fdc5ef5fc06d96463e97f3b0badc0ffd26bb Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Thu, 23 Nov 2023 15:09:39 +0100 Subject: [PATCH 2/3] Add IndicatorProps type --- src/components/Indicator.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx index 31c503cb0fb9..9cbb4f1215b8 100644 --- a/src/components/Indicator.tsx +++ b/src/components/Indicator.tsx @@ -38,6 +38,8 @@ type IndicatorOnyxProps = { loginList: OnyxEntry; }; +type IndicatorProps = IndicatorOnyxProps; + function Indicator({ reimbursementAccount = {}, allPolicyMembers = {}, @@ -83,7 +85,7 @@ function Indicator({ Indicator.displayName = 'Indicator'; -export default withOnyx({ +export default withOnyx({ allPolicyMembers: { key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, From ad89b1b81228391dfe054cd0aebab7afb8b76274 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 24 Nov 2023 10:39:55 +0100 Subject: [PATCH 3/3] Remove unnecessary default params --- src/components/Indicator.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx index 9cbb4f1215b8..5332c4bd984f 100644 --- a/src/components/Indicator.tsx +++ b/src/components/Indicator.tsx @@ -40,16 +40,7 @@ type IndicatorOnyxProps = { type IndicatorProps = IndicatorOnyxProps; -function Indicator({ - reimbursementAccount = {}, - allPolicyMembers = {}, - policies = {}, - bankAccountList = {}, - fundList = {}, - userWallet = null, - walletTerms = {}, - loginList = {}, -}: IndicatorOnyxProps) { +function Indicator({reimbursementAccount, allPolicyMembers, policies, bankAccountList, fundList, userWallet, walletTerms, loginList}: IndicatorOnyxProps) { const theme = useTheme(); const styles = useThemeStyles();