@resira/ui 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -173,6 +173,7 @@ function ResiraProvider({
173
173
  resourceId,
174
174
  domain,
175
175
  config,
176
+ checkoutSessionToken,
176
177
  onClose,
177
178
  children
178
179
  }) {
@@ -262,9 +263,10 @@ function ResiraProvider({
262
263
  deeplinkGuest,
263
264
  onStepChange,
264
265
  onBookingComplete,
265
- onError
266
+ onError,
267
+ checkoutSessionToken
266
268
  }),
267
- [client, resourceId, activeResourceId, setActiveResourceId, catalogMode, allowMultiSelect, domain, theme, locale, domainConfig, stripePublishableKey, termsText, waiverText, showWaiver, showTerms, showRemainingSpots, depositPercent, refundPolicy, onClose, classNames, serviceLayout, visibleServiceCount, groupServicesByCategory, renderServiceCard, showStepIndicator, deeplink, deeplinkGuest, onStepChange, onBookingComplete, onError]
269
+ [client, resourceId, activeResourceId, setActiveResourceId, catalogMode, allowMultiSelect, domain, theme, locale, domainConfig, stripePublishableKey, termsText, waiverText, showWaiver, showTerms, showRemainingSpots, depositPercent, refundPolicy, onClose, classNames, serviceLayout, visibleServiceCount, groupServicesByCategory, renderServiceCard, showStepIndicator, deeplink, deeplinkGuest, onStepChange, onBookingComplete, onError, checkoutSessionToken]
268
270
  );
269
271
  return /* @__PURE__ */ jsxRuntime.jsx(ResiraContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "resira-root", style: cssVars, children }) });
270
272
  }
@@ -596,6 +598,60 @@ function useDishes(enabled = true) {
596
598
  }, [client, enabled]);
597
599
  return { dishes, loading, error };
598
600
  }
601
+ function useCheckoutSession(token) {
602
+ const { client } = useResira();
603
+ const [session, setSession] = react.useState(null);
604
+ const [loading, setLoading] = react.useState(!!token);
605
+ const [error, setError] = react.useState(null);
606
+ const [errorCode, setErrorCode] = react.useState(null);
607
+ react.useEffect(() => {
608
+ if (!token) {
609
+ setSession(null);
610
+ setLoading(false);
611
+ setError(null);
612
+ setErrorCode(null);
613
+ return;
614
+ }
615
+ let cancelled = false;
616
+ setLoading(true);
617
+ setError(null);
618
+ setErrorCode(null);
619
+ async function fetchSession() {
620
+ try {
621
+ const data = await client.getCheckoutSession(token);
622
+ if (!cancelled) {
623
+ setSession(data.session);
624
+ }
625
+ } catch (err) {
626
+ if (cancelled) return;
627
+ const apiErr = err;
628
+ const message = apiErr.body?.error ?? (err instanceof Error ? err.message : "Failed to load checkout session");
629
+ if (apiErr.status === 404) {
630
+ setError("Invalid booking link");
631
+ setErrorCode("not_found");
632
+ } else if (message.toLowerCase().includes("consumed")) {
633
+ setError("This booking was already completed");
634
+ setErrorCode("consumed");
635
+ } else if (message.toLowerCase().includes("expired")) {
636
+ setError("Session expired \u2014 please start a new booking");
637
+ setErrorCode("expired");
638
+ } else {
639
+ setError(message);
640
+ setErrorCode("unknown");
641
+ }
642
+ } finally {
643
+ if (!cancelled) {
644
+ setLoading(false);
645
+ }
646
+ }
647
+ }
648
+ fetchSession();
649
+ return () => {
650
+ cancelled = true;
651
+ };
652
+ }, [client, token]);
653
+ return { session, loading, error, errorCode };
654
+ }
599
655
  var defaultSize = 20;
