Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PersonalInfo Step #30576

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
24 changes: 22 additions & 2 deletions src/components/Form/FormWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]),

Expand All @@ -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(() => {
Expand Down Expand Up @@ -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
Expand All @@ -150,6 +169,7 @@ function FormWrapper(props) {
isSubmitActionDangerous,
isSubmitButtonVisible,
onSubmit,
submitButtonStyles,
style,
submitButtonText,
],
Expand Down
15 changes: 7 additions & 8 deletions src/components/InteractiveStepSubHeader.js
Original file line number Diff line number Diff line change
@@ -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 */
Expand Down
36 changes: 34 additions & 2 deletions src/components/NewDatePicker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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,
};
Expand All @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useSubStep.js
Original file line number Diff line number Diff line change
@@ -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 */
Expand Down
18 changes: 17 additions & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
18 changes: 17 additions & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you get these translations verified in Slack?

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',
Expand Down
2 changes: 0 additions & 2 deletions src/pages/ReimbursementAccount/AddressForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]}
/>
</>
Expand Down
51 changes: 51 additions & 0 deletions src/pages/ReimbursementAccount/PersonalInfo/HelpLinks.js
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we prefer passing the translate function here instead of using the hook here?

};

const defaultProps = {
containerStyles: [],
};

function HelpLinks({containerStyles, translate}) {
return (
<View style={[styles.flexRow, styles.alignItemsCenter, containerStyles]}>
<Icon src={Expensicons.QuestionMark} />
<View style={[styles.ml2, styles.dFlex, styles.flexRow]}>
<TextLink
style={[styles.textMicro]}
href={CONST.BANK_ACCOUNT_PERSONAL_DOCUMENTATION_INFO_URL}
>
{translate('requestorStep.learnMore')}
</TextLink>
<Text style={[styles.textMicroSupporting]}>{' | '}</Text>
<TextLink
style={[styles.textMicro, styles.textLink]}
href={CONST.PERSONAL_DATA_PROTECTION_INFO_URL}
>
{translate('requestorStep.isMyDataSafe')}
</TextLink>
</View>
</View>
);
}

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

export default HelpLinks;
Loading
Loading