diff --git a/src/index.js b/src/index.js
index 94dea87..a0bfb3b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -119,7 +119,12 @@ type State = {
cardNumberLength: number,
cardNumber: ?string,
errorText: ?string,
- showZip: boolean
+ showZip: boolean,
+ cardNumberInvalid: boolean,
+ cardExpiryInvalid: boolean,
+ cardCVCInvalid: boolean,
+ cardZipInvalid: boolean,
+ valid: boolean
};
const inputRenderer = ({ props }: Object) => ;
@@ -163,7 +168,12 @@ class CreditCardInput extends Component {
cardNumberLength: 0,
cardNumber: null,
errorText: null,
- showZip: false
+ showZip: false,
+ cardNumberInvalid: false,
+ cardExpiryInvalid: false,
+ cardCVCInvalid: false,
+ cardZipInvalid: false,
+ valid: true
};
}
@@ -225,7 +235,7 @@ class CreditCardInput extends Component {
this.setState({ showZip: cardNumberLength >= 6 });
}
- this.setFieldValid();
+ this.setFieldValid('cardNumber');
if (cardTypeLengths) {
const lastCardTypeLength = cardTypeLengths[cardTypeLengths.length - 1];
for (let length of cardTypeLengths) {
@@ -286,7 +296,7 @@ class CreditCardInput extends Component {
this.cardExpiryField.value = formatExpiry(cardExpiry);
- this.setFieldValid();
+ this.setFieldValid('cardExpiry');
const expiryError = isExpiryInvalid(
cardExpiry,
@@ -341,7 +351,7 @@ class CreditCardInput extends Component {
const isZipFieldAvailable = this.props.enableZipInput && this.state.showZip;
const cardType = payment.fns.cardType(this.state.cardNumber);
- this.setFieldValid();
+ this.setFieldValid('cardCVC');
if (CVCLength >= 4) {
if (!payment.fns.validateCardCVC(CVC, cardType)) {
this.setFieldInvalid(
@@ -395,7 +405,7 @@ class CreditCardInput extends Component {
const zip = e.target.value;
const zipLength = zip.length;
- this.setFieldValid();
+ this.setFieldValid('cardZip');
if (zipLength >= 5 && !isZipValid(zip)) {
this.setFieldInvalid(
@@ -429,11 +439,42 @@ class CreditCardInput extends Component {
};
};
+ handleValidityStatusChange = () => {
+ const { onValidityStatusChange, enableZipInput } = this.props;
+ const {
+ cardNumberInvalid,
+ cardExpiryInvalid,
+ cardCVCInvalid,
+ cardZipInvalid
+ } = this.state;
+
+ const valid =
+ !cardNumberInvalid &&
+ !cardExpiryInvalid &&
+ !cardCVCInvalid &&
+ (enableZipInput ? !cardZipInvalid : true);
+ const statusHasChanged = this.state.valid !== valid;
+
+ this.setState({
+ valid: valid
+ });
+
+ if (onValidityStatusChange && statusHasChanged) {
+ onValidityStatusChange(valid);
+ }
+ };
+
setFieldInvalid = (errorText: string, inputName?: string) => {
const { invalidClassName, onError } = this.props;
// $FlowFixMe
document.getElementById('field-wrapper').classList.add(invalidClassName);
- this.setState({ errorText });
+ this.setState(
+ {
+ errorText,
+ [`${inputName}Invalid`]: true
+ },
+ this.handleValidityStatusChange
+ );
if (inputName) {
const { onError } = this.props[`${inputName}InputProps`];
@@ -445,11 +486,17 @@ class CreditCardInput extends Component {
}
};
- setFieldValid = () => {
+ setFieldValid = (inputName?: string) => {
const { invalidClassName } = this.props;
// $FlowFixMe
document.getElementById('field-wrapper').classList.remove(invalidClassName);
- this.setState({ errorText: null });
+ this.setState(
+ {
+ errorText: null,
+ [`${inputName}Invalid`]: false
+ },
+ this.handleValidityStatusChange
+ );
};
render = () => {
diff --git a/src/index.stories.js b/src/index.stories.js
index 1bc4ffc..7e7fb4e 100644
--- a/src/index.stories.js
+++ b/src/index.stories.js
@@ -32,6 +32,7 @@ storiesOf('CreditCardInput', module)
onChange: e => console.log('number change', e),
onError: err => console.log(`number error: ${err}`)
}}
+ onValidityStatusChange={valid => console.log(`Is valid: ${valid}`)}
/>
))