600
656
  function CalendarIcon({ size = defaultSize, className }) {
601
657
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2677,7 +2733,8 @@ var STEP_LABELS = {
2677
2733
  details: "Details",
2678
2734
  terms: "Terms",
2679
2735
  payment: "Payment",
2680
- confirmation: "Done"
2736
+ confirmation: "Done",
2737
+ checkout: "Checkout"
2681
2738
  };
2682
2739
  function ResiraBookingWidget() {
2683
2740
  const {
@@ -2699,16 +2756,26 @@ function ResiraBookingWidget() {
2699
2756
  deeplinkGuest,
2700
2757
  onStepChange,
2701
2758
  onBookingComplete,
2702
- onError
2759
+ onError,
2760
+ checkoutSessionToken
2703
2761
  } = useResira();
2704
2762
  const isDateBased = domain === "rental";
2705
2763
  const isTimeBased = domain === "restaurant" || domain === "watersport" || domain === "service";
2706
2764
  const isServiceBased = domain === "watersport" || domain === "service";
2707
2765
  const hasPayment = !!stripePublishableKey;
2708
- const STEPS = react.useMemo(
2709
- () => buildSteps(domain, hasPayment, catalogMode),
2710
- [domain, hasPayment, catalogMode]
2711
- );
2766
+ const isCheckoutMode = !!checkoutSessionToken;
2767
+ const {
2768
+ session: checkoutSession,
2769
+ loading: checkoutSessionLoading,
2770
+ error: checkoutSessionError,
2771
+ errorCode: checkoutSessionErrorCode
2772
+ } = useCheckoutSession(checkoutSessionToken);
2773
+ const STEPS = react.useMemo(() => {
2774
+ if (isCheckoutMode) {
2775
+ return ["checkout", "payment", "confirmation"];
2776
+ }
2777
+ return buildSteps(domain, hasPayment, catalogMode);
2778
+ }, [domain, hasPayment, catalogMode, isCheckoutMode]);
2712
2779
  const initialStep = STEPS[0];
2713
2780
  const [step, setStep] = react.useState(initialStep);
2714
2781
  const [selectedResourceIds, setSelectedResourceIds] = react.useState([]);
@@ -2789,6 +2856,16 @@ function ResiraBookingWidget() {
2789
2856
  const [paymentFormReady, setPaymentFormReady] = react.useState(false);
2790
2857
  const [paymentFormSubmitting, setPaymentFormSubmitting] = react.useState(false);
2791
2858
  const paymentPayload = react.useMemo(() => {
2859
+ if (isCheckoutMode && checkoutSession) {
2860
+ return {
2861
+ checkoutSessionToken,
2862
+ guestName: guest.guestName.trim() || checkoutSession.guestName || "",
2863
+ guestEmail: guest.guestEmail.trim() || checkoutSession.guestEmail || void 0,
2864
+ guestPhone: guest.guestPhone.trim() || void 0,
2865
+ notes: guest.notes.trim() || void 0,
2866
+ termsAccepted: termsAccepted || void 0
2867
+ };
2868
+ }
2792
2869
  const resourceId = activeResourceId ?? selectedProduct?.equipmentIds?.[0] ?? "";
2793
2870
  return {
2794
2871
  productId: selectedProduct?.id ?? "",
@@ -2805,7 +2882,7 @@ function ResiraBookingWidget() {
2805
2882
  promoCode: discountCode.trim() || void 0,
2806
2883
  termsAccepted: termsAccepted || void 0
2807
2884
  };
2808
- }, [activeResourceId, selectedProduct, selection, guest, discountCode, termsAccepted]);
2885
+ }, [activeResourceId, selectedProduct, selection, guest, discountCode, termsAccepted, isCheckoutMode, checkoutSession, checkoutSessionToken]);
2809
2886
  const blockedDates = react.useMemo(() => {
2810
2887
  const dates = calendarData?.dates?.blockedDates ?? availability?.dates?.blockedDates ?? [];
2811
2888
  return new Set(dates);
@@ -2863,6 +2940,8 @@ function ResiraBookingWidget() {
2863
2940
  return locale.payment;
2864
2941
  case "confirmation":
2865
2942
  return locale.bookingConfirmed;
2943
+ case "checkout":
2944
+ return "Checkout";
2866
2945
  }
2867
2946
  }, [step, isDateBased, isServiceBased, locale, domain]);
2868
2947
  const stepSubtitle = react.useMemo(() => {
@@ -2881,8 +2960,10 @@ function ResiraBookingWidget() {
2881
2960
  return "Complete your booking securely";
2882
2961
  case "confirmation":
2883
2962
  return "";
2963
+ case "checkout":
2964
+ return checkoutSession?.productName ?? "Complete your booking";
2884
2965
  }
2885
- }, [step, domainConfig.label, locale, allowMultiSelect, isServiceBased, selectedProduct, domain]);
2966
+ }, [step, domainConfig.label, locale, allowMultiSelect, isServiceBased, selectedProduct, domain, checkoutSession]);
2886
2967
  const canContinue = react.useMemo(() => {
2887
2968
  if (step === "resource") {
2888
2969
  if (isServiceBased) return !!selectedProduct;
@@ -3060,6 +3141,35 @@ function ResiraBookingWidget() {
3060
3141
  const handlePaymentError = react.useCallback((msg) => {
3061
3142
  onError?.("payment_error", msg);
3062
3143
  }, [onError]);
3144
+ const handleCheckoutSubmit = react.useCallback(async () => {
3145
+ const contactMode = "email-required";
3146
+ const errors = validateGuestForm(guest, {
3147
+ required: locale.required,
3148
+ invalidEmail: locale.invalidEmail,
3149
+ contactRequired: locale.contactRequired
3150
+ }, contactMode);
3151
+ if (Object.keys(errors).length > 0) {
3152
+ setFormErrors(errors);
3153
+ return;
3154
+ }
3155
+ setFormErrors({});
3156
+ if (checkoutSession?.checkoutConfig.termsRequired && !termsAccepted) {
3157
+ setTermsError(locale.termsRequired);
3158
+ return;
3159
+ }
3160
+ setTermsError(null);
3161
+ const result = await createPayment(paymentPayload);
3162
+ if (!result) return;
3163
+ if (result.amountNow === 0) {
3164
+ if (result.reservationId) {
3165
+ const confirmed = await confirmPayment(result.paymentIntentId, result.reservationId);
3166
+ if (!confirmed) return;
3167
+ }
3168
+ setStep("confirmation");
3169
+ } else {
3170
+ setStep("payment");
3171
+ }
3172
+ }, [guest, locale, checkoutSession, termsAccepted, createPayment, paymentPayload, confirmPayment]);
3063
3173
  const handleSubmitNoPayment = react.useCallback(async () => {
3064
3174
  if (showTerms && !termsAccepted) {
3065
3175
  setTermsError(locale.termsRequired);
@@ -3090,6 +3200,17 @@ function ResiraBookingWidget() {
3090
3200
  const footerBusy = submitting || creatingPayment || confirmingPayment || paymentFormSubmitting;
3091
3201
  const paymentActionDisabled = !paymentIntent || !paymentFormReady || paymentFormSubmitting || confirmingPayment;
3092
3202
  const [deeplinkApplied, setDeeplinkApplied] = react.useState(false);
3203
+ const [checkoutGuestFilled, setCheckoutGuestFilled] = react.useState(false);
3204
+ react.useEffect(() => {
3205
+ if (checkoutGuestFilled || !checkoutSession) return;
3206
+ setGuest((prev) => ({
3207
+ guestName: checkoutSession.guestName ?? prev.guestName,
3208
+ guestEmail: checkoutSession.guestEmail ?? prev.guestEmail,
3209
+ guestPhone: prev.guestPhone,
3210
+ notes: prev.notes
3211
+ }));
3212
+ setCheckoutGuestFilled(true);
3213
+ }, [checkoutSession, checkoutGuestFilled]);
3093
3214
  react.useEffect(() => {
3094
3215
  if (deeplinkApplied || !deeplink) return;
3095
3216
  if (deeplink.productId && products.length > 0 && !selectedProduct) {
@@ -3325,6 +3446,93 @@ function ResiraBookingWidget() {
3325
3446
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "resira-error-message", children: paymentError })
3326
3447
  ] })
3327
3448
  ] }),
3449
+ step === "checkout" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3450
+ checkoutSessionLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-loading", role: "status", "aria-live": "polite", "aria-busy": "true", children: [
3451
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "resira-spinner", "aria-hidden": "true" }),
3452
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-loading-text", children: locale.loading })
3453
+ ] }),
3454
+ checkoutSessionError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-error", role: "alert", "aria-live": "assertive", children: [
3455
+ /* @__PURE__ */ jsxRuntime.jsx(AlertCircleIcon, { size: 24 }),
3456
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "resira-error-message", children: checkoutSessionError }),
3457
+ (checkoutSessionErrorCode === "not_found" || checkoutSessionErrorCode === "expired") && onClose && /* @__PURE__ */ jsxRuntime.jsx(
3458
+ "button",
3459
+ {
3460
+ type: "button",
3461
+ className: "resira-btn resira-btn--secondary resira-error-retry",
3462
+ onClick: onClose,
3463
+ children: "Start a new booking"
3464
+ }
3465
+ )
3466
+ ] }),
3467
+ checkoutSession && !checkoutSessionError && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3468
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary", style: { marginBottom: 16 }, children: [
3469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3470
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: "Service" }),
3471
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value", children: checkoutSession.productName })
3472
+ ] }),
3473
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3474
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: "Date" }),
3475
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value", children: (/* @__PURE__ */ new Date(checkoutSession.date + "T00:00:00")).toLocaleDateString("default", { weekday: "short", month: "short", day: "numeric" }) })
3476
+ ] }),
3477
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3478
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: "Time" }),
3479
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-summary-value", children: [
3480
+ new Date(checkoutSession.startTime).toLocaleTimeString("default", { hour: "2-digit", minute: "2-digit", hour12: false }),
3481
+ " \u2013 ",
3482
+ new Date(checkoutSession.endTime).toLocaleTimeString("default", { hour: "2-digit", minute: "2-digit", hour12: false })
3483
+ ] })
3484
+ ] }),
3485
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3486
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: "Duration" }),
3487
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "resira-summary-value", children: [
3488
+ checkoutSession.durationMinutes,
3489
+ " min"
3490
+ ] })
3491
+ ] }),
3492
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3493
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: locale.guests }),
3494
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value", children: checkoutSession.partySize })
3495
+ ] }),
3496
+ checkoutSession.promoCode && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3497
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label", children: locale.discountCode }),
3498
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value", children: checkoutSession.promoCode })
3499
+ ] }),
3500
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "resira-summary-divider" }),
3501
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-summary-row", children: [
3502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-label resira-summary-total", children: locale.total }),
3503
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value resira-summary-total", children: formatPrice5(checkoutSession.priceCents, checkoutSession.currency) })
3504
+ ] })
3505
+ ] }),
3506
+ /* @__PURE__ */ jsxRuntime.jsx(
3507
+ GuestForm,
3508
+ {
3509
+ values: guest,
3510
+ onChange: setGuest,
3511
+ errors: formErrors
3512
+ }
3513
+ ),
3514
+ checkoutSession.checkoutConfig.termsRequired && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsxRuntime.jsx(
3515
+ WaiverConsent,
3516
+ {
3517
+ termsAccepted,
3518
+ onTermsChange: setTermsAccepted,
3519
+ waiverAccepted: false,
3520
+ onWaiverChange: () => {
3521
+ },
3522
+ discountCode: "",
3523
+ onDiscountCodeChange: () => {
3524
+ },
3525
+ onPromoValidated: () => {
3526
+ },
3527
+ error: termsError ?? void 0
3528
+ }
3529
+ ) }),
3530
+ paymentError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-error", style: { padding: "12px 0" }, children: [
3531
+ /* @__PURE__ */ jsxRuntime.jsx(AlertCircleIcon, { size: 18 }),
3532
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "resira-error-message", children: paymentError })
3533
+ ] })
3534
+ ] })
3535
+ ] }),
3328
3536
  step === "payment" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3329
