lbry-desktop/ui/js/component/cardVerify/view.jsx
2017-07-18 19:00:13 -04:00

377 lines
7.6 KiB
JavaScript

import React from "react";
import PropTypes from "prop-types";
import Link from "component/link";
let scriptLoading = false;
let scriptLoaded = false;
let scriptDidError = false;
class CardVerify extends React.Component {
static defaultProps = {
label: "Verify",
locale: "auto",
};
static propTypes = {
// If included, will render the default blue button with label text.
// (Requires including stripe-checkout.css or adding the .styl file
// to your pipeline)
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,
// ==========================
// Highly Recommended Options
// ==========================
// Name of the company or website.
name: PropTypes.string,
// A description of the product or service being purchased.
description: PropTypes.string,
// Specify auto to display Checkout in the user's preferred language, if
// available. English will be used by default.
//
// https://stripe.com/docs/checkout#supported-languages
// for more info.
locale: PropTypes.oneOf([
"auto", // (Default) Automatically chosen by checkout
"zh", // Simplified Chinese
"da", // Danish
"nl", // Dutch
"en", // English
"fr", // French
"de", // German
"it", // Italian
"ja", // Japanease
"no", // Norwegian
"es", // Spanish
"sv", // Swedish
]),
// ==============
// Optional Props
// ==============
// The currency of the amount (3-letter ISO code). The default is USD.
currency: PropTypes.oneOf([
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BIF",
"BMD",
"BND",
"BOB",
"BRL",
"BSD",
"BWP",
"BZD",
"CAD",
"CDF",
"CHF",
"CLP",
"CNY",
"COP",
"CRC",
"CVE",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EEK",
"EGP",
"ETB",
"EUR",
"FJD",
"FKP",
"GBP",
"GEL",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"ISK",
"JMD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KRW",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LVL",
"MAD",
"MDL",
"MGA",
"MKD",
"MNT",
"MOP",
"MRO",
"MUR",
"MVR",
"MWK",
"MXN",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SEK",
"SGD",
"SHP",
"SLL",
"SOS",
"SRD",
"STD",
"SVC",
"SZL",
"THB",
"TJS",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"UYU",
"UZS",
"VND",
"VUV",
"WST",
"XAF",
"XCD",
"XOF",
"XPF",
"YER",
"ZAR",
"ZMW",
]),
// The label of the payment button in the Checkout form (e.g. “Subscribe”,
// “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced
// by the provided amount. Otherwise, the amount will be appended to the
// end of your label.
panelLabel: PropTypes.string,
};
constructor(props) {
super(props);
this.state = {
open: false,
};
}
componentDidMount() {
if (scriptLoaded) {
return;
}
if (scriptLoading) {
return;
}
scriptLoading = true;
const script = document.createElement("script");
script.src = "https://checkout.stripe.com/checkout.js";
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) => {
promise.then(
() => (canceled ? cancel({ isCanceled: true }) : accept())
);
promise.catch(
error => (canceled ? cancel({ isCanceled: true }) : cancel(error))
);
});
return {
promise: wrappedPromise,
cancel() {
canceled = true;
},
};
})();
this.loadPromise.promise
.then(this.onScriptLoaded)
.catch(this.onScriptError);
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) => {
throw new Error("Unable to load credit validation script.");
};
onClosed = () => {
this.setState({ open: false });
};
getConfig = () =>
["token", "name", "description"].reduce(
(config, key) =>
Object.assign(
{},
config,
this.props.hasOwnProperty(key) && {
[key]: this.props[key],
}
),
{
allowRememberMe: false,
closed: this.onClosed,
description: __("Confirm Identity"),
email: this.props.email,
panelLabel: "Verify",
}
);
updateStripeHandler() {
if (!CardVerify.stripeHandler) {
CardVerify.stripeHandler = StripeCheckout.configure({
key: this.props.stripeKey,
});
}
}
showStripeDialog() {
this.setState({ open: true });
CardVerify.stripeHandler.open(this.getConfig());
}
onClick = () => {
if (scriptDidError) {
try {
throw new Error(
"Tried to call onClick, but StripeCheckout failed to load"
);
} catch (x) {}
} else if (CardVerify.stripeHandler) {
this.showStripeDialog();
} else {
this.hasPendingClick = true;
}
};
render() {
return (
<Link
button="primary"
label={this.props.label}
disabled={
this.props.disabled || this.state.open || this.hasPendingClick
}
onClick={this.onClick.bind(this)}
/>
);
}
}
export default CardVerify;