Skip to content

Commit

Permalink
Merge pull request #34220 from MrMuzyk/feat/personal-info-ts-migration
Browse files Browse the repository at this point in the history
feat: PersonalInfo ts migration
  • Loading branch information
mountiny authored Jan 10, 2024
2 parents 2da7382 + a8452f9 commit ad0c28c
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 166 deletions.
9 changes: 8 additions & 1 deletion src/libs/actions/BankAccounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ type BusinessAddress = {
addressZipCode?: string;
};

type PersonalAddress = {
requestorAddressStreet?: string;
requestorAddressCity?: string;
requestorAddressState?: string;
requestorAddressZipCode?: string;
};

function clearPlaid(): Promise<void> {
Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, '');
Onyx.set(ONYXKEYS.PLAID_CURRENT_EVENT, null);
Expand Down Expand Up @@ -528,4 +535,4 @@ export {
setReimbursementAccountLoading,
};

export type {BusinessAddress};
export type {BusinessAddress, PersonalAddress};
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import PropTypes from 'prop-types';
import React from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';

const propTypes = {
type HelpLinkProps = {
/** Style for wrapping View */
// eslint-disable-next-line react/forbid-prop-types
containerStyles: PropTypes.arrayOf(PropTypes.object),

/** Translate function */
translate: PropTypes.func.isRequired,
};

const defaultProps = {
containerStyles: [],
containerStyles?: StyleProp<ViewStyle>;
};

function HelpLinks({containerStyles, translate}) {
function HelpLinks({containerStyles}: HelpLinkProps) {
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();

return (
<View style={[styles.flexRow, styles.alignItemsCenter, containerStyles]}>
<Icon src={Expensicons.QuestionMark} />
<Icon
src={Expensicons.QuestionMark}
fill={theme.icon}
/>
<View style={[styles.ml2, styles.dFlex, styles.flexRow]}>
<TextLink
style={[styles.textMicro]}
Expand All @@ -36,7 +35,7 @@ function HelpLinks({containerStyles, translate}) {
</TextLink>
<Text style={[styles.textMicroSupporting]}>{' | '}</Text>
<TextLink
style={[styles.textMicro, styles.textLink]}
style={[styles.textMicro]}
href={CONST.PERSONAL_DATA_PROTECTION_INFO_URL}
>
{translate('requestorStep.isMyDataSafe')}
Expand All @@ -47,7 +46,5 @@ function HelpLinks({containerStyles, translate}) {
}

HelpLinks.displayName = 'HelpLinks';
HelpLinks.propTypes = propTypes;
HelpLinks.defaultProps = defaultProps;

export default HelpLinks;
Original file line number Diff line number Diff line change
@@ -1,64 +1,58 @@
import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useMemo} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
import useSubStep from '@hooks/useSubStep';
import type {SubStepProps} from '@hooks/useSubStep/types';
import useThemeStyles from '@hooks/useThemeStyles';
import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
import getDefaultValueForReimbursementAccountField from '@pages/ReimbursementAccount/utils/getDefaultValueForReimbursementAccountField';
import getInitialSubstepForPersonalInfo from '@pages/ReimbursementAccount/utils/getInitialSubstepForPersonalInfo';
import getSubstepValues from '@pages/ReimbursementAccount/utils/getSubstepValues';
import * as BankAccounts from '@userActions/BankAccounts';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ReimbursementAccount, ReimbursementAccountDraft} from '@src/types/onyx';
import Address from './substeps/Address';
import Confirmation from './substeps/Confirmation';
import DateOfBirth from './substeps/DateOfBirth';
import FullName from './substeps/FullName';
import SocialSecurityNumber from './substeps/SocialSecurityNumber';

const propTypes = {
type PersonalInfoOnyxProps = {
/** Reimbursement account from ONYX */
reimbursementAccount: reimbursementAccountPropTypes,
reimbursementAccount: OnyxEntry<ReimbursementAccount>;

/** The draft values of the bank account being setup */
reimbursementAccountDraft: reimbursementAccountDraftPropTypes,
reimbursementAccountDraft: OnyxEntry<ReimbursementAccountDraft>;
};

type PersonalInfoProps = PersonalInfoOnyxProps & {
/** Goes to the previous step */
onBackButtonPress: PropTypes.func.isRequired,
onBackButtonPress: () => void;

/** Exits flow and goes back to the workspace initial page */
onCloseButtonPress: PropTypes.func.isRequired,
};

const defaultProps = {
reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
reimbursementAccountDraft: {},
onCloseButtonPress: () => void;
};

const bodyContent = [FullName, DateOfBirth, SocialSecurityNumber, Address, Confirmation];
const bodyContent: Array<React.ComponentType<SubStepProps>> = [FullName, DateOfBirth, SocialSecurityNumber, Address, Confirmation];
const personalInfoStepKeys = CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY;

const PersonalInfo = forwardRef(({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress, onCloseButtonPress}, ref) => {
function PersonalInfo({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress, onCloseButtonPress}: PersonalInfoProps, ref: React.ForwardedRef<View>) {
const {translate} = useLocalize();
const styles = useThemeStyles();

const values = useMemo(() => getSubstepValues(personalInfoStepKeys, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);

const submit = useCallback(() => {
const payload = {
bankAccountID: getDefaultValueForReimbursementAccountField(reimbursementAccount, personalInfoStepKeys.BANK_ACCOUNT_ID, 0),
...values,
};

BankAccounts.updatePersonalInformationForBankAccount(payload);
}, [reimbursementAccount, values]);
}, [values]);
const startFrom = useMemo(() => getInitialSubstepForPersonalInfo(values), [values]);

const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent, startFrom, onFinished: submit});
Expand Down Expand Up @@ -98,17 +92,15 @@ const PersonalInfo = forwardRef(({reimbursementAccount, reimbursementAccountDraf
/>
</ScreenWrapper>
);
});
}

PersonalInfo.propTypes = propTypes;
PersonalInfo.defaultProps = defaultProps;
PersonalInfo.displayName = 'PersonalInfo';

export default withOnyx({
export default withOnyx<PersonalInfoProps, PersonalInfoOnyxProps>({
reimbursementAccount: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
},
reimbursementAccountDraft: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT,
},
})(PersonalInfo);
})(forwardRef(PersonalInfo));
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
import React from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import FormProvider from '@components/Form/FormProvider';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import type {SubStepProps} from '@hooks/useSubStep/types';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ValidationUtils from '@libs/ValidationUtils';
import AddressForm from '@pages/ReimbursementAccount/AddressForm';
import HelpLinks from '@pages/ReimbursementAccount/PersonalInfo/HelpLinks';
import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes';
import getDefaultValueForReimbursementAccountField from '@pages/ReimbursementAccount/utils/getDefaultValueForReimbursementAccountField';
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 type * as OnyxCommon from '@src/types/onyx/OnyxCommon';

const propTypes = {
type AddressOnyxProps = {
/** Reimbursement account from ONYX */
reimbursementAccount: reimbursementAccountPropTypes,

...subStepPropTypes,
reimbursementAccount: OnyxEntry<ReimbursementAccount>;
};

const defaultProps = {
reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
};
type AddressProps = AddressOnyxProps & SubStepProps;

const personalInfoStepKey = CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY;

Expand All @@ -38,7 +35,7 @@ const INPUT_KEYS = {

const REQUIRED_FIELDS = [personalInfoStepKey.STREET, personalInfoStepKey.CITY, personalInfoStepKey.STATE, personalInfoStepKey.ZIP_CODE];

const validate = (values) => {
const validate = (values: FormValues): OnyxCommon.Errors => {
const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);

if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) {
Expand All @@ -52,23 +49,24 @@ const validate = (values) => {
return errors;
};

function Address({reimbursementAccount, onNext, isEditing}) {
function Address({reimbursementAccount, onNext, isEditing}: AddressProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();

const defaultValues = {
street: getDefaultValueForReimbursementAccountField(reimbursementAccount, personalInfoStepKey.STREET, ''),
city: getDefaultValueForReimbursementAccountField(reimbursementAccount, personalInfoStepKey.CITY, ''),
state: getDefaultValueForReimbursementAccountField(reimbursementAccount, personalInfoStepKey.STATE, ''),
zipCode: getDefaultValueForReimbursementAccountField(reimbursementAccount, personalInfoStepKey.ZIP_CODE, ''),
street: reimbursementAccount?.achData?.[personalInfoStepKey.STREET] ?? '',
city: reimbursementAccount?.achData?.[personalInfoStepKey.CITY] ?? '',
state: reimbursementAccount?.achData?.[personalInfoStepKey.STATE] ?? '',
zipCode: reimbursementAccount?.achData?.[personalInfoStepKey.ZIP_CODE] ?? '',
};

const handleSubmit = (values) => {
const handleSubmit = (values: BankAccounts.PersonalAddress) => {
BankAccounts.addPersonalAddressForDraft(values);
onNext();
};

return (
// @ts-expect-error TODO: Remove this once Form (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
<FormProvider
formID={ONYXKEYS.REIMBURSEMENT_ACCOUNT}
submitButtonText={isEditing ? translate('common.confirm') : translate('common.next')}
Expand All @@ -87,20 +85,15 @@ function Address({reimbursementAccount, onNext, isEditing}) {
streetTranslationKey="common.streetAddress"
defaultValues={defaultValues}
/>
<HelpLinks
translate={translate}
containerStyles={[styles.mt5]}
/>
<HelpLinks containerStyles={[styles.mt5]} />
</View>
</FormProvider>
);
}

Address.propTypes = propTypes;
Address.defaultProps = defaultProps;
Address.displayName = 'Address';

export default withOnyx({
export default withOnyx<AddressProps, AddressOnyxProps>({
reimbursementAccount: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
},
Expand Down
Loading

0 comments on commit ad0c28c

Please sign in to comment.