react-tap-payment
Version:
ReactJS library for implementing TAP payment gateway
430 lines (416 loc) • 15.3 kB
JavaScript
'use strict';
var React = require('react');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
const l = {
// checkoutURL: "https://tap-checkout.netlify.app/",
checkoutURL: "https://checkout.touchandpay.me/"
// checkoutURL: "http://localhost:3050/",
};
class u {
constructor(t) {
this.iframe = null, this.background = null, this.iframeLoaded = false, this.isIframeOpen = false, this.transactionDefaults = t, this.checkoutLoaded = false, this.checkoutRemoved = false, this.fallback = h(), this.initializeCheckout(), this.listenForEvents();
}
/**
* Set new transaction parameters and update the iframe
*/
setTransaction(t) {
this.transactionDefaults && this.resetCheckout(), this.transactionDefaults = t, this.updateIframe();
}
/**
* Initializes the checkout iframe and background
*/
initializeCheckout() {
this.createPopupBackground();
}
/**
* Fetch transaction parameters, excluding unwanted fields
*/
getTransactionParameters() {
if (!this.transactionDefaults)
return null;
this.transactionDefaults.metadata.referrer = v();
const t = [
"customButton",
"onClose",
"callback",
"tlsFallback"
], i = f(this.transactionDefaults, t);
return i.mode = "popup", i.hasTLSFallback = !!this.transactionDefaults.tlsFallback, i.metadata && typeof i.metadata != "string" && (i.metadata = JSON.stringify(i.metadata)), i.split && typeof i.split != "string" && Object.keys(i.split).length > 0 && (i.split = JSON.stringify(i.split)), i;
}
/**
* Updates the iframe content with new transaction details
*/
updateIframe() {
const t = this.getTransactionParameters(), i = t ? "newTransaction" : "popup";
setTimeout(() => {
this.iframe.contentWindow.postMessage(
{
type: "inline:url",
path: i,
params: t
},
"*"
);
}, 3e3);
}
/**
* Listen for events from the iframe
*/
listenForEvents() {
const t = this;
window.addEventListener(
"message",
(i) => {
!t.isEmbed && !t.checkoutRemoved && t.handleCheckoutEvents(i);
},
false
);
}
/**
* Open the iframe for a new checkout
*/
openIframe() {
this.showCheckout();
}
/**
* Creates the background and iframe for the popup
*/
createPopupBackground() {
const t = document.createElement("iframe");
t.setAttribute("frameBorder", "0"), t.setAttribute("allowtransparency", "true"), t.id = d(), t.name = "checkout-background-" + t.id, t.style.cssText = `
z-index: 999999999999999;
background: rgba(0, 0, 0, 0.75);
border: none;
overflow-x: hidden;
overflow-y: hidden;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
visibility: hidden;
display: none;
transition: opacity 0.3s;
`, this.background = t, document.body.appendChild(t);
const i = this.background.contentWindow.document;
i.open(), i.write(P()), i.close();
const n = document.createElement("iframe");
n.setAttribute("frameBorder", "0"), n.setAttribute("allowtransparency", "true"), n.setAttribute("allowpaymentrequest", "true"), n.id = d(), n.name = "checkout-" + n.id, n.style.cssText = `
z-index: 999999999999999;
background: transparent;
border: none;
overflow-x: hidden;
overflow-y: hidden;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
visibility: hidden;
display: none;
`, n.src = l.checkoutURL + "popup", this.iframe = n, document.body.appendChild(n);
}
/**
* Opens the checkout iframe and displays the background
*/
showCheckout() {
!this.iframe || this.isIframeOpen || (this.background.style.display = "", this.background.style.visibility = "visible", this.iframe.style.display = "", this.iframe.contentWindow.postMessage("render", "*"), this.isIframeOpen = true);
}
/**
* Remove the loader once the transaction is loaded
*/
removeLoader() {
this.iframe.style.visibility = "visible";
const t = this.background.contentWindow.document.getElementById("app-loader");
t && (t.style.display = "none");
}
/**
* Handles events received from the iframe, such as success or closing the iframe
*/
handleCheckoutEvents(t) {
if (t.origin + "/" === l.checkoutURL && this.iframe.contentWindow === t.source) {
const i = t.data || t.message;
try {
i && i.response.success.status === 1 && (this.closeCheckout(!0), this.handleSuccess(i));
} catch {
}
switch (i) {
case "loaded:transaction":
this.removeLoader();
break;
case "close":
this.closeCheckout(), this.transactionDefaults.onClose && this.transactionDefaults.onClose.call(this);
break;
}
}
}
/**
* Closes the checkout iframe
*/
closeCheckout(t = false) {
this.background.style.opacity = 0, this.iframe.style.display = "none", this.iframe.contentWindow.postMessage("close", "*"), this.isIframeOpen = false, setTimeout(() => {
this.resetBackground();
}, 300);
}
/**
* Resets the iframe and background to initial state
*/
resetCheckout() {
this.resetIframe(), this.resetBackground();
}
/**
* Resets the visibility of the main iframe
*/
resetIframe() {
this.iframe.style.visibility = "hidden", this.transactionDefaults = null, this.updateIframe();
}
/**
* Resets the background and loader
*/
resetBackground() {
this.background.style.display = "none", this.background.style.opacity = 1, this.background.contentWindow.document.getElementById(
"app-loader"
).style.display = "block";
}
/**
* Handles successful transactions
*/
handleSuccess(t) {
this.transactionDefaults.callback && this.transactionDefaults.callback.call(this, t);
}
/**
* Clean up resources
*/
destroy() {
this.messageHandler && this.eventListenerAdded && (window.removeEventListener("message", this.messageHandler), this.eventListenerAdded = false, this.messageHandler = null), this.iframe && (this.iframe.remove(), this.iframe = null), this.background && (this.background.remove(), this.background = null), this.iframeLoaded = false, this.isIframeOpen = false, this.checkoutRemoved = true;
}
}
let o;
const r = {
isInitialized: false,
initialize(e) {
o = new u(e), this.isInitialized = true;
},
setup(e, t) {
const i = {
apiKey: e.apiKey || "",
// required
transID: e.transID || "",
// required
amount: e.amount || "",
// required
email: e.email || "",
// required
env: e.env || "",
phone: e.phone || "",
savePaymentDetails: e.savePaymentDetails || false,
customerReference: e.customerReference || "",
metadata: e.metadata || {},
onClose: e.onClose || "",
callback: e.callback || "",
tlsFallback: e.tlsFallback || "",
customPayload: {
email: e.email,
...e.customPayload || {}
// Ensure customPayload is an object
}
};
if (m(i) && (this.isInitialized ? o.setTransaction(i) : this.initialize(i), !t))
return o;
},
destroy() {
o && (o.destroy(), o = null), this.isInitialized = false;
}
};
function c() {
return typeof window < "u" ? window : {};
}
if (typeof c() < "u") {
const e = c();
e.TAPPaymentPop = r, e.onload = () => {
r.isInitialized || r.initialize();
};
}
function d() {
let e = "";
const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 5; i++)
e += t.charAt(Math.floor(Math.random() * t.length));
return e;
}
function h() {
const e = "onload" in document.createElement("iframe");
return e || console.warn(
"This browser does not support iframes. Please redirect to standard"
), !e;
}
function f(e, t) {
const i = JSON.parse(JSON.stringify(e));
return t.forEach((n) => {
delete i[n];
}), Object.keys(i).forEach((n) => {
(i[n] === null || i[n] === void 0 || i[n].length === 0) && delete i[n];
}), i;
}
function m(e) {
if (p(e), e.apiKey === null)
throw new Error("Please provide your public key via the key attribute");
if (e.amount === null)
throw new Error("Please provide transaction amount via the amount");
if (e.email === null)
throw new Error(
"Please provide customer email via the email or customerCode attribute"
);
if (e.savePaymentDetails) {
if (!e.customerReference)
throw new Error(
"Please provide customerReference when savePaymentDetails is true."
);
if (!e.phone)
throw new Error("Please provide phone when savePaymentDetails is true.");
}
return true;
}
function p(e) {
const t = {
email: "email",
amount: "integer",
onClose: "function",
callback: "function"
};
for (const s in e)
e.hasOwnProperty(s) && i(s, e[s]);
function i(s, a) {
if (t[s] && a)
switch (t[s]) {
case "email":
y(a) || n(s);
break;
case "integer":
b(a) || n(s);
break;
case "function":
g(a) || n(s);
break;
case "object":
k(a) || n(s);
break;
case "array":
w(a) || n(s);
}
}
function n(s) {
const a = t[s];
throw alert(`Attribute ${s} must be a valid ${a}`), new Error(`Attribute ${s} must be a valid ${a}`);
}
}
function y(e) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);
}
function b(e) {
return /^\d+$/.test(e);
}
function g(e) {
return typeof e == "function";
}
function k(e) {
return e !== null && typeof e == "object";
}
function w(e) {
return Array.isArray(e);
}
function v() {
return window.location.href;
}
function P() {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Loading...</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { display: flex; justify-content: center; align-items: center; height: 100vh; background: rgba(0, 0, 0, 0.50); }
.loader { width: 50px; height: 50px; border: 5px solid white; border-top-color: transparent; border-radius: 50%; animation: spin 1s linear infinite; }
spin { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div class="loader" id="app-loader"></div>
</body>
</html>
`;
}
var callTAPPaymentPop = function (tapPaymentArgs) {
var handler = r.setup(tapPaymentArgs);
handler.openIframe();
};
function useTAPPayment(hookConfig) {
function initializePayment(_a) {
var config = _a.config, onSuccess = _a.onSuccess, onClose = _a.onClose;
var args = __assign(__assign({}, hookConfig), config);
var apiKey = args.apiKey, amount = args.amount, transID = args.transID, firstname = args.firstname, lastname = args.lastname, phone = args.phone, email = args.email, env = args.env, savePaymentDetails = args.savePaymentDetails, customerReference = args.customerReference, billerID = args.billerID, productID = args.productID, metadata = args.metadata, label = args.label, quantity = args.quantity, rest = __rest(args, ["apiKey", "amount", "transID", "firstname", "lastname", "phone", "email", "env", "savePaymentDetails", "customerReference", "billerID", "productID", "metadata", "label", "quantity"]);
var tapPaymentArgs = {
callback: onSuccess ? onSuccess : function () { return null; },
onClose: onClose ? onClose : function () { return null; },
apiKey: apiKey,
transID: transID,
email: email,
amount: amount,
env: env,
phone: phone !== null && phone !== void 0 ? phone : undefined,
savePaymentDetails: savePaymentDetails !== null && savePaymentDetails !== void 0 ? savePaymentDetails : undefined,
customerReference: customerReference !== null && customerReference !== void 0 ? customerReference : undefined,
customPayload: __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({}, (firstname && { firstname: firstname })), (lastname && { lastname: lastname })), (email && { email: email })), (phone && { phone: phone })), (billerID && { billerID: billerID })), (productID && { productID: productID })), (metadata && { metadata: metadata })), (label && { label: label })), (quantity && { quantity: quantity })), (rest && __assign({}, rest)))
};
callTAPPaymentPop(tapPaymentArgs);
}
return initializePayment;
}
var TAPPaymentButton = function (_a) {
var text = _a.text, className = _a.className, children = _a.children, onSuccess = _a.onSuccess, onClose = _a.onClose, disabled = _a.disabled, config = __rest(_a, ["text", "className", "children", "onSuccess", "onClose", "disabled"]);
var initializePayment = useTAPPayment(config);
return (React.createElement("button", { className: className, onClick: function () { return initializePayment({ config: config, onSuccess: onSuccess, onClose: onClose }); }, disabled: disabled }, text || children));
};
exports.TAPPaymentButton = TAPPaymentButton;
exports.useTAPPayment = useTAPPayment;
//# sourceMappingURL=index.js.map