3537
  paymentError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-error", children: [
3330
3538
  /* @__PURE__ */ jsxRuntime.jsx(AlertCircleIcon, { size: 24 }),
@@ -3410,31 +3618,45 @@ function ResiraBookingWidget() {
3410
3618
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "resira-summary-value resira-summary-total", children: formatPrice5(computedPrice.total, currency) })
3411
3619
  ] })
3412
3620
  ] })
3413
- ] }) }),
3414
- onClose && /* @__PURE__ */ jsxRuntime.jsx(
3415
- "button",
3416
- {
3417
- type: "button",
3418
- className: "resira-btn resira-btn--primary",
3419
- style: { marginTop: 20, width: "100%" },
3420
- onClick: onClose,
3421
- children: locale.done
3422
- }
3423
- )
3621
+ ] }) })
3424
3622
  ] })
3425
3623
  ] }),
3426
- step !== "confirmation" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `resira-widget-footer${currentIndex > 0 ? "" : " resira-widget-footer--single"}`, children: [
3427
- currentIndex > 0 && /* @__PURE__ */ jsxRuntime.jsx(
3624
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "resira-widget-footer", children: [
3625
+ /* @__PURE__ */ jsxRuntime.jsx(
3428
3626
  "button",
3429
3627
  {
3430
3628
  type: "button",
3431
3629
  className: "resira-btn resira-btn--secondary",
3432
3630
  onClick: handleBack,
3433
- disabled: footerBusy,
3631
+ disabled: footerBusy || currentIndex === 0,
3632
+ style: currentIndex === 0 || step === "confirmation" ? { visibility: "hidden" } : void 0,
3633
+ "aria-hidden": currentIndex === 0 || step === "confirmation",
3434
3634
  children: locale.back
3435
3635
  }
3436
3636
  ),
3437
- (step === "resource" || step === "availability") && /* @__PURE__ */ jsxRuntime.jsx(
3637
+ step === "confirmation" ? onClose ? /* @__PURE__ */ jsxRuntime.jsx(
3638
+ "button",
3639
+ {
3640
+ type: "button",
3641
+ className: "resira-btn resira-btn--primary",
3642
+ onClick: onClose,
3643
+ children: locale.done
3644
+ }
3645
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { visibility: "hidden" }, className: "resira-btn resira-btn--primary", children: locale.continue }) : step === "checkout" ? /* @__PURE__ */ jsxRuntime.jsx(
3646
+ "button",
3647
+ {
3648
+ type: "button",
3649
+ className: "resira-btn resira-btn--primary",
3650
+ onClick: () => {
3651
+ void handleCheckoutSubmit();
3652
+ },
3653
+ disabled: footerBusy || checkoutSessionLoading || !!checkoutSessionError,
3654
+ children: creatingPayment ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3655
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "resira-spinner", style: { width: 16, height: 16 } }),
3656
+ locale.processingPayment
3657
+ ] }) : checkoutSession ? `${locale.payNow} \u2014 ${formatPrice5(checkoutSession.priceCents, checkoutSession.currency)}` : locale.continue
3658
+ }
3659
+ ) : step === "resource" || step === "availability" ? /* @__PURE__ */ jsxRuntime.jsx(
3438
3660
  "button",
3439
3661
  {
3440
3662
  type: "button",
@@ -3445,8 +3667,7 @@ function ResiraBookingWidget() {
3445
3667
  disabled: !canContinue || footerBusy,
3446
3668
  children: locale.continue
3447
3669
  }
3448
- ),
3449
- step === "details" && /* @__PURE__ */ jsxRuntime.jsx(
3670
+ ) : step === "details" ? /* @__PURE__ */ jsxRuntime.jsx(
3450
3671
  "button",
3451
3672
  {
3452
3673
  type: "button",
@@ -3458,8 +3679,7 @@ function ResiraBookingWidget() {
3458
3679
  locale.loading
3459
3680
  ] }) : domain === "restaurant" && !hasPayment ? locale.reserveTable : locale.continue
3460
3681
  }
