recur-tw 0.9.11 → 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 +182 -91
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +182 -91
- package/dist/recur.umd.js +204 -142
- 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,24 +594,24 @@
|
|
|
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">
|
|
609
609
|
<div class="order-row">
|
|
610
|
-
<span class="order-label"
|
|
611
|
-
<div class="skeleton skeleton-order-value"></div>
|
|
610
|
+
<span class="order-label">方案</span>
|
|
611
|
+
<div class="skeleton skeleton-order-value" style="width: 120px;"></div>
|
|
612
612
|
</div>
|
|
613
613
|
<div class="order-row">
|
|
614
|
-
<span class="order-label"
|
|
614
|
+
<span class="order-label">小計</span>
|
|
615
615
|
<div class="skeleton skeleton-order-value"></div>
|
|
616
616
|
</div>
|
|
617
617
|
<div class="coupon-section">
|
|
@@ -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,12 +987,18 @@
|
|
|
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;
|
|
1001
|
+
background-color: #ffffff;
|
|
996
1002
|
border: 1px solid #d1d5db;
|
|
997
1003
|
border-radius: 6px;
|
|
998
1004
|
outline: none;
|
|
@@ -1003,9 +1009,41 @@
|
|
|
1003
1009
|
text-transform: none;
|
|
1004
1010
|
}
|
|
1005
1011
|
|
|
1012
|
+
.recur-coupon__input:hover:not(:focus) {
|
|
1013
|
+
border-color: #9ca3af;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1006
1016
|
.recur-coupon__input:focus {
|
|
1007
|
-
border-color:
|
|
1008
|
-
|
|
1017
|
+
border-color: var(--ring, hsl(215 16% 47%));
|
|
1018
|
+
outline: 0;
|
|
1019
|
+
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);
|
|
1020
|
+
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
|
1021
|
+
}
|
|
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;
|
|
1009
1047
|
}
|
|
1010
1048
|
|
|
1011
1049
|
.recur-coupon__btn {
|
|
@@ -1043,16 +1081,6 @@
|
|
|
1043
1081
|
cursor: not-allowed;
|
|
1044
1082
|
}
|
|
1045
1083
|
|
|
1046
|
-
.recur-coupon__btn--cancel {
|
|
1047
|
-
background: transparent;
|
|
1048
|
-
color: #718096;
|
|
1049
|
-
border: 1px solid #d1d5db;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
.recur-coupon__btn--cancel:hover {
|
|
1053
|
-
background: #f7fafc;
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
1084
|
.recur-coupon__error {
|
|
1057
1085
|
width: 100%;
|
|
1058
1086
|
margin-top: 8px;
|
|
@@ -1060,6 +1088,28 @@
|
|
|
1060
1088
|
color: #dc2626;
|
|
1061
1089
|
}
|
|
1062
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
|
+
|
|
1063
1113
|
.recur-coupon__applied {
|
|
1064
1114
|
display: flex;
|
|
1065
1115
|
align-items: center;
|
|
@@ -1201,8 +1251,9 @@
|
|
|
1201
1251
|
|
|
1202
1252
|
.recur-form-input {
|
|
1203
1253
|
width: 100%;
|
|
1204
|
-
|
|
1205
|
-
|
|
1254
|
+
height: 36px;
|
|
1255
|
+
padding: 0 12px;
|
|
1256
|
+
font-size: 14px;
|
|
1206
1257
|
border: 1px solid #d1d5db;
|
|
1207
1258
|
border-radius: 6px;
|
|
1208
1259
|
transition: border-color 0.2s;
|
|
@@ -1210,9 +1261,10 @@
|
|
|
1210
1261
|
}
|
|
1211
1262
|
|
|
1212
1263
|
.recur-form-input:focus {
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
box-shadow: 0 0 0 3px
|
|
1264
|
+
border-color: var(--ring, hsl(215 16% 47%));
|
|
1265
|
+
outline: 0;
|
|
1266
|
+
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent);
|
|
1267
|
+
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
|
1216
1268
|
}
|
|
1217
1269
|
|
|
1218
1270
|
.recur-form-input:hover:not(:focus) {
|
|
@@ -1335,23 +1387,27 @@
|
|
|
1335
1387
|
animation: recur-skeleton-loading 1.5s ease-in-out infinite;
|
|
1336
1388
|
border-radius: 4px;
|
|
1337
1389
|
}
|
|
1338
|
-
`});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`
|
|
1339
1391
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1340
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" />
|
|
1341
1393
|
</svg>
|
|
1342
|
-
`,tag:
|
|
1394
|
+
`,tag:p`
|
|
1343
1395
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1344
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" />
|
|
1345
1397
|
</svg>
|
|
1346
|
-
`,tagApplied:
|
|
1398
|
+
`,tagApplied:p`
|
|
1347
1399
|
<svg class="recur-coupon__applied-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1348
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" />
|
|
1349
1401
|
</svg>
|
|
1350
|
-
`,close:
|
|
1402
|
+
`,close:p`
|
|
1351
1403
|
<svg class="recur-coupon__remove-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1352
1404
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
1353
1405
|
</svg>
|
|
1354
|
-
`,
|
|
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`
|
|
1355
1411
|
<style>${this.getShadowDOMStyles()}</style>
|
|
1356
1412
|
|
|
1357
1413
|
<div class="payment-form-wrapper">
|
|
@@ -1377,11 +1433,11 @@
|
|
|
1377
1433
|
<slot name="actions"></slot>
|
|
1378
1434
|
|
|
1379
1435
|
<div class="security-note">
|
|
1380
|
-
${
|
|
1436
|
+
${L.lock}
|
|
1381
1437
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
1382
1438
|
</div>
|
|
1383
1439
|
</div>
|
|
1384
|
-
`;X(t,this.shadowRoot)}renderLightDOM(){let t=
|
|
1440
|
+
`;X(t,this.shadowRoot)}renderLightDOM(){let t=p`
|
|
1385
1441
|
<style id="${this.containerId}-styles">
|
|
1386
1442
|
${this.getLightDOMStyles()}
|
|
1387
1443
|
${this.getCustomStyles()}
|
|
@@ -1410,18 +1466,12 @@
|
|
|
1410
1466
|
height: 36px !important;
|
|
1411
1467
|
}
|
|
1412
1468
|
${this.customStyles}
|
|
1413
|
-
`}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r)
|
|
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`
|
|
1414
1470
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1415
1471
|
<div class="recur-order-summary__row">
|
|
1416
|
-
<span class="recur-order-summary__label"
|
|
1417
|
-
<span class="recur-order-summary__value recur-skeleton" style="width:
|
|
1472
|
+
<span class="recur-order-summary__label">方案</span>
|
|
1473
|
+
<span class="recur-order-summary__value recur-skeleton" style="width: 120px; height: 20px;"></span>
|
|
1418
1474
|
</div>
|
|
1419
|
-
${h?m`
|
|
1420
|
-
<div class="recur-order-summary__row">
|
|
1421
|
-
<span class="recur-order-summary__label">計費週期</span>
|
|
1422
|
-
<span class="recur-order-summary__value recur-skeleton" style="width: 40px; height: 20px;"></span>
|
|
1423
|
-
</div>
|
|
1424
|
-
`:b}
|
|
1425
1475
|
<div class="recur-order-summary__row">
|
|
1426
1476
|
<span class="recur-order-summary__label">小計</span>
|
|
1427
1477
|
<span class="recur-order-summary__value recur-skeleton" style="width: 80px; height: 20px;"></span>
|
|
@@ -1434,20 +1484,13 @@
|
|
|
1434
1484
|
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1435
1485
|
</div>
|
|
1436
1486
|
</div>
|
|
1437
|
-
|
|
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`
|
|
1438
1488
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1439
1489
|
<div class="recur-order-summary__row">
|
|
1440
|
-
<span class="recur-order-summary__label"
|
|
1441
|
-
<span class="recur-order-summary__value">${
|
|
1490
|
+
<span class="recur-order-summary__label">方案</span>
|
|
1491
|
+
<span class="recur-order-summary__value">${h}</span>
|
|
1442
1492
|
</div>
|
|
1443
1493
|
|
|
1444
|
-
${p?m`
|
|
1445
|
-
<div class="recur-order-summary__row">
|
|
1446
|
-
<span class="recur-order-summary__label">計費週期</span>
|
|
1447
|
-
<span class="recur-order-summary__value">每${s}</span>
|
|
1448
|
-
</div>
|
|
1449
|
-
`:b}
|
|
1450
|
-
|
|
1451
1494
|
<!-- 小計 (Subtotal) - always show -->
|
|
1452
1495
|
<div class="recur-order-summary__row">
|
|
1453
1496
|
<span class="recur-order-summary__label">小計</span>
|
|
@@ -1465,90 +1508,112 @@
|
|
|
1465
1508
|
<span class="recur-order-summary__total">NT$ ${d.toLocaleString()}</span>
|
|
1466
1509
|
</div>
|
|
1467
1510
|
</div>
|
|
1468
|
-
`}
|
|
1469
|
-
<div class="recur-coupon__applied">
|
|
1470
|
-
<div class="recur-coupon__applied
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
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>
|
|
1486
1534
|
</div>
|
|
1487
|
-
|
|
1488
|
-
-
|
|
1489
|
-
|
|
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}
|
|
1490
1544
|
</div>
|
|
1491
|
-
|
|
1545
|
+
`}return this._showCouponInput?p`
|
|
1492
1546
|
<div style="width: 100%;">
|
|
1493
1547
|
<div class="recur-coupon__input-row">
|
|
1494
|
-
<
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
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>
|
|
1504
1570
|
<button
|
|
1505
1571
|
type="button"
|
|
1506
1572
|
class="recur-coupon__btn recur-coupon__btn--apply"
|
|
1507
1573
|
?disabled=${this._couponLoading||!this._couponCode.trim()}
|
|
1508
1574
|
@click=${()=>this.applyCoupon()}
|
|
1509
1575
|
>
|
|
1510
|
-
${this._couponLoading?
|
|
1511
|
-
</button>
|
|
1512
|
-
<button
|
|
1513
|
-
type="button"
|
|
1514
|
-
class="recur-coupon__btn recur-coupon__btn--cancel"
|
|
1515
|
-
?disabled=${this._couponLoading}
|
|
1516
|
-
@click=${()=>this.cancelCouponInput()}
|
|
1517
|
-
>
|
|
1518
|
-
取消
|
|
1576
|
+
${this._couponLoading?L.spinner:"\u5957\u7528"}
|
|
1519
1577
|
</button>
|
|
1520
1578
|
</div>
|
|
1521
|
-
${this._couponError?
|
|
1579
|
+
${this._couponError?p`
|
|
1522
1580
|
<div class="recur-coupon__error">${this._couponError}</div>
|
|
1523
|
-
`:
|
|
1581
|
+
`:f}
|
|
1524
1582
|
</div>
|
|
1525
|
-
`:
|
|
1583
|
+
`:p`
|
|
1526
1584
|
<button
|
|
1527
1585
|
type="button"
|
|
1528
1586
|
class="recur-coupon__trigger"
|
|
1529
1587
|
@click=${()=>this.showCouponInput()}
|
|
1530
1588
|
>
|
|
1531
|
-
${
|
|
1589
|
+
${L.tag}
|
|
1532
1590
|
有優惠碼?
|
|
1533
1591
|
</button>
|
|
1534
|
-
`}showCouponInput(){this._showCouponInput=!0,this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}cancelCouponInput(){this._showCouponInput=!1,this._couponCode="",this._couponError=null,this.updateCouponSectionDOM()}handleCouponInputChange(t){this._couponCode=t.target.value.toUpperCase(),this._couponError=null,this.updateApplyButtonState()}handleCouponKeydown(t){t.key==="Enter"?(t.preventDefault(),this.applyCoupon()):t.key==="Escape"&&this.cancelCouponInput()}updateApplyButtonState(){let t=this.querySelector(".recur-coupon__btn--apply");t&&(t.disabled=this._couponLoading||!this._couponCode.trim())}updateCouponSectionDOM(){let t=`${this.containerId}-coupon`,r=document.getElementById(t);r&&(this._appliedCoupon?(r.innerHTML=this.getCouponAppliedHTML(),this.bindCouponAppliedEvents(r)):this._showCouponInput?(r.innerHTML=this.getCouponInputHTML(),this.bindCouponInputEvents(r)):(r.innerHTML=this.getCouponTriggerHTML(),this.bindCouponTriggerEvents(r)))}getCouponTriggerHTML(){return`
|
|
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`
|
|
1535
1593
|
<button type="button" class="recur-coupon__trigger">
|
|
1536
1594
|
<svg class="recur-coupon__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1537
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" />
|
|
1538
1596
|
</svg>
|
|
1539
1597
|
\u6709\u512A\u60E0\u78BC\uFF1F
|
|
1540
1598
|
</button>
|
|
1541
|
-
`}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`
|
|
1542
1604
|
<div style="width: 100%;">
|
|
1543
1605
|
<div class="recur-coupon__input-row">
|
|
1544
|
-
<
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
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>
|
|
1552
1617
|
<button
|
|
1553
1618
|
type="button"
|
|
1554
1619
|
class="recur-coupon__btn recur-coupon__btn--apply"
|
|
@@ -1556,43 +1621,40 @@
|
|
|
1556
1621
|
>
|
|
1557
1622
|
${this._couponLoading?'<span class="recur-coupon__spinner"></span>':"\u5957\u7528"}
|
|
1558
1623
|
</button>
|
|
1559
|
-
<button
|
|
1560
|
-
type="button"
|
|
1561
|
-
class="recur-coupon__btn recur-coupon__btn--cancel"
|
|
1562
|
-
${this._couponLoading?"disabled":""}
|
|
1563
|
-
>
|
|
1564
|
-
\u53D6\u6D88
|
|
1565
|
-
</button>
|
|
1566
1624
|
</div>
|
|
1567
1625
|
${t}
|
|
1568
1626
|
</div>
|
|
1569
|
-
`}getCouponAppliedHTML(){let t=this._appliedCoupon;return`
|
|
1570
|
-
<div class="recur-coupon__applied">
|
|
1571
|
-
<div class="recur-coupon__applied
|
|
1572
|
-
<
|
|
1573
|
-
<
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
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>
|
|
1579
1640
|
</div>
|
|
1580
|
-
|
|
1641
|
+
${s}
|
|
1642
|
+
${a}
|
|
1581
1643
|
</div>
|
|
1582
|
-
`}bindCouponTriggerEvents(t){t.querySelector(".recur-coupon__trigger")?.addEventListener("click",()=>this.showCouponInput())}bindCouponInputEvents(t){let r=t.querySelector(".recur-coupon__input"),o=t.querySelector(".recur-coupon__btn--apply"),i=t.querySelector(".recur-
|
|
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`
|
|
1583
1645
|
<div class="recur-info-display">
|
|
1584
|
-
${t?
|
|
1646
|
+
${t?p`
|
|
1585
1647
|
<div class="recur-info-row">
|
|
1586
1648
|
<span class="recur-info-label">姓名</span>
|
|
1587
1649
|
<span class="recur-info-value">${t}</span>
|
|
1588
1650
|
</div>
|
|
1589
|
-
`:
|
|
1651
|
+
`:f}
|
|
1590
1652
|
<div class="recur-info-row">
|
|
1591
1653
|
<span class="recur-info-label">電子郵件</span>
|
|
1592
1654
|
<span class="recur-info-value">${r}</span>
|
|
1593
1655
|
</div>
|
|
1594
1656
|
</div>
|
|
1595
|
-
`:
|
|
1657
|
+
`:p`
|
|
1596
1658
|
<div class="recur-form-group">
|
|
1597
1659
|
<label class="recur-form-label" for="${this.containerId}-email">Email</label>
|
|
1598
1660
|
<input
|
|
@@ -1615,7 +1677,7 @@
|
|
|
1615
1677
|
required
|
|
1616
1678
|
/>
|
|
1617
1679
|
</div>
|
|
1618
|
-
`}renderCardFields(){return
|
|
1680
|
+
`}renderCardFields(){return p`
|
|
1619
1681
|
<div class="recur-card-field">
|
|
1620
1682
|
<label class="recur-card-field-label">卡號</label>
|
|
1621
1683
|
<div class="recur-card-field-container" id="${this.containerId}-card-no-wrapper">
|
|
@@ -1641,7 +1703,7 @@
|
|
|
1641
1703
|
</div>
|
|
1642
1704
|
</div>
|
|
1643
1705
|
</div>
|
|
1644
|
-
`}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`
|
|
1645
1707
|
<button
|
|
1646
1708
|
type="submit"
|
|
1647
1709
|
id="${this.containerId}-submit-btn"
|
|
@@ -1650,7 +1712,7 @@
|
|
|
1650
1712
|
>
|
|
1651
1713
|
<span id="${this.containerId}-submit-text">確認付款</span>
|
|
1652
1714
|
</button>
|
|
1653
|
-
`}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=`
|
|
1654
1716
|
<span class="recur-loading-spinner"></span>
|
|
1655
1717
|
<span>\u8655\u7406\u4E2D...</span>
|
|
1656
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=`
|
|
@@ -1882,7 +1944,7 @@
|
|
|
1882
1944
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
1883
1945
|
<circle cx="12" cy="7" r="4"/>
|
|
1884
1946
|
</svg>
|
|
1885
|
-
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var zt={};C(zt,{RecurCheckout:()=>
|
|
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=`
|
|
1886
1948
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
1887
1949
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
1888
1950
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -1952,21 +2014,21 @@
|
|
|
1952
2014
|
</p>
|
|
1953
2015
|
</form>
|
|
1954
2016
|
</div>
|
|
1955
|
-
`}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let r=document.createElement("script");r.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",r.async=!0,r.onload=()=>e(),r.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(r)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");let e=window.UniPayment;if(!e)throw new Error("PAYUNi SDK not loaded");let t={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=e.createSession(this.sdkToken,t),await this.payuniSDK.start(),this.payuniSDK.onUpdate(r=>{let o=r?.status;o&&(this.isFormValid=o.CardNo===!0&&o.CardExp===!0&&o.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.checkoutId)throw new Error("Checkout session not initialized");if(!this.payuniSDK)throw new Error("Payment system not initialized");let r=await this.payuniSDK.getTradeResult();if(r.Status!=="SUCCESS")throw new Error(r.Message||"Card validation failed");let o=r.EncryptInfo||r.creditToken;if(!o)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let i=this.getBaseUrl(),s=await fetch(`${i}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:o,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!s.ok){let
|
|
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=`
|
|
1956
2018
|
width: 100%;
|
|
1957
2019
|
border: none;
|
|
1958
2020
|
min-height: 200px;
|
|
1959
2021
|
display: block;
|
|
1960
2022
|
user-select: none;
|
|
1961
2023
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1962
|
-
`.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Se(n){return new N(n)}var Ht="https://vendor.payuni.com.tw/sdk/uni-payment.js",Bt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,
|
|
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",`
|
|
1963
2025
|
.form-input-focus {
|
|
1964
2026
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1965
2027
|
outline: 0 !important;
|
|
1966
2028
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
1967
2029
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
1968
2030
|
}
|
|
1969
|
-
`),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=`
|
|
1970
2032
|
.recur-dialog {
|
|
1971
2033
|
border: none;
|
|
1972
2034
|
border-radius: 12px;
|
|
@@ -2022,7 +2084,7 @@
|
|
|
2022
2084
|
.recur-dialog__close:hover {
|
|
2023
2085
|
background: rgba(0, 0, 0, 0.1);
|
|
2024
2086
|
}
|
|
2025
|
-
`,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function
|
|
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);})();
|
|
2026
2088
|
/*! Bundled license information:
|
|
2027
2089
|
|
|
2028
2090
|
lit-html/node/lit-html.js:
|