recur-tw 0.9.10 → 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 +112 -82
- 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: 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}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\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:
|
|
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: 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}\n\n.recur-coupon__btn--apply {\n background: #18181b;\n color: white;\n border: none;\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:
|
|
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
|
/* ============================================
|
|
@@ -1013,12 +1017,21 @@
|
|
|
1013
1017
|
cursor: pointer;
|
|
1014
1018
|
transition: background-color 0.2s, opacity 0.2s;
|
|
1015
1019
|
white-space: nowrap;
|
|
1020
|
+
display: inline-flex;
|
|
1021
|
+
align-items: center;
|
|
1022
|
+
justify-content: center;
|
|
1016
1023
|
}
|
|
1017
1024
|
|
|
1018
1025
|
.recur-coupon__btn--apply {
|
|
1019
1026
|
background: #18181b;
|
|
1020
1027
|
color: white;
|
|
1021
1028
|
border: none;
|
|
1029
|
+
min-width: 52px;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.recur-coupon__btn--apply .recur-coupon__spinner {
|
|
1033
|
+
width: 14px;
|
|
1034
|
+
height: 14px;
|
|
1022
1035
|
}
|
|
1023
1036
|
|
|
1024
1037
|
.recur-coupon__btn--apply:hover:not(:disabled) {
|
|
@@ -1049,50 +1062,49 @@
|
|
|
1049
1062
|
|
|
1050
1063
|
.recur-coupon__applied {
|
|
1051
1064
|
display: flex;
|
|
1052
|
-
align-items:
|
|
1053
|
-
justify-content: space-between;
|
|
1065
|
+
align-items: center;
|
|
1054
1066
|
gap: 8px;
|
|
1055
1067
|
width: 100%;
|
|
1068
|
+
height: 36px;
|
|
1056
1069
|
}
|
|
1057
1070
|
|
|
1058
1071
|
.recur-coupon__applied-info {
|
|
1059
1072
|
display: flex;
|
|
1060
|
-
align-items:
|
|
1061
|
-
gap:
|
|
1073
|
+
align-items: center;
|
|
1074
|
+
gap: 6px;
|
|
1062
1075
|
min-width: 0;
|
|
1076
|
+
flex: 1;
|
|
1063
1077
|
}
|
|
1064
1078
|
|
|
1065
1079
|
.recur-coupon__applied-icon {
|
|
1066
1080
|
width: 16px;
|
|
1067
1081
|
height: 16px;
|
|
1068
|
-
color: #
|
|
1082
|
+
color: #dc2626;
|
|
1069
1083
|
flex-shrink: 0;
|
|
1070
|
-
margin-top: 2px;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
.recur-coupon__applied-details {
|
|
1074
|
-
min-width: 0;
|
|
1075
1084
|
}
|
|
1076
1085
|
|
|
1077
1086
|
.recur-coupon__applied-name {
|
|
1078
1087
|
font-size: 14px;
|
|
1079
1088
|
font-weight: 500;
|
|
1080
|
-
color: #
|
|
1081
|
-
overflow: hidden;
|
|
1082
|
-
text-overflow: ellipsis;
|
|
1089
|
+
color: #dc2626;
|
|
1083
1090
|
white-space: nowrap;
|
|
1084
1091
|
}
|
|
1085
1092
|
|
|
1086
1093
|
.recur-coupon__applied-code {
|
|
1087
|
-
font-size:
|
|
1088
|
-
color: #
|
|
1094
|
+
font-size: 14px;
|
|
1095
|
+
color: #9ca3af;
|
|
1096
|
+
white-space: nowrap;
|
|
1097
|
+
margin-right: 2px;
|
|
1089
1098
|
}
|
|
1090
1099
|
|
|
1091
1100
|
.recur-coupon__applied-amount {
|
|
1092
1101
|
font-size: 14px;
|
|
1093
1102
|
font-weight: 500;
|
|
1094
|
-
color: #
|
|
1103
|
+
color: #dc2626;
|
|
1095
1104
|
white-space: nowrap;
|
|
1105
|
+
font-variant-numeric: tabular-nums;
|
|
1106
|
+
flex-shrink: 0;
|
|
1107
|
+
margin-left: auto;
|
|
1096
1108
|
}
|
|
1097
1109
|
|
|
1098
1110
|
.recur-coupon__remove {
|
|
@@ -1106,6 +1118,7 @@
|
|
|
1106
1118
|
display: flex;
|
|
1107
1119
|
align-items: center;
|
|
1108
1120
|
justify-content: center;
|
|
1121
|
+
flex-shrink: 0;
|
|
1109
1122
|
}
|
|
1110
1123
|
|
|
1111
1124
|
.recur-coupon__remove:hover {
|
|
@@ -1311,7 +1324,18 @@
|
|
|
1311
1324
|
@keyframes recur-spin {
|
|
1312
1325
|
to { transform: rotate(360deg); }
|
|
1313
1326
|
}
|
|
1314
|
-
|
|
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`
|
|
1315
1339
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1316
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" />
|
|
1317
1341
|
</svg>
|
|
@@ -1353,7 +1377,7 @@
|
|
|
1353
1377
|
<slot name="actions"></slot>
|
|
1354
1378
|
|
|
1355
1379
|
<div class="security-note">
|
|
1356
|
-
${
|
|
1380
|
+
${B.lock}
|
|
1357
1381
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
1358
1382
|
</div>
|
|
1359
1383
|
</div>
|
|
@@ -1386,35 +1410,56 @@
|
|
|
1386
1410
|
height: 36px !important;
|
|
1387
1411
|
}
|
|
1388
1412
|
${this.customStyles}
|
|
1389
|
-
`}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`
|
|
1390
1438
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1391
1439
|
<div class="recur-order-summary__row">
|
|
1392
|
-
<span class="recur-order-summary__label"
|
|
1440
|
+
<span class="recur-order-summary__label">${p?"\u8A02\u95B1\u65B9\u6848":"\u5546\u54C1"}</span>
|
|
1393
1441
|
<span class="recur-order-summary__value">${t}</span>
|
|
1394
1442
|
</div>
|
|
1395
1443
|
|
|
1396
|
-
${
|
|
1444
|
+
${p?m`
|
|
1397
1445
|
<div class="recur-order-summary__row">
|
|
1398
1446
|
<span class="recur-order-summary__label">計費週期</span>
|
|
1399
1447
|
<span class="recur-order-summary__value">每${s}</span>
|
|
1400
1448
|
</div>
|
|
1401
|
-
`:
|
|
1449
|
+
`:b}
|
|
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>
|
|
1402
1456
|
|
|
1457
|
+
<!-- 優惠碼區塊 (Coupon section with discount amount) -->
|
|
1403
1458
|
<div class="recur-coupon" id="${this.containerId}-coupon">
|
|
1404
1459
|
${this.renderCoupon()}
|
|
1405
1460
|
</div>
|
|
1406
1461
|
|
|
1407
|
-
|
|
1408
|
-
<div class="recur-order-summary__row">
|
|
1409
|
-
<span class="recur-order-summary__label">小計</span>
|
|
1410
|
-
<span class="recur-order-summary__value">NT$ ${a.toLocaleString()}</span>
|
|
1411
|
-
</div>
|
|
1412
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1413
|
-
<span class="recur-order-summary__label">折扣</span>
|
|
1414
|
-
<span class="recur-order-summary__value">-NT$ ${c.toLocaleString()}</span>
|
|
1415
|
-
</div>
|
|
1416
|
-
`:f}
|
|
1417
|
-
|
|
1462
|
+
<!-- 總計 (Total) -->
|
|
1418
1463
|
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1419
1464
|
<span class="recur-order-summary__label">總計</span>
|
|
1420
1465
|
<span class="recur-order-summary__total">NT$ ${d.toLocaleString()}</span>
|
|
@@ -1423,27 +1468,25 @@
|
|
|
1423
1468
|
`}renderCoupon(){return this._appliedCoupon?m`
|
|
1424
1469
|
<div class="recur-coupon__applied">
|
|
1425
1470
|
<div class="recur-coupon__applied-info">
|
|
1426
|
-
${
|
|
1427
|
-
|
|
1428
|
-
<
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
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>
|
|
1435
1486
|
</div>
|
|
1436
1487
|
<span class="recur-coupon__applied-amount">
|
|
1437
1488
|
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1438
1489
|
</span>
|
|
1439
|
-
<button
|
|
1440
|
-
type="button"
|
|
1441
|
-
class="recur-coupon__remove"
|
|
1442
|
-
?disabled=${this._couponLoading}
|
|
1443
|
-
@click=${()=>this.removeCoupon()}
|
|
1444
|
-
>
|
|
1445
|
-
${this._couponLoading?N.spinner:N.close}
|
|
1446
|
-
</button>
|
|
1447
1490
|
</div>
|
|
1448
1491
|
`:this._showCouponInput?m`
|
|
1449
1492
|
<div style="width: 100%;">
|
|
@@ -1464,7 +1507,7 @@
|
|
|
1464
1507
|
?disabled=${this._couponLoading||!this._couponCode.trim()}
|
|
1465
1508
|
@click=${()=>this.applyCoupon()}
|
|
1466
1509
|
>
|
|
1467
|
-
${this._couponLoading?
|
|
1510
|
+
${this._couponLoading?B.spinner:"\u5957\u7528"}
|
|
1468
1511
|
</button>
|
|
1469
1512
|
<button
|
|
1470
1513
|
type="button"
|
|
@@ -1477,7 +1520,7 @@
|
|
|
1477
1520
|
</div>
|
|
1478
1521
|
${this._couponError?m`
|
|
1479
1522
|
<div class="recur-coupon__error">${this._couponError}</div>
|
|
1480
|
-
`:
|
|
1523
|
+
`:b}
|
|
1481
1524
|
</div>
|
|
1482
1525
|
`:m`
|
|
1483
1526
|
<button
|
|
@@ -1485,10 +1528,10 @@
|
|
|
1485
1528
|
class="recur-coupon__trigger"
|
|
1486
1529
|
@click=${()=>this.showCouponInput()}
|
|
1487
1530
|
>
|
|
1488
|
-
${
|
|
1531
|
+
${B.tag}
|
|
1489
1532
|
有優惠碼?
|
|
1490
1533
|
</button>
|
|
1491
|
-
`}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`
|
|
1492
1535
|
<button type="button" class="recur-coupon__trigger">
|
|
1493
1536
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1494
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" />
|
|
@@ -1523,40 +1566,27 @@
|
|
|
1523
1566
|
</div>
|
|
1524
1567
|
${t}
|
|
1525
1568
|
</div>
|
|
1526
|
-
`}getCouponAppliedHTML(){let t=this._appliedCoupon
|
|
1569
|
+
`}getCouponAppliedHTML(){let t=this._appliedCoupon;return`
|
|
1527
1570
|
<div class="recur-coupon__applied">
|
|
1528
1571
|
<div class="recur-coupon__applied-info">
|
|
1529
1572
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1530
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" />
|
|
1531
1574
|
</svg>
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
${
|
|
1535
|
-
</
|
|
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>
|
|
1536
1579
|
</div>
|
|
1537
1580
|
<span class="recur-coupon__applied-amount">-NT$ ${t.discountAmount.toLocaleString()}</span>
|
|
1538
|
-
<button type="button" class="recur-coupon__remove" ${this._couponLoading?"disabled":""}>
|
|
1539
|
-
${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>'}
|
|
1540
|
-
</button>
|
|
1541
1581
|
</div>
|
|
1542
|
-
`}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,
|
|
1543
|
-
<div class="recur-order-summary__row">
|
|
1544
|
-
<span class="recur-order-summary__label">\u5C0F\u8A08</span>
|
|
1545
|
-
<span class="recur-order-summary__value">NT$ ${r.toLocaleString()}</span>
|
|
1546
|
-
</div>
|
|
1547
|
-
`,p=`
|
|
1548
|
-
<div class="recur-order-summary__row recur-order-summary__row--discount">
|
|
1549
|
-
<span class="recur-order-summary__label">\u6298\u6263</span>
|
|
1550
|
-
<span class="recur-order-summary__value">-NT$ ${o.toLocaleString()}</span>
|
|
1551
|
-
</div>
|
|
1552
|
-
`;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`
|
|
1553
1583
|
<div class="recur-info-display">
|
|
1554
1584
|
${t?m`
|
|
1555
1585
|
<div class="recur-info-row">
|
|
1556
1586
|
<span class="recur-info-label">姓名</span>
|
|
1557
1587
|
<span class="recur-info-value">${t}</span>
|
|
1558
1588
|
</div>
|
|
1559
|
-
`:
|
|
1589
|
+
`:b}
|
|
1560
1590
|
<div class="recur-info-row">
|
|
1561
1591
|
<span class="recur-info-label">電子郵件</span>
|
|
1562
1592
|
<span class="recur-info-value">${r}</span>
|
|
@@ -1852,7 +1882,7 @@
|
|
|
1852
1882
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1853
1883
|
<circle cx="12" cy="7" r="4"/>
|
|
1854
1884
|
</svg>
|
|
1855
|
-
`}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=`
|
|
1856
1886
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1857
1887
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1858
1888
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -1922,21 +1952,21 @@
|
|
|
1922
1952
|
</p>
|
|
1923
1953
|
</form>
|
|
1924
1954
|
</div>
|
|
1925
|
-
`}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=`
|
|
1926
1956
|
width: 100%;
|
|
1927
1957
|
border: none;
|
|
1928
1958
|
min-height: 200px;
|
|
1929
1959
|
display: block;
|
|
1930
1960
|
user-select: none;
|
|
1931
1961
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1932
|
-
`.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",`
|
|
1933
1963
|
.form-input-focus {
|
|
1934
1964
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1935
1965
|
outline: 0 !important;
|
|
1936
1966
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
1937
1967
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
1938
1968
|
}
|
|
1939
|
-
`),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=`
|
|
1940
1970
|
.recur-dialog {
|
|
1941
1971
|
border: none;
|
|
1942
1972
|
border-radius: 12px;
|
|
@@ -1992,7 +2022,7 @@
|
|
|
1992
2022
|
.recur-dialog__close:hover {
|
|
1993
2023
|
background: rgba(0, 0, 0, 0.1);
|
|
1994
2024
|
}
|
|
1995
|
-
`,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);})();
|
|
1996
2026
|
/*! Bundled license information:
|
|
1997
2027
|
|
|
1998
2028
|
lit-html/node/lit-html.js:
|
package/dist/server.cjs
CHANGED
package/dist/server.js
CHANGED