@lockerverse/react 0.2.19 → 0.2.21

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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # `@lockerverse/react`
2
2
 
3
- React payment UI for Lockerverse checkout. The host owns product selection; this package renders and completes the payment step with Stripe Elements.
3
+ React payment UI powered by Stripe Custom Checkout Sessions. The host owns
4
+ Product selection; this package renders and completes the payment step.
4
5
 
5
6
  ## Install
6
7
 
@@ -23,11 +24,8 @@ export function Checkout() {
23
24
  name: "Auburn Community",
24
25
  }}
25
26
  communitySlug="auburn"
26
- onPaymentComplete={(payment) => {
27
- console.info("Payment complete", payment.checkoutId);
28
- }}
29
- onPaymentUncertain={({ paymentReference, reason }) => {
30
- console.info("Payment needs status recovery", paymentReference, reason);
27
+ onPaymentComplete={(result) => {
28
+ console.info("Checkout complete", result.paymentReference);
31
29
  }}
32
30
  selection={[{ productSlug: "adult", quantity: 1 }]}
33
31
  theme="dark"
@@ -37,46 +35,10 @@ export function Checkout() {
37
35
  }
38
36
  ```
39
37
 
40
- For a development backend, provide both `environment="development"` and `apiBaseUrl`.
41
-
42
- ```tsx
43
- <LockerversePayment
44
- apiBaseUrl="https://portal-dev.lockerverse.com/api"
45
- communitySlug="luis-c"
46
- environment="development"
47
- selection={[{ productSlug: "adult", quantity: 1 }]}
48
- widgetSlug="new-payment-widget"
49
- />
50
- ```
51
-
52
- ## Styling
53
-
54
- Use `theme="dark"` or `theme="light"`. Brand the default UI with `branding.accentColor`, or override its CSS variables through `style` or a scoped stylesheet.
55
-
56
- ```tsx
57
- <LockerversePayment
58
- // ...checkout props
59
- style={{
60
- "--lockerverse-accent": "#ff6b35",
61
- "--lockerverse-radius": "14px",
62
- }}
63
- />
64
- ```
65
-
66
- The package keeps React, React DOM, and Stripe's React libraries as peer dependencies so it does not ship duplicate framework code. It does not render product selectors or depend on Lockerverse's Next.js application components.
67
-
68
- ## Payment outcomes
69
-
70
- `onPaymentComplete` runs only after Lockerverse reports `success`. A successful payment is terminal, even if the host callback throws.
71
-
72
- If the authoritative total, discount, currency, line items, or connected Stripe account changes, the component displays the new quote before creating a Stripe token. The customer must explicitly submit again.
73
-
74
- An authoritative `failed` result is retryable and the next submit receives a new payment reference. `pending`, unresolved `action_required`, and failed same-reference recovery stay locked so the customer cannot accidentally create a second payment. The optional `onPaymentUncertain` callback receives the retained `paymentReference` and one of these reasons:
75
-
76
- - `pending`
77
- - `action_required`
78
- - `recovery_failed`
79
-
80
- To abandon a locked attempt and intentionally start a new checkout, the host must remount `LockerversePayment` with a new React `key` after resolving the payment status through its own workflow.
38
+ For development, provide both `environment="development"` and `apiBaseUrl`.
39
+ The component supports dark and light themes, an accent color, CSS variables,
40
+ and host CSS. It intentionally does not render Product selection.
81
41
 
82
- Malformed host selections and invalid custom tips render customer-safe validation messages and do not call the Lockerverse API. Product selection remains owned by the host application.
42
+ The package uses Stripe's React Checkout Elements directly. React, React DOM,
43
+ and Stripe libraries are peer dependencies, so consuming applications do not
44
+ receive duplicate framework copies.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { loadStripe } from "@stripe/stripe-js";
2
- import { CSSProperties, ComponentPropsWithoutRef } from "react";
3
- import { CreateLockerverseWidgetOptions, LockerversePaymentResult } from "@lockerverse/sdk/checkout";
1
+ import { CreateLockerverseWidgetOptions, LockerverseCatalog, LockerverseCustomFieldAnswer } from "@lockerverse/sdk/checkout";
2
+ import { loadStripe } from "@stripe/stripe-js/pure/index.js";
3
+ import { CSSProperties, ComponentPropsWithoutRef, PropsWithChildren } from "react";
4
4
  //#region src/types.d.ts
5
5
  type LockerversePaymentSelectionItem = {
6
6
  amountCents: number;
@@ -15,27 +15,64 @@ type LockerversePaymentBranding = {
15
15
  imageUrl?: string | null;
16
16
  name: string;
17
17
  };
18
+ type LockerversePaymentCompletion = {
19
+ paymentReference: string;
20
+ sessionId: string;
21
+ };
18
22
  type LockerversePaymentStyle = CSSProperties & {
19
23
  "--lockerverse-accent"?: string;
20
24
  "--lockerverse-accent-contrast"?: string;
25
+ "--lockerverse-bg"?: string;
26
+ "--lockerverse-border"?: string;
27
+ "--lockerverse-control"?: string;
28
+ "--lockerverse-font-family"?: string;
29
+ "--lockerverse-muted"?: string;
21
30
  "--lockerverse-radius"?: string;
22
- };
23
- type LockerversePaymentUncertain = {
24
- paymentReference: string;
25
- reason: "action_required" | "pending" | "recovery_failed";
31
+ "--lockerverse-text"?: string;
26
32
  };
27
33
  type LockerversePaymentProps = CreateLockerverseWidgetOptions & Omit<ComponentPropsWithoutRef<"section">, "children" | "onError"> & {
28
34
  branding?: LockerversePaymentBranding;
29
- onPaymentComplete?: (payment: LockerversePaymentResult) => void;
30
- onPaymentUncertain?: (payment: LockerversePaymentUncertain) => void;
35
+ includeServiceFee?: boolean;
36
+ onPaymentComplete?: (result: LockerversePaymentCompletion) => void;
37
+ returnUrl?: string;
31
38
  selection: LockerversePaymentSelectionItem[];
32
- stripeLoader?: typeof loadStripe;
39
+ unstable_stripeLoader?: typeof loadStripe;
33
40
  style?: LockerversePaymentStyle;
34
41
  theme?: LockerversePaymentTheme;
42
+ tipCents?: number;
35
43
  };
36
44
  //#endregion
37
- //#region src/lockerverse-payment.d.ts
38
- declare function LockerversePayment({ apiBaseUrl, branding, className, communitySlug, environment, fetch, onError, onPaymentComplete, onPaymentUncertain, requestTimeoutMs, selection, sentryDsn, style, stripeLoader, theme, widgetSlug, ...sectionProps }: LockerversePaymentProps): import("react").JSX.Element;
45
+ //#region src/checkout-session-payment.d.ts
46
+ type CheckoutSessionStripeLoader = typeof loadStripe;
47
+ type LockerverseCheckoutSessionProviderProps = CreateLockerverseWidgetOptions & PropsWithChildren<{
48
+ accentColor?: string;
49
+ email?: string;
50
+ includeServiceFee?: boolean;
51
+ returnUrl: string;
52
+ selection: LockerversePaymentSelectionItem[];
53
+ unstable_stripeLoader?: CheckoutSessionStripeLoader;
54
+ theme?: "dark" | "light";
55
+ tipCents?: number;
56
+ }>;
57
+ type CheckoutContextValue = {
58
+ applyPromoCode: (promoCode: string) => Promise<string | null>;
59
+ catalog: LockerverseCatalog;
60
+ confirm: (contact: {
61
+ customFieldAnswers?: LockerverseCustomFieldAnswer[];
62
+ email: string;
63
+ memberId?: string;
64
+ merchSize?: "XS" | "S" | "M" | "L" | "XL" | "XXL" | "XXXL";
65
+ phone?: string;
66
+ }) => Promise<LockerversePaymentCompletion>;
67
+ paymentReference: string;
68
+ totalCents: number;
69
+ };
70
+ declare function LockerverseCheckoutSessionProvider(props: LockerverseCheckoutSessionProviderProps): import("react").JSX.Element;
71
+ declare function useLockerverseCheckoutSession(): CheckoutContextValue;
72
+ declare function LockerverseCheckoutSessionPaymentForm({ onComplete }: {
73
+ onComplete?: (result: LockerversePaymentCompletion) => void;
74
+ }): import("react").JSX.Element;
75
+ declare function LockerversePayment(props: LockerversePaymentProps): import("react").JSX.Element;
39
76
  //#endregion
40
- export { LockerversePayment, type LockerversePaymentBranding, type LockerversePaymentProps, type LockerversePaymentSelectionItem, type LockerversePaymentStyle, type LockerversePaymentTheme, type LockerversePaymentUncertain };
77
+ export { LockerverseCheckoutSessionPaymentForm, LockerverseCheckoutSessionProvider, type LockerverseCheckoutSessionProviderProps, LockerversePayment, type LockerversePaymentBranding, type LockerversePaymentCompletion, type LockerversePaymentProps, type LockerversePaymentSelectionItem, type LockerversePaymentStyle, type LockerversePaymentTheme, useLockerverseCheckoutSession };
41
78
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/lockerverse-payment.tsx"],"mappings":";;;;KAOY;EACN;EAAqB;;EACrB;EAAqB;;KAEf;KAEA;EACV;EACA;EACA;;KAGU,0BAA0B;EACpC;EACA;EACA;;KAGU;EACV;EACA;;KAGU,0BAA0B,iCACpC,KAAK;EACH,WAAW;EACX,qBAAqB,SAAS;EAC9B,sBAAsB,SAAS;EAC/B,WAAW;EACX,sBAAsB;EACtB,QAAQ;EACR,QAAQ;;;;iBCwkCI,qBACd,YACA,UACA,WACA,eACA,aACA,OACA,SACA,mBACA,oBACA,kBACA,WACA,WACA,OACA,cACA,OACA,eACG,gBACF,0CAAuB,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/checkout-session-payment.tsx"],"mappings":";;;;KAIY;EACN;EAAqB;;EACrB;EAAqB;;KAEf;KAEA;EACV;EACA;EACA;;KAGU;EACV;EACA;;KAGU,0BAA0B;EACpC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU,0BAA0B,iCACpC,KAAK;EACH,WAAW;EACX;EACA,qBAAqB,QAAQ;EAC7B;EACA,WAAW;EACX,+BAA+B;EAC/B,QAAQ;EACR,QAAQ;EACR;;;;KCRC,qCAAqC;KAE9B,0CACV,iCACE;EACE;EACA;EACA;EACA;EACA,WAAW;EACX,wBAAwB;EACxB;EACA;;KAUD;EACH,iBAAiB,sBAAsB;EACvC,SAAS;EACT,UAAU;IACR,qBAAqB;IACrB;IACA;IACA;IACA;QACI,QAAQ;EACd;EACA;;iBAsHc,mCACd,OAAO,0DAAuC,IAAA;iBA8KhC,iCAA6B;iBAyI7B,wCACd;EAEA,cAAc,QAAQ;oBACvB,IAAA;iBAiMe,mBAAmB,OAAO,0CAAuB,IAAA"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{AddressElement as e,Elements as t,PaymentElement as n,useElements as r,useStripe as i}from"@stripe/react-stripe-js";import{loadStripe as a}from"@stripe/stripe-js";import{useEffect as o,useId as s,useMemo as c,useReducer as l,useRef as u,useState as d}from"react";import{Fragment as f,jsx as p,jsxs as m}from"react/jsx-runtime";import{LockerverseSdkError as h,createLockerverseCheckoutClient as g}from"@lockerverse/sdk/checkout";import{array as _,email as v,minLength as y,minValue as b,nonEmpty as x,number as S,object as C,pipe as w,regex as T,safeInteger as E,safeParse as D,strictObject as O,string as k,transform as A,trim as j,union as M}from"valibot";const N=/^#([\da-f]{3}|[\da-f]{6})$/i;function P(e){let t=N.exec(e.trim());if(!t)return;let[,n]=t;if(!n)return;let r=n.length===3?Array.from(n,e=>`${e}${e}`).join(``):n;return[0,2,4].map(e=>Number.parseInt(r.slice(e,e+2),16))}function ee([e,t,n]){let[r=0,i=0,a=0]=[e,t,n].map((e=0)=>{let t=e/255;return t<=.04045?t/12.92:((t+.055)/1.055)**2.4});return .2126*r+.7152*i+.0722*a}function te(e){let t=P(e);if(!t)return;let n=ee(t);return(n+.05)/.05>=1.05/(n+.05)?`#000`:`#fff`}const ne=[`XS`,`S`,`M`,`L`,`XL`,`XXL`,`XXXL`],F=[`15`,`12`,`10`,`5`];function re({enabled:e,error:t,errorId:n,onChange:r,values:i}){if(!e)return null;let a=e=>r({...i,...e});return m(`div`,{className:`lockerverse-payment__tip-box`,children:[p(`p`,{children:`Add a tip to support the Lockerverse platform`}),m(`div`,{"aria-label":`Tip amount`,role:`radiogroup`,children:[F.map(e=>m(`button`,{"aria-pressed":i.tipPercent===e,onClick:()=>a({tipPercent:e}),type:`button`,children:[e,`%`]},e)),p(`button`,{"aria-pressed":i.tipPercent===`custom`,onClick:()=>a({tipPercent:`custom`}),type:`button`,children:`Other`})]}),i.tipPercent===`custom`?m(`label`,{children:[p(`span`,{children:`Custom tip`}),m(`span`,{className:`lockerverse-payment__money-input`,children:[p(`span`,{"aria-hidden":`true`,children:`$`}),p(`input`,{"aria-describedby":t?n:void 0,"aria-invalid":t?`true`:void 0,inputMode:`decimal`,name:`tip`,onChange:e=>a({customTip:e.currentTarget.value}),placeholder:`0.00`,value:i.customTip})]}),t?p(`span`,{className:`lockerverse-payment__field-message`,id:n,children:t}):null]}):p(`input`,{name:`tip`,type:`hidden`,value:i.tipPercent})]})}function ie({checked:e,children:t,name:n,onChange:r}){return m(`label`,{className:`lockerverse-payment__check-row`,children:[p(`input`,{checked:e,name:n,onChange:e=>r(e.currentTarget.checked),type:`checkbox`}),p(`span`,{children:t})]})}function ae({customFields:e,errors:t,fields:n,idPrefix:r,onChange:i,values:a}){let o=e=>i({...a,...e});return m(`div`,{className:`lockerverse-payment__additional-fields`,children:[n.memberId?m(`label`,{children:[p(`span`,{children:`Member ID`}),p(`input`,{name:`memberId`,onChange:e=>o({memberId:e.currentTarget.value}),placeholder:`Optional`,value:a.memberId})]}):null,n.merchSize?m(`label`,{children:[p(`span`,{children:`Size`}),p(`select`,{name:`merchSize`,onChange:e=>o({merchSize:e.currentTarget.value}),value:a.merchSize,children:ne.map(e=>p(`option`,{value:e,children:e},e))})]}):null,n.promoCode?m(`label`,{children:[p(`span`,{children:`Promo code`}),p(`input`,{name:`promoCode`,onChange:e=>o({promoCode:e.currentTarget.value}),placeholder:`Optional`,value:a.promoCode})]}):null,e.map(e=>p(se,{error:t[e.id],field:e,idPrefix:r,onChange:t=>o({customFields:{...a.customFields,[e.id]:t}}),value:a.customFields[e.id]},e.id))]})}function oe({amountCents:e,enabled:t,onChange:n,values:r}){return t?m(ie,{checked:r.includeServiceFee,name:`includeServiceFee`,onChange:e=>n({...r,includeServiceFee:e}),children:[`Add `,L(e),` to help cover processing fees`]}):null}function se({error:e,field:t,idPrefix:n,onChange:r,value:i}){let a=`custom:${t.id}`,o=`${n}-custom-${t.id}`,s=`${o}-error`;switch(t.type){case`text`:case`textarea`:return p(ce,{controlId:o,error:e,errorId:s,field:t,name:a,onChange:r,value:i});case`select`:case`multi_select`:return p(le,{controlId:o,error:e,errorId:s,field:t,name:a,onChange:r,value:i});case`radio`:case`checkboxes`:return p(ue,{controlId:o,error:e,errorId:s,field:t,name:a,onChange:r,value:i});default:return null}}function I({error:e,id:t}){return e?p(`p`,{className:`lockerverse-payment__field-message`,id:t,children:e}):null}function ce({controlId:e,error:t,errorId:n,field:r,name:i,onChange:a,value:o}){let s={"aria-describedby":t?n:void 0,"aria-invalid":t?`true`:void 0,id:e,name:i,onChange:e=>a(e.currentTarget.value),required:r.required,value:typeof o==`string`?o:``};return m(`label`,{htmlFor:e,children:[p(`span`,{children:r.label}),r.type===`textarea`?p(`textarea`,{...s}):p(`input`,{...s}),p(I,{error:t,id:n})]})}function le({controlId:e,error:t,errorId:n,field:r,name:i,onChange:a,value:o}){return m(`label`,{htmlFor:e,children:[p(`span`,{children:r.label}),m(`select`,{"aria-describedby":t?n:void 0,"aria-invalid":t?`true`:void 0,id:e,multiple:r.type===`multi_select`,name:i,onChange:e=>a(r.type===`multi_select`?[...e.currentTarget.selectedOptions].map(e=>e.value):e.currentTarget.value),required:r.required,value:o??(r.type===`multi_select`?[]:``),children:[r.type===`select`?p(`option`,{value:``,children:`Select…`}):null,r.options.map(e=>p(`option`,{value:e.id,children:e.label},e.id))]}),p(I,{error:t,id:n})]})}function ue({controlId:e,error:t,errorId:n,field:r,name:i,onChange:a,value:o}){return m(`fieldset`,{"aria-describedby":t?n:void 0,"aria-invalid":t?`true`:void 0,children:[p(`legend`,{children:r.label}),r.options.map((t,n)=>{let s=Array.isArray(o)?o.includes(t.id):o===t.id;return m(`label`,{className:`lockerverse-payment__check-row`,children:[p(`input`,{checked:s,id:`${e}-${n}`,name:i,onChange:e=>{if(r.type===`radio`){a(t.id);return}let n=Array.isArray(o)?o:[];a(e.currentTarget.checked?[...n,t.id]:n.filter(e=>e!==t.id))},required:r.required,type:r.type===`radio`?`radio`:`checkbox`,value:t.id}),p(`span`,{children:t.label})]},t.id)}),p(I,{error:t,id:n})]})}function L(e){return new Intl.NumberFormat(`en-US`,{currency:`USD`,style:`currency`}).format(e/100)}const R=[`amountCents`,`discountableSubtotalCents`,`discountCents`,`serviceFeeCents`,`subtotalCents`,`tipCents`,`totalCents`];function z(e,t){return R.some(n=>e[n]!==t[n])||e.payment.connectedAccountId!==t.payment.connectedAccountId||e.payment.currency!==t.payment.currency||JSON.stringify(e.appliedDiscount)!==JSON.stringify(t.appliedDiscount)||JSON.stringify(e.lineItems)!==JSON.stringify(t.lineItems)}function B(e){return e.checkoutStatus===`success`?{kind:`success`,payment:e}:e.checkoutStatus===`failed`?{kind:`failed`,payment:e}:{kind:`unresolved`,paymentReference:e.paymentReference,reason:e.checkoutStatus===`action_required`?`action_required`:`pending`}}async function V(e,t,n){if(t.checkoutStatus!==`action_required`)return B(t);if(t.clientSecret)try{await n.handleNextAction({clientSecret:t.clientSecret})}catch{}try{return B(await e.getPaymentStatus(t.paymentReference))}catch{return{kind:`unresolved`,paymentReference:t.paymentReference,reason:`action_required`}}}async function H(e,t,n){let r;try{r=await e.submitPayment(t)}catch(n){if(!(n instanceof h&&n.recoveryRecommended))throw n;try{r=await e.getPaymentStatus(t.checkout.paymentReference)}catch{return{kind:`unresolved`,paymentReference:t.checkout.paymentReference,reason:`recovery_failed`}}}return V(e,r,n)}const U=w(k(),j(),x()),W=w(S(),E(),b(1)),G=w(_(M([O({amountCents:W,productSlug:U}),O({productSlug:U,quantity:W})])),y(1)),de=w(k(),j(),T(/^(?:0|[1-9]\d*)(?:\.\d{1,2})?$/,`Enter a valid tip amount.`),A(e=>Math.round(Number(e)*100)),E(`Enter a valid tip amount.`));function fe(e){let t=D(de,e);return t.success?{cents:t.output,success:!0}:{message:t.issues[0]?.message??`Enter a valid tip amount.`,success:!1}}function K(e){let t=D(G,e);return t.success?{success:!0,value:t.output}:{message:`Lockerverse payment configuration is invalid.`,success:!1}}const q=w(k(),j(),x(`Email is required.`),v(`Enter a valid email address.`)),J=w(k(),j(),x(`Phone is required.`),T(/^\+[1-9]\d{6,14}$/,`Enter a valid phone number.`));function Y(e){return e.trim().replace(/[().\s-]/g,``)}function pe(e,t){let n=t?{...e,phone:Y(e.phone)}:e,r=C(t?{email:q,phone:J}:{email:q}),i=D(r,n);if(i.success)return{errors:{},value:i.output};let a={};for(let e of i.issues){let t=e.path?.[0]?.key;(t===`email`||t===`phone`)&&!a[t]&&(a[t]=e.message)}return{errors:a,value:null}}function me(e,t){let n={};for(let r of e){if(!r.required)continue;let e=`${r.label} is required.`,i=t[r.id],a=r.type===`checkboxes`||r.type===`multi_select`?D(w(_(k()),y(1,e)),i??[]):D(w(k(),j(),x(e)),typeof i==`string`?i:``);a.success||(n[r.id]=a.issues[0]?.message??e)}return n}function he(e,t){switch(t.type){case`loading`:return{configuration:t.configuration,phase:`loading`,revision:e.revision,selectionKey:t.selectionKey};case`ready`:return{catalog:t.catalog,checkoutItems:t.checkoutItems,client:t.client,configuration:t.configuration,phase:`ready`,preparedCheckout:t.preparedCheckout,revision:e.revision+1,selectionKey:t.selectionKey};case`error`:return{configuration:t.configuration,failure:t.failure,phase:`error`,revision:e.revision,selectionKey:t.selectionKey};case`checkout`:return e.phase===`ready`?{...e,preparedCheckout:t.preparedCheckout}:e;default:return e}}function ge(e,t){if(`amountCents`in t){if(e.pricingMode!==`custom`)throw TypeError(`Fixed-price Products do not accept custom amounts.`);if(e.minimumAmountCents!==null&&t.amountCents<e.minimumAmountCents)throw TypeError(`Product amount must be at least ${e.minimumAmountCents} cents.`);return{amountCents:t.amountCents,productId:e.id}}if(e.pricingMode!==`fixed`)throw TypeError(`Custom-amount Products do not accept quantities.`);if(e.minimumQuantity!==null&&t.quantity<e.minimumQuantity)throw TypeError(`Product quantity must be at least ${e.minimumQuantity}.`);if(e.maximumQuantity!==null&&t.quantity>e.maximumQuantity)throw TypeError(`Product quantity must not exceed ${e.maximumQuantity}.`);if(e.inventoryQuantity!==null&&t.quantity>e.inventoryQuantity)throw TypeError(`Requested Product quantity is unavailable.`);return{productId:e.id,quantity:t.quantity}}function X(e,t){if(t.length===0)throw TypeError(`Lockerverse payment requires at least one Product.`);return t.map(t=>{let n=e.products.find(e=>e.slug===t.productSlug);if(!n)throw TypeError(`Product ${t.productSlug} is not available.`);return ge(n,t)})}function Z(e,t){let{apiBaseUrl:n,communitySlug:r,environment:i,fetch:a,requestTimeoutMs:o,sentryDsn:s,widgetSlug:c}=e,l={communitySlug:r,widgetSlug:c,...a?{fetch:a}:{},...t?{onError:t}:{},...o===void 0?{}:{requestTimeoutMs:o},...s===void 0?{}:{sentryDsn:s}};if(n===void 0){if(i===`development`)throw TypeError(`Lockerverse development checkout requires an API base URL.`);return{...l,...i===`production`?{environment:i}:{}}}if(!i)throw TypeError(`Lockerverse development checkout requires an environment.`);return{...l,apiBaseUrl:n,environment:i}}function Q(e,t,n){return e?.configuration===t&&e.selectionKey===n}function _e({apiBaseUrl:e,communitySlug:t,environment:n,fetch:r,onError:i,paymentState:a,requestTimeoutMs:s,selection:d,sentryDsn:f,widgetSlug:p}){let m=c(()=>({apiBaseUrl:e,communitySlug:t,environment:n,fetch:r,requestTimeoutMs:s,sentryDsn:f,widgetSlug:p}),[e,t,n,r,s,f,p]),h=K(d),_=h.success?JSON.stringify(h.value):`invalid-selection`,v=c(()=>h.success?JSON.parse(_):[],[h.success,_]),[y,b]=l(he,{phase:`idle`,revision:0}),x=u(void 0),S=u(void 0),C=u(i);return C.current=i,o(()=>{if(!h.success||a===`submitting`||a===`success`||a===`unresolved`||Q(S.current,m,_)||Q(x.current,m,_))return;let e=!0,t={configuration:m,selectionKey:_};x.current=t,b({configuration:m,selectionKey:_,type:`loading`});async function n(){try{let n=g(Z(m,e=>C.current?.(e))),r=await n.load(),i=X(r,v),a=await n.calculateTotal({...r.widget.fields.serviceFee?{includeServiceFee:!0}:{},items:i});e&&(x.current=void 0,S.current=t,b({catalog:r,checkoutItems:i,client:n,configuration:m,preparedCheckout:a,selectionKey:_,type:`ready`}))}catch(n){e&&(x.current=void 0,S.current=t,b({configuration:m,failure:n instanceof Error?n.message:`Lockerverse payment could not load.`,selectionKey:_,type:`error`}))}}return n(),()=>{e=!1,Q(x.current,m,_)&&(x.current=void 0)}},[m,h.success,a,_,v]),{selectionError:h.success?void 0:h.message,session:y,updateCheckout:e=>b({preparedCheckout:e,type:`checkout`})}}function $(e){return new Intl.NumberFormat(`en-US`,{currency:`USD`,style:`currency`}).format(e/100)}function ve(e,t){return t.tipPercent===`custom`?fe(t.customTip):{cents:Math.round(e*Number(t.tipPercent)/100),success:!0}}const ye=[{callingCode:`+1`,label:`🇺🇸 +1`,value:`US`},{callingCode:`+52`,label:`🇲🇽 +52`,value:`MX`},{callingCode:`+380`,label:`🇺🇦 +380`,value:`UA`},{callingCode:`+48`,label:`🇵🇱 +48`,value:`PL`},{callingCode:`+1`,label:`🇨🇦 +1`,value:`CA`},{callingCode:`+49`,label:`🇩🇪 +49`,value:`DE`},{callingCode:`+44`,label:`🇬🇧 +44`,value:`GB`},{callingCode:`+46`,label:`🇸🇪 +46`,value:`SE`},{callingCode:`+358`,label:`🇫🇮 +358`,value:`FI`},{callingCode:`+1`,label:`🇵🇷 +1`,value:`PR`}];function be(e,t){return e.trim().startsWith(`+`)?e:`${ye.find(e=>e.value===t)?.callingCode??`+1`}${e}`}function xe(e,t){return e.map(e=>{let n=t[e.id];return e.type===`checkboxes`||e.type===`multi_select`?{fieldId:e.id,value:Array.isArray(n)?n:[]}:{fieldId:e.id,value:typeof n==`string`?n:``}})}function Se(e,t,n,r){return{email:n,...e.widget.fields.serviceFee?{includeServiceFee:t.includeServiceFee}:{},...e.widget.fields.promoCode&&t.promoCode.trim()?{promoCode:t.promoCode.trim()}:{},...e.widget.fields.tipping?{tipCents:r}:{}}}async function Ce(e,t){let n=e.getElement(`address`,{mode:t}),r=t===`billing`?`Billing`:`Shipping`;if(!n)throw Error(`${r} address is still loading.`);let i=await n.getValue();if(!i.complete)throw Error(`${r} address is required.`);return i.value}function we(e,t,n,r){if(e.widget.fields.shipping)return n.shippingMatchesBilling?r:Ce(t,`shipping`)}function Te({billingAddress:e,catalog:t,email:n,phone:r,shippingAddress:i}){return{payment_method_data:{billing_details:{address:e.address,email:n,name:e.name,...t.widget.fields.phone?{phone:r}:{}}},...i?{shipping:{address:i.address,name:i.name,phone:t.widget.fields.phone?r:i.phone??null}}:{}}}function Ee({catalog:e,confirmationToken:t,email:n,fieldValues:r,phone:i}){return{confirmationToken:t,customFieldAnswers:xe(e.widget.customFields,r.customFields),email:n,...e.widget.fields.memberId&&r.memberId.trim()?{memberId:r.memberId.trim()}:{},...e.widget.fields.merchSize?{merchSize:r.merchSize}:{},...e.widget.fields.phone?{phone:i}:{}}}async function De({catalog:e,checkoutItems:t,client:n,elements:r,email:i,fieldValues:a,phone:o,quote:s,stripe:c}){let l=i.trim().toLowerCase(),u=Y(o),d=ve(s.subtotalCents,a);if(!d.success)throw Error(d.message);let f=Se(e,a,l,d.cents),p=await n.calculateTotal({...f,items:t});if(await r.update({amount:p.totalCents}),z(s,p))return{kind:`quote_changed`,quote:p};let m=await r.submit();if(m.error)throw Error(m.error.message);let h=await Ce(r,`billing`),g=await we(e,r,a,h),_=await c.createConfirmationToken({elements:r,params:Te({billingAddress:h,catalog:e,email:l,phone:u,shippingAddress:g})});if(_.error)throw Error(_.error.message);let v=await H(n,{checkout:p,submission:Ee({catalog:e,confirmationToken:_.confirmationToken.id,email:l,fieldValues:a,phone:u})},c);return v.kind===`failed`?{kind:`payment_failed`,message:`Payment was declined. Check your payment details and try again.`}:v.kind===`unresolved`?{kind:`payment_unresolved`,paymentReference:v.paymentReference,reason:v.reason}:{kind:`payment`,payment:v.payment,quote:p}}function Oe({accentColor:e,catalog:n,checkoutItems:r,client:i,onPaymentComplete:a,onPaymentUncertain:o,onQuoteChange:s,quote:l,onStateChange:u,stripeLoader:d,theme:f}){let m=c(()=>d(n.payment.publishableKey,l.payment.connectedAccountId?{stripeAccount:l.payment.connectedAccountId}:void 0),[n.payment.publishableKey,l.payment.connectedAccountId,d]);return p(t,{options:{amount:l.totalCents,appearance:{rules:{".Input:focus":{borderColor:e,boxShadow:`none`,outline:`none`}},theme:f===`light`?`stripe`:`night`,variables:{borderRadius:`8px`,colorBackground:f===`light`?`#f5f6f7`:`#101010`,colorDanger:f===`light`?`#c52b3e`:`#ef4444`,colorPrimary:e,colorText:f===`light`?`#121416`:`#ffffff`,colorTextPlaceholder:f===`light`?`#72767d`:`#6b6b6b`,colorTextSecondary:f===`light`?`#62666d`:`#a1a1aa`,focusBoxShadow:`none`,focusOutline:`none`,fontFamily:`Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif`,fontSizeBase:`16px`}},currency:l.payment.currency,excludedPaymentMethodTypes:[`us_bank_account`],mode:`payment`,syncAddressCheckbox:`none`},stripe:m,children:p(Ie,{catalog:n,checkoutItems:r,client:i,onPaymentComplete:a,onPaymentUncertain:o,onQuoteChange:s,onStateChange:u,quote:l})},`${n.payment.publishableKey}:${l.payment.connectedAccountId??`platform`}`)}function ke({label:e}){return m(`div`,{className:`lockerverse-payment__stripe-loader`,role:`status`,children:[p(`p`,{children:e}),m(`div`,{"aria-hidden":`true`,children:[p(`span`,{}),p(`span`,{}),p(`span`,{})]})]})}function Ae({onError:e,onReady:t,ready:r}){return m(`div`,{className:`lockerverse-payment__stripe-element`,"data-ready":r,children:[r?null:p(ke,{label:`Loading payment form...`}),p(n,{onLoadError:({error:t})=>e(t.message??`Payment form failed to load.`),onReady:t,options:{business:{name:`Lockerverse`},fields:{billingDetails:{email:`auto`}},layout:`tabs`,terms:{applePay:`auto`,auBecsDebit:`never`,bancontact:`never`,card:`always`,cashapp:`never`,googlePay:`never`,ideal:`never`,paypal:`auto`,sepaDebit:`never`,sofort:`never`,usBankAccount:`never`},wallets:{applePay:`auto`,googlePay:`never`}}})]})}function je({label:t,mode:n,onError:r,onReady:i,ready:a}){return m(`div`,{className:`lockerverse-payment__address`,children:[p(`h2`,{children:t}),m(`div`,{className:`lockerverse-payment__stripe-element lockerverse-payment__stripe-element--address`,"data-ready":a,children:[a?null:p(ke,{label:`Loading ${t.toLowerCase()}...`}),p(e,{onLoadError:({error:e})=>r(e.message??`${t} failed to load.`),onReady:i,options:{autocomplete:{mode:`automatic`},mode:n}})]})]})}function Me({message:e}){return e?p(`p`,{className:`lockerverse-payment__field-message`,role:`alert`,children:e}):null}function Ne({customFieldErrors:e,emailRef:t,form:n,parsedTipSuccess:r,phoneRef:i,validationErrors:a}){if(a.email){t.current?.focus();return}if(a.phone){i.current?.focus();return}if(!r){n.querySelector(`[name="tip"]`)?.focus();return}let[o]=Object.keys(e);o&&n.querySelector(`[name="custom:${o}"]`)?.focus()}function Pe({onPaymentComplete:e,onPaymentUncertain:t,onQuoteChange:n,onStateChange:r,result:i,setDisplayedTotalCents:a,setPaymentError:o,setTerminalState:s}){if(i.kind===`quote_changed`){let e=`The total changed to ${$(i.quote.totalCents)}. Review it and pay again.`;n(i.quote,e),a(i.quote.totalCents),r(`idle`);return}if(i.kind===`payment_failed`){o(i.message),r(`error`);return}if(i.kind===`payment_unresolved`){s({kind:`unresolved`,message:`Payment is still processing. Do not submit it again.`}),r(`unresolved`);try{t?.({paymentReference:i.paymentReference,reason:i.reason})}catch{}return}n(i.quote),s({kind:`success`,message:`Payment completed successfully.`}),r(`success`);try{e?.(i.payment)}catch{}}function Fe({email:e,emailErrorId:t,emailId:n,emailRef:r,errors:i,onEmailChange:a,onPhoneChange:o,onPhoneCountryChange:s,phone:c,phoneCountry:l,phoneEnabled:u,phoneErrorId:d,phoneId:h,phoneRef:g}){return m(`div`,{className:`lockerverse-payment__contact`,children:[p(`label`,{htmlFor:n,children:`Email`}),p(`input`,{"aria-describedby":i.email?t:void 0,"aria-invalid":i.email?`true`:void 0,autoComplete:`email`,id:n,name:`email`,onChange:e=>a(e.currentTarget.value),placeholder:`name@example.com`,ref:r,type:`email`,value:e}),i.email?p(`p`,{className:`lockerverse-payment__field-message`,id:t,children:i.email}):null,u?m(f,{children:[p(`label`,{htmlFor:h,children:`Phone`}),m(`div`,{className:`lockerverse-payment__phone-control`,children:[p(`select`,{"aria-label":`Phone number country`,name:`phoneCountry`,onChange:e=>s(e.currentTarget.value),value:l,children:ye.map(e=>p(`option`,{value:e.value,children:e.label},e.value))}),p(`input`,{"aria-describedby":i.phone?d:void 0,"aria-invalid":i.phone?`true`:void 0,autoComplete:`tel`,id:h,inputMode:`tel`,name:`phone`,onChange:e=>o(e.currentTarget.value),placeholder:`(201) 555-0123`,ref:g,type:`tel`,value:c})]}),i.phone?p(`p`,{className:`lockerverse-payment__field-message`,id:d,children:i.phone}):null]}):null]})}function Ie({catalog:e,checkoutItems:t,client:n,onPaymentComplete:a,onPaymentUncertain:c,onQuoteChange:l,onStateChange:f,quote:h}){let[g,_]=d(``),[v,y]=d(``),[b,x]=d(`US`),[S,C]=d({}),[w,T]=d(),[E,D]=d({}),[O,k]=d(),[A,j]=d(!1),[M,N]=d(),[P,ee]=d(!1),[te,ne]=d(!1),[F,se]=d(!1),[I,ce]=d({customFields:{},customTip:``,includeServiceFee:e.widget.fields.serviceFee,memberId:``,merchSize:`M`,promoCode:``,shippingMatchesBilling:!0,tipPercent:`10`}),[le,ue]=d(h.totalCents),L=u(null),R=u(null),z=u(null),B=r(),V=i(),H=`lockerverse-${s()}`,U=`${H}-email`,W=`${U}-error`,G=`${H}-phone`,de=`${G}-error`,fe=`${H}-tip-error`,K=e.widget.fields.tipping?ve(h.subtotalCents,I):{cents:0,success:!0},q=K.success?K.cents:null,J=q??0,Y=le-J,he=!e.widget.fields.shipping||I.shippingMatchesBilling||F;o(()=>{if(q===null)return;let t=e.widget.fields.serviceFee&&I.includeServiceFee?h.serviceFeeCents||Math.round(h.subtotalCents*e.pricingPolicy.serviceFeeRateBasisPoints/1e4):0,n=h.totalCents-h.serviceFeeCents-h.tipCents+t+q;ue(n),B?.update({amount:n})},[e.widget.fields.serviceFee,e.widget.fields.tipping,B,I.includeServiceFee,I.tipPercent,I.customTip,q,h.serviceFeeCents,h.tipCents,h.totalCents]),o(()=>{A&&z.current?.focus()},[A]);function ge(e){C(t=>{let n={...t};return delete n[e],n})}function X(e){ce(e),D({}),k(void 0)}function Z(e){T(e),f(`error`)}async function Q(r){r.preventDefault();let i=pe({email:g,phone:be(v,b)},e.widget.fields.phone),o=me(e.widget.customFields,I.customFields);if(!(i.value&&K.success)||Object.keys(o).length>0){C(i.errors),D(o),k(K.success?void 0:K.message),f(`invalid`);let e=r.currentTarget;queueMicrotask(()=>{Ne({customFieldErrors:o,emailRef:L,form:e,parsedTipSuccess:K.success,phoneRef:R,validationErrors:i.errors})});return}if(C({}),D({}),!(B&&V)){T(`Payment form is still loading.`),f(`error`);return}T(void 0),j(!0),f(`submitting`);try{Pe({onPaymentComplete:a,onPaymentUncertain:c,onQuoteChange:l,onStateChange:f,result:await De({catalog:e,checkoutItems:t,client:n,elements:B,email:g,fieldValues:I,phone:be(v,b),quote:h,stripe:V}),setDisplayedTotalCents:ue,setPaymentError:T,setTerminalState:N})}catch(e){T(e instanceof Error?e.message:`Payment could not be completed.`),f(`error`)}finally{j(!1)}}return M?p(`p`,{className:`lockerverse-payment__payment-status`,ref:z,role:`status`,tabIndex:-1,children:M.message}):m(`form`,{"aria-busy":A,className:`lockerverse-payment__form`,noValidate:!0,onSubmit:Q,children:[p(`div`,{"data-lockerverse-input-region":``,inert:A?!0:void 0,children:m(`fieldset`,{className:`lockerverse-payment__input-fieldset`,disabled:A,children:[p(re,{enabled:e.widget.fields.tipping,error:O,errorId:fe,onChange:X,values:I}),p(Fe,{email:g,emailErrorId:W,emailId:U,emailRef:L,errors:S,onEmailChange:e=>{_(e),ge(`email`)},onPhoneChange:e=>{y(e),ge(`phone`)},onPhoneCountryChange:x,phone:v,phoneCountry:b,phoneEnabled:e.widget.fields.phone,phoneErrorId:de,phoneId:G,phoneRef:R}),p(Ae,{onError:Z,onReady:()=>ee(!0),ready:P}),p(je,{label:`Billing address`,mode:`billing`,onError:Z,onReady:()=>ne(!0),ready:te}),e.widget.fields.shipping?m(`div`,{className:`lockerverse-payment__shipping`,children:[p(ie,{checked:I.shippingMatchesBilling,name:`shippingMatchesBilling`,onChange:e=>{X({...I,shippingMatchesBilling:e}),e||se(!1)},children:`Shipping is same as billing information`}),I.shippingMatchesBilling?null:p(je,{label:`Shipping address`,mode:`shipping`,onError:Z,onReady:()=>se(!0),ready:F})]}):null,p(ae,{customFields:e.widget.customFields,errors:E,fields:e.widget.fields,idPrefix:H,onChange:X,values:I}),m(`div`,{className:`lockerverse-payment__actions`,children:[p(oe,{amountCents:h.serviceFeeCents||Math.round(h.subtotalCents*e.pricingPolicy.serviceFeeRateBasisPoints/1e4),enabled:e.widget.fields.serviceFee,onChange:X,values:I}),p(`button`,{"aria-busy":A,"aria-label":`Process payment for ${$(le)} total`,disabled:A||!(P&&te&&he),type:`submit`,children:A?`Processing…`:`Process Payment (${$(Y)})${J>0?` + ${$(J)} tip`:``}`})]})]})}),A?p(`p`,{className:`lockerverse-payment__payment-status`,ref:z,role:`status`,tabIndex:-1,children:`Processing payment…`}):null,p(Me,{message:w})]})}function Le(){return m(`div`,{className:`lockerverse-payment__skeleton-loader-block`,children:[p(`span`,{className:`lockerverse-payment__skeleton-loader-label`}),m(`div`,{className:`lockerverse-payment__skeleton-loader-content`,children:[p(`span`,{className:`lockerverse-payment__skeleton-loader-full`}),m(`div`,{className:`lockerverse-payment__skeleton-loader-grid`,children:[p(`span`,{className:`lockerverse-payment__skeleton-loader-half`}),p(`span`,{className:`lockerverse-payment__skeleton-loader-half`})]})]})]})}function Re(){return m(`div`,{className:`lockerverse-payment__loading`,children:[p(`span`,{"aria-live":`polite`,className:`lockerverse-payment__sr-only`,role:`status`,children:`Loading payment…`}),m(`div`,{"aria-hidden":`true`,className:`lockerverse-payment__skeleton`,children:[m(`div`,{className:`lockerverse-payment__skeleton-branding`,children:[p(`span`,{className:`lockerverse-payment__skeleton-avatar`}),p(`span`,{className:`lockerverse-payment__skeleton-community`})]}),m(`div`,{className:`lockerverse-payment__skeleton-contact`,children:[m(`div`,{className:`lockerverse-payment__skeleton-field`,children:[p(`span`,{className:`lockerverse-payment__skeleton-label`}),p(`span`,{className:`lockerverse-payment__skeleton-input`})]}),m(`div`,{className:`lockerverse-payment__skeleton-field`,children:[p(`span`,{className:`lockerverse-payment__skeleton-label`}),p(`span`,{className:`lockerverse-payment__skeleton-input`})]})]}),p(Le,{}),p(Le,{}),m(`div`,{className:`lockerverse-payment__skeleton-actions`,children:[p(`span`,{className:`lockerverse-payment__skeleton-check-line`}),p(`span`,{className:`lockerverse-payment__skeleton-button`})]})]})]})}function ze({apiBaseUrl:e,branding:t,className:n,communitySlug:r,environment:i,fetch:s,onError:c,onPaymentComplete:l,onPaymentUncertain:u,requestTimeoutMs:f,selection:h,sentryDsn:g,style:_,stripeLoader:v=a,theme:y=`dark`,widgetSlug:b,...x}){let[S,C]=d(),[w,T]=d(`idle`),{selectionError:E,session:D,updateCheckout:O}=_e({apiBaseUrl:e,communitySlug:r,environment:i,fetch:s,onError:c,paymentState:w,requestTimeoutMs:f,selection:h,sentryDsn:g,widgetSlug:b});o(()=>{D.phase===`loading`&&C(void 0)},[D.phase]),o(()=>{D.phase===`ready`&&T(e=>e===`success`||e===`unresolved`?e:`idle`)},[D.phase,D.revision]);let k=[`lockerverse-payment`,n].filter(Boolean).join(` `),A=te(_?.[`--lockerverse-accent`]??t?.accentColor??`#38d77a`),j={..._,...t?.accentColor&&_?.[`--lockerverse-accent`]===void 0?{"--lockerverse-accent":t.accentColor}:{},...A&&_?.[`--lockerverse-accent-contrast`]===void 0?{"--lockerverse-accent-contrast":A}:{}};if(E)return p(`section`,{...x,className:k,"data-lockerverse-theme":y,role:`alert`,style:j,children:E});if(D.phase===`error`)return p(`section`,{...x,className:k,"data-lockerverse-theme":y,role:`alert`,children:D.failure});if(D.phase!==`ready`)return p(`section`,{...x,"aria-busy":`true`,"aria-label":`Payment`,className:k,"data-lockerverse-theme":y,children:p(Re,{})});let{catalog:M,checkoutItems:N,client:P,preparedCheckout:ee}=D;return m(`section`,{...x,"aria-label":`Payment`,className:k,"data-lockerverse-theme":y,"data-payment-state":w,style:j,children:[m(`header`,{children:[M.widget.showCommunityBranding&&t?m(`div`,{className:`lockerverse-payment__branding`,children:[t.imageUrl?p(`img`,{alt:t.name,height:`48`,src:t.imageUrl,width:`48`}):null,p(`strong`,{children:t.name})]}):null,p(`h1`,{children:M.widget.title??M.widget.name}),M.widget.description?p(`p`,{children:M.widget.description}):null]}),S?p(`p`,{className:`lockerverse-payment__payment-status`,role:`status`,children:S}):null,p(Oe,{accentColor:_?.[`--lockerverse-accent`]??t?.accentColor??`#38d77a`,catalog:M,checkoutItems:N,client:P,onPaymentComplete:l,onPaymentUncertain:u,onQuoteChange:(e,t)=>{C(t),O(e)},onStateChange:T,quote:ee,stripeLoader:v,theme:y})]})}export{ze as LockerversePayment};
1
+ import{createLockerverseCheckoutClient as e}from"@lockerverse/sdk/checkout";import{BillingAddressElement as t,CheckoutElementsProvider as n,PaymentElement as r,ShippingAddressElement as i,useCheckoutElements as a}from"@stripe/react-stripe-js/checkout";import{loadStripe as o}from"@stripe/stripe-js/pure/index.js";import{createContext as s,useContext as c,useEffect as l,useMemo as u,useRef as d,useState as f}from"react";import{jsx as p,jsxs as m}from"react/jsx-runtime";const h=s(null);function g(e,t){if(!t.length)throw Error(`Select at least one Product before opening checkout.`);return t.map(t=>{let n=e.products.find(e=>e.slug===t.productSlug);if(!n)throw Error(`Product ${t.productSlug} is unavailable.`);return`amountCents`in t?{amountCents:t.amountCents,productId:n.id}:{productId:n.id,quantity:t.quantity}})}function _(e){let t={communitySlug:e.communitySlug,...e.fetch?{fetch:e.fetch}:{},...e.onError?{onError:e.onError}:{},...e.requestTimeoutMs===void 0?{}:{requestTimeoutMs:e.requestTimeoutMs},...e.sentryDsn===void 0?{}:{sentryDsn:e.sentryDsn},widgetSlug:e.widgetSlug};return e.apiBaseUrl?{...t,apiBaseUrl:e.apiBaseUrl,environment:e.environment}:{...t,environment:`production`}}function v({children:e,loaded:t}){let n=a();if(n.type===`loading`)return p(`div`,{role:`status`,children:`Loading secure payment form…`});if(n.type===`error`)return p(`div`,{role:`alert`,children:n.error.message});let{checkout:r}=n,i={async applyPromoCode(e){let n=await r.runServerUpdate(()=>t.client.updateSessionDiscount({paymentReference:t.session.paymentReference,...e.trim()?{promoCode:e.trim()}:{}}));return n.type===`error`?n.error.message:null},catalog:t.catalog,async confirm(e){let n=await r.runServerUpdate(()=>t.client.updateSessionDetails({...e.customFieldAnswers?{customFieldAnswers:e.customFieldAnswers}:{},email:e.email,...e.memberId?{memberId:e.memberId}:{},...e.merchSize?{merchSize:e.merchSize}:{},paymentReference:t.session.paymentReference,...e.phone?{phone:e.phone}:{}}));if(n.type===`error`)throw Error(n.error.message);let i=await x(r,e.email,e.phone??``);if(`error`in i)throw Error(i.error);let a=await r.confirm({email:i.email,...i.phone?{phoneNumber:i.phone}:{},redirect:`if_required`,returnUrl:t.returnUrl});if(a.type===`error`)throw Error(a.error.message);return{paymentReference:t.session.paymentReference,sessionId:t.session.sessionId}},paymentReference:t.session.paymentReference,totalCents:r.total.total.minorUnitsAmount};return p(h.Provider,{value:i,children:e})}function y(t){let[r,i]=f(null),[a,s]=f(null),[c,h]=f(0),y=d(null),b=JSON.stringify({email:t.email,includeServiceFee:t.includeServiceFee,returnUrl:t.returnUrl,selection:t.selection,tipCents:t.tipCents}),x=d({email:t.email,includeServiceFee:t.includeServiceFee,key:b,requestKey:globalThis.crypto.randomUUID(),returnUrl:t.returnUrl,selection:t.selection,tipCents:t.tipCents}),S=u(()=>_(t),[t.apiBaseUrl,t.communitySlug,t.environment,t.fetch,t.onError,t.requestTimeoutMs,t.sentryDsn,t.widgetSlug]);l(()=>{let t=!0;if(y.current?.clientOptions!==S||c>0){let t=e(S),n=x.current;y.current={clientOptions:S,promise:(async()=>{let e=await t.load(),r=g(e,n.selection),i=n.includeServiceFee??e.widget.fields.serviceFee,a=await t.createSession({...n.email?{email:n.email}:{},...e.widget.fields.serviceFee?{includeServiceFee:i}:{},items:r,requestKey:n.requestKey,returnUrl:n.returnUrl,...n.tipCents===void 0?{}:{tipCents:n.tipCents}});return{catalog:e,client:t,returnUrl:n.returnUrl,session:a}})()}}return i(null),s(null),y.current.promise.then(e=>{t&&i(e)}).catch(e=>{t&&s(e instanceof Error?e.message:`Unable to load checkout.`)}),()=>{t=!1}},[S,c]);let C=u(()=>r?(t.unstable_stripeLoader??o)(r.catalog.payment.publishableKey,{betas:[`custom_checkout_server_updates_1`],...r.session.connectedAccountId?{stripeAccount:r.session.connectedAccountId}:{}}):null,[r,t.unstable_stripeLoader]),w=u(()=>r?{clientSecret:r.session.clientSecret,elementsOptions:{appearance:{theme:t.theme===`light`?`stripe`:`night`,variables:{colorBackground:`transparent`,colorPrimary:t.accentColor??`#38d77a`}}}}:null,[r,t.accentColor,t.theme]);return b===x.current.key?a?m(`div`,{className:`lockerverse-payment__payment-status`,role:`alert`,children:[p(`p`,{children:a}),p(`button`,{onClick:()=>h(e=>e+1),type:`button`,children:`Try again`})]}):r&&w?p(n,{options:w,stripe:C,children:p(v,{loaded:r,children:t.children})}):m(`div`,{className:`lockerverse-payment__loading`,children:[p(`span`,{className:`lockerverse-payment__sr-only`,role:`status`,children:`Preparing secure checkout…`}),m(`div`,{"aria-hidden":`true`,className:`lockerverse-payment__skeleton`,children:[p(`div`,{className:`lockerverse-payment__skeleton-contact`,children:m(`div`,{className:`lockerverse-payment__skeleton-field`,children:[p(`span`,{className:`lockerverse-payment__skeleton-label`}),p(`span`,{className:`lockerverse-payment__skeleton-input`})]})}),m(`div`,{className:`lockerverse-payment__skeleton-loader-block`,children:[p(`span`,{className:`lockerverse-payment__skeleton-loader-label`}),p(`span`,{className:`lockerverse-payment__skeleton-loader-full`})]}),p(`div`,{className:`lockerverse-payment__skeleton-actions`,children:p(`span`,{className:`lockerverse-payment__skeleton-button`})})]})]}):p(`div`,{className:`lockerverse-payment__payment-status`,role:`alert`,children:`Checkout selection changed. Remount this payment component for the new selection.`})}function b(){let e=c(h);if(!e)throw Error(`useLockerverseCheckoutSession must be used inside LockerverseCheckoutSessionProvider.`);return e}async function x(e,t,n){let r=t.trim().toLowerCase();if(!r)return{error:`Email is required.`};let i=await e.updateEmail(r);if(i.type===`error`)return{error:i.error.message};let a=n.trim();if(a&&(await e.updatePhoneNumber(a)).type===`error`)return{error:`Phone number is invalid.`};let o=await e.validateElements();return o.type===`error`?{error:o.error.message}:{email:r,phone:a}}function S({fields:e,onChange:t,values:n}){return e.map(e=>{let r=n[e.id]??(e.type.includes(`multi`)||e.type===`checkboxes`?[]:``);if(e.type===`textarea`)return m(`label`,{children:[p(`span`,{children:e.label}),p(`textarea`,{name:e.id,onChange:n=>t(e.id,n.currentTarget.value),required:e.required,value:String(r)})]},e.id);if(e.type===`select`)return m(`label`,{children:[p(`span`,{children:e.label}),m(`select`,{name:e.id,onChange:n=>t(e.id,n.currentTarget.value),required:e.required,value:String(r),children:[p(`option`,{value:``,children:`Select…`}),e.options.map(e=>p(`option`,{value:e.id,children:e.label},e.id))]})]},e.id);if(e.type===`radio`||e.type===`checkboxes`||e.type===`multi_select`){let n=Array.isArray(r)?r:[r];return m(`fieldset`,{children:[p(`legend`,{children:e.label}),e.options.map(r=>{let i=n.includes(r.id);return m(`label`,{className:`lockerverse-payment__choice`,children:[p(`input`,{checked:i,name:e.id,onChange:()=>{if(e.type===`radio`){t(e.id,r.id);return}t(e.id,i?n.filter(e=>e!==r.id):[...n,r.id])},required:e.required&&n.length===0,type:e.type===`radio`?`radio`:`checkbox`,value:r.id}),p(`span`,{children:r.label})]},r.id)})]},e.id)}return m(`label`,{children:[p(`span`,{children:e.label}),p(`input`,{name:e.id,onChange:n=>t(e.id,n.currentTarget.value),required:e.required,type:`text`,value:String(r)})]},e.id)})}function C({onComplete:e}){let{applyPromoCode:n,catalog:a,confirm:o,totalCents:s}=b(),[c,l]=f(``),[u,d]=f(``),[h,g]=f(``),[_,v]=f(``),[y,x]=f({}),[C,w]=f(``),[T,E]=f(null),[D,O]=f(!1);async function k(){O(!0),E(null);try{E(await n(C))}catch(e){E(e instanceof Error?e.message:`Unable to update checkout.`)}finally{O(!1)}}async function A(t){t.preventDefault(),O(!0),E(null);try{e?.(await o({customFieldAnswers:a.widget.customFields.map(e=>({fieldId:e.id,value:y[e.id]??null})),email:c,...h?{memberId:h}:{},..._?{merchSize:_}:{},...u?{phone:u}:{}}))}catch(e){E(e instanceof Error?e.message:`Unable to complete checkout.`)}finally{O(!1)}}return m(`form`,{className:`lockerverse-payment__form`,onSubmit:A,children:[m(`header`,{children:[p(`h1`,{children:a.widget.title??a.widget.name}),a.widget.description?p(`p`,{children:a.widget.description}):null]}),m(`div`,{className:`lockerverse-payment__contact`,children:[m(`label`,{children:[p(`span`,{children:`Email`}),p(`input`,{autoComplete:`email`,inputMode:`email`,name:`email`,onChange:e=>l(e.currentTarget.value),placeholder:`you@example.com`,required:!0,type:`email`,value:c})]}),a.widget.fields.phone?m(`label`,{children:[p(`span`,{children:`Phone`}),p(`input`,{autoComplete:`tel`,inputMode:`tel`,name:`phone`,onChange:e=>d(e.currentTarget.value),placeholder:`+1 555 555 5555`,required:!0,type:`tel`,value:u})]}):null,a.widget.fields.memberId?m(`label`,{children:[p(`span`,{children:`Member ID`}),p(`input`,{name:`memberId`,onChange:e=>g(e.currentTarget.value),required:!0,type:`text`,value:h})]}):null,a.widget.fields.merchSize?m(`label`,{children:[p(`span`,{children:`Merch size`}),m(`select`,{name:`merchSize`,onChange:e=>v(e.currentTarget.value),required:!0,value:_,children:[p(`option`,{value:``,children:`Select…`}),[`XS`,`S`,`M`,`L`,`XL`,`XXL`,`XXXL`].map(e=>p(`option`,{value:e,children:e},e))]})]}):null]}),m(`div`,{className:`lockerverse-payment__address`,children:[p(`h2`,{children:`Billing information`}),p(t,{})]}),a.widget.fields.shipping?m(`div`,{className:`lockerverse-payment__shipping`,children:[p(`h2`,{children:`Shipping information`}),p(i,{})]}):null,m(`div`,{className:`lockerverse-payment__stripe-element`,hidden:s===0,children:[p(`h2`,{children:`Payment details`}),p(r,{})]}),a.widget.fields.promoCode?m(`div`,{className:`lockerverse-payment__additional-fields`,children:[m(`label`,{children:[p(`span`,{children:`Promo code`}),p(`input`,{name:`promoCode`,onChange:e=>w(e.currentTarget.value),placeholder:`Optional`,value:C})]}),p(`button`,{disabled:D,onClick:k,type:`button`,children:C.trim()?`Apply code`:`Remove code`})]}):null,a.widget.customFields.length?p(`div`,{className:`lockerverse-payment__custom-fields`,children:p(S,{fields:a.widget.customFields,onChange:(e,t)=>x(n=>({...n,[e]:t})),values:y})}):null,T?p(`div`,{role:`alert`,children:T}):null,p(`div`,{className:`lockerverse-payment__actions`,children:p(`button`,{disabled:D,type:`submit`,children:s===0?`Complete free order`:`Pay $${(s/100).toFixed(2)}`})})]})}function w(e){let{apiBaseUrl:t,branding:n,className:r,communitySlug:i,environment:a,fetch:o,includeServiceFee:s,onError:c,onPaymentComplete:l,requestTimeoutMs:u,returnUrl:d,selection:f,sentryDsn:h,unstable_stripeLoader:g,style:_,theme:v=`dark`,tipCents:b,widgetSlug:x,...S}=e,w=d??(globalThis.location===void 0?`https://lockerverse.com`:globalThis.location.href),T=[`lockerverse-payment`,r].filter(Boolean).join(` `),E=t?{apiBaseUrl:t,communitySlug:i,environment:a,widgetSlug:x}:{communitySlug:i,environment:`production`,widgetSlug:x},D=n?.accentColor?{..._,"--lockerverse-accent":n.accentColor}:_;return m(`section`,{...S,className:T,"data-lockerverse-theme":v,style:D,children:[n?m(`div`,{className:`lockerverse-payment__branding`,children:[n.imageUrl?p(`img`,{alt:``,height:`48`,src:n.imageUrl,width:`48`}):null,p(`strong`,{children:n.name})]}):null,p(y,{...E,...n?.accentColor?{accentColor:n.accentColor}:{},...o?{fetch:o}:{},...s===void 0?{}:{includeServiceFee:s},...c?{onError:c}:{},...u===void 0?{}:{requestTimeoutMs:u},returnUrl:w,selection:f,...h===void 0?{}:{sentryDsn:h},...g?{unstable_stripeLoader:g}:{},theme:v,...b===void 0?{}:{tipCents:b},children:p(C,{...l?{onComplete:l}:{}})})]})}export{C as LockerverseCheckoutSessionPaymentForm,y as LockerverseCheckoutSessionProvider,w as LockerversePayment,b as useLockerverseCheckoutSession};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["formatMoney"],"sources":["../src/accent-contrast.ts","../src/checkout-fields.tsx","../src/payment-attempt.ts","../src/payment-input.ts","../src/payment-validation.ts","../src/use-checkout-session.ts","../src/lockerverse-payment.tsx"],"sourcesContent":["const HEX_COLOR = /^#([\\da-f]{3}|[\\da-f]{6})$/i;\n\nfunction parseHexColor(color: string) {\n const match = HEX_COLOR.exec(color.trim());\n if (!match) {\n return;\n }\n const [, value] = match;\n if (!value) {\n return;\n }\n const expanded =\n value.length === 3\n ? Array.from(value, (character) => `${character}${character}`).join(\"\")\n : value;\n return [0, 2, 4].map((offset) =>\n Number.parseInt(expanded.slice(offset, offset + 2), 16)\n );\n}\n\nfunction relativeLuminance([red, green, blue]: number[]) {\n const [linearRed = 0, linearGreen = 0, linearBlue = 0] = [\n red,\n green,\n blue,\n ].map((channel = 0) => {\n const normalized = channel / 255;\n return normalized <= 0.040_45\n ? normalized / 12.92\n : ((normalized + 0.055) / 1.055) ** 2.4;\n });\n return 0.2126 * linearRed + 0.7152 * linearGreen + 0.0722 * linearBlue;\n}\n\nexport function getAccentContrast(color: string) {\n const parsed = parseHexColor(color);\n if (!parsed) {\n return;\n }\n const luminance = relativeLuminance(parsed);\n const blackContrast = (luminance + 0.05) / 0.05;\n const whiteContrast = 1.05 / (luminance + 0.05);\n return blackContrast >= whiteContrast ? \"#000\" : \"#fff\";\n}\n","import type {\n LockerverseCustomField,\n LockerverseMultiOptionCustomField,\n LockerverseSingleOptionCustomField,\n LockerverseWidgetFields,\n} from \"@lockerverse/sdk/checkout\";\n\nexport const MERCH_SIZES = [\"XS\", \"S\", \"M\", \"L\", \"XL\", \"XXL\", \"XXXL\"] as const;\n\nexport type CheckoutFieldValues = {\n customTip: string;\n customFields: Record<string, string | string[]>;\n includeServiceFee: boolean;\n memberId: string;\n merchSize: (typeof MERCH_SIZES)[number];\n promoCode: string;\n shippingMatchesBilling: boolean;\n tipPercent: \"5\" | \"10\" | \"12\" | \"15\" | \"custom\";\n};\n\nconst TIP_OPTIONS = [\"15\", \"12\", \"10\", \"5\"] as const;\n\nexport function TipField({\n enabled,\n error,\n errorId,\n onChange,\n values,\n}: {\n enabled: boolean;\n error: string | undefined;\n errorId: string;\n onChange: (values: CheckoutFieldValues) => void;\n values: CheckoutFieldValues;\n}) {\n if (!enabled) {\n return null;\n }\n const update = (next: Partial<CheckoutFieldValues>) =>\n onChange({ ...values, ...next });\n return (\n <div className=\"lockerverse-payment__tip-box\">\n <p>Add a tip to support the Lockerverse platform</p>\n <div aria-label=\"Tip amount\" role=\"radiogroup\">\n {TIP_OPTIONS.map((tip) => (\n <button\n aria-pressed={values.tipPercent === tip}\n key={tip}\n onClick={() => update({ tipPercent: tip })}\n type=\"button\"\n >\n {tip}%\n </button>\n ))}\n <button\n aria-pressed={values.tipPercent === \"custom\"}\n onClick={() => update({ tipPercent: \"custom\" })}\n type=\"button\"\n >\n Other\n </button>\n </div>\n {values.tipPercent === \"custom\" ? (\n <label>\n <span>Custom tip</span>\n <span className=\"lockerverse-payment__money-input\">\n <span aria-hidden=\"true\">$</span>\n <input\n aria-describedby={error ? errorId : undefined}\n aria-invalid={error ? \"true\" : undefined}\n inputMode=\"decimal\"\n name=\"tip\"\n onChange={(event) =>\n update({ customTip: event.currentTarget.value })\n }\n placeholder=\"0.00\"\n value={values.customTip}\n />\n </span>\n {error ? (\n <span className=\"lockerverse-payment__field-message\" id={errorId}>\n {error}\n </span>\n ) : null}\n </label>\n ) : (\n <input name=\"tip\" type=\"hidden\" value={values.tipPercent} />\n )}\n </div>\n );\n}\n\nexport function CheckoutToggle({\n checked,\n children,\n name,\n onChange,\n}: {\n checked: boolean;\n children: React.ReactNode;\n name: string;\n onChange: (checked: boolean) => void;\n}) {\n return (\n <label className=\"lockerverse-payment__check-row\">\n <input\n checked={checked}\n name={name}\n onChange={(event) => onChange(event.currentTarget.checked)}\n type=\"checkbox\"\n />\n <span>{children}</span>\n </label>\n );\n}\n\nexport function AdditionalCheckoutFields({\n customFields,\n errors,\n fields,\n idPrefix,\n onChange,\n values,\n}: {\n customFields: LockerverseCustomField[];\n errors: Record<string, string>;\n fields: LockerverseWidgetFields;\n idPrefix: string;\n onChange: (values: CheckoutFieldValues) => void;\n values: CheckoutFieldValues;\n}) {\n const update = (next: Partial<CheckoutFieldValues>) =>\n onChange({ ...values, ...next });\n\n return (\n <div className=\"lockerverse-payment__additional-fields\">\n {fields.memberId ? (\n <label>\n <span>Member ID</span>\n <input\n name=\"memberId\"\n onChange={(event) =>\n update({ memberId: event.currentTarget.value })\n }\n placeholder=\"Optional\"\n value={values.memberId}\n />\n </label>\n ) : null}\n {fields.merchSize ? (\n <label>\n <span>Size</span>\n <select\n name=\"merchSize\"\n onChange={(event) =>\n update({\n merchSize: event.currentTarget\n .value as CheckoutFieldValues[\"merchSize\"],\n })\n }\n value={values.merchSize}\n >\n {MERCH_SIZES.map((size) => (\n <option key={size} value={size}>\n {size}\n </option>\n ))}\n </select>\n </label>\n ) : null}\n {fields.promoCode ? (\n <label>\n <span>Promo code</span>\n <input\n name=\"promoCode\"\n onChange={(event) =>\n update({ promoCode: event.currentTarget.value })\n }\n placeholder=\"Optional\"\n value={values.promoCode}\n />\n </label>\n ) : null}\n {customFields.map((field) => (\n <CustomField\n error={errors[field.id]}\n field={field}\n idPrefix={idPrefix}\n key={field.id}\n onChange={(value) =>\n update({\n customFields: { ...values.customFields, [field.id]: value },\n })\n }\n value={values.customFields[field.id]}\n />\n ))}\n </div>\n );\n}\n\nexport function ServiceFeeField({\n amountCents,\n enabled,\n onChange,\n values,\n}: {\n amountCents: number;\n enabled: boolean;\n onChange: (values: CheckoutFieldValues) => void;\n values: CheckoutFieldValues;\n}) {\n if (!enabled) {\n return null;\n }\n return (\n <CheckoutToggle\n checked={values.includeServiceFee}\n name=\"includeServiceFee\"\n onChange={(includeServiceFee) =>\n onChange({ ...values, includeServiceFee })\n }\n >\n Add {formatMoney(amountCents)} to help cover processing fees\n </CheckoutToggle>\n );\n}\n\nfunction CustomField({\n error,\n field,\n idPrefix,\n onChange,\n value,\n}: {\n error: string | undefined;\n field: LockerverseCustomField;\n idPrefix: string;\n onChange: (value: string | string[]) => void;\n value: string | string[] | undefined;\n}) {\n const name = `custom:${field.id}`;\n const controlId = `${idPrefix}-custom-${field.id}`;\n const errorId = `${controlId}-error`;\n switch (field.type) {\n case \"text\":\n case \"textarea\":\n return (\n <TextCustomField\n controlId={controlId}\n error={error}\n errorId={errorId}\n field={field}\n name={name}\n onChange={onChange}\n value={value}\n />\n );\n case \"select\":\n case \"multi_select\":\n return (\n <SelectCustomField\n controlId={controlId}\n error={error}\n errorId={errorId}\n field={field}\n name={name}\n onChange={onChange}\n value={value}\n />\n );\n case \"radio\":\n case \"checkboxes\":\n return (\n <ChoiceCustomField\n controlId={controlId}\n error={error}\n errorId={errorId}\n field={field}\n name={name}\n onChange={onChange}\n value={value}\n />\n );\n default:\n return null;\n }\n}\n\ntype CustomFieldControlProps = {\n controlId: string;\n error: string | undefined;\n errorId: string;\n name: string;\n onChange: (value: string | string[]) => void;\n value: string | string[] | undefined;\n};\n\nfunction FieldError({ error, id }: { error: string | undefined; id: string }) {\n if (!error) {\n return null;\n }\n return (\n <p className=\"lockerverse-payment__field-message\" id={id}>\n {error}\n </p>\n );\n}\n\nfunction TextCustomField({\n controlId,\n error,\n errorId,\n field,\n name,\n onChange,\n value,\n}: CustomFieldControlProps & {\n field: Extract<LockerverseCustomField, { type: \"text\" | \"textarea\" }>;\n}) {\n const commonProps = {\n \"aria-describedby\": error ? errorId : undefined,\n \"aria-invalid\": error ? (\"true\" as const) : undefined,\n id: controlId,\n name,\n onChange: (\n event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ) => onChange(event.currentTarget.value),\n required: field.required,\n value: typeof value === \"string\" ? value : \"\",\n };\n return (\n <label htmlFor={controlId}>\n <span>{field.label}</span>\n {field.type === \"textarea\" ? (\n <textarea {...commonProps} />\n ) : (\n <input {...commonProps} />\n )}\n <FieldError error={error} id={errorId} />\n </label>\n );\n}\n\nfunction SelectCustomField({\n controlId,\n error,\n errorId,\n field,\n name,\n onChange,\n value,\n}: CustomFieldControlProps & {\n field: LockerverseMultiOptionCustomField | LockerverseSingleOptionCustomField;\n}) {\n return (\n <label htmlFor={controlId}>\n <span>{field.label}</span>\n <select\n aria-describedby={error ? errorId : undefined}\n aria-invalid={error ? \"true\" : undefined}\n id={controlId}\n multiple={field.type === \"multi_select\"}\n name={name}\n onChange={(event) =>\n onChange(\n field.type === \"multi_select\"\n ? [...event.currentTarget.selectedOptions].map(\n (option) => option.value\n )\n : event.currentTarget.value\n )\n }\n required={field.required}\n value={value ?? (field.type === \"multi_select\" ? [] : \"\")}\n >\n {field.type === \"select\" ? <option value=\"\">Select…</option> : null}\n {field.options.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n <FieldError error={error} id={errorId} />\n </label>\n );\n}\n\nfunction ChoiceCustomField({\n controlId,\n error,\n errorId,\n field,\n name,\n onChange,\n value,\n}: CustomFieldControlProps & {\n field: LockerverseMultiOptionCustomField | LockerverseSingleOptionCustomField;\n}) {\n return (\n <fieldset\n aria-describedby={error ? errorId : undefined}\n aria-invalid={error ? \"true\" : undefined}\n >\n <legend>{field.label}</legend>\n {field.options.map((option, index) => {\n const selected = Array.isArray(value)\n ? value.includes(option.id)\n : value === option.id;\n return (\n <label className=\"lockerverse-payment__check-row\" key={option.id}>\n <input\n checked={selected}\n id={`${controlId}-${index}`}\n name={name}\n onChange={(event) => {\n if (field.type === \"radio\") {\n onChange(option.id);\n return;\n }\n const selectedValues = Array.isArray(value) ? value : [];\n onChange(\n event.currentTarget.checked\n ? [...selectedValues, option.id]\n : selectedValues.filter((id) => id !== option.id)\n );\n }}\n required={field.required}\n type={field.type === \"radio\" ? \"radio\" : \"checkbox\"}\n value={option.id}\n />\n <span>{option.label}</span>\n </label>\n );\n })}\n <FieldError error={error} id={errorId} />\n </fieldset>\n );\n}\n\nfunction formatMoney(amountCents: number) {\n return new Intl.NumberFormat(\"en-US\", {\n currency: \"USD\",\n style: \"currency\",\n }).format(amountCents / 100);\n}\n","import type {\n LockerverseCheckoutClient,\n LockerverseCheckoutQuote,\n LockerversePaymentResult,\n LockerverseSubmitPaymentInput,\n} from \"@lockerverse/sdk/checkout\";\nimport { LockerverseSdkError } from \"@lockerverse/sdk/checkout\";\nimport type { Stripe } from \"@stripe/stripe-js\";\n\nconst AMOUNT_KEYS = [\n \"amountCents\",\n \"discountableSubtotalCents\",\n \"discountCents\",\n \"serviceFeeCents\",\n \"subtotalCents\",\n \"tipCents\",\n \"totalCents\",\n] as const satisfies readonly (keyof LockerverseCheckoutQuote)[];\n\nexport function hasMaterialQuoteChange(\n displayed: LockerverseCheckoutQuote,\n current: LockerverseCheckoutQuote\n) {\n return (\n AMOUNT_KEYS.some((key) => displayed[key] !== current[key]) ||\n displayed.payment.connectedAccountId !==\n current.payment.connectedAccountId ||\n displayed.payment.currency !== current.payment.currency ||\n JSON.stringify(displayed.appliedDiscount) !==\n JSON.stringify(current.appliedDiscount) ||\n JSON.stringify(displayed.lineItems) !== JSON.stringify(current.lineItems)\n );\n}\n\nexport type PaymentAttemptOutcome =\n | { kind: \"failed\"; payment: LockerversePaymentResult }\n | { kind: \"success\"; payment: LockerversePaymentResult }\n | {\n kind: \"unresolved\";\n paymentReference: string;\n reason: \"action_required\" | \"pending\" | \"recovery_failed\";\n };\n\nfunction classifyPayment(\n payment: LockerversePaymentResult\n): PaymentAttemptOutcome {\n if (payment.checkoutStatus === \"success\") {\n return { kind: \"success\", payment };\n }\n if (payment.checkoutStatus === \"failed\") {\n return { kind: \"failed\", payment };\n }\n return {\n kind: \"unresolved\",\n paymentReference: payment.paymentReference,\n reason:\n payment.checkoutStatus === \"action_required\"\n ? \"action_required\"\n : \"pending\",\n };\n}\n\nasync function settleRequiredAction(\n client: LockerverseCheckoutClient,\n payment: LockerversePaymentResult,\n stripe: Stripe\n): Promise<PaymentAttemptOutcome> {\n if (payment.checkoutStatus !== \"action_required\") {\n return classifyPayment(payment);\n }\n if (payment.clientSecret) {\n try {\n await stripe.handleNextAction({ clientSecret: payment.clientSecret });\n } catch {\n // Status recovery below is authoritative even when Stripe UI fails.\n }\n }\n try {\n const recovered = await client.getPaymentStatus(payment.paymentReference);\n return classifyPayment(recovered);\n } catch {\n return {\n kind: \"unresolved\",\n paymentReference: payment.paymentReference,\n reason: \"action_required\",\n };\n }\n}\n\nexport async function submitPaymentAttempt(\n client: LockerverseCheckoutClient,\n input: LockerverseSubmitPaymentInput,\n stripe: Stripe\n): Promise<PaymentAttemptOutcome> {\n let payment: LockerversePaymentResult;\n try {\n payment = await client.submitPayment(input);\n } catch (error) {\n if (!(error instanceof LockerverseSdkError && error.recoveryRecommended)) {\n throw error;\n }\n try {\n payment = await client.getPaymentStatus(input.checkout.paymentReference);\n } catch {\n return {\n kind: \"unresolved\",\n paymentReference: input.checkout.paymentReference,\n reason: \"recovery_failed\",\n };\n }\n }\n return settleRequiredAction(client, payment, stripe);\n}\n","import {\n array,\n minLength,\n minValue,\n nonEmpty,\n number,\n pipe,\n regex,\n safeInteger,\n safeParse,\n strictObject,\n string,\n transform,\n trim,\n union,\n} from \"valibot\";\n\nconst productSlugSchema = pipe(string(), trim(), nonEmpty());\nconst positiveSafeIntegerSchema = pipe(number(), safeInteger(), minValue(1));\n\nconst paymentSelectionSchema = pipe(\n array(\n union([\n strictObject({\n amountCents: positiveSafeIntegerSchema,\n productSlug: productSlugSchema,\n }),\n strictObject({\n productSlug: productSlugSchema,\n quantity: positiveSafeIntegerSchema,\n }),\n ])\n ),\n minLength(1)\n);\n\nconst customTipSchema = pipe(\n string(),\n trim(),\n regex(/^(?:0|[1-9]\\d*)(?:\\.\\d{1,2})?$/, \"Enter a valid tip amount.\"),\n transform((value) => Math.round(Number(value) * 100)),\n safeInteger(\"Enter a valid tip amount.\")\n);\n\nexport function parseCustomTipCents(input: string) {\n const result = safeParse(customTipSchema, input);\n return result.success\n ? ({ cents: result.output, success: true } as const)\n : ({\n message: result.issues[0]?.message ?? \"Enter a valid tip amount.\",\n success: false,\n } as const);\n}\n\nexport function parsePaymentSelection(input: unknown) {\n const result = safeParse(paymentSelectionSchema, input);\n return result.success\n ? ({ success: true, value: result.output } as const)\n : ({\n message: \"Lockerverse payment configuration is invalid.\",\n success: false,\n } as const);\n}\n","import type { LockerverseCustomField } from \"@lockerverse/sdk/checkout\";\nimport {\n array,\n email,\n minLength,\n nonEmpty,\n object,\n pipe,\n regex,\n safeParse,\n string,\n trim,\n} from \"valibot\";\n\nconst emailSchema = pipe(\n string(),\n trim(),\n nonEmpty(\"Email is required.\"),\n email(\"Enter a valid email address.\")\n);\n\nconst phoneSchema = pipe(\n string(),\n trim(),\n nonEmpty(\"Phone is required.\"),\n regex(/^\\+[1-9]\\d{6,14}$/, \"Enter a valid phone number.\")\n);\n\nexport function normalizePhone(input: string) {\n return input.trim().replace(/[().\\s-]/g, \"\");\n}\n\nexport type ContactErrors = {\n email?: string;\n phone?: string;\n};\n\nexport function validateContact(\n input: { email: string; phone: string },\n requiresPhone: boolean\n) {\n const normalizedInput = requiresPhone\n ? { ...input, phone: normalizePhone(input.phone) }\n : input;\n const schema = requiresPhone\n ? object({ email: emailSchema, phone: phoneSchema })\n : object({ email: emailSchema });\n const result = safeParse(schema, normalizedInput);\n\n if (result.success) {\n return { errors: {} as ContactErrors, value: result.output } as const;\n }\n\n const errors: ContactErrors = {};\n for (const issue of result.issues) {\n const field = issue.path?.[0]?.key;\n if ((field === \"email\" || field === \"phone\") && !errors[field]) {\n errors[field] = issue.message;\n }\n }\n return { errors, value: null } as const;\n}\n\nexport function validateCustomFields(\n fields: LockerverseCustomField[],\n values: Record<string, string | string[]>\n) {\n const errors: Record<string, string> = {};\n for (const field of fields) {\n if (!field.required) {\n continue;\n }\n const message = `${field.label} is required.`;\n const value = values[field.id];\n const result =\n field.type === \"checkboxes\" || field.type === \"multi_select\"\n ? safeParse(pipe(array(string()), minLength(1, message)), value ?? [])\n : safeParse(\n pipe(string(), trim(), nonEmpty(message)),\n typeof value === \"string\" ? value : \"\"\n );\n if (!result.success) {\n errors[field.id] = result.issues[0]?.message ?? message;\n }\n }\n return errors;\n}\n","import type {\n CreateLockerverseWidgetOptions,\n LockerverseCatalog,\n LockerverseCheckoutClient,\n LockerverseCheckoutItem,\n LockerversePreparedCheckout,\n LockerverseProduct,\n} from \"@lockerverse/sdk/checkout\";\nimport { createLockerverseCheckoutClient } from \"@lockerverse/sdk/checkout\";\nimport { useEffect, useMemo, useReducer, useRef } from \"react\";\nimport { parsePaymentSelection } from \"./payment-input.ts\";\nimport type {\n LockerversePaymentProps,\n LockerversePaymentSelectionItem,\n} from \"./types.ts\";\n\nexport type CheckoutPaymentState =\n | \"error\"\n | \"idle\"\n | \"invalid\"\n | \"submitting\"\n | \"success\"\n | \"unresolved\";\n\ntype CheckoutConfiguration = {\n apiBaseUrl: LockerversePaymentProps[\"apiBaseUrl\"] | undefined;\n communitySlug: string;\n environment: LockerversePaymentProps[\"environment\"] | undefined;\n fetch: LockerversePaymentProps[\"fetch\"] | undefined;\n requestTimeoutMs: number | undefined;\n sentryDsn: string | null | undefined;\n widgetSlug: string;\n};\n\ntype SessionState =\n | { phase: \"idle\"; revision: number }\n | {\n configuration: CheckoutConfiguration;\n phase: \"loading\";\n revision: number;\n selectionKey: string;\n }\n | {\n configuration: CheckoutConfiguration;\n failure: string;\n phase: \"error\";\n revision: number;\n selectionKey: string;\n }\n | {\n catalog: LockerverseCatalog;\n checkoutItems: LockerverseCheckoutItem[];\n client: LockerverseCheckoutClient;\n configuration: CheckoutConfiguration;\n phase: \"ready\";\n preparedCheckout: LockerversePreparedCheckout;\n revision: number;\n selectionKey: string;\n };\n\ntype SessionAction =\n | {\n configuration: CheckoutConfiguration;\n selectionKey: string;\n type: \"loading\";\n }\n | {\n catalog: LockerverseCatalog;\n checkoutItems: LockerverseCheckoutItem[];\n client: LockerverseCheckoutClient;\n configuration: CheckoutConfiguration;\n preparedCheckout: LockerversePreparedCheckout;\n selectionKey: string;\n type: \"ready\";\n }\n | {\n configuration: CheckoutConfiguration;\n failure: string;\n selectionKey: string;\n type: \"error\";\n }\n | { preparedCheckout: LockerversePreparedCheckout; type: \"checkout\" };\n\ntype LoadIdentity = {\n configuration: CheckoutConfiguration;\n selectionKey: string;\n};\n\nfunction sessionReducer(\n state: SessionState,\n action: SessionAction\n): SessionState {\n switch (action.type) {\n case \"loading\":\n return {\n configuration: action.configuration,\n phase: \"loading\",\n revision: state.revision,\n selectionKey: action.selectionKey,\n };\n case \"ready\":\n return {\n catalog: action.catalog,\n checkoutItems: action.checkoutItems,\n client: action.client,\n configuration: action.configuration,\n phase: \"ready\",\n preparedCheckout: action.preparedCheckout,\n revision: state.revision + 1,\n selectionKey: action.selectionKey,\n };\n case \"error\":\n return {\n configuration: action.configuration,\n failure: action.failure,\n phase: \"error\",\n revision: state.revision,\n selectionKey: action.selectionKey,\n };\n case \"checkout\":\n return state.phase === \"ready\"\n ? { ...state, preparedCheckout: action.preparedCheckout }\n : state;\n default:\n return state;\n }\n}\n\nfunction buildCheckoutItem(\n product: LockerverseProduct,\n item: LockerversePaymentSelectionItem\n): LockerverseCheckoutItem {\n if (\"amountCents\" in item) {\n if (product.pricingMode !== \"custom\") {\n throw new TypeError(\"Fixed-price Products do not accept custom amounts.\");\n }\n if (\n product.minimumAmountCents !== null &&\n item.amountCents < product.minimumAmountCents\n ) {\n throw new TypeError(\n `Product amount must be at least ${product.minimumAmountCents} cents.`\n );\n }\n return { amountCents: item.amountCents, productId: product.id };\n }\n if (product.pricingMode !== \"fixed\") {\n throw new TypeError(\"Custom-amount Products do not accept quantities.\");\n }\n if (\n product.minimumQuantity !== null &&\n item.quantity < product.minimumQuantity\n ) {\n throw new TypeError(\n `Product quantity must be at least ${product.minimumQuantity}.`\n );\n }\n if (\n product.maximumQuantity !== null &&\n item.quantity > product.maximumQuantity\n ) {\n throw new TypeError(\n `Product quantity must not exceed ${product.maximumQuantity}.`\n );\n }\n if (\n product.inventoryQuantity !== null &&\n item.quantity > product.inventoryQuantity\n ) {\n throw new TypeError(\"Requested Product quantity is unavailable.\");\n }\n return { productId: product.id, quantity: item.quantity };\n}\n\nfunction buildCheckoutItems(\n catalog: LockerverseCatalog,\n selection: LockerversePaymentSelectionItem[]\n): LockerverseCheckoutItem[] {\n if (selection.length === 0) {\n throw new TypeError(\"Lockerverse payment requires at least one Product.\");\n }\n return selection.map((item) => {\n const product = catalog.products.find(\n (candidate) => candidate.slug === item.productSlug\n );\n if (!product) {\n throw new TypeError(`Product ${item.productSlug} is not available.`);\n }\n return buildCheckoutItem(product, item);\n });\n}\n\nfunction createCheckoutOptions(\n configuration: CheckoutConfiguration,\n onError: LockerversePaymentProps[\"onError\"]\n): CreateLockerverseWidgetOptions {\n const {\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n requestTimeoutMs,\n sentryDsn,\n widgetSlug,\n } = configuration;\n const common = {\n communitySlug,\n widgetSlug,\n ...(fetch ? { fetch } : {}),\n ...(onError ? { onError } : {}),\n ...(requestTimeoutMs === undefined ? {} : { requestTimeoutMs }),\n ...(sentryDsn === undefined ? {} : { sentryDsn }),\n };\n if (apiBaseUrl === undefined) {\n if (environment === \"development\") {\n throw new TypeError(\n \"Lockerverse development checkout requires an API base URL.\"\n );\n }\n return {\n ...common,\n ...(environment === \"production\" ? { environment } : {}),\n };\n }\n if (!environment) {\n throw new TypeError(\n \"Lockerverse development checkout requires an environment.\"\n );\n }\n return { ...common, apiBaseUrl, environment };\n}\n\nfunction isSameLoad(\n identity: LoadIdentity | undefined,\n configuration: CheckoutConfiguration,\n selectionKey: string\n) {\n return (\n identity?.configuration === configuration &&\n identity.selectionKey === selectionKey\n );\n}\n\nexport function useCheckoutSession({\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n onError,\n paymentState,\n requestTimeoutMs,\n selection,\n sentryDsn,\n widgetSlug,\n}: CheckoutConfiguration & {\n onError: LockerversePaymentProps[\"onError\"];\n paymentState: CheckoutPaymentState;\n selection: LockerversePaymentProps[\"selection\"];\n}) {\n const configuration = useMemo<CheckoutConfiguration>(\n () => ({\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n requestTimeoutMs,\n sentryDsn,\n widgetSlug,\n }),\n [\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n requestTimeoutMs,\n sentryDsn,\n widgetSlug,\n ]\n );\n const parsedSelection = parsePaymentSelection(selection);\n const selectionKey = parsedSelection.success\n ? JSON.stringify(parsedSelection.value)\n : \"invalid-selection\";\n const stableSelection = useMemo(\n () =>\n parsedSelection.success\n ? (JSON.parse(selectionKey) as LockerversePaymentSelectionItem[])\n : [],\n [parsedSelection.success, selectionKey]\n );\n const [session, dispatch] = useReducer(sessionReducer, {\n phase: \"idle\",\n revision: 0,\n });\n const loadingRef = useRef<LoadIdentity | undefined>(undefined);\n const settledRef = useRef<LoadIdentity | undefined>(undefined);\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n useEffect(() => {\n if (!parsedSelection.success) {\n return;\n }\n if (\n paymentState === \"submitting\" ||\n paymentState === \"success\" ||\n paymentState === \"unresolved\" ||\n isSameLoad(settledRef.current, configuration, selectionKey) ||\n isSameLoad(loadingRef.current, configuration, selectionKey)\n ) {\n return;\n }\n\n let active = true;\n const identity = { configuration, selectionKey };\n loadingRef.current = identity;\n dispatch({ configuration, selectionKey, type: \"loading\" });\n\n async function loadPayment() {\n try {\n const client = createLockerverseCheckoutClient(\n createCheckoutOptions(configuration, (error) =>\n onErrorRef.current?.(error)\n )\n );\n const catalog = await client.load();\n const checkoutItems = buildCheckoutItems(catalog, stableSelection);\n const preparedCheckout = await client.calculateTotal({\n ...(catalog.widget.fields.serviceFee\n ? { includeServiceFee: true }\n : {}),\n items: checkoutItems,\n });\n if (active) {\n loadingRef.current = undefined;\n settledRef.current = identity;\n dispatch({\n catalog,\n checkoutItems,\n client,\n configuration,\n preparedCheckout,\n selectionKey,\n type: \"ready\",\n });\n }\n } catch (error) {\n if (active) {\n loadingRef.current = undefined;\n settledRef.current = identity;\n dispatch({\n configuration,\n failure:\n error instanceof Error\n ? error.message\n : \"Lockerverse payment could not load.\",\n selectionKey,\n type: \"error\",\n });\n }\n }\n }\n\n loadPayment();\n return () => {\n active = false;\n if (isSameLoad(loadingRef.current, configuration, selectionKey)) {\n loadingRef.current = undefined;\n }\n };\n }, [\n configuration,\n parsedSelection.success,\n paymentState,\n selectionKey,\n stableSelection,\n ]);\n\n return {\n selectionError: parsedSelection.success\n ? undefined\n : parsedSelection.message,\n session,\n updateCheckout: (preparedCheckout: LockerversePreparedCheckout) =>\n dispatch({ preparedCheckout, type: \"checkout\" }),\n };\n}\n","import type {\n LockerverseCatalog,\n LockerverseCheckoutClient,\n LockerverseCheckoutItem,\n LockerverseCustomField,\n LockerverseCustomFieldAnswer,\n LockerversePreparedCheckout,\n} from \"@lockerverse/sdk/checkout\";\nimport {\n AddressElement,\n Elements,\n PaymentElement,\n useElements,\n useStripe,\n} from \"@stripe/react-stripe-js\";\nimport type { Stripe, StripeElements } from \"@stripe/stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { getAccentContrast } from \"./accent-contrast.ts\";\nimport {\n AdditionalCheckoutFields,\n type CheckoutFieldValues,\n CheckoutToggle,\n ServiceFeeField,\n TipField,\n} from \"./checkout-fields.tsx\";\nimport {\n hasMaterialQuoteChange,\n submitPaymentAttempt,\n} from \"./payment-attempt.ts\";\nimport { parseCustomTipCents } from \"./payment-input.ts\";\nimport {\n normalizePhone,\n validateContact,\n validateCustomFields,\n} from \"./payment-validation.ts\";\nimport type { LockerversePaymentProps } from \"./types.ts\";\nimport {\n type CheckoutPaymentState,\n useCheckoutSession,\n} from \"./use-checkout-session.ts\";\n\nfunction formatMoney(amountCents: number) {\n return new Intl.NumberFormat(\"en-US\", {\n currency: \"USD\",\n style: \"currency\",\n }).format(amountCents / 100);\n}\n\nfunction getTipCents(\n subtotalCents: number,\n values: Pick<CheckoutFieldValues, \"customTip\" | \"tipPercent\">\n) {\n if (values.tipPercent === \"custom\") {\n return parseCustomTipCents(values.customTip);\n }\n return {\n cents: Math.round((subtotalCents * Number(values.tipPercent)) / 100),\n success: true,\n } as const;\n}\n\nconst PHONE_COUNTRIES = [\n { callingCode: \"+1\", label: \"🇺🇸 +1\", value: \"US\" },\n { callingCode: \"+52\", label: \"🇲🇽 +52\", value: \"MX\" },\n { callingCode: \"+380\", label: \"🇺🇦 +380\", value: \"UA\" },\n { callingCode: \"+48\", label: \"🇵🇱 +48\", value: \"PL\" },\n { callingCode: \"+1\", label: \"🇨🇦 +1\", value: \"CA\" },\n { callingCode: \"+49\", label: \"🇩🇪 +49\", value: \"DE\" },\n { callingCode: \"+44\", label: \"🇬🇧 +44\", value: \"GB\" },\n { callingCode: \"+46\", label: \"🇸🇪 +46\", value: \"SE\" },\n { callingCode: \"+358\", label: \"🇫🇮 +358\", value: \"FI\" },\n { callingCode: \"+1\", label: \"🇵🇷 +1\", value: \"PR\" },\n] as const;\n\nfunction getInternationalPhone(phone: string, country: string) {\n if (phone.trim().startsWith(\"+\")) {\n return phone;\n }\n const callingCode =\n PHONE_COUNTRIES.find((option) => option.value === country)?.callingCode ??\n \"+1\";\n return `${callingCode}${phone}`;\n}\n\nfunction buildCustomFieldAnswers(\n fields: LockerverseCustomField[],\n values: Record<string, string | string[]>\n): LockerverseCustomFieldAnswer[] {\n return fields.map((field): LockerverseCustomFieldAnswer => {\n const value = values[field.id];\n if (field.type === \"checkboxes\" || field.type === \"multi_select\") {\n return { fieldId: field.id, value: Array.isArray(value) ? value : [] };\n }\n return {\n fieldId: field.id,\n value: typeof value === \"string\" ? value : \"\",\n };\n });\n}\n\nfunction buildQuoteRequest(\n catalog: LockerverseCatalog,\n fieldValues: CheckoutFieldValues,\n email: string,\n tipCents: number\n) {\n return {\n email,\n ...(catalog.widget.fields.serviceFee\n ? { includeServiceFee: fieldValues.includeServiceFee }\n : {}),\n ...(catalog.widget.fields.promoCode && fieldValues.promoCode.trim()\n ? { promoCode: fieldValues.promoCode.trim() }\n : {}),\n ...(catalog.widget.fields.tipping ? { tipCents } : {}),\n };\n}\n\nasync function getCompleteAddress(\n elements: StripeElements,\n mode: \"billing\" | \"shipping\"\n) {\n const addressElement = elements.getElement(\"address\", { mode });\n const label = mode === \"billing\" ? \"Billing\" : \"Shipping\";\n if (!addressElement) {\n throw new Error(`${label} address is still loading.`);\n }\n const address = await addressElement.getValue();\n if (!address.complete) {\n throw new Error(`${label} address is required.`);\n }\n return address.value;\n}\n\nfunction getShippingAddress(\n catalog: LockerverseCatalog,\n elements: StripeElements,\n fieldValues: CheckoutFieldValues,\n billingAddress: Awaited<ReturnType<typeof getCompleteAddress>>\n) {\n if (!catalog.widget.fields.shipping) {\n return;\n }\n return fieldValues.shippingMatchesBilling\n ? billingAddress\n : getCompleteAddress(elements, \"shipping\");\n}\n\nfunction buildConfirmationParams({\n billingAddress,\n catalog,\n email,\n phone,\n shippingAddress,\n}: {\n billingAddress: Awaited<ReturnType<typeof getCompleteAddress>>;\n catalog: LockerverseCatalog;\n email: string;\n phone: string;\n shippingAddress: Awaited<ReturnType<typeof getCompleteAddress>> | undefined;\n}) {\n return {\n payment_method_data: {\n billing_details: {\n address: billingAddress.address,\n email,\n name: billingAddress.name,\n ...(catalog.widget.fields.phone ? { phone } : {}),\n },\n },\n ...(shippingAddress\n ? {\n shipping: {\n address: shippingAddress.address,\n name: shippingAddress.name,\n phone: catalog.widget.fields.phone\n ? phone\n : (shippingAddress.phone ?? null),\n },\n }\n : {}),\n };\n}\n\nfunction buildPaymentRequest({\n catalog,\n confirmationToken,\n email,\n fieldValues,\n phone,\n}: {\n catalog: LockerverseCatalog;\n confirmationToken: string;\n email: string;\n fieldValues: CheckoutFieldValues;\n phone: string;\n}) {\n return {\n confirmationToken,\n customFieldAnswers: buildCustomFieldAnswers(\n catalog.widget.customFields,\n fieldValues.customFields\n ),\n email,\n ...(catalog.widget.fields.memberId && fieldValues.memberId.trim()\n ? { memberId: fieldValues.memberId.trim() }\n : {}),\n ...(catalog.widget.fields.merchSize\n ? { merchSize: fieldValues.merchSize }\n : {}),\n ...(catalog.widget.fields.phone ? { phone } : {}),\n };\n}\n\nasync function completePayment({\n catalog,\n checkoutItems,\n client,\n elements,\n email,\n fieldValues,\n phone,\n quote,\n stripe,\n}: {\n catalog: LockerverseCatalog;\n checkoutItems: LockerverseCheckoutItem[];\n client: LockerverseCheckoutClient;\n elements: StripeElements;\n email: string;\n fieldValues: CheckoutFieldValues;\n phone: string;\n quote: LockerversePreparedCheckout;\n stripe: Stripe;\n}) {\n const normalizedEmail = email.trim().toLowerCase();\n const normalizedPhone = normalizePhone(phone);\n const parsedTip = getTipCents(quote.subtotalCents, fieldValues);\n if (!parsedTip.success) {\n throw new Error(parsedTip.message);\n }\n const pricing = buildQuoteRequest(\n catalog,\n fieldValues,\n normalizedEmail,\n parsedTip.cents\n );\n const currentQuote = await client.calculateTotal({\n ...pricing,\n items: checkoutItems,\n });\n await elements.update({ amount: currentQuote.totalCents });\n if (hasMaterialQuoteChange(quote, currentQuote)) {\n return { kind: \"quote_changed\" as const, quote: currentQuote };\n }\n\n const elementSubmission = await elements.submit();\n if (elementSubmission.error) {\n throw new Error(elementSubmission.error.message);\n }\n\n const billingAddress = await getCompleteAddress(elements, \"billing\");\n const shippingAddress = await getShippingAddress(\n catalog,\n elements,\n fieldValues,\n billingAddress\n );\n\n const tokenResult = await stripe.createConfirmationToken({\n elements,\n params: buildConfirmationParams({\n billingAddress,\n catalog,\n email: normalizedEmail,\n phone: normalizedPhone,\n shippingAddress,\n }),\n });\n if (tokenResult.error) {\n throw new Error(tokenResult.error.message);\n }\n\n const outcome = await submitPaymentAttempt(\n client,\n {\n checkout: currentQuote,\n submission: buildPaymentRequest({\n catalog,\n confirmationToken: tokenResult.confirmationToken.id,\n email: normalizedEmail,\n fieldValues,\n phone: normalizedPhone,\n }),\n },\n stripe\n );\n if (outcome.kind === \"failed\") {\n return {\n kind: \"payment_failed\" as const,\n message:\n \"Payment was declined. Check your payment details and try again.\",\n };\n }\n if (outcome.kind === \"unresolved\") {\n return {\n kind: \"payment_unresolved\" as const,\n paymentReference: outcome.paymentReference,\n reason: outcome.reason,\n };\n }\n return {\n kind: \"payment\" as const,\n payment: outcome.payment,\n quote: currentQuote,\n };\n}\n\nfunction ReadyPayment({\n accentColor,\n catalog,\n checkoutItems,\n client,\n onPaymentComplete,\n onPaymentUncertain,\n onQuoteChange,\n quote,\n onStateChange,\n stripeLoader,\n theme,\n}: {\n accentColor: string;\n catalog: LockerverseCatalog;\n checkoutItems: LockerverseCheckoutItem[];\n client: LockerverseCheckoutClient;\n onPaymentComplete: LockerversePaymentProps[\"onPaymentComplete\"];\n onPaymentUncertain: LockerversePaymentProps[\"onPaymentUncertain\"];\n onQuoteChange: (quote: LockerversePreparedCheckout, notice?: string) => void;\n quote: LockerversePreparedCheckout;\n onStateChange: (\n state:\n | \"error\"\n | \"idle\"\n | \"invalid\"\n | \"submitting\"\n | \"success\"\n | \"unresolved\"\n ) => void;\n stripeLoader: typeof loadStripe;\n theme: LockerversePaymentProps[\"theme\"];\n}) {\n const stripe = useMemo(\n () =>\n stripeLoader(\n catalog.payment.publishableKey,\n quote.payment.connectedAccountId\n ? { stripeAccount: quote.payment.connectedAccountId }\n : undefined\n ),\n [\n catalog.payment.publishableKey,\n quote.payment.connectedAccountId,\n stripeLoader,\n ]\n );\n\n return (\n <Elements\n key={`${catalog.payment.publishableKey}:${quote.payment.connectedAccountId ?? \"platform\"}`}\n options={{\n amount: quote.totalCents,\n appearance: {\n rules: {\n \".Input:focus\": {\n borderColor: accentColor,\n boxShadow: \"none\",\n outline: \"none\",\n },\n },\n theme: theme === \"light\" ? \"stripe\" : \"night\",\n variables: {\n borderRadius: \"8px\",\n colorBackground: theme === \"light\" ? \"#f5f6f7\" : \"#101010\",\n colorDanger: theme === \"light\" ? \"#c52b3e\" : \"#ef4444\",\n colorPrimary: accentColor,\n colorText: theme === \"light\" ? \"#121416\" : \"#ffffff\",\n colorTextPlaceholder: theme === \"light\" ? \"#72767d\" : \"#6b6b6b\",\n colorTextSecondary: theme === \"light\" ? \"#62666d\" : \"#a1a1aa\",\n focusBoxShadow: \"none\",\n focusOutline: \"none\",\n fontFamily:\n \"Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif\",\n fontSizeBase: \"16px\",\n },\n },\n currency: quote.payment.currency,\n excludedPaymentMethodTypes: [\"us_bank_account\"],\n mode: \"payment\",\n syncAddressCheckbox: \"none\",\n }}\n stripe={stripe}\n >\n <PaymentForm\n catalog={catalog}\n checkoutItems={checkoutItems}\n client={client}\n onPaymentComplete={onPaymentComplete}\n onPaymentUncertain={onPaymentUncertain}\n onQuoteChange={onQuoteChange}\n onStateChange={onStateChange}\n quote={quote}\n />\n </Elements>\n );\n}\n\nfunction StripeElementLoader({ label }: { label: string }) {\n return (\n <div className=\"lockerverse-payment__stripe-loader\" role=\"status\">\n <p>{label}</p>\n <div aria-hidden=\"true\">\n <span />\n <span />\n <span />\n </div>\n </div>\n );\n}\n\nfunction StripePaymentField({\n onError,\n onReady,\n ready,\n}: {\n onError: (message: string) => void;\n onReady: () => void;\n ready: boolean;\n}) {\n return (\n <div className=\"lockerverse-payment__stripe-element\" data-ready={ready}>\n {ready ? null : <StripeElementLoader label=\"Loading payment form...\" />}\n <PaymentElement\n onLoadError={({ error }) =>\n onError(error.message ?? \"Payment form failed to load.\")\n }\n onReady={onReady}\n options={{\n business: { name: \"Lockerverse\" },\n fields: { billingDetails: { email: \"auto\" } },\n layout: \"tabs\",\n terms: {\n applePay: \"auto\",\n auBecsDebit: \"never\",\n bancontact: \"never\",\n card: \"always\",\n cashapp: \"never\",\n googlePay: \"never\",\n ideal: \"never\",\n paypal: \"auto\",\n sepaDebit: \"never\",\n sofort: \"never\",\n usBankAccount: \"never\",\n },\n wallets: { applePay: \"auto\", googlePay: \"never\" },\n }}\n />\n </div>\n );\n}\n\nfunction StripeAddressField({\n label,\n mode,\n onError,\n onReady,\n ready,\n}: {\n label: string;\n mode: \"billing\" | \"shipping\";\n onError: (message: string) => void;\n onReady: () => void;\n ready: boolean;\n}) {\n return (\n <div className=\"lockerverse-payment__address\">\n <h2>{label}</h2>\n <div\n className=\"lockerverse-payment__stripe-element lockerverse-payment__stripe-element--address\"\n data-ready={ready}\n >\n {ready ? null : (\n <StripeElementLoader label={`Loading ${label.toLowerCase()}...`} />\n )}\n <AddressElement\n onLoadError={({ error }) =>\n onError(error.message ?? `${label} failed to load.`)\n }\n onReady={onReady}\n options={{ autocomplete: { mode: \"automatic\" }, mode }}\n />\n </div>\n </div>\n );\n}\n\nfunction PaymentErrorMessage({ message }: { message: string | undefined }) {\n if (!message) {\n return null;\n }\n return (\n <p className=\"lockerverse-payment__field-message\" role=\"alert\">\n {message}\n </p>\n );\n}\n\ntype PaymentUiState =\n | \"error\"\n | \"idle\"\n | \"invalid\"\n | \"submitting\"\n | \"success\"\n | \"unresolved\";\n\ntype PaymentTerminalState = {\n kind: \"success\" | \"unresolved\";\n message: string;\n};\n\ntype CompletePaymentResult = Awaited<ReturnType<typeof completePayment>>;\n\nfunction focusFirstValidationError({\n customFieldErrors,\n emailRef,\n form,\n parsedTipSuccess,\n phoneRef,\n validationErrors,\n}: {\n customFieldErrors: Record<string, string>;\n emailRef: React.RefObject<HTMLInputElement | null>;\n form: HTMLFormElement;\n parsedTipSuccess: boolean;\n phoneRef: React.RefObject<HTMLInputElement | null>;\n validationErrors: { email?: string; phone?: string };\n}) {\n if (validationErrors.email) {\n emailRef.current?.focus();\n return;\n }\n if (validationErrors.phone) {\n phoneRef.current?.focus();\n return;\n }\n if (!parsedTipSuccess) {\n form.querySelector<HTMLElement>('[name=\"tip\"]')?.focus();\n return;\n }\n const [firstFieldId] = Object.keys(customFieldErrors);\n if (firstFieldId) {\n form.querySelector<HTMLElement>(`[name=\"custom:${firstFieldId}\"]`)?.focus();\n }\n}\n\nfunction applyPaymentOutcome({\n onPaymentComplete,\n onPaymentUncertain,\n onQuoteChange,\n onStateChange,\n result,\n setDisplayedTotalCents,\n setPaymentError,\n setTerminalState,\n}: {\n onPaymentComplete: LockerversePaymentProps[\"onPaymentComplete\"];\n onPaymentUncertain: LockerversePaymentProps[\"onPaymentUncertain\"];\n onQuoteChange: (quote: LockerversePreparedCheckout, notice?: string) => void;\n onStateChange: (state: PaymentUiState) => void;\n result: CompletePaymentResult;\n setDisplayedTotalCents: (total: number) => void;\n setPaymentError: (message: string) => void;\n setTerminalState: (state: PaymentTerminalState) => void;\n}) {\n if (result.kind === \"quote_changed\") {\n const notice = `The total changed to ${formatMoney(result.quote.totalCents)}. Review it and pay again.`;\n onQuoteChange(result.quote, notice);\n setDisplayedTotalCents(result.quote.totalCents);\n onStateChange(\"idle\");\n return;\n }\n if (result.kind === \"payment_failed\") {\n setPaymentError(result.message);\n onStateChange(\"error\");\n return;\n }\n if (result.kind === \"payment_unresolved\") {\n setTerminalState({\n kind: \"unresolved\",\n message: \"Payment is still processing. Do not submit it again.\",\n });\n onStateChange(\"unresolved\");\n try {\n onPaymentUncertain?.({\n paymentReference: result.paymentReference,\n reason: result.reason,\n });\n } catch {\n // Host callback failures must not unlock an uncertain payment.\n }\n return;\n }\n onQuoteChange(result.quote);\n setTerminalState({\n kind: \"success\",\n message: \"Payment completed successfully.\",\n });\n onStateChange(\"success\");\n try {\n onPaymentComplete?.(result.payment);\n } catch {\n // Host callback failures must not turn a completed payment into an error.\n }\n}\n\nfunction ContactFields({\n email,\n emailErrorId,\n emailId,\n emailRef,\n errors,\n onEmailChange,\n onPhoneChange,\n onPhoneCountryChange,\n phone,\n phoneCountry,\n phoneEnabled,\n phoneErrorId,\n phoneId,\n phoneRef,\n}: {\n email: string;\n emailErrorId: string;\n emailId: string;\n emailRef: React.RefObject<HTMLInputElement | null>;\n errors: { email?: string; phone?: string };\n onEmailChange: (value: string) => void;\n onPhoneChange: (value: string) => void;\n onPhoneCountryChange: (value: string) => void;\n phone: string;\n phoneCountry: string;\n phoneEnabled: boolean;\n phoneErrorId: string;\n phoneId: string;\n phoneRef: React.RefObject<HTMLInputElement | null>;\n}) {\n return (\n <div className=\"lockerverse-payment__contact\">\n <label htmlFor={emailId}>Email</label>\n <input\n aria-describedby={errors.email ? emailErrorId : undefined}\n aria-invalid={errors.email ? \"true\" : undefined}\n autoComplete=\"email\"\n id={emailId}\n name=\"email\"\n onChange={(event) => onEmailChange(event.currentTarget.value)}\n placeholder=\"name@example.com\"\n ref={emailRef}\n type=\"email\"\n value={email}\n />\n {errors.email ? (\n <p className=\"lockerverse-payment__field-message\" id={emailErrorId}>\n {errors.email}\n </p>\n ) : null}\n {phoneEnabled ? (\n <>\n <label htmlFor={phoneId}>Phone</label>\n <div className=\"lockerverse-payment__phone-control\">\n <select\n aria-label=\"Phone number country\"\n name=\"phoneCountry\"\n onChange={(event) =>\n onPhoneCountryChange(event.currentTarget.value)\n }\n value={phoneCountry}\n >\n {PHONE_COUNTRIES.map((country) => (\n <option key={country.value} value={country.value}>\n {country.label}\n </option>\n ))}\n </select>\n <input\n aria-describedby={errors.phone ? phoneErrorId : undefined}\n aria-invalid={errors.phone ? \"true\" : undefined}\n autoComplete=\"tel\"\n id={phoneId}\n inputMode=\"tel\"\n name=\"phone\"\n onChange={(event) => onPhoneChange(event.currentTarget.value)}\n placeholder=\"(201) 555-0123\"\n ref={phoneRef}\n type=\"tel\"\n value={phone}\n />\n </div>\n {errors.phone ? (\n <p className=\"lockerverse-payment__field-message\" id={phoneErrorId}>\n {errors.phone}\n </p>\n ) : null}\n </>\n ) : null}\n </div>\n );\n}\n\nfunction PaymentForm({\n catalog,\n checkoutItems,\n client,\n onPaymentComplete,\n onPaymentUncertain,\n onQuoteChange,\n onStateChange,\n quote,\n}: {\n catalog: LockerverseCatalog;\n checkoutItems: LockerverseCheckoutItem[];\n client: LockerverseCheckoutClient;\n onPaymentComplete: LockerversePaymentProps[\"onPaymentComplete\"];\n onPaymentUncertain: LockerversePaymentProps[\"onPaymentUncertain\"];\n onQuoteChange: (quote: LockerversePreparedCheckout, notice?: string) => void;\n onStateChange: (state: PaymentUiState) => void;\n quote: LockerversePreparedCheckout;\n}) {\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [phoneCountry, setPhoneCountry] = useState(\"US\");\n const [errors, setErrors] = useState<{ email?: string; phone?: string }>({});\n const [paymentError, setPaymentError] = useState<string>();\n const [customFieldErrors, setCustomFieldErrors] = useState<\n Record<string, string>\n >({});\n const [tipError, setTipError] = useState<string>();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [terminalState, setTerminalState] = useState<PaymentTerminalState>();\n const [isPaymentReady, setIsPaymentReady] = useState(false);\n const [isBillingAddressReady, setIsBillingAddressReady] = useState(false);\n const [isShippingAddressReady, setIsShippingAddressReady] = useState(false);\n const [fieldValues, setFieldValues] = useState<CheckoutFieldValues>({\n customFields: {},\n customTip: \"\",\n includeServiceFee: catalog.widget.fields.serviceFee,\n memberId: \"\",\n merchSize: \"M\",\n promoCode: \"\",\n shippingMatchesBilling: true,\n tipPercent: \"10\",\n });\n const [displayedTotalCents, setDisplayedTotalCents] = useState(\n quote.totalCents\n );\n const emailRef = useRef<HTMLInputElement>(null);\n const phoneRef = useRef<HTMLInputElement>(null);\n const statusRef = useRef<HTMLParagraphElement>(null);\n const elements = useElements();\n const stripe = useStripe();\n const idPrefix = `lockerverse-${useId()}`;\n const emailId = `${idPrefix}-email`;\n const emailErrorId = `${emailId}-error`;\n const phoneId = `${idPrefix}-phone`;\n const phoneErrorId = `${phoneId}-error`;\n const tipErrorId = `${idPrefix}-tip-error`;\n const parsedTip = catalog.widget.fields.tipping\n ? getTipCents(quote.subtotalCents, fieldValues)\n : ({ cents: 0, success: true } as const);\n const parsedTipCents = parsedTip.success ? parsedTip.cents : null;\n const displayedTipCents = parsedTipCents ?? 0;\n const displayedBaseCents = displayedTotalCents - displayedTipCents;\n const isRequiredShippingReady =\n !catalog.widget.fields.shipping ||\n fieldValues.shippingMatchesBilling ||\n isShippingAddressReady;\n\n useEffect(() => {\n if (parsedTipCents === null) {\n return;\n }\n const previewServiceFeeCents =\n catalog.widget.fields.serviceFee && fieldValues.includeServiceFee\n ? quote.serviceFeeCents ||\n Math.round(\n (quote.subtotalCents *\n catalog.pricingPolicy.serviceFeeRateBasisPoints) /\n 10_000\n )\n : 0;\n const previewTotalCents =\n quote.totalCents -\n quote.serviceFeeCents -\n quote.tipCents +\n previewServiceFeeCents +\n parsedTipCents;\n setDisplayedTotalCents(previewTotalCents);\n elements?.update({ amount: previewTotalCents });\n }, [\n catalog.widget.fields.serviceFee,\n catalog.widget.fields.tipping,\n elements,\n fieldValues.includeServiceFee,\n fieldValues.tipPercent,\n fieldValues.customTip,\n parsedTipCents,\n quote.serviceFeeCents,\n quote.tipCents,\n quote.totalCents,\n ]);\n\n useEffect(() => {\n if (isSubmitting) {\n statusRef.current?.focus();\n }\n }, [isSubmitting]);\n\n function clearError(field: \"email\" | \"phone\") {\n setErrors((current) => {\n const next = { ...current };\n delete next[field];\n return next;\n });\n }\n\n function handleFieldValuesChange(nextValues: CheckoutFieldValues) {\n setFieldValues(nextValues);\n setCustomFieldErrors({});\n setTipError(undefined);\n }\n\n function handleStripeLoadError(message: string) {\n setPaymentError(message);\n onStateChange(\"error\");\n }\n\n async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const validation = validateContact(\n { email, phone: getInternationalPhone(phone, phoneCountry) },\n catalog.widget.fields.phone\n );\n const nextCustomFieldErrors = validateCustomFields(\n catalog.widget.customFields,\n fieldValues.customFields\n );\n if (\n !(validation.value && parsedTip.success) ||\n Object.keys(nextCustomFieldErrors).length > 0\n ) {\n setErrors(validation.errors);\n setCustomFieldErrors(nextCustomFieldErrors);\n setTipError(parsedTip.success ? undefined : parsedTip.message);\n onStateChange(\"invalid\");\n const form = event.currentTarget;\n queueMicrotask(() => {\n focusFirstValidationError({\n customFieldErrors: nextCustomFieldErrors,\n emailRef,\n form,\n parsedTipSuccess: parsedTip.success,\n phoneRef,\n validationErrors: validation.errors,\n });\n });\n return;\n }\n\n setErrors({});\n setCustomFieldErrors({});\n\n if (!(elements && stripe)) {\n setPaymentError(\"Payment form is still loading.\");\n onStateChange(\"error\");\n return;\n }\n\n setPaymentError(undefined);\n setIsSubmitting(true);\n onStateChange(\"submitting\");\n\n try {\n const result = await completePayment({\n catalog,\n checkoutItems,\n client,\n elements,\n email,\n fieldValues,\n phone: getInternationalPhone(phone, phoneCountry),\n quote,\n stripe,\n });\n applyPaymentOutcome({\n onPaymentComplete,\n onPaymentUncertain,\n onQuoteChange,\n onStateChange,\n result,\n setDisplayedTotalCents,\n setPaymentError,\n setTerminalState,\n });\n } catch (error) {\n setPaymentError(\n error instanceof Error\n ? error.message\n : \"Payment could not be completed.\"\n );\n onStateChange(\"error\");\n } finally {\n setIsSubmitting(false);\n }\n }\n\n if (terminalState) {\n return (\n <p\n className=\"lockerverse-payment__payment-status\"\n ref={statusRef}\n role=\"status\"\n tabIndex={-1}\n >\n {terminalState.message}\n </p>\n );\n }\n\n return (\n <form\n aria-busy={isSubmitting}\n className=\"lockerverse-payment__form\"\n noValidate\n onSubmit={handleSubmit}\n >\n <div\n data-lockerverse-input-region=\"\"\n inert={isSubmitting ? true : undefined}\n >\n <fieldset\n className=\"lockerverse-payment__input-fieldset\"\n disabled={isSubmitting}\n >\n <TipField\n enabled={catalog.widget.fields.tipping}\n error={tipError}\n errorId={tipErrorId}\n onChange={handleFieldValuesChange}\n values={fieldValues}\n />\n <ContactFields\n email={email}\n emailErrorId={emailErrorId}\n emailId={emailId}\n emailRef={emailRef}\n errors={errors}\n onEmailChange={(value) => {\n setEmail(value);\n clearError(\"email\");\n }}\n onPhoneChange={(value) => {\n setPhone(value);\n clearError(\"phone\");\n }}\n onPhoneCountryChange={setPhoneCountry}\n phone={phone}\n phoneCountry={phoneCountry}\n phoneEnabled={catalog.widget.fields.phone}\n phoneErrorId={phoneErrorId}\n phoneId={phoneId}\n phoneRef={phoneRef}\n />\n <StripePaymentField\n onError={handleStripeLoadError}\n onReady={() => setIsPaymentReady(true)}\n ready={isPaymentReady}\n />\n <StripeAddressField\n label=\"Billing address\"\n mode=\"billing\"\n onError={handleStripeLoadError}\n onReady={() => setIsBillingAddressReady(true)}\n ready={isBillingAddressReady}\n />\n {catalog.widget.fields.shipping ? (\n <div className=\"lockerverse-payment__shipping\">\n <CheckoutToggle\n checked={fieldValues.shippingMatchesBilling}\n name=\"shippingMatchesBilling\"\n onChange={(shippingMatchesBilling) => {\n handleFieldValuesChange({\n ...fieldValues,\n shippingMatchesBilling,\n });\n if (!shippingMatchesBilling) {\n setIsShippingAddressReady(false);\n }\n }}\n >\n Shipping is same as billing information\n </CheckoutToggle>\n {fieldValues.shippingMatchesBilling ? null : (\n <StripeAddressField\n label=\"Shipping address\"\n mode=\"shipping\"\n onError={handleStripeLoadError}\n onReady={() => setIsShippingAddressReady(true)}\n ready={isShippingAddressReady}\n />\n )}\n </div>\n ) : null}\n <AdditionalCheckoutFields\n customFields={catalog.widget.customFields}\n errors={customFieldErrors}\n fields={catalog.widget.fields}\n idPrefix={idPrefix}\n onChange={handleFieldValuesChange}\n values={fieldValues}\n />\n <div className=\"lockerverse-payment__actions\">\n <ServiceFeeField\n amountCents={\n quote.serviceFeeCents ||\n Math.round(\n (quote.subtotalCents *\n catalog.pricingPolicy.serviceFeeRateBasisPoints) /\n 10_000\n )\n }\n enabled={catalog.widget.fields.serviceFee}\n onChange={handleFieldValuesChange}\n values={fieldValues}\n />\n <button\n aria-busy={isSubmitting}\n aria-label={`Process payment for ${formatMoney(displayedTotalCents)} total`}\n disabled={\n isSubmitting ||\n !(\n isPaymentReady &&\n isBillingAddressReady &&\n isRequiredShippingReady\n )\n }\n type=\"submit\"\n >\n {isSubmitting\n ? \"Processing…\"\n : `Process Payment (${formatMoney(displayedBaseCents)})${\n displayedTipCents > 0\n ? ` + ${formatMoney(displayedTipCents)} tip`\n : \"\"\n }`}\n </button>\n </div>\n </fieldset>\n </div>\n {isSubmitting ? (\n <p\n className=\"lockerverse-payment__payment-status\"\n ref={statusRef}\n role=\"status\"\n tabIndex={-1}\n >\n Processing payment…\n </p>\n ) : null}\n <PaymentErrorMessage message={paymentError} />\n </form>\n );\n}\n\nfunction SkeletonLoaderBlock() {\n return (\n <div className=\"lockerverse-payment__skeleton-loader-block\">\n <span className=\"lockerverse-payment__skeleton-loader-label\" />\n <div className=\"lockerverse-payment__skeleton-loader-content\">\n <span className=\"lockerverse-payment__skeleton-loader-full\" />\n <div className=\"lockerverse-payment__skeleton-loader-grid\">\n <span className=\"lockerverse-payment__skeleton-loader-half\" />\n <span className=\"lockerverse-payment__skeleton-loader-half\" />\n </div>\n </div>\n </div>\n );\n}\n\nfunction PaymentSkeleton() {\n return (\n <div className=\"lockerverse-payment__loading\">\n <span\n aria-live=\"polite\"\n className=\"lockerverse-payment__sr-only\"\n role=\"status\"\n >\n Loading payment…\n </span>\n <div aria-hidden=\"true\" className=\"lockerverse-payment__skeleton\">\n <div className=\"lockerverse-payment__skeleton-branding\">\n <span className=\"lockerverse-payment__skeleton-avatar\" />\n <span className=\"lockerverse-payment__skeleton-community\" />\n </div>\n <div className=\"lockerverse-payment__skeleton-contact\">\n <div className=\"lockerverse-payment__skeleton-field\">\n <span className=\"lockerverse-payment__skeleton-label\" />\n <span className=\"lockerverse-payment__skeleton-input\" />\n </div>\n <div className=\"lockerverse-payment__skeleton-field\">\n <span className=\"lockerverse-payment__skeleton-label\" />\n <span className=\"lockerverse-payment__skeleton-input\" />\n </div>\n </div>\n <SkeletonLoaderBlock />\n <SkeletonLoaderBlock />\n <div className=\"lockerverse-payment__skeleton-actions\">\n <span className=\"lockerverse-payment__skeleton-check-line\" />\n <span className=\"lockerverse-payment__skeleton-button\" />\n </div>\n </div>\n </div>\n );\n}\n\nexport function LockerversePayment({\n apiBaseUrl,\n branding,\n className,\n communitySlug,\n environment,\n fetch,\n onError,\n onPaymentComplete,\n onPaymentUncertain,\n requestTimeoutMs,\n selection,\n sentryDsn,\n style,\n stripeLoader = loadStripe,\n theme = \"dark\",\n widgetSlug,\n ...sectionProps\n}: LockerversePaymentProps) {\n const [notice, setNotice] = useState<string>();\n const [paymentState, setPaymentState] =\n useState<CheckoutPaymentState>(\"idle\");\n const { selectionError, session, updateCheckout } = useCheckoutSession({\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n onError,\n paymentState,\n requestTimeoutMs,\n selection,\n sentryDsn,\n widgetSlug,\n });\n\n useEffect(() => {\n if (session.phase === \"loading\") {\n setNotice(undefined);\n }\n }, [session.phase]);\n\n useEffect(() => {\n if (session.phase === \"ready\") {\n setPaymentState((current) =>\n current === \"success\" || current === \"unresolved\" ? current : \"idle\"\n );\n }\n }, [session.phase, session.revision]);\n\n const rootClassName = [\"lockerverse-payment\", className]\n .filter(Boolean)\n .join(\" \");\n const effectiveAccent =\n style?.[\"--lockerverse-accent\"] ?? branding?.accentColor ?? \"#38d77a\";\n const automaticAccentContrast = getAccentContrast(effectiveAccent);\n const rootStyle: LockerversePaymentProps[\"style\"] = {\n ...style,\n ...(branding?.accentColor && style?.[\"--lockerverse-accent\"] === undefined\n ? { \"--lockerverse-accent\": branding.accentColor }\n : {}),\n ...(automaticAccentContrast &&\n style?.[\"--lockerverse-accent-contrast\"] === undefined\n ? { \"--lockerverse-accent-contrast\": automaticAccentContrast }\n : {}),\n };\n\n if (selectionError) {\n return (\n <section\n {...sectionProps}\n className={rootClassName}\n data-lockerverse-theme={theme}\n role=\"alert\"\n style={rootStyle}\n >\n {selectionError}\n </section>\n );\n }\n\n if (session.phase === \"error\") {\n return (\n <section\n {...sectionProps}\n className={rootClassName}\n data-lockerverse-theme={theme}\n role=\"alert\"\n >\n {session.failure}\n </section>\n );\n }\n\n if (session.phase !== \"ready\") {\n return (\n <section\n {...sectionProps}\n aria-busy=\"true\"\n aria-label=\"Payment\"\n className={rootClassName}\n data-lockerverse-theme={theme}\n >\n <PaymentSkeleton />\n </section>\n );\n }\n\n const { catalog, checkoutItems, client, preparedCheckout } = session;\n\n return (\n <section\n {...sectionProps}\n aria-label=\"Payment\"\n className={rootClassName}\n data-lockerverse-theme={theme}\n data-payment-state={paymentState}\n style={rootStyle}\n >\n <header>\n {catalog.widget.showCommunityBranding && branding ? (\n <div className=\"lockerverse-payment__branding\">\n {branding.imageUrl ? (\n <img\n alt={branding.name}\n height=\"48\"\n src={branding.imageUrl}\n width=\"48\"\n />\n ) : null}\n <strong>{branding.name}</strong>\n </div>\n ) : null}\n <h1>{catalog.widget.title ?? catalog.widget.name}</h1>\n {catalog.widget.description ? (\n <p>{catalog.widget.description}</p>\n ) : null}\n </header>\n {notice ? (\n <p className=\"lockerverse-payment__payment-status\" role=\"status\">\n {notice}\n </p>\n ) : null}\n <ReadyPayment\n accentColor={\n style?.[\"--lockerverse-accent\"] ?? branding?.accentColor ?? \"#38d77a\"\n }\n catalog={catalog}\n checkoutItems={checkoutItems}\n client={client}\n onPaymentComplete={onPaymentComplete}\n onPaymentUncertain={onPaymentUncertain}\n onQuoteChange={(nextQuote, nextNotice) => {\n setNotice(nextNotice);\n updateCheckout(nextQuote);\n }}\n onStateChange={setPaymentState}\n quote={preparedCheckout}\n stripeLoader={stripeLoader}\n theme={theme}\n />\n </section>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/checkout-session-payment.tsx"],"sourcesContent":["import type {\n CreateLockerverseWidgetOptions,\n LockerverseCatalog,\n LockerverseCheckoutClient,\n LockerverseCheckoutItem,\n LockerverseCheckoutSession,\n LockerverseCustomField,\n LockerverseCustomFieldAnswer,\n} from \"@lockerverse/sdk/checkout\";\nimport { createLockerverseCheckoutClient } from \"@lockerverse/sdk/checkout\";\nimport type { StripeCheckoutElementsValue } from \"@stripe/react-stripe-js/checkout\";\nimport {\n BillingAddressElement,\n CheckoutElementsProvider,\n PaymentElement,\n ShippingAddressElement,\n useCheckoutElements,\n} from \"@stripe/react-stripe-js/checkout\";\nimport { loadStripe } from \"@stripe/stripe-js/pure\";\nimport {\n createContext,\n type FormEvent,\n type PropsWithChildren,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n LockerversePaymentCompletion,\n LockerversePaymentProps,\n LockerversePaymentSelectionItem,\n} from \"./types.ts\";\n\ntype CheckoutSessionStripeLoader = typeof loadStripe;\n\nexport type LockerverseCheckoutSessionProviderProps =\n CreateLockerverseWidgetOptions &\n PropsWithChildren<{\n accentColor?: string;\n email?: string;\n includeServiceFee?: boolean;\n returnUrl: string;\n selection: LockerversePaymentSelectionItem[];\n unstable_stripeLoader?: CheckoutSessionStripeLoader;\n theme?: \"dark\" | \"light\";\n tipCents?: number;\n }>;\n\ntype LoadedCheckout = {\n catalog: LockerverseCatalog;\n client: LockerverseCheckoutClient;\n returnUrl: string;\n session: LockerverseCheckoutSession;\n};\n\ntype CheckoutContextValue = {\n applyPromoCode: (promoCode: string) => Promise<string | null>;\n catalog: LockerverseCatalog;\n confirm: (contact: {\n customFieldAnswers?: LockerverseCustomFieldAnswer[];\n email: string;\n memberId?: string;\n merchSize?: \"XS\" | \"S\" | \"M\" | \"L\" | \"XL\" | \"XXL\" | \"XXXL\";\n phone?: string;\n }) => Promise<LockerversePaymentCompletion>;\n paymentReference: string;\n totalCents: number;\n};\n\nconst CheckoutContext = createContext<CheckoutContextValue | null>(null);\n\nfunction resolveItems(\n catalog: LockerverseCatalog,\n selection: LockerversePaymentSelectionItem[]\n) {\n if (!selection.length) {\n throw new Error(\"Select at least one Product before opening checkout.\");\n }\n return selection.map((selected): LockerverseCheckoutItem => {\n const product = catalog.products.find(\n (candidate) => candidate.slug === selected.productSlug\n );\n if (!product) {\n throw new Error(`Product ${selected.productSlug} is unavailable.`);\n }\n return \"amountCents\" in selected\n ? { amountCents: selected.amountCents, productId: product.id }\n : { productId: product.id, quantity: selected.quantity };\n });\n}\n\nfunction createClientOptions(\n props: LockerverseCheckoutSessionProviderProps\n): CreateLockerverseWidgetOptions {\n const common = {\n communitySlug: props.communitySlug,\n ...(props.fetch ? { fetch: props.fetch } : {}),\n ...(props.onError ? { onError: props.onError } : {}),\n ...(props.requestTimeoutMs === undefined\n ? {}\n : { requestTimeoutMs: props.requestTimeoutMs }),\n ...(props.sentryDsn === undefined ? {} : { sentryDsn: props.sentryDsn }),\n widgetSlug: props.widgetSlug,\n };\n return props.apiBaseUrl\n ? {\n ...common,\n apiBaseUrl: props.apiBaseUrl,\n environment: props.environment,\n }\n : { ...common, environment: \"production\" };\n}\n\nfunction CheckoutBridge({\n children,\n loaded,\n}: PropsWithChildren<{ loaded: LoadedCheckout }>) {\n const result = useCheckoutElements();\n if (result.type === \"loading\") {\n return <div role=\"status\">Loading secure payment form…</div>;\n }\n if (result.type === \"error\") {\n return <div role=\"alert\">{result.error.message}</div>;\n }\n const { checkout } = result;\n const value: CheckoutContextValue = {\n async applyPromoCode(promoCode) {\n const update = await checkout.runServerUpdate(() =>\n loaded.client.updateSessionDiscount({\n paymentReference: loaded.session.paymentReference,\n ...(promoCode.trim() ? { promoCode: promoCode.trim() } : {}),\n })\n );\n return update.type === \"error\" ? update.error.message : null;\n },\n catalog: loaded.catalog,\n async confirm(contact) {\n const detailsUpdate = await checkout.runServerUpdate(() =>\n loaded.client.updateSessionDetails({\n ...(contact.customFieldAnswers\n ? { customFieldAnswers: contact.customFieldAnswers }\n : {}),\n email: contact.email,\n ...(contact.memberId ? { memberId: contact.memberId } : {}),\n ...(contact.merchSize ? { merchSize: contact.merchSize } : {}),\n paymentReference: loaded.session.paymentReference,\n ...(contact.phone ? { phone: contact.phone } : {}),\n })\n );\n if (detailsUpdate.type === \"error\") {\n throw new Error(detailsUpdate.error.message);\n }\n const prepared = await prepareCheckoutContact(\n checkout,\n contact.email,\n contact.phone ?? \"\"\n );\n if (\"error\" in prepared) {\n throw new Error(prepared.error);\n }\n const confirmation = await checkout.confirm({\n email: prepared.email,\n ...(prepared.phone ? { phoneNumber: prepared.phone } : {}),\n redirect: \"if_required\",\n returnUrl: loaded.returnUrl,\n });\n if (confirmation.type === \"error\") {\n throw new Error(confirmation.error.message);\n }\n return {\n paymentReference: loaded.session.paymentReference,\n sessionId: loaded.session.sessionId,\n };\n },\n paymentReference: loaded.session.paymentReference,\n totalCents: checkout.total.total.minorUnitsAmount,\n };\n return (\n <CheckoutContext.Provider value={value}>\n {children}\n </CheckoutContext.Provider>\n );\n}\n\nexport function LockerverseCheckoutSessionProvider(\n props: LockerverseCheckoutSessionProviderProps\n) {\n const [loaded, setLoaded] = useState<LoadedCheckout | null>(null);\n const [failure, setFailure] = useState<string | null>(null);\n const [revision, setRevision] = useState(0);\n const preparation = useRef<{\n clientOptions: CreateLockerverseWidgetOptions;\n promise: Promise<LoadedCheckout>;\n } | null>(null);\n const currentCheckoutKey = JSON.stringify({\n email: props.email,\n includeServiceFee: props.includeServiceFee,\n returnUrl: props.returnUrl,\n selection: props.selection,\n tipCents: props.tipCents,\n });\n const initialCheckout = useRef({\n email: props.email,\n includeServiceFee: props.includeServiceFee,\n key: currentCheckoutKey,\n requestKey: globalThis.crypto.randomUUID(),\n returnUrl: props.returnUrl,\n selection: props.selection,\n tipCents: props.tipCents,\n });\n const clientOptions = useMemo(\n () => createClientOptions(props),\n [\n props.apiBaseUrl,\n props.communitySlug,\n props.environment,\n props.fetch,\n props.onError,\n props.requestTimeoutMs,\n props.sentryDsn,\n props.widgetSlug,\n ]\n );\n\n useEffect(() => {\n let active = true;\n if (preparation.current?.clientOptions !== clientOptions || revision > 0) {\n const client = createLockerverseCheckoutClient(clientOptions);\n const checkoutInput = initialCheckout.current;\n preparation.current = {\n clientOptions,\n promise: (async () => {\n const catalog = await client.load();\n const items = resolveItems(catalog, checkoutInput.selection);\n const includeServiceFee =\n checkoutInput.includeServiceFee ?? catalog.widget.fields.serviceFee;\n const session = await client.createSession({\n ...(checkoutInput.email ? { email: checkoutInput.email } : {}),\n ...(catalog.widget.fields.serviceFee ? { includeServiceFee } : {}),\n items,\n requestKey: checkoutInput.requestKey,\n returnUrl: checkoutInput.returnUrl,\n ...(checkoutInput.tipCents === undefined\n ? {}\n : { tipCents: checkoutInput.tipCents }),\n });\n return {\n catalog,\n client,\n returnUrl: checkoutInput.returnUrl,\n session,\n };\n })(),\n };\n }\n setLoaded(null);\n setFailure(null);\n preparation.current.promise\n .then((next) => {\n if (active) {\n setLoaded(next);\n }\n })\n .catch((error: unknown) => {\n if (active) {\n setFailure(\n error instanceof Error ? error.message : \"Unable to load checkout.\"\n );\n }\n });\n return () => {\n active = false;\n };\n }, [clientOptions, revision]);\n\n const stripe = useMemo(() => {\n if (!loaded) {\n return null;\n }\n const stripeLoader = props.unstable_stripeLoader ?? loadStripe;\n return stripeLoader(loaded.catalog.payment.publishableKey, {\n betas: [\"custom_checkout_server_updates_1\"],\n ...(loaded.session.connectedAccountId\n ? { stripeAccount: loaded.session.connectedAccountId }\n : {}),\n });\n }, [loaded, props.unstable_stripeLoader]);\n const providerOptions = useMemo(\n () =>\n loaded\n ? {\n clientSecret: loaded.session.clientSecret,\n elementsOptions: {\n appearance: {\n theme:\n props.theme === \"light\"\n ? (\"stripe\" as const)\n : (\"night\" as const),\n variables: {\n colorBackground: \"transparent\",\n colorPrimary: props.accentColor ?? \"#38d77a\",\n },\n },\n },\n }\n : null,\n [loaded, props.accentColor, props.theme]\n );\n\n if (currentCheckoutKey !== initialCheckout.current.key) {\n return (\n <div className=\"lockerverse-payment__payment-status\" role=\"alert\">\n Checkout selection changed. Remount this payment component for the new\n selection.\n </div>\n );\n }\n if (failure) {\n return (\n <div className=\"lockerverse-payment__payment-status\" role=\"alert\">\n <p>{failure}</p>\n <button onClick={() => setRevision((value) => value + 1)} type=\"button\">\n Try again\n </button>\n </div>\n );\n }\n if (!(loaded && providerOptions)) {\n return (\n <div className=\"lockerverse-payment__loading\">\n <span className=\"lockerverse-payment__sr-only\" role=\"status\">\n Preparing secure checkout…\n </span>\n <div aria-hidden=\"true\" className=\"lockerverse-payment__skeleton\">\n <div className=\"lockerverse-payment__skeleton-contact\">\n <div className=\"lockerverse-payment__skeleton-field\">\n <span className=\"lockerverse-payment__skeleton-label\" />\n <span className=\"lockerverse-payment__skeleton-input\" />\n </div>\n </div>\n <div className=\"lockerverse-payment__skeleton-loader-block\">\n <span className=\"lockerverse-payment__skeleton-loader-label\" />\n <span className=\"lockerverse-payment__skeleton-loader-full\" />\n </div>\n <div className=\"lockerverse-payment__skeleton-actions\">\n <span className=\"lockerverse-payment__skeleton-button\" />\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <CheckoutElementsProvider options={providerOptions} stripe={stripe}>\n <CheckoutBridge loaded={loaded}>{props.children}</CheckoutBridge>\n </CheckoutElementsProvider>\n );\n}\n\nexport function useLockerverseCheckoutSession() {\n const value = useContext(CheckoutContext);\n if (!value) {\n throw new Error(\n \"useLockerverseCheckoutSession must be used inside LockerverseCheckoutSessionProvider.\"\n );\n }\n return value;\n}\n\nasync function prepareCheckoutContact(\n checkout: StripeCheckoutElementsValue,\n email: string,\n phone: string\n) {\n const normalizedEmail = email.trim().toLowerCase();\n if (!normalizedEmail) {\n return { error: \"Email is required.\" } as const;\n }\n const emailResult = await checkout.updateEmail(normalizedEmail);\n if (emailResult.type === \"error\") {\n return { error: emailResult.error.message } as const;\n }\n const normalizedPhone = phone.trim();\n if (normalizedPhone) {\n const phoneResult = await checkout.updatePhoneNumber(normalizedPhone);\n if (phoneResult.type === \"error\") {\n return { error: \"Phone number is invalid.\" } as const;\n }\n }\n const validation = await checkout.validateElements();\n if (validation.type === \"error\") {\n return { error: validation.error.message } as const;\n }\n return { email: normalizedEmail, phone: normalizedPhone } as const;\n}\n\nfunction LockerverseCustomFields({\n fields,\n onChange,\n values,\n}: {\n fields: LockerverseCustomField[];\n onChange: (fieldId: string, value: string | string[]) => void;\n values: Record<string, string | string[]>;\n}) {\n return fields.map((field) => {\n const value =\n values[field.id] ??\n (field.type.includes(\"multi\") || field.type === \"checkboxes\" ? [] : \"\");\n if (field.type === \"textarea\") {\n return (\n <label key={field.id}>\n <span>{field.label}</span>\n <textarea\n name={field.id}\n onChange={(event) => onChange(field.id, event.currentTarget.value)}\n required={field.required}\n value={String(value)}\n />\n </label>\n );\n }\n if (field.type === \"select\") {\n return (\n <label key={field.id}>\n <span>{field.label}</span>\n <select\n name={field.id}\n onChange={(event) => onChange(field.id, event.currentTarget.value)}\n required={field.required}\n value={String(value)}\n >\n <option value=\"\">Select…</option>\n {field.options.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n if (\n field.type === \"radio\" ||\n field.type === \"checkboxes\" ||\n field.type === \"multi_select\"\n ) {\n const selected = Array.isArray(value) ? value : [value];\n return (\n <fieldset key={field.id}>\n <legend>{field.label}</legend>\n {field.options.map((option) => {\n const checked = selected.includes(option.id);\n return (\n <label className=\"lockerverse-payment__choice\" key={option.id}>\n <input\n checked={checked}\n name={field.id}\n onChange={() => {\n if (field.type === \"radio\") {\n onChange(field.id, option.id);\n return;\n }\n onChange(\n field.id,\n checked\n ? selected.filter((id) => id !== option.id)\n : [...selected, option.id]\n );\n }}\n required={field.required && selected.length === 0}\n type={field.type === \"radio\" ? \"radio\" : \"checkbox\"}\n value={option.id}\n />\n <span>{option.label}</span>\n </label>\n );\n })}\n </fieldset>\n );\n }\n return (\n <label key={field.id}>\n <span>{field.label}</span>\n <input\n name={field.id}\n onChange={(event) => onChange(field.id, event.currentTarget.value)}\n required={field.required}\n type=\"text\"\n value={String(value)}\n />\n </label>\n );\n });\n}\n\nexport function LockerverseCheckoutSessionPaymentForm({\n onComplete,\n}: {\n onComplete?: (result: LockerversePaymentCompletion) => void;\n}) {\n const { applyPromoCode, catalog, confirm, totalCents } =\n useLockerverseCheckoutSession();\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [memberId, setMemberId] = useState(\"\");\n const [merchSize, setMerchSize] = useState(\"\");\n const [customFieldValues, setCustomFieldValues] = useState<\n Record<string, string | string[]>\n >({});\n const [promoCode, setPromoCode] = useState(\"\");\n const [message, setMessage] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n async function updateDiscount() {\n setBusy(true);\n setMessage(null);\n try {\n setMessage(await applyPromoCode(promoCode));\n } catch (error) {\n setMessage(\n error instanceof Error ? error.message : \"Unable to update checkout.\"\n );\n } finally {\n setBusy(false);\n }\n }\n\n async function submit(event: FormEvent) {\n event.preventDefault();\n setBusy(true);\n setMessage(null);\n try {\n onComplete?.(\n await confirm({\n customFieldAnswers: catalog.widget.customFields.map((field) => ({\n fieldId: field.id,\n value: customFieldValues[field.id] ?? null,\n })) as LockerverseCustomFieldAnswer[],\n email,\n ...(memberId ? { memberId } : {}),\n ...(merchSize\n ? {\n merchSize: merchSize as\n | \"XS\"\n | \"S\"\n | \"M\"\n | \"L\"\n | \"XL\"\n | \"XXL\"\n | \"XXXL\",\n }\n : {}),\n ...(phone ? { phone } : {}),\n })\n );\n } catch (error) {\n setMessage(\n error instanceof Error ? error.message : \"Unable to complete checkout.\"\n );\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <form className=\"lockerverse-payment__form\" onSubmit={submit}>\n <header>\n <h1>{catalog.widget.title ?? catalog.widget.name}</h1>\n {catalog.widget.description ? (\n <p>{catalog.widget.description}</p>\n ) : null}\n </header>\n <div className=\"lockerverse-payment__contact\">\n <label>\n <span>Email</span>\n <input\n autoComplete=\"email\"\n inputMode=\"email\"\n name=\"email\"\n onChange={(event) => setEmail(event.currentTarget.value)}\n placeholder=\"you@example.com\"\n required\n type=\"email\"\n value={email}\n />\n </label>\n {catalog.widget.fields.phone ? (\n <label>\n <span>Phone</span>\n <input\n autoComplete=\"tel\"\n inputMode=\"tel\"\n name=\"phone\"\n onChange={(event) => setPhone(event.currentTarget.value)}\n placeholder=\"+1 555 555 5555\"\n required\n type=\"tel\"\n value={phone}\n />\n </label>\n ) : null}\n {catalog.widget.fields.memberId ? (\n <label>\n <span>Member ID</span>\n <input\n name=\"memberId\"\n onChange={(event) => setMemberId(event.currentTarget.value)}\n required\n type=\"text\"\n value={memberId}\n />\n </label>\n ) : null}\n {catalog.widget.fields.merchSize ? (\n <label>\n <span>Merch size</span>\n <select\n name=\"merchSize\"\n onChange={(event) => setMerchSize(event.currentTarget.value)}\n required\n value={merchSize}\n >\n <option value=\"\">Select…</option>\n {([\"XS\", \"S\", \"M\", \"L\", \"XL\", \"XXL\", \"XXXL\"] as const).map(\n (size) => (\n <option key={size} value={size}>\n {size}\n </option>\n )\n )}\n </select>\n </label>\n ) : null}\n </div>\n <div className=\"lockerverse-payment__address\">\n <h2>Billing information</h2>\n <BillingAddressElement />\n </div>\n {catalog.widget.fields.shipping ? (\n <div className=\"lockerverse-payment__shipping\">\n <h2>Shipping information</h2>\n <ShippingAddressElement />\n </div>\n ) : null}\n <div\n className=\"lockerverse-payment__stripe-element\"\n hidden={totalCents === 0}\n >\n <h2>Payment details</h2>\n <PaymentElement />\n </div>\n {catalog.widget.fields.promoCode ? (\n <div className=\"lockerverse-payment__additional-fields\">\n <label>\n <span>Promo code</span>\n <input\n name=\"promoCode\"\n onChange={(event) => setPromoCode(event.currentTarget.value)}\n placeholder=\"Optional\"\n value={promoCode}\n />\n </label>\n <button disabled={busy} onClick={updateDiscount} type=\"button\">\n {promoCode.trim() ? \"Apply code\" : \"Remove code\"}\n </button>\n </div>\n ) : null}\n {catalog.widget.customFields.length ? (\n <div className=\"lockerverse-payment__custom-fields\">\n <LockerverseCustomFields\n fields={catalog.widget.customFields}\n onChange={(fieldId, value) =>\n setCustomFieldValues((current) => ({\n ...current,\n [fieldId]: value,\n }))\n }\n values={customFieldValues}\n />\n </div>\n ) : null}\n {message ? <div role=\"alert\">{message}</div> : null}\n <div className=\"lockerverse-payment__actions\">\n <button disabled={busy} type=\"submit\">\n {totalCents === 0\n ? \"Complete free order\"\n : `Pay $${(totalCents / 100).toFixed(2)}`}\n </button>\n </div>\n </form>\n );\n}\n\nexport function LockerversePayment(props: LockerversePaymentProps) {\n const {\n apiBaseUrl,\n branding,\n className,\n communitySlug,\n environment,\n fetch,\n includeServiceFee,\n onError,\n onPaymentComplete,\n requestTimeoutMs,\n returnUrl,\n selection,\n sentryDsn,\n unstable_stripeLoader,\n style,\n theme = \"dark\",\n tipCents,\n widgetSlug,\n ...sectionProps\n } = props;\n const destination =\n returnUrl ??\n (typeof globalThis.location === \"undefined\"\n ? \"https://lockerverse.com\"\n : globalThis.location.href);\n const rootClassName = [\"lockerverse-payment\", className]\n .filter(Boolean)\n .join(\" \");\n const clientOptions = apiBaseUrl\n ? { apiBaseUrl, communitySlug, environment, widgetSlug }\n : { communitySlug, environment: \"production\" as const, widgetSlug };\n const rootStyle = branding?.accentColor\n ? ({ ...style, \"--lockerverse-accent\": branding.accentColor } as const)\n : style;\n\n return (\n <section\n {...sectionProps}\n className={rootClassName}\n data-lockerverse-theme={theme}\n style={rootStyle}\n >\n {branding ? (\n <div className=\"lockerverse-payment__branding\">\n {branding.imageUrl ? (\n <img alt=\"\" height=\"48\" src={branding.imageUrl} width=\"48\" />\n ) : null}\n <strong>{branding.name}</strong>\n </div>\n ) : null}\n <LockerverseCheckoutSessionProvider\n {...clientOptions}\n {...(branding?.accentColor\n ? { accentColor: branding.accentColor }\n : {})}\n {...(fetch ? { fetch } : {})}\n {...(includeServiceFee === undefined ? {} : { includeServiceFee })}\n {...(onError ? { onError } : {})}\n {...(requestTimeoutMs === undefined ? {} : { requestTimeoutMs })}\n returnUrl={destination}\n selection={selection}\n {...(sentryDsn === undefined ? {} : { sentryDsn })}\n {...(unstable_stripeLoader ? { unstable_stripeLoader } : {})}\n theme={theme}\n {...(tipCents === undefined ? {} : { tipCents })}\n >\n <LockerverseCheckoutSessionPaymentForm\n {...(onPaymentComplete ? { onComplete: onPaymentComplete } : {})}\n />\n </LockerverseCheckoutSessionProvider>\n </section>\n );\n}\n"],"mappings":"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"}