recur-tw 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/checkout.js +10 -2
- package/dist/index.cjs +155 -80
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +155 -80
- package/dist/recur.umd.js +48 -49
- package/dist/server.cjs +1 -1
- package/dist/server.js +1 -1
- package/dist/widget.js +11 -3
- package/package.json +1 -1
package/dist/recur.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var RecurCheckout=(()=>{var te=Object.defineProperty;var
|
|
1
|
+
"use strict";var RecurCheckout=(()=>{var te=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var St=Object.getOwnPropertyNames;var Tt=Object.prototype.hasOwnProperty;var It=(s,e,t)=>e in s?te(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var k=(s,e)=>()=>(s&&(e=s(s=0)),e);var S=(s,e)=>{for(var t in e)te(s,t,{get:e[t],enumerable:!0})},$t=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of St(e))!Tt.call(s,o)&&o!==t&&te(s,o,{get:()=>e[o],enumerable:!(r=Et(e,o))||r.enumerable});return s};var At=s=>$t(te({},"__esModule",{value:!0}),s);var l=(s,e,t)=>It(s,typeof e!="symbol"?e+"":e,t);var Me={};S(Me,{RecurLoadingSpinner:()=>re});var re,Le=k(()=>{"use strict";re=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
|
|
2
2
|
<style>
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
<div class="recur-sdk__spinner"></div>
|
|
42
42
|
${this.message?`<p class="recur-sdk__loading-text">${this.message}</p>`:""}
|
|
43
|
-
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",re)});var
|
|
43
|
+
`}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",re)});var Ue={};S(Ue,{RecurSuccessMessage:()=>oe});var oe,He=k(()=>{"use strict";oe=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
|
|
44
44
|
<style>
|
|
45
45
|
:host {
|
|
46
46
|
display: block;
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
<p class="recur-sdk__success-message">${this.successMessage}</p>
|
|
122
122
|
<slot></slot>
|
|
123
123
|
</div>
|
|
124
|
-
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",oe)});var
|
|
124
|
+
`}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",oe)});var Ne={};S(Ne,{RecurErrorDisplay:()=>ie});var ie,Be=k(()=>{"use strict";ie=class extends HTMLElement{static get observedAttributes(){return["error","error-title","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get errorTitle(){return this.getAttribute("error-title")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
|
|
125
125
|
<style>
|
|
126
126
|
:host {
|
|
127
127
|
display: block;
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
</button>
|
|
221
221
|
`:""}
|
|
222
222
|
</div>
|
|
223
|
-
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var
|
|
223
|
+
`,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var ze={};S(ze,{RecurSkeletonLoader:()=>ne});var ne,Oe=k(()=>{"use strict";ne=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
|
|
224
224
|
<div class="skeleton-field">
|
|
225
225
|
<div class="skeleton-label"></div>
|
|
226
226
|
<div class="skeleton-input"></div>
|
|
@@ -391,9 +391,9 @@
|
|
|
391
391
|
</style>
|
|
392
392
|
|
|
393
393
|
${e}
|
|
394
|
-
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",
|
|
395
|
-
\f\r]`,F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,
|
|
396
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),
|
|
394
|
+
`}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",ne)});function Ge(s,e){if(!Se(s)||!s.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ke!==void 0?Ke.createHTML(e):e}function N(s,e,t=s,r){if(e===Y)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(s),o._$AT(s,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=N(s,o._$AS(s,e.values),o,r)),e}var H,se,Ke,We,A,Xe,Rt,L,V,q,Se,Dt,ke,F,je,Fe,P,Ve,qe,Je,Te,p,tr,rr,Y,b,Ye,M,Pt,W,we,X,B,xe,_e,Ce,Ee,Mt,J,Ie=k(()=>{"use strict";H=globalThis,se=H.trustedTypes,Ke=se?se.createPolicy("lit-html",{createHTML:s=>s}):void 0,We="$lit$",A=`lit$${Math.random().toFixed(9).slice(2)}$`,Xe="?"+A,Rt=`<${Xe}>`,L=H.document===void 0?{createTreeWalker:()=>({})}:document,V=()=>L.createComment(""),q=s=>s===null||typeof s!="object"&&typeof s!="function",Se=Array.isArray,Dt=s=>Se(s)||typeof s?.[Symbol.iterator]=="function",ke=`[
|
|
395
|
+
\f\r]`,F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,je=/-->/g,Fe=/>/g,P=RegExp(`>|${ke}(?:([^\\s"'>=/]+)(${ke}*=${ke}*(?:[^
|
|
396
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ve=/'/g,qe=/"/g,Je=/^(?:script|style|textarea|title)$/i,Te=s=>(e,...t)=>({_$litType$:s,strings:e,values:t}),p=Te(1),tr=Te(2),rr=Te(3),Y=Symbol.for("lit-noChange"),b=Symbol.for("lit-nothing"),Ye=new WeakMap,M=L.createTreeWalker(L,129);Pt=(s,e)=>{let t=s.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",n=F;for(let a=0;a<t;a++){let c=s[a],u,m,h=-1,x=0;for(;x<c.length&&(n.lastIndex=x,m=n.exec(c),m!==null);)x=n.lastIndex,n===F?m[1]==="!--"?n=je:m[1]!==void 0?n=Fe:m[2]!==void 0?(Je.test(m[2])&&(o=RegExp("</"+m[2],"g")),n=P):m[3]!==void 0&&(n=P):n===P?m[0]===">"?(n=o??F,h=-1):m[1]===void 0?h=-2:(h=n.lastIndex-m[2].length,u=m[1],n=m[3]===void 0?P:m[3]==='"'?qe:Ve):n===qe||n===Ve?n=P:n===je||n===Fe?n=F:(n=P,o=void 0);let d=n===P&&s[a+1].startsWith("/>")?" ":"";i+=n===F?c+Rt:h>=0?(r.push(u),c.slice(0,h)+We+c.slice(h)+A+d):c+A+(h===-2?a:d)}return[Ge(s,i+(s[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},W=class s{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,n=0,a=e.length-1,c=this.parts,[u,m]=Pt(e,t);if(this.el=s.createElement(u,r),M.currentNode=this.el.content,t===2||t===3){let h=this.el.content.firstChild;h.replaceWith(...h.childNodes)}for(;(o=M.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let h of o.getAttributeNames())if(h.endsWith(We)){let x=m[n++],d=o.getAttribute(h).split(A),_=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:_[2],strings:d,ctor:_[1]==="."?xe:_[1]==="?"?_e:_[1]==="@"?Ce:B}),o.removeAttribute(h)}else h.startsWith(A)&&(c.push({type:6,index:i}),o.removeAttribute(h));if(Je.test(o.tagName)){let h=o.textContent.split(A),x=h.length-1;if(x>0){o.textContent=se?se.emptyScript:"";for(let d=0;d<x;d++)o.append(h[d],V()),M.nextNode(),c.push({type:2,index:++i});o.append(h[x],V())}}}else if(o.nodeType===8)if(o.data===Xe)c.push({type:2,index:i});else{let h=-1;for(;(h=o.data.indexOf(A,h+1))!==-1;)c.push({type:7,index:i}),h+=A.length-1}i++}}static createElement(e,t){let r=L.createElement("template");return r.innerHTML=e,r}};we=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??L).importNode(t,!0);M.currentNode=o;let i=M.nextNode(),n=0,a=0,c=r[0];for(;c!==void 0;){if(n===c.index){let u;c.type===2?u=new X(i,i.nextSibling,this,e):c.type===1?u=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(u=new Ee(i,this,e)),this._$AV.push(u),c=r[++a]}n!==c?.index&&(i=M.nextNode(),n++)}return M.currentNode=L,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++}},X=class s{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=b,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=N(this,e,t),q(e)?e===b||e==null||e===""?(this._$AH!==b&&this._$AR(),this._$AH=b):e!==this._$AH&&e!==Y&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Dt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==b&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(L.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=W.createElement(Ge(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new we(o,this),n=i.u(this.options);i.p(t),this.T(n),this._$AH=i}}_$AC(e){let t=Ye.get(e.strings);return t===void 0&&Ye.set(e.strings,t=new W(e)),t}k(e){Se(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 s(this.O(V()),this.O(V()),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=b,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=b}_$AI(e,t=this,r,o){let i=this.strings,n=!1;if(i===void 0)e=N(this,e,t,0),n=!q(e)||e!==this._$AH&&e!==Y,n&&(this._$AH=e);else{let a=e,c,u;for(e=i[0],c=0;c<i.length-1;c++)u=N(this,a[r+c],t,c),u===Y&&(u=this._$AH[c]),n||(n=!q(u)||u!==this._$AH[c]),u===b?e=b:e!==b&&(e+=(u??"")+i[c+1]),this._$AH[c]=u}n&&!o&&this.j(e)}j(e){e===b?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},xe=class extends B{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===b?void 0:e}},_e=class extends B{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==b)}},Ce=class extends B{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=N(this,e,t,0)??b)===Y)return;let r=this._$AH,o=e===b&&r!==b||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==b&&(r===b||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},Ee=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){N(this,e)}},Mt=H.litHtmlPolyfillSupport;Mt?.(W,X),(H.litHtmlVersions??(H.litHtmlVersions=[])).push("3.3.1");J=(s,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new X(e.insertBefore(V(),i),i,void 0,t??{})}return o._$AI(s),o}});var Qe,Ze=k(()=>{Qe=`/**
|
|
397
397
|
* Payment Form Skeleton - Shadow DOM Styles
|
|
398
398
|
* Loading skeleton that matches the structure of RecurPaymentForm
|
|
399
399
|
*/
|
|
@@ -605,7 +605,7 @@
|
|
|
605
605
|
color: #4a5568;
|
|
606
606
|
margin: 0;
|
|
607
607
|
}
|
|
608
|
-
`});var
|
|
608
|
+
`});var et={};S(et,{RecurPaymentFormSkeleton:()=>ae});var Ut,ae,tt=k(()=>{"use strict";Ie();Ze();Ut=p`
|
|
609
609
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
610
610
|
<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" />
|
|
611
611
|
</svg>
|
|
@@ -668,11 +668,11 @@
|
|
|
668
668
|
</div>
|
|
669
669
|
`}renderSubmitButton(){return p`<div class="skeleton skeleton-button"></div>`}renderSecurityNote(){return p`
|
|
670
670
|
<div class="security-note">
|
|
671
|
-
${
|
|
671
|
+
${Ut}
|
|
672
672
|
<p class="security-text">您的付款資訊經過加密保護</p>
|
|
673
673
|
</div>
|
|
674
674
|
`}render(){let e=p`
|
|
675
|
-
<style>${
|
|
675
|
+
<style>${Qe}</style>
|
|
676
676
|
|
|
677
677
|
<div class="payment-form-wrapper">
|
|
678
678
|
${this.renderHeader()}
|
|
@@ -682,7 +682,7 @@
|
|
|
682
682
|
${this.renderSubmitButton()}
|
|
683
683
|
${this.renderSecurityNote()}
|
|
684
684
|
</div>
|
|
685
|
-
`;J(e,this.shadowRoot)}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",ae)});var
|
|
685
|
+
`;J(e,this.shadowRoot)}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",ae)});var rt={};S(rt,{RecurToast:()=>ce,RecurToastContainer:()=>G});var ce,T,G,ot=k(()=>{"use strict";ce=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
686
686
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
687
687
|
</svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
688
688
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
@@ -802,7 +802,7 @@
|
|
|
802
802
|
</svg>
|
|
803
803
|
</button>
|
|
804
804
|
</div>
|
|
805
|
-
`,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",o=>{o.stopPropagation(),this.dismiss()}),this.shadowRoot.querySelector(".toast")?.addEventListener("click",()=>this.dismiss())}static show(e,t="info",r=5e3){let o=G.getInstance(),i=document.createElement("recur-toast");return i.setAttribute("message",e),i.setAttribute("type",t),i.setAttribute("duration",r.toString()),o.appendChild(i),i}},
|
|
805
|
+
`,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",o=>{o.stopPropagation(),this.dismiss()}),this.shadowRoot.querySelector(".toast")?.addEventListener("click",()=>this.dismiss())}static show(e,t="info",r=5e3){let o=G.getInstance(),i=document.createElement("recur-toast");return i.setAttribute("message",e),i.setAttribute("type",t),i.setAttribute("duration",r.toString()),o.appendChild(i),i}},T=class T extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
|
|
806
806
|
<style>
|
|
807
807
|
:host {
|
|
808
808
|
position: fixed;
|
|
@@ -829,7 +829,7 @@
|
|
|
829
829
|
</style>
|
|
830
830
|
|
|
831
831
|
<slot></slot>
|
|
832
|
-
`}static getInstance(){return
|
|
832
|
+
`}static getInstance(){return T.instance||(T.instance=document.querySelector("recur-toast-container"),T.instance||(T.instance=document.createElement("recur-toast-container"),document.body.appendChild(T.instance))),T.instance}};l(T,"instance",null);G=T;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",ce);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",G)});var nt,it=k(()=>{nt=`/**
|
|
833
833
|
* Payment Form - Shadow DOM Styles
|
|
834
834
|
* These styles are encapsulated within the Shadow DOM
|
|
835
835
|
*/
|
|
@@ -902,7 +902,7 @@
|
|
|
902
902
|
color: #4a5568;
|
|
903
903
|
margin: 0;
|
|
904
904
|
}
|
|
905
|
-
`});var st
|
|
905
|
+
`});var at,st=k(()=>{at=`/**
|
|
906
906
|
* Payment Form - Light DOM Styles
|
|
907
907
|
* These styles are applied to slotted content in the Light DOM
|
|
908
908
|
* Using BEM naming convention with 'recur-' prefix for isolation
|
|
@@ -1515,7 +1515,7 @@
|
|
|
1515
1515
|
.recur-test-card-meta {
|
|
1516
1516
|
color: #9ca3af;
|
|
1517
1517
|
}
|
|
1518
|
-
`});var
|
|
1518
|
+
`});function Bt(s){let e=(1e4-s)/1e3;if(Number.isInteger(e))return`${e} \u6298`;let t=e*10;return Number.isInteger(t)?`${t} \u6298`:`${(e*10).toFixed(2)} \u6298`}function zt(s,e){if(!s)return"";let t=e&&e>1?e.toString():"";switch(s.toUpperCase()){case"MONTH":return`${t}\u6708`;case"YEAR":return`${t}\u5E74`;case"WEEK":return`${t}\u9031`;case"DAY":return`${t}\u5929`;default:return""}}function le(s){return`NT$ ${s.toLocaleString("zh-TW")}`}function lt(s){let{discountType:e,couponDiscountValue:t,discountAmount:r,duration:o,durationMonths:i,productPrice:n,productInterval:a,productIntervalCount:c,bonusMonths:u,bonusTrialDays:m}=s,h=zt(a,c),x=h?`${le(n)}/${h}`:le(n),d=Ot(u,m);if(r===0&&(u||m))return{line1:Kt(u,m),line2:null};if(r===0)return{line1:"",line2:null};let _=`\u4E4B\u5F8C ${x}`;if(e==="FIRST_PERIOD_PRICE"){let g=t,be=g===0?"\u514D\u8CBB":`\u7279\u50F9 ${le(g)}`;return{line1:d?`\u9996\u671F${be}\uFF0C${d}`:`\u9996\u671F${be}`,line2:_}}return e==="FIXED_AMOUNT"?ct({discountText:`\u6298 ${le(t)}`,duration:o,durationMonths:i,bonusSuffix:d,afterLine:_}):e==="PERCENTAGE"?ct({discountText:`\u4EAB ${Bt(t)}`,duration:o,durationMonths:i,bonusSuffix:d,afterLine:_}):{line1:"",line2:null}}function ct(s){let{discountText:e,duration:t,durationMonths:r,bonusSuffix:o,afterLine:i}=s;switch(t){case"ONCE":{let n=`\u9996\u671F${e}`;return{line1:o?`${n}\uFF0C${o}`:n,line2:i}}case"REPEATING":return{line1:`\u524D ${r??0} \u671F\u6BCF\u671F${e}`,line2:i};case"FOREVER":return{line1:`\u6BCF\u671F${e}`,line2:null};default:return{line1:"",line2:null}}}function Ot(s,e){let t=[];return s&&t.push(`\u52A0\u9001 ${s} \u500B\u6708`),e&&t.push(`\u5EF6\u9577 ${e} \u5929\u8A66\u7528`),t.length===0?null:`\u4E26${t.join("\u53CA")}`}function Kt(s,e){let t=[];return s&&t.push(`\u52A0\u9001 ${s} \u500B\u6708`),e&&t.push(`\u5EF6\u9577\u8A66\u7528 ${e} \u5929`),t.join("\u53CA")}var ut=k(()=>{"use strict"});var dt={};S(dt,{RecurPaymentForm:()=>ue});var U,ue,pt=k(()=>{"use strict";Ie();it();st();ut();U={lock:p`
|
|
1519
1519
|
<svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1520
1520
|
<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" />
|
|
1521
1521
|
</svg>
|
|
@@ -1535,7 +1535,7 @@
|
|
|
1535
1535
|
<svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1536
1536
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
1537
1537
|
</svg>
|
|
1538
|
-
`,spinner:p`<span class="recur-coupon__spinner"></span>`},
|
|
1538
|
+
`,spinner:p`<span class="recur-coupon__spinner"></span>`},ue=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_paymentSession",null);l(this,"_showTestCardHints",!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 nt}getLightDOMStyles(){return at}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=p`
|
|
1539
1539
|
<style>${this.getShadowDOMStyles()}</style>
|
|
1540
1540
|
|
|
1541
1541
|
<div class="payment-form-wrapper">
|
|
@@ -1600,7 +1600,7 @@
|
|
|
1600
1600
|
height: 36px !important;
|
|
1601
1601
|
}
|
|
1602
1602
|
${this.customStyles}
|
|
1603
|
-
`}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}isTestMode(){return(this.getAttribute("publishable-key")||"").startsWith("pk_test_")}renderTestCardHints(){if(!this.isTestMode())return p``;let t=[{number:"4147 6310 0000 0001",desc:"VISA \u6E2C\u8A66\u5361\uFF08\u6388\u6B0A\u6210\u529F\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"},{number:"3560 5110 0000 0001",desc:"JCB \u6E2C\u8A66\u5361\uFF08\u6388\u6B0A\u6210\u529F\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"},{number:"4147 6310 0000 0002",desc:"VISA \u6E2C\u8A66\u5361\uFF083D\u9A57\u8B49\u5931\u6557\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"}],r=(o,i)=>{let
|
|
1603
|
+
`}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-styles`);t&&(t.textContent=this.getLightDOMStyles()+this.getCustomStyles())}isTestMode(){return(this.getAttribute("publishable-key")||"").startsWith("pk_test_")}renderTestCardHints(){if(!this.isTestMode())return p``;let t=[{number:"4147 6310 0000 0001",desc:"VISA \u6E2C\u8A66\u5361\uFF08\u6388\u6B0A\u6210\u529F\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"},{number:"3560 5110 0000 0001",desc:"JCB \u6E2C\u8A66\u5361\uFF08\u6388\u6B0A\u6210\u529F\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"},{number:"4147 6310 0000 0002",desc:"VISA \u6E2C\u8A66\u5361\uFF083D\u9A57\u8B49\u5931\u6557\uFF09",expiry:"\u4EFB\u610F\u672A\u4F86\u65E5\u671F",cvc:"\u4EFB\u610F3\u78BC"}],r=(o,i)=>{let n=i.currentTarget;navigator.clipboard.writeText(o.replace(/\s/g,"")).then(()=>{let a=n.textContent;n.textContent="\u5DF2\u8907\u88FD!",n.classList.add("copied"),setTimeout(()=>{n.textContent=a,n.classList.remove("copied")},1500)})};return p`
|
|
1604
1604
|
<div class="recur-test-mode-banner">
|
|
1605
1605
|
<div class="recur-test-mode-header" @click=${()=>{this._showTestCardHints=!this._showTestCardHints,this.renderLightDOM()}}>
|
|
1606
1606
|
<span class="recur-test-mode-badge">🧪 測試模式</span>
|
|
@@ -1622,7 +1622,7 @@
|
|
|
1622
1622
|
</div>
|
|
1623
1623
|
`)}
|
|
1624
1624
|
</div>
|
|
1625
|
-
`:
|
|
1625
|
+
`:b}
|
|
1626
1626
|
</div>
|
|
1627
1627
|
`}renderOrderSummary(){let t=this.getAttribute("product-name"),r=this.getAttribute("amount"),o=this.getAttribute("interval");if(!t||!r)return p`
|
|
1628
1628
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
@@ -1642,11 +1642,11 @@
|
|
|
1642
1642
|
<span class="recur-order-summary__total recur-skeleton" style="width: 100px; height: 26px;"></span>
|
|
1643
1643
|
</div>
|
|
1644
1644
|
</div>
|
|
1645
|
-
`;let
|
|
1645
|
+
`;let n=o?{day:"\u65E5",week:"\u9031",month:"\u6708",year:"\u5E74"}[o]||o:"",a=Number(r),c=this._appliedCoupon?.discountAmount||0,u=a-c,m=n?`${t} / \u6BCF${n}`:t;return p`
|
|
1646
1646
|
<div class="recur-order-summary" id="${this.containerId}-order-summary">
|
|
1647
1647
|
<div class="recur-order-summary__row">
|
|
1648
1648
|
<span class="recur-order-summary__label">方案</span>
|
|
1649
|
-
<span class="recur-order-summary__value">${
|
|
1649
|
+
<span class="recur-order-summary__value">${m}</span>
|
|
1650
1650
|
</div>
|
|
1651
1651
|
|
|
1652
1652
|
<!-- 小計 (Subtotal) - always show -->
|
|
@@ -1663,10 +1663,10 @@
|
|
|
1663
1663
|
<!-- 總計 (Total) -->
|
|
1664
1664
|
<div class="recur-order-summary__row recur-order-summary__row--total">
|
|
1665
1665
|
<span class="recur-order-summary__label">總計</span>
|
|
1666
|
-
<span class="recur-order-summary__total">NT$ ${
|
|
1666
|
+
<span class="recur-order-summary__total">NT$ ${u.toLocaleString()}</span>
|
|
1667
1667
|
</div>
|
|
1668
1668
|
</div>
|
|
1669
|
-
`}
|
|
1669
|
+
`}getDiscountDisplay(){if(!this._appliedCoupon)return null;let t=parseInt(this.getAttribute("amount")||"0",10);return lt({discountType:this._appliedCoupon.discountType,couponDiscountValue:this._appliedCoupon.couponDiscountValue,discountAmount:this._appliedCoupon.discountAmount,duration:this._appliedCoupon.duration||"ONCE",durationMonths:this._appliedCoupon.durationMonths,productPrice:this._appliedCoupon.productPrice??t,productInterval:this._appliedCoupon.productInterval,productIntervalCount:this._appliedCoupon.productIntervalCount,bonusMonths:this._appliedCoupon.bonusMonths,bonusTrialDays:this._appliedCoupon.bonusTrialDays})}renderCoupon(){if(this._appliedCoupon){let t=this.getDiscountDisplay();return p`
|
|
1670
1670
|
<div class="recur-coupon__applied-wrapper">
|
|
1671
1671
|
<div class="recur-coupon__applied">
|
|
1672
1672
|
<div class="recur-coupon__applied-info">
|
|
@@ -1686,19 +1686,18 @@
|
|
|
1686
1686
|
${this._couponLoading?U.spinner:U.close}
|
|
1687
1687
|
</button>
|
|
1688
1688
|
</div>
|
|
1689
|
-
|
|
1690
|
-
-
|
|
1691
|
-
|
|
1689
|
+
${this._appliedCoupon.discountAmount>0?p`
|
|
1690
|
+
<span class="recur-coupon__applied-amount">
|
|
1691
|
+
-NT$ ${this._appliedCoupon.discountAmount.toLocaleString()}
|
|
1692
|
+
</span>
|
|
1693
|
+
`:b}
|
|
1692
1694
|
</div>
|
|
1693
|
-
${t?p`
|
|
1694
|
-
<p class="recur-coupon__description">${t}</p>
|
|
1695
|
-
`:
|
|
1696
|
-
${
|
|
1697
|
-
<
|
|
1698
|
-
|
|
1699
|
-
<span>${r}</span>
|
|
1700
|
-
</div>
|
|
1701
|
-
`:f}
|
|
1695
|
+
${t?.line1?p`
|
|
1696
|
+
<p class="recur-coupon__description">${t.line1}</p>
|
|
1697
|
+
`:b}
|
|
1698
|
+
${t?.line2?p`
|
|
1699
|
+
<p class="recur-coupon__description">${t.line2}</p>
|
|
1700
|
+
`:b}
|
|
1702
1701
|
</div>
|
|
1703
1702
|
`}return this._showCouponInput?p`
|
|
1704
1703
|
<div style="width: 100%;">
|
|
@@ -1723,7 +1722,7 @@
|
|
|
1723
1722
|
>
|
|
1724
1723
|
${U.clearInput}
|
|
1725
1724
|
</button>
|
|
1726
|
-
`:
|
|
1725
|
+
`:b}
|
|
1727
1726
|
</div>
|
|
1728
1727
|
<button
|
|
1729
1728
|
type="button"
|
|
@@ -1736,7 +1735,7 @@
|
|
|
1736
1735
|
</div>
|
|
1737
1736
|
${this._couponError?p`
|
|
1738
1737
|
<div class="recur-coupon__error">${this._couponError}</div>
|
|
1739
|
-
`:
|
|
1738
|
+
`:b}
|
|
1740
1739
|
</div>
|
|
1741
1740
|
`:p`
|
|
1742
1741
|
<button
|
|
@@ -1782,7 +1781,7 @@
|
|
|
1782
1781
|
</div>
|
|
1783
1782
|
${t}
|
|
1784
1783
|
</div>
|
|
1785
|
-
`}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.
|
|
1784
|
+
`}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.getDiscountDisplay(),i=t.discountAmount>0?`<span class="recur-coupon__applied-amount">-NT$ ${t.discountAmount.toLocaleString()}</span>`:"",n=o?.line1?`<p class="recur-coupon__description">${o.line1}</p>`:"",a=o?.line2?`<p class="recur-coupon__description">${o.line2}</p>`:"";return`
|
|
1786
1785
|
<div class="recur-coupon__applied-wrapper">
|
|
1787
1786
|
<div class="recur-coupon__applied">
|
|
1788
1787
|
<div class="recur-coupon__applied-info">
|
|
@@ -1794,19 +1793,19 @@
|
|
|
1794
1793
|
${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>'}
|
|
1795
1794
|
</button>
|
|
1796
1795
|
</div>
|
|
1797
|
-
|
|
1796
|
+
${i}
|
|
1798
1797
|
</div>
|
|
1799
|
-
${
|
|
1798
|
+
${n}
|
|
1800
1799
|
${a}
|
|
1801
1800
|
</div>
|
|
1802
|
-
`}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",
|
|
1801
|
+
`}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",n=>this.handleCouponInputChange(n)),r?.addEventListener("keydown",n=>this.handleCouponKeydown(n)),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})}),n=await i.json();if(!i.ok){this._couponError=n.error?.message||"\u512A\u60E0\u78BC\u7121\u6548",this._couponLoading=!1,this.updateCouponSectionDOM();return}this._appliedCoupon={code:n.discount.code,couponName:n.discount.coupon_name,discountType:n.discount.discount_type,discountAmount:n.discount.discount_amount,couponDiscountValue:n.discount.coupon_discount_value??n.discount.discount_amount,duration:n.discount.duration,durationMonths:n.discount.duration_months,bonusTrialDays:n.discount.bonus_trial_days,bonusMonths:n.discount.bonus_months,productInterval:n.discount.product_interval,productIntervalCount:n.discount.product_interval_count,productPrice:n.discount.product_price},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 n=await o.json();this._couponError=n.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`
|
|
1803
1802
|
<div class="recur-info-display">
|
|
1804
1803
|
${t?p`
|
|
1805
1804
|
<div class="recur-info-row">
|
|
1806
1805
|
<span class="recur-info-label">姓名</span>
|
|
1807
1806
|
<span class="recur-info-value">${t}</span>
|
|
1808
1807
|
</div>
|
|
1809
|
-
`:
|
|
1808
|
+
`:b}
|
|
1810
1809
|
<div class="recur-info-row">
|
|
1811
1810
|
<span class="recur-info-label">電子郵件</span>
|
|
1812
1811
|
<span class="recur-info-value">${r}</span>
|
|
@@ -1870,13 +1869,13 @@
|
|
|
1870
1869
|
>
|
|
1871
1870
|
<span id="${this.containerId}-submit-text">確認付款</span>
|
|
1872
1871
|
</button>
|
|
1873
|
-
`}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`),
|
|
1872
|
+
`}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`),n=document.getElementById(`${this.containerId}-card-cvc`);if(!o||!i||!n)return console.log("[PaymentForm] DOM elements not found, likely disconnected"),this._isInitializing=!1,null;if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before createSession"),this._isInitializing=!1,null;let 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){let u=c;if((u?.message?.includes("1008")||u?.message?.includes("timeout")||u?.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 u=c,m=u.status&&u.status.CardNo===!0&&u.status.CardExp===!0&&u.status.CardCvc===!0,h=document.getElementById(`${this.containerId}-submit-btn`);h&&(h.disabled=!m,console.log("[PaymentForm] Submit button disabled:",!m))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=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,n=document.getElementById(`${this.containerId}-email`),a=document.getElementById(`${this.containerId}-name`);if(n&&a){if(o=n.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=`
|
|
1874
1873
|
<span class="recur-loading-spinner"></span>
|
|
1875
1874
|
<span>\u8655\u7406\u4E2D...</span>
|
|
1876
1875
|
`):(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=`
|
|
1877
1876
|
<span class="recur-loading-spinner"></span>
|
|
1878
1877
|
<span>3D \u9A57\u8B49\u4E2D...</span>
|
|
1879
|
-
`):this.setButtonLoading(!1))}showError(t){let r=typeof t=="string"?t:t.message,o=typeof t=="object"?t.title:void 0,i=this.querySelector(".recur-sdk__error-container");i||(i=document.createElement("div"),i.className="recur-sdk__error-container",i.style.cssText="margin-bottom: 16px;",this.insertBefore(i,this.firstChild));let
|
|
1878
|
+
`):this.setButtonLoading(!1))}showError(t){let r=typeof t=="string"?t:t.message,o=typeof t=="object"?t.title:void 0,i=this.querySelector(".recur-sdk__error-container");i||(i=document.createElement("div"),i.className="recur-sdk__error-container",i.style.cssText="margin-bottom: 16px;",this.insertBefore(i,this.firstChild));let n=document.createElement("recur-error-display");n.setAttribute("error",r),o&&n.setAttribute("error-title",o),n.setAttribute("dismissible","true"),i.innerHTML="",i.appendChild(n),n.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",ue)});var mt={};S(mt,{RecurCheckoutButton:()=>de});var de,ht=k(()=>{"use strict";de=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),o=this.getAttribute("product-id"),i=this.getAttribute("success-url"),n=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!o){this.dispatchError("Missing required attribute: product-id");return}if(!i){this.dispatchError("Missing required attribute: success-url");return}if(!n){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let a=await this.createCheckoutSession({publishableKey:r,productId:o,successUrl:this.resolveUrl(i),cancelUrl:this.resolveUrl(n),customerEmail:this.getAttribute("customer-email")||void 0,mode:this.getAttribute("mode")});this.dispatchEvent(new CustomEvent("checkout-started",{detail:{sessionId:a.id,url:a.url},bubbles:!0,composed:!0})),window.location.href=a.url}catch(a){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(a instanceof Error?a.message:"Failed to create checkout session")}});this.attachShadow({mode:"open"})}static get observedAttributes(){return["publishable-key","product-id","success-url","cancel-url","customer-email","mode","button-text","button-style","disabled"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
|
|
1880
1879
|
<style>
|
|
1881
1880
|
:host {
|
|
1882
1881
|
display: inline-block;
|
|
@@ -1975,7 +1974,7 @@
|
|
|
1975
1974
|
${this._isLoading?'<span class="spinner"></span>':""}
|
|
1976
1975
|
<span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
|
|
1977
1976
|
</button>
|
|
1978
|
-
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),o={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(o.mode=t.mode),t.customerEmail&&(o.customerEmail=t.customerEmail);let i=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(o)});if(!i.ok){let
|
|
1977
|
+
`}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),o={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(o.mode=t.mode),t.customerEmail&&(o.customerEmail=t.customerEmail);let i=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(o)});if(!i.ok){let n=await i.json().catch(()=>({}));throw new Error(n.error?.message||`HTTP ${i.status}: Failed to create checkout session`)}return i.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",de)});var gt={};S(gt,{RecurPortalButton:()=>pe});var pe,ft=k(()=>{"use strict";pe=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),o=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(o){await this.fetchAndRedirect(o);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
|
|
1979
1978
|
<style>
|
|
1980
1979
|
:host {
|
|
1981
1980
|
display: inline-block;
|
|
@@ -2102,7 +2101,7 @@
|
|
|
2102
2101
|
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
|
2103
2102
|
<circle cx="12" cy="7" r="4"/>
|
|
2104
2103
|
</svg>
|
|
2105
|
-
`}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
|
|
2104
|
+
`}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 n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!n.ok){let u=await n.json().catch(()=>({}));throw new Error(u.error?.message||u.message||`HTTP ${n.status}: Failed to create portal session`)}let a=await n.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 instanceof Error?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",pe)});var Qt={};S(Qt,{RecurCheckout:()=>O,RecurElements:()=>z,create:()=>kt,createElements:()=>$e,default:()=>Zt,init:()=>vt});async function jt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(Le(),Me)),Promise.resolve().then(()=>(He(),Ue)),Promise.resolve().then(()=>(Be(),Ne)),Promise.resolve().then(()=>(Oe(),ze)),Promise.resolve().then(()=>(tt(),et)),Promise.resolve().then(()=>(ot(),rt)),Promise.resolve().then(()=>(pt(),dt)),Promise.resolve().then(()=>(ht(),mt)),Promise.resolve().then(()=>(ft(),gt))]);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"&&jt();function Ft(s){return s.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function w(s){if(s==null)return s;if(Array.isArray(s))return s.map(e=>w(e));if(s instanceof Date)return s;if(typeof s=="object"){let e={};for(let[t,r]of Object.entries(s)){let o=Ft(t);e[o]=w(r)}return e}return s}var me={name:"recur-tw",version:"0.13.2",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 . -p 8080 -o /examples/"},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","./checkout":"./dist/checkout.js","./widget":"./dist/widget.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 qt=me.version,Yt="vanilla",he=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":Yt,"X-Recur-SDK-Version":qt,"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 n={customerName:t,customerEmail:r};o&&(n.productId=o),i&&(n.productSlug=i);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(n)});if(!a.ok){let u=await a.json().catch(()=>({}));throw{code:u.error||"CHECKOUT_FAILED",message:u.message||"Failed to initiate checkout",details:u}}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 ge=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=`
|
|
2106
2105
|
<div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
|
|
2107
2106
|
<div class="recur-checkout-header" style="margin-bottom: 24px;">
|
|
2108
2107
|
<h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
|
|
@@ -2172,21 +2171,21 @@
|
|
|
2172
2171
|
</p>
|
|
2173
2172
|
</form>
|
|
2174
2173
|
</div>
|
|
2175
|
-
`}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");if(!window.UniPayment)throw new Error("PAYUNi SDK not loaded");let e={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=window.UniPayment.createSession(this.sdkToken,e),await this.payuniSDK.start(),this.payuniSDK.onUpdate?.(t=>{let r=t?.status;r&&(this.isFormValid=r.CardNo===!0&&r.CardExp===!0&&r.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(),
|
|
2174
|
+
`}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");if(!window.UniPayment)throw new Error("PAYUNi SDK not loaded");let e={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=window.UniPayment.createSession(this.sdkToken,e),await this.payuniSDK.start(),this.payuniSDK.onUpdate?.(t=>{let r=t?.status;r&&(this.isFormValid=r.CardNo===!0&&r.CardExp===!0&&r.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(),n=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(!n.ok){let m=await n.json().catch(()=>({}));throw new Error(m.error||"Failed to process payment")}let a=await n.json(),c=this.options.productId||this.options.planId||"",u={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(u),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 instanceof Error?e.message:"An error occurred";this.showError(t);let r={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(r)}};var z=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=`
|
|
2176
2175
|
width: 100%;
|
|
2177
2176
|
border: none;
|
|
2178
2177
|
min-height: 200px;
|
|
2179
2178
|
display: block;
|
|
2180
2179
|
user-select: none;
|
|
2181
2180
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
2182
|
-
`.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);let d=c instanceof Error?c.message:c?.message;o(new Error(d||"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);let c=a instanceof Error?a.message:a?.message;r(new Error(c||"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 Te(n){return new z(n)}var Bt="https://vendor.payuni.com.tw/sdk/uni-payment.js",Nt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,ge=!1,Z=null;async function mt(n=!1){return pt&&window.UniPayment?Promise.resolve():(ge&&Z||(ge=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Nt:Bt,r.async=!0,r.onload=()=>{pt=!0,ge=!1,e()},r.onerror=()=>{ge=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var zt=pe.version,Ot="vanilla",O=class n{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"_customer",null);l(this,"_subscription",null);l(this,"_entitlements",[]);l(this,"_customerIdentifier",null);l(this,"_isLoading",!1);l(this,"_error",null);l(this,"currentDialogElement",null);this.core=new me(e)}static async create(e){let t=new n(e);return e.customer&&(t._customerIdentifier=e.customer,await t.fetchEntitlements()),t}get customer(){return this._customer}get subscription(){return this._subscription}get entitlements(){return this._entitlements}get isLoading(){return this._isLoading}get error(){return this._error}async fetchEntitlements(){if(!this._customerIdentifier){console.warn("[Recur SDK] Cannot fetch entitlements: customer identifier not set");return}let e=this.core.getConfig();if(!e.publishableKey){console.warn("[Recur SDK] Cannot fetch entitlements: publishableKey is required");return}this._isLoading=!0,this._error=null;try{let t=e.baseUrl||"https://api.recur.tw",r=new URLSearchParams;this._customerIdentifier.email&&r.set("email",this._customerIdentifier.email),this._customerIdentifier.externalId&&r.set("external_id",this._customerIdentifier.externalId),this._customerIdentifier.id&&r.set("customer_id",this._customerIdentifier.id);let o=await fetch(`${t}/v1/customers/entitlements?${r.toString()}`,{method:"GET",headers:{"X-Recur-Publishable-Key":e.publishableKey,"X-Recur-SDK-Type":Ot,"X-Recur-SDK-Version":zt}});if(!o.ok){let a=await o.json().catch(()=>({}));throw new Error(a.error?.message||"Failed to fetch entitlements")}let i=await o.json(),s=k(i);this._customer=s.customer||null,this._subscription=s.subscription||null,this._entitlements=s.entitlements||[]}catch(t){console.error("[Recur SDK] Failed to fetch entitlements:",t),this._error=t instanceof Error?t:new Error("Failed to fetch entitlements")}finally{this._isLoading=!1}}async refetch(){await this.fetchEntitlements()}resolveProduct(e){if(typeof e=="string")return e;if("product"in e)return e.product;throw"feature"in e?new Error("Feature-based checks are not yet supported. Coming in Phase 2."):"benefit"in e?new Error("Benefit-based checks are not yet supported. Coming in Phase 2."):new Error("Invalid check target")}check(e,t){return t?.live?this.checkLive(e):this.checkSync(e)}checkSync(e){let t=this.resolveProduct(e);if(!this._customer)return{allowed:!1,reason:"no_customer"};if(this._entitlements.length===0)return{allowed:!1,reason:"no_entitlement"};let r=this._entitlements.find(o=>o.product===t||o.productId===t);return r?{allowed:!0,entitlement:r}:{allowed:!1,reason:"not_found"}}async checkLive(e){return await this.refetch(),this.checkSync(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=k(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=k(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 R=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!R.ok){let P=await R.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",P),new Error(P.error?.message||P.error||"Failed to create checkout session")}let fe=await R.json(),E=k(fe);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 R=y.details||y.error||"Failed to create checkout";throw new Error(R)}let x=await m.json(),u=k(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await mt(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let 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",`
|
|
2181
|
+
`.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),n=()=>{clearTimeout(i),this.off("ready",n),r()},a=c=>{clearTimeout(i),this.off("error",a);let u=c instanceof Error?c.message:c?.message;o(new Error(u||"Elements initialization failed"))};this.on("ready",n),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)},n=a=>{clearTimeout(o),this.off("error",n);let c=a instanceof Error?a.message:a?.message;r(new Error(c||"Tokenization failed"))};this.on("tokenized",i),this.on("error",n)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function $e(s){return new z(s)}var Wt="https://vendor.payuni.com.tw/sdk/uni-payment.js",Xt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",bt=!1,fe=!1,Z=null;async function yt(s=!1){return bt&&window.UniPayment?Promise.resolve():(fe&&Z||(fe=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=s?Xt:Wt,r.async=!0,r.onload=()=>{bt=!0,fe=!1,e()},r.onerror=()=>{fe=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var Jt=me.version,Gt="vanilla",O=class s{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"_customer",null);l(this,"_subscription",null);l(this,"_entitlements",[]);l(this,"_customerIdentifier",null);l(this,"_isLoading",!1);l(this,"_error",null);l(this,"currentDialogElement",null);this.core=new he(e)}static async create(e){let t=new s(e);return e.customer&&(t._customerIdentifier=e.customer,await t.fetchEntitlements()),t}get customer(){return this._customer}get subscription(){return this._subscription}get entitlements(){return this._entitlements}get isLoading(){return this._isLoading}get error(){return this._error}async fetchEntitlements(){if(!this._customerIdentifier){console.warn("[Recur SDK] Cannot fetch entitlements: customer identifier not set");return}let e=this.core.getConfig();if(!e.publishableKey){console.warn("[Recur SDK] Cannot fetch entitlements: publishableKey is required");return}this._isLoading=!0,this._error=null;try{let t=e.baseUrl||"https://api.recur.tw",r=new URLSearchParams;this._customerIdentifier.email&&r.set("email",this._customerIdentifier.email),this._customerIdentifier.externalId&&r.set("external_id",this._customerIdentifier.externalId),this._customerIdentifier.id&&r.set("customer_id",this._customerIdentifier.id);let o=await fetch(`${t}/v1/customers/entitlements?${r.toString()}`,{method:"GET",headers:{"X-Recur-Publishable-Key":e.publishableKey,"X-Recur-SDK-Type":Gt,"X-Recur-SDK-Version":Jt}});if(!o.ok){let a=await o.json().catch(()=>({}));throw new Error(a.error?.message||"Failed to fetch entitlements")}let i=await o.json(),n=w(i);this._customer=n.customer||null,this._subscription=n.subscription||null,this._entitlements=n.entitlements||[]}catch(t){console.error("[Recur SDK] Failed to fetch entitlements:",t),this._error=t instanceof Error?t:new Error("Failed to fetch entitlements")}finally{this._isLoading=!1}}async refetch(){await this.fetchEntitlements()}resolveProduct(e){if(typeof e=="string")return e;if("product"in e)return e.product;throw"feature"in e?new Error("Feature-based checks are not yet supported. Coming in Phase 2."):"benefit"in e?new Error("Benefit-based checks are not yet supported. Coming in Phase 2."):new Error("Invalid check target")}check(e,t){return t?.live?this.checkLive(e):this.checkSync(e)}checkSync(e){let t=this.resolveProduct(e);if(!this._customer)return{allowed:!1,reason:"no_customer"};if(this._entitlements.length===0)return{allowed:!1,reason:"no_entitlement"};let r=this._entitlements.find(o=>o.product===t||o.productId===t);return r?{allowed:!0,entitlement:r}:{allowed:!1,reason:"not_found"}}async checkLive(e){return await this.refetch(),this.checkSync(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 ge(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 n=await i.json(),a=w(n);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 n=await i.json(),a=w(n);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 n=this.getBaseUrl();console.log("[Recur SDK] Base URL:",n);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 R=await fetch(`${n}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!R.ok){let D=await R.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",D),new Error(D.error?.message||D.error||"Failed to create checkout session")}let ye=await R.json(),E=w(ye);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 u=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,u=y.container}else if(c==="iframe"){if(u=this.getEmbeddedContainer(e.container),!u)throw new Error("Container is required for iframe mode");u.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");u.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let m={customerName:e.customerName,customerEmail:e.customerEmail};o&&(m.productId=o),i&&(m.productSlug=i),e.externalCustomerId&&(m.externalCustomerId=e.externalCustomerId),e.successUrl&&(m.successUrl=e.successUrl),e.cancelUrl&&(m.cancelUrl=e.cancelUrl);let h=await fetch(`${n}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(m)});if(!h.ok){let y=await h.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let R=y.details||y.error||"Failed to create checkout";throw new Error(R)}let x=await h.json(),d=w(x);if(console.log("[Recur SDK] Checkout created successfully:",d),e.onSuccess?.(d),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!d.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let _=!d.livemode;if(console.log("[Recur SDK] Environment:",_?"SANDBOX":"PRODUCTION"),await yt(_),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..."),!u)throw new Error("Payment container not available");u.innerHTML="";let g=document.createElement("recur-payment-form");if(g.setAttribute("container-id",u.id||"recur-payment-container"),d.checkout?.id&&g.setAttribute("checkout-id",d.checkout.id),g.setAttribute("api-base-url",n),e.customerName&&g.setAttribute("customer-name",e.customerName),e.customerEmail&&g.setAttribute("customer-email",e.customerEmail),d.product?.name&&g.setAttribute("product-name",d.product.name),d.checkout?.amount&&g.setAttribute("amount",d.checkout.amount.toString()),d.product?.interval&&g.setAttribute("interval",d.product.interval),g.setAttribute("custom-styles",`
|
|
2183
2182
|
.form-input-focus {
|
|
2184
2183
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
2185
2184
|
outline: 0 !important;
|
|
2186
2185
|
box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
|
|
2187
2186
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
|
|
2188
2187
|
}
|
|
2189
|
-
`),
|
|
2188
|
+
`),u.appendChild(g),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await g.initializePayment(d.sdkToken,_?"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..."),g.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let R=y,{paymentSession:ye}=R.detail;try{let E=await ye.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let D=E.HashTimestamp||E.timestamp,Ae={};if(d.checkout.productType==="SUBSCRIPTION"){let I=d.creditToken,C=d.sdkTimestamp;if(!I)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Ae={creditToken:I,timestamp:C||D},console.log("[Recur SDK] Using creditToken from checkout:",I.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",C?"from checkout (sdkTimestamp)":"from tradeResult")}let ve=await fetch(`${n}/v1/checkouts/${d.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify(Ae)});if(!ve.ok){let I=await ve.json().catch(()=>({}));throw new Error(I.error||"Failed to execute payment")}let xt=await ve.json(),f=w(xt);if(console.log("[Recur SDK] Payment executed:",f),f.requires3D&&f.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=f.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let C=window.open(f.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!C){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=f.redirectUrl;return}if(await new Promise(j=>setTimeout(j,100)),C.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=f.redirectUrl;return}g.setVerifying?.(!0);let Q=d.checkout.id,Re=d.checkout.clientSecret,_t=90,Ct=2e3,K=!0,De=!1,Pe;console.log("[Recur SDK] Starting 3D verification polling...");for(let j=0;j<_t&&K;j++){if(C.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${n}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Re)}`,{headers:a});if(v.ok){let $=await v.json();if($.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),K=!1,De=!0,Pe=$.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"),g.setVerifying?.(!1),g.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${n}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Re)}`,{headers:a});if(v.ok){let $=await v.json(),ee=$.checkout?.status;if(console.log(`[Recur SDK] Poll ${j+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),K=!1;try{C.close()}catch{}g.setVerifying?.(!1),e.onPaymentComplete&&(f.subscription?e.onPaymentComplete({id:f.subscription.id,status:"ACTIVE",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:f.subscription.billingPeriod,currentPeriodStart:f.subscription.currentPeriodStart,currentPeriodEnd:f.subscription.currentPeriodEnd}):e.onPaymentComplete({id:$.checkout?.orderId||Q,status:"SUCCEEDED",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),K=!1;try{C.close()}catch{}throw g.setVerifying?.(!1),g.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){let $=v instanceof Error?v.message:String(v);if($==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||$==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,Ct))}if(K){console.log("[Recur SDK] 3D verification polling timeout");try{C.close()}catch{}throw g.setVerifying?.(!1),g.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}De&&(console.log("[Recur SDK] Handling success after popup close"),g.setVerifying?.(!1),e.onPaymentComplete&&(f.subscription?e.onPaymentComplete({id:f.subscription.id,status:"ACTIVE",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:f.subscription.billingPeriod,currentPeriodStart:f.subscription.currentPeriodStart,currentPeriodEnd:f.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Pe||Q,status:"SUCCEEDED",productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(f.subscription)e.onPaymentComplete({id:f.subscription.id,status:f.subscription.status,productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:f.subscription.billingPeriod,currentPeriodStart:f.subscription.currentPeriodStart,currentPeriodEnd:f.subscription.currentPeriodEnd});else{let I=f.charge?.id||f.paymentIntent?.id,C=f.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:I,status:C,productId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),g.resetButton?.(),r&&(r.close(),r.remove())}catch(E){console.error("[Recur SDK] Payment error:",E);let D={code:"PAYMENT_FAILED",message:E instanceof Error?E.message:"Payment failed"};e.onError?.(D),g.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(n){console.error("[Recur SDK] Checkout error:",n),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:n instanceof Error?n.message:"An unknown error occurred"};throw e.onError?.(a),n}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
|
|
2190
2189
|
.recur-dialog {
|
|
2191
2190
|
border: none;
|
|
2192
2191
|
border-radius: 12px;
|
|
@@ -2242,7 +2241,7 @@
|
|
|
2242
2241
|
.recur-dialog__close:hover {
|
|
2243
2242
|
background: rgba(0, 0, 0, 0.1);
|
|
2244
2243
|
}
|
|
2245
|
-
`,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
|
|
2244
|
+
`,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 n=document.createElement("recur-payment-form-skeleton");return i.appendChild(n),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 vt(s){return new O(s)}function kt(s){return O.create(s)}var Zt={init:vt,create:kt,RecurCheckout:O,RecurElements:z,createElements:$e};return At(Qt);})();
|
|
2246
2245
|
/*! Bundled license information:
|
|
2247
2246
|
|
|
2248
2247
|
lit-html/node/lit-html.js:
|