Skip to content

Commit

Permalink
Sync with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
mountiny committed Dec 29, 2023
2 parents 06b826b + 68b0160 commit 943863d
Show file tree
Hide file tree
Showing 46 changed files with 873 additions and 1,054 deletions.
8 changes: 8 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@ const CONST = {
EXIT: 'EXIT',
},
},
COMPLETE_VERIFICATION: {
INPUT_KEY: {
BANK_ACCOUNT_ID: 'bankAccountID',
IS_AUTHORIZED_TO_USE_BANK_ACCOUNT: 'isAuthorizedToUseBankAccount',
CERTIFY_TRUE_INFORMATION: 'certifyTrueInformation',
ACCEPT_TERMS_AND_CONDITIONS: 'acceptTermsAndConditions',
},
},
ERROR: {
MISSING_ROUTING_NUMBER: '402 Missing routingNumber',
MAX_ROUTING_NUMBER: '402 Maximum Size Exceeded routingNumber',
Expand Down
30 changes: 18 additions & 12 deletions src/components/DatePicker/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {setYear} from 'date-fns';
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, {forwardRef, useState} from 'react';
import React, {forwardRef, useEffect, useState} from 'react';
import {View} from 'react-native';
import * as Expensicons from '@components/Icon/Expensicons';
import refPropTypes from '@components/refPropTypes';
Expand Down Expand Up @@ -37,6 +37,12 @@ const propTypes = {
/** A maximum date of calendar to select */
maxDate: PropTypes.objectOf(Date),

/** A function that is passed by FormWrapper */
onInputChange: PropTypes.func.isRequired,

/** A function that is passed by FormWrapper */
onTouched: PropTypes.func.isRequired,

/** Saves a draft of the input value when used in a form */
shouldSaveDraft: PropTypes.bool,

Expand All @@ -56,6 +62,7 @@ const datePickerDefaultProps = {
};

function DatePicker({
forwardedRef,
containerStyles,
defaultValue,
disabled,
Expand All @@ -68,7 +75,6 @@ function DatePicker({
onInputChange,
onTouched,
placeholder,
translate,
value,
shouldSaveDraft,
formID,
Expand All @@ -77,6 +83,16 @@ function DatePicker({
const {translate} = useLocalize();
const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined);

const onSelected = (newValue) => {
if (_.isFunction(onTouched)) {
onTouched();
}
if (_.isFunction(onInputChange)) {
onInputChange(newValue);
}
setSelectedDate(newValue);
};

useEffect(() => {
// Value is provided to input via props and onChange never fires. We have to save draft manually.
if (shouldSaveDraft && formID !== '') {
Expand All @@ -90,16 +106,6 @@ function DatePicker({
setSelectedDate(value);
}, [formID, inputID, selectedDate, shouldSaveDraft, value]);

useEffect(() => {
if (_.isFunction(onTouched)) {
onTouched();
}
if (_.isFunction(onInputChange)) {
onInputChange(newValue);
}
setSelectedDate(newValue);
};

return (
<View style={styles.datePickerRoot}>
<View style={[isSmallScreenWidth ? styles.flex2 : {}, styles.pointerEventsNone]}>
Expand Down
10 changes: 5 additions & 5 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ type UnresponsiveProps = {

type IconProps = {
/** Flag to choose between avatar image or an icon */
iconType: typeof CONST.ICON_TYPE_ICON;
iconType?: typeof CONST.ICON_TYPE_ICON;

/** Icon to display on the left side of component */
icon: IconAsset;
};

type AvatarProps = {
iconType: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
iconType?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;

icon: AvatarSource;
};
Expand Down Expand Up @@ -85,7 +85,7 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
titleStyle?: ViewStyle;

/** Any adjustments to style when menu item is hovered or pressed */
hoverAndPressStyle: StyleProp<AnimatedStyle<ViewStyle>>;
hoverAndPressStyle?: StyleProp<AnimatedStyle<ViewStyle>>;

/** Additional styles to style the description text below the title */
descriptionTextStyle?: StyleProp<TextStyle>;
Expand Down Expand Up @@ -175,7 +175,7 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
isSelected?: boolean;

/** Prop to identify if we should load avatars vertically instead of diagonally */
shouldStackHorizontally: boolean;
shouldStackHorizontally?: boolean;

/** Prop to represent the size of the avatar images to be shown */
avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
Expand Down Expand Up @@ -220,7 +220,7 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
furtherDetails?: string;

/** The function that should be called when this component is LongPressed or right-clicked. */
onSecondaryInteraction: () => void;
onSecondaryInteraction?: () => void;

/** Array of objects that map display names to their corresponding tooltip */
titleWithTooltips: DisplayNameWithTooltip[];
Expand Down
11 changes: 3 additions & 8 deletions src/hooks/useSubStep.ts → src/hooks/useSubStep/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import {ReactNode, useCallback, useRef, useState} from 'react';
import {useCallback, useRef, useState} from 'react';
import type {UseSubStep} from './types';

type Props = {
bodyContent: ReactNode[];
onFinished: () => void;
startFrom?: number;
};

export default function useSubStep({bodyContent, onFinished, startFrom = 0}: Props) {
export default function useSubStep({bodyContent, onFinished, startFrom = 0}: UseSubStep) {
const [screenIndex, setScreenIndex] = useState(startFrom);
const isEditing = useRef(false);

Expand Down
31 changes: 31 additions & 0 deletions src/hooks/useSubStep/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {ComponentType} from 'react';

type SubStepProps = {
/** value indicating whether user is editing one of the sub steps */
isEditing: boolean;

/** continues to next sub step */
onNext: () => void;

/** moves user to passed sub step */
onMove: (step: number) => void;

/** index of currently displayed sub step */
screenIndex?: number;

/** moves user to previous sub step */
prevScreen?: () => void;
};

type UseSubStep = {
/** array of components that will become sub steps */
bodyContent: Array<ComponentType<SubStepProps>>;

/** called on last sub step */
onFinished: () => void;

/** index of initial sub step to display */
startFrom?: number;
};

export type {SubStepProps, UseSubStep};
23 changes: 21 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1536,10 +1536,29 @@ export default {
confirmAgreements: 'Please confirm the agreements below.',
certifyTrueAndAccurate: 'I certify that the information provided is true and accurate',
certifyTrueAndAccurateError: 'Must certify information is true and accurate',
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.',
isAuthorizedToUseBankAccount: 'I am authorized to use my company bank account for business spend',
isAuthorizedToUseBankAccountError: 'You must be a controlling officer with authorization to operate the business bank account.',
termsAndConditions: 'terms and conditions',
},
connectBankAccountStep: {
connectBankAccount: 'Connect bank account',
finishButtonText: 'Finish setup',
validateYourBankAccount: 'Validate your bank account',
validateButtonText: 'Validate',
validationInputLabel: 'Transaction',
maxAttemptsReached: 'Validation for this bank account has been disabled due to too many incorrect attempts.',
description: 'A day or two after you add your account to Expensify we send three (3) transactions to your account. They have a merchant line like "Expensify, Inc. Validation".',
descriptionCTA: 'Please enter each transaction amount in the fields below. Example: 1.51.',
reviewingInfo: "Thanks! We're reviewing your information, and will be in touch shortly. Please check your chat with Concierge ",
forNextSteps: ' for next steps to finish setting up your bank account.',
letsChatCTA: "Yes, let's chat",
letsChatText: 'Thanks for doing that. We need your help verifying a few pieces of information, but we can work this out quickly over chat. Ready?',
letsChatTitle: "Let's chat!",
enable2FATitle: 'Prevent fraud, enable two-factor authentication!',
enable2FAText:
'We take your security seriously, so please set up two-factor authentication for your account now. That will allow us to dispute Expensify Card digital transactions, and will reduce your risk for fraud.',
secureYourAccount: 'Secure your account',
},
reimbursementAccountLoadingAnimation: {
oneMoment: 'One moment',
explanationLine: 'We’re taking a look at your information. You will be able to continue with next steps shortly.',
Expand Down
34 changes: 27 additions & 7 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1555,13 +1555,33 @@ export default {
},
},
completeVerificationStep: {
completeVerification: 'Complete verification',
confirmAgreements: 'Please confirm the agreements below.',
certifyTrueAndAccurate: 'I certify that the information provided is true and accurate',
certifyTrueAndAccurateError: 'Must certify information is true and accurate',
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.',
termsAndConditions: 'terms and conditions',
completeVerification: 'Completar la verificación',
confirmAgreements: 'Por favor, confirma los Acuerdos a continuación.',
certifyTrueAndAccurate: 'Certifico que la información dada es verdadera y precisa',
certifyTrueAndAccurateError: 'Debe certificar que la información es verdadera y precisa',
isAuthorizedToUseBankAccount: 'Estoy autorizado para usar la cuenta bancaria de mi empresa para gastos comerciales',
isAuthorizedToUseBankAccountError: 'Debes ser un oficial controlador con autorización para operar la cuenta bancaria de la empresa.',
termsAndConditions: 'Términos y Condiciones',
},
connectBankAccountStep: {
connectBankAccount: 'Conectar cuenta bancaria',
finishButtonText: 'Finalizar configuración',
validateYourBankAccount: 'Valida tu cuenta bancaria',
validateButtonText: 'Validar',
validationInputLabel: 'Transacción',
maxAttemptsReached: 'La validación para esta cuenta bancaria se ha desactivado debido a demasiados intentos incorrectos.',
description:
'Un día o dos después de agregar tu cuenta a Expensify, enviamos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".',
descriptionCTA: 'Ingresa el importe de cada transacción en los campos a continuación. Ejemplo: 1.51.',
reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ',
forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.',
letsChatCTA: 'Sí, vamos a chatear',
letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos resolver esto rápidamente a través del chat. ¿Estás Listo?',
letsChatTitle: '¡Vamos a chatear!',
enable2FATitle: '¡Evita fraudes, habilita la autenticación de dos factores!',
enable2FAText:
'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.',
secureYourAccount: 'Asegura tu cuenta',
},
reimbursementAccountLoadingAnimation: {
oneMoment: 'Un momento',
Expand Down
15 changes: 13 additions & 2 deletions src/libs/actions/BankAccounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ type ReimbursementAccountStep = BankAccountStep | '';

type ReimbursementAccountSubStep = BankAccountSubStep | '';

type PlaidBankAccountToConnect = Omit<PlaidBankAccount, 'isSavings' | 'addressName' | 'mask'>;

type BusinessAddress = {
addressStreet?: string;
addressCity?: string;
addressState?: string;
addressZipCode?: string;
};

function clearPlaid(): Promise<void> {
Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, '');
Onyx.set(ONYXKEYS.PLAID_CURRENT_EVENT, null);
Expand Down Expand Up @@ -131,7 +140,7 @@ function addBusinessWebsiteForDraft(website: string) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, {website});
}

function addBusinessAddressForDraft(businessAddress: {addressStreet?: string; addressCity?: string; addressState?: string; addressZipCode?: string}) {
function addBusinessAddressForDraft(businessAddress: BusinessAddress) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, businessAddress);
}

Expand All @@ -142,7 +151,7 @@ function addPersonalAddressForDraft(personalAddress: {requestorAddressStreet?: s
/**
* Submit Bank Account step with Plaid data so php can perform some checks.
*/
function connectBankAccountWithPlaid(bankAccountID: number, selectedPlaidBankAccount: PlaidBankAccount) {
function connectBankAccountWithPlaid(bankAccountID: number, selectedPlaidBankAccount: PlaidBankAccountToConnect) {
const commandName = 'ConnectBankAccountWithPlaid';

type ConnectBankAccountWithPlaidParams = {
Expand Down Expand Up @@ -486,3 +495,5 @@ export {
verifyIdentityForBankAccount,
setReimbursementAccountLoading,
};

export type {BusinessAddress};
2 changes: 1 addition & 1 deletion src/libs/actions/ReimbursementAccount/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export {setBankAccountFormValidationErrors, setPersonalBankAccountFormValidation
* - CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL to ask them to enter their accountNumber and routingNumber
* - CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID to ask them to login to their bank via Plaid
*
* @param {String} subStep
* @param {String | null} subStep
*/
function setBankAccountSubStep(subStep) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {subStep}});
Expand Down
8 changes: 7 additions & 1 deletion src/pages/ReimbursementAccount/ACHContractStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ const propTypes = {

function ACHContractStep({onBackButtonPress, onCloseButtonPress}) {
const [isBeneficialOwnerInfoSet, setIsBeneficialOwnerInfoSet] = useState(false);
const handleCompleteVerificationBackButtonPress = () => setIsBeneficialOwnerInfoSet(false);

if (isBeneficialOwnerInfoSet) {
return <CompleteVerification setIsBeneficialOwnerInfoSet={setIsBeneficialOwnerInfoSet} />;
return (
<CompleteVerification
onBackButtonPress={handleCompleteVerificationBackButtonPress}
onCloseButtonPress={onCloseButtonPress}
/>
);
}

return (
Expand Down
Loading

0 comments on commit 943863d

Please sign in to comment.