Skip to content

Commit

Permalink
Implemented card expiry validation with better error messages (closes
Browse files Browse the repository at this point in the history
  • Loading branch information
teobais authored and jxom committed Mar 18, 2018
1 parent f67ebdb commit dfc260c
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 8 deletions.
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[ignore]
.*/node_modules/config-chain/.*

[include]

Expand Down
86 changes: 86 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"eslint": "^4.11.0",
"eslint-config-react-app": "^2.0.1",
"eslint-plugin-flowtype": "^2.39.1",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-react": "^7.4.0",
Expand Down
20 changes: 12 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import creditCardType from 'credit-card-type';
import styled from 'styled-components';

import images from './utils/images';
import isExpiryInvalid from './utils/is-expiry-invalid';

const Container = styled.div`
display: inline-block;
Expand Down Expand Up @@ -184,8 +185,10 @@ class CreditCardInput extends Component<Props, State> {
};

handleCardExpiryBlur = (e: SyntheticInputEvent<*>) => {
if (!payment.fns.validateCardExpiry(e.target.value)) {
this.setFieldInvalid('Expiry date is invalid');
const cardExpiry = e.target.value.split(' / ').join('/');
const expiryError = isExpiryInvalid(cardExpiry);
if (expiryError) {
this.setFieldInvalid(expiryError);
}

const { cardExpiryInputProps } = this.props;
Expand All @@ -195,16 +198,17 @@ class CreditCardInput extends Component<Props, State> {
};

handleCardExpiryChange = (e: SyntheticInputEvent<*>) => {
const cardExpiry = e.target.value;
const cardExpiryLength = cardExpiry.split(' / ').join('').length;
const cardExpiry = e.target.value.split(' / ').join('/');
payment.formatCardExpiry(document.getElementById('card-expiry'));

this.setFieldValid();
if (cardExpiryLength >= 4) {
if (payment.fns.validateCardExpiry(cardExpiry)) {
this.cvcField.focus();

const expiryError = isExpiryInvalid(cardExpiry);
if (cardExpiry.length > 4) {
if (expiryError) {
this.setFieldInvalid(expiryError);
} else {
this.setFieldInvalid('Expiry date is invalid');
this.cvcField.focus();
}
}

Expand Down
32 changes: 32 additions & 0 deletions src/utils/is-expiry-invalid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// @flow

const ERROR_TEXT__INVALID_EXPIRY_DATE = 'Expiry date is invalid';
const ERROR_TEXT__MONTH_OUT_OF_RANGE = 'Expiry month must be between 01 and 12';
const ERROR_TEXT__YEAR_OUT_OF_RANGE = 'Expiry year cannot be in the past';

const EXPIRY_DATE_REGEX = /^(\d{2})\/(\d{4}|\d{2})$/;
const MONTH_REGEX = /(0[1-9]|1[0-2])/;

export default (expiryDate: string) => {
const splitDate = expiryDate.split('/');
if (!EXPIRY_DATE_REGEX.test(expiryDate)) {
return ERROR_TEXT__INVALID_EXPIRY_DATE;
}

const expiryMonth = splitDate[0];
if (!MONTH_REGEX.test(expiryMonth)) {
return ERROR_TEXT__MONTH_OUT_OF_RANGE;
}

const expiryYear = splitDate[1];
let currentYear = new Date().getFullYear();
currentYear = parseInt(
expiryYear.length === 4 ? currentYear : currentYear.toString().substr(-2),
10
);
if (currentYear > parseInt(expiryYear, 10)) {
return ERROR_TEXT__YEAR_OUT_OF_RANGE;
}

return false;
};

0 comments on commit dfc260c

Please sign in to comment.