3461
- ),
3462
- step === "terms" && /* @__PURE__ */ jsxRuntime.jsx(
3682
+ ) : step === "terms" ? /* @__PURE__ */ jsxRuntime.jsx(
3463
3683
  "button",
3464
3684
  {
3465
3685
  type: "button",
@@ -3476,8 +3696,7 @@ function ResiraBookingWidget() {
3476
3696
  locale.loading
3477
3697
  ] }) : hasPayment ? locale.continue : locale.bookNow
3478
3698
  }
3479
- ),
3480
- step === "payment" && !paymentIntent && /* @__PURE__ */ jsxRuntime.jsx(
3699
+ ) : step === "payment" && !paymentIntent ? /* @__PURE__ */ jsxRuntime.jsx(
3481
3700
  "button",
3482
3701
  {
3483
3702
  type: "button",
@@ -3491,8 +3710,7 @@ function ResiraBookingWidget() {
3491
3710
  locale.processingPayment
3492
3711
  ] }) : computedPrice ? `${locale.payNow} \u2014 ${formatPrice5(computedPrice.amountNow, currency)}` : locale.payNow
3493
3712
  }
3494
- ),
3495
- step === "payment" && paymentIntent?.amountNow != null && paymentIntent.amountNow > 0 && /* @__PURE__ */ jsxRuntime.jsx(
3713
+ ) : step === "payment" && paymentIntent?.amountNow != null && paymentIntent.amountNow > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3496
3714
  "button",
