@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/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
@@ -0,0 +1,8 @@
1
+ import checkout from "./lib/main.js";
2
+ import PayByAppWidget from "./lib/widget.js";
3
+ import "./style.css";
4
+
5
+ export default {
6
+ checkout,
7
+ PayByAppWidget,
8
+ };
@@ -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
+ }
@@ -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;