2017-12-21 22:08:54 +01:00
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Button from 'component/button';
|
|
|
|
import * as icons from 'constants/icons';
|
2017-07-19 01:00:13 +02:00
|
|
|
|
|
|
|
let scriptLoading = false;
|
|
|
|
let scriptLoaded = false;
|
|
|
|
let scriptDidError = false;
|
|
|
|
|
|
|
|
class CardVerify extends React.Component {
|
|
|
|
static propTypes = {
|
2017-07-27 20:42:43 +02:00
|
|
|
disabled: PropTypes.bool,
|
|
|
|
|
2017-07-19 01:00:13 +02:00
|
|
|
label: PropTypes.string,
|
|
|
|
|
|
|
|
// =====================================================
|
|
|
|
// Required by stripe
|
|
|
|
// see Stripe docs for more info:
|
|
|
|
// https://stripe.com/docs/checkout#integration-custom
|
|
|
|
// =====================================================
|
|
|
|
|
|
|
|
// Your publishable key (test or live).
|
|
|
|
// can't use "key" as a prop in react, so have to change the keyname
|
|
|
|
stripeKey: PropTypes.string.isRequired,
|
|
|
|
|
|
|
|
// The callback to invoke when the Checkout process is complete.
|
|
|
|
// function(token)
|
|
|
|
// token is the token object created.
|
|
|
|
// token.id can be used to create a charge or customer.
|
|
|
|
// token.email contains the email address entered by the user.
|
|
|
|
token: PropTypes.func.isRequired,
|
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
open: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
if (scriptLoaded) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scriptLoading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
scriptLoading = true;
|
|
|
|
|
2017-12-21 22:08:54 +01:00
|
|
|
const script = document.createElement('script');
|
|
|
|
script.src = 'https://checkout.stripe.com/checkout.js';
|
2017-07-19 01:00:13 +02:00
|
|
|
script.async = 1;
|
|
|
|
|
|
|
|
this.loadPromise = (() => {
|
|
|
|
let canceled = false;
|
|
|
|
const promise = new Promise((resolve, reject) => {
|
|
|
|
script.onload = () => {
|
|
|
|
scriptLoaded = true;
|
|
|
|
scriptLoading = false;
|
|
|
|
resolve();
|
|
|
|
this.onScriptLoaded();
|
|
|
|
};
|
|
|
|
script.onerror = event => {
|
|
|
|
scriptDidError = true;
|
|
|
|
scriptLoading = false;
|
|
|
|
reject(event);
|
|
|
|
this.onScriptError(event);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
const wrappedPromise = new Promise((accept, cancel) => {
|
2017-12-21 22:08:54 +01:00
|
|
|
promise.then(() => (canceled ? cancel({ isCanceled: true }) : accept()));
|
|
|
|
promise.catch(error => (canceled ? cancel({ isCanceled: true }) : cancel(error)));
|
2017-07-19 01:00:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
promise: wrappedPromise,
|
|
|
|
cancel() {
|
|
|
|
canceled = true;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
2017-12-21 22:08:54 +01:00
|
|
|
this.loadPromise.promise.then(this.onScriptLoaded).catch(this.onScriptError);
|
2017-07-19 01:00:13 +02:00
|
|
|
|
|
|
|
document.body.appendChild(script);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
if (!scriptLoading) {
|
|
|
|
this.updateStripeHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
if (this.loadPromise) {
|
|
|
|
this.loadPromise.cancel();
|
|
|
|
}
|
|
|
|
if (CardVerify.stripeHandler && this.state.open) {
|
|
|
|
CardVerify.stripeHandler.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onScriptLoaded = () => {
|
|
|
|
if (!CardVerify.stripeHandler) {
|
|
|
|
CardVerify.stripeHandler = StripeCheckout.configure({
|
|
|
|
key: this.props.stripeKey,
|
|
|
|
});
|
|
|
|
if (this.hasPendingClick) {
|
|
|
|
this.showStripeDialog();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onScriptError = (...args) => {
|
2017-12-21 22:08:54 +01:00
|
|
|
throw new Error('Unable to load credit validation script.');
|
2017-07-19 01:00:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
onClosed = () => {
|
|
|
|
this.setState({ open: false });
|
|
|
|
};
|
|
|
|
|
|
|
|
updateStripeHandler() {
|
|
|
|
if (!CardVerify.stripeHandler) {
|
|
|
|
CardVerify.stripeHandler = StripeCheckout.configure({
|
|
|
|
key: this.props.stripeKey,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
showStripeDialog() {
|
|
|
|
this.setState({ open: true });
|
2017-07-25 20:59:47 +02:00
|
|
|
CardVerify.stripeHandler.open({
|
|
|
|
allowRememberMe: false,
|
|
|
|
closed: this.onClosed,
|
2017-12-21 22:08:54 +01:00
|
|
|
description: __('Confirm Identity'),
|
2017-07-25 20:59:47 +02:00
|
|
|
email: this.props.email,
|
2017-12-21 22:08:54 +01:00
|
|
|
locale: 'auto',
|
|
|
|
panelLabel: 'Verify',
|
2017-07-25 20:59:47 +02:00
|
|
|
token: this.props.token,
|
2017-07-27 20:42:43 +02:00
|
|
|
zipCode: true,
|
2017-07-25 20:59:47 +02:00
|
|
|
});
|
2017-07-19 01:00:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
onClick = () => {
|
|
|
|
if (scriptDidError) {
|
|
|
|
try {
|
2017-12-21 22:08:54 +01:00
|
|
|
throw new Error('Tried to call onClick, but StripeCheckout failed to load');
|
2017-07-19 01:00:13 +02:00
|
|
|
} catch (x) {}
|
|
|
|
} else if (CardVerify.stripeHandler) {
|
|
|
|
this.showStripeDialog();
|
|
|
|
} else {
|
|
|
|
this.hasPendingClick = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
2018-03-26 23:32:43 +02:00
|
|
|
<Button
|
2017-08-26 05:21:26 +02:00
|
|
|
button="alt"
|
2017-07-19 01:00:13 +02:00
|
|
|
label={this.props.label}
|
2018-03-26 23:32:43 +02:00
|
|
|
icon={icons.LOCK}
|
2017-12-21 22:08:54 +01:00
|
|
|
disabled={this.props.disabled || this.state.open || this.hasPendingClick}
|
2017-07-19 01:00:13 +02:00
|
|
|
onClick={this.onClick.bind(this)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default CardVerify;
|