tap-payment-popupjs
Version:
library for loading TAP's payment checkout gateway.
355 lines (354 loc) • 11.7 kB
JavaScript
const c = {
// checkoutURL: "https://tap-checkout.netlify.app/",
checkoutURL: "https://checkout.touchandpay.me/"
// checkoutURL: "http://localhost:3050/",
};
class u {
/**
* Constructor for the InlinePayment class.
* @param {object} transactionDefaults - Default transaction parameters.
*/
constructor(t) {
this.iframe = null, this.background = null, this.isIframeOpen = !1, this.transactionDefaults = t, this.checkoutRemoved = !1, this.fallback = h(), this.messageHandler = null, this.initializeCheckout(), this.listenForEvents();
}
/**
* Sets new transaction parameters and updates the iframe.
* If a transaction already exists, it resets the checkout before setting the new one.
* @param {object} transactionDefaults - The new transaction parameters.
*/
setTransaction(t) {
this.transactionDefaults && this.resetCheckout(), this.transactionDefaults = t, this.updateIframe();
}
/**
* Initializes the checkout by creating the popup background.
*/
initializeCheckout() {
this.createPopupBackground();
}
/**
* Prepares and returns the transaction parameters to be sent to the iframe.
* It excludes internal fields and formats metadata and split fields.
* @returns {object|null} The transaction parameters or null if not set.
*/
getTransactionParameters() {
if (!this.transactionDefaults)
return null;
const t = ["onClose", "callback"];
return f(this.transactionDefaults, t);
}
/**
* Sends a message to the iframe to update its content with new transaction details.
*/
updateIframe() {
const t = this.getTransactionParameters();
setTimeout(() => {
this.iframe.contentWindow.postMessage(
{
params: t
},
"*"
);
}, 3e3);
}
/**
* Sets up a window event listener to handle messages from the checkout iframe.
*/
listenForEvents() {
this.messageHandler = (t) => {
this.checkoutRemoved || this.handleCheckoutEvents(t);
}, window.addEventListener("message", this.messageHandler, !1);
}
/**
* Opens the iframe to start a new checkout process.
*/
openIframe() {
this.showCheckout();
}
/**
* Creates the background and checkout iframes and appends them to the document body.
* The background iframe contains a loading spinner.
*/
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 n = this.background.contentWindow.document;
n.open(), n.write(v()), n.close();
const i = document.createElement("iframe");
i.setAttribute("frameBorder", "0"), i.setAttribute("allowtransparency", "true"), i.setAttribute("allowpaymentrequest", "true"), i.id = d(), i.name = "checkout-" + i.id, i.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;
`, i.src = c.checkoutURL + "popup", this.iframe = i, document.body.appendChild(i);
}
/**
* Displays the checkout iframe and the background overlay.
*/
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 = !0);
}
/**
* Hides the loading spinner in the background iframe 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 checkout iframe, such as success or close events.
* @param {MessageEvent} event - The event object from the message listener.
*/
handleCheckoutEvents(t) {
if (t.origin + "/" === c.checkoutURL && this.iframe.contentWindow === t.source) {
const n = t.data || t.message;
try {
n && n.response.success.status === 1 && (this.closeCheckout(!0), this.handleSuccess(n));
} catch {
}
switch (n) {
case "loaded:transaction":
this.removeLoader();
break;
case "close":
this.closeCheckout();
break;
}
}
}
/**
* Closes the checkout iframe and hides the background.
* @param {boolean} [success=false] - Indicates if the checkout was closed due to a successful transaction.
*/
closeCheckout(t = !1) {
this.background.style.opacity = 0, this.iframe.style.display = "none", this.iframe.contentWindow.postMessage("close", "*"), this.isIframeOpen = !1, !t && this.transactionDefaults.onClose && this.transactionDefaults.onClose.call(this), setTimeout(() => {
this.resetBackground();
}, 300);
}
/**
* Resets the iframe and background to their initial states.
*/
resetCheckout() {
this.resetIframe(), this.resetBackground();
}
/**
* Resets the main checkout iframe's visibility and clears transaction data.
*/
resetIframe() {
this.iframe.style.visibility = "hidden", this.transactionDefaults = null, this.updateIframe();
}
/**
* Resets the background iframe to its initial state, showing the loader.
*/
resetBackground() {
this.background.style.display = "none", this.background.style.opacity = 1, this.background.contentWindow.document.getElementById(
"app-loader"
).style.display = "block";
}
/**
* Handles the callback for a successful transaction.
* @param {object} response - The success response from the checkout iframe.
*/
handleSuccess(t) {
this.transactionDefaults.callback && this.transactionDefaults.callback.call(this, t);
}
/**
* Cleans up all resources, removing event listeners and DOM elements.
*/
destroy() {
this.messageHandler && (window.removeEventListener("message", this.messageHandler), this.messageHandler = null), this.iframe && (this.iframe.remove(), this.iframe = null), this.background && (this.background.remove(), this.background = null), this.isIframeOpen = !1, this.checkoutRemoved = !0;
}
}
let a;
const r = {
isInitialized: !1,
/**
* Initializes the inline payment system with default transaction parameters.
* @param {object} transactionDefaults - Default transaction parameters.
*/
initialize(e) {
a = new u(e), console.log("TAPPaymentPop initialized"), this.isInitialized = !0;
},
/**
* Sets up a new transaction. If not initialized, it will initialize first.
* @param {object} transactionDetails - The details for the transaction.
* @returns {InlinePayment|undefined} The instance of InlinePayment or undefined.
*/
setup(e) {
const t = {
apiKey: e.apiKey || "",
// required
transID: e.transID || "",
// required
amount: e.amount || "",
// required
email: e.email || "",
// required
env: e.env || "",
phone: e.phone || "",
superAgentFee: e.superAgentFee || "",
savePaymentDetails: e.savePaymentDetails || !1,
customerReference: e.customerReference || "",
onClose: e.onClose || "",
callback: e.callback || "",
customPayload: {
email: e.email,
...e.customPayload || {}
// Ensure customPayload is an object
}
};
if (m(t))
return this.isInitialized ? (console.log("Setting transaction parameters"), a.setTransaction(t)) : (console.log("Initializing inline payment with parameters"), this.initialize(t)), a;
},
/**
* Destroys the current inline payment instance and cleans up resources.
*/
destroy() {
a && (a.destroy(), a = null), this.isInitialized = !1;
}
};
function l() {
return typeof window < "u" ? window : {};
}
if (typeof l() < "u") {
const e = l();
e.TAPPaymentPop = r, e.onload = () => {
r.isInitialized || r.initialize();
};
}
function d() {
let e = "";
const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let n = 0; n < 5; n++)
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 n = JSON.parse(JSON.stringify(e));
return t.forEach((i) => {
delete n[i];
}), Object.keys(n).forEach((i) => {
(n[i] === null || n[i] === void 0 || n[i].length === 0) && delete n[i];
}), n;
}
function m(e) {
if (p(e), !e.apiKey)
throw new Error("Please provide your public key via the key attribute");
if (!e.amount)
throw new Error("Please provide transaction amount via the amount");
if (!e.email)
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 !0;
}
function p(e) {
const t = {
email: "email",
amount: "number",
superAgentFee: "number",
onClose: "function",
callback: "function"
};
for (const s in e)
e.hasOwnProperty(s) && n(s, e[s]);
function n(s, o) {
if (t[s] && o)
switch (t[s]) {
case "email":
y(o) || i(s);
break;
case "number":
b(o) || i(s);
break;
case "function":
g(o) || i(s);
break;
case "object":
w(o) || i(s);
break;
case "array":
k(o) || i(s);
}
}
function i(s) {
const o = t[s];
throw alert(`Attribute ${s} must be a valid ${o}`), new Error(`Attribute ${s} must be a valid ${o}`);
}
}
function y(e) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);
}
function b(e) {
const t = typeof e == "string" ? parseFloat(e) : e;
return !isNaN(t) && isFinite(t) && t > 0;
}
function g(e) {
return typeof e == "function";
}
function w(e) {
return e !== null && typeof e == "object";
}
function k(e) {
return Array.isArray(e);
}
function v() {
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>`;
}
export {
r as TAPPaymentPop
};
//# sourceMappingURL=index.js.map