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

Update Add Debit Card form to match VBA styles #5940

Merged
merged 38 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7238347
add back functionality to add debit card form
Jag96 Oct 12, 2021
7517045
add required fields
Jag96 Oct 12, 2021
9905fd4
update validate to check multiple fields
Jag96 Oct 12, 2021
c039913
add error text translations and getError func
Jag96 Oct 12, 2021
50396e1
update error state on submit only
Jag96 Oct 12, 2021
db58ee3
fix imports/order
Jag96 Oct 18, 2021
d287b7d
update all form components
Jag96 Oct 18, 2021
1b1e695
add number pad const
Jag96 Oct 18, 2021
9d8136c
update styles and add form alert
Jag96 Oct 19, 2021
25ed399
Merge branch 'main' into joe-update-add-debit-form
Jag96 Oct 19, 2021
b59665e
fix scrollTo bug
Jag96 Oct 19, 2021
76d4c51
fix alignment for textLink
Jag96 Oct 19, 2021
36c2440
remove unused function, update error messages
Jag96 Oct 19, 2021
23361a8
update expirationDate logic to allow multiple formats
Jag96 Oct 19, 2021
1920496
confirm expiration date is in the future
Jag96 Oct 19, 2021
cf4fa1f
add tests
Jag96 Oct 19, 2021
c3d8aaf
remove unused translations, update expiration date hint
Jag96 Oct 19, 2021
886ca9a
update setstate calls for error alert
Jag96 Oct 19, 2021
b15bb30
fix moment deprecated warning
Jag96 Oct 19, 2021
9ee27f5
add loading indicator and error handling
Jag96 Oct 20, 2021
a2e4cde
re-add expiration date separator hanlder
Jag96 Oct 20, 2021
aed717e
merge main
Jag96 Oct 20, 2021
36c379d
fix infinite spinner bug
Jag96 Oct 20, 2021
82c5717
merge main
Jag96 Oct 25, 2021
7357314
add translations to payment options
Jag96 Oct 25, 2021
2ab2122
add onyx key
Jag96 Oct 25, 2021
a7b3bfd
update submitting key
Jag96 Oct 25, 2021
e46a120
show api error message
Jag96 Oct 26, 2021
37ed496
fix translateX for mobile devices
Jag96 Oct 26, 2021
b4fe64b
update onyx key to specify form
Jag96 Oct 26, 2021
38cc5cc
capitalize cardUtils
Jag96 Oct 26, 2021
adca837
remove unnecessary catch
Jag96 Oct 26, 2021
a2818be
move onyx merge/set into actions
Jag96 Oct 26, 2021
b52de92
use sentence case
Jag96 Oct 26, 2021
9a31b62
use addressSearch component
Jag96 Oct 26, 2021
2615711
use the last of the month for expiration
Jag96 Oct 26, 2021
804c0e4
allow any separator for expiration date
Jag96 Oct 26, 2021
e2897a5
remove expiration date modifier
Jag96 Oct 26, 2021
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
3 changes: 2 additions & 1 deletion src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ const CONST = {
KEYBOARD_TYPE: {
NUMERIC: 'numeric',
PHONE_PAD: 'phone-pad',
NUMBER_PAD: 'number-pad',
},

ATTACHMENT_PICKER_TYPE: {
Expand Down Expand Up @@ -443,7 +444,7 @@ const CONST = {
NUMBER: /^[0-9]+$/,
CARD_NUMBER: /^[0-9]{15,16}$/,
CARD_SECURITY_CODE: /^[0-9]{3,4}$/,
CARD_EXPIRATION_DATE: /(0[1-9]|10|11|12)\/20[0-9]{2}$/,
CARD_EXPIRATION_DATE: /^(0[1-9]|1[0-2])([^0-9])?([0-9]{4}|([0-9]{2}))$/,
PAYPAL_ME_USERNAME: /^[a-zA-Z0-9]+$/,

// Adapted from: https://gist.github.com/dperini/729294
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,7 @@ export default {

// Set when we are loading payment methods
IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods',

// Stores values for the add debit card form
ADD_DEBIT_CARD_FORM: 'addDebitCardForm',
};
6 changes: 6 additions & 0 deletions src/components/FormAlertWithSubmitButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ const propTypes = {
/** Styles for container element */
containerStyles: PropTypes.arrayOf(PropTypes.object),

/** Is the button in a loading state */
isLoading: PropTypes.bool,

...withLocalizePropTypes,
};

Expand All @@ -45,6 +48,7 @@ const defaultProps = {
isDisabled: false,
isMessageHtml: false,
containerStyles: [],
isLoading: false,
};

const FormAlertWithSubmitButton = ({
Expand All @@ -57,6 +61,7 @@ const FormAlertWithSubmitButton = ({
message,
isMessageHtml,
containerStyles,
isLoading,
}) => {
/**
* @returns {React.Component}
Expand Down Expand Up @@ -114,6 +119,7 @@ const FormAlertWithSubmitButton = ({
text={buttonText}
onPress={onSubmit}
isDisabled={isDisabled}
isLoading={isLoading}
/>
</View>
);
Expand Down
25 changes: 12 additions & 13 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ export default {
confirm: 'Confirm',
reset: 'Reset',
done: 'Done',
debitCard: 'Debit card',
payPalMe: 'PayPal.me/',
},
attachmentPicker: {
cameraPermissionRequired: 'Camera permission required',
Expand Down Expand Up @@ -279,32 +281,29 @@ export default {
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Enter your username to get paid back via PayPal.',
payPalMe: 'PayPal.me/',
yourPayPalUsername: 'Your PayPal username',
addPayPalAccount: 'Add PayPal account',
editPayPalAccount: 'Update PayPal account',
growlMessageOnSave: 'Your PayPal username was successfully added',
formatError: 'Invalid PayPal.me username',
},
addDebitCardPage: {
addADebitCard: 'Add a Debit Card',
nameOnCard: 'Name on Card',
debitCardNumber: 'Debit Card Number',
expiration: 'Expiration',
expirationDate: 'MM/YYYY',
addADebitCard: 'Add a debit card',
nameOnCard: 'Name on card',
debitCardNumber: 'Debit card number',
expiration: 'Expiration date',
expirationDate: 'MM/YY',
cvv: 'CVV',
billingAddress: 'Billing Address',
streetAddress: 'Street Address',
cityName: 'City Name',
expensifyTermsOfService: 'Expensify Terms Of Service',
billingAddress: 'Billing address',
expensifyTermsOfService: 'Expensify Terms of Service',
growlMessageOnSave: 'Your debit card was successfully added',
error: {
invalidName: 'Please add a valid name',
zipCode: 'Please enter a valid zip code',
invalidName: 'Please enter a valid name',
addressZipCode: 'Please enter a valid zip code',
debitCardNumber: 'Please enter a valid debit card number',
expirationDate: 'Please enter a valid expiration date',
securityCode: 'Please enter a valid security code',
address: 'Please enter a valid billing address',
addressStreet: 'Please enter a valid billing address that is not a PO Box',
addressState: 'Please select a state',
addressCity: 'Please enter a city',
acceptedTerms: 'You must accept the Terms of Service to continue',
Expand Down
15 changes: 7 additions & 8 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ export default {
confirm: 'Confirmar',
reset: 'Restablecer',
done: 'Listo',
debitCard: 'Tarjeta de débito',
payPalMe: 'PayPal.me/',
},
attachmentPicker: {
cameraPermissionRequired: 'Se necesita permiso para usar la cámara',
Expand Down Expand Up @@ -279,7 +281,6 @@ export default {
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Escribe tu nombre de usuario para que otros puedan pagarte a través de PayPal.',
payPalMe: 'PayPal.me/',
yourPayPalUsername: 'Tu usuario de PayPal',
addPayPalAccount: 'Agregar cuenta de PayPal',
growlMessageOnSave: 'Su nombre de usuario de PayPal se agregó correctamente',
Expand All @@ -290,21 +291,19 @@ export default {
addADebitCard: 'Agregar una tarjeta de débito',
nameOnCard: 'Nombre en la tarjeta',
debitCardNumber: 'Numero de la tarjeta de débito',
expiration: 'Vencimiento',
expiration: 'Fecha de vencimiento',
expirationDate: 'MM/AA',
cvv: 'CVV',
billingAddress: 'Dirección de Envio',
streetAddress: 'Dirección',
cityName: 'Nombre de la ciudad',
billingAddress: 'Dirección de envio',
expensifyTermsOfService: 'Expensify Términos de servicio',
growlMessageOnSave: 'Su tarteja de débito se agregó correctamente',
error: {
invalidName: 'Por favor agregue un nombre válido',
zipCode: 'Por favor ingrese un código postal válido',
invalidName: 'Por favor ingrese un nombre válido',
addressZipCode: 'Por favor ingrese un código postal válido',
debitCardNumber: 'Ingrese un número de tarjeta de débito válido',
expirationDate: 'Por favor introduzca una fecha de vencimiento válida',
securityCode: 'Ingrese un código de seguridad válido',
address: 'Ingrese una dirección de facturación válida',
addressStreet: 'Ingrese una dirección de facturación válida que no sea un apartado postal',
addressState: 'Por favor seleccione un estado',
addressCity: 'Por favor ingrese una ciudad',
acceptedTerms: 'Debes aceptar los Términos de servicio para continuar',
Expand Down
39 changes: 39 additions & 0 deletions src/libs/CardUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Returns the masked card number (ex: 4242XXXXXXXX4242)
*
* @param {String} cardNumber
* @return {Boolean}
*/
function maskCardNumber(cardNumber) {
const firstFour = cardNumber.substring(0, 4);
const lastFour = cardNumber.substring(cardNumber.length - 4);

return `${firstFour}${'X'.repeat(cardNumber.length - 8)}${lastFour}`;
}

/**
* @param {String} expirationDateString - string in MM/YYYY, MM/YY, MMYY, or MMYYYY format
* @returns {String}
*/
function getMonthFromExpirationDateString(expirationDateString) {
return expirationDateString.substr(0, 2);
}

/**
* @param {String} expirationDateString - string in MMYY or MMYYYY format, with any non-number separator
* @returns {String}
*/
function getYearFromExpirationDateString(expirationDateString) {
const stringContainsNumbersOnly = /^\d+$/.test(expirationDateString);
const cardYear = stringContainsNumbersOnly
? expirationDateString.substr(2)
: expirationDateString.substr(3);

return cardYear.length === 2 ? `20${cardYear}` : cardYear;
}

export {
maskCardNumber,
getMonthFromExpirationDateString,
getYearFromExpirationDateString,
};
17 changes: 13 additions & 4 deletions src/libs/ValidationUtils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import moment from 'moment';
import _ from 'underscore';
import CONST from '../CONST';

import {getMonthFromExpirationDateString, getYearFromExpirationDateString} from './CardUtils';

/**
* Implements the Luhn Algorithm, a checksum formula used to validate credit card
Expand Down Expand Up @@ -76,14 +76,23 @@ function isRequiredFulfilled(value) {
}

/**
* Validates that this is a valid expiration date
* in the MM/YY or MM/YYYY format
* Validates that this is a valid expiration date. Supports the following formats:
* 1. MM/YY
* 2. MM/YYYY
* 3. MMYY
* 4. MMYYYY
*
* @param {String} string
* @returns {Boolean}
*/
function isValidExpirationDate(string) {
return CONST.REGEX.CARD_EXPIRATION_DATE.test(string);
if (!CONST.REGEX.CARD_EXPIRATION_DATE.test(string)) {
return false;
}

// Use the last of the month to check if the expiration date is in the future or not
const expirationDate = `${getYearFromExpirationDateString(string)}-${getMonthFromExpirationDateString(string)}-01`;
return moment(expirationDate).endOf('month').isAfter(moment());
}

/**
Expand Down
34 changes: 26 additions & 8 deletions src/libs/actions/PaymentMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ROUTES from '../../ROUTES';
import Growl from '../Growl';
import {translateLocal} from '../translate';
import Navigation from '../Navigation/Navigation';
import {maskCardNumber} from '../cardUtils';
import {maskCardNumber, getMonthFromExpirationDateString, getYearFromExpirationDateString} from '../CardUtils';

/**
* Calls the API to get the user's bankAccountList, cardList, wallet, and payPalMe
Expand Down Expand Up @@ -41,28 +41,30 @@ function getPaymentMethods() {
* @param {Object} params
*/
function addBillingCard(params) {
const cardYear = params.expirationDate.substr(3);
const cardMonth = params.expirationDate.substr(0, 2);
const cardMonth = getMonthFromExpirationDateString(params.expirationDate);
const cardYear = getYearFromExpirationDateString(params.expirationDate);

Onyx.merge(ONYXKEYS.ADD_DEBIT_CARD_FORM, {submitting: true});
API.AddBillingCard({
cardNumber: params.cardNumber,
cardYear,
cardMonth,
cardCVV: params.securityCode,
addressName: params.nameOnCard,
addressZip: params.zipCode,
addressZip: params.addressZipCode,
currency: CONST.CURRENCY.USD,
}).then(((response) => {
let errorMessage = '';
if (response.jsonCode === 200) {
const cardObject = {
additionalData: {
isBillingCard: false,
isP2PDebitCard: true,
},
addressName: params.nameOnCard,
addressState: params.selectedState,
addressStreet: params.billingAddress,
addressZip: params.zipCode,
addressState: params.addressState,
addressStreet: params.addressStreet,
addressZip: params.addressZipCode,
cardMonth,
cardNumber: maskCardNumber(params.cardNumber),
cardYear,
Expand All @@ -73,12 +75,28 @@ function addBillingCard(params) {
Growl.show(translateLocal('addDebitCardPage.growlMessageOnSave'), CONST.GROWL.SUCCESS, 3000);
Navigation.navigate(ROUTES.SETTINGS_PAYMENTS);
} else {
Growl.error(translateLocal('addDebitCardPage.error.genericFailureMessage', 3000));
errorMessage = response.message ? response.message : translateLocal('addDebitCardPage.error.genericFailureMessage');
marcaaron marked this conversation as resolved.
Show resolved Hide resolved
}

Onyx.merge(ONYXKEYS.ADD_DEBIT_CARD_FORM, {
submitting: false,
error: errorMessage,
});
}));
}

/**
* Resets the values for the add debit card form back to their initial states
*/
function clearDebitCardFormErrorAndSubmit() {
Onyx.set(ONYXKEYS.ADD_DEBIT_CARD_FORM, {
submitting: false,
error: '',
});
}

export {
getPaymentMethods,
addBillingCard,
clearDebitCardFormErrorAndSubmit,
};
17 changes: 0 additions & 17 deletions src/libs/cardUtils.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/pages/EnablePayments/AdditionalDetailsStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class AdditionalDetailsStep extends React.Component {
label: props.translate('common.ssnLast4'),
fieldName: 'ssn',
maxLength: 4,
keyboardType: 'number-pad',
keyboardType: CONST.KEYBOARD_TYPE.NUMBER_PAD,
},
];

Expand Down
4 changes: 2 additions & 2 deletions src/pages/ReimbursementAccount/BankAccountStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ class BankAccountStep extends React.Component {
/>
<ExpensiTextInput
label={this.props.translate('bankAccount.routingNumber')}
keyboardType="number-pad"
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
value={this.state.routingNumber}
onChangeText={value => this.clearErrorAndSetValue('routingNumber', value)}
disabled={shouldDisableInputs}
Expand All @@ -272,7 +272,7 @@ class BankAccountStep extends React.Component {
<ExpensiTextInput
containerStyles={[styles.mt4]}
label={this.props.translate('bankAccount.accountNumber')}
keyboardType="number-pad"
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
value={this.state.accountNumber}
onChangeText={value => this.clearErrorAndSetValue('accountNumber', value)}
disabled={shouldDisableInputs}
Expand Down
Loading