Skip to content

Commit

Permalink
Merge pull request #52078 from Expensify/cmartins-fixAlgo
Browse files Browse the repository at this point in the history
[CP Staging] Fix credit card validation
  • Loading branch information
luacmartins authored Nov 5, 2024
2 parents b80559d + 3615239 commit 83f2258
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
24 changes: 16 additions & 8 deletions src/components/AddPaymentCard/PaymentCardForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,26 @@ function PaymentCardForm({
};

const onChangeCardNumber = useCallback((newValue: string) => {
// replace all characters that are not spaces or digits
// Replace all characters that are not spaces or digits
let validCardNumber = newValue.replace(/[^\d ]/g, '');

// gets only the first 16 digits if the inputted number have more digits than that
// Gets only the first 16 digits if the inputted number have more digits than that
validCardNumber = validCardNumber.match(/(?:\d *){1,16}/)?.[0] ?? '';

// add the spacing between every 4 digits
validCardNumber =
validCardNumber
.replace(/ /g, '')
.match(/.{1,4}/g)
?.join(' ') ?? '';
// Remove all spaces to simplify formatting
const cleanedNumber = validCardNumber.replace(/ /g, '');

// Check if the number is a potential Amex card (starts with 34 or 37 and has up to 15 digits)
const isAmex = /^3[47]\d{0,13}$/.test(cleanedNumber);

// Format based on Amex or standard 4-4-4-4 pattern
if (isAmex) {
// Format as 4-6-5 for Amex
validCardNumber = cleanedNumber.replace(/(\d{1,4})(\d{1,6})?(\d{1,5})?/, (match, p1, p2, p3) => [p1, p2, p3].filter(Boolean).join(' '));
} else {
// Format as 4-4-4-4 for non-Amex
validCardNumber = cleanedNumber.match(/.{1,4}/g)?.join(' ') ?? '';
}

setCardNumber(validCardNumber);
}, []);
Expand Down
16 changes: 12 additions & 4 deletions src/libs/ValidationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,24 @@ import StringUtils from './StringUtils';
*/
function validateCardNumber(value: string): boolean {
let sum = 0;
for (let i = 0; i < value.length; i++) {
let intVal = parseInt(value.substr(i, 1), 10);
if (i % 2 === 0) {
let shouldDouble = false;

// Loop through the card number from right to left
for (let i = value.length - 1; i >= 0; i--) {
let intVal = parseInt(value[i], 10);

// Double every second digit from the right
if (shouldDouble) {
intVal *= 2;
if (intVal > 9) {
intVal = 1 + (intVal % 10);
intVal -= 9;
}
}

sum += intVal;
shouldDouble = !shouldDouble;
}

return sum % 10 === 0;
}

Expand Down

0 comments on commit 83f2258

Please sign in to comment.