recur-tw 0.9.12 → 0.9.13
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 +174 -68
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +174 -68
- package/dist/recur.umd.js +183 -117
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/recur.umd.js
CHANGED
|
@@ -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 Ne!==void 0?Ne.createHTML(e):e}function
|
|
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 H(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=H(n,o._$AS(n,e.values),o,r)),e}var U,ne,Ne,qe,I,Ve,Et,M,F,q,_e,Ct,be,j,ze,Oe,D,Ke,je,Ye,Ee,p,Ft,qt,V,f,Fe,P,St,Y,ye,W,B,ve,ke,we,xe,Tt,X,Ce=k(()=>{"use strict";U=globalThis,ne=U.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=U.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}),
|
|
386
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ke=/'/g,je=/"/g,Ye=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),p=Ee(1),Ft=Ee(2),qt=Ee(3),V=Symbol.for("lit-noChange"),f=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,h,m=-1,x=0;for(;x<c.length&&(s.lastIndex=x,h=s.exec(c),h!==null);)x=s.lastIndex,s===j?h[1]==="!--"?s=ze:h[1]!==void 0?s=Oe:h[2]!==void 0?(Ye.test(h[2])&&(o=RegExp("</"+h[2],"g")),s=D):h[3]!==void 0&&(s=D):s===D?h[0]===">"?(s=o??j,m=-1):h[1]===void 0?m=-2:(m=s.lastIndex-h[2].length,d=h[1],s=h[3]===void 0?D:h[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:m>=0?(r.push(d),c.slice(0,m)+qe+c.slice(m)+I+u):c+I+(m===-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,h]=St(e,t);if(this.el=n.createElement(d,r),P.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes)}for(;(o=P.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let m of o.getAttributeNames())if(m.endsWith(qe)){let x=h[s++],u=o.getAttribute(m).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:B}),o.removeAttribute(m)}else m.startsWith(I)&&(c.push({type:6,index:i}),o.removeAttribute(m));if(Ye.test(o.tagName)){let m=o.textContent.split(I),x=m.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(m[u],F()),P.nextNode(),c.push({type:2,index:++i});o.append(m[x],F())}}}else if(o.nodeType===8)if(o.data===Ve)c.push({type:2,index:i});else{let m=-1;for(;(m=o.data.indexOf(I,m+1))!==-1;)c.push({type:7,index:i}),m+=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=f,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=H(this,e,t),q(e)?e===f||e==null||e===""?(this._$AH!==f&&this._$AR(),this._$AH=f):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!==f&&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))}},B=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=f,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=f}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=H(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=H(this,a[r+c],t,c),d===V&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===f?e=f:e!==f&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===f?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ve=class extends B{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===f?void 0:e}},ke=class extends B{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==f)}},we=class extends B{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=H(this,e,t,0)??f)===V)return;let r=this._$AH,o=e===f&&r!==f||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==f&&(r===f||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){H(this,e)}},Tt=U.litHtmlPolyfillSupport;Tt?.(Y,W),(U.litHtmlVersions??(U.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
|
*/
|
|
@@ -594,15 +594,15 @@
|
|
|
594
594
|
color: #4a5568;
|
|
595
595
|
margin: 0;
|
|
596
596
|
}
|
|
597
|
-
`});var
|
|
597
|
+
`});var Ge={};C(Ge,{RecurPaymentFormSkeleton:()=>ae});var It,ae,Ze=k(()=>{"use strict";Ce();Xe();It=p`
|
|
598
598
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
599
599
|
<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" />
|
|
600
600
|
</svg>
|
|
601
|
-
`,ae=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}renderHeader(){return
|
|
601
|
+
`,ae=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}renderHeader(){return p`
|
|
602
602
|
<div class="form-header">
|
|
603
603
|
<h2 class="form-title">訂閱付款</h2>
|
|
604
604
|
</div>
|
|
605
|
-
`}renderOrderSummary(){return
|
|
605
|
+
`}renderOrderSummary(){return p`
|
|
606
606
|
<div class="form-section">
|
|
607
607
|
<h3 class="section-title">訂單摘要</h3>
|
|
608
608
|
<div class="order-summary">
|
|
@@ -623,7 +623,7 @@
|
|
|
623
623
|
</div>
|
|
624
624
|
</div>
|
|
625
625
|
</div>
|
|
626
|
-
`}renderCustomerInfo(){return
|
|
626
|
+
`}renderCustomerInfo(){return p`
|
|
627
627
|
<div class="form-section">
|
|
628
628
|
<h3 class="section-title">聯絡資訊</h3>
|
|
629
629
|
<div class="customer-info-display">
|
|
@@ -637,7 +637,7 @@
|
|
|
637
637
|
</div>
|
|
638
638
|
</div>
|
|
639
639
|
</div>
|
|
640
|
-
`}renderCardFields(){return
|
|
640
|
+
`}renderCardFields(){return p`
|
|
641
641
|
<div class="form-section">
|
|
642
642
|
<h3 class="section-title">信用卡資訊</h3>
|
|
643
643
|
<div class="card-field">
|
|
@@ -655,12 +655,12 @@
|
|
|
655
655
|
</div>
|
|
656
656
|
</div>
|
|
657
657
|
</div>
|
|
658
|
-
`}renderSubmitButton(){return
|
|
658
|
+
`}renderSubmitButton(){return p`<div class="skeleton skeleton-button"></div>`}renderSecurityNote(){return p`
|
|
659
659
|
<div class="security-note">
|
|
660
|
-
${
|
|
660
|
+
${It}
|
|
661
661
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
662
662
|
</div>
|
|
663
|
-
`}render(){let e=
|
|
663
|
+
`}render(){let e=p`
|
|
664
664
|
<style>${Je}</style>
|
|
665
665
|
|
|
666
666
|
<div class="payment-form-wrapper">
|
|
@@ -987,10 +987,15 @@
|
|
|
987
987
|
height: 36px;
|
|
988
988
|
}
|
|
989
989
|
|
|
990
|
-
.recur-coupon__input {
|
|
990
|
+
.recur-coupon__input-wrapper {
|
|
991
|
+
position: relative;
|
|
991
992
|
flex: 1;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
.recur-coupon__input {
|
|
996
|
+
width: 100%;
|
|
992
997
|
height: 36px;
|
|
993
|
-
padding: 0 12px;
|
|
998
|
+
padding: 0 32px 0 12px;
|
|
994
999
|
font-size: 14px;
|
|
995
1000
|
text-transform: uppercase;
|
|
996
1001
|
background-color: #ffffff;
|
|
@@ -1015,6 +1020,32 @@
|
|
|
1015
1020
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
|
1016
1021
|
}
|
|
1017
1022
|
|
|
1023
|
+
.recur-coupon__clear {
|
|
1024
|
+
position: absolute;
|
|
1025
|
+
right: 8px;
|
|
1026
|
+
top: 50%;
|
|
1027
|
+
transform: translateY(-50%);
|
|
1028
|
+
background: none;
|
|
1029
|
+
border: none;
|
|
1030
|
+
padding: 4px;
|
|
1031
|
+
cursor: pointer;
|
|
1032
|
+
color: #9ca3af;
|
|
1033
|
+
border-radius: 4px;
|
|
1034
|
+
display: flex;
|
|
1035
|
+
align-items: center;
|
|
1036
|
+
justify-content: center;
|
|
1037
|
+
transition: color 0.2s;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.recur-coupon__clear:hover {
|
|
1041
|
+
color: #6b7280;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
.recur-coupon__clear-icon {
|
|
1045
|
+
width: 16px;
|
|
1046
|
+
height: 16px;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1018
1049
|
.recur-coupon__btn {
|
|
1019
1050
|
height: 36px;
|
|
1020
1051
|
padding: 0 12px;
|
|
@@ -1050,16 +1081,6 @@
|
|
|
1050
1081
|
cursor: not-allowed;
|
|
1051
1082
|
}
|
|
1052
1083
|
|
|
1053
|
-
.recur-coupon__btn--cancel {
|
|
1054
|
-
background: transparent;
|
|
1055
|
-
color: #718096;
|
|
1056
|
-
border: 1px solid #d1d5db;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
.recur-coupon__btn--cancel:hover {
|
|
1060
|
-
background: #f7fafc;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
1084
|
.recur-coupon__error {
|
|
1064
1085
|
width: 100%;
|
|
1065
1086
|
margin-top: 8px;
|
|
@@ -1067,6 +1088,28 @@
|
|
|
1067
1088
|
color: #dc2626;
|
|
1068
1089
|
}
|
|
1069
1090
|
|
|
1091
|
+
.recur-coupon__applied-wrapper {
|
|
1092
|
+
width: 100%;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.recur-coupon__description {
|
|
1096
|
+
font-size: 12px;
|
|
1097
|
+
color: #6b7280;
|
|
1098
|
+
margin: 4px 0 0 22px;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
.recur-coupon__bonus {
|
|
1102
|
+
display: flex;
|
|
1103
|
+
align-items: center;
|
|
1104
|
+
gap: 6px;
|
|
1105
|
+
background: #dcfce7;
|
|
1106
|
+
border-radius: 6px;
|
|
1107
|
+
padding: 8px 12px;
|
|
1108
|
+
margin-top: 8px;
|
|
1109
|
+
font-size: 12px;
|
|
1110
|
+
color: #15803d;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1070
1113
|
.recur-coupon__applied {
|
|
1071
1114
|
display: flex;
|
|
1072
1115
|
align-items: center;
|
|
@@ -1344,23 +1387,27 @@
|
|
|
1344
1387
|
animation: recur-skeleton-loading 1.5s ease-in-out infinite;
|
|
1345
1388
|
border-radius: 4px;
|
|
1346
1389
|
}
|
|
1347
|
-
`});var st={};C(st,{RecurPaymentForm:()=>le});var
|
|
1390
|
+
`});var st={};C(st,{RecurPaymentForm:()=>le});var L,le,nt=k(()=>{"use strict";Ce();tt();ot();L={lock:p`
|
|
1348
1391
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1349
1392
|
<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" />
|
|
1350
1393
|
</svg>
|
|
1351
|
-
`,tag:
|
|
1394
|
+
`,tag:p`
|
|
1352
1395
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1353
1396
|
<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" />
|
|
1354
1397
|
</svg>
|
|
1355
|
-
`,tagApplied:
|
|
1398
|
+
`,tagApplied:p`
|
|
1356
1399
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1357
1400
|
<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" />
|
|
1358
1401
|
</svg>
|
|
1359
|
-
`,close:
|
|
1402
|
+
`,close:p`
|
|
1360
1403
|
<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1361
1404
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
1362
1405
|
</svg>
|
|
1363
|
-
`,
|
|
1406
|
+
`,clearInput:p`
|
|
1407
|
+
<svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1408
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
1409
|
+
</svg>
|
|
1410
|
+
`,spinner:p`<span class="recur-coupon__spinner"></span>`},le=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_showCouponInput",!1);l(this,"_couponCode","");l(this,"_couponLoading",!1);l(this,"_couponError",null);l(this,"_appliedCoupon",null);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","checkout-id","publishable-key","api-base-url"]}attributeChangedCallback(t,r,o){r!==o&&(t==="custom-styles"?(this.customStyles=o||"",this.updateCustomStyles()):this.updateOrderSummaryDOM())}getShadowDOMStyles(){return rt}getLightDOMStyles(){return it}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=p`
|
|
1364
1411
|
<style>${this.getShadowDOMStyles()}</style>
|
|
1365
1412
|
|
|
1366
1413
|
<div class="payment-form-wrapper">
|
|
@@ -1386,11 +1433,11 @@
|
|
|
1386
1433
|
<slot name="actions"></slot>
|
|
1387
1434
|
|
|
1388
1435
|
<div class="security-note">
|
|
1389
|
-
${
|
|
1436
|
+
${L.lock}
|
|
1390
1437
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
1391
1438
|
</div>
|
|
1392
1439
|
</div>
|
|
1393
|
-
`;X(t,this.shadowRoot)}renderLightDOM(){let t=
|
|
1440
|
+
`;X(t,this.shadowRoot)}renderLightDOM(){let t=p`
|
|
1394
1441
|
<style id="${this.containerId}-styles">
|
|
1395
1442
|
${this.getLightDOMStyles()}
|
|
1396
1443
|
${this.getCustomStyles()}
|
|
@@ -1419,7 +1466,7 @@
|
|
|
1419
1466
|
height: 36px !important;
|
|
1420
1467
|
}
|
|
1421
1468
|
${this.customStyles}
|
|
1422
|
-
`}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)return
|
|
1469
|
+
`}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)return p`
|
|
1423
1470
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1424
1471
|
<div class="recur-order-summary__row">
|
|
1425
1472
|
<span class="recur-order-summary__label">方案</span>
|
|
@@ -1437,11 +1484,11 @@
|
|
|
1437
1484
|
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1438
1485
|
</div>
|
|
1439
1486
|
</div>
|
|
1440
|
-
`;let s=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,d=a-c,
|
|
1487
|
+
`;let s=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,d=a-c,h=s?`${t} / \u6BCF${s}`:t;return p`
|
|
1441
1488
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1442
1489
|
<div class="recur-order-summary__row">
|
|
1443
1490
|
<span class="recur-order-summary__label">方案</span>
|
|
1444
|
-
<span class="recur-order-summary__value">${
|
|
1491
|
+
<span class="recur-order-summary__value">${h}</span>
|
|
1445
1492
|
</div>
|
|
1446
1493
|
|
|
1447
1494
|
<!-- 小計 (Subtotal) - always show -->
|
|
@@ -1461,90 +1508,112 @@
|
|
|
1461
1508
|
<span class="recur-order-summary__total">NT$ ${d.toLocaleString()}</span>
|
|
1462
1509
|
</div>
|
|
1463
1510
|
</div>
|
|
1464
|
-
`}
|
|
1465
|
-
<div class="recur-coupon__applied">
|
|
1466
|
-
<div class="recur-coupon__applied
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1511
|
+
`}getIntervalText(t,r){if(!t)return"";let o=r&&r>1?r.toString():"";switch(t.toUpperCase()){case"MONTH":return`${o}\u6708`;case"YEAR":return`${o}\u5E74`;case"WEEK":return`${o}\u9031`;case"DAY":return`${o}\u5929`;default:return""}}getDiscountDescription(){if(!this._appliedCoupon)return null;let{discountType:t,duration:r,durationMonths:o,productPrice:i,productInterval:s,productIntervalCount:a}=this._appliedCoupon,c=this.getIntervalText(s,a),d=i&&c?`NT$ ${i.toLocaleString()}/${c}`:i?`NT$ ${i.toLocaleString()}`:"",m=parseInt(this.getAttribute("amount")||"0",10)-this._appliedCoupon.discountAmount;if(t==="FIRST_PERIOD_PRICE")return d?`\u9996\u671F\u53EA\u9700 NT$ ${m.toLocaleString()}\uFF0C\u4E4B\u5F8C ${d}`:`\u9996\u671F\u53EA\u9700 NT$ ${m.toLocaleString()}`;if(r)switch(r){case"ONCE":return d?`\u9996\u671F\u6298\u6263\uFF0C\u4E4B\u5F8C ${d}`:"\u50C5\u9650\u9996\u671F";case"REPEATING":return o?`\u524D ${o} \u671F\u4EAB\u512A\u60E0\uFF0C\u4E4B\u5F8C\u6062\u5FA9\u539F\u50F9`:null;case"FOREVER":return"\u7D42\u8EAB\u512A\u60E0";default:return null}return null}getBonusDescription(){if(!this._appliedCoupon)return null;let t=[];return this._appliedCoupon.bonusTrialDays&&t.push(`\u5EF6\u9577\u8A66\u7528 ${this._appliedCoupon.bonusTrialDays} \u5929`),this._appliedCoupon.bonusMonths&&t.push(`\u52A0\u9001 ${this._appliedCoupon.bonusMonths} \u500B\u6708`),t.length>0?t.join("\u3001"):null}renderCoupon(){if(this._appliedCoupon){let t=this.getDiscountDescription(),r=this.getBonusDescription();return p`
|
|
1512
|
+
<div class="recur-coupon__applied-wrapper">
|
|
1513
|
+
<div class="recur-coupon__applied">
|
|
1514
|
+
<div class="recur-coupon__applied-info">
|
|
1515
|
+
${L.tagApplied}
|
|
1516
|
+
${this._appliedCoupon.couponName?p`
|
|
1517
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
|
|
1518
|
+
<span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
|
|
1519
|
+
`:p`
|
|
1520
|
+
<span class="recur-coupon__applied-name">${this._appliedCoupon.code}</span>
|
|
1521
|
+
`}
|
|
1522
|
+
<button
|
|
1523
|
+
type="button"
|
|
1524
|
+
class="recur-coupon__remove"
|
|
1525
|
+
?disabled=${this._couponLoading}
|
|
1526
|
+
@click=${()=>this.removeCoupon()}
|
|
1527
|
+
>
|
|
1528
|
+
${this._couponLoading?L.spinner:L.close}
|
|
1529
|
+
</button>
|
|
1530
|
+
</div>
|
|
1531
|
+
<span class="recur-coupon__applied-amount">
|
|
1532
|
+
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1533
|
+
</span>
|
|
1482
1534
|
</div>
|
|
1483
|
-
|
|
1484
|
-
-
|
|
1485
|
-
|
|
1535
|
+
${t?p`
|
|
1536
|
+
<p class="recur-coupon__description">${t}</p>
|
|
1537
|
+
`:f}
|
|
1538
|
+
${r?p`
|
|
1539
|
+
<div class="recur-coupon__bonus">
|
|
1540
|
+
<span>✨</span>
|
|
1541
|
+
<span>${r}</span>
|
|
1542
|
+
</div>
|
|
1543
|
+
`:f}
|
|
1486
1544
|
</div>
|
|
1487
|
-
|
|
1545
|
+
`}return this._showCouponInput?p`
|
|
1488
1546
|
<div style="width: 100%;">
|
|
1489
1547
|
<div class="recur-coupon__input-row">
|
|
1490
|
-
<
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1548
|
+
<div class="recur-coupon__input-wrapper">
|
|
1549
|
+
<input
|
|
1550
|
+
type="text"
|
|
1551
|
+
class="recur-coupon__input"
|
|
1552
|
+
id="${this.containerId}-coupon-input"
|
|
1553
|
+
placeholder="輸入優惠碼"
|
|
1554
|
+
.value=${this._couponCode}
|
|
1555
|
+
?disabled=${this._couponLoading}
|
|
1556
|
+
@input=${t=>this.handleCouponInputChange(t)}
|
|
1557
|
+
@keydown=${t=>this.handleCouponKeydown(t)}
|
|
1558
|
+
/>
|
|
1559
|
+
${this._couponCode&&!this._couponLoading?p`
|
|
1560
|
+
<button
|
|
1561
|
+
type="button"
|
|
1562
|
+
class="recur-coupon__clear"
|
|
1563
|
+
@click=${()=>this.clearCouponInput()}
|
|
1564
|
+
aria-label="清除"
|
|
1565
|
+
>
|
|
1566
|
+
${L.clearInput}
|
|
1567
|
+
</button>
|
|
1568
|
+
`:f}
|
|
1569
|
+
</div>
|
|
1500
1570
|
<button
|
|
1501
1571
|
type="button"
|
|
1502
1572
|
class="recur-coupon__btn recur-coupon__btn--apply"
|
|
1503
1573
|
?disabled=${this._couponLoading||!this._couponCode.trim()}
|
|
1504
1574
|
@click=${()=>this.applyCoupon()}
|
|
1505
1575
|
>
|
|
1506
|
-
${this._couponLoading?
|
|
1507
|
-
</button>
|
|
1508
|
-
<button
|
|
1509
|
-
type="button"
|
|
1510
|
-
class="recur-coupon__btn recur-coupon__btn--cancel"
|
|
1511
|
-
?disabled=${this._couponLoading}
|
|
1512
|
-
@click=${()=>this.cancelCouponInput()}
|
|
1513
|
-
>
|
|
1514
|
-
取消
|
|
1576
|
+
${this._couponLoading?L.spinner:"\u5957\u7528"}
|
|
1515
1577
|
</button>
|
|
1516
1578
|
</div>
|
|
1517
|
-
${this._couponError?
|
|
1579
|
+
${this._couponError?p`
|
|
1518
1580
|
<div class="recur-coupon__error">${this._couponError}</div>
|
|
1519
|
-
`:
|
|
1581
|
+
`:f}
|
|
1520
1582
|
</div>
|
|
1521
|
-
`:
|
|
1583
|
+
`:p`
|
|
1522
1584
|
<button
|
|
1523
1585
|
type="button"
|
|
1524
1586
|
class="recur-coupon__trigger"
|
|
1525
1587
|
@click=${()=>this.showCouponInput()}
|
|
1526
1588
|
>
|
|
1527
|
-
${
|
|
1589
|
+
${L.tag}
|
|
1528
1590
|
有優惠碼?
|
|
1529
1591
|
</button>
|
|
1530
|
-
`}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`
|
|
1592
|
+
`}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()}clearCouponInput(){this._couponCode="",this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}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`
|
|
1531
1593
|
<button type="button" class="recur-coupon__trigger">
|
|
1532
1594
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1533
1595
|
<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" />
|
|
1534
1596
|
</svg>
|
|
1535
1597
|
\u6709\u512A\u60E0\u78BC\uFF1F
|
|
1536
1598
|
</button>
|
|
1537
|
-
`}getCouponInputHTML(){let t=this._couponError?`<div class="recur-coupon__error">${this._couponError}</div>`:""
|
|
1599
|
+
`}getCouponInputHTML(){let t=this._couponError?`<div class="recur-coupon__error">${this._couponError}</div>`:"",r=this._couponCode&&!this._couponLoading?`<button type="button" class="recur-coupon__clear" aria-label="\u6E05\u9664">
|
|
1600
|
+
<svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1601
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
1602
|
+
</svg>
|
|
1603
|
+
</button>`:"";return`
|
|
1538
1604
|
<div style="width: 100%;">
|
|
1539
1605
|
<div class="recur-coupon__input-row">
|
|
1540
|
-
<
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1606
|
+
<div class="recur-coupon__input-wrapper">
|
|
1607
|
+
<input
|
|
1608
|
+
type="text"
|
|
1609
|
+
class="recur-coupon__input"
|
|
1610
|
+
id="${this.containerId}-coupon-input"
|
|
1611
|
+
placeholder="\u8F38\u5165\u512A\u60E0\u78BC"
|
|
1612
|
+
value="${this._couponCode}"
|
|
1613
|
+
${this._couponLoading?"disabled":""}
|
|
1614
|
+
/>
|
|
1615
|
+
${r}
|
|
1616
|
+
</div>
|
|
1548
1617
|
<button
|
|
1549
1618
|
type="button"
|
|
1550
1619
|
class="recur-coupon__btn recur-coupon__btn--apply"
|
|
@@ -1552,43 +1621,40 @@
|
|
|
1552
1621
|
>
|
|
1553
1622
|
${this._couponLoading?'<span class="recur-coupon__spinner"></span>':"\u5957\u7528"}
|
|
1554
1623
|
</button>
|
|
1555
|
-
<button
|
|
1556
|
-
type="button"
|
|
1557
|
-
class="recur-coupon__btn recur-coupon__btn--cancel"
|
|
1558
|
-
${this._couponLoading?"disabled":""}
|
|
1559
|
-
>
|
|
1560
|
-
\u53D6\u6D88
|
|
1561
|
-
</button>
|
|
1562
1624
|
</div>
|
|
1563
1625
|
${t}
|
|
1564
1626
|
</div>
|
|
1565
|
-
`}getCouponAppliedHTML(){let t=this._appliedCoupon;return`
|
|
1566
|
-
<div class="recur-coupon__applied">
|
|
1567
|
-
<div class="recur-coupon__applied
|
|
1568
|
-
<
|
|
1569
|
-
<
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1627
|
+
`}getCouponAppliedHTML(){let t=this._appliedCoupon,r=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>`,o=this.getDiscountDescription(),i=this.getBonusDescription(),s=o?`<p class="recur-coupon__description">${o}</p>`:"",a=i?`<div class="recur-coupon__bonus"><span>\u2728</span><span>${i}</span></div>`:"";return`
|
|
1628
|
+
<div class="recur-coupon__applied-wrapper">
|
|
1629
|
+
<div class="recur-coupon__applied">
|
|
1630
|
+
<div class="recur-coupon__applied-info">
|
|
1631
|
+
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1632
|
+
<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" />
|
|
1633
|
+
</svg>
|
|
1634
|
+
${r}
|
|
1635
|
+
<button type="button" class="recur-coupon__remove" ${this._couponLoading?"disabled":""}>
|
|
1636
|
+
${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
|
+
</button>
|
|
1638
|
+
</div>
|
|
1639
|
+
<span class="recur-coupon__applied-amount">-NT$ ${t.discountAmount.toLocaleString()}</span>
|
|
1575
1640
|
</div>
|
|
1576
|
-
|
|
1641
|
+
${s}
|
|
1642
|
+
${a}
|
|
1577
1643
|
</div>
|
|
1578
|
-
`}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-
|
|
1644
|
+
`}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__clear");r?.addEventListener("input",s=>this.handleCouponInputChange(s)),r?.addEventListener("keydown",s=>this.handleCouponKeydown(s)),o?.addEventListener("click",()=>this.applyCoupon()),i?.addEventListener("click",()=>this.clearCouponInput())}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,productInterval:s.discount.productInterval,productIntervalCount:s.discount.productIntervalCount,productPrice:s.discount.productPrice},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?p`
|
|
1579
1645
|
<div class="recur-info-display">
|
|
1580
|
-
${t?
|
|
1646
|
+
${t?p`
|
|
1581
1647
|
<div class="recur-info-row">
|
|
1582
1648
|
<span class="recur-info-label">姓名</span>
|
|
1583
1649
|
<span class="recur-info-value">${t}</span>
|
|
1584
1650
|
</div>
|
|
1585
|
-
`:
|
|
1651
|
+
`:f}
|
|
1586
1652
|
<div class="recur-info-row">
|
|
1587
1653
|
<span class="recur-info-label">電子郵件</span>
|
|
1588
1654
|
<span class="recur-info-value">${r}</span>
|
|
1589
1655
|
</div>
|
|
1590
1656
|
</div>
|
|
1591
|
-
`:
|
|
1657
|
+
`:p`
|
|
1592
1658
|
<div class="recur-form-group">
|
|
1593
1659
|
<label class="recur-form-label" for="${this.containerId}-email">Email</label>
|
|
1594
1660
|
<input
|
|
@@ -1611,7 +1677,7 @@
|
|
|
1611
1677
|
required
|
|
1612
1678
|
/>
|
|
1613
1679
|
</div>
|
|
1614
|
-
`}renderCardFields(){return
|
|
1680
|
+
`}renderCardFields(){return p`
|
|
1615
1681
|
<div class="recur-card-field">
|
|
1616
1682
|
<label class="recur-card-field-label">卡號</label>
|
|
1617
1683
|
<div class="recur-card-field-container" id="${this.containerId}-card-no-wrapper">
|
|
@@ -1637,7 +1703,7 @@
|
|
|
1637
1703
|
</div>
|
|
1638
1704
|
</div>
|
|
1639
1705
|
</div>
|
|
1640
|
-
`}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let o=document.getElementById(r);o&&o.classList.add("hidden")})}renderActions(){return
|
|
1706
|
+
`}hideCardSkeletons(){[`${this.containerId}-card-no-skeleton`,`${this.containerId}-card-exp-skeleton`,`${this.containerId}-card-cvc-skeleton`].forEach(r=>{let o=document.getElementById(r);o&&o.classList.add("hidden")})}renderActions(){return p`
|
|
1641
1707
|
<button
|
|
1642
1708
|
type="submit"
|
|
1643
1709
|
id="${this.containerId}-submit-btn"
|
|
@@ -1646,7 +1712,7 @@
|
|
|
1646
1712
|
>
|
|
1647
1713
|
<span id="${this.containerId}-submit-text">確認付款</span>
|
|
1648
1714
|
</button>
|
|
1649
|
-
`}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 o=document.getElementById(`${this.containerId}-card-no`),i=document.getElementById(`${this.containerId}-card-exp`),s=document.getElementById(`${this.containerId}-card-cvc`);if(!o||!i||!s)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 a=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 a.start()}catch(c){if((c?.message?.includes("1008")||c?.message?.includes("timeout")||c?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),a.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let d=c.status&&c.status.CardNo===!0&&c.status.CardExp===!0&&c.status.CardCvc===!0,
|
|
1715
|
+
`}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 o=document.getElementById(`${this.containerId}-card-no`),i=document.getElementById(`${this.containerId}-card-exp`),s=document.getElementById(`${this.containerId}-card-cvc`);if(!o||!i||!s)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 a=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 a.start()}catch(c){if((c?.message?.includes("1008")||c?.message?.includes("timeout")||c?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),a.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let d=c.status&&c.status.CardNo===!0&&c.status.CardExp===!0&&c.status.CardCvc===!0,h=document.getElementById(`${this.containerId}-submit-btn`);h&&(h.disabled=!d,console.log("[PaymentForm] Submit button disabled:",!d))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=a,this.setupFormSubmission(),this._isInitializing=!1,a))}catch(o){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",o),o}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let o,i,s=document.getElementById(`${this.containerId}-email`),a=document.getElementById(`${this.containerId}-name`);if(s&&a){if(o=s.value,i=a.value,!o||!i){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(o=this.getAttribute("customer-email")||void 0,i=this.getAttribute("customer-name")||void 0,!o||!i){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:o,customerName:i,paymentSession:this._paymentSession,appliedCoupon:this._appliedCoupon},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=`
|
|
1650
1716
|
<span class="recur-loading-spinner"></span>
|
|
1651
1717
|
<span>\u8655\u7406\u4E2D...</span>
|
|
1652
1718
|
`):(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=`
|
|
@@ -1878,7 +1944,7 @@
|
|
|
1878
1944
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1879
1945
|
<circle cx="12" cy="7" r="4"/>
|
|
1880
1946
|
</svg>
|
|
1881
|
-
`}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:()=>
|
|
1947
|
+
`}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:()=>Z,RecurElements:()=>N,createElements:()=>Se,default:()=>Nt,init:()=>mt});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(()=>(Ze(),Ge)),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.13",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 he=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=`
|
|
1882
1948
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1883
1949
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1884
1950
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -1948,21 +2014,21 @@
|
|
|
1948
2014
|
</p>
|
|
1949
2015
|
</form>
|
|
1950
2016
|
</div>
|
|
1951
|
-
`}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
|
|
2017
|
+
`}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 h=await s.json().catch(()=>({}));throw new Error(h.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=`
|
|
1952
2018
|
width: 100%;
|
|
1953
2019
|
border: none;
|
|
1954
2020
|
min-height: 200px;
|
|
1955
2021
|
display: block;
|
|
1956
2022
|
user-select: none;
|
|
1957
2023
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1958
|
-
`.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,me=!1,
|
|
2024
|
+
`.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,me=!1,G=null;async function ht(n=!1){return pt&&window.UniPayment?Promise.resolve():(me&&G||(me=!0,G=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Bt:Ht,r.async=!0,r.onload=()=>{pt=!0,me=!1,e()},r.onerror=()=>{me=!1,G=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),G)}var Z=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 he(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 h={customerName:e.customerName,customerEmail:e.customerEmail};o&&(h.productId=o),i&&(h.productSlug=i),e.externalCustomerId&&(h.externalCustomerId=e.externalCustomerId),e.successUrl&&(h.successUrl=e.successUrl),e.cancelUrl&&(h.cancelUrl=e.cancelUrl);let m=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(h)});if(!m.ok){let y=await m.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 m.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 ht(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 b=document.createElement("recur-payment-form");if(b.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&b.setAttribute("checkout-id",u.checkout.id),b.setAttribute("api-base-url",s),e.customerName&&b.setAttribute("customer-name",e.customerName),e.customerEmail&&b.setAttribute("customer-email",e.customerEmail),u.product?.name&&b.setAttribute("product-name",u.product.name),u.checkout?.amount&&b.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&b.setAttribute("interval",u.product.interval),b.setAttribute("custom-styles",`
|
|
1959
2025
|
.form-input-focus {
|
|
1960
2026
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1961
2027
|
outline: 0 !important;
|
|
1962
2028
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
1963
2029
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
1964
2030
|
}
|
|
1965
|
-
`),d.appendChild(
|
|
2031
|
+
`),d.appendChild(b),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await b.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..."),b.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}b.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"),b.setVerifying?.(!1),b.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{}b.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 b.setVerifying?.(!1),b.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 b.setVerifying?.(!1),b.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}Ie&&(console.log("[Recur SDK] Handling success after popup close"),b.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!"),b.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),b.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=`
|
|
1966
2032
|
.recur-dialog {
|
|
1967
2033
|
border: none;
|
|
1968
2034
|
border-radius: 12px;
|
|
@@ -2018,7 +2084,7 @@
|
|
|
2018
2084
|
.recur-dialog__close:hover {
|
|
2019
2085
|
background: rgba(0, 0, 0, 0.1);
|
|
2020
2086
|
}
|
|
2021
|
-
`,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 mt(n){return new
|
|
2087
|
+
`,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 mt(n){return new Z(n)}var Nt={init:mt,RecurCheckout:Z,RecurElements:N,createElements:Se};return _t(zt);})();
|
|
2022
2088
|
/*! Bundled license information:
|
|
2023
2089
|
|
|
2024
2090
|
lit-html/node/lit-html.js:
|