mmpay-browser-sdk 1.0.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/.vscode/settings.json +33 -0
- package/README.md +151 -0
- package/dist/cjs/index.d.ts +129 -0
- package/dist/cjs/index.js +469 -0
- package/dist/esm/index.d.ts +129 -0
- package/dist/esm/index.js +465 -0
- package/dist/mmpay-sdk.js +476 -0
- package/dist/mmpay-sdk.js.map +1 -0
- package/package.json +51 -0
- package/rollup.config.js +41 -0
- package/src/index.ts +529 -0
- package/test/home.html +243 -0
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
export class MMPaySDK {
|
|
2
|
+
constructor(publishableKey, options = {}) {
|
|
3
|
+
this.pollIntervalId = undefined;
|
|
4
|
+
this.onCompleteCallback = null;
|
|
5
|
+
this.overlayElement = null;
|
|
6
|
+
// Properties to store pending data for re-rendering after cancel attempt
|
|
7
|
+
this.pendingApiResponse = null;
|
|
8
|
+
this.pendingPaymentPayload = null;
|
|
9
|
+
this.QR_SIZE = 300;
|
|
10
|
+
if (!publishableKey) {
|
|
11
|
+
throw new Error("A Publishable Key is required to initialize [MMPaySDK].");
|
|
12
|
+
}
|
|
13
|
+
this.publishableKey = publishableKey;
|
|
14
|
+
this.environment = options.environment || 'production';
|
|
15
|
+
this.baseUrl = options.baseUrl || 'https://api.mm-pay.com';
|
|
16
|
+
this.merchantName = options.merchantName || 'Your Merchant';
|
|
17
|
+
this.POLL_INTERVAL_MS = options.pollInterval || 3000;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* _callApi
|
|
21
|
+
* @param endpoint
|
|
22
|
+
* @param data
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
async _callApi(endpoint, data = {}) {
|
|
26
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
'Authorization': `Bearer ${this.publishableKey}`
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(data)
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
const errorText = await response.text();
|
|
36
|
+
throw new Error(`API error (${response.status}): ${response.statusText}. Details: ${errorText}`);
|
|
37
|
+
}
|
|
38
|
+
return response.json();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* createPaymentRequest
|
|
42
|
+
* @param {PaymentData} payload
|
|
43
|
+
* @returns
|
|
44
|
+
*/
|
|
45
|
+
async createPaymentRequest(payload) {
|
|
46
|
+
try {
|
|
47
|
+
const endpoint = this.environment === 'sandbox'
|
|
48
|
+
? '/xpayments/sandbox-payment-create'
|
|
49
|
+
: '/xpayments/production-payment-create';
|
|
50
|
+
return await this._callApi(endpoint, payload);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error("Payment request failed:", error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* _createAndRenderModal
|
|
59
|
+
* @param {string} contentHtml
|
|
60
|
+
* @param isTerminal
|
|
61
|
+
* @returns
|
|
62
|
+
*/
|
|
63
|
+
_createAndRenderModal(contentHtml, isTerminal = false) {
|
|
64
|
+
this._cleanupModal(false);
|
|
65
|
+
const overlay = document.createElement('div');
|
|
66
|
+
overlay.id = 'mmpay-full-modal';
|
|
67
|
+
document.body.appendChild(overlay);
|
|
68
|
+
this.overlayElement = overlay;
|
|
69
|
+
const style = document.createElement('style');
|
|
70
|
+
style.innerHTML = `
|
|
71
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=Padauk:wght@400;700&display=swap');
|
|
72
|
+
|
|
73
|
+
#mmpay-full-modal {
|
|
74
|
+
position: fixed;
|
|
75
|
+
top: 0;
|
|
76
|
+
left: 0;
|
|
77
|
+
width: 100vw;
|
|
78
|
+
height: 100vh;
|
|
79
|
+
background-color: rgba(0, 0, 0, 0.85);
|
|
80
|
+
z-index: 9999;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: center;
|
|
84
|
+
transition: opacity 0.3s;
|
|
85
|
+
padding: 15px;
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
overflow: auto;
|
|
88
|
+
}
|
|
89
|
+
.mmpay-overlay-content {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
min-height: 100%;
|
|
94
|
+
width: 100%;
|
|
95
|
+
padding: 20px 0;
|
|
96
|
+
}
|
|
97
|
+
/* Card Base Styles */
|
|
98
|
+
.mmpay-card {
|
|
99
|
+
background: #ffffff;
|
|
100
|
+
border-radius: 16px;
|
|
101
|
+
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.4);
|
|
102
|
+
text-align: center;
|
|
103
|
+
font-family: 'Inter', 'Padauk', sans-serif;
|
|
104
|
+
border: 1px solid #f3f4f6;
|
|
105
|
+
animation: fadeInScale 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
106
|
+
box-sizing: border-box;
|
|
107
|
+
position: relative;
|
|
108
|
+
width: min(90vw, 330px);
|
|
109
|
+
margin: auto;
|
|
110
|
+
}
|
|
111
|
+
@keyframes fadeInScale {
|
|
112
|
+
from { opacity: 0; transform: scale(0.9); }
|
|
113
|
+
to { opacity: 1; transform: scale(1); }
|
|
114
|
+
}
|
|
115
|
+
.mmpay-close-btn {
|
|
116
|
+
position: absolute;
|
|
117
|
+
top: 10px;
|
|
118
|
+
right: 10px;
|
|
119
|
+
background: none;
|
|
120
|
+
border: none;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
padding: 8px;
|
|
123
|
+
color: #9ca3af;
|
|
124
|
+
border-radius: 50%;
|
|
125
|
+
transition: color 0.2s, background-color 0.2s;
|
|
126
|
+
line-height: 1;
|
|
127
|
+
z-index: 10;
|
|
128
|
+
}
|
|
129
|
+
.mmpay-close-btn:hover {
|
|
130
|
+
color: #4b5563;
|
|
131
|
+
background-color: #f3f4f6;
|
|
132
|
+
}
|
|
133
|
+
.mmpay-button {
|
|
134
|
+
background-color: #4f46e5;
|
|
135
|
+
color: white;
|
|
136
|
+
border: none;
|
|
137
|
+
padding: 10px 20px;
|
|
138
|
+
border-radius: 8px;
|
|
139
|
+
font-size: 0.95rem;
|
|
140
|
+
font-weight: 700;
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
margin-top: 15px;
|
|
143
|
+
transition: background-color 0.2s, box-shadow 0.2s, transform 0.1s;
|
|
144
|
+
box-shadow: 0 5px 15px rgba(79, 70, 229, 0.3);
|
|
145
|
+
width: 100%;
|
|
146
|
+
}
|
|
147
|
+
.mmpay-button:hover {
|
|
148
|
+
background-color: #4338ca;
|
|
149
|
+
box-shadow: 0 8px 18px rgba(67, 56, 202, 0.4);
|
|
150
|
+
transform: translateY(-1px);
|
|
151
|
+
}
|
|
152
|
+
.mmpay-button:active {
|
|
153
|
+
transform: translateY(0);
|
|
154
|
+
background-color: #3f35c7;
|
|
155
|
+
}
|
|
156
|
+
.mmpay-text-myanmar { font-family: 'Padauk', sans-serif; }
|
|
157
|
+
`;
|
|
158
|
+
overlay.appendChild(style);
|
|
159
|
+
window.MMPayCloseModal = (forceClose = false) => {
|
|
160
|
+
if (isTerminal || forceClose) {
|
|
161
|
+
this._cleanupModal(true);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this._showCancelConfirmationModal();
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
window.MMPayReRenderModal = () => this._reRenderPendingModalInstance();
|
|
168
|
+
overlay.innerHTML += `<div class="mmpay-overlay-content">${contentHtml}</div>`;
|
|
169
|
+
document.body.style.overflow = 'hidden'; // FIX: Prevent body scroll when modal is open
|
|
170
|
+
return overlay;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* showPaymentModal
|
|
174
|
+
* @param {PaymentData} payload
|
|
175
|
+
* @param {Function} onComplete
|
|
176
|
+
*/
|
|
177
|
+
async showPaymentModal(payload, onComplete) {
|
|
178
|
+
const initialContent = `<div class="mmpay-overlay-content"><div style="text-align: center; color: #fff;">ငွေပေးချေမှု စတင်နေသည်...</div></div>`;
|
|
179
|
+
this._createAndRenderModal(initialContent, false);
|
|
180
|
+
this.onCompleteCallback = onComplete;
|
|
181
|
+
try {
|
|
182
|
+
const apiResponse = await this.createPaymentRequest(payload);
|
|
183
|
+
if (apiResponse && apiResponse.qr && apiResponse.transactionId) {
|
|
184
|
+
this.pendingApiResponse = apiResponse;
|
|
185
|
+
this.pendingPaymentPayload = payload;
|
|
186
|
+
this._renderQrModalContent(apiResponse, payload, this.merchantName);
|
|
187
|
+
this._startPolling(apiResponse._id, onComplete);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
this._showTerminalMessage(apiResponse.orderId || 'N/A', 'FAILED', 'ငွေပေးချေမှု စတင်ရန် မအောင်မြင်ပါ။ QR ဒေတာ မရရှိပါ။');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
// Myanmar translation for "Error during payment initiation. See console."
|
|
195
|
+
this._showTerminalMessage(payload.orderId || 'N/A', 'FAILED', 'ငွေပေးချေမှု စတင်စဉ် အမှားအယွင်း ဖြစ်ပွားသည်။ ကွန်ဆိုးလ်တွင် ကြည့်ပါ။');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* _renderQrModalContent
|
|
200
|
+
* @param {CreatePaymentResponse} apiResponse
|
|
201
|
+
* @param {PaymentData} payload
|
|
202
|
+
* @param {string} merchantName
|
|
203
|
+
*/
|
|
204
|
+
_renderQrModalContent(apiResponse, payload, merchantName) {
|
|
205
|
+
const qrData = apiResponse.qr;
|
|
206
|
+
const amountDisplay = `${apiResponse.amount.toFixed(2)} ${apiResponse.currency}`;
|
|
207
|
+
const qrCanvasId = 'mmpayQrCanvas';
|
|
208
|
+
const orderId = payload.orderId;
|
|
209
|
+
window.MMPayDownloadQR = function () {
|
|
210
|
+
const canvas = document.getElementById(qrCanvasId);
|
|
211
|
+
if (!canvas)
|
|
212
|
+
return;
|
|
213
|
+
try {
|
|
214
|
+
const dataURL = canvas.toDataURL('image/png');
|
|
215
|
+
const link = document.createElement('a');
|
|
216
|
+
link.href = dataURL;
|
|
217
|
+
link.download = `MMPay-QR-${orderId}.png`;
|
|
218
|
+
document.body.appendChild(link);
|
|
219
|
+
link.click();
|
|
220
|
+
document.body.removeChild(link);
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
console.error("Failed to download QR image:", e);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const qrContentHtml = `
|
|
227
|
+
<style>
|
|
228
|
+
.mmpay-card { max-width: 350px; padding: 16px; }
|
|
229
|
+
.mmpay-header { color: #1f2937; font-size: 1rem; font-weight: bold; margin-bottom: 8px; }
|
|
230
|
+
.mmpay-qr-container { padding: 0; margin: 10px auto; display: inline-block; line-height: 0; width: 300px; height: 300px; }
|
|
231
|
+
#${qrCanvasId} { display: block; background: white; border-radius: 8px; width: 100%; height: 100%; }
|
|
232
|
+
.mmpay-amount { font-size: 1.2rem; font-weight: 800; color: #1f2937; margin: 0; }
|
|
233
|
+
.mmpay-separator { border-top: 1px solid #f3f4f6; margin: 12px 0; }
|
|
234
|
+
.mmpay-detail { font-size: 0.8rem; color: #6b7280; margin: 3px 0; display: flex; justify-content: space-between; align-items: center; padding: 0 5px; }
|
|
235
|
+
.mmpay-detail strong { color: #374151; font-weight: 600; text-align: right; }
|
|
236
|
+
.mmpay-detail span { text-align: left; }
|
|
237
|
+
.mmpay-secure-text { color: #757575; border-radius: 9999px; font-size: 0.8rem; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }
|
|
238
|
+
.mmpay-warning { font-size: 0.75rem; color: #9ca3af; font-weight: 500; margin-top: 12px; line-height: 1.5; }
|
|
239
|
+
</style>
|
|
240
|
+
|
|
241
|
+
<div class="mmpay-card">
|
|
242
|
+
<!-- Close Button - Triggers Confirmation Modal -->
|
|
243
|
+
<button class="mmpay-close-btn" onclick="MMPayCloseModal(false)">
|
|
244
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
|
|
245
|
+
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
|
|
246
|
+
</svg>
|
|
247
|
+
</button>
|
|
248
|
+
|
|
249
|
+
<div style="padding:0px auto 16px auto">
|
|
250
|
+
<img src="https://upload.wikimedia.org/wikipedia/commons/2/2f/MMQR_Logo.svg" style="width:40px">
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div class="mmpay-header mmpay-text-myanmar">
|
|
254
|
+
${merchantName} သို့ပေးချေပါ
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
<div class="mmpay-amount">${amountDisplay}</div>
|
|
258
|
+
|
|
259
|
+
<div class="mmpay-qr-container">
|
|
260
|
+
<canvas id="${qrCanvasId}" width="${this.QR_SIZE}" height="${this.QR_SIZE}"></canvas>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<button class="mmpay-button mmpay-text-myanmar" onclick="MMPayDownloadQR()">
|
|
264
|
+
QR ကုဒ်ကို ဒေါင်းလုဒ်လုပ်ပါ
|
|
265
|
+
</button>
|
|
266
|
+
|
|
267
|
+
<div class="mmpay-separator"></div>
|
|
268
|
+
|
|
269
|
+
<div class="mmpay-detail">
|
|
270
|
+
<span class="mmpay-text-myanmar">မှာယူမှုနံပါတ်:</span> <strong>${apiResponse.orderId}</strong>
|
|
271
|
+
</div>
|
|
272
|
+
<div class="mmpay-detail">
|
|
273
|
+
<span class="mmpay-text-myanmar">ငွေပေးငွေယူနံပါတ်:</span> <strong>${apiResponse.transactionId}</strong>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
<p class="mmpay-warning mmpay-text-myanmar">
|
|
277
|
+
ကျေးဇူးပြု၍ သင့်ဖုန်းဖြင့် ငွေပေးချေမှုကို အပြီးသတ်ပေးပါ။
|
|
278
|
+
</p>
|
|
279
|
+
|
|
280
|
+
<div class="mmpay-secure-text">
|
|
281
|
+
လုံခြုံသော ငွေပေးချေမှု
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
`;
|
|
285
|
+
this._cleanupModal(false);
|
|
286
|
+
this._createAndRenderModal(qrContentHtml, false);
|
|
287
|
+
this._injectQrScript(qrData, qrCanvasId);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* _showTerminalMessage
|
|
291
|
+
* @param {string} orderId
|
|
292
|
+
* @param {string} status
|
|
293
|
+
* @param {string} message
|
|
294
|
+
*/
|
|
295
|
+
_showTerminalMessage(orderId, status, message) {
|
|
296
|
+
this._cleanupModal(true);
|
|
297
|
+
const successColor = '#10b981'; // Tailwind Green 500
|
|
298
|
+
const failureColor = '#ef4444'; // Tailwind Red 500
|
|
299
|
+
const expiredColor = '#f59e0b'; // Tailwind Amber 500
|
|
300
|
+
let color;
|
|
301
|
+
let iconSvg;
|
|
302
|
+
let statusText;
|
|
303
|
+
if (status === 'SUCCESS') {
|
|
304
|
+
color = successColor;
|
|
305
|
+
statusText = 'အောင်မြင်';
|
|
306
|
+
iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="${color}" viewBox="0 0 16 16">
|
|
307
|
+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022l-3.473 4.425-2.094-2.094a.75.75 0 0 0-1.06 1.06L6.92 10.865l.764.764a.75.75 0 0 0 1.06 0l4.5-5.5a.75.75 0 0 0-.01-1.05z"/>
|
|
308
|
+
</svg>`;
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
// Shared icon for FAILED and EXPIRED (X mark)
|
|
312
|
+
color = status === 'FAILED' ? failureColor : expiredColor;
|
|
313
|
+
statusText = status === 'FAILED' ? 'မအောင်မြင်' : 'သက်တမ်းကုန်';
|
|
314
|
+
iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="${color}" viewBox="0 0 16 16">
|
|
315
|
+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.146a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.146z"/>
|
|
316
|
+
</svg>`;
|
|
317
|
+
}
|
|
318
|
+
const content = `
|
|
319
|
+
<div class="mmpay-card mmpay-terminal-card" style="
|
|
320
|
+
background: white; padding: 25px; box-sizing: border-box;
|
|
321
|
+
">
|
|
322
|
+
<div style="margin-bottom: 20px;">${iconSvg}</div>
|
|
323
|
+
|
|
324
|
+
<h2 style="font-size: 1.5rem; font-weight: 800; color: ${color}; margin-bottom: 10px;">
|
|
325
|
+
ငွေပေးချေမှု ${statusText}
|
|
326
|
+
</h2>
|
|
327
|
+
<p style="color: #4b5563; font-size: 0.95rem; font-weight: 600;">မှာယူမှုနံပါတ်: ${orderId}</p>
|
|
328
|
+
<p style="color: #6b7280; margin-top: 15px; margin-bottom: 25px; font-size: 0.9rem;">${message}</p>
|
|
329
|
+
|
|
330
|
+
<button class="mmpay-button mmpay-text-myanmar" style="background-color: ${color};" onclick="MMPayCloseModal(true)">
|
|
331
|
+
ပိတ်မည်
|
|
332
|
+
</button>
|
|
333
|
+
</div>
|
|
334
|
+
`;
|
|
335
|
+
this._createAndRenderModal(content, true); // Set isTerminal=true so the close button always forces cleanup
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* _showCancelConfirmationModal
|
|
339
|
+
*/
|
|
340
|
+
_showCancelConfirmationModal() {
|
|
341
|
+
if (this.pollIntervalId !== undefined) {
|
|
342
|
+
window.clearInterval(this.pollIntervalId);
|
|
343
|
+
this.pollIntervalId = undefined;
|
|
344
|
+
}
|
|
345
|
+
this._cleanupModal(false);
|
|
346
|
+
const content = `
|
|
347
|
+
<div class="mmpay-card mmpay-terminal-card" style="
|
|
348
|
+
background: white; padding: 25px; box-sizing: border-box;
|
|
349
|
+
">
|
|
350
|
+
<h2 style="font-size: 1.25rem; font-weight: 800; color: #f59e0b; margin-bottom: 10px;">
|
|
351
|
+
ငွေပေးချေမှုကို ပယ်ဖျက်မည်လား။
|
|
352
|
+
</h2>
|
|
353
|
+
<p style="color: #6b7280; margin-top: 15px; margin-bottom: 25px; font-size: 0.9rem;">
|
|
354
|
+
သင်သည် QR ဖြင့် ငွေပေးချေခြင်း မပြုရသေးကြောင်း သေချာပါသလား။ ပယ်ဖျက်ပြီးပါက ပြန်လည် စတင်ရပါမည်။
|
|
355
|
+
</p>
|
|
356
|
+
|
|
357
|
+
<div style="display: flex; gap: 10px;">
|
|
358
|
+
<button class="mmpay-button mmpay-text-myanmar"
|
|
359
|
+
style="flex-grow: 1; background-color: #f3f4f6; color: #1f2937; box-shadow: none; margin-top: 0;"
|
|
360
|
+
onclick="MMPayCloseModal(true)">
|
|
361
|
+
ပယ်ဖျက်မည်
|
|
362
|
+
</button>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
`;
|
|
366
|
+
this._createAndRenderModal(content, false); // Set isTerminal=false so the close button calls MMPayCloseModal(true)
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* _reRenderPendingModalInstance
|
|
370
|
+
*/
|
|
371
|
+
_reRenderPendingModalInstance() {
|
|
372
|
+
if (this.pendingApiResponse && this.pendingPaymentPayload && this.onCompleteCallback) {
|
|
373
|
+
this._cleanupModal(true);
|
|
374
|
+
this.showPaymentModal(this.pendingPaymentPayload, this.onCompleteCallback);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
this._cleanupModal(true);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Cleans up the modal and stops polling.
|
|
382
|
+
* @param restoreBodyScroll
|
|
383
|
+
*/
|
|
384
|
+
_cleanupModal(restoreBodyScroll) {
|
|
385
|
+
if (this.pollIntervalId !== undefined) {
|
|
386
|
+
window.clearInterval(this.pollIntervalId);
|
|
387
|
+
this.pollIntervalId = undefined;
|
|
388
|
+
}
|
|
389
|
+
if (this.overlayElement && this.overlayElement.parentNode) {
|
|
390
|
+
this.overlayElement.parentNode.removeChild(this.overlayElement);
|
|
391
|
+
this.overlayElement = null;
|
|
392
|
+
}
|
|
393
|
+
if (restoreBodyScroll) {
|
|
394
|
+
document.body.style.overflow = '';
|
|
395
|
+
}
|
|
396
|
+
delete window.MMPayCloseModal;
|
|
397
|
+
delete window.MMPayReRenderModal;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* _injectQrScript
|
|
401
|
+
* @param {string} qrData
|
|
402
|
+
* @param {string} qrCanvasId
|
|
403
|
+
*/
|
|
404
|
+
_injectQrScript(qrData, qrCanvasId) {
|
|
405
|
+
const script = document.createElement('script');
|
|
406
|
+
script.src = "https://cdn.jsdelivr.net/npm/qrious@4.0.2/dist/qrious.min.js";
|
|
407
|
+
script.onload = () => {
|
|
408
|
+
setTimeout(() => {
|
|
409
|
+
const canvas = document.getElementById(qrCanvasId);
|
|
410
|
+
if (typeof QRious !== 'undefined' && canvas) {
|
|
411
|
+
new QRious({
|
|
412
|
+
element: canvas,
|
|
413
|
+
value: qrData,
|
|
414
|
+
size: this.QR_SIZE,
|
|
415
|
+
padding: 15,
|
|
416
|
+
level: 'H'
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
console.error('Failed to load QRious or find canvas.');
|
|
421
|
+
}
|
|
422
|
+
}, 10);
|
|
423
|
+
};
|
|
424
|
+
document.head.appendChild(script);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* _startPolling
|
|
428
|
+
* @param {string} _id
|
|
429
|
+
* @param {Function} onComplete
|
|
430
|
+
*/
|
|
431
|
+
async _startPolling(_id, onComplete) {
|
|
432
|
+
if (this.pollIntervalId !== undefined) {
|
|
433
|
+
window.clearInterval(this.pollIntervalId);
|
|
434
|
+
}
|
|
435
|
+
const checkStatus = async () => {
|
|
436
|
+
try {
|
|
437
|
+
const endpoint = this.environment === 'sandbox'
|
|
438
|
+
? '/xpayments/sandbox-payment-polling'
|
|
439
|
+
: '/xpayments/production-payment-polling';
|
|
440
|
+
const response = await this._callApi(endpoint, { _id: _id });
|
|
441
|
+
const status = (response.status || '').toUpperCase();
|
|
442
|
+
if (status === 'SUCCESS' || status === 'FAILED' || status === 'EXPIRED') {
|
|
443
|
+
window.clearInterval(this.pollIntervalId);
|
|
444
|
+
this.pollIntervalId = undefined;
|
|
445
|
+
const success = status === 'SUCCESS';
|
|
446
|
+
const message = success ?
|
|
447
|
+
`ငွေပေးချေမှု အောင်မြင်ပါပြီ။ ငွေပေးငွေယူ ရည်ညွှန်းနံပါတ်: ${response.transactionRefId || 'N/A'}` :
|
|
448
|
+
`ငွေပေးချေမှု ${status === 'FAILED' ? 'မအောင်မြင်ပါ' : 'သက်တမ်းကုန်သွားပါပြီ'}.`;
|
|
449
|
+
this._showTerminalMessage(response.orderId || 'N/A', status, message);
|
|
450
|
+
if (onComplete) {
|
|
451
|
+
onComplete({ success: success, transaction: response });
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
console.error("Polling error:", error);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
checkStatus();
|
|
461
|
+
this.pollIntervalId = window.setInterval(checkStatus, this.POLL_INTERVAL_MS);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// Make the SDK class and its instance methods accessible globally
|
|
465
|
+
window.MMPaySDK = MMPaySDK;
|