recur-tw 0.9.4 → 0.9.7
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 +175 -97
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +175 -97
- package/dist/recur.umd.js +122 -90
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/dist/server.d.cts +0 -194
- package/dist/server.d.ts +0 -194
package/dist/recur.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var RecurCheckout=(()=>{var
|
|
1
|
+
"use strict";var RecurCheckout=(()=>{var A=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var De=Object.getOwnPropertyNames;var Ue=Object.prototype.hasOwnProperty;var Le=(a,e,t)=>e in a?A(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var w=(a,e)=>()=>(a&&(e=a(a=0)),e);var v=(a,e)=>{for(var t in e)A(a,t,{get:e[t],enumerable:!0})},Me=(a,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of De(e))!Ue.call(a,i)&&i!==t&&A(a,i,{get:()=>e[i],enumerable:!(r=Pe(e,i))||r.enumerable});return a};var _e=a=>Me(A({},"__esModule",{value:!0}),a);var c=(a,e,t)=>Le(a,typeof e!="symbol"?e+"":e,t);var ie={};v(ie,{RecurLoadingSpinner:()=>z});var z,se=w(()=>{"use strict";z=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
|
|
2
2
|
<style>
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
<div class="recur-sdk__spinner"></div>
|
|
42
42
|
${this.message?`<p class="recur-sdk__loading-text">${this.message}</p>`:""}
|
|
43
|
-
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",z)});var oe={};v(oe,{RecurSuccessMessage:()
|
|
43
|
+
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",z)});var oe={};v(oe,{RecurSuccessMessage:()=>H});var H,ne=w(()=>{"use strict";H=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
|
|
44
44
|
<style>
|
|
45
45
|
:host {
|
|
46
46
|
display: block;
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
<p class="recur-sdk__success-message">${this.successMessage}</p>
|
|
122
122
|
<slot></slot>
|
|
123
123
|
</div>
|
|
124
|
-
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message"
|
|
124
|
+
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",H)});var ae={};v(ae,{RecurErrorDisplay:()=>$});var $,ce=w(()=>{"use strict";$=class extends HTMLElement{static get observedAttributes(){return["error","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
|
|
125
125
|
<style>
|
|
126
126
|
:host {
|
|
127
127
|
display: block;
|
|
@@ -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"
|
|
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",$)});var le={};v(le,{RecurSkeletonLoader:()=>B});var B,de=w(()=>{"use strict";B=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>
|
|
@@ -229,11 +229,14 @@
|
|
|
229
229
|
<div class="skeleton-label"></div>
|
|
230
230
|
<div class="skeleton-input"></div>
|
|
231
231
|
</div>
|
|
232
|
-
<div class="skeleton-
|
|
233
|
-
<div class="skeleton-
|
|
234
|
-
|
|
235
|
-
<div class="skeleton-input
|
|
236
|
-
|
|
232
|
+
<div class="skeleton-row">
|
|
233
|
+
<div class="skeleton-field">
|
|
234
|
+
<div class="skeleton-label"></div>
|
|
235
|
+
<div class="skeleton-input"></div>
|
|
236
|
+
</div>
|
|
237
|
+
<div class="skeleton-field">
|
|
238
|
+
<div class="skeleton-label"></div>
|
|
239
|
+
<div class="skeleton-input"></div>
|
|
237
240
|
</div>
|
|
238
241
|
</div>
|
|
239
242
|
<div class="skeleton-button"></div>
|
|
@@ -252,6 +255,7 @@
|
|
|
252
255
|
<style>
|
|
253
256
|
:host {
|
|
254
257
|
display: block;
|
|
258
|
+
container-type: inline-size; /* Enable container queries */
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
@keyframes recur-sdk-pulse {
|
|
@@ -287,8 +291,8 @@
|
|
|
287
291
|
|
|
288
292
|
.skeleton-row {
|
|
289
293
|
display: grid;
|
|
290
|
-
grid-template-columns:
|
|
291
|
-
gap:
|
|
294
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
295
|
+
column-gap: 16px;
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
.skeleton-input-half {
|
|
@@ -377,7 +381,7 @@
|
|
|
377
381
|
</style>
|
|
378
382
|
|
|
379
383
|
${e}
|
|
380
|
-
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",
|
|
384
|
+
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",B)});var ue={};v(ue,{RecurPaymentFormSkeleton:()=>K});var K,me=w(()=>{"use strict";K=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
|
|
381
385
|
<style>
|
|
382
386
|
:host {
|
|
383
387
|
display: block;
|
|
@@ -505,9 +509,7 @@
|
|
|
505
509
|
}
|
|
506
510
|
|
|
507
511
|
.info-row {
|
|
508
|
-
|
|
509
|
-
align-items: center;
|
|
510
|
-
margin-bottom: 6px;
|
|
512
|
+
margin-bottom: 12px;
|
|
511
513
|
}
|
|
512
514
|
|
|
513
515
|
.info-row:last-child {
|
|
@@ -515,9 +517,11 @@
|
|
|
515
517
|
}
|
|
516
518
|
|
|
517
519
|
.info-label {
|
|
518
|
-
|
|
520
|
+
display: block;
|
|
521
|
+
font-size: 12px;
|
|
522
|
+
line-height: 16px;
|
|
519
523
|
color: #718096;
|
|
520
|
-
|
|
524
|
+
margin-bottom: 2px;
|
|
521
525
|
}
|
|
522
526
|
|
|
523
527
|
.skeleton-info-value {
|
|
@@ -542,8 +546,8 @@
|
|
|
542
546
|
|
|
543
547
|
.card-row {
|
|
544
548
|
display: grid;
|
|
545
|
-
grid-template-columns:
|
|
546
|
-
gap:
|
|
549
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
550
|
+
column-gap: 16px;
|
|
547
551
|
}
|
|
548
552
|
|
|
549
553
|
/* Submit Button - matches .recur-submit-button: padding 14px*2 + font 16px * line-height ~1.5 */
|
|
@@ -601,14 +605,14 @@
|
|
|
601
605
|
|
|
602
606
|
<!-- Customer Info Section (matches createCustomerInfoSection read-only display) -->
|
|
603
607
|
<div class="form-section">
|
|
604
|
-
<h3 class="section-title">\
|
|
608
|
+
<h3 class="section-title">\u806F\u7D61\u8CC7\u8A0A</h3>
|
|
605
609
|
<div class="customer-info-display">
|
|
606
610
|
<div class="info-row">
|
|
607
|
-
<span class="info-label">\
|
|
611
|
+
<span class="info-label">\u59D3\u540D</span>
|
|
608
612
|
<div class="skeleton skeleton-info-value"></div>
|
|
609
613
|
</div>
|
|
610
614
|
<div class="info-row">
|
|
611
|
-
<span class="info-label">\u96FB\u5B50\u90F5\u4EF6
|
|
615
|
+
<span class="info-label">\u96FB\u5B50\u90F5\u4EF6</span>
|
|
612
616
|
<div class="skeleton skeleton-info-value" style="width: 160px;"></div>
|
|
613
617
|
</div>
|
|
614
618
|
</div>
|
|
@@ -644,7 +648,7 @@
|
|
|
644
648
|
<p class="security-text">\u60A8\u7684\u4ED8\u6B3E\u8CC7\u8A0A\u7D93\u904E\u52A0\u5BC6\u4FDD\u8B77</p>
|
|
645
649
|
</div>
|
|
646
650
|
</div>
|
|
647
|
-
`}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",
|
|
651
|
+
`}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",K)});var pe={};v(pe,{RecurToast:()=>N,RecurToastContainer:()=>D});var N,x,D,he=w(()=>{"use strict";N=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
648
652
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
649
653
|
</svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
650
654
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
@@ -764,7 +768,7 @@
|
|
|
764
768
|
</svg>
|
|
765
769
|
</button>
|
|
766
770
|
</div>
|
|
767
|
-
`,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",
|
|
771
|
+
`,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",i=>{i.stopPropagation(),this.dismiss()}),this.shadowRoot.querySelector(".toast")?.addEventListener("click",()=>this.dismiss())}static show(e,t="info",r=5e3){let i=D.getInstance(),s=document.createElement("recur-toast");return s.setAttribute("message",e),s.setAttribute("type",t),s.setAttribute("duration",r.toString()),i.appendChild(s),s}},x=class x extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
|
|
768
772
|
<style>
|
|
769
773
|
:host {
|
|
770
774
|
position: fixed;
|
|
@@ -791,7 +795,7 @@
|
|
|
791
795
|
</style>
|
|
792
796
|
|
|
793
797
|
<slot></slot>
|
|
794
|
-
`}static getInstance(){return x.instance||(x.instance=document.querySelector("recur-toast-container"),x.instance||(x.instance=document.createElement("recur-toast-container"),document.body.appendChild(x.instance))),x.instance}};c(x,"instance",null);
|
|
798
|
+
`}static getInstance(){return x.instance||(x.instance=document.querySelector("recur-toast-container"),x.instance||(x.instance=document.createElement("recur-toast-container"),document.body.appendChild(x.instance))),x.instance}};c(x,"instance",null);D=x;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",N);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",D)});var fe={};v(fe,{RecurPaymentForm:()=>O});var O,ge=w(()=>{"use strict";O=class extends HTMLElement{constructor(){super();c(this,"containerId");c(this,"customStyles");c(this,"_isInitializing",!1);c(this,"_initializationAborted",!1);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","product-name","amount","interval"]}attributeChangedCallback(t,r,i){t==="custom-styles"&&r!==i?(this.customStyles=i||"",this.updateCustomStyles()):r!==i&&this.updateCustomerInfoSection()}render(){this.shadowRoot.innerHTML=`
|
|
795
799
|
<style>
|
|
796
800
|
:host {
|
|
797
801
|
display: block;
|
|
@@ -805,6 +809,10 @@
|
|
|
805
809
|
background: white;
|
|
806
810
|
border-radius: 12px;
|
|
807
811
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
812
|
+
/* Prevent double-tap zoom on iOS */
|
|
813
|
+
touch-action: manipulation;
|
|
814
|
+
/* Enable container queries for responsive layout */
|
|
815
|
+
container-type: inline-size;
|
|
808
816
|
}
|
|
809
817
|
|
|
810
818
|
.form-header {
|
|
@@ -870,7 +878,7 @@
|
|
|
870
878
|
<slot name="order-summary"></slot>
|
|
871
879
|
|
|
872
880
|
<div class="form-section">
|
|
873
|
-
<h3 class="section-title">\
|
|
881
|
+
<h3 class="section-title">\u806F\u7D61\u8CC7\u8A0A</h3>
|
|
874
882
|
<!-- Slot for customer info fields (Light DOM) -->
|
|
875
883
|
<slot name="customer-info"></slot>
|
|
876
884
|
</div>
|
|
@@ -899,7 +907,7 @@
|
|
|
899
907
|
height: 36px !important;
|
|
900
908
|
}
|
|
901
909
|
`;t.textContent=this.customStyles+`
|
|
902
|
-
`+r,this.appendChild(t);let
|
|
910
|
+
`+r,this.appendChild(t);let i=this.createOrderSummarySection();i.slot="order-summary",this.appendChild(i);let s=this.createCustomerInfoSection();s.slot="customer-info",this.appendChild(s);let n=this.createCardFieldsSection();n.slot="card-fields",this.appendChild(n);let o=this.createActionsSection();o.slot="actions",this.appendChild(o)}updateCustomerInfoSection(){let t=this.querySelector('[slot="customer-info"]');if(t){let r=this.createCustomerInfoSection();r.slot="customer-info",t.replaceWith(r)}}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-custom-styles`);if(t){let r=`
|
|
903
911
|
/* PAYUNi iframe \u5BB9\u5668\u9AD8\u5EA6\uFF08\u4F7F\u7528\u5BE6\u969B\u7684 container ID\uFF09 */
|
|
904
912
|
#${this.containerId}-card-no,
|
|
905
913
|
#${this.containerId}-card-exp,
|
|
@@ -907,7 +915,7 @@
|
|
|
907
915
|
height: 36px !important;
|
|
908
916
|
}
|
|
909
917
|
`;t.textContent=this.customStyles+`
|
|
910
|
-
`+r}}createOrderSummarySection(){let t=document.createElement("div");t.className="order-summary-section";let r=this.getAttribute("
|
|
918
|
+
`+r}}createOrderSummarySection(){let t=document.createElement("div");t.className="order-summary-section";let r=this.getAttribute("product-name"),i=this.getAttribute("amount"),s=this.getAttribute("interval");if(!r||!i)return t;let o=s?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[s]||s:"";return t.innerHTML=`
|
|
911
919
|
<style>
|
|
912
920
|
.order-summary-section {
|
|
913
921
|
background: #f7fafc;
|
|
@@ -970,9 +978,9 @@
|
|
|
970
978
|
`:""}
|
|
971
979
|
<div class="order-summary-item">
|
|
972
980
|
<span class="order-summary-label">\u7E3D\u8A08</span>
|
|
973
|
-
<span class="order-summary-total">NT$ ${Number(
|
|
981
|
+
<span class="order-summary-total">NT$ ${Number(i).toLocaleString()}</span>
|
|
974
982
|
</div>
|
|
975
|
-
`,t}createCustomerInfoSection(){let t=document.createElement("div");t.className="customer-info-section";let r=this.getAttribute("customer-name"),
|
|
983
|
+
`,t}createCustomerInfoSection(){let t=document.createElement("div");t.className="customer-info-section";let r=this.getAttribute("customer-name"),i=this.getAttribute("customer-email");return i?t.innerHTML=`
|
|
976
984
|
<style>
|
|
977
985
|
.recur-info-display {
|
|
978
986
|
background: #f7fafc;
|
|
@@ -983,9 +991,7 @@
|
|
|
983
991
|
}
|
|
984
992
|
|
|
985
993
|
.recur-info-row {
|
|
986
|
-
|
|
987
|
-
align-items: center;
|
|
988
|
-
margin-bottom: 6px;
|
|
994
|
+
margin-bottom: 12px;
|
|
989
995
|
}
|
|
990
996
|
|
|
991
997
|
.recur-info-row:last-child {
|
|
@@ -993,29 +999,34 @@
|
|
|
993
999
|
}
|
|
994
1000
|
|
|
995
1001
|
.recur-info-label {
|
|
996
|
-
|
|
1002
|
+
display: block;
|
|
1003
|
+
font-size: 12px;
|
|
1004
|
+
line-height: 16px;
|
|
997
1005
|
color: #718096;
|
|
998
|
-
|
|
1006
|
+
margin-bottom: 2px;
|
|
999
1007
|
}
|
|
1000
1008
|
|
|
1001
1009
|
.recur-info-value {
|
|
1010
|
+
display: block;
|
|
1002
1011
|
font-size: 14px;
|
|
1003
1012
|
line-height: 20px;
|
|
1013
|
+
min-height: 20px;
|
|
1004
1014
|
color: #2d3748;
|
|
1005
1015
|
font-weight: 500;
|
|
1016
|
+
word-break: break-all;
|
|
1006
1017
|
}
|
|
1007
1018
|
</style>
|
|
1008
1019
|
|
|
1009
1020
|
<div class="recur-info-display">
|
|
1010
1021
|
${r?`
|
|
1011
1022
|
<div class="recur-info-row">
|
|
1012
|
-
<span class="recur-info-label">\
|
|
1023
|
+
<span class="recur-info-label">\u59D3\u540D</span>
|
|
1013
1024
|
<span class="recur-info-value">${r}</span>
|
|
1014
1025
|
</div>
|
|
1015
1026
|
`:""}
|
|
1016
1027
|
<div class="recur-info-row">
|
|
1017
|
-
<span class="recur-info-label">\u96FB\u5B50\u90F5\u4EF6
|
|
1018
|
-
<span class="recur-info-value">${
|
|
1028
|
+
<span class="recur-info-label">\u96FB\u5B50\u90F5\u4EF6</span>
|
|
1029
|
+
<span class="recur-info-value">${i}</span>
|
|
1019
1030
|
</div>
|
|
1020
1031
|
</div>
|
|
1021
1032
|
`:t.innerHTML=`
|
|
@@ -1037,7 +1048,7 @@
|
|
|
1037
1048
|
.recur-form-input {
|
|
1038
1049
|
width: 100%;
|
|
1039
1050
|
padding: 10px 12px;
|
|
1040
|
-
font-size:
|
|
1051
|
+
font-size: 16px; /* 16px prevents iOS Safari auto-zoom on focus */
|
|
1041
1052
|
border: 1px solid #d1d5db;
|
|
1042
1053
|
border-radius: 6px;
|
|
1043
1054
|
transition: border-color 0.2s;
|
|
@@ -1097,12 +1108,14 @@
|
|
|
1097
1108
|
width: 100%;
|
|
1098
1109
|
max-width: 100%;
|
|
1099
1110
|
box-sizing: border-box;
|
|
1111
|
+
/* Help reduce iOS zoom issues */
|
|
1112
|
+
touch-action: manipulation;
|
|
1100
1113
|
}
|
|
1101
1114
|
|
|
1102
1115
|
.recur-card-row {
|
|
1103
1116
|
display: grid;
|
|
1104
|
-
grid-template-columns:
|
|
1105
|
-
gap:
|
|
1117
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
1118
|
+
column-gap: 16px;
|
|
1106
1119
|
max-width: 100%;
|
|
1107
1120
|
box-sizing: border-box;
|
|
1108
1121
|
}
|
|
@@ -1110,6 +1123,8 @@
|
|
|
1110
1123
|
/* Container needs relative positioning for skeleton overlay */
|
|
1111
1124
|
.recur-card-field-container {
|
|
1112
1125
|
position: relative;
|
|
1126
|
+
/* Help reduce iOS zoom issues */
|
|
1127
|
+
touch-action: manipulation;
|
|
1113
1128
|
}
|
|
1114
1129
|
|
|
1115
1130
|
/* Loading skeleton for card fields - shown until PAYUNi iframe loads */
|
|
@@ -1165,7 +1180,7 @@
|
|
|
1165
1180
|
</div>
|
|
1166
1181
|
</div>
|
|
1167
1182
|
</div>
|
|
1168
|
-
`,t}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let
|
|
1183
|
+
`,t}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let i=document.getElementById(r);i&&i.classList.add("hidden")})}createActionsSection(){let t=document.createElement("div");return t.className="actions-section",t.innerHTML=`
|
|
1169
1184
|
<style>
|
|
1170
1185
|
.recur-submit-button {
|
|
1171
1186
|
width: 100%;
|
|
@@ -1220,13 +1235,13 @@
|
|
|
1220
1235
|
>
|
|
1221
1236
|
<span id="${this.containerId}-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>
|
|
1222
1237
|
</button>
|
|
1223
|
-
`,t}async initializePayment(t,r){if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before start"),null;if(this._isInitializing=!0,await this.updateComplete(),this._initializationAborted)return console.log("[PaymentForm] Initialization aborted after updateComplete"),this._isInitializing=!1,null;if(!window.UniPayment)throw this._isInitializing=!1,new Error("PAYUNi SDK not loaded");try{let
|
|
1238
|
+
`,t}async initializePayment(t,r){if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before start"),null;if(this._isInitializing=!0,await this.updateComplete(),this._initializationAborted)return console.log("[PaymentForm] Initialization aborted after updateComplete"),this._isInitializing=!1,null;if(!window.UniPayment)throw this._isInitializing=!1,new Error("PAYUNi SDK not loaded");try{let i=document.getElementById(`${this.containerId}-card-no`),s=document.getElementById(`${this.containerId}-card-exp`),n=document.getElementById(`${this.containerId}-card-cvc`);if(!i||!s||!n)return console.log("[PaymentForm] DOM elements not found, likely disconnected"),this._isInitializing=!1,null;if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before createSession"),this._isInitializing=!1,null;let o=window.UniPayment.createSession(t,{env:r==="SANDBOX"?"S":"P",elements:{CardNo:`${this.containerId}-card-no`,CardExp:`${this.containerId}-card-exp`,CardCvc:`${this.containerId}-card-cvc`}});if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before paymentSession.start()"),this._isInitializing=!1,null;try{await o.start()}catch(l){if((l?.message?.includes("1008")||l?.message?.includes("timeout")||l?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw l}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),o.onUpdate?.(l=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",l);let m=l.status&&l.status.CardNo===!0&&l.status.CardExp===!0&&l.status.CardCvc===!0,b=document.getElementById(`${this.containerId}-submit-btn`);b&&(b.disabled=!m,console.log("[PaymentForm] Submit button disabled:",!m))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=o,this.setupFormSubmission(),this._isInitializing=!1,o))}catch(i){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",i),i}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let i,s,n=document.getElementById(`${this.containerId}-email`),o=document.getElementById(`${this.containerId}-name`);if(n&&o){if(i=n.value,s=o.value,!i||!s){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(i=this.getAttribute("customer-email")||void 0,s=this.getAttribute("customer-name")||void 0,!i||!s){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:i,customerName:s,paymentSession:this._paymentSession},bubbles:!0,composed:!0}))})}setButtonLoading(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
|
|
1224
1239
|
<span class="recur-loading-spinner"></span>
|
|
1225
1240
|
<span>\u8655\u7406\u4E2D...</span>
|
|
1226
1241
|
`):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}setVerifying(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
|
|
1227
1242
|
<span class="recur-loading-spinner"></span>
|
|
1228
1243
|
<span>3D \u9A57\u8B49\u4E2D...</span>
|
|
1229
|
-
`):this.setButtonLoading(!1))}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let
|
|
1244
|
+
`):this.setButtonLoading(!1))}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let i=document.createElement("recur-error-display");i.setAttribute("error",t),i.setAttribute("dismissible","true"),r.innerHTML="",r.appendChild(i),i.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",O)});var be={};v(be,{RecurCheckoutButton:()=>j});var j,ye=w(()=>{"use strict";j=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),i=this.getAttribute("product-id"),s=this.getAttribute("success-url"),n=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!i){this.dispatchError("Missing required attribute: product-id");return}if(!s){this.dispatchError("Missing required attribute: success-url");return}if(!n){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let o=await this.createCheckoutSession({publishableKey:r,productId:i,successUrl:this.resolveUrl(s),cancelUrl:this.resolveUrl(n),customerEmail:this.getAttribute("customer-email")||void 0,mode:this.getAttribute("mode")});this.dispatchEvent(new CustomEvent("checkout-started",{detail:{sessionId:o.id,url:o.url},bubbles:!0,composed:!0})),window.location.href=o.url}catch(o){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(o.message||"Failed to create checkout session")}});this.attachShadow({mode:"open"})}static get observedAttributes(){return["publishable-key","product-id","success-url","cancel-url","customer-email","mode","button-text","button-style","disabled"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
|
|
1230
1245
|
<style>
|
|
1231
1246
|
:host {
|
|
1232
1247
|
display: inline-block;
|
|
@@ -1319,13 +1334,13 @@
|
|
|
1319
1334
|
|
|
1320
1335
|
<button
|
|
1321
1336
|
class="${r}"
|
|
1322
|
-
${
|
|
1337
|
+
${i?"disabled":""}
|
|
1323
1338
|
aria-busy="${this._isLoading}"
|
|
1324
1339
|
>
|
|
1325
1340
|
${this._isLoading?'<span class="spinner"></span>':""}
|
|
1326
1341
|
<span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
|
|
1327
1342
|
</button>
|
|
1328
|
-
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),
|
|
1343
|
+
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(i.mode=t.mode),t.customerEmail&&(i.customerEmail=t.customerEmail);let s=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(i)});if(!s.ok){let n=await s.json().catch(()=>({}));throw new Error(n.error?.message||`HTTP ${s.status}: Failed to create checkout session`)}return s.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",j)});var ke={};v(ke,{RecurPortalButton:()=>F});var F,ve=w(()=>{"use strict";F=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),i=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(i){await this.fetchAndRedirect(i);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
|
|
1329
1344
|
<style>
|
|
1330
1345
|
:host {
|
|
1331
1346
|
display: inline-block;
|
|
@@ -1441,7 +1456,7 @@
|
|
|
1441
1456
|
|
|
1442
1457
|
<button
|
|
1443
1458
|
class="${r}"
|
|
1444
|
-
${
|
|
1459
|
+
${i?"disabled":""}
|
|
1445
1460
|
aria-busy="${this._isLoading}"
|
|
1446
1461
|
>
|
|
1447
1462
|
${this._isLoading?'<span class="spinner"></span>':this.getPortalIcon()}
|
|
@@ -1452,7 +1467,7 @@
|
|
|
1452
1467
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1453
1468
|
<circle cx="12" cy="7" r="4"/>
|
|
1454
1469
|
</svg>
|
|
1455
|
-
`}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"),
|
|
1470
|
+
`}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"),i=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let s={};r&&(s.customerId=r),i&&(s.returnUrl=i);let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok){let m=await n.json().catch(()=>({}));throw new Error(m.error?.message||m.message||`HTTP ${n.status}: Failed to create portal session`)}let o=await n.json(),l=o.url||o.portalUrl;if(!l)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(l)}catch(s){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(s.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",F)});var je={};v(je,{RecurCheckout:()=>L,RecurElements:()=>I,createElements:()=>Z,default:()=>Oe,init:()=>Se});async function Ae(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(se(),ie)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le)),Promise.resolve().then(()=>(me(),ue)),Promise.resolve().then(()=>(he(),pe)),Promise.resolve().then(()=>(ge(),fe)),Promise.resolve().then(()=>(ye(),be)),Promise.resolve().then(()=>(ve(),ke))]);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"&&Ae();function ze(a){return a.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function g(a){if(a==null)return a;if(Array.isArray(a))return a.map(e=>g(e));if(a instanceof Date)return a;if(typeof a=="object"){let e={};for(let[t,r]of Object.entries(a)){let i=ze(t);e[i]=g(r)}return e}return a}var we={name:"recur-tw",version:"0.9.7",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"}};var $e=we.version,Be="vanilla",q=class{constructor(e){c(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":Be,"X-Recur-SDK-Version":$e,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,i=e.productId||e.planId,s=e.productSlug;if(!i&&!s)throw new Error("Either productId or productSlug is required");let n={customerName:t,customerEmail:r};i&&(n.productId=i),s&&(n.productSlug=s);let o=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(n)});if(!o.ok){let m=await o.json().catch(()=>({}));throw{code:m.error||"CHECKOUT_FAILED",message:m.message||"Failed to initiate checkout",details:m}}let l=await o.json();return g(l)}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 s=await r.json().catch(()=>({}));throw{code:s.error||"FETCH_PRODUCTS_FAILED",message:s.message||"Failed to fetch products",details:s}}let i=await r.json();return g(i)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var V=class{constructor(e,t){c(this,"config");c(this,"options");c(this,"container");c(this,"checkoutId",null);c(this,"sdkToken",null);c(this,"sdkTimestamp",null);c(this,"creditToken",null);c(this,"sdkEnv","S");c(this,"payuniSDK",null);c(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 s=await t.json().catch(()=>({}));throw new Error(s.error||"Failed to initialize checkout")}let r=await t.json(),i=g(r);this.checkoutId=i.checkout.id,this.sdkToken=i.sdkToken,this.sdkTimestamp=i.sdkTimestamp||null,this.creditToken=i.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
|
|
1456
1471
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1457
1472
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1458
1473
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -1522,60 +1537,77 @@
|
|
|
1522
1537
|
</p>
|
|
1523
1538
|
</form>
|
|
1524
1539
|
</div>
|
|
1525
|
-
`}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
|
|
1540
|
+
`}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 i=r?.status;i&&(this.isFormValid=i.CardNo===!0&&i.CardExp===!0&&i.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 i=r.EncryptInfo||r.creditToken;if(!i)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let s=this.getBaseUrl(),n=await fetch(`${s}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:i,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!n.ok){let b=await n.json().catch(()=>({}));throw new Error(b.error||"Failed to process payment")}let o=await n.json(),l=this.options.productId||this.options.planId||"",m={subscription:{id:o.subscription?.id||o.charge?.id||"",status:o.success?"active":"failed",productId:l,productName:"",amount:o.charge?.amount||0,billingPeriod:o.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(m),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 I=class{constructor(e){c(this,"publishableKey");c(this,"baseUrl");c(this,"embedUrl");c(this,"iframe",null);c(this,"container",null);c(this,"sessionId",null);c(this,"timestamp",null);c(this,"creditToken",null);c(this,"sdkToken",null);c(this,"cardToken",null);c(this,"cardTimestamp",null);c(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=`
|
|
1526
1541
|
width: 100%;
|
|
1527
1542
|
border: none;
|
|
1528
1543
|
min-height: 200px;
|
|
1529
1544
|
display: block;
|
|
1530
1545
|
user-select: none;
|
|
1531
1546
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1532
|
-
`.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,
|
|
1547
|
+
`.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,i)=>{let s=setTimeout(()=>{i(new Error("Elements initialization timeout"))},3e4),n=()=>{clearTimeout(s),this.off("ready",n),r()},o=l=>{clearTimeout(s),this.off("error",o),i(new Error(l.message||"Elements initialization failed"))};this.on("ready",n),this.on("error",o)})}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(i=>i(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 i=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),s=o=>{clearTimeout(i),this.off("tokenized",s),t(o)},n=o=>{clearTimeout(i),this.off("error",n),r(new Error(o.message||"Tokenization failed"))};this.on("tokenized",s),this.on("error",n)})}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 Z(a){return new I(a)}var Ke="https://vendor.payuni.com.tw/sdk/uni-payment.js",Ne="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",xe=!1,Y=!1,U=null;async function Ee(a=!1){return xe&&window.UniPayment?Promise.resolve():(Y&&U||(Y=!0,U=new Promise((e,t)=>{let r=document.createElement("script");r.src=a?Ne:Ke,r.async=!0,r.onload=()=>{xe=!0,Y=!1,e()},r.onerror=()=>{Y=!1,U=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),U)}var L=class{constructor(e){c(this,"core");c(this,"currentDialog",null);c(this,"currentIframe",null);c(this,"currentDialogElement",null);this.core=new q(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 V(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 i=this.core.getConfig(),s=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":i.publishableKey},body:JSON.stringify(r)});if(!s.ok){let l=await s.json().catch(()=>({}));throw new Error(l.error?.message||l.error||"Failed to create checkout session")}let n=await s.json(),o=g(n);return{id:o.id,url:o.url,expiresAt:o.expiresAt,clientSecret:o.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),i=this.core.getConfig(),s=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":i.publishableKey}});if(!s.ok){let l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to get checkout status")}let n=await s.json(),o=g(n);return{id:o.checkout.id,status:o.checkout.status,amount:o.checkout.amount,currency:o.checkout.currency,lastCharge:o.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,i=e.productId||e.planId,s=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:i,productSlug:s,mode:e.mode}),!i&&!s)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let n=this.getBaseUrl();console.log("[Recur SDK] Base URL:",n);let o={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},l=e.mode||"modal";if(l==="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 h={successUrl:e.successUrl,cancelUrl:e.cancelUrl};i&&(h.productId=i),s&&(h.productSlug=s),e.customerEmail&&(h.customerEmail=e.customerEmail),e.customerName&&(h.customerName=e.customerName),e.externalCustomerId&&(h.externalCustomerId=e.externalCustomerId);let S=await fetch(`${n}/v1/checkout/sessions`,{method:"POST",headers:o,body:JSON.stringify(h)});if(!S.ok){let C=await S.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",C),new Error(C.error?.message||C.error||"Failed to create checkout session")}let J=await S.json(),k=g(J);console.log("[Recur SDK] Checkout session created:",k),console.log("[Recur SDK] Redirecting to hosted checkout:",k.url),window.location.href=k.url;return}let m=null;if(l==="modal"){let h=this.createDialogWithSkeleton(e.onClose);r=h.dialog,m=h.container}else if(l==="iframe"){if(m=this.getEmbeddedContainer(e.container),!m)throw new Error("Container is required for iframe mode");m.innerHTML="";let h=document.createElement("recur-payment-form-skeleton");m.appendChild(h)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let b={customerName:e.customerName,customerEmail:e.customerEmail};i&&(b.productId=i),s&&(b.productSlug=s),e.externalCustomerId&&(b.externalCustomerId=e.externalCustomerId),e.successUrl&&(b.successUrl=e.successUrl),e.cancelUrl&&(b.cancelUrl=e.cancelUrl);let X=await fetch(`${n}/v1/checkouts`,{method:"POST",headers:o,body:JSON.stringify(b)});if(!X.ok){let h=await X.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",h);let S=h.details||h.error||"Failed to create checkout";throw new Error(S)}let Ce=await X.json(),d=g(Ce);if(console.log("[Recur SDK] Checkout created successfully:",d),e.onSuccess?.(d),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!d.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let W=!d.livemode;if(console.log("[Recur SDK] Environment:",W?"SANDBOX":"PRODUCTION"),await Ee(W),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..."),!m)throw new Error("Payment container not available");m.innerHTML="";let p=document.createElement("recur-payment-form");if(p.setAttribute("container-id",m.id||"recur-payment-container"),e.customerName&&p.setAttribute("customer-name",e.customerName),e.customerEmail&&p.setAttribute("customer-email",e.customerEmail),d.product?.name&&p.setAttribute("product-name",d.product.name),d.checkout?.amount&&p.setAttribute("amount",d.checkout.amount.toString()),d.product?.interval&&p.setAttribute("interval",d.product.interval),p.setAttribute("custom-styles",`
|
|
1533
1548
|
.form-input-focus {
|
|
1534
1549
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1535
1550
|
outline: 0 !important;
|
|
1536
1551
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
1537
1552
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
1538
1553
|
}
|
|
1539
|
-
`),m.appendChild(p),await new Promise(h=>setTimeout(h,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await p.initializePayment(
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1554
|
+
`),m.appendChild(p),await new Promise(h=>setTimeout(h,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await p.initializePayment(d.sdkToken,W?"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..."),p.addEventListener("submit",(async h=>{console.log("[Recur SDK] Form submitted");let S=h,{paymentSession:J}=S.detail;try{let k=await J.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let C=k.HashTimestamp||k.timestamp,Q={};if(d.checkout.productType==="SUBSCRIPTION"){let E=d.creditToken,y=d.sdkTimestamp;if(!E)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Q={creditToken:E,timestamp:y||C},console.log("[Recur SDK] Using creditToken from checkout:",E.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",y?"from checkout (sdkTimestamp)":"from tradeResult")}let G=await fetch(`${n}/v1/checkouts/${d.checkout.id}/pay`,{method:"POST",headers:o,body:JSON.stringify(Q)});if(!G.ok){let E=await G.json().catch(()=>({}));throw new Error(E.error||"Failed to execute payment")}let Ie=await G.json(),u=g(Ie);if(console.log("[Recur SDK] Payment executed:",u),u.requires3D&&u.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=u.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let y=window.open(u.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!y){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=u.redirectUrl;return}if(await new Promise(R=>setTimeout(R,100)),y.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=u.redirectUrl;return}p.setVerifying?.(!0);let M=d.checkout.id,ee=d.checkout.clientSecret,Te=90,Re=2e3,T=!0,te=!1,re;console.log("[Recur SDK] Starting 3D verification polling...");for(let R=0;R<Te&&T;R++){if(y.closed){console.log("[Recur SDK] Popup was closed");try{let f=await fetch(`${n}/v1/checkouts/${M}/status?client_secret=${encodeURIComponent(ee)}`,{headers:o});if(f.ok){let P=await f.json();if(P.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),T=!1,te=!0,re=P.checkout?.orderId;break}}}catch(f){console.error("[Recur SDK] Final status check failed:",f)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),p.setVerifying?.(!1),p.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let f=await fetch(`${n}/v1/checkouts/${M}/status?client_secret=${encodeURIComponent(ee)}`,{headers:o});if(f.ok){let P=await f.json(),_=P.checkout?.status;if(console.log(`[Recur SDK] Poll ${R+1}: status = ${_}`),_==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),T=!1;try{y.close()}catch{}p.setVerifying?.(!1),e.onPaymentComplete&&(u.subscription?e.onPaymentComplete({id:u.subscription.id,status:"ACTIVE",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:u.subscription.billingPeriod,currentPeriodStart:u.subscription.currentPeriodStart,currentPeriodEnd:u.subscription.currentPeriodEnd}):e.onPaymentComplete({id:P.checkout?.orderId||M,status:"SUCCEEDED",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})),r&&(r.close(),r.remove());return}if(_==="CANCELED"||_==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),T=!1;try{y.close()}catch{}throw p.setVerifying?.(!1),p.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(f){if(f.message==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||f.message==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw f;console.error("[Recur SDK] Poll error:",f)}await new Promise(f=>setTimeout(f,Re))}if(T){console.log("[Recur SDK] 3D verification polling timeout");try{y.close()}catch{}throw p.setVerifying?.(!1),p.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}te&&(console.log("[Recur SDK] Handling success after popup close"),p.setVerifying?.(!1),e.onPaymentComplete&&(u.subscription?e.onPaymentComplete({id:u.subscription.id,status:"ACTIVE",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:u.subscription.billingPeriod,currentPeriodStart:u.subscription.currentPeriodStart,currentPeriodEnd:u.subscription.currentPeriodEnd}):e.onPaymentComplete({id:re||M,status:"SUCCEEDED",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(u.subscription)e.onPaymentComplete({id:u.subscription.id,status:u.subscription.status,productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:u.subscription.billingPeriod,currentPeriodStart:u.subscription.currentPeriodStart,currentPeriodEnd:u.subscription.currentPeriodEnd});else{let E=u.charge?.id||u.paymentIntent?.id,y=u.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:E,status:y,productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),p.resetButton?.(),r&&(r.close(),r.remove())}catch(k){console.error("[Recur SDK] Payment error:",k);let C={code:"PAYMENT_FAILED",message:k instanceof Error?k.message:"Payment failed"};e.onError?.(C),p.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(n){console.error("[Recur SDK] Checkout error:",n),r&&(r.close(),r.remove());let o={code:"CHECKOUT_ERROR",message:n instanceof Error?n.message:"An unknown error occurred"};throw e.onError?.(o),n}}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=`
|
|
1555
|
+
.recur-dialog {
|
|
1556
|
+
border: none;
|
|
1557
|
+
border-radius: 12px;
|
|
1558
|
+
padding: 0;
|
|
1559
|
+
max-width: 500px;
|
|
1560
|
+
width: 90%;
|
|
1561
|
+
max-height: 90vh;
|
|
1562
|
+
overflow: visible;
|
|
1563
|
+
background: transparent;
|
|
1564
|
+
/* Center the dialog */
|
|
1565
|
+
margin: auto;
|
|
1566
|
+
position: fixed;
|
|
1567
|
+
inset: 0;
|
|
1568
|
+
height: fit-content;
|
|
1569
|
+
}
|
|
1570
|
+
.recur-dialog::backdrop {
|
|
1571
|
+
background: rgba(0, 0, 0, 0.5);
|
|
1572
|
+
}
|
|
1573
|
+
.recur-dialog[open] {
|
|
1574
|
+
display: flex;
|
|
1575
|
+
flex-direction: column;
|
|
1576
|
+
}
|
|
1577
|
+
.recur-dialog__content {
|
|
1578
|
+
max-width: 500px;
|
|
1579
|
+
width: 100%;
|
|
1580
|
+
max-height: 90vh;
|
|
1581
|
+
overflow-y: auto;
|
|
1582
|
+
overflow-x: hidden;
|
|
1583
|
+
position: relative;
|
|
1584
|
+
border-radius: 12px;
|
|
1585
|
+
background: white;
|
|
1586
|
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
|
|
1587
|
+
}
|
|
1588
|
+
.recur-dialog__close {
|
|
1589
|
+
position: absolute;
|
|
1590
|
+
top: 12px;
|
|
1591
|
+
right: 12px;
|
|
1592
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1593
|
+
border: none;
|
|
1594
|
+
font-size: 18px;
|
|
1595
|
+
cursor: pointer;
|
|
1596
|
+
color: #666;
|
|
1597
|
+
padding: 0;
|
|
1598
|
+
width: 32px;
|
|
1599
|
+
height: 32px;
|
|
1600
|
+
display: flex;
|
|
1601
|
+
align-items: center;
|
|
1602
|
+
justify-content: center;
|
|
1603
|
+
border-radius: 50%;
|
|
1604
|
+
z-index: 10;
|
|
1605
|
+
transition: background 0.2s;
|
|
1606
|
+
}
|
|
1607
|
+
.recur-dialog__close:hover {
|
|
1608
|
+
background: rgba(0, 0, 0, 0.1);
|
|
1609
|
+
}
|
|
1610
|
+
`,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 i=document.createElement("button");i.className="recur-dialog__close",i.innerHTML="\u2715",i.type="button",i.onclick=()=>{this.closeDialog(),e?.()};let s=document.createElement("div");s.id="recur-dialog-payment-container";let n=document.createElement("recur-payment-form-skeleton");return s.appendChild(n),r.appendChild(i),r.appendChild(s),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("click",o=>{let l=t.getBoundingClientRect();o.clientX>=l.left&&o.clientX<=l.right&&o.clientY>=l.top&&o.clientY<=l.bottom||(this.closeDialog(),e?.())}),t.addEventListener("cancel",o=>{o.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:s}}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 s=await r.json().catch(()=>({}));throw new Error(s.error?.message||s.message||"Failed to create portal session")}let i=await r.json();return{id:i.id,url:i.url||i.portalUrl,expiresAt:i.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function Se(a){return new L(a)}var Oe={init:Se,RecurCheckout:L,RecurElements:I,createElements:Z};return _e(je);})();
|
|
1579
1611
|
if (typeof window !== "undefined") {
|
|
1580
1612
|
window.RecurCheckout = RecurCheckout.default;
|
|
1581
1613
|
window.RecurElements = RecurCheckout.RecurElements;
|