@devheit/paydeet-pay-by-app-plugin 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +75 -0
- package/const/app-constants.js +11 -0
- package/data/currencies.js +1084 -0
- package/index.html +13 -0
- package/index.js +8 -0
- package/lib/dom-setup.js +31 -0
- package/lib/main.js +70 -0
- package/lib/widget.js +121 -0
- package/package.json +36 -0
- package/public/vite.svg +1 -0
- package/style.css +49 -0
- package/util/validate-props.js +37 -0
package/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite App</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/main.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
package/index.js
ADDED
package/lib/dom-setup.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appRootId,
|
|
3
|
+
frameInClass,
|
|
4
|
+
frameOutClass,
|
|
5
|
+
} from "../const/app-constants.js";
|
|
6
|
+
|
|
7
|
+
function setupDom() {
|
|
8
|
+
const payByApp = document.createElement("div");
|
|
9
|
+
payByApp.setAttribute("id", appRootId);
|
|
10
|
+
document.body.appendChild(payByApp);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function tearDownDom() {
|
|
14
|
+
return new Promise(async function (resolve, reject) {
|
|
15
|
+
const payByApp = document.getElementById(appRootId);
|
|
16
|
+
if (payByApp) {
|
|
17
|
+
// before removing child, simulate shutdown animation
|
|
18
|
+
const frame = payByApp.querySelector("iframe.frame-in");
|
|
19
|
+
if (frame) {
|
|
20
|
+
frame.classList.remove(frameInClass);
|
|
21
|
+
frame.classList.add(frameOutClass);
|
|
22
|
+
}
|
|
23
|
+
frame.addEventListener("animationend", () => {
|
|
24
|
+
document.body.removeChild(payByApp);
|
|
25
|
+
resolve();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { setupDom, tearDownDom };
|
package/lib/main.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { appRootId } from '../const/app-constants.js';
|
|
2
|
+
import validateMainProps from '../util/validate-props.js';
|
|
3
|
+
import { setupDom, tearDownDom } from './dom-setup.js';
|
|
4
|
+
import PayByAppWidget from './widget.js';
|
|
5
|
+
|
|
6
|
+
async function closeApp(appReference) {
|
|
7
|
+
if (typeof appReference.close === 'function') {
|
|
8
|
+
await tearDownDom();
|
|
9
|
+
appReference
|
|
10
|
+
.close()
|
|
11
|
+
.then(() => {
|
|
12
|
+
console.info(
|
|
13
|
+
'<====== Thank you for using the pay by app experience powered by https://www.paydeet.com/ ======>'
|
|
14
|
+
);
|
|
15
|
+
})
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
console.error('Failed to close the app', err);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function checkout(props) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const validateResponse = validateMainProps(props);
|
|
25
|
+
if (!validateResponse.isValid) {
|
|
26
|
+
return reject({
|
|
27
|
+
success: false,
|
|
28
|
+
message: `Please provide a valid ${validateResponse.key}`,
|
|
29
|
+
callbackUrl: null,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
setupDom();
|
|
33
|
+
let appRef;
|
|
34
|
+
appRef = PayByAppWidget({
|
|
35
|
+
...props,
|
|
36
|
+
onSuccess: async (successResponse) => {
|
|
37
|
+
await closeApp(appRef);
|
|
38
|
+
resolve({
|
|
39
|
+
success: true,
|
|
40
|
+
message: successResponse,
|
|
41
|
+
callbackUrl: null,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
windowWidth: window.innerWidth,
|
|
45
|
+
onError: async () => {
|
|
46
|
+
await closeApp(appRef);
|
|
47
|
+
reject({
|
|
48
|
+
success: false,
|
|
49
|
+
message: 'Payment failed.',
|
|
50
|
+
callbackUrl: null,
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
onClose: async () => {
|
|
54
|
+
await closeApp(appRef);
|
|
55
|
+
resolve({
|
|
56
|
+
success: false,
|
|
57
|
+
message: 'Payment cancelled.',
|
|
58
|
+
callbackUrl: null,
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
appRef.render(`#${appRootId}`).then(() => {
|
|
63
|
+
console.info(
|
|
64
|
+
'<====== Welcome to the pay by app experience powered by https://www.paydeet.com/ ======>'
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default checkout;
|
package/lib/widget.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as zoid from "@krakenjs/zoid/dist/zoid.js";
|
|
2
|
+
import { appUrl, frameInClass } from "../const/app-constants.js";
|
|
3
|
+
let PayByAppWidget = zoid.create({
|
|
4
|
+
tag: "my-widget",
|
|
5
|
+
url: appUrl,
|
|
6
|
+
autoResize: {
|
|
7
|
+
width: true,
|
|
8
|
+
height: true,
|
|
9
|
+
},
|
|
10
|
+
props: {
|
|
11
|
+
amount: {
|
|
12
|
+
type: "number",
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
apiKey: {
|
|
16
|
+
type: "string",
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
currency: {
|
|
20
|
+
type: "string",
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
onSuccess: {
|
|
24
|
+
type: "function",
|
|
25
|
+
required: false,
|
|
26
|
+
},
|
|
27
|
+
onError: {
|
|
28
|
+
type: "function",
|
|
29
|
+
required: false,
|
|
30
|
+
},
|
|
31
|
+
onClose: {
|
|
32
|
+
type: "function",
|
|
33
|
+
required: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
prerenderTemplate({ doc }) {
|
|
37
|
+
// create frame
|
|
38
|
+
const html = doc.createElement("html");
|
|
39
|
+
const head = doc.createElement("head");
|
|
40
|
+
const style = doc.createElement("style");
|
|
41
|
+
const body = doc.createElement("body");
|
|
42
|
+
const spinner = doc.createElement("div");
|
|
43
|
+
const loader = doc.createElement("div");
|
|
44
|
+
|
|
45
|
+
spinner.classList.add("spinner");
|
|
46
|
+
loader.classList.add("loader");
|
|
47
|
+
spinner.appendChild(loader);
|
|
48
|
+
|
|
49
|
+
style.innerHTML = `{
|
|
50
|
+
html, body {
|
|
51
|
+
width: 100%;
|
|
52
|
+
height: 100%;
|
|
53
|
+
overflow: hidden;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: 0;
|
|
56
|
+
margin: 30px auto;
|
|
57
|
+
text-align: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.spinner {
|
|
61
|
+
position: absolute;
|
|
62
|
+
max-height: 60vmin;
|
|
63
|
+
max-width: 60vmin;
|
|
64
|
+
height: 40px;
|
|
65
|
+
width: 40px;
|
|
66
|
+
top: 50%;
|
|
67
|
+
left: 50%;
|
|
68
|
+
transform: translateX(-50%) translateY(-50%);
|
|
69
|
+
z-index: 10;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.spinner .loader {
|
|
73
|
+
height: 100%;
|
|
74
|
+
width: 100%;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
border: 3px solid rgba(0, 0, 0, .2);
|
|
77
|
+
border-top-color: rgba(33, 128, 192, 0.8);
|
|
78
|
+
border-radius: 100%;
|
|
79
|
+
animation: rotation .7s infinite linear;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@keyframes rotation {
|
|
83
|
+
from {
|
|
84
|
+
transform: rotate(0deg)
|
|
85
|
+
}
|
|
86
|
+
to {
|
|
87
|
+
transform: rotate(359deg)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}`;
|
|
91
|
+
|
|
92
|
+
html.appendChild(head);
|
|
93
|
+
head.appendChild(style);
|
|
94
|
+
head.appendChild(body);
|
|
95
|
+
body.appendChild(spinner);
|
|
96
|
+
return html;
|
|
97
|
+
},
|
|
98
|
+
containerTemplate: function containerTemplate({
|
|
99
|
+
doc,
|
|
100
|
+
uid,
|
|
101
|
+
frame,
|
|
102
|
+
prerenderFrame,
|
|
103
|
+
}) {
|
|
104
|
+
const container = doc.createElement("div");
|
|
105
|
+
container.id = uid;
|
|
106
|
+
container.appendChild(frame);
|
|
107
|
+
container.appendChild(prerenderFrame);
|
|
108
|
+
container.style.width = "500px";
|
|
109
|
+
container.style.height = "700px";
|
|
110
|
+
container.style.maxWidth = "100%";
|
|
111
|
+
container.style.maxHeight = "100%";
|
|
112
|
+
frame.setAttribute(
|
|
113
|
+
"style",
|
|
114
|
+
`width: 100%; height: 100%; border-radius: 12px;`
|
|
115
|
+
);
|
|
116
|
+
frame.setAttribute("class", frameInClass);
|
|
117
|
+
return container;
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export default PayByAppWidget;
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devheit/paydeet-pay-by-app-plugin",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Devheit/paydeet-pay-by-app-plugin.git"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "vite",
|
|
11
|
+
"build": "vite build",
|
|
12
|
+
"preview": "vite preview"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"vite": "^5.4.10"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@krakenjs/zoid": "^10.3.3"
|
|
19
|
+
},
|
|
20
|
+
"description": "A JavaScript plugin that enables seamless integration of [Paydeet's](https://www.paydeet.com/) pay-by-app checkout experience into your web application.",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Devheit/paydeet-pay-by-app-plugin/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Devheit/paydeet-pay-by-app-plugin#readme",
|
|
25
|
+
"main": "index.js",
|
|
26
|
+
"directories": {
|
|
27
|
+
"lib": "lib"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"paydeet",
|
|
31
|
+
"devheit",
|
|
32
|
+
"pay_by_app"
|
|
33
|
+
],
|
|
34
|
+
"author": "Temidayo Omoyajowo",
|
|
35
|
+
"license": "ISC"
|
|
36
|
+
}
|
package/public/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/style.css
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#pay-by-app {
|
|
2
|
+
z-index: 2147483647;
|
|
3
|
+
background: rgba(0, 0, 0, 0.75) !important;
|
|
4
|
+
border: 0px none transparent;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
margin: 0px;
|
|
7
|
+
padding: 0px;
|
|
8
|
+
-webkit-tap-highlight-color: transparent;
|
|
9
|
+
position: fixed;
|
|
10
|
+
left: 0px;
|
|
11
|
+
top: 0px;
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
transition: opacity 0.3s;
|
|
15
|
+
visibility: visible;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.frame-in {
|
|
22
|
+
animation: slide-in 0.5s ease-in;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@keyframes slide-in {
|
|
26
|
+
from {
|
|
27
|
+
opacity: 0;
|
|
28
|
+
transform: translateX(35%);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
to {
|
|
32
|
+
opacity: 1;
|
|
33
|
+
transform: translateX(0);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
.frame-out {
|
|
37
|
+
animation: slide-out 0.5s ease-out;
|
|
38
|
+
}
|
|
39
|
+
@keyframes slide-out {
|
|
40
|
+
to {
|
|
41
|
+
opacity: 0;
|
|
42
|
+
transform: translateX(35%);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
from {
|
|
46
|
+
opacity: 1;
|
|
47
|
+
transform: translateX(0);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { validCurrencyMap } from "../const/app-constants.js";
|
|
2
|
+
|
|
3
|
+
function validateMainProps(props) {
|
|
4
|
+
const expectedProps = {
|
|
5
|
+
amount: validateNumber,
|
|
6
|
+
apiKey: validateString,
|
|
7
|
+
currency: validateCurrency,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
for (const key in expectedProps) {
|
|
11
|
+
if (props[key] === undefined || !expectedProps[key](props[key])) {
|
|
12
|
+
return { key, isValid: false };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { isValid: true };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function validateNumber(number) {
|
|
20
|
+
if (typeof number !== "number" || number <= 0) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function validateString(string) {
|
|
27
|
+
if (typeof string !== "string" || string.length === 0) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validateCurrency(currency) {
|
|
34
|
+
return validCurrencyMap[currency] ? true : false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default validateMainProps;
|