3497
3715
  {
3498
3716
  type: "button",
@@ -3504,6 +3722,9 @@ function ResiraBookingWidget() {
3504
3722
  locale.processingPayment
3505
3723
  ] }) : `${locale.payNow} \u2014 ${formatPrice5(paymentIntent.amountNow, paymentIntent.currency)}`
3506
3724
  }
3725
+ ) : (
3726
+ /* Fallback placeholder to hold space (e.g. zero-amount payment auto-advancing) */
3727
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { visibility: "hidden" }, className: "resira-btn resira-btn--primary", children: locale.continue })
3507
3728
  )
3508
3729
  ] })
3509
3730
  ] });
@@ -3513,6 +3734,7 @@ function BookingModal({
3513
3734
  domain,
3514
3735
  resourceId,
3515
3736
  config,
3737
+ checkoutSessionToken,
3516
3738
  trigger,
3517
3739
  buttonLabel = "Book Now",
3518
3740
  buttonClassName,
@@ -3636,6 +3858,7 @@ function BookingModal({
3636
3858
  domain,
3637
3859
  resourceId,
3638
3860
  config,
3861
+ checkoutSessionToken,
3639
3862
  onClose: handleClose,
3640
3863
  children: /* @__PURE__ */ jsxRuntime.jsx(ResiraBookingWidget, {})
3641
3864
  }
@@ -4025,6 +4248,7 @@ exports.XIcon = XIcon;
4025
4248
  exports.resolveTheme = resolveTheme;
4026
4249
  exports.themeToCSS = themeToCSS;
4027
4250
  exports.useAvailability = useAvailability;
4251
+ exports.useCheckoutSession = useCheckoutSession;
4028
4252
  exports.useDish = useDish;
4029
4253
  exports.useDishes = useDishes;
4030
4254
  exports.usePaymentIntent = usePaymentIntent;