recur-tw 0.9.9 → 0.9.11
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.cjs +66 -67
- package/dist/index.js +66 -67
- package/dist/recur.umd.js +116 -83
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1035,7 +1035,7 @@ var init_payment_form_shadow = __esm({
|
|
|
1035
1035
|
var payment_form_light_default;
|
|
1036
1036
|
var init_payment_form_light = __esm({
|
|
1037
1037
|
"src/components/styles/payment-form-light.css"() {
|
|
1038
|
-
payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display:
|
|
1038
|
+
payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:focus {\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n padding: 10px 12px;\n font-size: 16px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
|
|
1039
1039
|
}
|
|
1040
1040
|
});
|
|
1041
1041
|
|
|
@@ -1224,7 +1224,32 @@ var init_payment_form = __esm({
|
|
|
1224
1224
|
const amount = this.getAttribute("amount");
|
|
1225
1225
|
const interval = this.getAttribute("interval");
|
|
1226
1226
|
if (!productName || !amount) {
|
|
1227
|
-
|
|
1227
|
+
const isSubscription2 = !!interval;
|
|
1228
|
+
return litHtml.html`
|
|
1229
|
+
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1230
|
+
<div class="recur-order-summary__row">
|
|
1231
|
+
<span class="recur-order-summary__label">${isSubscription2 ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
|
|
1232
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
|
|
1233
|
+
</div>
|
|
1234
|
+
${isSubscription2 ? litHtml.html`
|
|
1235
|
+
<div class="recur-order-summary__row">
|
|
1236
|
+
<span class="recur-order-summary__label">計費週期</span>
|
|
1237
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
|
|
1238
|
+
</div>
|
|
1239
|
+
` : litHtml.nothing}
|
|
1240
|
+
<div class="recur-order-summary__row">
|
|
1241
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1242
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1243
|
+
</div>
|
|
1244
|
+
<div class="recur-coupon">
|
|
1245
|
+
<span class="recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1246
|
+
</div>
|
|
1247
|
+
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1248
|
+
<span class="recur-order-summary__label">總計</span>
|
|
1249
|
+
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1250
|
+
</div>
|
|
1251
|
+
</div>
|
|
1252
|
+
`;
|
|
1228
1253
|
}
|
|
1229
1254
|
const intervalMap = {
|
|
1230
1255
|
"day": "\u65E5",
|
|
@@ -1236,35 +1261,33 @@ var init_payment_form = __esm({
|
|
|
1236
1261
|
const originalAmount = Number(amount);
|
|
1237
1262
|
const discountAmount = this._appliedCoupon?.discountAmount || 0;
|
|
1238
1263
|
const finalAmount = originalAmount - discountAmount;
|
|
1264
|
+
const isSubscription = !!periodText;
|
|
1239
1265
|
return litHtml.html`
|
|
1240
1266
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1241
1267
|
<div class="recur-order-summary__row">
|
|
1242
|
-
<span class="recur-order-summary__label"
|
|
1268
|
+
<span class="recur-order-summary__label">${isSubscription ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
|
|
1243
1269
|
<span class="recur-order-summary__value">${productName}</span>
|
|
1244
1270
|
</div>
|
|
1245
1271
|
|
|
1246
|
-
${
|
|
1272
|
+
${isSubscription ? litHtml.html`
|
|
1247
1273
|
<div class="recur-order-summary__row">
|
|
1248
1274
|
<span class="recur-order-summary__label">計費週期</span>
|
|
1249
1275
|
<span class="recur-order-summary__value">每${periodText}</span>
|
|
1250
1276
|
</div>
|
|
1251
1277
|
` : litHtml.nothing}
|
|
1252
1278
|
|
|
1279
|
+
<!-- 小計 (Subtotal) - always show -->
|
|
1280
|
+
<div class="recur-order-summary__row">
|
|
1281
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1282
|
+
<span class="recur-order-summary__value">NT$ ${originalAmount.toLocaleString()}</span>
|
|
1283
|
+
</div>
|
|
1284
|
+
|
|
1285
|
+
<!-- 優惠碼區塊 (Coupon section with discount amount) -->
|
|
1253
1286
|
<div class="recur-coupon" id="${this.containerId}-coupon">
|
|
1254
1287
|
${this.renderCoupon()}
|
|
1255
1288
|
</div>
|
|
1256
1289
|
|
|
1257
|
-
|
|
1258
|
-
<div class="recur-order-summary__row">
|
|
1259
|
-
<span class="recur-order-summary__label">小計</span>
|
|
1260
|
-
<span class="recur-order-summary__value">NT$ ${originalAmount.toLocaleString()}</span>
|
|
1261
|
-
</div>
|
|
1262
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1263
|
-
<span class="recur-order-summary__label">折扣</span>
|
|
1264
|
-
<span class="recur-order-summary__value">-NT$ ${discountAmount.toLocaleString()}</span>
|
|
1265
|
-
</div>
|
|
1266
|
-
` : litHtml.nothing}
|
|
1267
|
-
|
|
1290
|
+
<!-- 總計 (Total) -->
|
|
1268
1291
|
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1269
1292
|
<span class="recur-order-summary__label">總計</span>
|
|
1270
1293
|
<span class="recur-order-summary__total">NT$ ${finalAmount.toLocaleString()}</span>
|
|
@@ -1278,26 +1301,24 @@ var init_payment_form = __esm({
|
|
|
1278
1301
|
<div class="recur-coupon__applied">
|
|
1279
1302
|
<div class="recur-coupon__applied-info">
|
|
1280
1303
|
${icons.tagApplied}
|
|
1281
|
-
|
|
1282
|
-
<
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1304
|
+
${this._appliedCoupon.couponName ? litHtml.html`
|
|
1305
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
|
|
1306
|
+
<span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
|
|
1307
|
+
` : litHtml.html`
|
|
1308
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
|
|
1309
|
+
`}
|
|
1310
|
+
<button
|
|
1311
|
+
type="button"
|
|
1312
|
+
class="recur-coupon__remove"
|
|
1313
|
+
?disabled=${this._couponLoading}
|
|
1314
|
+
@click=${() => this.removeCoupon()}
|
|
1315
|
+
>
|
|
1316
|
+
${this._couponLoading ? icons.spinner : icons.close}
|
|
1317
|
+
</button>
|
|
1289
1318
|
</div>
|
|
1290
1319
|
<span class="recur-coupon__applied-amount">
|
|
1291
1320
|
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1292
1321
|
</span>
|
|
1293
|
-
<button
|
|
1294
|
-
type="button"
|
|
1295
|
-
class="recur-coupon__remove"
|
|
1296
|
-
?disabled=${this._couponLoading}
|
|
1297
|
-
@click=${() => this.removeCoupon()}
|
|
1298
|
-
>
|
|
1299
|
-
${this._couponLoading ? icons.spinner : icons.close}
|
|
1300
|
-
</button>
|
|
1301
1322
|
</div>
|
|
1302
1323
|
`;
|
|
1303
1324
|
}
|
|
@@ -1386,7 +1407,8 @@ var init_payment_form = __esm({
|
|
|
1386
1407
|
}
|
|
1387
1408
|
// Direct DOM manipulation for coupon section updates (avoids lit-html tracking issues)
|
|
1388
1409
|
updateCouponSectionDOM() {
|
|
1389
|
-
const
|
|
1410
|
+
const containerId = `${this.containerId}-coupon`;
|
|
1411
|
+
const container = document.getElementById(containerId);
|
|
1390
1412
|
if (!container) return;
|
|
1391
1413
|
if (this._appliedCoupon) {
|
|
1392
1414
|
container.innerHTML = this.getCouponAppliedHTML();
|
|
@@ -1443,22 +1465,19 @@ var init_payment_form = __esm({
|
|
|
1443
1465
|
}
|
|
1444
1466
|
getCouponAppliedHTML() {
|
|
1445
1467
|
const coupon = this._appliedCoupon;
|
|
1446
|
-
const
|
|
1468
|
+
const nameHTML = coupon.couponName ? `<span class="recur-coupon__applied-name">${coupon.couponName}</span><span class="recur-coupon__applied-code">(${coupon.code})</span>` : `<span class="recur-coupon__applied-name">${coupon.code}</span>`;
|
|
1447
1469
|
return `
|
|
1448
1470
|
<div class="recur-coupon__applied">
|
|
1449
1471
|
<div class="recur-coupon__applied-info">
|
|
1450
1472
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1451
1473
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
1452
1474
|
</svg>
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
${
|
|
1456
|
-
</
|
|
1475
|
+
${nameHTML}
|
|
1476
|
+
<button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
|
|
1477
|
+
${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1478
|
+
</button>
|
|
1457
1479
|
</div>
|
|
1458
1480
|
<span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
|
|
1459
|
-
<button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
|
|
1460
|
-
${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1461
|
-
</button>
|
|
1462
1481
|
</div>
|
|
1463
1482
|
`;
|
|
1464
1483
|
}
|
|
@@ -1485,31 +1504,7 @@ var init_payment_form = __esm({
|
|
|
1485
1504
|
const amount = Number(this.getAttribute("amount") || 0);
|
|
1486
1505
|
const discountAmount = this._appliedCoupon?.discountAmount || 0;
|
|
1487
1506
|
const finalAmount = amount - discountAmount;
|
|
1488
|
-
let discountRow = summaryContainer.querySelector(".recur-order-summary__row--discount");
|
|
1489
1507
|
const totalRow = summaryContainer.querySelector(".recur-order-summary__row--total");
|
|
1490
|
-
if (discountAmount > 0) {
|
|
1491
|
-
if (!discountRow && totalRow) {
|
|
1492
|
-
const subtotalHTML = `
|
|
1493
|
-
<div class="recur-order-summary__row">
|
|
1494
|
-
<span class="recur-order-summary__label">\u5C0F\u8A08</span>
|
|
1495
|
-
<span class="recur-order-summary__value">NT$ ${amount.toLocaleString()}</span>
|
|
1496
|
-
</div>
|
|
1497
|
-
`;
|
|
1498
|
-
const discountHTML = `
|
|
1499
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1500
|
-
<span class="recur-order-summary__label">\u6298\u6263</span>
|
|
1501
|
-
<span class="recur-order-summary__value">-NT$ ${discountAmount.toLocaleString()}</span>
|
|
1502
|
-
</div>
|
|
1503
|
-
`;
|
|
1504
|
-
totalRow.insertAdjacentHTML("beforebegin", subtotalHTML + discountHTML);
|
|
1505
|
-
}
|
|
1506
|
-
} else {
|
|
1507
|
-
const subtotalRow = summaryContainer.querySelector(".recur-order-summary__row:not(.recur-order-summary__row--total):last-of-type");
|
|
1508
|
-
discountRow?.remove();
|
|
1509
|
-
if (subtotalRow?.querySelector(".recur-order-summary__label")?.textContent === "\u5C0F\u8A08") {
|
|
1510
|
-
subtotalRow.remove();
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
1508
|
const totalValue = totalRow?.querySelector(".recur-order-summary__total");
|
|
1514
1509
|
if (totalValue) {
|
|
1515
1510
|
totalValue.textContent = `NT$ ${finalAmount.toLocaleString()}`;
|
|
@@ -1537,7 +1532,7 @@ var init_payment_form = __esm({
|
|
|
1537
1532
|
this._couponError = null;
|
|
1538
1533
|
this.updateCouponSectionDOM();
|
|
1539
1534
|
try {
|
|
1540
|
-
const response = await fetch(`${apiBaseUrl}/
|
|
1535
|
+
const response = await fetch(`${apiBaseUrl}/v1/checkouts/${checkoutId}/coupon`, {
|
|
1541
1536
|
method: "POST",
|
|
1542
1537
|
headers: { "Content-Type": "application/json" },
|
|
1543
1538
|
body: JSON.stringify({ code })
|
|
@@ -1583,7 +1578,7 @@ var init_payment_form = __esm({
|
|
|
1583
1578
|
this._couponLoading = true;
|
|
1584
1579
|
this.updateCouponSectionDOM();
|
|
1585
1580
|
try {
|
|
1586
|
-
const response = await fetch(`${apiBaseUrl}/
|
|
1581
|
+
const response = await fetch(`${apiBaseUrl}/v1/checkouts/${checkoutId}/coupon`, {
|
|
1587
1582
|
method: "DELETE"
|
|
1588
1583
|
});
|
|
1589
1584
|
if (!response.ok) {
|
|
@@ -2565,7 +2560,7 @@ function toCamelCase(obj) {
|
|
|
2565
2560
|
|
|
2566
2561
|
// package.json
|
|
2567
2562
|
var package_default = {
|
|
2568
|
-
version: "0.9.
|
|
2563
|
+
version: "0.9.11"};
|
|
2569
2564
|
var SDK_VERSION = package_default.version;
|
|
2570
2565
|
var SDK_TYPE = "react";
|
|
2571
2566
|
var RecurContext = React.createContext(null);
|
|
@@ -2881,6 +2876,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
|
|
|
2881
2876
|
container.innerHTML = "";
|
|
2882
2877
|
const paymentForm = document.createElement("recur-payment-form");
|
|
2883
2878
|
paymentForm.setAttribute("container-id", containerElementId);
|
|
2879
|
+
if (checkoutResult.checkout?.id) {
|
|
2880
|
+
paymentForm.setAttribute("checkout-id", checkoutResult.checkout.id);
|
|
2881
|
+
}
|
|
2882
|
+
paymentForm.setAttribute("api-base-url", baseUrl);
|
|
2884
2883
|
if (options.customerName) {
|
|
2885
2884
|
paymentForm.setAttribute("customer-name", options.customerName);
|
|
2886
2885
|
}
|
package/dist/index.js
CHANGED
|
@@ -1029,7 +1029,7 @@ var init_payment_form_shadow = __esm({
|
|
|
1029
1029
|
var payment_form_light_default;
|
|
1030
1030
|
var init_payment_form_light = __esm({
|
|
1031
1031
|
"src/components/styles/payment-form-light.css"() {
|
|
1032
|
-
payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display:
|
|
1032
|
+
payment_form_light_default = "/**\n * Payment Form - Light DOM Styles\n * These styles are applied to slotted content in the Light DOM\n * Using BEM naming convention with 'recur-' prefix for isolation\n */\n\n/* ============================================\n * Order Summary Styles\n * ============================================ */\n.recur-order-summary {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n padding: 16px;\n}\n\n.recur-order-summary__row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.recur-order-summary__row--total {\n margin-bottom: 0;\n padding-top: 12px;\n border-top: 1px solid #e2e8f0;\n}\n\n.recur-order-summary__label {\n font-size: 14px;\n color: #4a5568;\n}\n\n.recur-order-summary__value {\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n color: #2d3748;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.recur-order-summary__total {\n font-size: 18px;\n line-height: 26px;\n font-weight: 700;\n color: #1a202c;\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n/* ============================================\n * Coupon Section Styles\n * ============================================ */\n.recur-coupon {\n padding: 12px 0;\n border-top: 1px solid #e2e8f0;\n margin-top: 12px;\n min-height: 36px;\n display: flex;\n align-items: center;\n}\n\n.recur-coupon__trigger {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n height: 36px;\n background: none;\n border: none;\n padding: 0;\n font-size: 14px;\n line-height: 1;\n color: #718096;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.recur-coupon__trigger:hover {\n color: #4a5568;\n}\n\n.recur-coupon__trigger-icon {\n width: 16px;\n height: 16px;\n}\n\n.recur-coupon__input-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__input {\n flex: 1;\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n text-transform: uppercase;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.recur-coupon__input::placeholder {\n text-transform: none;\n}\n\n.recur-coupon__input:focus {\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-coupon__btn {\n height: 36px;\n padding: 0 12px;\n font-size: 14px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s, opacity 0.2s;\n white-space: nowrap;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\n min-width: 52px;\n}\n\n.recur-coupon__btn--apply .recur-coupon__spinner {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__btn--apply:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-coupon__btn--apply:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.recur-coupon__btn--cancel {\n background: transparent;\n color: #718096;\n border: 1px solid #d1d5db;\n}\n\n.recur-coupon__btn--cancel:hover {\n background: #f7fafc;\n}\n\n.recur-coupon__error {\n width: 100%;\n margin-top: 8px;\n font-size: 13px;\n color: #dc2626;\n}\n\n.recur-coupon__applied {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n}\n\n.recur-coupon__applied-info {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n\n.recur-coupon__applied-icon {\n width: 16px;\n height: 16px;\n color: #dc2626;\n flex-shrink: 0;\n}\n\n.recur-coupon__applied-name {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n}\n\n.recur-coupon__applied-code {\n font-size: 14px;\n color: #9ca3af;\n white-space: nowrap;\n margin-right: 2px;\n}\n\n.recur-coupon__applied-amount {\n font-size: 14px;\n font-weight: 500;\n color: #dc2626;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.recur-coupon__remove {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #9ca3af;\n border-radius: 4px;\n transition: color 0.2s, background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.recur-coupon__remove:hover {\n color: #6b7280;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.recur-coupon__remove-icon {\n width: 14px;\n height: 14px;\n}\n\n.recur-coupon__spinner {\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n/* Discount Row */\n.recur-order-summary__row--discount {\n color: #16a34a;\n}\n\n.recur-order-summary__row--discount .recur-order-summary__value {\n color: #16a34a;\n font-weight: 500;\n}\n\n/* ============================================\n * Customer Info Styles\n * ============================================ */\n.recur-info-display {\n background: #f7fafc;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 8px;\n}\n\n.recur-info-row {\n margin-bottom: 12px;\n}\n\n.recur-info-row:last-child {\n margin-bottom: 0;\n}\n\n.recur-info-label {\n display: block;\n font-size: 12px;\n line-height: 16px;\n color: #718096;\n margin-bottom: 2px;\n}\n\n.recur-info-value {\n display: block;\n font-size: 14px;\n line-height: 20px;\n min-height: 20px;\n color: #2d3748;\n font-weight: 500;\n word-break: break-all;\n}\n\n.recur-form-group {\n margin-bottom: 16px;\n}\n\n.recur-form-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-form-input {\n width: 100%;\n padding: 10px 12px;\n font-size: 16px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.recur-form-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.recur-form-input:hover:not(:focus) {\n border-color: #9ca3af;\n}\n\n/* ============================================\n * Card Fields Styles\n * ============================================ */\n.recur-card-field {\n margin-bottom: 16px;\n}\n\n.recur-card-field-label {\n display: block;\n font-size: 14px;\n font-weight: 500;\n color: #2d3748;\n margin-bottom: 6px;\n}\n\n.recur-payuni-iframe {\n height: 36px;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n touch-action: manipulation;\n}\n\n.recur-card-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n column-gap: 16px;\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.recur-card-field-container {\n position: relative;\n touch-action: manipulation;\n}\n\n.recur-card-skeleton {\n position: absolute;\n top: 0;\n left: 0;\n height: 36px;\n width: 100%;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n z-index: 1;\n pointer-events: none;\n}\n\n.recur-card-skeleton.hidden {\n display: none;\n}\n\n@keyframes recur-skeleton-loading {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ============================================\n * Submit Button Styles\n * ============================================ */\n.recur-submit-button {\n width: 100%;\n padding: 14px 20px;\n font-size: 16px;\n font-weight: 500;\n color: #ffffff;\n background: #18181b;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n box-sizing: border-box;\n}\n\n.recur-submit-button:hover:not(:disabled) {\n background: #27272a;\n}\n\n.recur-submit-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.recur-submit-button.loading {\n cursor: wait;\n}\n\n.recur-loading-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: recur-spin 0.6s linear infinite;\n}\n\n@keyframes recur-spin {\n to { transform: rotate(360deg); }\n}\n\n/* ============================================\n * Skeleton Loading Styles\n * ============================================ */\n.recur-skeleton {\n display: inline-block;\n background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);\n background-size: 200% 100%;\n animation: recur-skeleton-loading 1.5s ease-in-out infinite;\n border-radius: 4px;\n}\n";
|
|
1033
1033
|
}
|
|
1034
1034
|
});
|
|
1035
1035
|
|
|
@@ -1218,7 +1218,32 @@ var init_payment_form = __esm({
|
|
|
1218
1218
|
const amount = this.getAttribute("amount");
|
|
1219
1219
|
const interval = this.getAttribute("interval");
|
|
1220
1220
|
if (!productName || !amount) {
|
|
1221
|
-
|
|
1221
|
+
const isSubscription2 = !!interval;
|
|
1222
|
+
return html`
|
|
1223
|
+
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1224
|
+
<div class="recur-order-summary__row">
|
|
1225
|
+
<span class="recur-order-summary__label">${isSubscription2 ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
|
|
1226
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
|
|
1227
|
+
</div>
|
|
1228
|
+
${isSubscription2 ? html`
|
|
1229
|
+
<div class="recur-order-summary__row">
|
|
1230
|
+
<span class="recur-order-summary__label">計費週期</span>
|
|
1231
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
|
|
1232
|
+
</div>
|
|
1233
|
+
` : nothing}
|
|
1234
|
+
<div class="recur-order-summary__row">
|
|
1235
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1236
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1237
|
+
</div>
|
|
1238
|
+
<div class="recur-coupon">
|
|
1239
|
+
<span class="recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1240
|
+
</div>
|
|
1241
|
+
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1242
|
+
<span class="recur-order-summary__label">總計</span>
|
|
1243
|
+
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1244
|
+
</div>
|
|
1245
|
+
</div>
|
|
1246
|
+
`;
|
|
1222
1247
|
}
|
|
1223
1248
|
const intervalMap = {
|
|
1224
1249
|
"day": "\u65E5",
|
|
@@ -1230,35 +1255,33 @@ var init_payment_form = __esm({
|
|
|
1230
1255
|
const originalAmount = Number(amount);
|
|
1231
1256
|
const discountAmount = this._appliedCoupon?.discountAmount || 0;
|
|
1232
1257
|
const finalAmount = originalAmount - discountAmount;
|
|
1258
|
+
const isSubscription = !!periodText;
|
|
1233
1259
|
return html`
|
|
1234
1260
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1235
1261
|
<div class="recur-order-summary__row">
|
|
1236
|
-
<span class="recur-order-summary__label"
|
|
1262
|
+
<span class="recur-order-summary__label">${isSubscription ? "\u8A02\u95B1\u65B9\u6848" : "\u5546\u54C1"}</span>
|
|
1237
1263
|
<span class="recur-order-summary__value">${productName}</span>
|
|
1238
1264
|
</div>
|
|
1239
1265
|
|
|
1240
|
-
${
|
|
1266
|
+
${isSubscription ? html`
|
|
1241
1267
|
<div class="recur-order-summary__row">
|
|
1242
1268
|
<span class="recur-order-summary__label">計費週期</span>
|
|
1243
1269
|
<span class="recur-order-summary__value">每${periodText}</span>
|
|
1244
1270
|
</div>
|
|
1245
1271
|
` : nothing}
|
|
1246
1272
|
|
|
1273
|
+
<!-- 小計 (Subtotal) - always show -->
|
|
1274
|
+
<div class="recur-order-summary__row">
|
|
1275
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1276
|
+
<span class="recur-order-summary__value">NT$ ${originalAmount.toLocaleString()}</span>
|
|
1277
|
+
</div>
|
|
1278
|
+
|
|
1279
|
+
<!-- 優惠碼區塊 (Coupon section with discount amount) -->
|
|
1247
1280
|
<div class="recur-coupon" id="${this.containerId}-coupon">
|
|
1248
1281
|
${this.renderCoupon()}
|
|
1249
1282
|
</div>
|
|
1250
1283
|
|
|
1251
|
-
|
|
1252
|
-
<div class="recur-order-summary__row">
|
|
1253
|
-
<span class="recur-order-summary__label">小計</span>
|
|
1254
|
-
<span class="recur-order-summary__value">NT$ ${originalAmount.toLocaleString()}</span>
|
|
1255
|
-
</div>
|
|
1256
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1257
|
-
<span class="recur-order-summary__label">折扣</span>
|
|
1258
|
-
<span class="recur-order-summary__value">-NT$ ${discountAmount.toLocaleString()}</span>
|
|
1259
|
-
</div>
|
|
1260
|
-
` : nothing}
|
|
1261
|
-
|
|
1284
|
+
<!-- 總計 (Total) -->
|
|
1262
1285
|
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1263
1286
|
<span class="recur-order-summary__label">總計</span>
|
|
1264
1287
|
<span class="recur-order-summary__total">NT$ ${finalAmount.toLocaleString()}</span>
|
|
@@ -1272,26 +1295,24 @@ var init_payment_form = __esm({
|
|
|
1272
1295
|
<div class="recur-coupon__applied">
|
|
1273
1296
|
<div class="recur-coupon__applied-info">
|
|
1274
1297
|
${icons.tagApplied}
|
|
1275
|
-
|
|
1276
|
-
<
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1298
|
+
${this._appliedCoupon.couponName ? html`
|
|
1299
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
|
|
1300
|
+
<span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
|
|
1301
|
+
` : html`
|
|
1302
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
|
|
1303
|
+
`}
|
|
1304
|
+
<button
|
|
1305
|
+
type="button"
|
|
1306
|
+
class="recur-coupon__remove"
|
|
1307
|
+
?disabled=${this._couponLoading}
|
|
1308
|
+
@click=${() => this.removeCoupon()}
|
|
1309
|
+
>
|
|
1310
|
+
${this._couponLoading ? icons.spinner : icons.close}
|
|
1311
|
+
</button>
|
|
1283
1312
|
</div>
|
|
1284
1313
|
<span class="recur-coupon__applied-amount">
|
|
1285
1314
|
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1286
1315
|
</span>
|
|
1287
|
-
<button
|
|
1288
|
-
type="button"
|
|
1289
|
-
class="recur-coupon__remove"
|
|
1290
|
-
?disabled=${this._couponLoading}
|
|
1291
|
-
@click=${() => this.removeCoupon()}
|
|
1292
|
-
>
|
|
1293
|
-
${this._couponLoading ? icons.spinner : icons.close}
|
|
1294
|
-
</button>
|
|
1295
1316
|
</div>
|
|
1296
1317
|
`;
|
|
1297
1318
|
}
|
|
@@ -1380,7 +1401,8 @@ var init_payment_form = __esm({
|
|
|
1380
1401
|
}
|
|
1381
1402
|
// Direct DOM manipulation for coupon section updates (avoids lit-html tracking issues)
|
|
1382
1403
|
updateCouponSectionDOM() {
|
|
1383
|
-
const
|
|
1404
|
+
const containerId = `${this.containerId}-coupon`;
|
|
1405
|
+
const container = document.getElementById(containerId);
|
|
1384
1406
|
if (!container) return;
|
|
1385
1407
|
if (this._appliedCoupon) {
|
|
1386
1408
|
container.innerHTML = this.getCouponAppliedHTML();
|
|
@@ -1437,22 +1459,19 @@ var init_payment_form = __esm({
|
|
|
1437
1459
|
}
|
|
1438
1460
|
getCouponAppliedHTML() {
|
|
1439
1461
|
const coupon = this._appliedCoupon;
|
|
1440
|
-
const
|
|
1462
|
+
const nameHTML = coupon.couponName ? `<span class="recur-coupon__applied-name">${coupon.couponName}</span><span class="recur-coupon__applied-code">(${coupon.code})</span>` : `<span class="recur-coupon__applied-name">${coupon.code}</span>`;
|
|
1441
1463
|
return `
|
|
1442
1464
|
<div class="recur-coupon__applied">
|
|
1443
1465
|
<div class="recur-coupon__applied-info">
|
|
1444
1466
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1445
1467
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
1446
1468
|
</svg>
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
${
|
|
1450
|
-
</
|
|
1469
|
+
${nameHTML}
|
|
1470
|
+
<button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
|
|
1471
|
+
${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1472
|
+
</button>
|
|
1451
1473
|
</div>
|
|
1452
1474
|
<span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>
|
|
1453
|
-
<button type="button" class="recur-coupon__remove" ${this._couponLoading ? "disabled" : ""}>
|
|
1454
|
-
${this._couponLoading ? '<span class="recur-coupon__spinner"></span>' : '<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1455
|
-
</button>
|
|
1456
1475
|
</div>
|
|
1457
1476
|
`;
|
|
1458
1477
|
}
|
|
@@ -1479,31 +1498,7 @@ var init_payment_form = __esm({
|
|
|
1479
1498
|
const amount = Number(this.getAttribute("amount") || 0);
|
|
1480
1499
|
const discountAmount = this._appliedCoupon?.discountAmount || 0;
|
|
1481
1500
|
const finalAmount = amount - discountAmount;
|
|
1482
|
-
let discountRow = summaryContainer.querySelector(".recur-order-summary__row--discount");
|
|
1483
1501
|
const totalRow = summaryContainer.querySelector(".recur-order-summary__row--total");
|
|
1484
|
-
if (discountAmount > 0) {
|
|
1485
|
-
if (!discountRow && totalRow) {
|
|
1486
|
-
const subtotalHTML = `
|
|
1487
|
-
<div class="recur-order-summary__row">
|
|
1488
|
-
<span class="recur-order-summary__label">\u5C0F\u8A08</span>
|
|
1489
|
-
<span class="recur-order-summary__value">NT$ ${amount.toLocaleString()}</span>
|
|
1490
|
-
</div>
|
|
1491
|
-
`;
|
|
1492
|
-
const discountHTML = `
|
|
1493
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1494
|
-
<span class="recur-order-summary__label">\u6298\u6263</span>
|
|
1495
|
-
<span class="recur-order-summary__value">-NT$ ${discountAmount.toLocaleString()}</span>
|
|
1496
|
-
</div>
|
|
1497
|
-
`;
|
|
1498
|
-
totalRow.insertAdjacentHTML("beforebegin", subtotalHTML + discountHTML);
|
|
1499
|
-
}
|
|
1500
|
-
} else {
|
|
1501
|
-
const subtotalRow = summaryContainer.querySelector(".recur-order-summary__row:not(.recur-order-summary__row--total):last-of-type");
|
|
1502
|
-
discountRow?.remove();
|
|
1503
|
-
if (subtotalRow?.querySelector(".recur-order-summary__label")?.textContent === "\u5C0F\u8A08") {
|
|
1504
|
-
subtotalRow.remove();
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
1502
|
const totalValue = totalRow?.querySelector(".recur-order-summary__total");
|
|
1508
1503
|
if (totalValue) {
|
|
1509
1504
|
totalValue.textContent = `NT$ ${finalAmount.toLocaleString()}`;
|
|
@@ -1531,7 +1526,7 @@ var init_payment_form = __esm({
|
|
|
1531
1526
|
this._couponError = null;
|
|
1532
1527
|
this.updateCouponSectionDOM();
|
|
1533
1528
|
try {
|
|
1534
|
-
const response = await fetch(`${apiBaseUrl}/
|
|
1529
|
+
const response = await fetch(`${apiBaseUrl}/v1/checkouts/${checkoutId}/coupon`, {
|
|
1535
1530
|
method: "POST",
|
|
1536
1531
|
headers: { "Content-Type": "application/json" },
|
|
1537
1532
|
body: JSON.stringify({ code })
|
|
@@ -1577,7 +1572,7 @@ var init_payment_form = __esm({
|
|
|
1577
1572
|
this._couponLoading = true;
|
|
1578
1573
|
this.updateCouponSectionDOM();
|
|
1579
1574
|
try {
|
|
1580
|
-
const response = await fetch(`${apiBaseUrl}/
|
|
1575
|
+
const response = await fetch(`${apiBaseUrl}/v1/checkouts/${checkoutId}/coupon`, {
|
|
1581
1576
|
method: "DELETE"
|
|
1582
1577
|
});
|
|
1583
1578
|
if (!response.ok) {
|
|
@@ -2559,7 +2554,7 @@ function toCamelCase(obj) {
|
|
|
2559
2554
|
|
|
2560
2555
|
// package.json
|
|
2561
2556
|
var package_default = {
|
|
2562
|
-
version: "0.9.
|
|
2557
|
+
version: "0.9.11"};
|
|
2563
2558
|
var SDK_VERSION = package_default.version;
|
|
2564
2559
|
var SDK_TYPE = "react";
|
|
2565
2560
|
var RecurContext = createContext(null);
|
|
@@ -2875,6 +2870,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
|
|
|
2875
2870
|
container.innerHTML = "";
|
|
2876
2871
|
const paymentForm = document.createElement("recur-payment-form");
|
|
2877
2872
|
paymentForm.setAttribute("container-id", containerElementId);
|
|
2873
|
+
if (checkoutResult.checkout?.id) {
|
|
2874
|
+
paymentForm.setAttribute("checkout-id", checkoutResult.checkout.id);
|
|
2875
|
+
}
|
|
2876
|
+
paymentForm.setAttribute("api-base-url", baseUrl);
|
|
2878
2877
|
if (options.customerName) {
|
|
2879
2878
|
paymentForm.setAttribute("customer-name", options.customerName);
|
|
2880
2879
|
}
|
package/dist/recur.umd.js
CHANGED
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
</button>
|
|
212
212
|
`:""}
|
|
213
213
|
</div>
|
|
214
|
-
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var He={};C(He,{RecurSkeletonLoader:()=>se});var se,
|
|
214
|
+
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var He={};C(He,{RecurSkeletonLoader:()=>se});var se,Be=k(()=>{"use strict";se=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
|
|
215
215
|
<div class="skeleton-field">
|
|
216
216
|
<div class="skeleton-label"></div>
|
|
217
217
|
<div class="skeleton-input"></div>
|
|
@@ -381,9 +381,9 @@
|
|
|
381
381
|
</style>
|
|
382
382
|
|
|
383
383
|
${e}
|
|
384
|
-
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function We(n,e){if(!_e(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return
|
|
384
|
+
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function We(n,e){if(!_e(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ne!==void 0?Ne.createHTML(e):e}function U(n,e,t=n,r){if(e===V)return e;let o=r!==void 0?t._$Co?.[r]:t._$Cl,i=q(e)?void 0:e._$litDirective$;return o?.constructor!==i&&(o?._$AO?.(!1),i===void 0?o=void 0:(o=new i(n),o._$AT(n,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=U(n,o._$AS(n,e.values),o,r)),e}var L,ne,Ne,qe,I,Ve,Et,M,F,q,_e,Ct,be,j,ze,Oe,D,Ke,je,Ye,Ee,m,Ft,qt,V,b,Fe,P,St,Y,ye,W,H,ve,ke,we,xe,Tt,X,Ce=k(()=>{"use strict";L=globalThis,ne=L.trustedTypes,Ne=ne?ne.createPolicy("lit-html",{createHTML:n=>n}):void 0,qe="$lit$",I=`lit$${Math.random().toFixed(9).slice(2)}$`,Ve="?"+I,Et=`<${Ve}>`,M=L.document===void 0?{createTreeWalker:()=>({})}:document,F=()=>M.createComment(""),q=n=>n===null||typeof n!="object"&&typeof n!="function",_e=Array.isArray,Ct=n=>_e(n)||typeof n?.[Symbol.iterator]=="function",be=`[
|
|
385
385
|
\f\r]`,j=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ze=/-->/g,Oe=/>/g,D=RegExp(`>|${be}(?:([^\\s"'>=/]+)(${be}*=${be}*(?:[^
|
|
386
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ke=/'/g,je=/"/g,Ye=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),m=Ee(1),Ft=Ee(2),qt=Ee(3),V=Symbol.for("lit-noChange"),
|
|
386
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ke=/'/g,je=/"/g,Ye=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),m=Ee(1),Ft=Ee(2),qt=Ee(3),V=Symbol.for("lit-noChange"),b=Symbol.for("lit-nothing"),Fe=new WeakMap,P=M.createTreeWalker(M,129);St=(n,e)=>{let t=n.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",s=j;for(let a=0;a<t;a++){let c=n[a],d,p,h=-1,x=0;for(;x<c.length&&(s.lastIndex=x,p=s.exec(c),p!==null);)x=s.lastIndex,s===j?p[1]==="!--"?s=ze:p[1]!==void 0?s=Oe:p[2]!==void 0?(Ye.test(p[2])&&(o=RegExp("</"+p[2],"g")),s=D):p[3]!==void 0&&(s=D):s===D?p[0]===">"?(s=o??j,h=-1):p[1]===void 0?h=-2:(h=s.lastIndex-p[2].length,d=p[1],s=p[3]===void 0?D:p[3]==='"'?je:Ke):s===je||s===Ke?s=D:s===ze||s===Oe?s=j:(s=D,o=void 0);let u=s===D&&n[a+1].startsWith("/>")?" ":"";i+=s===j?c+Et:h>=0?(r.push(d),c.slice(0,h)+qe+c.slice(h)+I+u):c+I+(h===-2?a:u)}return[We(n,i+(n[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},Y=class n{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,s=0,a=e.length-1,c=this.parts,[d,p]=St(e,t);if(this.el=n.createElement(d,r),P.currentNode=this.el.content,t===2||t===3){let h=this.el.content.firstChild;h.replaceWith(...h.childNodes)}for(;(o=P.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let h of o.getAttributeNames())if(h.endsWith(qe)){let x=p[s++],u=o.getAttribute(h).split(I),T=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:T[2],strings:u,ctor:T[1]==="."?ve:T[1]==="?"?ke:T[1]==="@"?we:H}),o.removeAttribute(h)}else h.startsWith(I)&&(c.push({type:6,index:i}),o.removeAttribute(h));if(Ye.test(o.tagName)){let h=o.textContent.split(I),x=h.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(h[u],F()),P.nextNode(),c.push({type:2,index:++i});o.append(h[x],F())}}}else if(o.nodeType===8)if(o.data===Ve)c.push({type:2,index:i});else{let h=-1;for(;(h=o.data.indexOf(I,h+1))!==-1;)c.push({type:7,index:i}),h+=I.length-1}i++}}static createElement(e,t){let r=M.createElement("template");return r.innerHTML=e,r}};ye=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,o=(e?.creationScope??M).importNode(t,!0);P.currentNode=o;let i=P.nextNode(),s=0,a=0,c=r[0];for(;c!==void 0;){if(s===c.index){let d;c.type===2?d=new W(i,i.nextSibling,this,e):c.type===1?d=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(d=new xe(i,this,e)),this._$AV.push(d),c=r[++a]}s!==c?.index&&(i=P.nextNode(),s++)}return P.currentNode=M,o}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},W=class n{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=b,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=U(this,e,t),q(e)?e===b||e==null||e===""?(this._$AH!==b&&this._$AR(),this._$AH=b):e!==this._$AH&&e!==V&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Ct(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==b&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(M.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,o=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=Y.createElement(We(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new ye(o,this),s=i.u(this.options);i.p(t),this.T(s),this._$AH=i}}_$AC(e){let t=Fe.get(e.strings);return t===void 0&&Fe.set(e.strings,t=new Y(e)),t}k(e){_e(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,o=0;for(let i of e)o===t.length?t.push(r=new n(this.O(F()),this.O(F()),this,this.options)):r=t[o],r._$AI(i),o++;o<t.length&&(this._$AR(r&&r._$AB.nextSibling,o),t.length=o)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=e.nextSibling;e.remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},H=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=b,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=b}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=U(this,e,t,0),s=!q(e)||e!==this._$AH&&e!==V,s&&(this._$AH=e);else{let a=e,c,d;for(e=i[0],c=0;c<i.length-1;c++)d=U(this,a[r+c],t,c),d===V&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===b?e=b:e!==b&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===b?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ve=class extends H{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===b?void 0:e}},ke=class extends H{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==b)}},we=class extends H{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=U(this,e,t,0)??b)===V)return;let r=this._$AH,o=e===b&&r!==b||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==b&&(r===b||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},xe=class{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){U(this,e)}},Tt=L.litHtmlPolyfillSupport;Tt?.(Y,W),(L.litHtmlVersions??(L.litHtmlVersions=[])).push("3.3.1");X=(n,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new W(e.insertBefore(F(),i),i,void 0,t??{})}return o._$AI(n),o}});var Je,Xe=k(()=>{Je=`/**
|
|
387
387
|
* Payment Form Skeleton - Shadow DOM Styles
|
|
388
388
|
* Loading skeleton that matches the structure of RecurPaymentForm
|
|
389
389
|
*/
|
|
@@ -929,6 +929,8 @@
|
|
|
929
929
|
line-height: 20px;
|
|
930
930
|
font-weight: 500;
|
|
931
931
|
color: #2d3748;
|
|
932
|
+
text-align: right;
|
|
933
|
+
font-variant-numeric: tabular-nums;
|
|
932
934
|
}
|
|
933
935
|
|
|
934
936
|
.recur-order-summary__total {
|
|
@@ -936,6 +938,8 @@
|
|
|
936
938
|
line-height: 26px;
|
|
937
939
|
font-weight: 700;
|
|
938
940
|
color: #1a202c;
|
|
941
|
+
text-align: right;
|
|
942
|
+
font-variant-numeric: tabular-nums;
|
|
939
943
|
}
|
|
940
944
|
|
|
941
945
|
/* ============================================
|
|
@@ -951,9 +955,10 @@
|
|
|
951
955
|
}
|
|
952
956
|
|
|
953
957
|
.recur-coupon__trigger {
|
|
954
|
-
display:
|
|
958
|
+
display: flex;
|
|
955
959
|
align-items: center;
|
|
956
960
|
gap: 6px;
|
|
961
|
+
width: 100%;
|
|
957
962
|
height: 36px;
|
|
958
963
|
background: none;
|
|
959
964
|
border: none;
|
|
@@ -976,8 +981,10 @@
|
|
|
976
981
|
|
|
977
982
|
.recur-coupon__input-row {
|
|
978
983
|
display: flex;
|
|
984
|
+
align-items: center;
|
|
979
985
|
gap: 8px;
|
|
980
986
|
width: 100%;
|
|
987
|
+
height: 36px;
|
|
981
988
|
}
|
|
982
989
|
|
|
983
990
|
.recur-coupon__input {
|
|
@@ -1010,12 +1017,21 @@
|
|
|
1010
1017
|
cursor: pointer;
|
|
1011
1018
|
transition: background-color 0.2s, opacity 0.2s;
|
|
1012
1019
|
white-space: nowrap;
|
|
1020
|
+
display: inline-flex;
|
|
1021
|
+
align-items: center;
|
|
1022
|
+
justify-content: center;
|
|
1013
1023
|
}
|
|
1014
1024
|
|
|
1015
1025
|
.recur-coupon__btn--apply {
|
|
1016
1026
|
background: #18181b;
|
|
1017
1027
|
color: white;
|
|
1018
1028
|
border: none;
|
|
1029
|
+
min-width: 52px;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.recur-coupon__btn--apply .recur-coupon__spinner {
|
|
1033
|
+
width: 14px;
|
|
1034
|
+
height: 14px;
|
|
1019
1035
|
}
|
|
1020
1036
|
|
|
1021
1037
|
.recur-coupon__btn--apply:hover:not(:disabled) {
|
|
@@ -1046,50 +1062,49 @@
|
|
|
1046
1062
|
|
|
1047
1063
|
.recur-coupon__applied {
|
|
1048
1064
|
display: flex;
|
|
1049
|
-
align-items:
|
|
1050
|
-
justify-content: space-between;
|
|
1065
|
+
align-items: center;
|
|
1051
1066
|
gap: 8px;
|
|
1052
1067
|
width: 100%;
|
|
1068
|
+
height: 36px;
|
|
1053
1069
|
}
|
|
1054
1070
|
|
|
1055
1071
|
.recur-coupon__applied-info {
|
|
1056
1072
|
display: flex;
|
|
1057
|
-
align-items:
|
|
1058
|
-
gap:
|
|
1073
|
+
align-items: center;
|
|
1074
|
+
gap: 6px;
|
|
1059
1075
|
min-width: 0;
|
|
1076
|
+
flex: 1;
|
|
1060
1077
|
}
|
|
1061
1078
|
|
|
1062
1079
|
.recur-coupon__applied-icon {
|
|
1063
1080
|
width: 16px;
|
|
1064
1081
|
height: 16px;
|
|
1065
|
-
color: #
|
|
1082
|
+
color: #dc2626;
|
|
1066
1083
|
flex-shrink: 0;
|
|
1067
|
-
margin-top: 2px;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
.recur-coupon__applied-details {
|
|
1071
|
-
min-width: 0;
|
|
1072
1084
|
}
|
|
1073
1085
|
|
|
1074
1086
|
.recur-coupon__applied-name {
|
|
1075
1087
|
font-size: 14px;
|
|
1076
1088
|
font-weight: 500;
|
|
1077
|
-
color: #
|
|
1078
|
-
overflow: hidden;
|
|
1079
|
-
text-overflow: ellipsis;
|
|
1089
|
+
color: #dc2626;
|
|
1080
1090
|
white-space: nowrap;
|
|
1081
1091
|
}
|
|
1082
1092
|
|
|
1083
1093
|
.recur-coupon__applied-code {
|
|
1084
|
-
font-size:
|
|
1085
|
-
color: #
|
|
1094
|
+
font-size: 14px;
|
|
1095
|
+
color: #9ca3af;
|
|
1096
|
+
white-space: nowrap;
|
|
1097
|
+
margin-right: 2px;
|
|
1086
1098
|
}
|
|
1087
1099
|
|
|
1088
1100
|
.recur-coupon__applied-amount {
|
|
1089
1101
|
font-size: 14px;
|
|
1090
1102
|
font-weight: 500;
|
|
1091
|
-
color: #
|
|
1103
|
+
color: #dc2626;
|
|
1092
1104
|
white-space: nowrap;
|
|
1105
|
+
font-variant-numeric: tabular-nums;
|
|
1106
|
+
flex-shrink: 0;
|
|
1107
|
+
margin-left: auto;
|
|
1093
1108
|
}
|
|
1094
1109
|
|
|
1095
1110
|
.recur-coupon__remove {
|
|
@@ -1103,6 +1118,7 @@
|
|
|
1103
1118
|
display: flex;
|
|
1104
1119
|
align-items: center;
|
|
1105
1120
|
justify-content: center;
|
|
1121
|
+
flex-shrink: 0;
|
|
1106
1122
|
}
|
|
1107
1123
|
|
|
1108
1124
|
.recur-coupon__remove:hover {
|
|
@@ -1308,7 +1324,18 @@
|
|
|
1308
1324
|
@keyframes recur-spin {
|
|
1309
1325
|
to { transform: rotate(360deg); }
|
|
1310
1326
|
}
|
|
1311
|
-
|
|
1327
|
+
|
|
1328
|
+
/* ============================================
|
|
1329
|
+
* Skeleton Loading Styles
|
|
1330
|
+
* ============================================ */
|
|
1331
|
+
.recur-skeleton {
|
|
1332
|
+
display: inline-block;
|
|
1333
|
+
background: linear-gradient(90deg, #f0f0f0 0%, #e8e8e8 50%, #f0f0f0 100%);
|
|
1334
|
+
background-size: 200% 100%;
|
|
1335
|
+
animation: recur-skeleton-loading 1.5s ease-in-out infinite;
|
|
1336
|
+
border-radius: 4px;
|
|
1337
|
+
}
|
|
1338
|
+
`});var st={};C(st,{RecurPaymentForm:()=>le});var B,le,nt=k(()=>{"use strict";Ce();tt();ot();B={lock:m`
|
|
1312
1339
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1313
1340
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
|
1314
1341
|
</svg>
|
|
@@ -1350,7 +1377,7 @@
|
|
|
1350
1377
|
<slot name="actions"></slot>
|
|
1351
1378
|
|
|
1352
1379
|
<div class="security-note">
|
|
1353
|
-
${
|
|
1380
|
+
${B.lock}
|
|
1354
1381
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
1355
1382
|
</div>
|
|
1356
1383
|
</div>
|
|
@@ -1383,35 +1410,56 @@
|
|
|
1383
1410
|
height: 36px !important;
|
|
1384
1411
|
}
|
|
1385
1412
|
${this.customStyles}
|
|
1386
|
-
`}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r)
|
|
1413
|
+
`}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r){let h=!!o;return m`
|
|
1414
|
+
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1415
|
+
<div class="recur-order-summary__row">
|
|
1416
|
+
<span class="recur-order-summary__label">${h?"\u8A02\u95B1\u65B9\u6848":"\u5546\u54C1"}</span>
|
|
1417
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 100px; height: 20px;"></span>
|
|
1418
|
+
</div>
|
|
1419
|
+
${h?m`
|
|
1420
|
+
<div class="recur-order-summary__row">
|
|
1421
|
+
<span class="recur-order-summary__label">計費週期</span>
|
|
1422
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
|
|
1423
|
+
</div>
|
|
1424
|
+
`:b}
|
|
1425
|
+
<div class="recur-order-summary__row">
|
|
1426
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1427
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1428
|
+
</div>
|
|
1429
|
+
<div class="recur-coupon">
|
|
1430
|
+
<span class="recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
1431
|
+
</div>
|
|
1432
|
+
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1433
|
+
<span class="recur-order-summary__label">總計</span>
|
|
1434
|
+
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1435
|
+
</div>
|
|
1436
|
+
</div>
|
|
1437
|
+
`}let s=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,d=a-c,p=!!s;return m`
|
|
1387
1438
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1388
1439
|
<div class="recur-order-summary__row">
|
|
1389
|
-
<span class="recur-order-summary__label"
|
|
1440
|
+
<span class="recur-order-summary__label">${p?"\u8A02\u95B1\u65B9\u6848":"\u5546\u54C1"}</span>
|
|
1390
1441
|
<span class="recur-order-summary__value">${t}</span>
|
|
1391
1442
|
</div>
|
|
1392
1443
|
|
|
1393
|
-
${
|
|
1444
|
+
${p?m`
|
|
1394
1445
|
<div class="recur-order-summary__row">
|
|
1395
1446
|
<span class="recur-order-summary__label">計費週期</span>
|
|
1396
1447
|
<span class="recur-order-summary__value">每${s}</span>
|
|
1397
1448
|
</div>
|
|
1398
|
-
`:
|
|
1449
|
+
`:b}
|
|
1399
1450
|
|
|
1451
|
+
<!-- 小計 (Subtotal) - always show -->
|
|
1452
|
+
<div class="recur-order-summary__row">
|
|
1453
|
+
<span class="recur-order-summary__label">小計</span>
|
|
1454
|
+
<span class="recur-order-summary__value">NT$ ${a.toLocaleString()}</span>
|
|
1455
|
+
</div>
|
|
1456
|
+
|
|
1457
|
+
<!-- 優惠碼區塊 (Coupon section with discount amount) -->
|
|
1400
1458
|
<div class="recur-coupon" id="${this.containerId}-coupon">
|
|
1401
1459
|
${this.renderCoupon()}
|
|
1402
1460
|
</div>
|
|
1403
1461
|
|
|
1404
|
-
|
|
1405
|
-
<div class="recur-order-summary__row">
|
|
1406
|
-
<span class="recur-order-summary__label">小計</span>
|
|
1407
|
-
<span class="recur-order-summary__value">NT$ ${a.toLocaleString()}</span>
|
|
1408
|
-
</div>
|
|
1409
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1410
|
-
<span class="recur-order-summary__label">折扣</span>
|
|
1411
|
-
<span class="recur-order-summary__value">-NT$ ${c.toLocaleString()}</span>
|
|
1412
|
-
</div>
|
|
1413
|
-
`:f}
|
|
1414
|
-
|
|
1462
|
+
<!-- 總計 (Total) -->
|
|
1415
1463
|
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1416
1464
|
<span class="recur-order-summary__label">總計</span>
|
|
1417
1465
|
<span class="recur-order-summary__total">NT$ ${d.toLocaleString()}</span>
|
|
@@ -1420,27 +1468,25 @@
|
|
|
1420
1468
|
`}renderCoupon(){return this._appliedCoupon?m`
|
|
1421
1469
|
<div class="recur-coupon__applied">
|
|
1422
1470
|
<div class="recur-coupon__applied-info">
|
|
1423
|
-
${
|
|
1424
|
-
|
|
1425
|
-
<
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1471
|
+
${B.tagApplied}
|
|
1472
|
+
${this._appliedCoupon.couponName?m`
|
|
1473
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
|
|
1474
|
+
<span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
|
|
1475
|
+
`:m`
|
|
1476
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
|
|
1477
|
+
`}
|
|
1478
|
+
<button
|
|
1479
|
+
type="button"
|
|
1480
|
+
class="recur-coupon__remove"
|
|
1481
|
+
?disabled=${this._couponLoading}
|
|
1482
|
+
@click=${()=>this.removeCoupon()}
|
|
1483
|
+
>
|
|
1484
|
+
${this._couponLoading?B.spinner:B.close}
|
|
1485
|
+
</button>
|
|
1432
1486
|
</div>
|
|
1433
1487
|
<span class="recur-coupon__applied-amount">
|
|
1434
1488
|
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1435
1489
|
</span>
|
|
1436
|
-
<button
|
|
1437
|
-
type="button"
|
|
1438
|
-
class="recur-coupon__remove"
|
|
1439
|
-
?disabled=${this._couponLoading}
|
|
1440
|
-
@click=${()=>this.removeCoupon()}
|
|
1441
|
-
>
|
|
1442
|
-
${this._couponLoading?N.spinner:N.close}
|
|
1443
|
-
</button>
|
|
1444
1490
|
</div>
|
|
1445
1491
|
`:this._showCouponInput?m`
|
|
1446
1492
|
<div style="width: 100%;">
|
|
@@ -1461,7 +1507,7 @@
|
|
|
1461
1507
|
?disabled=${this._couponLoading||!this._couponCode.trim()}
|
|
1462
1508
|
@click=${()=>this.applyCoupon()}
|
|
1463
1509
|
>
|
|
1464
|
-
${this._couponLoading?
|
|
1510
|
+
${this._couponLoading?B.spinner:"\u5957\u7528"}
|
|
1465
1511
|
</button>
|
|
1466
1512
|
<button
|
|
1467
1513
|
type="button"
|
|
@@ -1474,7 +1520,7 @@
|
|
|
1474
1520
|
</div>
|
|
1475
1521
|
${this._couponError?m`
|
|
1476
1522
|
<div class="recur-coupon__error">${this._couponError}</div>
|
|
1477
|
-
`:
|
|
1523
|
+
`:b}
|
|
1478
1524
|
</div>
|
|
1479
1525
|
`:m`
|
|
1480
1526
|
<button
|
|
@@ -1482,10 +1528,10 @@
|
|
|
1482
1528
|
class="recur-coupon__trigger"
|
|
1483
1529
|
@click=${()=>this.showCouponInput()}
|
|
1484
1530
|
>
|
|
1485
|
-
${
|
|
1531
|
+
${B.tag}
|
|
1486
1532
|
有優惠碼?
|
|
1487
1533
|
</button>
|
|
1488
|
-
`}showCouponInput(){this._showCouponInput=!0,this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}cancelCouponInput(){this._showCouponInput=!1,this._couponCode="",this._couponError=null,this.updateCouponSectionDOM()}handleCouponInputChange(t){this._couponCode=t.target.value.toUpperCase(),this._couponError=null,this.updateApplyButtonState()}handleCouponKeydown(t){t.key==="Enter"?(t.preventDefault(),this.applyCoupon()):t.key==="Escape"&&this.cancelCouponInput()}updateApplyButtonState(){let t=this.querySelector(".recur-coupon__btn--apply");t&&(t.disabled=this._couponLoading||!this._couponCode.trim())}updateCouponSectionDOM(){let t
|
|
1534
|
+
`}showCouponInput(){this._showCouponInput=!0,this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}cancelCouponInput(){this._showCouponInput=!1,this._couponCode="",this._couponError=null,this.updateCouponSectionDOM()}handleCouponInputChange(t){this._couponCode=t.target.value.toUpperCase(),this._couponError=null,this.updateApplyButtonState()}handleCouponKeydown(t){t.key==="Enter"?(t.preventDefault(),this.applyCoupon()):t.key==="Escape"&&this.cancelCouponInput()}updateApplyButtonState(){let t=this.querySelector(".recur-coupon__btn--apply");t&&(t.disabled=this._couponLoading||!this._couponCode.trim())}updateCouponSectionDOM(){let t=`${this.containerId}-coupon`,r=document.getElementById(t);r&&(this._appliedCoupon?(r.innerHTML=this.getCouponAppliedHTML(),this.bindCouponAppliedEvents(r)):this._showCouponInput?(r.innerHTML=this.getCouponInputHTML(),this.bindCouponInputEvents(r)):(r.innerHTML=this.getCouponTriggerHTML(),this.bindCouponTriggerEvents(r)))}getCouponTriggerHTML(){return`
|
|
1489
1535
|
<button type="button" class="recur-coupon__trigger">
|
|
1490
1536
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1491
1537
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
@@ -1520,40 +1566,27 @@
|
|
|
1520
1566
|
</div>
|
|
1521
1567
|
${t}
|
|
1522
1568
|
</div>
|
|
1523
|
-
`}getCouponAppliedHTML(){let t=this._appliedCoupon
|
|
1569
|
+
`}getCouponAppliedHTML(){let t=this._appliedCoupon;return`
|
|
1524
1570
|
<div class="recur-coupon__applied">
|
|
1525
1571
|
<div class="recur-coupon__applied-info">
|
|
1526
1572
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1527
1573
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
1528
1574
|
</svg>
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
${
|
|
1532
|
-
</
|
|
1575
|
+
${t.couponName?`<span class="recur-coupon__applied-name">${t.couponName}</span><span class="recur-coupon__applied-code">(${t.code})</span>`:`<span class="recur-coupon__applied-name">${t.code}</span>`}
|
|
1576
|
+
<button type="button" class="recur-coupon__remove" ${this._couponLoading?"disabled":""}>
|
|
1577
|
+
${this._couponLoading?'<span class="recur-coupon__spinner"></span>':'<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1578
|
+
</button>
|
|
1533
1579
|
</div>
|
|
1534
1580
|
<span class="recur-coupon__applied-amount">-NT$ ${t.discountAmount.toLocaleString()}</span>
|
|
1535
|
-
<button type="button" class="recur-coupon__remove" ${this._couponLoading?"disabled":""}>
|
|
1536
|
-
${this._couponLoading?'<span class="recur-coupon__spinner"></span>':'<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>'}
|
|
1537
|
-
</button>
|
|
1538
1581
|
</div>
|
|
1539
|
-
`}bindCouponTriggerEvents(t){t.querySelector(".recur-coupon__trigger")?.addEventListener("click",()=>this.showCouponInput())}bindCouponInputEvents(t){let r=t.querySelector(".recur-coupon__input"),o=t.querySelector(".recur-coupon__btn--apply"),i=t.querySelector(".recur-coupon__btn--cancel");r?.addEventListener("input",s=>this.handleCouponInputChange(s)),r?.addEventListener("keydown",s=>this.handleCouponKeydown(s)),o?.addEventListener("click",()=>this.applyCoupon()),i?.addEventListener("click",()=>this.cancelCouponInput())}bindCouponAppliedEvents(t){t.querySelector(".recur-coupon__remove")?.addEventListener("click",()=>this.removeCoupon())}updateOrderSummaryDOM(){let t=document.getElementById(`${this.containerId}-order-summary`);if(!t)return;let r=Number(this.getAttribute("amount")||0),o=this._appliedCoupon?.discountAmount||0,i=r-o,
|
|
1540
|
-
<div class="recur-order-summary__row">
|
|
1541
|
-
<span class="recur-order-summary__label">\u5C0F\u8A08</span>
|
|
1542
|
-
<span class="recur-order-summary__value">NT$ ${r.toLocaleString()}</span>
|
|
1543
|
-
</div>
|
|
1544
|
-
`,p=`
|
|
1545
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1546
|
-
<span class="recur-order-summary__label">\u6298\u6263</span>
|
|
1547
|
-
<span class="recur-order-summary__value">-NT$ ${o.toLocaleString()}</span>
|
|
1548
|
-
</div>
|
|
1549
|
-
`;a.insertAdjacentHTML("beforebegin",d+p)}}else{let d=t.querySelector(".recur-order-summary__row:not(.recur-order-summary__row--total):last-of-type");s?.remove(),d?.querySelector(".recur-order-summary__label")?.textContent==="\u5C0F\u8A08"&&d.remove()}let c=a?.querySelector(".recur-order-summary__total");c&&(c.textContent=`NT$ ${i.toLocaleString()}`),this.updateCouponSectionDOM()}async applyCoupon(){let t=this._couponCode.trim();if(!t){this._couponError="\u8ACB\u8F38\u5165\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}let r=this.getAttribute("checkout-id"),o=this.getAttribute("api-base-url")||"";if(!r){this._couponError="\u7121\u6CD5\u5957\u7528\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}this._couponLoading=!0,this._couponError=null,this.updateCouponSectionDOM();try{let i=await fetch(`${o}/api/checkout/${r}/coupon`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:t})}),s=await i.json();if(!i.ok){this._couponError=s.error?.message||"\u512A\u60E0\u78BC\u7121\u6548",this._couponLoading=!1,this.updateCouponSectionDOM();return}this._appliedCoupon={code:s.discount.code,couponName:s.discount.couponName,discountType:s.discount.discountType,discountAmount:s.discount.discountAmount,duration:s.discount.duration,durationMonths:s.discount.durationMonths,bonusTrialDays:s.discount.bonusTrialDays,bonusMonths:s.discount.bonusMonths},this._showCouponInput=!1,this._couponCode="",this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-applied",{detail:{coupon:this._appliedCoupon},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}async removeCoupon(){let t=this.getAttribute("checkout-id"),r=this.getAttribute("api-base-url")||"";if(t){this._couponLoading=!0,this.updateCouponSectionDOM();try{let o=await fetch(`${r}/api/checkout/${t}/coupon`,{method:"DELETE"});if(!o.ok){let s=await o.json();this._couponError=s.error?.message||"\u79FB\u9664\u5931\u6557",this._couponLoading=!1,this.updateCouponSectionDOM();return}let i=this._appliedCoupon;this._appliedCoupon=null,this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-removed",{detail:{coupon:i},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}}getAppliedCoupon(){return this._appliedCoupon}renderCustomerInfo(){let t=this.getAttribute("customer-name"),r=this.getAttribute("customer-email");return r?m`
|
|
1582
|
+
`}bindCouponTriggerEvents(t){t.querySelector(".recur-coupon__trigger")?.addEventListener("click",()=>this.showCouponInput())}bindCouponInputEvents(t){let r=t.querySelector(".recur-coupon__input"),o=t.querySelector(".recur-coupon__btn--apply"),i=t.querySelector(".recur-coupon__btn--cancel");r?.addEventListener("input",s=>this.handleCouponInputChange(s)),r?.addEventListener("keydown",s=>this.handleCouponKeydown(s)),o?.addEventListener("click",()=>this.applyCoupon()),i?.addEventListener("click",()=>this.cancelCouponInput())}bindCouponAppliedEvents(t){t.querySelector(".recur-coupon__remove")?.addEventListener("click",()=>this.removeCoupon())}updateOrderSummaryDOM(){let t=document.getElementById(`${this.containerId}-order-summary`);if(!t)return;let r=Number(this.getAttribute("amount")||0),o=this._appliedCoupon?.discountAmount||0,i=r-o,a=t.querySelector(".recur-order-summary__row--total")?.querySelector(".recur-order-summary__total");a&&(a.textContent=`NT$ ${i.toLocaleString()}`),this.updateCouponSectionDOM()}async applyCoupon(){let t=this._couponCode.trim();if(!t){this._couponError="\u8ACB\u8F38\u5165\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}let r=this.getAttribute("checkout-id"),o=this.getAttribute("api-base-url")||"";if(!r){this._couponError="\u7121\u6CD5\u5957\u7528\u512A\u60E0\u78BC",this.updateCouponSectionDOM();return}this._couponLoading=!0,this._couponError=null,this.updateCouponSectionDOM();try{let i=await fetch(`${o}/v1/checkouts/${r}/coupon`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:t})}),s=await i.json();if(!i.ok){this._couponError=s.error?.message||"\u512A\u60E0\u78BC\u7121\u6548",this._couponLoading=!1,this.updateCouponSectionDOM();return}this._appliedCoupon={code:s.discount.code,couponName:s.discount.couponName,discountType:s.discount.discountType,discountAmount:s.discount.discountAmount,duration:s.discount.duration,durationMonths:s.discount.durationMonths,bonusTrialDays:s.discount.bonusTrialDays,bonusMonths:s.discount.bonusMonths},this._showCouponInput=!1,this._couponCode="",this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-applied",{detail:{coupon:this._appliedCoupon},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}async removeCoupon(){let t=this.getAttribute("checkout-id"),r=this.getAttribute("api-base-url")||"";if(t){this._couponLoading=!0,this.updateCouponSectionDOM();try{let o=await fetch(`${r}/v1/checkouts/${t}/coupon`,{method:"DELETE"});if(!o.ok){let s=await o.json();this._couponError=s.error?.message||"\u79FB\u9664\u5931\u6557",this._couponLoading=!1,this.updateCouponSectionDOM();return}let i=this._appliedCoupon;this._appliedCoupon=null,this._couponLoading=!1,this.updateOrderSummaryDOM(),this.dispatchEvent(new CustomEvent("coupon-removed",{detail:{coupon:i},bubbles:!0,composed:!0}))}catch{this._couponError="\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66",this._couponLoading=!1,this.updateCouponSectionDOM()}}}getAppliedCoupon(){return this._appliedCoupon}renderCustomerInfo(){let t=this.getAttribute("customer-name"),r=this.getAttribute("customer-email");return r?m`
|
|
1550
1583
|
<div class="recur-info-display">
|
|
1551
1584
|
${t?m`
|
|
1552
1585
|
<div class="recur-info-row">
|
|
1553
1586
|
<span class="recur-info-label">姓名</span>
|
|
1554
1587
|
<span class="recur-info-value">${t}</span>
|
|
1555
1588
|
</div>
|
|
1556
|
-
`:
|
|
1589
|
+
`:b}
|
|
1557
1590
|
<div class="recur-info-row">
|
|
1558
1591
|
<span class="recur-info-label">電子郵件</span>
|
|
1559
1592
|
<span class="recur-info-value">${r}</span>
|
|
@@ -1849,7 +1882,7 @@
|
|
|
1849
1882
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1850
1883
|
<circle cx="12" cy="7" r="4"/>
|
|
1851
1884
|
</svg>
|
|
1852
|
-
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var zt={};C(zt,{RecurCheckout:()=>G,RecurElements:()=>
|
|
1885
|
+
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var zt={};C(zt,{RecurCheckout:()=>G,RecurElements:()=>N,createElements:()=>Se,default:()=>Nt,init:()=>ht});async function Dt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(De(),Re)),Promise.resolve().then(()=>(Me(),Pe)),Promise.resolve().then(()=>(Ue(),Le)),Promise.resolve().then(()=>(Be(),He)),Promise.resolve().then(()=>(Ge(),Ze)),Promise.resolve().then(()=>(et(),Qe)),Promise.resolve().then(()=>(nt(),st)),Promise.resolve().then(()=>(ct(),at)),Promise.resolve().then(()=>(dt(),lt))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&Dt();function Pt(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function w(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>w(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let o=Pt(t);e[o]=w(r)}return e}return n}var ut={name:"recur-tw",version:"0.9.11",description:"React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",type:"module",private:!1,author:"Recur",license:"Elastic-2.0",keywords:["react","vanilla-js","subscription","checkout","payment","payuni","recurring-billing","taiwan","\u7E41\u9AD4\u4E2D\u6587","sdk","embedded-checkout"],homepage:"https://recur.tw/",bugs:{email:"support@recur.tw"},scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint .","lint:fix":"eslint . --fix","type-check":"tsc --noEmit",examples:"npx http-server examples -p 8080 -o"},main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js",require:"./dist/server.cjs"},"./vanilla":"./dist/recur.umd.js","./package.json":"./package.json"},unpkg:"./dist/recur.umd.js",jsdelivr:"./dist/recur.umd.js",files:["dist","README.md","AGENTS.md","LICENSE"],sideEffects:["src/components/**/*.ts","src/components/**/*.js"],peerDependencies:{react:">=18.0.0","react-dom":">=18.0.0"},peerDependenciesMeta:{react:{optional:!0},"react-dom":{optional:!0}},devDependencies:{"@eslint/js":"^9.39.1","@types/node":"^20.19.9","@types/react":"^19.1.9","@types/react-dom":"^19.1.7","@workspace/typescript-config":"workspace:*",autoprefixer:"^10.4.22",eslint:"^9","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.0.1",postcss:"^8.5.6",react:"^19.2.1","react-dom":"^19.2.1",tailwindcss:"^4.1.11",tsup:"^8.3.5",typescript:"^5.9.2","typescript-eslint":"^8.47.0"},dependencies:{"lit-html":"^3.3.1"}};var Lt=ut.version,Ut="vanilla",pe=class{constructor(e){l(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}getHeaders(){return{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey,"X-Recur-SDK-Type":Ut,"X-Recur-SDK-Version":Lt,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,o=e.productId||e.planId,i=e.productSlug;if(!o&&!i)throw new Error("Either productId or productSlug is required");let s={customerName:t,customerEmail:r};o&&(s.productId=o),i&&(s.productSlug=i);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let c=await a.json();return w(c)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:this.getHeaders()});if(!r.ok){let i=await r.json().catch(()=>({}));throw{code:i.error||"FETCH_PRODUCTS_FAILED",message:i.message||"Failed to fetch products",details:i}}let o=await r.json();return w(o)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var me=class{constructor(e,t){l(this,"config");l(this,"options");l(this,"container");l(this,"checkoutId",null);l(this,"sdkToken",null);l(this,"sdkTimestamp",null);l(this,"creditToken",null);l(this,"sdkEnv","S");l(this,"payuniSDK",null);l(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.productId||this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||"Failed to initialize checkout")}let r=await t.json(),o=w(r);this.checkoutId=o.checkout.id,this.sdkToken=o.sdkToken,this.sdkTimestamp=o.sdkTimestamp||null,this.creditToken=o.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
|
|
1853
1886
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1854
1887
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1855
1888
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -1919,21 +1952,21 @@
|
|
|
1919
1952
|
</p>
|
|
1920
1953
|
</form>
|
|
1921
1954
|
</div>
|
|
1922
|
-
`}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let r=document.createElement("script");r.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",r.async=!0,r.onload=()=>e(),r.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(r)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");let e=window.UniPayment;if(!e)throw new Error("PAYUNi SDK not loaded");let t={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=e.createSession(this.sdkToken,t),await this.payuniSDK.start(),this.payuniSDK.onUpdate(r=>{let o=r?.status;o&&(this.isFormValid=o.CardNo===!0&&o.CardExp===!0&&o.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.checkoutId)throw new Error("Checkout session not initialized");if(!this.payuniSDK)throw new Error("Payment system not initialized");let r=await this.payuniSDK.getTradeResult();if(r.Status!=="SUCCESS")throw new Error(r.Message||"Card validation failed");let o=r.EncryptInfo||r.creditToken;if(!o)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let i=this.getBaseUrl(),s=await fetch(`${i}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:o,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!s.ok){let p=await s.json().catch(()=>({}));throw new Error(p.error||"Failed to process payment")}let a=await s.json(),c=this.options.productId||this.options.planId||"",d={subscription:{id:a.subscription?.id||a.charge?.id||"",status:a.success?"active":"failed",productId:c,productName:"",amount:a.charge?.amount||0,billingPeriod:a.subscription?.billingPeriod||"MONTHLY",trialDays:null},subscriber:{id:"",email:document.getElementById("recur-email")?.value||"",name:document.getElementById("recur-name")?.value||""},nextSteps:{getSdkToken:"",completeSubscription:""}};this.options.onSuccess&&this.options.onSuccess(d),this.showSuccess()}catch(e){this.handleError(e)}finally{this.showLoading(!1)}}showLoading(e){let t=document.getElementById("recur-submit-btn");t&&(t.disabled=e,t.textContent=e?"Processing...":"Subscribe Now")}showError(e){let t=document.getElementById("recur-error");t&&(t.textContent=e,t.style.display="block")}hideError(){let e=document.getElementById("recur-error");e&&(e.style.display="none")}showSuccess(){this.container.innerHTML="";let e=document.createElement("recur-success-message");e.setAttribute("title","Subscription Complete!"),e.setAttribute("message","Thank you for subscribing. You will receive a confirmation email shortly."),this.container.appendChild(e)}handleError(e){let t=e?.message||"An error occurred";this.showError(t);let r={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(r)}};var
|
|
1955
|
+
`}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let r=document.createElement("script");r.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",r.async=!0,r.onload=()=>e(),r.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(r)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");let e=window.UniPayment;if(!e)throw new Error("PAYUNi SDK not loaded");let t={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=e.createSession(this.sdkToken,t),await this.payuniSDK.start(),this.payuniSDK.onUpdate(r=>{let o=r?.status;o&&(this.isFormValid=o.CardNo===!0&&o.CardExp===!0&&o.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.checkoutId)throw new Error("Checkout session not initialized");if(!this.payuniSDK)throw new Error("Payment system not initialized");let r=await this.payuniSDK.getTradeResult();if(r.Status!=="SUCCESS")throw new Error(r.Message||"Card validation failed");let o=r.EncryptInfo||r.creditToken;if(!o)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let i=this.getBaseUrl(),s=await fetch(`${i}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:o,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!s.ok){let p=await s.json().catch(()=>({}));throw new Error(p.error||"Failed to process payment")}let a=await s.json(),c=this.options.productId||this.options.planId||"",d={subscription:{id:a.subscription?.id||a.charge?.id||"",status:a.success?"active":"failed",productId:c,productName:"",amount:a.charge?.amount||0,billingPeriod:a.subscription?.billingPeriod||"MONTHLY",trialDays:null},subscriber:{id:"",email:document.getElementById("recur-email")?.value||"",name:document.getElementById("recur-name")?.value||""},nextSteps:{getSdkToken:"",completeSubscription:""}};this.options.onSuccess&&this.options.onSuccess(d),this.showSuccess()}catch(e){this.handleError(e)}finally{this.showLoading(!1)}}showLoading(e){let t=document.getElementById("recur-submit-btn");t&&(t.disabled=e,t.textContent=e?"Processing...":"Subscribe Now")}showError(e){let t=document.getElementById("recur-error");t&&(t.textContent=e,t.style.display="block")}hideError(){let e=document.getElementById("recur-error");e&&(e.style.display="none")}showSuccess(){this.container.innerHTML="";let e=document.createElement("recur-success-message");e.setAttribute("title","Subscription Complete!"),e.setAttribute("message","Thank you for subscribing. You will receive a confirmation email shortly."),this.container.appendChild(e)}handleError(e){let t=e?.message||"An error occurred";this.showError(t);let r={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(r)}};var N=class{constructor(e){l(this,"publishableKey");l(this,"baseUrl");l(this,"embedUrl");l(this,"iframe",null);l(this,"container",null);l(this,"sessionId",null);l(this,"timestamp",null);l(this,"creditToken",null);l(this,"sdkToken",null);l(this,"cardToken",null);l(this,"cardTimestamp",null);l(this,"eventHandlers",new Map);typeof e=="string"?(this.publishableKey=e,this.baseUrl=this.getDefaultBaseUrl(),this.embedUrl=this.getDefaultEmbedUrl()):(this.publishableKey=e.publishableKey,this.baseUrl=e.baseUrl||this.getDefaultBaseUrl(),this.embedUrl=e.embedUrl||this.getDefaultEmbedUrl()),window.addEventListener("message",this.handleMessage.bind(this))}async mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t)throw new Error(`Container not found: ${e}`);return this.container=t,this.iframe=document.createElement("iframe"),this.iframe.src=`${this.embedUrl}/elements?key=${encodeURIComponent(this.publishableKey)}`,this.iframe.style.cssText=`
|
|
1923
1956
|
width: 100%;
|
|
1924
1957
|
border: none;
|
|
1925
1958
|
min-height: 200px;
|
|
1926
1959
|
display: block;
|
|
1927
1960
|
user-select: none;
|
|
1928
1961
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1929
|
-
`.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Se(n){return new
|
|
1962
|
+
`.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Se(n){return new N(n)}var Ht="https://vendor.payuni.com.tw/sdk/uni-payment.js",Bt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,he=!1,Z=null;async function mt(n=!1){return pt&&window.UniPayment?Promise.resolve():(he&&Z||(he=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Bt:Ht,r.async=!0,r.onload=()=>{pt=!0,he=!1,e()},r.onerror=()=>{he=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var G=class{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"currentDialogElement",null);this.core=new pe(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new me(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");if(!e.successUrl)throw new Error("successUrl is required for hosted checkout");if(!e.cancelUrl)throw new Error("cancelUrl is required for hosted checkout");let r={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId);let o=this.core.getConfig(),i=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":o.publishableKey},body:JSON.stringify(r)});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error?.message||c.error||"Failed to create checkout session")}let s=await i.json(),a=w(s);return{id:a.id,url:a.url,expiresAt:a.expiresAt,clientSecret:a.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),o=this.core.getConfig(),i=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":o.publishableKey}});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error||"Failed to get checkout status")}let s=await i.json(),a=w(s);return{id:a.checkout.id,status:a.checkout.status,amount:a.checkout.amount,currency:a.checkout.currency,lastCharge:a.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,o=e.productId||e.planId,i=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:o,productSlug:i,mode:e.mode}),!o&&!i)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let s=this.getBaseUrl();console.log("[Recur SDK] Base URL:",s);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},c=e.mode||"modal";if(c==="redirect"){if(!e.successUrl)throw new Error("successUrl is required for redirect mode");if(!e.cancelUrl)throw new Error("cancelUrl is required for redirect mode");console.log("[Recur SDK] Creating hosted checkout session...");let y={successUrl:e.successUrl,cancelUrl:e.cancelUrl};o&&(y.productId=o),i&&(y.productSlug=i),e.customerEmail&&(y.customerEmail=e.customerEmail),e.customerName&&(y.customerName=e.customerName),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let A=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!A.ok){let R=await A.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",R),new Error(R.error?.message||R.error||"Failed to create checkout session")}let ge=await A.json(),E=w(ge);console.log("[Recur SDK] Checkout session created:",E),console.log("[Recur SDK] Redirecting to hosted checkout:",E.url),window.location.href=E.url;return}let d=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,d=y.container}else if(c==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");d.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let p={customerName:e.customerName,customerEmail:e.customerEmail};o&&(p.productId=o),i&&(p.productSlug=i),e.externalCustomerId&&(p.externalCustomerId=e.externalCustomerId),e.successUrl&&(p.successUrl=e.successUrl),e.cancelUrl&&(p.cancelUrl=e.cancelUrl);let h=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(p)});if(!h.ok){let y=await h.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let A=y.details||y.error||"Failed to create checkout";throw new Error(A)}let x=await h.json(),u=w(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await mt(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let f=document.createElement("recur-payment-form");if(f.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&f.setAttribute("checkout-id",u.checkout.id),f.setAttribute("api-base-url",s),e.customerName&&f.setAttribute("customer-name",e.customerName),e.customerEmail&&f.setAttribute("customer-email",e.customerEmail),u.product?.name&&f.setAttribute("product-name",u.product.name),u.checkout?.amount&&f.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&f.setAttribute("interval",u.product.interval),f.setAttribute("custom-styles",`
|
|
1930
1963
|
.form-input-focus {
|
|
1931
1964
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1932
1965
|
outline: 0 !important;
|
|
1933
1966
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
1934
1967
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
1935
1968
|
}
|
|
1936
|
-
`),d.appendChild(
|
|
1969
|
+
`),d.appendChild(f),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await f.initializePayment(u.sdkToken,T?"SANDBOX":"PRODUCTION")===null){console.log("[Recur SDK] Initialization aborted");return}console.log("[Recur SDK] PAYUNi SDK initialized successfully"),console.log("[Recur SDK] Step 6: Setting up submit handler..."),f.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let A=y,{paymentSession:ge}=A.detail;try{let E=await ge.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let R=E.HashTimestamp||E.timestamp,Te={};if(u.checkout.productType==="SUBSCRIPTION"){let $=u.creditToken,_=u.sdkTimestamp;if(!$)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Te={creditToken:$,timestamp:_||R},console.log("[Recur SDK] Using creditToken from checkout:",$.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",_?"from checkout (sdkTimestamp)":"from tradeResult")}let fe=await fetch(`${s}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify(Te)});if(!fe.ok){let $=await fe.json().catch(()=>({}));throw new Error($.error||"Failed to execute payment")}let gt=await fe.json(),g=w(gt);if(console.log("[Recur SDK] Payment executed:",g),g.requires3D&&g.redirectUrl){if(console.log("[Recur SDK] 3D verification required"),/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/wv|WebView|FBAN|FBAV|Instagram|Line|MicroMessenger|QQ/i.test(navigator.userAgent)||/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)||"standalone"in navigator&&navigator.standalone){console.log("[Recur SDK] Mobile/WebView detected, using redirect for 3D verification"),window.location.href=g.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let _=window.open(g.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!_){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=g.redirectUrl;return}if(await new Promise(O=>setTimeout(O,100)),_.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=g.redirectUrl;return}f.setVerifying?.(!0);let Q=u.checkout.id,$e=u.checkout.clientSecret,ft=90,bt=2e3,z=!0,Ie=!1,Ae;console.log("[Recur SDK] Starting 3D verification polling...");for(let O=0;O<ft&&z;O++){if(_.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent($e)}`,{headers:a});if(v.ok){let K=await v.json();if(K.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),z=!1,Ie=!0,Ae=K.checkout?.orderId;break}}}catch(v){console.error("[Recur SDK] Final status check failed:",v)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent($e)}`,{headers:a});if(v.ok){let K=await v.json(),ee=K.checkout?.status;if(console.log(`[Recur SDK] Poll ${O+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),z=!1;try{_.close()}catch{}f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:K.checkout?.orderId||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),z=!1;try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){if(v.message==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||v.message==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,bt))}if(z){console.log("[Recur SDK] 3D verification polling timeout");try{_.close()}catch{}throw f.setVerifying?.(!1),f.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}Ie&&(console.log("[Recur SDK] Handling success after popup close"),f.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Ae||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(g.subscription)e.onPaymentComplete({id:g.subscription.id,status:g.subscription.status,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd});else{let $=g.charge?.id||g.paymentIntent?.id,_=g.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:$,status:_,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),f.resetButton?.(),r&&(r.close(),r.remove())}catch(E){console.error("[Recur SDK] Payment error:",E);let R={code:"PAYMENT_FAILED",message:E instanceof Error?E.message:"Payment failed"};e.onError?.(R),f.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(s){console.error("[Recur SDK] Checkout error:",s),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:s instanceof Error?s.message:"An unknown error occurred"};throw e.onError?.(a),s}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
|
|
1937
1970
|
.recur-dialog {
|
|
1938
1971
|
border: none;
|
|
1939
1972
|
border-radius: 12px;
|
|
@@ -1989,7 +2022,7 @@
|
|
|
1989
2022
|
.recur-dialog__close:hover {
|
|
1990
2023
|
background: rgba(0, 0, 0, 0.1);
|
|
1991
2024
|
}
|
|
1992
|
-
`,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function ht(n){return new G(n)}var
|
|
2025
|
+
`,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function ht(n){return new G(n)}var Nt={init:ht,RecurCheckout:G,RecurElements:N,createElements:Se};return _t(zt);})();
|
|
1993
2026
|
/*! Bundled license information:
|
|
1994
2027
|
|
|
1995
2028
|
lit-html/node/lit-html.js:
|
package/dist/server.cjs
CHANGED
package/dist/server.js
CHANGED