recur-tw 0.13.0 → 0.13.2
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/checkout.js +10 -2
- package/dist/index.cjs +155 -80
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +155 -80
- package/dist/recur.umd.js +48 -49
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/dist/widget.js +11 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1046,6 +1046,124 @@ var init_payment_form_light = __esm({
|
|
|
1046
1046
|
}
|
|
1047
1047
|
});
|
|
1048
1048
|
|
|
1049
|
+
// src/utils/checkout-display.ts
|
|
1050
|
+
function formatZhe(basisPoints) {
|
|
1051
|
+
const zhe = (1e4 - basisPoints) / 1e3;
|
|
1052
|
+
if (Number.isInteger(zhe)) return `${zhe} \u6298`;
|
|
1053
|
+
const zhe10 = zhe * 10;
|
|
1054
|
+
if (Number.isInteger(zhe10)) return `${zhe10} \u6298`;
|
|
1055
|
+
return `${(zhe * 10).toFixed(2)} \u6298`;
|
|
1056
|
+
}
|
|
1057
|
+
function getIntervalText(interval, count) {
|
|
1058
|
+
if (!interval) return "";
|
|
1059
|
+
const countText = count && count > 1 ? count.toString() : "";
|
|
1060
|
+
switch (interval.toUpperCase()) {
|
|
1061
|
+
case "MONTH":
|
|
1062
|
+
return `${countText}\u6708`;
|
|
1063
|
+
case "YEAR":
|
|
1064
|
+
return `${countText}\u5E74`;
|
|
1065
|
+
case "WEEK":
|
|
1066
|
+
return `${countText}\u9031`;
|
|
1067
|
+
case "DAY":
|
|
1068
|
+
return `${countText}\u5929`;
|
|
1069
|
+
default:
|
|
1070
|
+
return "";
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
function formatPrice(amount) {
|
|
1074
|
+
return `NT$ ${amount.toLocaleString("zh-TW")}`;
|
|
1075
|
+
}
|
|
1076
|
+
function getCheckoutDiscountDisplay(input) {
|
|
1077
|
+
const {
|
|
1078
|
+
discountType,
|
|
1079
|
+
couponDiscountValue,
|
|
1080
|
+
discountAmount,
|
|
1081
|
+
duration,
|
|
1082
|
+
durationMonths,
|
|
1083
|
+
productPrice,
|
|
1084
|
+
productInterval,
|
|
1085
|
+
productIntervalCount,
|
|
1086
|
+
bonusMonths,
|
|
1087
|
+
bonusTrialDays
|
|
1088
|
+
} = input;
|
|
1089
|
+
const intervalText = getIntervalText(productInterval, productIntervalCount);
|
|
1090
|
+
const originalPriceText = intervalText ? `${formatPrice(productPrice)}/${intervalText}` : formatPrice(productPrice);
|
|
1091
|
+
const bonusSuffix = buildBonusSuffix(bonusMonths, bonusTrialDays);
|
|
1092
|
+
if (discountAmount === 0 && (bonusMonths || bonusTrialDays)) {
|
|
1093
|
+
return {
|
|
1094
|
+
line1: buildPureBonusLine(bonusMonths, bonusTrialDays),
|
|
1095
|
+
line2: null
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
if (discountAmount === 0) {
|
|
1099
|
+
return { line1: "", line2: null };
|
|
1100
|
+
}
|
|
1101
|
+
const afterLine = `\u4E4B\u5F8C ${originalPriceText}`;
|
|
1102
|
+
if (discountType === "FIRST_PERIOD_PRICE") {
|
|
1103
|
+
const firstPeriodPrice = couponDiscountValue;
|
|
1104
|
+
const priceText = firstPeriodPrice === 0 ? "\u514D\u8CBB" : `\u7279\u50F9 ${formatPrice(firstPeriodPrice)}`;
|
|
1105
|
+
const line1 = bonusSuffix ? `\u9996\u671F${priceText}\uFF0C${bonusSuffix}` : `\u9996\u671F${priceText}`;
|
|
1106
|
+
return { line1, line2: afterLine };
|
|
1107
|
+
}
|
|
1108
|
+
if (discountType === "FIXED_AMOUNT") {
|
|
1109
|
+
return buildStandardDiscount({
|
|
1110
|
+
discountText: `\u6298 ${formatPrice(couponDiscountValue)}`,
|
|
1111
|
+
duration,
|
|
1112
|
+
durationMonths,
|
|
1113
|
+
bonusSuffix,
|
|
1114
|
+
afterLine
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
if (discountType === "PERCENTAGE") {
|
|
1118
|
+
return buildStandardDiscount({
|
|
1119
|
+
discountText: `\u4EAB ${formatZhe(couponDiscountValue)}`,
|
|
1120
|
+
duration,
|
|
1121
|
+
durationMonths,
|
|
1122
|
+
bonusSuffix,
|
|
1123
|
+
afterLine
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
return { line1: "", line2: null };
|
|
1127
|
+
}
|
|
1128
|
+
function buildStandardDiscount(opts) {
|
|
1129
|
+
const { discountText, duration, durationMonths, bonusSuffix, afterLine } = opts;
|
|
1130
|
+
switch (duration) {
|
|
1131
|
+
case "ONCE": {
|
|
1132
|
+
const base = `\u9996\u671F${discountText}`;
|
|
1133
|
+
const line1 = bonusSuffix ? `${base}\uFF0C${bonusSuffix}` : base;
|
|
1134
|
+
return { line1, line2: afterLine };
|
|
1135
|
+
}
|
|
1136
|
+
case "REPEATING": {
|
|
1137
|
+
const periods = durationMonths ?? 0;
|
|
1138
|
+
const line1 = `\u524D ${periods} \u671F\u6BCF\u671F${discountText}`;
|
|
1139
|
+
return { line1, line2: afterLine };
|
|
1140
|
+
}
|
|
1141
|
+
case "FOREVER": {
|
|
1142
|
+
const line1 = `\u6BCF\u671F${discountText}`;
|
|
1143
|
+
return { line1, line2: null };
|
|
1144
|
+
}
|
|
1145
|
+
default:
|
|
1146
|
+
return { line1: "", line2: null };
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
function buildBonusSuffix(bonusMonths, bonusTrialDays) {
|
|
1150
|
+
const parts = [];
|
|
1151
|
+
if (bonusMonths) parts.push(`\u52A0\u9001 ${bonusMonths} \u500B\u6708`);
|
|
1152
|
+
if (bonusTrialDays) parts.push(`\u5EF6\u9577 ${bonusTrialDays} \u5929\u8A66\u7528`);
|
|
1153
|
+
if (parts.length === 0) return null;
|
|
1154
|
+
return `\u4E26${parts.join("\u53CA")}`;
|
|
1155
|
+
}
|
|
1156
|
+
function buildPureBonusLine(bonusMonths, bonusTrialDays) {
|
|
1157
|
+
const parts = [];
|
|
1158
|
+
if (bonusMonths) parts.push(`\u52A0\u9001 ${bonusMonths} \u500B\u6708`);
|
|
1159
|
+
if (bonusTrialDays) parts.push(`\u5EF6\u9577\u8A66\u7528 ${bonusTrialDays} \u5929`);
|
|
1160
|
+
return parts.join("\u53CA");
|
|
1161
|
+
}
|
|
1162
|
+
var init_checkout_display = __esm({
|
|
1163
|
+
"src/utils/checkout-display.ts"() {
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1049
1167
|
// src/components/payment-form.ts
|
|
1050
1168
|
var payment_form_exports = {};
|
|
1051
1169
|
__export(payment_form_exports, {
|
|
@@ -1056,6 +1174,7 @@ var init_payment_form = __esm({
|
|
|
1056
1174
|
"src/components/payment-form.ts"() {
|
|
1057
1175
|
init_payment_form_shadow();
|
|
1058
1176
|
init_payment_form_light();
|
|
1177
|
+
init_checkout_display();
|
|
1059
1178
|
icons = {
|
|
1060
1179
|
lock: html`
|
|
1061
1180
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -1359,73 +1478,26 @@ var init_payment_form = __esm({
|
|
|
1359
1478
|
</div>
|
|
1360
1479
|
`;
|
|
1361
1480
|
}
|
|
1362
|
-
//
|
|
1363
|
-
|
|
1364
|
-
if (!interval) return "";
|
|
1365
|
-
const countText = count && count > 1 ? count.toString() : "";
|
|
1366
|
-
switch (interval.toUpperCase()) {
|
|
1367
|
-
case "MONTH":
|
|
1368
|
-
return `${countText}\u6708`;
|
|
1369
|
-
case "YEAR":
|
|
1370
|
-
return `${countText}\u5E74`;
|
|
1371
|
-
case "WEEK":
|
|
1372
|
-
return `${countText}\u9031`;
|
|
1373
|
-
case "DAY":
|
|
1374
|
-
return `${countText}\u5929`;
|
|
1375
|
-
default:
|
|
1376
|
-
return "";
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
// Get discount description based on type and duration
|
|
1380
|
-
getDiscountDescription() {
|
|
1481
|
+
// Get unified discount display using shared function
|
|
1482
|
+
getDiscountDisplay() {
|
|
1381
1483
|
if (!this._appliedCoupon) return null;
|
|
1382
|
-
const { discountType, duration, durationMonths, productPrice, productInterval, productIntervalCount } = this._appliedCoupon;
|
|
1383
|
-
const intervalText = this.getIntervalText(productInterval, productIntervalCount);
|
|
1384
|
-
const originalPriceText = productPrice && intervalText ? `NT$ ${productPrice.toLocaleString()}/${intervalText}` : productPrice ? `NT$ ${productPrice.toLocaleString()}` : "";
|
|
1385
1484
|
const amount = parseInt(this.getAttribute("amount") || "0", 10);
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1399
|
-
return "\u50C5\u9650\u9996\u671F";
|
|
1400
|
-
case "REPEATING":
|
|
1401
|
-
if (durationMonths) {
|
|
1402
|
-
return `\u524D ${durationMonths} \u671F\u4EAB\u512A\u60E0\uFF0C\u4E4B\u5F8C\u6062\u5FA9\u539F\u50F9`;
|
|
1403
|
-
}
|
|
1404
|
-
return null;
|
|
1405
|
-
case "FOREVER":
|
|
1406
|
-
return "\u7D42\u8EAB\u512A\u60E0";
|
|
1407
|
-
default:
|
|
1408
|
-
return null;
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
return null;
|
|
1412
|
-
}
|
|
1413
|
-
// Get bonus description
|
|
1414
|
-
getBonusDescription() {
|
|
1415
|
-
if (!this._appliedCoupon) return null;
|
|
1416
|
-
const parts = [];
|
|
1417
|
-
if (this._appliedCoupon.bonusTrialDays) {
|
|
1418
|
-
parts.push(`\u5EF6\u9577\u8A66\u7528 ${this._appliedCoupon.bonusTrialDays} \u5929`);
|
|
1419
|
-
}
|
|
1420
|
-
if (this._appliedCoupon.bonusMonths) {
|
|
1421
|
-
parts.push(`\u52A0\u9001 ${this._appliedCoupon.bonusMonths} \u500B\u6708`);
|
|
1422
|
-
}
|
|
1423
|
-
return parts.length > 0 ? parts.join("\u3001") : null;
|
|
1485
|
+
return getCheckoutDiscountDisplay({
|
|
1486
|
+
discountType: this._appliedCoupon.discountType,
|
|
1487
|
+
couponDiscountValue: this._appliedCoupon.couponDiscountValue,
|
|
1488
|
+
discountAmount: this._appliedCoupon.discountAmount,
|
|
1489
|
+
duration: this._appliedCoupon.duration || "ONCE",
|
|
1490
|
+
durationMonths: this._appliedCoupon.durationMonths,
|
|
1491
|
+
productPrice: this._appliedCoupon.productPrice ?? amount,
|
|
1492
|
+
productInterval: this._appliedCoupon.productInterval,
|
|
1493
|
+
productIntervalCount: this._appliedCoupon.productIntervalCount,
|
|
1494
|
+
bonusMonths: this._appliedCoupon.bonusMonths,
|
|
1495
|
+
bonusTrialDays: this._appliedCoupon.bonusTrialDays
|
|
1496
|
+
});
|
|
1424
1497
|
}
|
|
1425
1498
|
renderCoupon() {
|
|
1426
1499
|
if (this._appliedCoupon) {
|
|
1427
|
-
const
|
|
1428
|
-
const bonusDescription = this.getBonusDescription();
|
|
1500
|
+
const display = this.getDiscountDisplay();
|
|
1429
1501
|
return html`
|
|
1430
1502
|
<div class="recur-coupon__applied-wrapper">
|
|
1431
1503
|
<div class="recur-coupon__applied">
|
|
@@ -1446,18 +1518,17 @@ var init_payment_form = __esm({
|
|
|
1446
1518
|
${this._couponLoading ? icons.spinner : icons.close}
|
|
1447
1519
|
</button>
|
|
1448
1520
|
</div>
|
|
1449
|
-
|
|
1450
|
-
-
|
|
1451
|
-
|
|
1521
|
+
${this._appliedCoupon.discountAmount > 0 ? html`
|
|
1522
|
+
<span class="recur-coupon__applied-amount">
|
|
1523
|
+
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1524
|
+
</span>
|
|
1525
|
+
` : nothing}
|
|
1452
1526
|
</div>
|
|
1453
|
-
${
|
|
1454
|
-
<p class="recur-coupon__description">${
|
|
1527
|
+
${display?.line1 ? html`
|
|
1528
|
+
<p class="recur-coupon__description">${display.line1}</p>
|
|
1455
1529
|
` : nothing}
|
|
1456
|
-
${
|
|
1457
|
-
<
|
|
1458
|
-
<span>✨</span>
|
|
1459
|
-
<span>${bonusDescription}</span>
|
|
1460
|
-
</div>
|
|
1530
|
+
${display?.line2 ? html`
|
|
1531
|
+
<p class="recur-coupon__description">${display.line2}</p>
|
|
1461
1532
|
` : nothing}
|
|
1462
1533
|
</div>
|
|
1463
1534
|
`;
|
|
@@ -1620,10 +1691,10 @@ var init_payment_form = __esm({
|
|
|
1620
1691
|
getCouponAppliedHTML() {
|
|
1621
1692
|
const coupon = this._appliedCoupon;
|
|
1622
1693
|
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>`;
|
|
1623
|
-
const
|
|
1624
|
-
const
|
|
1625
|
-
const
|
|
1626
|
-
const
|
|
1694
|
+
const display = this.getDiscountDisplay();
|
|
1695
|
+
const amountHTML = coupon.discountAmount > 0 ? `<span class="recur-coupon__applied-amount">-NT$ ${coupon.discountAmount.toLocaleString()}</span>` : "";
|
|
1696
|
+
const line1HTML = display?.line1 ? `<p class="recur-coupon__description">${display.line1}</p>` : "";
|
|
1697
|
+
const line2HTML = display?.line2 ? `<p class="recur-coupon__description">${display.line2}</p>` : "";
|
|
1627
1698
|
return `
|
|
1628
1699
|
<div class="recur-coupon__applied-wrapper">
|
|
1629
1700
|
<div class="recur-coupon__applied">
|
|
@@ -1636,10 +1707,10 @@ var init_payment_form = __esm({
|
|
|
1636
1707
|
${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>'}
|
|
1637
1708
|
</button>
|
|
1638
1709
|
</div>
|
|
1639
|
-
|
|
1710
|
+
${amountHTML}
|
|
1640
1711
|
</div>
|
|
1641
|
-
${
|
|
1642
|
-
${
|
|
1712
|
+
${line1HTML}
|
|
1713
|
+
${line2HTML}
|
|
1643
1714
|
</div>
|
|
1644
1715
|
`;
|
|
1645
1716
|
}
|
|
@@ -1711,6 +1782,7 @@ var init_payment_form = __esm({
|
|
|
1711
1782
|
couponName: data.discount.coupon_name,
|
|
1712
1783
|
discountType: data.discount.discount_type,
|
|
1713
1784
|
discountAmount: data.discount.discount_amount,
|
|
1785
|
+
couponDiscountValue: data.discount.coupon_discount_value ?? data.discount.discount_amount,
|
|
1714
1786
|
duration: data.discount.duration,
|
|
1715
1787
|
durationMonths: data.discount.duration_months,
|
|
1716
1788
|
bonusTrialDays: data.discount.bonus_trial_days,
|
|
@@ -2736,7 +2808,7 @@ function toCamelCase(obj) {
|
|
|
2736
2808
|
|
|
2737
2809
|
// package.json
|
|
2738
2810
|
var package_default = {
|
|
2739
|
-
version: "0.13.
|
|
2811
|
+
version: "0.13.2"};
|
|
2740
2812
|
var SDK_VERSION = package_default.version;
|
|
2741
2813
|
var SDK_TYPE = "react";
|
|
2742
2814
|
var RecurContext = createContext(null);
|
|
@@ -2955,6 +3027,8 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
|
|
|
2955
3027
|
dialog.className = "recur-sdk__dialog";
|
|
2956
3028
|
dialogContent = document.createElement("div");
|
|
2957
3029
|
dialogContent.className = "recur-sdk__dialog-content";
|
|
3030
|
+
dialogContent.setAttribute("tabindex", "-1");
|
|
3031
|
+
dialogContent.setAttribute("autofocus", "");
|
|
2958
3032
|
dialogContent.style.cssText = `
|
|
2959
3033
|
max-width: 500px;
|
|
2960
3034
|
width: 100%;
|
|
@@ -2965,6 +3039,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
|
|
|
2965
3039
|
border-radius: 12px;
|
|
2966
3040
|
background: white;
|
|
2967
3041
|
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
|
|
3042
|
+
outline: none;
|
|
2968
3043
|
`;
|
|
2969
3044
|
const closeButton = document.createElement("button");
|
|
2970
3045
|
closeButton.className = "recur-sdk__close-button";
|