diff --git a/src/CONST.ts b/src/CONST.ts
index 9e7c1f007335..46526cdbdafd 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -165,6 +165,18 @@ const CONST = {
DOMAIN: '@expensify.sms',
},
BANK_ACCOUNT: {
+ PERSONAL_INFO_STEP: {
+ INPUT_KEY: {
+ FIRST_NAME: 'firstName',
+ LAST_NAME: 'lastName',
+ DOB: 'dob',
+ SSN_LAST_4: 'ssnLast4',
+ STREET: 'requestorAddressStreet',
+ CITY: 'requestorAddressCity',
+ STATE: 'requestorAddressState',
+ ZIP_CODE: 'requestorAddressZipCode',
+ },
+ },
PLAID: {
ALLOWED_THROTTLED_COUNT: 2,
ERROR: {
diff --git a/src/components/Form/FormWrapper.js b/src/components/Form/FormWrapper.js
index 55abcc1fc923..5f20e25104f3 100644
--- a/src/components/Form/FormWrapper.js
+++ b/src/components/Form/FormWrapper.js
@@ -56,6 +56,10 @@ const propTypes = {
/** Container styles */
style: stylePropTypes,
+ /** Submit button container styles */
+ // eslint-disable-next-line react/forbid-prop-types
+ submitButtonStyles: PropTypes.arrayOf(PropTypes.object),
+
/** Custom content to display in the footer after submit button */
footerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
@@ -74,10 +78,25 @@ const defaultProps = {
scrollContextEnabled: false,
footerContent: null,
style: [],
+ submitButtonStyles: [],
};
function FormWrapper(props) {
- const {onSubmit, children, formState, errors, inputRefs, submitButtonText, footerContent, isSubmitButtonVisible, style, enabledWhenOffline, isSubmitActionDangerous, formID} = props;
+ const {
+ onSubmit,
+ children,
+ formState,
+ errors,
+ inputRefs,
+ submitButtonText,
+ footerContent,
+ isSubmitButtonVisible,
+ style,
+ enabledWhenOffline,
+ isSubmitActionDangerous,
+ formID,
+ submitButtonStyles,
+ } = props;
const formRef = useRef(null);
const formContentRef = useRef(null);
const errorMessage = useMemo(() => {
@@ -129,7 +148,7 @@ function FormWrapper(props) {
focusInput.focus();
}
}}
- containerStyles={[styles.mh0, styles.mt5, styles.flex1]}
+ containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...submitButtonStyles]}
enabledWhenOffline={enabledWhenOffline}
isSubmitActionDangerous={isSubmitActionDangerous}
disablePressOnEnter
@@ -150,6 +169,7 @@ function FormWrapper(props) {
isSubmitActionDangerous,
isSubmitButtonVisible,
onSubmit,
+ submitButtonStyles,
style,
submitButtonText,
],
diff --git a/src/components/InteractiveStepSubHeader.js b/src/components/InteractiveStepSubHeader.js
index 75fdce8ad3b5..0405d2bd9ede 100644
--- a/src/components/InteractiveStepSubHeader.js
+++ b/src/components/InteractiveStepSubHeader.js
@@ -1,16 +1,15 @@
-import React, {forwardRef, useState, useImperativeHandle} from 'react';
-import PropTypes from 'prop-types';
import map from 'lodash/map';
+import PropTypes from 'prop-types';
+import React, {forwardRef, useImperativeHandle, useState} from 'react';
import {View} from 'react-native';
-
-import CONST from '../CONST';
-import variables from '../styles/variables';
-import styles from '../styles/styles';
-import colors from '../styles/colors';
+import colors from '@styles/colors';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
import Text from './Text';
-import Icon from './Icon';
const propTypes = {
/** List of the Route Name to navigate when the step is selected */
diff --git a/src/components/NewDatePicker/index.js b/src/components/NewDatePicker/index.js
index f03b4e2cb796..66e4a337df2f 100644
--- a/src/components/NewDatePicker/index.js
+++ b/src/components/NewDatePicker/index.js
@@ -9,6 +9,7 @@ import TextInput from '@components/TextInput';
import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '@components/TextInput/baseTextInputPropTypes';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import styles from '@styles/styles';
+import * as FormActions from '@userActions/FormActions';
import CONST from '@src/CONST';
import CalendarPicker from './CalendarPicker';
@@ -33,6 +34,12 @@ const propTypes = {
/** A maximum date of calendar to select */
maxDate: PropTypes.objectOf(Date),
+ /** Saves a draft of the input value when used in a form */
+ shouldSaveDraft: PropTypes.bool,
+
+ /** ID of the wrapping form */
+ formID: PropTypes.string,
+
...withLocalizePropTypes,
...baseTextInputPropTypes,
};
@@ -42,17 +49,42 @@ const datePickerDefaultProps = {
minDate: setYear(new Date(), CONST.CALENDAR_PICKER.MIN_YEAR),
maxDate: setYear(new Date(), CONST.CALENDAR_PICKER.MAX_YEAR),
value: undefined,
+ shouldSaveDraft: false,
+ formID: '',
};
-function NewDatePicker({containerStyles, defaultValue, disabled, errorText, inputID, isSmallScreenWidth, label, maxDate, minDate, onInputChange, onTouched, placeholder, translate, value}) {
+function NewDatePicker({
+ containerStyles,
+ defaultValue,
+ disabled,
+ errorText,
+ inputID,
+ isSmallScreenWidth,
+ label,
+ maxDate,
+ minDate,
+ onInputChange,
+ onTouched,
+ placeholder,
+ translate,
+ value,
+ shouldSaveDraft,
+ formID,
+}) {
const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined);
useEffect(() => {
+ // Value is provided to input via props and onChange never fires. We have to save draft manually.
+ if (shouldSaveDraft && formID !== '') {
+ FormActions.setDraftValues(formID, {[inputID]: selectedDate});
+ }
+
if (selectedDate === value || _.isUndefined(value)) {
return;
}
+
setSelectedDate(value);
- }, [selectedDate, value]);
+ }, [formID, inputID, selectedDate, shouldSaveDraft, value]);
useEffect(() => {
if (_.isFunction(onTouched)) {
diff --git a/src/hooks/useSubStep.js b/src/hooks/useSubStep.js
index 86071e278913..bfd88f5d5c57 100644
--- a/src/hooks/useSubStep.js
+++ b/src/hooks/useSubStep.js
@@ -1,5 +1,5 @@
-import {useState, useRef, useCallback} from 'react';
import PropTypes from 'prop-types';
+import {useCallback, useRef, useState} from 'react';
const propTypes = {
/** an array of substep components */
diff --git a/src/languages/en.ts b/src/languages/en.ts
index c186a1fffedf..8772e4b3eaac 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -167,6 +167,7 @@ export default {
noPO: 'PO boxes and mail drop addresses are not allowed',
city: 'City',
state: 'State',
+ streetAddress: 'Street address',
stateOrProvince: 'State / Province',
country: 'Country',
zip: 'Zip code',
@@ -266,6 +267,7 @@ export default {
tbd: 'TBD',
selectCurrency: 'Select a currency',
card: 'Card',
+ whyDoWeAskForThis: 'Why do we ask for this?',
},
location: {
useCurrent: 'Use current location',
@@ -1347,13 +1349,27 @@ export default {
},
requestorStep: {
headerTitle: 'Personal information',
- subtitle: 'Please provide your personal information.',
learnMore: 'Learn more',
isMyDataSafe: 'Is my data safe?',
onFidoConditions: 'By continuing with the request to add this bank account, you confirm that you have read, understand and accept ',
isControllingOfficer: 'I am authorized to use my company bank account for business spend',
isControllingOfficerError: 'You must be a controlling officer with authorization to operate the business bank account.',
},
+ personalInfoStep: {
+ personalInfo: 'Personal info',
+ enterYourLegalFirstAndLast: 'Enter your legal first and last name.',
+ legalFirstName: 'Legal first name',
+ legalLastName: 'Legal last name',
+ legalName: 'Legal name',
+ enterYourDateOfBirth: 'Enter your date of birth.',
+ enterTheLast4: 'Enter the last 4 of your SSN.',
+ dontWorry: "Don't worry, we don't do any personal credit checks!",
+ last4SSN: 'Last 4 Social Security Number',
+ enterYourAddress: 'Enter your address.',
+ address: 'Address',
+ letsDoubleCheck: "Let's double check everything looks right",
+ byAddingThisBankAccount: 'By adding this bank account, you confirm that you have read, understand and accept',
+ },
validationStep: {
headerTitle: 'Validate Bank Account',
buttonText: 'Finish setup',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a0a30bcf4141..06b559170d0e 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -157,6 +157,7 @@ export default {
noPO: 'No se aceptan apartados ni direcciones postales',
city: 'Ciudad',
state: 'Estado',
+ streetAddress: 'Dirección',
stateOrProvince: 'Estado / Provincia',
country: 'País',
zip: 'Código postal',
@@ -256,6 +257,7 @@ export default {
tbd: 'Por determinar',
selectCurrency: 'Selecciona una moneda',
card: 'Tarjeta',
+ whyDoWeAskForThis: '¿Por qué pedimos esto?',
},
location: {
useCurrent: 'Usar ubicación actual',
@@ -1366,13 +1368,27 @@ export default {
},
requestorStep: {
headerTitle: 'Información personal',
- subtitle: 'Dé más información sobre tí.',
learnMore: 'Más información',
isMyDataSafe: '¿Están seguros mis datos?',
onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
},
+ personalInfoStep: {
+ personalInfo: 'Información Personal',
+ enterYourLegalFirstAndLast: 'Ingrese su Nombre y Apellido',
+ legalFirstName: 'Nombre',
+ legalLastName: 'Apellido',
+ legalName: 'Nombre legal',
+ enterYourDateOfBirth: 'Ingrese su fecha de Cumple años',
+ enterTheLast4: 'Ingrese los últimos 4 dígitos de su NSS',
+ dontWorry: 'No se preocupe, no hacemos ninguna verificación de créditos',
+ last4SSN: 'Últimos 4 dígitos de su Número de Seguro Social',
+ enterYourAddress: 'Ingrese su dirección',
+ address: 'Dirección',
+ letsDoubleCheck: 'Revisemos que todo esté bien',
+ byAddingThisBankAccount: 'Agregando esta cuenta bancaria, confirmas que as leído, entendido y aceptado',
+ },
validationStep: {
headerTitle: 'Validar cuenta bancaria',
buttonText: 'Finalizar configuración',
diff --git a/src/pages/ReimbursementAccount/AddressForm.js b/src/pages/ReimbursementAccount/AddressForm.js
index b8675fd9cc0e..0f63b6a3eb92 100644
--- a/src/pages/ReimbursementAccount/AddressForm.js
+++ b/src/pages/ReimbursementAccount/AddressForm.js
@@ -104,7 +104,6 @@ function AddressForm(props) {
defaultValue={props.defaultValues.street}
onInputChange={props.onFieldChange}
errorText={props.errors.street ? props.translate('bankAccount.error.addressStreet') : ''}
- hint={props.translate('common.noPO')}
renamedInputKeys={props.inputKeys}
maxInputLength={CONST.FORM_CHARACTER_LIMIT}
isLimitedToUSA
@@ -145,7 +144,6 @@ function AddressForm(props) {
onChangeText={(value) => props.onFieldChange({zipCode: value})}
errorText={props.errors.zipCode ? props.translate('bankAccount.error.zipCode') : ''}
maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.ZIP_CODE}
- hint={props.translate('common.zipCodeExampleFormat', {zipSampleFormat: CONST.COUNTRY_ZIP_REGEX_DATA.US.samples})}
containerStyles={[styles.mt2]}
/>
>
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/HelpLinks.js b/src/pages/ReimbursementAccount/PersonalInfo/HelpLinks.js
new file mode 100644
index 000000000000..aee1b59f8e15
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/HelpLinks.js
@@ -0,0 +1,51 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+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 styles from '@styles/styles';
+import CONST from '@src/CONST';
+
+const propTypes = {
+ /** 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: [],
+};
+
+function HelpLinks({containerStyles, translate}) {
+ return (
+
+
+
+
+ {translate('requestorStep.learnMore')}
+
+ {' | '}
+
+ {translate('requestorStep.isMyDataSafe')}
+
+
+
+ );
+}
+
+HelpLinks.displayName = 'HelpLinks';
+HelpLinks.propTypes = propTypes;
+HelpLinks.defaultProps = defaultProps;
+
+export default HelpLinks;
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.js b/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.js
new file mode 100644
index 000000000000..218e7438d06e
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.js
@@ -0,0 +1,109 @@
+import _ from 'lodash';
+import React, {useCallback, useMemo} from 'react';
+import {View} from 'react-native';
+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 Navigation from '@libs/Navigation/Navigation';
+import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
+import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import getInitialSubstepForPersonalInfo from '@pages/ReimbursementAccount/utils/getInitialSubstepForPersonalInfo';
+import getPersonalInfoValues from '@pages/ReimbursementAccount/utils/getPersonalInfoValues';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+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 = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ /** The draft values of the bank account being setup */
+ reimbursementAccountDraft: reimbursementAccountDraftPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+ reimbursementAccountDraft: {},
+};
+
+const STEPS_HEADER_HEIGHT = 40;
+// TODO Will most likely come from different place
+const STEP_NAMES = ['1', '2', '3', '4', '5'];
+
+const bodyContent = [FullName, DateOfBirth, SocialSecurityNumber, Address, Confirmation];
+
+function PersonalInfo({reimbursementAccount, reimbursementAccountDraft}) {
+ const {translate} = useLocalize();
+
+ const values = useMemo(() => getPersonalInfoValues(reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
+
+ const submit = useCallback(() => {
+ const payload = {
+ bankAccountID: _.get(reimbursementAccount, 'achData.bankAccountID', 0),
+ ...values,
+ };
+
+ BankAccounts.updatePersonalInformationForBankAccount(payload);
+ }, [reimbursementAccount, values]);
+ const startFrom = useMemo(() => getInitialSubstepForPersonalInfo(values), [values]);
+
+ const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent, startFrom, onFinished: submit});
+
+ const handleBackButtonPress = () => {
+ if (screenIndex === 0) {
+ Navigation.goBack(ROUTES.HOME);
+ } else {
+ prevScreen();
+ }
+ };
+
+ return (
+
+
+
+ {}}
+ // TODO Will be replaced with proper values
+ startStep={1}
+ stepNames={STEP_NAMES}
+ />
+
+
+
+ );
+}
+
+PersonalInfo.propTypes = propTypes;
+PersonalInfo.defaultProps = defaultProps;
+PersonalInfo.displayName = 'PersonalInfo';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+ reimbursementAccountDraft: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT,
+ },
+})(PersonalInfo);
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.js
new file mode 100644
index 000000000000..b50ee2f22e3a
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.js
@@ -0,0 +1,103 @@
+import lodashGet from 'lodash/get';
+import React from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import Form from '@components/Form';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+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 styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+const propTypes = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ ...subStepPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+};
+
+const INPUT_KEYS = {
+ street: CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET,
+ city: CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY,
+ state: CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE,
+ zipCode: CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE,
+};
+
+const REQUIRED_FIELDS = [
+ CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET,
+ CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY,
+ CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE,
+ CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE,
+];
+
+const validate = (values) => {
+ const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);
+
+ if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) {
+ errors.requestorAddressStreet = 'bankAccount.error.addressStreet';
+ }
+
+ if (values.requestorAddressZipCode && !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) {
+ errors.requestorAddressZipCode = 'bankAccount.error.zipCode';
+ }
+
+ return errors;
+};
+
+function Address({reimbursementAccount, onNext, isEditing}) {
+ const {translate} = useLocalize();
+
+ const defaultValues = {
+ street: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET], ''),
+ city: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY], ''),
+ state: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE], ''),
+ zipCode: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE], ''),
+ };
+
+ return (
+
+ );
+}
+
+Address.propTypes = propTypes;
+Address.defaultProps = defaultProps;
+Address.displayName = 'Address';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+})(Address);
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/Confirmation.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Confirmation.js
new file mode 100644
index 000000000000..03d0ca5f5b25
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Confirmation.js
@@ -0,0 +1,139 @@
+import React, {useMemo} from 'react';
+import {ScrollView, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import Button from '@components/Button';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
+import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes';
+import getPersonalInfoValues from '@pages/ReimbursementAccount/utils/getPersonalInfoValues';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+const propTypes = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ /** The draft values of the bank account being setup */
+ reimbursementAccountDraft: reimbursementAccountDraftPropTypes,
+
+ ...subStepPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+ reimbursementAccountDraft: {},
+};
+
+function Confirmation({reimbursementAccount, reimbursementAccountDraft, onNext, onMove}) {
+ const {translate} = useLocalize();
+
+ const values = useMemo(() => getPersonalInfoValues(reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
+ const error = ErrorUtils.getLatestErrorMessage(reimbursementAccount);
+
+ return (
+
+
+ {translate('personalInfoStep.letsDoubleCheck')}
+ {
+ onMove(0);
+ }}
+ />
+ {
+ onMove(1);
+ }}
+ />
+ {
+ onMove(2);
+ }}
+ />
+ {
+ onMove(3);
+ }}
+ />
+
+
+ {`${translate('personalInfoStep.byAddingThisBankAccount')} `}
+
+ {translate('onfidoStep.facialScan')}
+
+ {', '}
+
+ {translate('common.privacy')}
+
+ {` ${translate('common.and')} `}
+
+ {translate('common.termsOfService')}
+
+
+
+ {error.length > 0 && (
+
+ )}
+
+
+
+
+ );
+}
+
+Confirmation.propTypes = propTypes;
+Confirmation.defaultProps = defaultProps;
+Confirmation.displayName = 'Confirmation';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+ reimbursementAccountDraft: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT,
+ },
+})(Confirmation);
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.js
new file mode 100644
index 000000000000..4a4e35cda463
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.js
@@ -0,0 +1,100 @@
+import {subYears} from 'date-fns';
+import lodashGet from 'lodash/get';
+import React from 'react';
+import {withOnyx} from 'react-native-onyx';
+import FormProvider from '@components/Form/FormProvider';
+import NewDatePicker from '@components/NewDatePicker';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import HelpLinks from '@pages/ReimbursementAccount/PersonalInfo/HelpLinks';
+import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
+import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+const propTypes = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ /** The draft values of the bank account being setup */
+ reimbursementAccountDraft: reimbursementAccountDraftPropTypes,
+
+ ...subStepPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+ reimbursementAccountDraft: {},
+};
+
+const REQUIRED_FIELDS = [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB];
+
+const validate = (values) => {
+ const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);
+
+ if (values.dob) {
+ if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) {
+ errors.dob = 'bankAccount.error.dob';
+ } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) {
+ errors.dob = 'bankAccount.error.age';
+ }
+ }
+
+ return errors;
+};
+
+function DateOfBirth({reimbursementAccount, reimbursementAccountDraft, onNext, isEditing}) {
+ const {translate} = useLocalize();
+
+ const dobDefaultValue =
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB], '') ||
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB, '');
+
+ const minDate = subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE);
+ const maxDate = subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT);
+
+ return (
+
+ {translate('personalInfoStep.enterYourDateOfBirth')}
+
+
+
+ );
+}
+
+DateOfBirth.propTypes = propTypes;
+DateOfBirth.defaultProps = defaultProps;
+DateOfBirth.displayName = 'DateOfBirth';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+ reimbursementAccountDraft: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT,
+ },
+})(DateOfBirth);
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.js
new file mode 100644
index 000000000000..15a22d4092d5
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.js
@@ -0,0 +1,86 @@
+import lodashGet from 'lodash/get';
+import React from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import Form from '@components/Form';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+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 styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+const propTypes = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ ...subStepPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+};
+
+const REQUIRED_FIELDS = [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME];
+
+const validate = (values) => ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);
+
+function FullName({reimbursementAccount, onNext, isEditing}) {
+ const {translate} = useLocalize();
+
+ const defaultValues = {
+ firstName: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME], ''),
+ lastName: lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME], ''),
+ };
+
+ return (
+
+ );
+}
+
+FullName.propTypes = propTypes;
+FullName.defaultProps = defaultProps;
+FullName.displayName = 'FullName';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+})(FullName);
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.js
new file mode 100644
index 000000000000..935565aff07a
--- /dev/null
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.js
@@ -0,0 +1,87 @@
+import lodashGet from 'lodash/get';
+import React from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import Form from '@components/Form';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+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 styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+const propTypes = {
+ /** Reimbursement account from ONYX */
+ reimbursementAccount: reimbursementAccountPropTypes,
+
+ ...subStepPropTypes,
+};
+
+const defaultProps = {
+ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
+};
+
+const REQUIRED_FIELDS = [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4];
+
+const validate = (values) => {
+ const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);
+
+ if (values.ssnLast4 && !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) {
+ errors.ssnLast4 = 'bankAccount.error.ssnLast4';
+ }
+
+ return errors;
+};
+function SocialSecurityNumber({reimbursementAccount, onNext, isEditing}) {
+ const {translate} = useLocalize();
+
+ const defaultSsnLast4 = lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4], '');
+
+ return (
+
+ );
+}
+
+SocialSecurityNumber.propTypes = propTypes;
+SocialSecurityNumber.defaultProps = defaultProps;
+SocialSecurityNumber.displayName = 'SocialSecurityNumber';
+
+export default withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+})(SocialSecurityNumber);
diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js
index 0eddb727d56d..92346aff73ee 100644
--- a/src/pages/ReimbursementAccount/RequestorStep.js
+++ b/src/pages/ReimbursementAccount/RequestorStep.js
@@ -1,110 +1,18 @@
-import _ from 'lodash';
import PropTypes from 'prop-types';
-import React, {useCallback, useMemo} from 'react';
-import {View} from 'react-native';
-import CheckboxWithLabel from '@components/CheckboxWithLabel';
-import Form from '@components/Form';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import ScreenWrapper from '@components/ScreenWrapper';
-import Text from '@components/Text';
-import TextLink from '@components/TextLink';
-import useLocalize from '@hooks/useLocalize';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import styles from '@styles/styles';
-import * as BankAccounts from '@userActions/BankAccounts';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import IdentityForm from './IdentityForm';
+import React from 'react';
+import PersonalInfo from './PersonalInfo/PersonalInfo';
import {reimbursementAccountPropTypes} from './reimbursementAccountPropTypes';
import RequestorOnfidoStep from './RequestorOnfidoStep';
const propTypes = {
onBackButtonPress: PropTypes.func.isRequired,
- getDefaultStateForField: PropTypes.func.isRequired,
reimbursementAccount: reimbursementAccountPropTypes.isRequired,
/** If we should show Onfido flow */
shouldShowOnfido: PropTypes.bool.isRequired,
};
-const REQUIRED_FIELDS = ['firstName', 'lastName', 'dob', 'ssnLast4', 'requestorAddressStreet', 'requestorAddressCity', 'requestorAddressState', 'requestorAddressZipCode'];
-const INPUT_KEYS = {
- firstName: 'firstName',
- lastName: 'lastName',
- dob: 'dob',
- ssnLast4: 'ssnLast4',
- street: 'requestorAddressStreet',
- city: 'requestorAddressCity',
- state: 'requestorAddressState',
- zipCode: 'requestorAddressZipCode',
-};
-const STEP_COUNTER = {step: 3, total: 5};
-
-const validate = (values) => {
- const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);
-
- if (values.dob) {
- if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) {
- errors.dob = 'bankAccount.error.dob';
- } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) {
- errors.dob = 'bankAccount.error.age';
- }
- }
-
- if (values.ssnLast4 && !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) {
- errors.ssnLast4 = 'bankAccount.error.ssnLast4';
- }
-
- if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) {
- errors.requestorAddressStreet = 'bankAccount.error.addressStreet';
- }
-
- if (values.requestorAddressZipCode && !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) {
- errors.requestorAddressZipCode = 'bankAccount.error.zipCode';
- }
-
- if (!ValidationUtils.isRequiredFulfilled(values.isControllingOfficer)) {
- errors.isControllingOfficer = 'requestorStep.isControllingOfficerError';
- }
-
- return errors;
-};
-
-function RequestorStep({reimbursementAccount, shouldShowOnfido, onBackButtonPress, getDefaultStateForField}) {
- const {translate} = useLocalize();
-
- const defaultValues = useMemo(
- () => ({
- firstName: getDefaultStateForField(INPUT_KEYS.firstName),
- lastName: getDefaultStateForField(INPUT_KEYS.lastName),
- street: getDefaultStateForField(INPUT_KEYS.street),
- city: getDefaultStateForField(INPUT_KEYS.city),
- state: getDefaultStateForField(INPUT_KEYS.state),
- zipCode: getDefaultStateForField(INPUT_KEYS.zipCode),
- dob: getDefaultStateForField(INPUT_KEYS.dob),
- ssnLast4: getDefaultStateForField(INPUT_KEYS.ssnLast4),
- }),
- [getDefaultStateForField],
- );
-
- const submit = useCallback(
- (values) => {
- const payload = {
- bankAccountID: _.get(reimbursementAccount, 'achData.bankAccountID', 0),
- ...values,
- };
-
- BankAccounts.updatePersonalInformationForBankAccount(payload);
- },
- [reimbursementAccount],
- );
-
- const renderLabelComponent = () => (
-
- {translate('requestorStep.isControllingOfficer')}
-
- );
-
+function RequestorStep({reimbursementAccount, shouldShowOnfido, onBackButtonPress}) {
if (shouldShowOnfido) {
return (
-
-
-
- );
+ return ;
}
RequestorStep.propTypes = propTypes;
diff --git a/src/pages/ReimbursementAccount/subStepPropTypes.js b/src/pages/ReimbursementAccount/subStepPropTypes.js
new file mode 100644
index 000000000000..3f7498c83202
--- /dev/null
+++ b/src/pages/ReimbursementAccount/subStepPropTypes.js
@@ -0,0 +1,14 @@
+import PropTypes from 'prop-types';
+
+const subStepPropTypes = {
+ /** is substep being edited from confirmation screen */
+ isEditing: PropTypes.bool.isRequired,
+
+ /** method that navigates to next substep */
+ onNext: PropTypes.func.isRequired,
+
+ /** method that navigates to passed step from confirmation screen */
+ onMove: PropTypes.func.isRequired,
+};
+
+export default subStepPropTypes;
diff --git a/src/pages/ReimbursementAccount/utils/getInitialSubstepForPersonalInfo.js b/src/pages/ReimbursementAccount/utils/getInitialSubstepForPersonalInfo.js
new file mode 100644
index 000000000000..f9f1e351902a
--- /dev/null
+++ b/src/pages/ReimbursementAccount/utils/getInitialSubstepForPersonalInfo.js
@@ -0,0 +1,35 @@
+import CONST from '@src/CONST';
+
+/**
+ * Returns the initial substep for the Personal Info step based on already existing data
+ *
+ * @param {Object} data object that stores personal info data
+ *
+ * @returns {number}
+ */
+function getInitialSubstepForPersonalInfo(data) {
+ if (data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME] === undefined && data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME] === undefined) {
+ return 0;
+ }
+
+ if (data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB] === undefined) {
+ return 1;
+ }
+
+ if (data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4] === undefined) {
+ return 2;
+ }
+
+ if (
+ data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET] === undefined ||
+ data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY] === undefined ||
+ data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE] === undefined ||
+ data[CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE] === undefined
+ ) {
+ return 3;
+ }
+
+ return 4;
+}
+
+export default getInitialSubstepForPersonalInfo;
diff --git a/src/pages/ReimbursementAccount/utils/getPersonalInfoValues.js b/src/pages/ReimbursementAccount/utils/getPersonalInfoValues.js
new file mode 100644
index 000000000000..30ea1165ecb6
--- /dev/null
+++ b/src/pages/ReimbursementAccount/utils/getPersonalInfoValues.js
@@ -0,0 +1,42 @@
+import lodashGet from 'lodash/get';
+import CONST from '@src/CONST';
+
+/**
+ * Returns values for personal info step
+ *
+ * @param {Object} reimbursementAccountDraft object that stores personal info draft data
+ *
+ * @param {Object} reimbursementAccount object that stores personal info data
+ *
+ * @returns {Object}
+ */
+function getPersonalInfoValues(reimbursementAccountDraft, reimbursementAccount) {
+ return {
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.FIRST_NAME], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.LAST_NAME], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.DOB], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.SSN_LAST_4], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STREET], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.CITY], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.STATE], ''),
+ [CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE]:
+ lodashGet(reimbursementAccountDraft, CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE, '') ||
+ lodashGet(reimbursementAccount, ['achData', CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY.ZIP_CODE], ''),
+ };
+}
+
+export default getPersonalInfoValues;
diff --git a/src/stories/InteractiveStepSubHeader.stories.js b/src/stories/InteractiveStepSubHeader.stories.js
index ab27037771b1..64ee76edb5d7 100644
--- a/src/stories/InteractiveStepSubHeader.stories.js
+++ b/src/stories/InteractiveStepSubHeader.stories.js
@@ -1,8 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, {useRef} from 'react';
-import {View, Button} from 'react-native';
-
-import InteractiveStepSubHeader from '../components/InteractiveStepSubHeader';
+import {Button, View} from 'react-native';
+import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
/**
* We use the Component Story Format for writing stories. Follow the docs here: