@auto-topup/web 0.2.3
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/dist/index.d.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +594 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +578 -0
- package/dist/index.mjs.map +1 -0
- package/dist/retailcode.iife.global.js +235 -0
- package/package.json +41 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { TopupCallbacks } from '@auto-topup/core';
|
|
2
|
+
export { TopupCallbacks } from '@auto-topup/core';
|
|
3
|
+
|
|
4
|
+
interface WidgetOptions extends TopupCallbacks {
|
|
5
|
+
publicKey: string;
|
|
6
|
+
msisdn: string;
|
|
7
|
+
container: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
theme?: {
|
|
10
|
+
accent?: string;
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
declare class TopupWidget {
|
|
15
|
+
private readonly client;
|
|
16
|
+
private readonly opts;
|
|
17
|
+
constructor(opts: WidgetOptions);
|
|
18
|
+
mount(): Promise<void>;
|
|
19
|
+
private renderSpinner;
|
|
20
|
+
private buildModalHtml;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CreateConfig extends TopupCallbacks {
|
|
24
|
+
publicKey: string;
|
|
25
|
+
msisdn: string;
|
|
26
|
+
container: string;
|
|
27
|
+
/** Defaults to https://corporatedevapi.retailcode.com.ng — only set this for testing */
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
theme?: {
|
|
30
|
+
accent?: string;
|
|
31
|
+
fontFamily?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
declare const RetailcodeTopup: {
|
|
35
|
+
create(config: CreateConfig): {
|
|
36
|
+
mount: () => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { type CreateConfig, RetailcodeTopup, TopupWidget };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { TopupCallbacks } from '@auto-topup/core';
|
|
2
|
+
export { TopupCallbacks } from '@auto-topup/core';
|
|
3
|
+
|
|
4
|
+
interface WidgetOptions extends TopupCallbacks {
|
|
5
|
+
publicKey: string;
|
|
6
|
+
msisdn: string;
|
|
7
|
+
container: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
theme?: {
|
|
10
|
+
accent?: string;
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
declare class TopupWidget {
|
|
15
|
+
private readonly client;
|
|
16
|
+
private readonly opts;
|
|
17
|
+
constructor(opts: WidgetOptions);
|
|
18
|
+
mount(): Promise<void>;
|
|
19
|
+
private renderSpinner;
|
|
20
|
+
private buildModalHtml;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CreateConfig extends TopupCallbacks {
|
|
24
|
+
publicKey: string;
|
|
25
|
+
msisdn: string;
|
|
26
|
+
container: string;
|
|
27
|
+
/** Defaults to https://corporatedevapi.retailcode.com.ng — only set this for testing */
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
theme?: {
|
|
30
|
+
accent?: string;
|
|
31
|
+
fontFamily?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
declare const RetailcodeTopup: {
|
|
35
|
+
create(config: CreateConfig): {
|
|
36
|
+
mount: () => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { type CreateConfig, RetailcodeTopup, TopupWidget };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __export = (target, all) => {
|
|
24
|
+
for (var name in all)
|
|
25
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
26
|
+
};
|
|
27
|
+
var __copyProps = (to, from, except, desc) => {
|
|
28
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
29
|
+
for (let key of __getOwnPropNames(from))
|
|
30
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
31
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
32
|
+
}
|
|
33
|
+
return to;
|
|
34
|
+
};
|
|
35
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
36
|
+
|
|
37
|
+
// src/index.ts
|
|
38
|
+
var index_exports = {};
|
|
39
|
+
__export(index_exports, {
|
|
40
|
+
RetailcodeTopup: () => RetailcodeTopup,
|
|
41
|
+
TopupWidget: () => TopupWidget
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(index_exports);
|
|
44
|
+
var import_core3 = require("@auto-topup/core");
|
|
45
|
+
|
|
46
|
+
// src/widget.ts
|
|
47
|
+
var import_core2 = require("@auto-topup/core");
|
|
48
|
+
|
|
49
|
+
// src/dialog.ts
|
|
50
|
+
var loadPromise = null;
|
|
51
|
+
function loadSwal() {
|
|
52
|
+
if (window.Swal) return Promise.resolve();
|
|
53
|
+
if (loadPromise) return loadPromise;
|
|
54
|
+
loadPromise = new Promise((resolve) => {
|
|
55
|
+
const link = document.createElement("link");
|
|
56
|
+
link.rel = "stylesheet";
|
|
57
|
+
link.href = "https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css";
|
|
58
|
+
document.head.appendChild(link);
|
|
59
|
+
const script = document.createElement("script");
|
|
60
|
+
script.src = "https://cdn.jsdelivr.net/npm/sweetalert2@11";
|
|
61
|
+
script.onload = () => resolve();
|
|
62
|
+
document.head.appendChild(script);
|
|
63
|
+
});
|
|
64
|
+
return loadPromise;
|
|
65
|
+
}
|
|
66
|
+
function swal(opts) {
|
|
67
|
+
return window.Swal.fire(opts);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/webview.ts
|
|
71
|
+
function updateUrlStatus(status) {
|
|
72
|
+
const url = new URL(window.location.href);
|
|
73
|
+
url.searchParams.set("status", status);
|
|
74
|
+
window.history.replaceState({}, "", url);
|
|
75
|
+
}
|
|
76
|
+
function closeWebview(onClose, unmount, success = false) {
|
|
77
|
+
var _a, _b, _c, _d, _e, _f;
|
|
78
|
+
const url = new URL(window.location.href);
|
|
79
|
+
url.searchParams.set("isClose", "true");
|
|
80
|
+
window.history.replaceState({}, "", url);
|
|
81
|
+
const isNative = !!(window.ReactNativeWebView || window.RetailcodeFlutter || ((_b = (_a = window.webkit) == null ? void 0 : _a.messageHandlers) == null ? void 0 : _b.retailcode) || ((_c = window.Android) == null ? void 0 : _c.close));
|
|
82
|
+
if (!isNative) unmount == null ? void 0 : unmount();
|
|
83
|
+
onClose == null ? void 0 : onClose({ closed: true });
|
|
84
|
+
const msg = JSON.stringify({ action: "close", success });
|
|
85
|
+
if (window.ReactNativeWebView) {
|
|
86
|
+
window.ReactNativeWebView.postMessage(msg);
|
|
87
|
+
} else if (window.RetailcodeFlutter) {
|
|
88
|
+
window.RetailcodeFlutter.postMessage(msg);
|
|
89
|
+
} else if ((_e = (_d = window.webkit) == null ? void 0 : _d.messageHandlers) == null ? void 0 : _e.retailcode) {
|
|
90
|
+
window.webkit.messageHandlers.retailcode.postMessage({ action: "close", success });
|
|
91
|
+
} else if ((_f = window.Android) == null ? void 0 : _f.close) {
|
|
92
|
+
window.Android.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/styles.ts
|
|
97
|
+
var import_core = require("@auto-topup/core");
|
|
98
|
+
function buildTokens(accent, fontFamily) {
|
|
99
|
+
return {
|
|
100
|
+
accent,
|
|
101
|
+
accentHover: (0, import_core.mix)(accent, -10),
|
|
102
|
+
accentFocus: (0, import_core.rgba)(accent, 0.15),
|
|
103
|
+
accentShadow: (0, import_core.rgba)(accent, 0.25),
|
|
104
|
+
fontFamily
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function buildStyles(t) {
|
|
108
|
+
return `
|
|
109
|
+
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap');
|
|
110
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
111
|
+
|
|
112
|
+
:host {
|
|
113
|
+
display: flex;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
min-height: 100vh;
|
|
116
|
+
font-family: ${t.fontFamily};
|
|
117
|
+
background: #FFFFFF;
|
|
118
|
+
}
|
|
119
|
+
@media (min-width: 560px) {
|
|
120
|
+
:host { background: rgba(0,0,0,.50); align-items: center; padding: 20px; }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.rc-modal {
|
|
124
|
+
width: 100%; max-width: 440px; background: #FFFFFF; overflow: hidden;
|
|
125
|
+
animation: modalSlide .35s cubic-bezier(.22,1,.36,1) both;
|
|
126
|
+
border-radius: 0; box-shadow: none;
|
|
127
|
+
}
|
|
128
|
+
@media (min-width: 560px) {
|
|
129
|
+
.rc-modal {
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
box-shadow: 0 2px 8px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.12), 0 32px 64px rgba(0,0,0,.08);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
@keyframes modalSlide { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:none; } }
|
|
135
|
+
|
|
136
|
+
.rc-header { padding: 24px 20px 14px; }
|
|
137
|
+
.rc-header-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
|
|
138
|
+
.rc-title h2 { font-size: 19px; font-weight: 700; color: #111827; letter-spacing: -.3px; }
|
|
139
|
+
.rc-title p { font-size: 13px; color: #6B7280; margin-top: 3px; line-height: 1.4; }
|
|
140
|
+
|
|
141
|
+
.rc-close-btn {
|
|
142
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
143
|
+
width: 28px; height: 28px; background: #F3F4F6; border: none;
|
|
144
|
+
border-radius: 6px; color: #6B7280; cursor: pointer; transition: background .15s; flex-shrink: 0;
|
|
145
|
+
}
|
|
146
|
+
.rc-close-btn:hover { background: #E5E7EB; }
|
|
147
|
+
|
|
148
|
+
.rc-account-bar {
|
|
149
|
+
display: flex; align-items: center; background: ${t.accent};
|
|
150
|
+
padding: 10px 14px; border-radius: 6px; color: #fff;
|
|
151
|
+
}
|
|
152
|
+
.rc-dot { width: 8px; height: 8px; background: #4ADE80; border-radius: 50%; margin-right: 10px; box-shadow: 0 0 0 2px rgba(74,222,128,.3); flex-shrink: 0; }
|
|
153
|
+
.rc-acc-label { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; opacity: .65; display: block; margin-bottom: 1px; }
|
|
154
|
+
.rc-acc-no { font-size: 14px; font-weight: 700; letter-spacing: .03em; }
|
|
155
|
+
|
|
156
|
+
.rc-content { padding: 20px 20px 16px; }
|
|
157
|
+
.rc-group { margin-bottom: 14px; }
|
|
158
|
+
.rc-group-title { font-size: 10px; font-weight: 700; color: #9CA3AF; text-transform: uppercase; letter-spacing: .09em; margin-bottom: 10px; }
|
|
159
|
+
|
|
160
|
+
.rc-field { position: relative; margin-bottom: 10px; }
|
|
161
|
+
.rc-field:last-child { margin-bottom: 0; }
|
|
162
|
+
.rc-field label { position: absolute; left: 12px; top: 16px; font-size: 13.5px; color: #9CA3AF; transition: all .16s cubic-bezier(.4,0,.2,1); pointer-events: none; transform-origin: left top; }
|
|
163
|
+
.rc-field input, .rc-field select {
|
|
164
|
+
width: 100%; height: 52px; padding: 20px 12px 6px;
|
|
165
|
+
background: #F9FAFB; border: 1.5px solid #E5E7EB; border-radius: 6px;
|
|
166
|
+
font-family: inherit; font-size: 14px; font-weight: 500; color: #111827;
|
|
167
|
+
outline: none; transition: border-color .18s, box-shadow .18s, background .18s;
|
|
168
|
+
appearance: none; -webkit-appearance: none;
|
|
169
|
+
}
|
|
170
|
+
.rc-field select {
|
|
171
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
|
|
172
|
+
background-repeat: no-repeat; background-position: right 12px center; padding-right: 34px; cursor: pointer;
|
|
173
|
+
}
|
|
174
|
+
.rc-field input:focus, .rc-field select:focus {
|
|
175
|
+
border-color: ${t.accent}; background: #FFFFFF; box-shadow: 0 0 0 3px ${t.accentFocus};
|
|
176
|
+
}
|
|
177
|
+
.rc-field.has-val label, .rc-field input:focus ~ label, .rc-field select:focus ~ label {
|
|
178
|
+
top: 7px; font-size: 10.5px; font-weight: 700; color: ${t.accent};
|
|
179
|
+
}
|
|
180
|
+
.rc-field small { display: block; margin-top: 4px; font-size: 11px; color: #9CA3AF; }
|
|
181
|
+
|
|
182
|
+
.rc-row { display: grid; gap: 10px; margin-bottom: 10px; }
|
|
183
|
+
.rc-row .rc-field { margin-bottom: 0; }
|
|
184
|
+
.rc-divider { height: 1px; background: #F3F4F6; margin: 16px 0; border: none; }
|
|
185
|
+
.section-animate { animation: fadeIn .25s ease-out; }
|
|
186
|
+
@keyframes fadeIn { from { opacity:0; transform:translateY(4px); } to { opacity:1; transform:none; } }
|
|
187
|
+
|
|
188
|
+
.rc-link-wrap { margin-top: 12px; text-align: center; font-size: 13px; color: #9CA3AF; }
|
|
189
|
+
.rc-link-wrap a { color: ${t.accent}; text-decoration: none; font-weight: 600; cursor: pointer; }
|
|
190
|
+
.rc-link-wrap a:hover { text-decoration: underline; }
|
|
191
|
+
|
|
192
|
+
.rc-submit-btn {
|
|
193
|
+
width: 100%; height: 52px; background: ${t.accent}; color: #FFFFFF; border: none;
|
|
194
|
+
border-radius: 6px; font-family: inherit; font-size: 15px; font-weight: 700;
|
|
195
|
+
cursor: pointer; letter-spacing: .01em; margin-top: 6px;
|
|
196
|
+
box-shadow: 0 4px 12px ${t.accentShadow};
|
|
197
|
+
transition: background .18s, transform .1s, box-shadow .18s;
|
|
198
|
+
}
|
|
199
|
+
.rc-submit-btn:hover:not(:disabled) { background: ${t.accentHover}; transform: translateY(-1px); box-shadow: 0 6px 18px ${(0, import_core.rgba)(t.accent, 0.35)}; }
|
|
200
|
+
.rc-submit-btn:active:not(:disabled) { transform: translateY(0); }
|
|
201
|
+
.rc-submit-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
|
|
202
|
+
|
|
203
|
+
.rc-spinner-ring {
|
|
204
|
+
width: 48px; height: 48px;
|
|
205
|
+
border: 4px solid ${(0, import_core.rgba)(t.accent, 0.18)};
|
|
206
|
+
border-top-color: ${t.accent};
|
|
207
|
+
border-radius: 50%;
|
|
208
|
+
animation: rc-spin .75s linear infinite;
|
|
209
|
+
}
|
|
210
|
+
@keyframes rc-spin { to { transform: rotate(360deg); } }
|
|
211
|
+
|
|
212
|
+
.rc-footer {
|
|
213
|
+
text-align: center; padding: 0 20px 18px; font-size: 11px; color: #D1D5DB;
|
|
214
|
+
display: flex; align-items: center; justify-content: center; gap: 5px;
|
|
215
|
+
}
|
|
216
|
+
.rc-footer svg { opacity: .5; }
|
|
217
|
+
.hidden { display: none !important; }
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/widget.ts
|
|
222
|
+
var TopupWidget = class {
|
|
223
|
+
constructor(opts) {
|
|
224
|
+
this.opts = opts;
|
|
225
|
+
this.client = new import_core2.RetailcodeApiClient(opts.publicKey, opts.baseUrl);
|
|
226
|
+
}
|
|
227
|
+
async mount() {
|
|
228
|
+
var _a;
|
|
229
|
+
const { msisdn, container, onClose, theme = {} } = this.opts;
|
|
230
|
+
const target = document.querySelector(container);
|
|
231
|
+
if (!target) return;
|
|
232
|
+
const accent = (0, import_core2.resolveAccent)(theme.accent);
|
|
233
|
+
const fontFamily = (_a = theme.fontFamily) != null ? _a : "'DM Sans', system-ui, sans-serif";
|
|
234
|
+
const tokens = buildTokens(accent, fontFamily);
|
|
235
|
+
let shadow = null;
|
|
236
|
+
const showInitError = (message) => {
|
|
237
|
+
const html = `
|
|
238
|
+
<div style="font-family:${fontFamily};padding:24px;border:1.5px solid #FCA5A5;background:#FEF2F2;border-radius:8px;color:#991B1B;text-align:center;max-width:440px;margin:40px auto;">
|
|
239
|
+
<div style="font-weight:700;font-size:15px;margin-bottom:4px;">SDK failed to initialize</div>
|
|
240
|
+
<div style="font-size:13px;opacity:0.8;">${message}</div>
|
|
241
|
+
</div>`;
|
|
242
|
+
if (shadow) shadow.innerHTML = html;
|
|
243
|
+
else target.innerHTML = html;
|
|
244
|
+
};
|
|
245
|
+
if (!(0, import_core2.isValidMsisdn)(msisdn)) {
|
|
246
|
+
showInitError("Subscriber phone number is not valid.");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
shadow = target.attachShadow({ mode: "open" });
|
|
250
|
+
this.renderSpinner(shadow, tokens);
|
|
251
|
+
let cfg;
|
|
252
|
+
try {
|
|
253
|
+
cfg = await this.client.fetchConfig(msisdn);
|
|
254
|
+
} catch (e) {
|
|
255
|
+
const msg = e instanceof import_core2.RetailcodeApiError ? e.message : "Could not connect to the activation server.";
|
|
256
|
+
showInitError(msg);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
shadow.innerHTML = "";
|
|
260
|
+
await loadSwal();
|
|
261
|
+
const {
|
|
262
|
+
name: prefilledName = "",
|
|
263
|
+
subscribedAirtime = false,
|
|
264
|
+
subscribedData = false,
|
|
265
|
+
airtimethresholds = {},
|
|
266
|
+
airtimeMin = 0,
|
|
267
|
+
airtimeMax = 1e4,
|
|
268
|
+
dataThresholds = {},
|
|
269
|
+
dataPlans = [],
|
|
270
|
+
terms = null
|
|
271
|
+
} = cfg;
|
|
272
|
+
const isFullSubscriber = subscribedAirtime && subscribedData;
|
|
273
|
+
const isPartialSubscriber = (subscribedAirtime || subscribedData) && !isFullSubscriber;
|
|
274
|
+
const isBrandNew = !subscribedAirtime && !subscribedData;
|
|
275
|
+
if (isBrandNew && terms) {
|
|
276
|
+
const result = await swal({
|
|
277
|
+
title: "Terms & Conditions",
|
|
278
|
+
html: `
|
|
279
|
+
<div style="text-align:left;font-size:13px;line-height:1.65;color:#374151;max-height:340px;overflow-y:auto;padding-right:4px;font-family:${fontFamily};">
|
|
280
|
+
${typeof terms === "string" ? terms.replace(/\n/g, "<br>") : ""}
|
|
281
|
+
</div>`,
|
|
282
|
+
confirmButtonText: "I Agree & Continue",
|
|
283
|
+
confirmButtonColor: accent,
|
|
284
|
+
showCancelButton: true,
|
|
285
|
+
cancelButtonText: "Decline",
|
|
286
|
+
cancelButtonColor: "#9CA3AF",
|
|
287
|
+
allowOutsideClick: false,
|
|
288
|
+
allowEscapeKey: false,
|
|
289
|
+
reverseButtons: true
|
|
290
|
+
});
|
|
291
|
+
if (!result.isConfirmed) {
|
|
292
|
+
closeWebview(onClose);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const airtimeOptions = Object.entries(airtimethresholds).map(([k, id]) => `<option value="${id}">Below \u20A6${k}</option>`).join("");
|
|
297
|
+
const dataOptions = Object.entries(dataThresholds).map(([k, id]) => `<option value="${id}">Below ${k}</option>`).join("");
|
|
298
|
+
const dataPlanOptions = dataPlans.map((p) => `<option value="${p.productId}">${p.allowance} \u2014 \u20A6${p.price}</option>`).join("");
|
|
299
|
+
const modal = document.createElement("div");
|
|
300
|
+
modal.className = "rc-modal";
|
|
301
|
+
modal.innerHTML = this.buildModalHtml({
|
|
302
|
+
tokens,
|
|
303
|
+
msisdn,
|
|
304
|
+
prefilledName,
|
|
305
|
+
airtimeMin,
|
|
306
|
+
airtimeMax,
|
|
307
|
+
airtimeOptions,
|
|
308
|
+
dataOptions,
|
|
309
|
+
dataPlanOptions
|
|
310
|
+
});
|
|
311
|
+
shadow.appendChild(modal);
|
|
312
|
+
const $ = (id) => shadow.getElementById(id);
|
|
313
|
+
const typeSelect = $("rc-type-select");
|
|
314
|
+
const airtimeSec = $("section-airtime");
|
|
315
|
+
const dataSec = $("section-data");
|
|
316
|
+
const titleText = $("rc-main-title");
|
|
317
|
+
const descText = $("rc-desc");
|
|
318
|
+
const submitBtn = $("rc-submit");
|
|
319
|
+
const msisdnField = $("field-msisdn");
|
|
320
|
+
const depLinkWrap = $("rc-dependent-link-wrap");
|
|
321
|
+
const depControls = $("section-dependent-controls");
|
|
322
|
+
const typeSelectorGrp = $("group-type-selector");
|
|
323
|
+
const beneficiaryRow = $("row-beneficiary");
|
|
324
|
+
const spendingRow = $("row-spending");
|
|
325
|
+
const airtimeMaxField = $("field-airtime-max");
|
|
326
|
+
const dataMaxField = $("field-data-max");
|
|
327
|
+
let forceDependentView = false;
|
|
328
|
+
const refreshUI = () => {
|
|
329
|
+
const isDep = isFullSubscriber || forceDependentView;
|
|
330
|
+
const mode = typeSelect.value;
|
|
331
|
+
if (isDep) {
|
|
332
|
+
titleText.innerText = "Add Dependent";
|
|
333
|
+
descText.innerText = "Configure subscription for someone else";
|
|
334
|
+
msisdnField.classList.remove("hidden");
|
|
335
|
+
beneficiaryRow.style.gridTemplateColumns = "1fr 1fr";
|
|
336
|
+
typeSelectorGrp.classList.remove("hidden");
|
|
337
|
+
depLinkWrap.classList.add("hidden");
|
|
338
|
+
depControls.classList.remove("hidden");
|
|
339
|
+
airtimeSec.classList.toggle("hidden", mode === "data");
|
|
340
|
+
dataSec.classList.toggle("hidden", mode === "airtime");
|
|
341
|
+
airtimeMaxField.classList.toggle("hidden", mode === "data");
|
|
342
|
+
dataMaxField.classList.toggle("hidden", mode === "airtime");
|
|
343
|
+
spendingRow.style.gridTemplateColumns = mode === "both" ? "1fr 1fr" : "1fr";
|
|
344
|
+
} else if (isPartialSubscriber) {
|
|
345
|
+
titleText.innerText = "Complete Profile";
|
|
346
|
+
descText.innerText = "Finish your Auto Topup subscription";
|
|
347
|
+
msisdnField.classList.add("hidden");
|
|
348
|
+
beneficiaryRow.style.gridTemplateColumns = "1fr";
|
|
349
|
+
typeSelectorGrp.classList.add("hidden");
|
|
350
|
+
depLinkWrap.classList.remove("hidden");
|
|
351
|
+
depControls.classList.add("hidden");
|
|
352
|
+
airtimeSec.classList.toggle("hidden", subscribedAirtime);
|
|
353
|
+
dataSec.classList.toggle("hidden", subscribedData);
|
|
354
|
+
} else {
|
|
355
|
+
titleText.innerText = "Auto Topup Subscription";
|
|
356
|
+
descText.innerText = "Automate your airtime & data recharge";
|
|
357
|
+
msisdnField.classList.add("hidden");
|
|
358
|
+
beneficiaryRow.style.gridTemplateColumns = "1fr";
|
|
359
|
+
typeSelectorGrp.classList.remove("hidden");
|
|
360
|
+
depLinkWrap.classList.add("hidden");
|
|
361
|
+
depControls.classList.add("hidden");
|
|
362
|
+
airtimeSec.classList.toggle("hidden", mode === "data");
|
|
363
|
+
dataSec.classList.toggle("hidden", mode === "airtime");
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
refreshUI();
|
|
367
|
+
const unmount = () => {
|
|
368
|
+
shadow.innerHTML = "";
|
|
369
|
+
};
|
|
370
|
+
typeSelect.addEventListener("change", refreshUI);
|
|
371
|
+
$("rc-close").addEventListener("click", () => closeWebview(onClose, unmount));
|
|
372
|
+
$("rc-switch-to-dep").addEventListener("click", (e) => {
|
|
373
|
+
e.preventDefault();
|
|
374
|
+
forceDependentView = true;
|
|
375
|
+
$("rc-name").value = "";
|
|
376
|
+
refreshUI();
|
|
377
|
+
});
|
|
378
|
+
$("rc-name").addEventListener("input", (e) => {
|
|
379
|
+
const el = e.target;
|
|
380
|
+
el.value = el.value.replace(/[^a-zA-Z\s]/g, "");
|
|
381
|
+
});
|
|
382
|
+
["rc-msisdn-input", "airtimeTopupValue", "rc-airtime-max", "rc-data-max"].forEach((id) => {
|
|
383
|
+
var _a2;
|
|
384
|
+
(_a2 = $(id)) == null ? void 0 : _a2.addEventListener("input", (e) => {
|
|
385
|
+
const el = e.target;
|
|
386
|
+
el.value = el.value.replace(/\D/g, "");
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
shadow.querySelectorAll(".rc-field input, .rc-field select").forEach((el) => {
|
|
390
|
+
const sync = () => el.closest(".rc-field").classList.toggle("has-val", el.value !== "");
|
|
391
|
+
el.addEventListener("input", sync);
|
|
392
|
+
el.addEventListener("change", sync);
|
|
393
|
+
sync();
|
|
394
|
+
});
|
|
395
|
+
submitBtn.addEventListener("click", async () => {
|
|
396
|
+
var _a2, _b;
|
|
397
|
+
const getVal = (id) => {
|
|
398
|
+
var _a3, _b2;
|
|
399
|
+
return (_b2 = (_a3 = $(id)) == null ? void 0 : _a3.value.trim()) != null ? _b2 : "";
|
|
400
|
+
};
|
|
401
|
+
const isDep = isFullSubscriber || forceDependentView;
|
|
402
|
+
const beneficiary = isDep ? getVal("rc-msisdn-input") : msisdn;
|
|
403
|
+
if (!airtimeSec.classList.contains("hidden")) {
|
|
404
|
+
if (!(0, import_core2.isValidAmount)(getVal("airtimeTopupValue"), airtimeMin, airtimeMax)) {
|
|
405
|
+
swal({ icon: "warning", title: "Invalid Amount", text: `Enter \u20A6${airtimeMin} \u2013 \u20A6${airtimeMax}.`, confirmButtonColor: accent });
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (isDep && !beneficiary) {
|
|
410
|
+
swal({ icon: "warning", title: "Wait!", text: "Enter the dependent phone number.", confirmButtonColor: accent });
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
submitBtn.disabled = true;
|
|
414
|
+
submitBtn.innerText = "Processing\u2026";
|
|
415
|
+
const common = { network: "MTN", msisdn: beneficiary, name: getVal("rc-name") };
|
|
416
|
+
try {
|
|
417
|
+
if (!airtimeSec.classList.contains("hidden")) {
|
|
418
|
+
await this.client.subscribeAirtime(__spreadValues(__spreadProps(__spreadValues({}, common), {
|
|
419
|
+
airtimeThresholdId: getVal("airtimeThresholdId"),
|
|
420
|
+
airtimeTopupValue: getVal("airtimeTopupValue")
|
|
421
|
+
}), isDep && { customerMsisdn: msisdn, monthlyMaximum: getVal("rc-airtime-max") }));
|
|
422
|
+
}
|
|
423
|
+
if (!dataSec.classList.contains("hidden")) {
|
|
424
|
+
await this.client.subscribeData(__spreadValues(__spreadProps(__spreadValues({}, common), {
|
|
425
|
+
dataThresholdId: getVal("dataThresholdId"),
|
|
426
|
+
dataTopupValue: getVal("dataTopupValue")
|
|
427
|
+
}), isDep && { customerMsisdn: msisdn, monthlyMaximum: getVal("rc-data-max") }));
|
|
428
|
+
}
|
|
429
|
+
updateUrlStatus("successful");
|
|
430
|
+
(_b = (_a2 = this.opts).onSuccess) == null ? void 0 : _b.call(_a2, { success: true });
|
|
431
|
+
swal({
|
|
432
|
+
icon: "success",
|
|
433
|
+
title: "Subscription Active!",
|
|
434
|
+
text: "Your auto top-up is now enabled.",
|
|
435
|
+
confirmButtonColor: accent,
|
|
436
|
+
didClose: () => closeWebview(onClose, unmount, true)
|
|
437
|
+
});
|
|
438
|
+
} catch (err) {
|
|
439
|
+
updateUrlStatus("failed");
|
|
440
|
+
swal({ icon: "error", title: "Oops!", text: err.message, confirmButtonColor: accent });
|
|
441
|
+
submitBtn.disabled = false;
|
|
442
|
+
submitBtn.innerText = "Activate Subscription";
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
447
|
+
renderSpinner(shadow, tokens) {
|
|
448
|
+
var _a, _b;
|
|
449
|
+
const el = document.createElement("div");
|
|
450
|
+
el.innerHTML = `
|
|
451
|
+
<style>
|
|
452
|
+
:host { display:flex; align-items:center; justify-content:center; min-height:100vh; background:#fff; }
|
|
453
|
+
@media (min-width:560px) { :host { background:rgba(0,0,0,.50); } }
|
|
454
|
+
${(_b = (_a = buildStyles(tokens).match(/\.rc-spinner-ring[\s\S]*?@keyframes rc-spin[\s\S]*?}/)) == null ? void 0 : _a[0]) != null ? _b : ""}
|
|
455
|
+
</style>
|
|
456
|
+
<div class="rc-spinner-ring"></div>`;
|
|
457
|
+
shadow.appendChild(el);
|
|
458
|
+
}
|
|
459
|
+
buildModalHtml(p) {
|
|
460
|
+
return `
|
|
461
|
+
<style>${buildStyles(p.tokens)}</style>
|
|
462
|
+
|
|
463
|
+
<div class="rc-header">
|
|
464
|
+
<div class="rc-header-top">
|
|
465
|
+
<div class="rc-title">
|
|
466
|
+
<h2 id="rc-main-title">Auto Topup Subscription</h2>
|
|
467
|
+
<p id="rc-desc">Automate your airtime & data recharge</p>
|
|
468
|
+
</div>
|
|
469
|
+
<button class="rc-close-btn" id="rc-close" aria-label="Close">
|
|
470
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
471
|
+
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
472
|
+
</svg>
|
|
473
|
+
</button>
|
|
474
|
+
</div>
|
|
475
|
+
<div class="rc-account-bar">
|
|
476
|
+
<div class="rc-dot"></div>
|
|
477
|
+
<div>
|
|
478
|
+
<span class="rc-acc-label">Your Phone Number</span>
|
|
479
|
+
<span class="rc-acc-no">${(0, import_core2.formatPhone)(p.msisdn)}</span>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
|
|
484
|
+
<div class="rc-content">
|
|
485
|
+
<div class="rc-group">
|
|
486
|
+
<p class="rc-group-title">Registration Details</p>
|
|
487
|
+
<div class="rc-row" id="row-beneficiary">
|
|
488
|
+
<div class="rc-field" id="field-name">
|
|
489
|
+
<input type="text" id="rc-name" placeholder=" " value="${p.prefilledName}" autocomplete="name">
|
|
490
|
+
<label>Full Name</label>
|
|
491
|
+
</div>
|
|
492
|
+
<div class="rc-field hidden" id="field-msisdn">
|
|
493
|
+
<input type="tel" id="rc-msisdn-input" placeholder=" " autocomplete="tel">
|
|
494
|
+
<label>Phone Number</label>
|
|
495
|
+
</div>
|
|
496
|
+
</div>
|
|
497
|
+
</div>
|
|
498
|
+
|
|
499
|
+
<div class="rc-group" id="group-type-selector">
|
|
500
|
+
<p class="rc-group-title">Subscription Type</p>
|
|
501
|
+
<div class="rc-field has-val">
|
|
502
|
+
<select id="rc-type-select">
|
|
503
|
+
<option value="airtime">Airtime Only</option>
|
|
504
|
+
<option value="data">Data Only</option>
|
|
505
|
+
<option value="both">Both Airtime & Data</option>
|
|
506
|
+
</select>
|
|
507
|
+
<label>Automation Mode</label>
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
|
|
511
|
+
<hr class="rc-divider">
|
|
512
|
+
|
|
513
|
+
<div id="section-airtime" class="section-animate">
|
|
514
|
+
<p class="rc-group-title">Airtime Setup</p>
|
|
515
|
+
<div class="rc-row" style="grid-template-columns:1fr 1fr">
|
|
516
|
+
<div class="rc-field has-val">
|
|
517
|
+
<select id="airtimeThresholdId">${p.airtimeOptions || '<option value="">Loading\u2026</option>'}</select>
|
|
518
|
+
<label>Recharge when</label>
|
|
519
|
+
</div>
|
|
520
|
+
<div class="rc-field">
|
|
521
|
+
<input type="tel" id="airtimeTopupValue" placeholder=" ">
|
|
522
|
+
<label>Amount (\u20A6)</label>
|
|
523
|
+
<small>\u20A6${p.airtimeMin} \u2013 \u20A6${p.airtimeMax}</small>
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<div id="section-data" class="hidden section-animate">
|
|
529
|
+
<p class="rc-group-title">Data Setup</p>
|
|
530
|
+
<div class="rc-row" style="grid-template-columns:1fr 1fr">
|
|
531
|
+
<div class="rc-field has-val">
|
|
532
|
+
<select id="dataThresholdId">${p.dataOptions || '<option value="">Loading\u2026</option>'}</select>
|
|
533
|
+
<label>Recharge when</label>
|
|
534
|
+
</div>
|
|
535
|
+
<div class="rc-field has-val">
|
|
536
|
+
<select id="dataTopupValue">${p.dataPlanOptions || '<option value="">Loading\u2026</option>'}</select>
|
|
537
|
+
<label>Select Plan</label>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
541
|
+
|
|
542
|
+
<div id="section-dependent-controls" class="hidden">
|
|
543
|
+
<hr class="rc-divider">
|
|
544
|
+
<p class="rc-group-title">Spending Controls</p>
|
|
545
|
+
<div class="rc-row" id="row-spending">
|
|
546
|
+
<div class="rc-field" id="field-airtime-max">
|
|
547
|
+
<input type="tel" id="rc-airtime-max" placeholder=" ">
|
|
548
|
+
<label>Airtime Limit (\u20A6)</label>
|
|
549
|
+
</div>
|
|
550
|
+
<div class="rc-field" id="field-data-max">
|
|
551
|
+
<input type="tel" id="rc-data-max" placeholder=" ">
|
|
552
|
+
<label>Data Limit (\u20A6)</label>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
<button class="rc-submit-btn" id="rc-submit">Activate Subscription</button>
|
|
558
|
+
|
|
559
|
+
<div id="rc-dependent-link-wrap" class="rc-link-wrap hidden">
|
|
560
|
+
Or <a id="rc-switch-to-dep">add a dependent instead</a>
|
|
561
|
+
</div>
|
|
562
|
+
</div>
|
|
563
|
+
|
|
564
|
+
<div class="rc-footer">
|
|
565
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
566
|
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
|
567
|
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
|
568
|
+
</svg>
|
|
569
|
+
Secured by <strong> Retailcode</strong>
|
|
570
|
+
</div>
|
|
571
|
+
`;
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
// src/index.ts
|
|
576
|
+
var RetailcodeTopup = {
|
|
577
|
+
create(config) {
|
|
578
|
+
var _a;
|
|
579
|
+
const widget = new TopupWidget(__spreadProps(__spreadValues({}, config), {
|
|
580
|
+
theme: __spreadProps(__spreadValues({}, config.theme), {
|
|
581
|
+
accent: (0, import_core3.resolveAccent)((_a = config.theme) == null ? void 0 : _a.accent)
|
|
582
|
+
})
|
|
583
|
+
}));
|
|
584
|
+
return {
|
|
585
|
+
mount: () => widget.mount()
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
590
|
+
0 && (module.exports = {
|
|
591
|
+
RetailcodeTopup,
|
|
592
|
+
TopupWidget
|
|
593
|
+
});
|
|
594
|
+
//# sourceMappingURL=index.js.map
|