@riverbankcms/sdk 0.149.0 → 0.150.0

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.
Files changed (165) hide show
  1. package/dist/EventEmbeddedCheckoutStep-D00Kc8Zj.mjs +285 -0
  2. package/dist/{PreviewEditorSidebar-DBKln68M.mjs → PreviewEditorSidebar-7ZhmmnBB.mjs} +3 -3
  3. package/dist/{PreviewEditorUI-DpRX4Mum.mjs → PreviewEditorUI-BIJucTRd.mjs} +2 -2
  4. package/dist/{SdkPreviewModeRuntime-DJPmPY-r.mjs → SdkPreviewModeRuntime-tj45gmCX.mjs} +4 -3
  5. package/dist/{SiteChromeCustomizeContext-JYA0cJ_Z.mjs → SiteChromeCustomizeContext-BFOt0ss-.mjs} +4454 -4059
  6. package/dist/_dts/ai/src/contracts/proposals.d.ts +660 -0
  7. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +510 -0
  8. package/dist/_dts/api/src/billing.d.ts +2 -2
  9. package/dist/_dts/api/src/contentRuntime.d.ts +5 -1
  10. package/dist/_dts/api/src/footerCompositionContracts.d.ts +9 -0
  11. package/dist/_dts/api/src/footerSettings.d.ts +3 -3
  12. package/dist/_dts/api/src/index.d.ts +1 -1
  13. package/dist/_dts/api/src/navigation/bookingPortalLink.d.ts +13 -0
  14. package/dist/_dts/api/src/navigation.d.ts +1 -0
  15. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +9 -173
  16. package/dist/_dts/api/src/sdkThemeWire.d.ts +12 -0
  17. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +3 -3
  18. package/dist/_dts/api/src/siteSettings.d.ts +2 -0
  19. package/dist/_dts/blocks/src/client/site-chrome.d.ts +1 -1
  20. package/dist/_dts/blocks/src/client.d.ts +2 -1
  21. package/dist/_dts/blocks/src/rendering/server.d.ts +1 -1
  22. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +30 -3
  23. package/dist/_dts/blocks/src/system/designCapabilities.d.ts +10 -1
  24. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  25. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +38 -18
  26. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +1 -1
  27. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.server.d.ts +6 -0
  28. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventEmbeddedCheckoutStep.d.ts +13 -0
  29. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationPayment.d.ts +15 -0
  30. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +0 -1
  31. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/FullyBookedStep.d.ts +6 -0
  32. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentBlockingPanel.d.ts +3 -0
  33. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +2 -0
  34. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +15 -5
  35. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +4 -2
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/paymentLocation.d.ts +3 -0
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/paymentResponse.d.ts +72 -0
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +66 -5
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -4
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.d.ts +13 -5
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +11 -52
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +19 -2
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -42
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +7 -8
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +90 -24
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useGuestRegistrationRecovery.d.ts +30 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +24 -12
  48. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useRegistrationAdmission.d.ts +18 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/wizardSteps.d.ts +6 -1
  50. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +1 -1
  51. package/dist/_dts/blocks/src/system/runtime/shared/stripe/browserStripe.d.ts +8 -0
  52. package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +8 -0
  53. package/dist/_dts/commerce/src/purchase/checkoutCopy.d.ts +10 -0
  54. package/dist/_dts/commerce/src/purchase/checkoutPresentation.d.ts +49 -0
  55. package/dist/_dts/commerce/src/purchase/checkoutSessionMetadata.d.ts +4 -4
  56. package/dist/_dts/commerce/src/purchase/checkoutStripeFinalizationPlanning.d.ts +5 -1
  57. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +9 -0
  58. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
  59. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +1 -0
  60. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +9 -2
  61. package/dist/_dts/commerce/src/purchase/types.d.ts +5 -6
  62. package/dist/_dts/content-editor/src/FooterComposerOverview.d.ts +3 -2
  63. package/dist/_dts/content-editor/src/footerPreviewRuntime.d.ts +6 -1
  64. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +7 -0
  65. package/dist/_dts/core/src/index.d.ts +1 -0
  66. package/dist/_dts/core/src/patch/index.d.ts +30 -0
  67. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +30 -1
  68. package/dist/_dts/sdk/src/bookings/index.d.ts +2 -1
  69. package/dist/_dts/sdk/src/bookings/types.d.ts +1 -1
  70. package/dist/_dts/sdk/src/version.d.ts +1 -1
  71. package/dist/_dts/theme-core/src/blocks/index.d.ts +1 -0
  72. package/dist/_dts/theme-core/src/blocks/opaquePanels.d.ts +147 -0
  73. package/dist/_dts/theme-core/src/boxBackgroundSchema.d.ts +22 -0
  74. package/dist/_dts/theme-core/src/buttons/buttonSurfaceContext.d.ts +22 -0
  75. package/dist/_dts/theme-core/src/cards/roles.d.ts +12 -0
  76. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  77. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +198 -0
  78. package/dist/_dts/theme-core/src/palette/utils/index.d.ts +2 -0
  79. package/dist/_dts/theme-core/src/palette/utils/scrimContrast.d.ts +22 -0
  80. package/dist/_dts/theme-core/src/runtime/bridgeColourTokens.d.ts +10 -0
  81. package/dist/_dts/theme-core/src/schema.d.ts +330 -0
  82. package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +0 -51
  83. package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +0 -51
  84. package/dist/_dts/theme-core/src/site-styles/lookResolution.d.ts +11 -0
  85. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorCapabilities.d.ts +7 -1
  86. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +7 -1
  87. package/dist/_dts/theme-core/src/site-styles/previewRuntimeCapabilities.d.ts +12 -6
  88. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +7 -4
  89. package/dist/_dts/theme-core/src/site-styles/sectionSurfaceBackgrounds.d.ts +65 -0
  90. package/dist/_dts/theme-core/src/site-styles/types.d.ts +17 -0
  91. package/dist/_dts/theme-core/src/surfaces/opaqueSurface.d.ts +43 -0
  92. package/dist/client/{BookingMailingListNote-Cr3EeTP5.mjs → BookingMailingListNote-CYHOufsI.mjs} +10 -440
  93. package/dist/client/{CheckboxChoice-B33MqoUo.mjs → CheckboxChoice-M-3HycLw.mjs} +1 -1
  94. package/dist/client/{DemoBookingPortalAccess-BFGB1Fay.mjs → DemoBookingPortalAccess-Cvr9O_ca.mjs} +2 -2
  95. package/dist/client/{EventCombined.client-DKYV0_ft.mjs → EventCombined.client-m5UZIobP.mjs} +7 -7
  96. package/dist/client/EventEmbeddedCheckoutStep-DL6zFAkA.mjs +289 -0
  97. package/dist/client/{EventListing.client-B9UIcEYc.mjs → EventListing.client-DeMfCM04.mjs} +2 -2
  98. package/dist/client/{LeafletStaticMap-CFLPkP0K.mjs → LeafletStaticMap-CvZ3gOdD.mjs} +1 -1
  99. package/dist/client/{checkoutUrls-CXhko2Rv.mjs → RichText-BtfNvQV6.mjs} +2 -29
  100. package/dist/client/{TerminalPanel-JjmgxEsR.mjs → TerminalPanel-CUCNEwlH.mjs} +2 -18
  101. package/dist/client/{ThemedButton-CKV1Jh2m.mjs → ThemedButton-C7WhXuRl.mjs} +2 -2
  102. package/dist/client/{accordion-DXWIfT3T.mjs → accordion-cQm5mjqs.mjs} +1 -1
  103. package/dist/client/{bookingForm-CjZgHNvv.mjs → bookingForm-BVPJE5RQ.mjs} +11 -10
  104. package/dist/client/bookings.mjs +2668 -1134
  105. package/dist/client/{carousel-DSLikmvZ.mjs → carousel-3vgnY7LC.mjs} +2 -2
  106. package/dist/client/{carousel.client-A2lG-9od.mjs → carousel.client-CISsdZvg.mjs} +1 -1
  107. package/dist/client/{cart-HDjWReFt.mjs → cart-BGK4oOjm.mjs} +3 -3
  108. package/dist/client/{checkout-CUvRZA3W.mjs → checkout-GsBLUNJD.mjs} +3 -3
  109. package/dist/client/checkoutUrls-ChxwaNtO.mjs +28 -0
  110. package/dist/client/client.mjs +3042 -1868
  111. package/dist/client/{colorStyles-j5U9v5JA.mjs → colorStyles-D-32xHZh.mjs} +2 -30
  112. package/dist/client/{context-DFmaZa-Q.mjs → context-D_8s12Fp.mjs} +1 -1
  113. package/dist/client/{dates-BBep1JnF.mjs → dates-DeJQbQ9T.mjs} +2 -2
  114. package/dist/client/{eventCalendar-zEobhxo4.mjs → eventCalendar-cmucD4NR.mjs} +10 -10
  115. package/dist/client/{eventCombined-Dp7bz5k-.mjs → eventCombined-ku3E9FTl.mjs} +4 -4
  116. package/dist/client/{eventDetails-FE-zqTt7.mjs → eventDetails-CyKZ61sF.mjs} +5 -5
  117. package/dist/client/{eventListing-BMt5snal.mjs → eventListing-B7yxGIhX.mjs} +4 -4
  118. package/dist/client/{eventRegistration-O6ZxHfOb.mjs → eventRegistration-BoXfSFgZ.mjs} +1403 -857
  119. package/dist/client/{form-DFa1D8vt.mjs → form-CNQOWhJo.mjs} +5 -5
  120. package/dist/client/{headerSection-CmjHLR-N.mjs → headerSection-DahaBJGQ.mjs} +3 -3
  121. package/dist/client/hooks.mjs +123 -64
  122. package/dist/client/{locationMap-BXKP_lGh.mjs → locationMap-BoDjqYlW.mjs} +4 -4
  123. package/dist/client/{media-Cl38iOMI.mjs → media-BFY0y2rb.mjs} +2 -1
  124. package/dist/client/{newsletterForm-CU-HmxGx.mjs → newsletterForm-DtzXDklw.mjs} +4 -4
  125. package/dist/client/{pricing-KEAEsibq.mjs → pricing-DXEh2Lhh.mjs} +1 -1
  126. package/dist/client/{productDetail-Ckp7MGnt.mjs → productDetail-D7cPa-00.mjs} +3 -3
  127. package/dist/client/{productList-D91V0sYa.mjs → productList-D1XMap66.mjs} +3 -3
  128. package/dist/client/{propsDecoder-DZd6RJeA.mjs → propsDecoder-DiIeBopB.mjs} +758 -245
  129. package/dist/client/rendering/client.mjs +4381 -2892
  130. package/dist/client/rendering/islands.mjs +19 -19
  131. package/dist/client/rendering.mjs +3026 -1852
  132. package/dist/client/result-DRW7JWXz.mjs +30 -0
  133. package/dist/client/{routeIslandApiConfig-E1EkhhYY.mjs → routeIslandApiConfig-wzR4lKAY.mjs} +1 -1
  134. package/dist/client/scrollToBlock-C86BYkyV.mjs +17 -0
  135. package/dist/client/{shop-4F2jLQPI.mjs → shop-CYT5P-S5.mjs} +8 -8
  136. package/dist/client/{shop-commerce-store-vicweP2K.mjs → shop-commerce-store-wKhsJQxI.mjs} +1 -1
  137. package/dist/client/{shop-commerce-BbfCJjB3.mjs → shop-commerce-ypBu_dx4.mjs} +9 -9
  138. package/dist/client/{shopShared-DlONJt0T.mjs → shopShared-DFGhYrf2.mjs} +52 -6
  139. package/dist/client/{useEventFilters-COYyL3m7.mjs → useEventFilters-blSbN5o7.mjs} +8 -8
  140. package/dist/preview-next/client/runtime.mjs +3 -3
  141. package/dist/{sdk-runtime-CwvFFjB-.mjs → sdk-runtime-2p8uQk1V.mjs} +1 -1
  142. package/dist/{separator-ByL72zUT.mjs → separator-Cvvzk0Oo.mjs} +1 -1
  143. package/dist/server/components.mjs +4066 -3765
  144. package/dist/server/config-validation.mjs +185 -126
  145. package/dist/server/config.mjs +185 -126
  146. package/dist/server/data.mjs +123 -64
  147. package/dist/server/index.mjs +1 -1
  148. package/dist/server/next.mjs +615 -314
  149. package/dist/server/page-converter.mjs +100 -56
  150. package/dist/server/prebuild.mjs +1 -1
  151. package/dist/server/rendering/server.mjs +4041 -3751
  152. package/dist/server/rendering.mjs +4069 -3768
  153. package/dist/server/routing.mjs +149 -72
  154. package/dist/server/server.mjs +124 -65
  155. package/dist/server/theme-bridge.mjs +1122 -310
  156. package/dist/server/theme.mjs +126 -116
  157. package/dist/spinner-CDo6AkDz.mjs +658 -0
  158. package/dist/styles/index.css +75 -212
  159. package/package.json +1 -1
  160. package/dist/_dts/billing/src/checkout/platform.d.ts +0 -77
  161. package/dist/_dts/billing/src/config/env.d.ts +0 -29
  162. package/dist/_dts/billing/src/stripe/client.d.ts +0 -29
  163. package/dist/_dts/blocks/src/system/runtime/hooks/usePaymentVerification.d.ts +0 -63
  164. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.d.ts +0 -9
  165. package/dist/client/urlParams-D71VXFGx.mjs +0 -47
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as React$1 from "react";
3
- import React, { createContext, createElement, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
3
+ import React, { Suspense, createContext, createElement, lazy, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { z } from "zod";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region \0rolldown/runtime.js
@@ -13,6 +13,7 @@ var __esmMin = (fn, res, err) => () => {
13
13
  throw err = [e], e;
14
14
  }
15
15
  };
16
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
16
17
  var __exportAll = (all, no_symbols) => {
17
18
  let target = {};
18
19
  for (var name in all) __defProp(target, name, {
@@ -2499,9 +2500,9 @@ function err$1(error) {
2499
2500
  error
2500
2501
  };
2501
2502
  }
2503
+ var init_result = __esmMin((() => {}));
2502
2504
  //#endregion
2503
2505
  //#region ../core/src/branded.ts
2504
- const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2505
2506
  function parseUuidBrand(value, unsafeConstructor) {
2506
2507
  if (typeof value !== "string") return err$1({ kind: "not_string" });
2507
2508
  const normalized = value.trim().toLowerCase();
@@ -2509,19 +2510,24 @@ function parseUuidBrand(value, unsafeConstructor) {
2509
2510
  if (!UUID_PATTERN.test(normalized)) return err$1({ kind: "invalid_uuid" });
2510
2511
  return ok$1(unsafeConstructor(normalized));
2511
2512
  }
2512
- const unsafeAsSiteId = (id) => id;
2513
- const unsafeAsEventOfferingId = (id) => id;
2514
- const unsafeAsEventSeriesId = (id) => id;
2515
- const unsafeAsMediaAssetId = (id) => id;
2516
- const unsafeAsStorageBucketName = (value) => value;
2517
- const unsafeAsStoragePath = (value) => value;
2518
- const unsafeAsFormId = (id) => id;
2519
- const unsafeAsPassId = (id) => id;
2520
- const unsafeAsCustomerPassId = (id) => id;
2521
- const unsafeAsAppointmentServiceId = (id) => id;
2522
- const unsafeAsAppointmentResourceId = (id) => id;
2523
- const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
2524
- const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
2513
+ var UUID_PATTERN, unsafeAsSiteId, unsafeAsEventOfferingId, unsafeAsEventSeriesId, unsafeAsMediaAssetId, unsafeAsStorageBucketName, unsafeAsStoragePath, unsafeAsFormId, unsafeAsPassId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, unsafeAsAppointmentResourceId, parseEventOfferingId, parseEventSeriesId;
2514
+ var init_branded = __esmMin((() => {
2515
+ init_result();
2516
+ UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2517
+ unsafeAsSiteId = (id) => id;
2518
+ unsafeAsEventOfferingId = (id) => id;
2519
+ unsafeAsEventSeriesId = (id) => id;
2520
+ unsafeAsMediaAssetId = (id) => id;
2521
+ unsafeAsStorageBucketName = (value) => value;
2522
+ unsafeAsStoragePath = (value) => value;
2523
+ unsafeAsFormId = (id) => id;
2524
+ unsafeAsPassId = (id) => id;
2525
+ unsafeAsCustomerPassId = (id) => id;
2526
+ unsafeAsAppointmentServiceId = (id) => id;
2527
+ unsafeAsAppointmentResourceId = (id) => id;
2528
+ parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
2529
+ parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
2530
+ }));
2525
2531
  //#endregion
2526
2532
  //#region ../core/src/date-math.ts
2527
2533
  function addDaysToDate(date, dayCount) {
@@ -2537,29 +2543,49 @@ function addDaysToIso(isoString, dayCount) {
2537
2543
  function subtractDaysFromIso(isoString, dayCount) {
2538
2544
  return addDaysToIso(isoString, -dayCount);
2539
2545
  }
2546
+ var init_date_math = __esmMin((() => {}));
2547
+ //#endregion
2548
+ //#region ../core/src/html-entities.ts
2549
+ var init_html_entities = __esmMin((() => {}));
2550
+ //#endregion
2551
+ //#region ../core/src/duration.ts
2552
+ var init_duration = __esmMin((() => {}));
2553
+ //#endregion
2554
+ //#region ../core/src/demo-capability-policy.ts
2555
+ var init_demo_capability_policy = __esmMin((() => {}));
2556
+ //#endregion
2557
+ //#region ../core/src/demo-claim-access.ts
2558
+ var init_demo_claim_access = __esmMin((() => {}));
2559
+ //#endregion
2560
+ //#region ../core/src/demo-lifecycle-status.ts
2561
+ var init_demo_lifecycle_status = __esmMin((() => {}));
2562
+ //#endregion
2563
+ //#region ../core/src/demo-warm-pool-target.ts
2564
+ var init_demo_warm_pool_target = __esmMin((() => {}));
2565
+ //#endregion
2566
+ //#region ../core/src/demo-runtime.ts
2567
+ var init_demo_runtime = __esmMin((() => {}));
2568
+ //#endregion
2569
+ //#region ../core/src/collections.ts
2570
+ var init_collections = __esmMin((() => {}));
2571
+ //#endregion
2572
+ //#region ../core/src/event-booking-offer.ts
2573
+ var init_event_booking_offer = __esmMin((() => {}));
2574
+ //#endregion
2575
+ //#region ../core/src/event-booking-offer-parser.ts
2576
+ var init_event_booking_offer_parser = __esmMin((() => {}));
2540
2577
  //#endregion
2541
2578
  //#region ../core/src/assert-never.ts
2542
2579
  function assertNever$4(value, message = "Unexpected variant") {
2543
2580
  throw new Error(`${message}: ${String(value)}`);
2544
2581
  }
2582
+ var init_assert_never = __esmMin((() => {}));
2545
2583
  //#endregion
2546
2584
  //#region ../core/src/currency-format.ts
2547
- const CURRENCY_CODE_INPUT_PATTERN = /^[A-Za-z]{3}$/;
2548
2585
  /** Parse + normalize a currency code, or return null if it isn't a 3-letter code. */
2549
2586
  function parseCurrencyCode(value) {
2550
2587
  return CURRENCY_CODE_INPUT_PATTERN.test(value) ? value.toUpperCase() : null;
2551
2588
  }
2552
- const CURRENCY_LOCALE_BY_CODE = {
2553
- USD: "en-US",
2554
- GBP: "en-GB",
2555
- EUR: "de-DE",
2556
- AUD: "en-AU",
2557
- CAD: "en-CA",
2558
- NZD: "en-NZ",
2559
- JPY: "ja-JP",
2560
- CNY: "zh-CN",
2561
- CHF: "de-CH"
2562
- };
2563
2589
  function resolveCurrencyLocale(currencyCode, override) {
2564
2590
  return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
2565
2591
  }
@@ -2609,15 +2635,32 @@ function formatCurrencyMajorUnits(amount, currency, options) {
2609
2635
  return `${amount.toFixed(2)} ${currencyCode}`;
2610
2636
  }
2611
2637
  }
2638
+ var CURRENCY_CODE_INPUT_PATTERN, CURRENCY_LOCALE_BY_CODE;
2639
+ var init_currency_format = __esmMin((() => {
2640
+ CURRENCY_CODE_INPUT_PATTERN = /^[A-Za-z]{3}$/;
2641
+ CURRENCY_LOCALE_BY_CODE = {
2642
+ USD: "en-US",
2643
+ GBP: "en-GB",
2644
+ EUR: "de-DE",
2645
+ AUD: "en-AU",
2646
+ CAD: "en-CA",
2647
+ NZD: "en-NZ",
2648
+ JPY: "ja-JP",
2649
+ CNY: "zh-CN",
2650
+ CHF: "de-CH"
2651
+ };
2652
+ }));
2612
2653
  //#endregion
2613
2654
  //#region ../core/src/planner.ts
2614
- /** Default clock for production callers that do not inject time explicitly. */
2615
- const systemPlanningClock = { now: () => Date.now() };
2616
2655
  /** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
2617
2656
  function resolvePlanningNowDate(input = {}) {
2618
2657
  if (input.now !== void 0) return input.now;
2619
2658
  return new Date((input.clock ?? systemPlanningClock).now());
2620
2659
  }
2660
+ var systemPlanningClock;
2661
+ var init_planner = __esmMin((() => {
2662
+ systemPlanningClock = { now: () => Date.now() };
2663
+ }));
2621
2664
  //#endregion
2622
2665
  //#region ../core/src/event-pricing.ts
2623
2666
  /** Capacity closes booking, but does not make an otherwise eligible price unknown. */
@@ -2756,6 +2799,10 @@ function canonicalEventPricingDisplay(pricing) {
2756
2799
  default: return assertNever$4(pricing);
2757
2800
  }
2758
2801
  }
2802
+ var init_event_pricing = __esmMin((() => {
2803
+ init_assert_never();
2804
+ init_planner();
2805
+ }));
2759
2806
  //#endregion
2760
2807
  //#region ../core/src/event-page-surface-subject.ts
2761
2808
  function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
@@ -2860,6 +2907,16 @@ function parseEventSeriesIdList(values) {
2860
2907
  function isRecord$9(value) {
2861
2908
  return typeof value === "object" && value !== null && !Array.isArray(value);
2862
2909
  }
2910
+ var init_event_page_surface_subject = __esmMin((() => {
2911
+ init_branded();
2912
+ init_result();
2913
+ }));
2914
+ //#endregion
2915
+ //#region ../core/src/event-page-selection.ts
2916
+ var init_event_page_selection = __esmMin((() => {}));
2917
+ //#endregion
2918
+ //#region ../core/src/public-event-booking-availability.ts
2919
+ var init_public_event_booking_availability = __esmMin((() => {}));
2863
2920
  //#endregion
2864
2921
  //#region ../core/src/money-input.ts
2865
2922
  function unsafeAsNonNegativeCents(value) {
@@ -2872,6 +2929,7 @@ function unsafeAsNonNegativeCents(value) {
2872
2929
  function toNonNegativeCents(value) {
2873
2930
  return unsafeAsNonNegativeCents(Math.max(0, Math.trunc(value)));
2874
2931
  }
2932
+ var init_money_input = __esmMin((() => {}));
2875
2933
  //#endregion
2876
2934
  //#region ../core/src/booking-flexible-balance.ts
2877
2935
  function clampFlexibleBalanceConfiguredAmount(amountCents, totalAmountCents) {
@@ -2890,6 +2948,12 @@ function resolveFlexibleBalanceDueAt(input) {
2890
2948
  function assertNever$3(value) {
2891
2949
  throw new Error(`Unexpected value: ${String(value)}`);
2892
2950
  }
2951
+ var init_booking_flexible_balance = __esmMin((() => {
2952
+ init_date_math();
2953
+ }));
2954
+ //#endregion
2955
+ //#region ../core/src/booking-refunds.ts
2956
+ var init_booking_refunds = __esmMin((() => {}));
2893
2957
  //#endregion
2894
2958
  //#region ../core/src/booking-instalments.ts
2895
2959
  function isDepositBearingBookingInstalmentPlan(plan) {
@@ -2950,6 +3014,13 @@ function addMonthsPreservingAnchorDay(date, intervalCount) {
2950
3014
  function assertNever$2(value) {
2951
3015
  throw new Error(`Unexpected value: ${String(value)}`);
2952
3016
  }
3017
+ var init_booking_instalments = __esmMin((() => {}));
3018
+ //#endregion
3019
+ //#region ../core/src/booking-instalment-deposit.ts
3020
+ var init_booking_instalment_deposit = __esmMin((() => {}));
3021
+ //#endregion
3022
+ //#region ../core/src/booking-live-payment-terms.ts
3023
+ var init_booking_live_payment_terms = __esmMin((() => {}));
2953
3024
  //#endregion
2954
3025
  //#region ../core/src/booking-payment-options.ts
2955
3026
  /** Automatic instalments and a flexible balance cannot share one booking offer. */
@@ -2960,11 +3031,11 @@ function validateBookingPaymentOptionKinds(kinds) {
2960
3031
  if (uniqueKinds.has("instalment_plan") && uniqueKinds.has("flexible_balance")) return err$1("incompatible_collection_options");
2961
3032
  return ok$1(void 0);
2962
3033
  }
3034
+ var init_booking_payment_options = __esmMin((() => {
3035
+ init_result();
3036
+ }));
2963
3037
  //#endregion
2964
3038
  //#region ../core/src/booking-time-zone.ts
2965
- const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
2966
- const timeZoneValidityCache = /* @__PURE__ */ new Map();
2967
- const NUMERIC_OFFSET_TIME_ZONE_PATTERN = /^(?:[+-]\d{2}(?::?\d{2})?|(?:UTC|GMT)[+-]\d{1,2}(?::?\d{2})?)$/iu;
2968
3039
  function isValidBookingTimeZone(timeZone) {
2969
3040
  const normalized = timeZone.trim();
2970
3041
  if (NUMERIC_OFFSET_TIME_ZONE_PATTERN.test(normalized)) return false;
@@ -2987,13 +3058,15 @@ function parseBookingTimeZone(timeZone) {
2987
3058
  if (normalized.length === 0 || NUMERIC_OFFSET_TIME_ZONE_PATTERN.test(normalized) || !isValidBookingTimeZone(normalized)) return err$1("invalid-time-zone");
2988
3059
  return ok$1(normalized);
2989
3060
  }
3061
+ var TIME_ZONE_VALIDITY_CACHE_LIMIT, timeZoneValidityCache, NUMERIC_OFFSET_TIME_ZONE_PATTERN;
3062
+ var init_booking_time_zone = __esmMin((() => {
3063
+ init_result();
3064
+ TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
3065
+ timeZoneValidityCache = /* @__PURE__ */ new Map();
3066
+ NUMERIC_OFFSET_TIME_ZONE_PATTERN = /^(?:[+-]\d{2}(?::?\d{2})?|(?:UTC|GMT)[+-]\d{1,2}(?::?\d{2})?)$/iu;
3067
+ }));
2990
3068
  //#endregion
2991
3069
  //#region ../core/src/booking-date-time.ts
2992
- const DEFAULT_LOCALE = "en-US";
2993
- const FALLBACK_TIMEZONE = "UTC";
2994
- const LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
2995
- const DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
2996
- const dateTimeFormatterCache = /* @__PURE__ */ new Map();
2997
3070
  function getSafeTimeZone(timeZone) {
2998
3071
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
2999
3072
  return normalized.length > 0 && isValidBookingTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
@@ -3148,6 +3221,19 @@ function addLocalScheduleDays(date, days) {
3148
3221
  day: utcDate.getUTCDate()
3149
3222
  };
3150
3223
  }
3224
+ var DEFAULT_LOCALE, FALLBACK_TIMEZONE, LOCAL_DATE_PATTERN, DATE_TIME_FORMATTER_CACHE_LIMIT, dateTimeFormatterCache;
3225
+ var init_booking_date_time = __esmMin((() => {
3226
+ init_result();
3227
+ init_booking_time_zone();
3228
+ DEFAULT_LOCALE = "en-US";
3229
+ FALLBACK_TIMEZONE = "UTC";
3230
+ LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
3231
+ DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
3232
+ dateTimeFormatterCache = /* @__PURE__ */ new Map();
3233
+ }));
3234
+ //#endregion
3235
+ //#region ../core/src/booking-consent.ts
3236
+ var init_booking_consent = __esmMin((() => {}));
3151
3237
  //#endregion
3152
3238
  //#region ../core/src/appointment-service-categories.ts
3153
3239
  /**
@@ -3188,12 +3274,148 @@ function layoutServicesByCategory(categories, services, options) {
3188
3274
  other
3189
3275
  };
3190
3276
  }
3277
+ var init_appointment_service_categories = __esmMin((() => {}));
3278
+ //#endregion
3279
+ //#region ../core/src/dated-offering-settlement.ts
3280
+ var init_dated_offering_settlement = __esmMin((() => {}));
3281
+ //#endregion
3282
+ //#region ../core/src/person-records.ts
3283
+ var init_person_records = __esmMin((() => {}));
3284
+ //#endregion
3285
+ //#region ../core/src/rectification.ts
3286
+ var init_rectification = __esmMin((() => {}));
3287
+ //#endregion
3288
+ //#region ../core/src/location.ts
3289
+ var init_location = __esmMin((() => {}));
3290
+ //#endregion
3291
+ //#region ../core/src/business-address.ts
3292
+ var init_business_address = __esmMin((() => {}));
3293
+ //#endregion
3294
+ //#region ../core/src/narrow-result.ts
3295
+ var init_narrow_result = __esmMin((() => {}));
3296
+ //#endregion
3297
+ //#region ../core/src/non-empty-array.ts
3298
+ var init_non_empty_array = __esmMin((() => {}));
3299
+ //#endregion
3300
+ //#region ../core/src/editor-state.ts
3301
+ var init_editor_state = __esmMin((() => {}));
3302
+ //#endregion
3303
+ //#region ../core/src/editor-value-sync.ts
3304
+ var init_editor_value_sync = __esmMin((() => {}));
3305
+ //#endregion
3306
+ //#region ../core/src/edit-lease.ts
3307
+ var init_edit_lease = __esmMin((() => {}));
3308
+ //#endregion
3309
+ //#region ../core/src/block-content-identity.ts
3310
+ var init_block_content_identity = __esmMin((() => {}));
3311
+ //#endregion
3312
+ //#region ../core/src/sensitive-collection.ts
3313
+ var init_sensitive_collection = __esmMin((() => {}));
3314
+ //#endregion
3315
+ //#region ../core/src/assertNever.ts
3316
+ var init_assertNever$1 = __esmMin((() => {}));
3317
+ //#endregion
3318
+ //#region ../core/src/participants.ts
3319
+ var init_participants = __esmMin((() => {}));
3320
+ //#endregion
3321
+ //#region ../core/src/public-url-validation.ts
3322
+ var init_public_url_validation = __esmMin((() => {}));
3323
+ //#endregion
3324
+ //#region ../core/src/public-profile.ts
3325
+ var init_public_profile = __esmMin((() => {}));
3326
+ //#endregion
3327
+ //#region ../core/src/public-experience.ts
3328
+ var init_public_experience = __esmMin((() => {}));
3329
+ //#endregion
3330
+ //#region ../core/src/rich-text.ts
3331
+ var init_rich_text = __esmMin((() => {}));
3332
+ //#endregion
3333
+ //#region ../core/src/footer-composition.ts
3334
+ var init_footer_composition = __esmMin((() => {}));
3335
+ //#endregion
3336
+ //#region ../core/src/footer-navigation-layout.ts
3337
+ var init_footer_navigation_layout = __esmMin((() => {}));
3338
+ var init_footer_arrangement = __esmMin((() => {
3339
+ new Map([
3340
+ "brand",
3341
+ "supporting-text",
3342
+ "social-links",
3343
+ "navigation",
3344
+ "business-address",
3345
+ "contact",
3346
+ "opening-hours",
3347
+ "engagement",
3348
+ "legal-navigation",
3349
+ "legal"
3350
+ ].map((kind, index) => [kind, index]));
3351
+ }));
3352
+ //#endregion
3353
+ //#region ../core/src/footer-composition-types.ts
3354
+ var init_footer_composition_types = __esmMin((() => {}));
3355
+ //#endregion
3356
+ //#region ../core/src/footer-engagement.ts
3357
+ var init_footer_engagement = __esmMin((() => {}));
3358
+ //#endregion
3359
+ //#region ../core/src/mailing-list-identifiers.ts
3360
+ var init_mailing_list_identifiers = __esmMin((() => {}));
3361
+ //#endregion
3362
+ //#region ../core/src/mailing-list-setup.ts
3363
+ var init_mailing_list_setup = __esmMin((() => {}));
3364
+ //#endregion
3365
+ //#region ../core/src/mailing-list-setup-parser.ts
3366
+ var init_mailing_list_setup_parser = __esmMin((() => {}));
3367
+ //#endregion
3368
+ //#region ../core/src/mailing-list-targeting.ts
3369
+ var init_mailing_list_targeting = __esmMin((() => {}));
3191
3370
  //#endregion
3192
3371
  //#region ../core/src/mailing-list-runtime.ts
3193
3372
  function resolveBookingSignupOffer(context, siteName) {
3194
3373
  const name = siteName?.trim() ?? "";
3195
3374
  return context?.tag === "configured" && context.bookingSignup.tag === "offered" ? { siteName: name.length > 0 ? name : "this site" } : null;
3196
3375
  }
3376
+ var init_mailing_list_runtime = __esmMin((() => {}));
3377
+ //#endregion
3378
+ //#region ../core/src/mailing-list-targeting-parser.ts
3379
+ var init_mailing_list_targeting_parser = __esmMin((() => {}));
3380
+ //#endregion
3381
+ //#region ../core/src/mailing-list-submission.ts
3382
+ var init_mailing_list_submission = __esmMin((() => {}));
3383
+ //#endregion
3384
+ //#region ../core/src/number-input.ts
3385
+ var init_number_input = __esmMin((() => {}));
3386
+ //#endregion
3387
+ //#region ../core/src/field-errors.ts
3388
+ var init_field_errors = __esmMin((() => {}));
3389
+ //#endregion
3390
+ //#region ../core/src/form-submission-preview.ts
3391
+ var init_form_submission_preview = __esmMin((() => {}));
3392
+ //#endregion
3393
+ //#region ../core/src/csv-cells.ts
3394
+ var init_csv_cells = __esmMin((() => {}));
3395
+ //#endregion
3396
+ //#region ../core/src/csv-date-filter.ts
3397
+ var init_csv_date_filter = __esmMin((() => {}));
3398
+ //#endregion
3399
+ //#region ../core/src/csv-escape.ts
3400
+ var init_csv_escape = __esmMin((() => {}));
3401
+ //#endregion
3402
+ //#region ../core/src/csv-filename.ts
3403
+ var init_csv_filename = __esmMin((() => {}));
3404
+ //#endregion
3405
+ //#region ../core/src/csv-render.ts
3406
+ var init_csv_render = __esmMin((() => {}));
3407
+ //#endregion
3408
+ //#region ../core/src/csv-types.ts
3409
+ var init_csv_types = __esmMin((() => {}));
3410
+ //#endregion
3411
+ //#region ../core/src/email-format.ts
3412
+ var init_email_format = __esmMin((() => {}));
3413
+ //#endregion
3414
+ //#region ../core/src/slug.ts
3415
+ var init_slug = __esmMin((() => {}));
3416
+ //#endregion
3417
+ //#region ../core/src/string.ts
3418
+ var init_string = __esmMin((() => {}));
3197
3419
  //#endregion
3198
3420
  //#region ../core/src/uuid.ts
3199
3421
  function generateUuidV4(cryptoSource = globalThis.crypto) {
@@ -3204,6 +3426,18 @@ function generateUuidV4(cryptoSource = globalThis.crypto) {
3204
3426
  const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
3205
3427
  return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
3206
3428
  }
3429
+ var init_uuid = __esmMin((() => {}));
3430
+ //#endregion
3431
+ //#region ../core/src/stable-json.ts
3432
+ var init_stable_json = __esmMin((() => {}));
3433
+ //#endregion
3434
+ //#region ../core/src/secret.ts
3435
+ var init_secret = __esmMin((() => {}));
3436
+ //#endregion
3437
+ //#region ../core/src/site-route-target.ts
3438
+ var init_site_route_target = __esmMin((() => {}));
3439
+ //#endregion
3440
+ //#region ../core/src/whole-series-run-schedule.ts
3207
3441
  function sessionStartMs(session) {
3208
3442
  return Date.parse(session.startsAt);
3209
3443
  }
@@ -3216,6 +3450,162 @@ function sessionStartMs(session) {
3216
3450
  function orderedLiveRunSessions(sessions) {
3217
3451
  return sessions.filter((session) => session.status !== "cancelled" && Number.isFinite(sessionStartMs(session))).sort((left, right) => sessionStartMs(left) - sessionStartMs(right));
3218
3452
  }
3453
+ var init_whole_series_run_schedule = __esmMin((() => {}));
3454
+ //#endregion
3455
+ //#region ../core/src/public-read-cache-contract.ts
3456
+ function availability(transport) {
3457
+ return {
3458
+ kind: "live",
3459
+ reason: "booking_correctness",
3460
+ freshness: "availability",
3461
+ transport
3462
+ };
3463
+ }
3464
+ function content(tags, transport = "direct") {
3465
+ return {
3466
+ kind: "tagged",
3467
+ tags,
3468
+ freshness: "content",
3469
+ transport
3470
+ };
3471
+ }
3472
+ var PUBLIC_READ_CACHE_POLICIES;
3473
+ var init_public_read_cache_contract = __esmMin((() => {
3474
+ PUBLIC_READ_CACHE_POLICIES = {
3475
+ listPublishedEntries: content(["published_content"]),
3476
+ getPublishedEntryPreview: content(["published_content"]),
3477
+ listPublicEvents: availability("direct"),
3478
+ listPublicEventCalendarWindow: availability("direct"),
3479
+ listPublicRecurringSchedule: availability("batch_only"),
3480
+ getPublicEventDetails: availability("batch_only"),
3481
+ resolveEventSubroute: availability("direct"),
3482
+ listPublicRouteCandidates: content(["published_content"], "batch_only"),
3483
+ listPublicTeamMembers: content(["public_team_members"]),
3484
+ listPublicProducts: availability("direct"),
3485
+ listPublicPasses: availability("direct"),
3486
+ listPublicMemberships: availability("direct"),
3487
+ getPublicFormById: content(["site_forms"]),
3488
+ getPublicBookingServices: availability("direct"),
3489
+ getPublicBookingService: availability("direct"),
3490
+ getPublicBookingResourcesReference: availability("direct"),
3491
+ getPublicBookingAvailableDates: availability("direct"),
3492
+ getPublicBookingAvailableSlots: availability("direct"),
3493
+ getPublicWeeklySlotAvailability: availability("direct"),
3494
+ listPublicForms: content(["site_forms"]),
3495
+ checkRedirect: content([]),
3496
+ getPublicRoutableContent: content(["published_content"]),
3497
+ getPublicSitemapRoutes: content(["published_content"])
3498
+ };
3499
+ new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
3500
+ }));
3501
+ //#endregion
3502
+ //#region ../core/src/booking-verticals.ts
3503
+ var init_booking_verticals = __esmMin((() => {}));
3504
+ //#endregion
3505
+ //#region ../core/src/event-series-behaviour.ts
3506
+ var init_event_series_behaviour = __esmMin((() => {}));
3507
+ //#endregion
3508
+ //#region ../core/src/navigation-locations.ts
3509
+ var init_navigation_locations = __esmMin((() => {}));
3510
+ //#endregion
3511
+ //#region ../core/src/navigation-portal-labels.ts
3512
+ var init_navigation_portal_labels = __esmMin((() => {}));
3513
+ //#endregion
3514
+ //#region ../core/src/event-preset-vocabulary.ts
3515
+ var init_event_preset_vocabulary = __esmMin((() => {}));
3516
+ //#endregion
3517
+ //#region ../core/src/event-catalogue.ts
3518
+ var init_event_catalogue = __esmMin((() => {}));
3519
+ //#endregion
3520
+ //#region ../core/src/patch/index.ts
3521
+ var init_patch = __esmMin((() => {}));
3522
+ //#endregion
3523
+ //#region ../core/src/index.ts
3524
+ var init_src = __esmMin((() => {
3525
+ init_branded();
3526
+ init_date_math();
3527
+ init_html_entities();
3528
+ init_duration();
3529
+ init_demo_capability_policy();
3530
+ init_demo_claim_access();
3531
+ init_demo_lifecycle_status();
3532
+ init_demo_warm_pool_target();
3533
+ init_demo_runtime();
3534
+ init_collections();
3535
+ init_event_booking_offer();
3536
+ init_event_booking_offer_parser();
3537
+ init_event_pricing();
3538
+ init_event_page_surface_subject();
3539
+ init_event_page_selection();
3540
+ init_public_event_booking_availability();
3541
+ init_money_input();
3542
+ init_booking_flexible_balance();
3543
+ init_booking_refunds();
3544
+ init_booking_instalments();
3545
+ init_booking_instalment_deposit();
3546
+ init_booking_live_payment_terms();
3547
+ init_booking_payment_options();
3548
+ init_booking_date_time();
3549
+ init_booking_consent();
3550
+ init_appointment_service_categories();
3551
+ init_dated_offering_settlement();
3552
+ init_person_records();
3553
+ init_rectification();
3554
+ init_location();
3555
+ init_business_address();
3556
+ init_result();
3557
+ init_narrow_result();
3558
+ init_non_empty_array();
3559
+ init_editor_state();
3560
+ init_editor_value_sync();
3561
+ init_edit_lease();
3562
+ init_block_content_identity();
3563
+ init_sensitive_collection();
3564
+ init_assertNever$1();
3565
+ init_participants();
3566
+ init_public_url_validation();
3567
+ init_public_profile();
3568
+ init_public_experience();
3569
+ init_rich_text();
3570
+ init_footer_composition();
3571
+ init_footer_navigation_layout();
3572
+ init_footer_arrangement();
3573
+ init_footer_composition_types();
3574
+ init_footer_engagement();
3575
+ init_mailing_list_identifiers();
3576
+ init_mailing_list_setup();
3577
+ init_mailing_list_setup_parser();
3578
+ init_mailing_list_targeting();
3579
+ init_mailing_list_runtime();
3580
+ init_mailing_list_targeting_parser();
3581
+ init_mailing_list_submission();
3582
+ init_number_input();
3583
+ init_field_errors();
3584
+ init_form_submission_preview();
3585
+ init_csv_cells();
3586
+ init_csv_date_filter();
3587
+ init_csv_escape();
3588
+ init_csv_filename();
3589
+ init_csv_render();
3590
+ init_csv_types();
3591
+ init_currency_format();
3592
+ init_email_format();
3593
+ init_slug();
3594
+ init_string();
3595
+ init_uuid();
3596
+ init_stable_json();
3597
+ init_secret();
3598
+ init_site_route_target();
3599
+ init_whole_series_run_schedule();
3600
+ init_public_read_cache_contract();
3601
+ init_booking_verticals();
3602
+ init_event_series_behaviour();
3603
+ init_navigation_locations();
3604
+ init_navigation_portal_labels();
3605
+ init_event_preset_vocabulary();
3606
+ init_event_catalogue();
3607
+ init_patch();
3608
+ }));
3219
3609
  //#endregion
3220
3610
  //#region ../theme-core/src/footer/mode.ts
3221
3611
  const footerModeSchema = z.enum([
@@ -7041,12 +7431,22 @@ const mediaPresentationSchema = commonSchema.extend({
7041
7431
  const boxBackgroundSchema = z.discriminatedUnion("type", [
7042
7432
  commonSchema.extend({
7043
7433
  type: z.literal("color"),
7044
- color: tokenOrCssColorValueSchema.nullable().optional()
7434
+ color: tokenOrCssColorValueSchema.nullable().optional(),
7435
+ /**
7436
+ * Compiler-owned. The scrim a site-style colour surface lays over media
7437
+ * that replaces it (a Look's band meeting an authored photo), sized so the
7438
+ * surface's foreground stays legible over any pixel. A colour background
7439
+ * never draws it itself; `resolveSectionBackground` moves it onto the
7440
+ * merged media background as its overlay.
7441
+ */
7442
+ mediaScrim: boxBackgroundOverlaySchema.nullable().optional()
7045
7443
  }),
7046
7444
  commonSchema.extend({
7047
7445
  type: z.literal("gradient"),
7048
7446
  gradient: z.string().nullable().optional(),
7049
- gradientPresetId: z.string().min(1).nullable().optional()
7447
+ gradientPresetId: z.string().min(1).nullable().optional(),
7448
+ /** Compiler-owned; see the colour branch. */
7449
+ mediaScrim: boxBackgroundOverlaySchema.nullable().optional()
7050
7450
  }),
7051
7451
  mediaPresentationSchema.extend({
7052
7452
  type: z.literal("image"),
@@ -7870,6 +8270,7 @@ const RichTextDocSchema = z.object({
7870
8270
  }).strict();
7871
8271
  //#endregion
7872
8272
  //#region ../core/src/booking-payment-schemas.ts
8273
+ init_booking_payment_options();
7873
8274
  const stripObject = (shape) => z.object(shape);
7874
8275
  const strictObject = (shape) => z.strictObject(shape);
7875
8276
  const depositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
@@ -8319,6 +8720,7 @@ const eventScheduleScopeValues = [
8319
8720
  ];
8320
8721
  //#endregion
8321
8722
  //#region ../blocks/src/system/blocks/events/shared/calendarWindow.ts
8723
+ init_src();
8322
8724
  /** Runtime picker sentinels and bound loader IDs must describe the same query. */
8323
8725
  function normalizeCalendarFilterId(value) {
8324
8726
  const id = value?.trim();
@@ -9553,112 +9955,690 @@ function assertNever$1(value, message) {
9553
9955
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
9554
9956
  }
9555
9957
  //#endregion
9556
- //#region ../blocks/src/system/runtime/nodes/booking-form.reserved-fields.ts
9557
- const BOOKING_FORM_DATA_RESERVED_KEY_VALUES = [
9558
- "serviceId",
9559
- "resourceId",
9560
- "selectedDate",
9561
- "selectedSlot",
9562
- "discountCode",
9563
- "selectedSlidingAmountInput",
9564
- "selectedCollectionOptionKind",
9565
- "selectedAppointmentPackageId",
9566
- "mailingListOptIn"
9567
- ];
9568
- const BOOKING_FORM_DATA_RESERVED_KEYS = new Set(BOOKING_FORM_DATA_RESERVED_KEY_VALUES);
9958
+ //#region ../commerce/src/purchase/types.ts
9959
+ var init_types = __esmMin((() => {}));
9569
9960
  //#endregion
9570
- //#region ../blocks/src/system/runtime/nodes/booking-form.consent.ts
9571
- function resolveSelectedAppointmentConsent(service) {
9572
- return service?.consent ? {
9573
- kind: "required-for-selected-service",
9574
- field: toBookingRequirementConsentField(service.consent)
9575
- } : { kind: "not-applicable" };
9576
- }
9577
- function projectSelectedAppointmentConsentIntoForm(form, selectedConsent) {
9578
- if (!form) return null;
9579
- const sourceFields = form.schema?.fields ?? [];
9580
- const baseFields = sourceFields.filter((field) => field.type !== "booking_requirement_consent");
9581
- const fields = selectedConsent.kind === "required-for-selected-service" ? [...baseFields, selectedConsent.field] : baseFields;
9582
- if (selectedConsent.kind === "not-applicable" && baseFields.length === sourceFields.length) return form;
9583
- return {
9584
- ...form,
9585
- schema: {
9586
- ...form.schema,
9587
- fields
9588
- }
9589
- };
9590
- }
9961
+ //#region ../commerce/src/purchase/allocation.ts
9962
+ var init_allocation = __esmMin((() => {})), ORDER_STATUSES, CLOSED_ORDER_STATUSES, ORDER_PAYMENT_METHODS, CHECKOUT_COMMIT_STATES, ORDER_CHECKOUT_RECONCILIATION_STATES, ORDER_ITEM_RECONCILIATION_STATES, ORDER_ITEM_COMMIT_STATES, RESERVATION_FINALIZATION_STATES, DISCOUNT_REDEMPTION_STATUSES, ORDER_ITEM_KINDS;
9963
+ var init_orderTypes = __esmMin((() => {
9964
+ ORDER_STATUSES = [
9965
+ "pending",
9966
+ "paid",
9967
+ "partially_refunded",
9968
+ "refunded",
9969
+ "failed",
9970
+ "cancelled"
9971
+ ];
9972
+ new Set(ORDER_STATUSES);
9973
+ CLOSED_ORDER_STATUSES = ["failed", "cancelled"];
9974
+ new Set(CLOSED_ORDER_STATUSES);
9975
+ ORDER_PAYMENT_METHODS = [
9976
+ "stripe",
9977
+ "store_credit",
9978
+ "mixed",
9979
+ "pass_redemption",
9980
+ "membership_access",
9981
+ "free",
9982
+ "manual",
9983
+ "waived"
9984
+ ];
9985
+ new Set(ORDER_PAYMENT_METHODS);
9986
+ CHECKOUT_COMMIT_STATES = [
9987
+ "pending",
9988
+ "committing",
9989
+ "committed",
9990
+ "compensated"
9991
+ ];
9992
+ new Set(CHECKOUT_COMMIT_STATES);
9993
+ ORDER_CHECKOUT_RECONCILIATION_STATES = [
9994
+ "not_needed",
9995
+ "evidence_pending",
9996
+ "needed"
9997
+ ];
9998
+ new Set(ORDER_CHECKOUT_RECONCILIATION_STATES);
9999
+ ORDER_ITEM_RECONCILIATION_STATES = ["not_needed", "needed"];
10000
+ new Set(ORDER_ITEM_RECONCILIATION_STATES);
10001
+ ORDER_ITEM_COMMIT_STATES = [
10002
+ "pending",
10003
+ "committed",
10004
+ "compensated"
10005
+ ];
10006
+ new Set(ORDER_ITEM_COMMIT_STATES);
10007
+ RESERVATION_FINALIZATION_STATES = [
10008
+ "not_applicable",
10009
+ "reserved",
10010
+ "consumed",
10011
+ "released"
10012
+ ];
10013
+ new Set(RESERVATION_FINALIZATION_STATES);
10014
+ DISCOUNT_REDEMPTION_STATUSES = [
10015
+ "pending",
10016
+ "redeemed",
10017
+ "released",
10018
+ "expired"
10019
+ ];
10020
+ new Set(DISCOUNT_REDEMPTION_STATUSES);
10021
+ ORDER_ITEM_KINDS = [
10022
+ "event_ticket",
10023
+ "product",
10024
+ "pass",
10025
+ "event_series_registration",
10026
+ "appointment",
10027
+ "membership"
10028
+ ];
10029
+ new Set(ORDER_ITEM_KINDS);
10030
+ }));
9591
10031
  //#endregion
9592
- //#region ../blocks/src/system/runtime/nodes/booking-form.state.ts
9593
- function toTrimmedString(value) {
9594
- const trimmed = value?.trim();
9595
- return trimmed ? trimmed : void 0;
10032
+ //#region ../commerce/src/purchase/orderPlanningTypes.ts
10033
+ var init_orderPlanningTypes = __esmMin((() => {}));
10034
+ //#endregion
10035
+ //#region ../commerce/src/utils/assertNever.ts
10036
+ function assertNever(value, message) {
10037
+ if (message) throw new Error(message);
10038
+ throw new Error(`Unexpected value: ${String(value)}`);
9596
10039
  }
9597
- function getSessionIdFromLocation(location) {
9598
- const fromSearch = new URLSearchParams(location.search).get("session_id");
9599
- if (fromSearch) return fromSearch;
9600
- return location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
10040
+ var init_assertNever = __esmMin((() => {}));
10041
+ //#endregion
10042
+ //#region ../commerce/src/purchase/bookingInstalmentSchedule.ts
10043
+ function resolveBookingInitialInstalmentAmountCents(input) {
10044
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10045
+ switch (input.plan.kind) {
10046
+ case "deposit_plus_one_remainder":
10047
+ case "deposit_plus_scheduled_instalments": return clampConfiguredAmount(input.plan.depositAmountCents, totalAmountCents);
10048
+ case "equal_scheduled_instalments": return splitAmountWithRemainderInFirst(totalAmountCents, input.plan.instalmentCount)[0] ?? 0;
10049
+ default: return assertNever(input.plan);
10050
+ }
9601
10051
  }
9602
- function getBookingRedirectStateFromLocation(location) {
9603
- const booking = new URLSearchParams(location.search).get("booking");
9604
- if (booking === "cancelled") return { kind: "cancelled" };
9605
- if (booking === "success") {
9606
- const sessionId = getSessionIdFromLocation(location);
9607
- if (sessionId) return {
9608
- kind: "success",
9609
- sessionId
9610
- };
10052
+ function buildBookingInstalmentSchedule(input) {
10053
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10054
+ switch (input.plan.kind) {
10055
+ case "deposit_plus_one_remainder": {
10056
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
10057
+ const remainderAmountCents = Math.max(0, totalAmountCents - depositAmountCents);
10058
+ return omitZeroAmountFutureRows([createScheduleRow({
10059
+ sequence: 1,
10060
+ stateAtBooking: "paid_today",
10061
+ dueAt: input.anchorAt,
10062
+ amountCents: depositAmountCents
10063
+ }), createScheduleRow({
10064
+ sequence: 2,
10065
+ stateAtBooking: "scheduled",
10066
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, input.plan.remainderDueCount, input.plan.intervalUnit),
10067
+ amountCents: remainderAmountCents
10068
+ })]);
10069
+ }
10070
+ case "deposit_plus_scheduled_instalments": {
10071
+ const plan = input.plan;
10072
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
10073
+ const instalmentAmounts = splitAmountWithRemainderInFirst(Math.max(0, totalAmountCents - depositAmountCents), plan.instalmentCount);
10074
+ return omitZeroAmountFutureRows([createScheduleRow({
10075
+ sequence: 1,
10076
+ stateAtBooking: "paid_today",
10077
+ dueAt: input.anchorAt,
10078
+ amountCents: depositAmountCents
10079
+ }), ...instalmentAmounts.map((amountCents, index) => createScheduleRow({
10080
+ sequence: index + 2,
10081
+ stateAtBooking: "scheduled",
10082
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * (index + 1), plan.intervalUnit),
10083
+ amountCents
10084
+ }))]);
10085
+ }
10086
+ case "equal_scheduled_instalments": {
10087
+ const plan = input.plan;
10088
+ return omitZeroAmountFutureRows(splitAmountWithRemainderInFirst(totalAmountCents, plan.instalmentCount).map((amountCents, index) => createScheduleRow({
10089
+ sequence: index + 1,
10090
+ stateAtBooking: index === 0 ? "paid_today" : "scheduled",
10091
+ dueAt: index === 0 ? input.anchorAt : addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * index, plan.intervalUnit),
10092
+ amountCents
10093
+ })));
10094
+ }
10095
+ default: return assertNever(input.plan);
9611
10096
  }
9612
- return { kind: "none" };
9613
10097
  }
9614
- function resolveAppointmentCheckoutVerificationState(input) {
9615
- if (!input.config) return { tag: "idle" };
9616
- const appointmentId = input.result?.appointmentId ?? null;
9617
- const paymentStatus = input.result?.paymentStatus ?? null;
9618
- const appointmentStatus = input.result?.appointmentStatus ?? null;
9619
- if (input.pollingStatus === "completed" && appointmentId && (paymentStatus === "completed" || paymentStatus === "not_required")) return {
9620
- tag: "confirmed",
9621
- sessionId: input.config.sessionId,
9622
- appointmentId,
9623
- resourceName: input.result?.resourceName ?? null,
9624
- paymentStatus
9625
- };
9626
- if (input.pollingStatus === "timeout") return {
9627
- tag: "timeout",
9628
- sessionId: input.config.sessionId,
9629
- appointmentId,
9630
- message: "We’re still confirming your payment. This can take a minute – you can check again, and you won’t be charged twice."
10098
+ function createScheduleRow(input) {
10099
+ return {
10100
+ id: `payment-${input.sequence}`,
10101
+ sequence: input.sequence,
10102
+ stateAtBooking: input.stateAtBooking,
10103
+ dueAt: input.dueAt,
10104
+ amountCents: input.amountCents
9631
10105
  };
9632
- if (input.pollingStatus === "failed") {
9633
- if (paymentStatus === "refunded") return {
9634
- tag: "failed",
9635
- sessionId: input.config.sessionId,
9636
- reason: "payment_refunded",
9637
- message: "Payment was refunded. Please contact support.",
9638
- appointmentId
9639
- };
9640
- if (paymentStatus === "cancelled") return {
9641
- tag: "failed",
9642
- sessionId: input.config.sessionId,
9643
- reason: "checkout_cancelled",
9644
- message: "Checkout was cancelled before the appointment could be confirmed.",
9645
- appointmentId
9646
- };
9647
- if (appointmentStatus === "cancelled") return {
9648
- tag: "failed",
9649
- sessionId: input.config.sessionId,
9650
- reason: "appointment_cancelled",
9651
- message: "The appointment was cancelled before it could be confirmed.",
9652
- appointmentId
9653
- };
9654
- if (paymentStatus === "failed") return {
9655
- tag: "failed",
9656
- sessionId: input.config.sessionId,
9657
- reason: "payment_failed",
9658
- message: "Payment could not be verified. Please try again.",
9659
- appointmentId
9660
- };
9661
- return {
10106
+ }
10107
+ var init_bookingInstalmentSchedule = __esmMin((() => {
10108
+ init_src();
10109
+ init_assertNever();
10110
+ }));
10111
+ //#endregion
10112
+ //#region ../commerce/src/purchase/bookingPaymentSelection.ts
10113
+ var init_bookingPaymentSelection = __esmMin((() => {}));
10114
+ //#endregion
10115
+ //#region ../commerce/src/purchase/cancellationPolicy.ts
10116
+ var init_cancellationPolicy = __esmMin((() => {}));
10117
+ //#endregion
10118
+ //#region ../commerce/src/purchase/checkoutCollectionPlan.ts
10119
+ var init_checkoutCollectionPlan = __esmMin((() => {}));
10120
+ //#endregion
10121
+ //#region ../commerce/src/purchase/checkoutCommitPlan.ts
10122
+ var init_checkoutCommitPlan = __esmMin((() => {}));
10123
+ //#endregion
10124
+ //#region ../commerce/src/purchase/checkoutDiscountContextPlanning.ts
10125
+ var init_checkoutDiscountContextPlanning = __esmMin((() => {}));
10126
+ //#endregion
10127
+ //#region ../commerce/src/purchase/checkoutErrorCodes.ts
10128
+ var init_checkoutErrorCodes = __esmMin((() => {}));
10129
+ //#endregion
10130
+ //#region ../commerce/src/purchase/checkoutOrderItemProjection.ts
10131
+ var init_checkoutOrderItemProjection = __esmMin((() => {}));
10132
+ //#endregion
10133
+ //#region ../commerce/src/purchase/checkoutPaymentFlow.ts
10134
+ var init_checkoutPaymentFlow = __esmMin((() => {}));
10135
+ //#endregion
10136
+ //#region ../commerce/src/purchase/checkoutPaymentPlanPlanning.ts
10137
+ var init_checkoutPaymentPlanPlanning = __esmMin((() => {}));
10138
+ //#endregion
10139
+ //#region ../commerce/src/purchase/checkoutPaymentTerms.ts
10140
+ var init_checkoutPaymentTerms = __esmMin((() => {}));
10141
+ //#endregion
10142
+ //#region ../commerce/src/purchase/checkoutQuantity.ts
10143
+ var init_checkoutQuantity = __esmMin((() => {}));
10144
+ //#endregion
10145
+ //#region ../commerce/src/purchase/settlement.ts
10146
+ var init_settlement = __esmMin((() => {}));
10147
+ //#endregion
10148
+ //#region ../commerce/src/purchase/checkoutSettlement.ts
10149
+ var init_checkoutSettlement = __esmMin((() => {}));
10150
+ //#endregion
10151
+ //#region ../commerce/src/purchase/checkoutStripeFinalizationPlanning.ts
10152
+ var init_checkoutStripeFinalizationPlanning = __esmMin((() => {}));
10153
+ //#endregion
10154
+ //#region ../commerce/src/purchase/checkoutStripeSessionPlanning.ts
10155
+ var init_checkoutStripeSessionPlanning = __esmMin((() => {})), datedOfferingSharedEngineMetadataShape, orderCheckoutSessionMetadataBaseShape, absentDatedOfferingSharedEngineMetadataShape, LegacyOrderCheckoutSessionMetadataSchema, SharedDatedOfferingOrderCheckoutSessionMetadataSchema;
10156
+ var init_checkoutSessionMetadata = __esmMin((() => {
10157
+ datedOfferingSharedEngineMetadataShape = {
10158
+ datedOfferingEngineContractVersion: z.literal("shared_v1"),
10159
+ datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
10160
+ datedOfferingCapacityHoldId: z.string().uuid(),
10161
+ datedOfferingCapacityHoldAuditRef: z.string().uuid(),
10162
+ customerId: z.string().uuid(),
10163
+ eventSeriesId: z.string().uuid()
10164
+ };
10165
+ z.object(datedOfferingSharedEngineMetadataShape);
10166
+ orderCheckoutSessionMetadataBaseShape = {
10167
+ type: z.literal("order"),
10168
+ site_id: z.string().uuid(),
10169
+ order_id: z.string().uuid().optional(),
10170
+ customer_email: z.string().email().optional(),
10171
+ customer_name: z.string().optional(),
10172
+ product_id: z.string().uuid().optional(),
10173
+ attendee_id: z.string().uuid().optional(),
10174
+ occurrence_id: z.string().uuid().optional(),
10175
+ tickets_count: z.string().optional(),
10176
+ notes: z.string().optional(),
10177
+ discount_redemption_id: z.string().uuid().optional(),
10178
+ discount_code_id: z.string().uuid().optional(),
10179
+ discount_code: z.string().optional(),
10180
+ discount_public_label: z.string().optional(),
10181
+ credit_reservation_id: z.string().uuid().optional(),
10182
+ credit_reserved_cents: z.string().optional(),
10183
+ discount_code_amount_cents: z.string().optional(),
10184
+ order_payment_reason: z.enum([
10185
+ "instalment_payoff",
10186
+ "flexible_balance_initial",
10187
+ "flexible_balance_paydown"
10188
+ ]).optional(),
10189
+ order_payment_plan_id: z.string().uuid().optional(),
10190
+ order_flexible_balance_contract_id: z.string().uuid().optional()
10191
+ };
10192
+ absentDatedOfferingSharedEngineMetadataShape = {
10193
+ datedOfferingEngineContractVersion: z.never().optional(),
10194
+ datedOfferingEngineRouteKind: z.never().optional(),
10195
+ datedOfferingCapacityHoldId: z.never().optional(),
10196
+ datedOfferingCapacityHoldAuditRef: z.never().optional(),
10197
+ customerId: z.never().optional(),
10198
+ eventSeriesId: z.never().optional()
10199
+ };
10200
+ LegacyOrderCheckoutSessionMetadataSchema = z.object({
10201
+ ...orderCheckoutSessionMetadataBaseShape,
10202
+ ...absentDatedOfferingSharedEngineMetadataShape
10203
+ });
10204
+ SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
10205
+ ...orderCheckoutSessionMetadataBaseShape,
10206
+ ...datedOfferingSharedEngineMetadataShape
10207
+ });
10208
+ z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
10209
+ }));
10210
+ //#endregion
10211
+ //#region ../commerce/src/purchase/canonicalRefundPlanner.ts
10212
+ var init_canonicalRefundPlanner = __esmMin((() => {}));
10213
+ //#endregion
10214
+ //#region ../commerce/src/purchase/refundPolicy.ts
10215
+ var init_refundPolicy = __esmMin((() => {}));
10216
+ //#endregion
10217
+ //#region ../commerce/src/purchase/orderItemSupport.ts
10218
+ var init_orderItemSupport = __esmMin((() => {}));
10219
+ //#endregion
10220
+ //#region ../commerce/src/purchase/confirmationEmailPayment.ts
10221
+ var init_confirmationEmailPayment = __esmMin((() => {}));
10222
+ //#endregion
10223
+ //#region ../commerce/src/purchase/discountApplication.ts
10224
+ var init_discountApplication = __esmMin((() => {}));
10225
+ //#endregion
10226
+ //#region ../commerce/src/purchase/oneTimeCheckoutPlanning.ts
10227
+ var init_oneTimeCheckoutPlanning = __esmMin((() => {}));
10228
+ //#endregion
10229
+ //#region ../commerce/src/purchase/order-number.ts
10230
+ var init_order_number = __esmMin((() => {}));
10231
+ //#endregion
10232
+ //#region ../commerce/src/purchase/orderCancellationPlan.ts
10233
+ var init_orderCancellationPlan = __esmMin((() => {}));
10234
+ //#endregion
10235
+ //#region ../commerce/src/purchase/orderTotals.ts
10236
+ var init_orderTotals = __esmMin((() => {}));
10237
+ //#endregion
10238
+ //#region ../commerce/src/purchase/orderConfirmationPlanning.ts
10239
+ var init_orderConfirmationPlanning = __esmMin((() => {}));
10240
+ //#endregion
10241
+ //#region ../commerce/src/purchase/orderCompletionEmailPlan.ts
10242
+ var init_orderCompletionEmailPlan = __esmMin((() => {}));
10243
+ //#endregion
10244
+ //#region ../commerce/src/purchase/orderFulfillmentPlan.ts
10245
+ var init_orderFulfillmentPlan = __esmMin((() => {}));
10246
+ //#endregion
10247
+ //#region ../commerce/src/purchase/orderFulfillmentResult.ts
10248
+ var init_orderFulfillmentResult = __esmMin((() => {}));
10249
+ //#endregion
10250
+ //#region ../commerce/src/purchase/orderHistoryLedgerFilters.ts
10251
+ var init_orderHistoryLedgerFilters = __esmMin((() => {}));
10252
+ //#endregion
10253
+ //#region ../commerce/src/purchase/orderHistorySource.ts
10254
+ var init_orderHistorySource = __esmMin((() => {}));
10255
+ //#endregion
10256
+ //#region ../commerce/src/purchase/orderInstalmentAdminSettlement.ts
10257
+ var init_orderInstalmentAdminSettlement = __esmMin((() => {}));
10258
+ //#endregion
10259
+ //#region ../commerce/src/purchase/orderInstalmentClosure.ts
10260
+ var init_orderInstalmentClosure = __esmMin((() => {}));
10261
+ //#endregion
10262
+ //#region ../commerce/src/purchase/orderInstalmentLifecycle.ts
10263
+ var init_orderInstalmentLifecycle = __esmMin((() => {}));
10264
+ //#endregion
10265
+ //#region ../commerce/src/purchase/orderInstalmentPlan.ts
10266
+ var init_orderInstalmentPlan = __esmMin((() => {})), STRIPE_COMMISSION_FREE_REASONS, historicalContext, percentSchema;
10267
+ var init_stripeCommissionMetadata = __esmMin((() => {
10268
+ init_src();
10269
+ STRIPE_COMMISSION_FREE_REASONS = [
10270
+ "managed_billing",
10271
+ "no_commission_plan",
10272
+ "billing_evidence_invalid",
10273
+ "fee_rounds_to_zero",
10274
+ "payment_not_stripe"
10275
+ ];
10276
+ historicalContext = {
10277
+ currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
10278
+ sourcePlanId: z.string().trim().min(1).optional()
10279
+ };
10280
+ percentSchema = z.number().finite().min(0).max(100);
10281
+ z.discriminatedUnion("kind", [
10282
+ z.object({
10283
+ kind: z.literal("commission_free"),
10284
+ reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
10285
+ ...historicalContext
10286
+ }),
10287
+ z.object({
10288
+ kind: z.literal("application_fee_amount"),
10289
+ amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
10290
+ percent: percentSchema,
10291
+ ...historicalContext
10292
+ }),
10293
+ z.object({
10294
+ kind: z.literal("application_fee_percent"),
10295
+ percent: percentSchema,
10296
+ ...historicalContext
10297
+ })
10298
+ ]);
10299
+ }));
10300
+ //#endregion
10301
+ //#region ../commerce/src/purchase/orderItemMetadata.ts
10302
+ var init_orderItemMetadata = __esmMin((() => {
10303
+ init_stripeCommissionMetadata();
10304
+ }));
10305
+ //#endregion
10306
+ //#region ../commerce/src/purchase/orderListFilters.ts
10307
+ var init_orderListFilters = __esmMin((() => {}));
10308
+ var init_orderPaymentState = __esmMin((() => {
10309
+ init_src();
10310
+ toNonNegativeCents(0);
10311
+ }));
10312
+ //#endregion
10313
+ //#region ../commerce/src/purchase/orderPaymentReceipt.ts
10314
+ var init_orderPaymentReceipt = __esmMin((() => {}));
10315
+ //#endregion
10316
+ //#region ../commerce/src/purchase/pendingCheckoutSessionClaim.ts
10317
+ var init_pendingCheckoutSessionClaim = __esmMin((() => {}));
10318
+ //#endregion
10319
+ //#region ../commerce/src/purchase/orderPaymentLinkPlanning.ts
10320
+ var init_orderPaymentLinkPlanning = __esmMin((() => {
10321
+ init_orderPaymentState();
10322
+ }));
10323
+ //#endregion
10324
+ //#region ../commerce/src/purchase/orderRefundPlanning.ts
10325
+ var init_orderRefundPlanning = __esmMin((() => {}));
10326
+ //#endregion
10327
+ //#region ../commerce/src/purchase/orderRefundPolicy.ts
10328
+ var init_orderRefundPolicy = __esmMin((() => {}));
10329
+ //#endregion
10330
+ //#region ../commerce/src/purchase/persistedCheckoutLines.ts
10331
+ var init_persistedCheckoutLines = __esmMin((() => {}));
10332
+ //#endregion
10333
+ //#region ../commerce/src/purchase/protectedDepositRefundPolicy.ts
10334
+ var init_protectedDepositRefundPolicy = __esmMin((() => {}));
10335
+ //#endregion
10336
+ //#region ../commerce/src/purchase/refundRailSplit.ts
10337
+ var init_refundRailSplit = __esmMin((() => {}));
10338
+ //#endregion
10339
+ //#region ../commerce/src/purchase/shopRefundPlanning.ts
10340
+ var init_shopRefundPlanning = __esmMin((() => {}));
10341
+ //#endregion
10342
+ //#region ../commerce/src/purchase/stripeMinimumCharge.ts
10343
+ var init_stripeMinimumCharge = __esmMin((() => {}));
10344
+ //#endregion
10345
+ //#region ../commerce/src/purchase/stripeCheckoutReturnUrl.ts
10346
+ var init_stripeCheckoutReturnUrl = __esmMin((() => {}));
10347
+ //#endregion
10348
+ //#region ../commerce/src/purchase/checkoutCopy.ts
10349
+ var checkoutCopy;
10350
+ var init_checkoutCopy = __esmMin((() => {
10351
+ checkoutCopy = {
10352
+ /** A payment is still being confirmed; checking again is safe. */
10353
+ checkoutStillConfirming: "We’re still confirming your payment. This can take a minute – you can check again, and you won’t be charged twice.",
10354
+ /** A previous attempt can't be confirmed automatically; the business needs to check it. */
10355
+ checkoutAssistanceRequired: "We can’t confirm your last payment attempt yet. Please don’t pay again – contact the business so they can check it."
10356
+ };
10357
+ }));
10358
+ //#endregion
10359
+ //#region ../commerce/src/purchase/stateTransitions.ts
10360
+ var init_stateTransitions = __esmMin((() => {}));
10361
+ //#endregion
10362
+ //#region ../commerce/src/purchase/event-registration-errors.ts
10363
+ function parseEventRegistrationErrorReason(value) {
10364
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
10365
+ }
10366
+ var eventRegistrationErrors;
10367
+ var init_event_registration_errors = __esmMin((() => {
10368
+ eventRegistrationErrors = {
10369
+ registrationClosed: {
10370
+ message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
10371
+ action: "none"
10372
+ },
10373
+ paymentInvestigationRequired: {
10374
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
10375
+ action: "none"
10376
+ },
10377
+ paymentProviderUnavailable: {
10378
+ message: "We couldn’t reach the payment provider. Please try again in a minute.",
10379
+ action: "retry"
10380
+ },
10381
+ paymentHostUnavailable: {
10382
+ message: "Card payments aren’t available on this web address yet. Please contact the organiser to book.",
10383
+ action: "none"
10384
+ },
10385
+ checkoutTemporarilyUnavailable: {
10386
+ message: "Event payments are temporarily unavailable while we make an update. Please try again later.",
10387
+ action: "retry"
10388
+ },
10389
+ paymentPageUnavailable: {
10390
+ message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
10391
+ action: "retry"
10392
+ },
10393
+ paymentUnavailable: {
10394
+ message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
10395
+ action: "none"
10396
+ },
10397
+ capacityChanged: {
10398
+ message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
10399
+ action: "places"
10400
+ },
10401
+ selectionChanged: {
10402
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
10403
+ action: "places"
10404
+ },
10405
+ registrationPreparationChanged: {
10406
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
10407
+ action: "places"
10408
+ },
10409
+ registrationAlreadyExists: {
10410
+ message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
10411
+ action: "portal"
10412
+ },
10413
+ holdExpired: {
10414
+ message: "Your reservation has timed out. Please check availability and choose your places again.",
10415
+ action: "start"
10416
+ },
10417
+ waitlistUnavailable: {
10418
+ message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
10419
+ action: "event"
10420
+ },
10421
+ paymentContextMismatch: {
10422
+ message: "The payment options for this event have changed. Please check the latest options before continuing.",
10423
+ action: "payment-options"
10424
+ },
10425
+ verificationFailed: {
10426
+ message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
10427
+ action: "none"
10428
+ },
10429
+ idempotencyConflict: {
10430
+ message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
10431
+ action: "portal"
10432
+ },
10433
+ invalidCommitInput: {
10434
+ message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
10435
+ action: "details"
10436
+ }
10437
+ };
10438
+ }));
10439
+ //#endregion
10440
+ //#region ../commerce/src/purchase/eventCheckoutRecoveryWindow.ts
10441
+ var init_eventCheckoutRecoveryWindow = __esmMin((() => {}));
10442
+ //#endregion
10443
+ //#region ../commerce/src/purchase/checkoutPresentation.ts
10444
+ function publishableKeyMode(publishableKey) {
10445
+ if (publishableKey.startsWith("pk_live_")) return "live";
10446
+ if (publishableKey.startsWith("pk_test_")) return "test";
10447
+ return null;
10448
+ }
10449
+ function checkBrowserStripeKey(publishableKey, livemode) {
10450
+ const key = publishableKey?.trim();
10451
+ if (!key) return {
10452
+ tag: "unavailable",
10453
+ reason: "missing_key"
10454
+ };
10455
+ const mode = publishableKeyMode(key);
10456
+ if (mode === null) return {
10457
+ tag: "unavailable",
10458
+ reason: "invalid_key"
10459
+ };
10460
+ return mode === (livemode ? "live" : "test") ? {
10461
+ tag: "ready",
10462
+ publishableKey: key
10463
+ } : {
10464
+ tag: "unavailable",
10465
+ reason: "mode_mismatch"
10466
+ };
10467
+ }
10468
+ var init_checkoutPresentation = __esmMin((() => {}));
10469
+ //#endregion
10470
+ //#region ../commerce/src/purchase/index.ts
10471
+ var init_purchase = __esmMin((() => {
10472
+ init_types();
10473
+ init_allocation();
10474
+ init_orderTypes();
10475
+ init_orderPlanningTypes();
10476
+ init_bookingInstalmentSchedule();
10477
+ init_bookingPaymentSelection();
10478
+ init_cancellationPolicy();
10479
+ init_checkoutCollectionPlan();
10480
+ init_checkoutCommitPlan();
10481
+ init_checkoutDiscountContextPlanning();
10482
+ init_checkoutErrorCodes();
10483
+ init_checkoutOrderItemProjection();
10484
+ init_checkoutPaymentFlow();
10485
+ init_checkoutPaymentPlanPlanning();
10486
+ init_checkoutPaymentTerms();
10487
+ init_checkoutQuantity();
10488
+ init_checkoutSettlement();
10489
+ init_checkoutStripeFinalizationPlanning();
10490
+ init_checkoutStripeSessionPlanning();
10491
+ init_checkoutSessionMetadata();
10492
+ init_canonicalRefundPlanner();
10493
+ init_confirmationEmailPayment();
10494
+ init_discountApplication();
10495
+ init_oneTimeCheckoutPlanning();
10496
+ init_order_number();
10497
+ init_orderCancellationPlan();
10498
+ init_orderConfirmationPlanning();
10499
+ init_orderCompletionEmailPlan();
10500
+ init_orderFulfillmentPlan();
10501
+ init_orderFulfillmentResult();
10502
+ init_orderHistoryLedgerFilters();
10503
+ init_orderHistorySource();
10504
+ init_orderInstalmentAdminSettlement();
10505
+ init_orderInstalmentClosure();
10506
+ init_orderInstalmentLifecycle();
10507
+ init_orderInstalmentPlan();
10508
+ init_orderItemMetadata();
10509
+ init_orderItemSupport();
10510
+ init_orderListFilters();
10511
+ init_orderPaymentState();
10512
+ init_orderPaymentReceipt();
10513
+ init_orderPaymentLinkPlanning();
10514
+ init_orderRefundPlanning();
10515
+ init_orderRefundPolicy();
10516
+ init_orderTotals();
10517
+ init_persistedCheckoutLines();
10518
+ init_pendingCheckoutSessionClaim();
10519
+ init_protectedDepositRefundPolicy();
10520
+ init_refundRailSplit();
10521
+ init_refundPolicy();
10522
+ init_settlement();
10523
+ init_shopRefundPlanning();
10524
+ init_stripeMinimumCharge();
10525
+ init_stripeCheckoutReturnUrl();
10526
+ init_checkoutCopy();
10527
+ init_stateTransitions();
10528
+ init_event_registration_errors();
10529
+ init_eventCheckoutRecoveryWindow();
10530
+ init_stripeCommissionMetadata();
10531
+ init_checkoutPresentation();
10532
+ }));
10533
+ //#endregion
10534
+ //#region ../blocks/src/system/runtime/nodes/booking-form.reserved-fields.ts
10535
+ const BOOKING_FORM_DATA_RESERVED_KEY_VALUES = [
10536
+ "serviceId",
10537
+ "resourceId",
10538
+ "selectedDate",
10539
+ "selectedSlot",
10540
+ "discountCode",
10541
+ "selectedSlidingAmountInput",
10542
+ "selectedCollectionOptionKind",
10543
+ "selectedAppointmentPackageId",
10544
+ "mailingListOptIn"
10545
+ ];
10546
+ const BOOKING_FORM_DATA_RESERVED_KEYS = new Set(BOOKING_FORM_DATA_RESERVED_KEY_VALUES);
10547
+ //#endregion
10548
+ //#region ../blocks/src/system/runtime/nodes/booking-form.consent.ts
10549
+ function resolveSelectedAppointmentConsent(service) {
10550
+ return service?.consent ? {
10551
+ kind: "required-for-selected-service",
10552
+ field: toBookingRequirementConsentField(service.consent)
10553
+ } : { kind: "not-applicable" };
10554
+ }
10555
+ function projectSelectedAppointmentConsentIntoForm(form, selectedConsent) {
10556
+ if (!form) return null;
10557
+ const sourceFields = form.schema?.fields ?? [];
10558
+ const baseFields = sourceFields.filter((field) => field.type !== "booking_requirement_consent");
10559
+ const fields = selectedConsent.kind === "required-for-selected-service" ? [...baseFields, selectedConsent.field] : baseFields;
10560
+ if (selectedConsent.kind === "not-applicable" && baseFields.length === sourceFields.length) return form;
10561
+ return {
10562
+ ...form,
10563
+ schema: {
10564
+ ...form.schema,
10565
+ fields
10566
+ }
10567
+ };
10568
+ }
10569
+ //#endregion
10570
+ //#region ../blocks/src/system/runtime/nodes/booking-form.state.ts
10571
+ init_src();
10572
+ init_purchase();
10573
+ function toTrimmedString(value) {
10574
+ const trimmed = value?.trim();
10575
+ return trimmed ? trimmed : void 0;
10576
+ }
10577
+ function getSessionIdFromLocation(location) {
10578
+ const fromSearch = new URLSearchParams(location.search).get("session_id");
10579
+ if (fromSearch) return fromSearch;
10580
+ return location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
10581
+ }
10582
+ function getBookingRedirectStateFromLocation(location) {
10583
+ const booking = new URLSearchParams(location.search).get("booking");
10584
+ if (booking === "cancelled") return { kind: "cancelled" };
10585
+ if (booking === "success") {
10586
+ const sessionId = getSessionIdFromLocation(location);
10587
+ if (sessionId) return {
10588
+ kind: "success",
10589
+ sessionId
10590
+ };
10591
+ }
10592
+ return { kind: "none" };
10593
+ }
10594
+ function resolveAppointmentCheckoutVerificationState(input) {
10595
+ if (!input.config) return { tag: "idle" };
10596
+ const appointmentId = input.result?.appointmentId ?? null;
10597
+ const paymentStatus = input.result?.paymentStatus ?? null;
10598
+ const appointmentStatus = input.result?.appointmentStatus ?? null;
10599
+ if (input.pollingStatus === "completed" && appointmentId && (paymentStatus === "completed" || paymentStatus === "not_required")) return {
10600
+ tag: "confirmed",
10601
+ sessionId: input.config.sessionId,
10602
+ appointmentId,
10603
+ resourceName: input.result?.resourceName ?? null,
10604
+ paymentStatus
10605
+ };
10606
+ if (input.pollingStatus === "timeout") return {
10607
+ tag: "timeout",
10608
+ sessionId: input.config.sessionId,
10609
+ appointmentId,
10610
+ message: checkoutCopy.checkoutStillConfirming
10611
+ };
10612
+ if (input.pollingStatus === "failed") {
10613
+ if (paymentStatus === "refunded") return {
10614
+ tag: "failed",
10615
+ sessionId: input.config.sessionId,
10616
+ reason: "payment_refunded",
10617
+ message: "Payment was refunded. Please contact support.",
10618
+ appointmentId
10619
+ };
10620
+ if (paymentStatus === "cancelled") return {
10621
+ tag: "failed",
10622
+ sessionId: input.config.sessionId,
10623
+ reason: "checkout_cancelled",
10624
+ message: "Checkout was cancelled before the appointment could be confirmed.",
10625
+ appointmentId
10626
+ };
10627
+ if (appointmentStatus === "cancelled") return {
10628
+ tag: "failed",
10629
+ sessionId: input.config.sessionId,
10630
+ reason: "appointment_cancelled",
10631
+ message: "The appointment was cancelled before it could be confirmed.",
10632
+ appointmentId
10633
+ };
10634
+ if (paymentStatus === "failed") return {
10635
+ tag: "failed",
10636
+ sessionId: input.config.sessionId,
10637
+ reason: "payment_failed",
10638
+ message: "Payment could not be verified. Please try again.",
10639
+ appointmentId
10640
+ };
10641
+ return {
9662
10642
  tag: "failed",
9663
10643
  sessionId: input.config.sessionId,
9664
10644
  reason: "unknown",
@@ -10089,6 +11069,7 @@ function useSelectedAppointmentConsentForm(form, selectedService) {
10089
11069
  }
10090
11070
  //#endregion
10091
11071
  //#region ../blocks/src/utils/date-formatting.ts
11072
+ init_src();
10092
11073
  /**
10093
11074
  * Resolve the browser/runtime timezone for booking surfaces.
10094
11075
  * Falls back to UTC when the environment does not expose a valid zone.
@@ -10302,15 +11283,7 @@ function availableDatesReducer(state, action) {
10302
11283
  }
10303
11284
  //#endregion
10304
11285
  //#region ../blocks/src/system/runtime/hooks/useAvailableDates.ts
10305
- /**
10306
- * Custom hook for fetching dates with available appointment slots
10307
- *
10308
- * Uses the Block API Client for type-safe API calls.
10309
- * Must be used within a BlockApiProvider.
10310
- *
10311
- * Prefetches available dates for a date range with support for progressive loading.
10312
- * Returns a Set for O(1) lookup when filtering DatePicker options.
10313
- */
11286
+ init_src();
10314
11287
  const AVAILABILITY_REFRESH_INTERVAL_MS$1 = 3e4;
10315
11288
  const AVAILABILITY_REFRESH_JITTER_MS$1 = 5e3;
10316
11289
  /**
@@ -10489,6 +11462,7 @@ function availableSlotsReducer(state, action) {
10489
11462
  * Uses the Block API Client for type-safe API calls.
10490
11463
  * Must be used within a BlockApiProvider.
10491
11464
  */
11465
+ init_src();
10492
11466
  const AVAILABILITY_REFRESH_INTERVAL_MS = 3e4;
10493
11467
  const AVAILABILITY_REFRESH_JITTER_MS = 5e3;
10494
11468
  /**
@@ -10969,248 +11943,21 @@ function useDiscountCodeUi(options) {
10969
11943
  };
10970
11944
  }
10971
11945
  //#endregion
10972
- //#region ../commerce/src/utils/assertNever.ts
10973
- function assertNever(value, message) {
10974
- if (message) throw new Error(message);
10975
- throw new Error(`Unexpected value: ${String(value)}`);
11946
+ //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
11947
+ function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
11948
+ return {
11949
+ title: "Pay in full",
11950
+ description: "Pay everything today and your booking is confirmed.",
11951
+ ctaLabel: `Pay ${formattedTotal} now`
11952
+ };
10976
11953
  }
10977
- //#endregion
10978
- //#region ../commerce/src/purchase/bookingInstalmentSchedule.ts
10979
- function resolveBookingInitialInstalmentAmountCents(input) {
10980
- const totalAmountCents = Math.max(0, input.totalAmountCents);
10981
- switch (input.plan.kind) {
10982
- case "deposit_plus_one_remainder":
10983
- case "deposit_plus_scheduled_instalments": return clampConfiguredAmount(input.plan.depositAmountCents, totalAmountCents);
10984
- case "equal_scheduled_instalments": return splitAmountWithRemainderInFirst(totalAmountCents, input.plan.instalmentCount)[0] ?? 0;
10985
- default: return assertNever(input.plan);
10986
- }
10987
- }
10988
- function buildBookingInstalmentSchedule(input) {
10989
- const totalAmountCents = Math.max(0, input.totalAmountCents);
10990
- switch (input.plan.kind) {
10991
- case "deposit_plus_one_remainder": {
10992
- const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
10993
- const remainderAmountCents = Math.max(0, totalAmountCents - depositAmountCents);
10994
- return omitZeroAmountFutureRows([createScheduleRow({
10995
- sequence: 1,
10996
- stateAtBooking: "paid_today",
10997
- dueAt: input.anchorAt,
10998
- amountCents: depositAmountCents
10999
- }), createScheduleRow({
11000
- sequence: 2,
11001
- stateAtBooking: "scheduled",
11002
- dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, input.plan.remainderDueCount, input.plan.intervalUnit),
11003
- amountCents: remainderAmountCents
11004
- })]);
11005
- }
11006
- case "deposit_plus_scheduled_instalments": {
11007
- const plan = input.plan;
11008
- const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
11009
- const instalmentAmounts = splitAmountWithRemainderInFirst(Math.max(0, totalAmountCents - depositAmountCents), plan.instalmentCount);
11010
- return omitZeroAmountFutureRows([createScheduleRow({
11011
- sequence: 1,
11012
- stateAtBooking: "paid_today",
11013
- dueAt: input.anchorAt,
11014
- amountCents: depositAmountCents
11015
- }), ...instalmentAmounts.map((amountCents, index) => createScheduleRow({
11016
- sequence: index + 2,
11017
- stateAtBooking: "scheduled",
11018
- dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * (index + 1), plan.intervalUnit),
11019
- amountCents
11020
- }))]);
11021
- }
11022
- case "equal_scheduled_instalments": {
11023
- const plan = input.plan;
11024
- return omitZeroAmountFutureRows(splitAmountWithRemainderInFirst(totalAmountCents, plan.instalmentCount).map((amountCents, index) => createScheduleRow({
11025
- sequence: index + 1,
11026
- stateAtBooking: index === 0 ? "paid_today" : "scheduled",
11027
- dueAt: index === 0 ? input.anchorAt : addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * index, plan.intervalUnit),
11028
- amountCents
11029
- })));
11030
- }
11031
- default: return assertNever(input.plan);
11032
- }
11033
- }
11034
- function createScheduleRow(input) {
11035
- return {
11036
- id: `payment-${input.sequence}`,
11037
- sequence: input.sequence,
11038
- stateAtBooking: input.stateAtBooking,
11039
- dueAt: input.dueAt,
11040
- amountCents: input.amountCents
11041
- };
11042
- }
11043
- //#endregion
11044
- //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
11045
- const datedOfferingSharedEngineMetadataShape = {
11046
- datedOfferingEngineContractVersion: z.literal("shared_v1"),
11047
- datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
11048
- datedOfferingCapacityHoldId: z.string().uuid(),
11049
- datedOfferingCapacityHoldAuditRef: z.string().uuid(),
11050
- customerId: z.string().uuid(),
11051
- eventSeriesId: z.string().uuid()
11052
- };
11053
- z.object(datedOfferingSharedEngineMetadataShape);
11054
- const orderCheckoutSessionMetadataBaseShape = {
11055
- type: z.literal("order"),
11056
- site_id: z.string().uuid(),
11057
- order_id: z.string().uuid().optional(),
11058
- customer_email: z.string().email().optional(),
11059
- customer_name: z.string().optional(),
11060
- product_id: z.string().uuid().optional(),
11061
- attendee_id: z.string().uuid().optional(),
11062
- occurrence_id: z.string().uuid().optional(),
11063
- tickets_count: z.string().optional(),
11064
- notes: z.string().optional(),
11065
- discount_redemption_id: z.string().uuid().optional(),
11066
- discount_code_id: z.string().uuid().optional(),
11067
- discount_code: z.string().optional(),
11068
- discount_public_label: z.string().optional(),
11069
- credit_reservation_id: z.string().uuid().optional(),
11070
- credit_reserved_cents: z.string().optional(),
11071
- discount_code_amount_cents: z.string().optional(),
11072
- order_payment_reason: z.enum([
11073
- "instalment_payoff",
11074
- "flexible_balance_initial",
11075
- "flexible_balance_paydown"
11076
- ]).optional(),
11077
- order_payment_plan_id: z.string().uuid().optional(),
11078
- order_flexible_balance_contract_id: z.string().uuid().optional()
11079
- };
11080
- const absentDatedOfferingSharedEngineMetadataShape = {
11081
- datedOfferingEngineContractVersion: z.never().optional(),
11082
- datedOfferingEngineRouteKind: z.never().optional(),
11083
- datedOfferingCapacityHoldId: z.never().optional(),
11084
- datedOfferingCapacityHoldAuditRef: z.never().optional(),
11085
- customerId: z.never().optional(),
11086
- eventSeriesId: z.never().optional()
11087
- };
11088
- const LegacyOrderCheckoutSessionMetadataSchema = z.object({
11089
- ...orderCheckoutSessionMetadataBaseShape,
11090
- ...absentDatedOfferingSharedEngineMetadataShape
11091
- });
11092
- const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
11093
- ...orderCheckoutSessionMetadataBaseShape,
11094
- ...datedOfferingSharedEngineMetadataShape
11095
- });
11096
- z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
11097
- //#endregion
11098
- //#region ../commerce/src/purchase/stripeCommissionMetadata.ts
11099
- /** Reasons are payment evidence, not an independent pricing policy. */
11100
- const STRIPE_COMMISSION_FREE_REASONS = [
11101
- "managed_billing",
11102
- "no_commission_plan",
11103
- "billing_evidence_invalid",
11104
- "fee_rounds_to_zero",
11105
- "payment_not_stripe"
11106
- ];
11107
- const historicalContext = {
11108
- currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
11109
- sourcePlanId: z.string().trim().min(1).optional()
11110
- };
11111
- const percentSchema = z.number().finite().min(0).max(100);
11112
- z.discriminatedUnion("kind", [
11113
- z.object({
11114
- kind: z.literal("commission_free"),
11115
- reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
11116
- ...historicalContext
11117
- }),
11118
- z.object({
11119
- kind: z.literal("application_fee_amount"),
11120
- amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
11121
- percent: percentSchema,
11122
- ...historicalContext
11123
- }),
11124
- z.object({
11125
- kind: z.literal("application_fee_percent"),
11126
- percent: percentSchema,
11127
- ...historicalContext
11128
- })
11129
- ]);
11130
- toNonNegativeCents(0);
11131
- //#endregion
11132
- //#region ../commerce/src/purchase/event-registration-errors.ts
11133
- const eventRegistrationErrors = {
11134
- registrationClosed: {
11135
- message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
11136
- action: "none"
11137
- },
11138
- paymentInvestigationRequired: {
11139
- message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
11140
- action: "none"
11141
- },
11142
- paymentProviderUnavailable: {
11143
- message: "We couldn’t reach the payment provider. Please try again in a minute.",
11144
- action: "retry"
11145
- },
11146
- paymentPageUnavailable: {
11147
- message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
11148
- action: "retry"
11149
- },
11150
- paymentUnavailable: {
11151
- message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
11152
- action: "none"
11153
- },
11154
- capacityChanged: {
11155
- message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
11156
- action: "places"
11157
- },
11158
- selectionChanged: {
11159
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11160
- action: "places"
11161
- },
11162
- registrationPreparationChanged: {
11163
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11164
- action: "places"
11165
- },
11166
- registrationAlreadyExists: {
11167
- message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
11168
- action: "portal"
11169
- },
11170
- holdExpired: {
11171
- message: "Your reservation has timed out. Please check availability and choose your places again.",
11172
- action: "start"
11173
- },
11174
- waitlistUnavailable: {
11175
- message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
11176
- action: "event"
11177
- },
11178
- paymentContextMismatch: {
11179
- message: "The payment options for this event have changed. Please check the latest options before continuing.",
11180
- action: "payment-options"
11181
- },
11182
- verificationFailed: {
11183
- message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
11184
- action: "none"
11185
- },
11186
- idempotencyConflict: {
11187
- message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
11188
- action: "portal"
11189
- },
11190
- invalidCommitInput: {
11191
- message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
11192
- action: "details"
11193
- }
11194
- };
11195
- function parseEventRegistrationErrorReason(value) {
11196
- return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
11197
- }
11198
- //#endregion
11199
- //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
11200
- function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
11201
- return {
11202
- title: "Pay in full",
11203
- description: "Pay everything today and your booking is confirmed.",
11204
- ctaLabel: `Pay ${formattedTotal} now`
11205
- };
11206
- }
11207
- function buildDeferredManualBookingPaymentOptionCopy() {
11208
- return {
11209
- title: "Pay offline",
11210
- description: "Book now and pay the business later, outside the platform.",
11211
- helperText: "Nothing is due today.",
11212
- ctaLabel: "Book now"
11213
- };
11954
+ function buildDeferredManualBookingPaymentOptionCopy() {
11955
+ return {
11956
+ title: "Pay offline",
11957
+ description: "Book now and pay the business later, outside the platform.",
11958
+ helperText: "Nothing is due today.",
11959
+ ctaLabel: "Book now"
11960
+ };
11214
11961
  }
11215
11962
  function buildInstalmentBookingPaymentOptionCopy(input) {
11216
11963
  return {
@@ -11240,11 +11987,7 @@ function formatDepositRefundabilityLabel(depositRefundability) {
11240
11987
  }
11241
11988
  //#endregion
11242
11989
  //#region ../blocks/src/system/runtime/shared/utils/formatting.ts
11243
- /**
11244
- * Shared Formatting Utilities
11245
- *
11246
- * Currency and date formatting helpers for registration blocks.
11247
- */
11990
+ init_src();
11248
11991
  /**
11249
11992
  * Format a price in cents to a localized currency string.
11250
11993
  *
@@ -11258,6 +12001,8 @@ function formatPrice(cents, currency = "GBP", locale) {
11258
12001
  }
11259
12002
  //#endregion
11260
12003
  //#region ../blocks/src/system/runtime/shared/bookingPaymentOptions.ts
12004
+ init_purchase();
12005
+ init_src();
11261
12006
  function resolveBookingPaymentDueNowCents(input) {
11262
12007
  switch (input.option.kind) {
11263
12008
  case "upfront": return input.totalCents;
@@ -11555,6 +12300,7 @@ function isBookingFieldValue(value) {
11555
12300
  }
11556
12301
  //#endregion
11557
12302
  //#region ../blocks/src/system/runtime/nodes/booking-form.headless.state.ts
12303
+ init_src();
11558
12304
  const unsafeAsBookingFieldId = (id) => id;
11559
12305
  function createInitialBookingFlowReducerState(input) {
11560
12306
  const initialData = input.initialData ?? {};
@@ -12249,6 +12995,7 @@ function isRecord$3(value) {
12249
12995
  }
12250
12996
  //#endregion
12251
12997
  //#region ../blocks/src/system/runtime/hooks/useHeadlessBookingFlow.ts
12998
+ init_src();
12252
12999
  function HeadlessBookingProvider$1({ config, children }) {
12253
13000
  return React.createElement(BlockApiProvider, {
12254
13001
  config,
@@ -13186,6 +13933,7 @@ function clsx() {
13186
13933
  for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
13187
13934
  return n;
13188
13935
  }
13936
+ var init_clsx = __esmMin((() => {}));
13189
13937
  //#endregion
13190
13938
  //#region ../blocks/src/system/runtime/nodes/spinner.tsx
13191
13939
  function resolveColorStyle(color) {
@@ -13236,8 +13984,12 @@ function SpinnerNode({ className, size = "md", color, strokeWidth = 3, srLabel,
13236
13984
  }) : null]
13237
13985
  });
13238
13986
  }
13987
+ var init_spinner = __esmMin((() => {
13988
+ init_clsx();
13989
+ }));
13239
13990
  //#endregion
13240
13991
  //#region ../blocks/src/system/runtime/shared/components/ThemedButton.tsx
13992
+ init_spinner();
13241
13993
  function themedButtonClasses(variant, size, extraClassName) {
13242
13994
  return [
13243
13995
  ...themeButtonVariantClassNames(variant),
@@ -13773,6 +14525,7 @@ function isUnsafePathSegment(segment) {
13773
14525
  }
13774
14526
  //#endregion
13775
14527
  //#region ../media-core/src/fileStorage.ts
14528
+ init_src();
13776
14529
  const FILE_STORAGE_BUCKETS = {
13777
14530
  publicSite: unsafeAsStorageBucketName("media"),
13778
14531
  privateSite: unsafeAsStorageBucketName("site-files-private"),
@@ -14000,6 +14753,7 @@ function mediaIdentifierOrFallback(current, fallback) {
14000
14753
  }
14001
14754
  //#endregion
14002
14755
  //#region ../blocks/src/system/runtime/nodes/media.tsx
14756
+ init_src();
14003
14757
  const MAX_RENDER_DIMENSION = 4096;
14004
14758
  const RELATIVE_IMG_PROXY_BASE_PATH = "/api/img";
14005
14759
  function getValidSourceDimension(value) {
@@ -14480,6 +15234,7 @@ function BookingConsentAgreement({ agreement, showTitle = true, title, titleId }
14480
15234
  }
14481
15235
  //#endregion
14482
15236
  //#region ../blocks/src/system/runtime/shared/components/CheckboxChoice.tsx
15237
+ init_clsx();
14483
15238
  /**
14484
15239
  * The customer-facing checkbox every block renders. Styling comes from the
14485
15240
  * theme's input CSS (`.form-check`, `.form-checkbox`), so it follows each
@@ -14519,6 +15274,7 @@ function BookingMailingListChoice({ booking }) {
14519
15274
  }
14520
15275
  //#endregion
14521
15276
  //#region ../blocks/src/system/runtime/nodes/booking-form.service-choices.tsx
15277
+ init_src();
14522
15278
  function optionCardClassName(isSelected) {
14523
15279
  return `rb-option-card${isSelected ? " rb-option-card--selected" : ""}`;
14524
15280
  }
@@ -14609,6 +15365,7 @@ function ServiceChoiceGrid({ booking, choices }) {
14609
15365
  }
14610
15366
  //#endregion
14611
15367
  //#region ../blocks/src/system/runtime/nodes/booking-form.submit-actions.tsx
15368
+ init_src();
14612
15369
  function resolvePrimaryActionLabel(isLastStep, requiresPayment) {
14613
15370
  if (!isLastStep) return "Continue";
14614
15371
  return requiresPayment ? "Continue to payment" : "Complete";
@@ -14675,6 +15432,8 @@ function BookingFormSubmitActions({ booking, onSubmit }) {
14675
15432
  }
14676
15433
  //#endregion
14677
15434
  //#region ../blocks/src/system/runtime/nodes/booking-form.default-ui.tsx
15435
+ init_src();
15436
+ init_spinner();
14678
15437
  function formatBookingAmount(amount, currency) {
14679
15438
  return formatCurrencyAmount(amount, currency, { decimals: "auto" });
14680
15439
  }
@@ -15361,28 +16120,6 @@ function scrollToBlock(anchorId) {
15361
16120
  });
15362
16121
  }
15363
16122
  //#endregion
15364
- //#region ../blocks/src/system/runtime/shared/utils/urlParams.ts
15365
- /**
15366
- * Consume multiple query params from the current URL's search string.
15367
- *
15368
- * Returns a record of consumed values (missing params are null) and removes
15369
- * all provided params from the URL in a single replaceState call.
15370
- */
15371
- function consumeSearchParams(paramNames) {
15372
- const url = new URL(window.location.href);
15373
- const values = Object.fromEntries(paramNames.map((name) => [name, url.searchParams.get(name)]));
15374
- let changed = false;
15375
- for (const name of paramNames) if (url.searchParams.has(name)) {
15376
- url.searchParams.delete(name);
15377
- changed = true;
15378
- }
15379
- if (changed) {
15380
- const newUrl = url.pathname + (url.search ? url.search : "") + url.hash;
15381
- window.history.replaceState({}, "", newUrl);
15382
- }
15383
- return values;
15384
- }
15385
- //#endregion
15386
16123
  //#region ../blocks/src/system/runtime/shared/components/StateIcon.tsx
15387
16124
  /**
15388
16125
  * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
@@ -15915,16 +16652,221 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
15915
16652
  });
15916
16653
  };
15917
16654
  //#endregion
16655
+ //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
16656
+ /** One admission decision for navigation, labels and completion. Email recovery
16657
+ * permits navigation only; submission remains the owner of payment recovery. */
16658
+ function resolveRegistrationAdmission(input) {
16659
+ if (input.hasWaitlistClaim) return { kind: "resume" };
16660
+ if (input.eligibilityLoading) return { kind: "checking" };
16661
+ if (input.eligibilityError) return {
16662
+ kind: "closed",
16663
+ reason: "optionsUnavailable",
16664
+ message: input.eligibilityError
16665
+ };
16666
+ if (!input.eligibility) return { kind: "checking" };
16667
+ const { registration, availability } = input.eligibility;
16668
+ if (registration.kind === "pending_payment") return { kind: "resume" };
16669
+ if (registration.kind === "waitlisted") return {
16670
+ kind: "closed",
16671
+ reason: "alreadyWaitlisted",
16672
+ message: "You're already on the waitlist for this event."
16673
+ };
16674
+ return admissionFromAvailability(availability, input.isAuthenticated);
16675
+ }
16676
+ function admissionFromAvailability(availability, isAuthenticated) {
16677
+ switch (availability.kind) {
16678
+ case "available": return { kind: "open" };
16679
+ case "waitlist": return {
16680
+ kind: "waitlist",
16681
+ recovery: isAuthenticated ? "none" : "byEmail"
16682
+ };
16683
+ case "unavailable": switch (availability.reason) {
16684
+ case "full": return {
16685
+ kind: "fullyBooked",
16686
+ recovery: isAuthenticated ? "none" : "byEmail"
16687
+ };
16688
+ case "paymentUnavailable": return {
16689
+ kind: "closed",
16690
+ reason: "unavailable",
16691
+ message: "Payment options are not available for this event."
16692
+ };
16693
+ case "selectionRequired": return { kind: "open" };
16694
+ case "bookingClosed": return {
16695
+ kind: "closed",
16696
+ reason: "unavailable",
16697
+ message: "Registration is not available for this event."
16698
+ };
16699
+ }
16700
+ }
16701
+ }
16702
+ function stepAfterTickets(admission) {
16703
+ switch (admission.kind) {
16704
+ case "open":
16705
+ case "resume":
16706
+ case "waitlist": return "enter-details";
16707
+ case "fullyBooked": return "fully-booked";
16708
+ case "checking":
16709
+ case "closed": return "select-tickets";
16710
+ }
16711
+ }
16712
+ function resolveRegistrationAvailabilityBlocker(admission) {
16713
+ switch (admission.kind) {
16714
+ case "open":
16715
+ case "resume":
16716
+ case "waitlist": return null;
16717
+ case "fullyBooked": return admission.recovery === "none" ? {
16718
+ kind: "unavailable",
16719
+ message: "This event is fully booked."
16720
+ } : null;
16721
+ case "checking": return {
16722
+ kind: "pending",
16723
+ message: "Checking availability..."
16724
+ };
16725
+ case "closed": return {
16726
+ kind: "unavailable",
16727
+ message: admission.message
16728
+ };
16729
+ }
16730
+ }
16731
+ function resolvePricingSelectionBlocker(input) {
16732
+ if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
16733
+ return input.slidingScaleSelectionMessage;
16734
+ }
16735
+ /** Submit owns fresh admission. Open quotes do not depend on an email lookup. */
16736
+ function resolveGuestNextStepCheck(admission, request) {
16737
+ switch (admission.kind) {
16738
+ case "open":
16739
+ case "resume": return {
16740
+ kind: "skip",
16741
+ outcome: { kind: "continue" }
16742
+ };
16743
+ case "checking": return {
16744
+ kind: "blocked",
16745
+ message: "Checking availability..."
16746
+ };
16747
+ case "closed": return {
16748
+ kind: "blocked",
16749
+ message: admission.message
16750
+ };
16751
+ case "fullyBooked":
16752
+ if (admission.recovery === "none") return {
16753
+ kind: "blocked",
16754
+ message: "This event is fully booked."
16755
+ };
16756
+ return recoveryCheckRequest(request);
16757
+ case "waitlist": return admission.recovery === "none" ? {
16758
+ kind: "skip",
16759
+ outcome: { kind: "waitlist" }
16760
+ } : recoveryCheckRequest(request);
16761
+ }
16762
+ }
16763
+ function recoveryCheckRequest(request) {
16764
+ return request ? {
16765
+ kind: "check",
16766
+ request
16767
+ } : {
16768
+ kind: "blocked",
16769
+ message: "Choose an event before checking your booking."
16770
+ };
16771
+ }
16772
+ function resolveRegistrationTicketContinuation(input) {
16773
+ if (input.isCheckingExistingRegistration) return {
16774
+ kind: "blocked",
16775
+ label: "Checking registration...",
16776
+ pending: true,
16777
+ message: "Your booking options are being checked."
16778
+ };
16779
+ if (input.ticketSelectionRequired && !input.hasValidTicketSelection) return {
16780
+ kind: "blocked",
16781
+ label: "Choose a ticket",
16782
+ pending: false,
16783
+ message: "Choose at least one available ticket to continue."
16784
+ };
16785
+ switch (input.admission.kind) {
16786
+ case "checking": return {
16787
+ kind: "blocked",
16788
+ label: "Checking availability...",
16789
+ pending: true,
16790
+ message: "Your booking options are being checked."
16791
+ };
16792
+ case "closed": return {
16793
+ kind: "blocked",
16794
+ label: input.admission.reason === "alreadyWaitlisted" ? "Already on waitlist" : input.admission.reason === "optionsUnavailable" ? "Availability unavailable" : "Registration unavailable",
16795
+ pending: false,
16796
+ message: input.admission.message
16797
+ };
16798
+ case "open":
16799
+ case "resume":
16800
+ case "waitlist":
16801
+ case "fullyBooked": return {
16802
+ kind: "advance",
16803
+ admission: input.admission,
16804
+ label: "Continue",
16805
+ pending: false
16806
+ };
16807
+ }
16808
+ }
16809
+ //#endregion
16810
+ //#region ../blocks/src/system/runtime/nodes/event-registration/useRegistrationAdmission.ts
16811
+ /** Owns admission and its navigation commands; renderers receive decisions. */
16812
+ function useRegistrationAdmission(input) {
16813
+ const { eligibility, eligibilityError, eligibilityLoading, hasWaitlistClaim, isAuthenticated, dispatchFlow } = input;
16814
+ const admission = useMemo(() => resolveRegistrationAdmission({
16815
+ eligibility,
16816
+ eligibilityError,
16817
+ eligibilityLoading,
16818
+ hasWaitlistClaim,
16819
+ isAuthenticated
16820
+ }), [
16821
+ eligibility,
16822
+ eligibilityError,
16823
+ eligibilityLoading,
16824
+ hasWaitlistClaim,
16825
+ isAuthenticated
16826
+ ]);
16827
+ useEffect(() => {
16828
+ dispatchFlow({
16829
+ type: "admission-updated",
16830
+ admission
16831
+ });
16832
+ }, [admission, dispatchFlow]);
16833
+ const ticketContinuation = resolveRegistrationTicketContinuation({
16834
+ admission,
16835
+ ticketSelectionRequired: input.ticketSelectionRequired,
16836
+ hasValidTicketSelection: input.hasValidTicketSelection,
16837
+ isCheckingExistingRegistration: isAuthenticated && input.existingRegistrationLoading
16838
+ });
16839
+ const handleTicketsComplete = () => {
16840
+ if (ticketContinuation.kind === "blocked") return {
16841
+ ok: false,
16842
+ reason: "blocked",
16843
+ message: ticketContinuation.message
16844
+ };
16845
+ dispatchFlow({
16846
+ type: "tickets-completed",
16847
+ admission: ticketContinuation.admission
16848
+ });
16849
+ return { ok: true };
16850
+ };
16851
+ const onRecoveryChecked = (outcome) => dispatchFlow({
16852
+ type: "recovery-checked",
16853
+ outcome
16854
+ });
16855
+ return {
16856
+ admission,
16857
+ ticketContinuation,
16858
+ handleTicketsComplete,
16859
+ onRecoveryChecked
16860
+ };
16861
+ }
16862
+ //#endregion
15918
16863
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
15919
16864
  function resolveRegistrationRecoveryAction(step, action) {
15920
16865
  if (step === "payment-failed") return "payment-options";
15921
16866
  if (step === "payment-status") return "none";
15922
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
16867
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "payment") return "none";
15923
16868
  return action;
15924
16869
  }
15925
- function canRecoverToWaitlist(eligibility) {
15926
- return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
15927
- }
15928
16870
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
15929
16871
  return enabled || step === "error" && action === "places";
15930
16872
  }
@@ -15938,7 +16880,6 @@ function resetRegistrationAfterExpiry(input) {
15938
16880
  const mode = input.preSelectedEvent?.deliveryMode;
15939
16881
  input.setSelectedAttendanceMode(mode === "online" || mode === "in_person" ? mode : null);
15940
16882
  input.setErrorMessage("");
15941
- input.setPendingRegistrationReference(null);
15942
16883
  }
15943
16884
  /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
15944
16885
  function recoverRegistrationError(action, handlers) {
@@ -16024,6 +16965,7 @@ function hasValidPricingOptionSelection(input) {
16024
16965
  }
16025
16966
  //#endregion
16026
16967
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
16968
+ init_src();
16027
16969
  function getPortalSubjectEmail(profile) {
16028
16970
  return profile?.email ?? null;
16029
16971
  }
@@ -16103,6 +17045,7 @@ function findSelectedTicketType(input) {
16103
17045
  }
16104
17046
  //#endregion
16105
17047
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
17048
+ init_src();
16106
17049
  /** Public requests share subject identity without copying the run's display sessions. */
16107
17050
  function toRegistrationRequestSubject(subject, attendanceMode) {
16108
17051
  return subject.kind === "occurrence" ? {
@@ -16473,6 +17416,7 @@ function logoutPortal(anchorId) {
16473
17416
  }
16474
17417
  //#endregion
16475
17418
  //#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
17419
+ init_purchase();
16476
17420
  const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
16477
17421
  function createInitialWaitlistClaimState(hasToken) {
16478
17422
  return hasToken ? { kind: "resolving" } : { kind: "idle" };
@@ -16619,444 +17563,178 @@ function useResolvedWaitlistClaim(deps, credential) {
16619
17563
  };
16620
17564
  }
16621
17565
  //#endregion
16622
- //#region ../blocks/src/system/runtime/hooks/usePaymentVerification.ts
16623
- /**
16624
- * Hook for polling payment status after Stripe redirects.
16625
- *
16626
- * Built on top of the generic usePolling hook, this provides
16627
- * a specialized interface for verifying event registration payments.
16628
- *
16629
- * @example
16630
- * ```tsx
16631
- * const verification = usePaymentVerification(
16632
- * step === 'verifying-payment' && attendeeId
16633
- * ? { transactionId: attendeeId }
16634
- * : null
16635
- * );
16636
- *
16637
- * useEffect(() => {
16638
- * if (verification.status === 'completed') {
16639
- * setStep('success');
16640
- * } else if (verification.status === 'failed') {
16641
- * setStep('payment-failed');
16642
- * } else if (verification.status === 'timeout') {
16643
- * setStep('verifying-timeout');
16644
- * }
16645
- * }, [verification.status]);
16646
- * ```
16647
- */
16648
- const paymentVerificationDeps = { useBlockApi };
16649
- function resolvePaymentPollingTarget(config) {
16650
- const reference = config.reference;
16651
- return reference.scope === "occurrence" ? {
16652
- key: `occurrence:${reference.attendeeId}`,
16653
- reference
16654
- } : {
16655
- key: `wholeSeries:${reference.registrationId}`,
16656
- reference
16657
- };
16658
- }
16659
- function createPaymentPollingConfig(api, settings) {
16660
- if (settings === null) return null;
16661
- const target = resolvePaymentPollingTarget(settings);
16662
- return {
16663
- restartKey: target.key,
16664
- pollFn: () => api.getEventRegistrationStatus(target.reference),
16665
- isComplete: (result) => result.paymentStatus === "completed" || result.paymentStatus === "not_required",
16666
- isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "refunded",
16667
- maxAttempts: settings.maxAttempts,
16668
- interval: settings.pollInterval
16669
- };
16670
- }
16671
- function getPaymentVerificationError(polling, paymentStatus) {
16672
- if (polling.status === "timeout") return "Could not verify payment. If you were charged, please contact support.";
16673
- if (polling.status === "failed" && paymentStatus !== null) return paymentStatus === "refunded" ? "Payment was refunded. Please contact support." : "Payment was declined. Please try again.";
16674
- return polling.error?.message ?? null;
16675
- }
16676
- function mapPaymentVerificationResult(polling) {
16677
- const paymentStatus = polling.result?.paymentStatus ?? null;
16678
- return {
16679
- status: polling.status,
16680
- paymentStatus,
16681
- attendeeStatus: polling.result?.attendeeStatus ?? null,
16682
- waitlistPosition: polling.result?.waitlistPosition ?? null,
16683
- error: getPaymentVerificationError(polling, paymentStatus),
16684
- retry: polling.retry
16685
- };
16686
- }
16687
- /**
16688
- * Hook for polling payment status after Stripe redirects.
16689
- *
16690
- * Pass config to start polling, or null to stop/idle.
16691
- * The hook handles cleanup on unmount and starts a new cycle when the status
16692
- * reference changes.
16693
- *
16694
- * @param config - Configuration for polling, or null to stop
16695
- * @returns Verification result with status, data, and retry function
16696
- */
16697
- function usePaymentVerification(config) {
16698
- return usePaymentVerificationWithDeps(config, paymentVerificationDeps);
16699
- }
16700
- function usePaymentVerificationWithDeps(config, deps) {
16701
- return mapPaymentVerificationResult(usePolling(createPaymentPollingConfig(deps.useBlockApi(), config)));
16702
- }
16703
- //#endregion
16704
- //#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
16705
- const EVENT_REGISTRATION_ANCHOR_ID = "event-registration";
16706
- const EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM = "registration_attempt";
16707
- //#endregion
16708
17566
  //#region ../blocks/src/system/runtime/nodes/event-registration/sessionStorage.ts
16709
17567
  const STORAGE_PREFIX = "riverbank:event-registration:";
16710
17568
  const STALE_THRESHOLD_MS = 1440 * 60 * 1e3;
16711
- /**
16712
- * Build the sessionStorage key for a specific registration.
16713
- */
16714
- function getStorageKey(siteId, checkoutAttemptId) {
16715
- return `${STORAGE_PREFIX}${siteId}:${checkoutAttemptId}`;
16716
- }
16717
- /**
16718
- * Check if sessionStorage is available.
16719
- * Returns false in private browsing mode or when storage is disabled.
16720
- */
16721
- function isStorageAvailable() {
16722
- try {
16723
- const testKey = "__riverbank_test__";
16724
- sessionStorage.setItem(testKey, "test");
16725
- sessionStorage.removeItem(testKey);
16726
- return true;
16727
- } catch {
16728
- return false;
16729
- }
17569
+ const paymentSelection = z.discriminatedUnion("method", [
17570
+ z.object({ method: z.literal("free") }),
17571
+ z.object({
17572
+ method: z.literal("stripe"),
17573
+ collectionOptionKind: z.enum([
17574
+ "upfront",
17575
+ "deferred_manual",
17576
+ "instalment_plan",
17577
+ "flexible_balance"
17578
+ ])
17579
+ }),
17580
+ z.object({
17581
+ method: z.literal("pass"),
17582
+ passId: z.string(),
17583
+ productName: z.string().optional()
17584
+ }),
17585
+ z.object({
17586
+ method: z.literal("membership"),
17587
+ membershipId: z.string(),
17588
+ productName: z.string().optional()
17589
+ }),
17590
+ z.object({
17591
+ method: z.literal("pass_bundle"),
17592
+ bundlePassId: z.string(),
17593
+ productName: z.string().optional(),
17594
+ productDescription: z.string().optional(),
17595
+ productPrice: z.number().optional(),
17596
+ productCurrency: z.string().optional()
17597
+ }),
17598
+ z.object({
17599
+ method: z.literal("membership_bundle"),
17600
+ bundleMembershipId: z.string(),
17601
+ productName: z.string().optional(),
17602
+ productDescription: z.string().optional(),
17603
+ productPrice: z.number().optional(),
17604
+ productCurrency: z.string().optional(),
17605
+ productInterval: z.string().optional()
17606
+ })
17607
+ ]);
17608
+ const schema = z.object({
17609
+ version: z.literal(6),
17610
+ reference: z.discriminatedUnion("scope", [z.object({
17611
+ scope: z.literal("occurrence"),
17612
+ attendeeId: z.string()
17613
+ }), z.object({
17614
+ scope: z.literal("wholeSeries"),
17615
+ registrationId: z.string()
17616
+ })]),
17617
+ formData: z.object({
17618
+ name: z.string(),
17619
+ email: z.string(),
17620
+ phone: z.string(),
17621
+ notes: z.string(),
17622
+ consentAccepted: z.boolean().optional(),
17623
+ mailingListOptIn: z.boolean().optional()
17624
+ }),
17625
+ ticketSelections: z.array(z.object({
17626
+ pricingOptionId: z.string().nullable(),
17627
+ quantity: z.number().int().positive()
17628
+ })).min(1),
17629
+ selectedEventId: z.string().nullable(),
17630
+ selectedAttendanceMode: z.enum(["in_person", "online"]).nullable().optional(),
17631
+ paymentSelection,
17632
+ guests: z.array(z.object({
17633
+ name: z.string(),
17634
+ email: z.string().nullable(),
17635
+ phone: z.string().nullable()
17636
+ })),
17637
+ selectedSlidingAmount: z.number().nullable(),
17638
+ discountCode: z.string(),
17639
+ mailingListSignupNote: z.enum(["confirmation_required", "not_confirmed"]).optional(),
17640
+ timestamp: z.number().finite()
17641
+ });
17642
+ function key(siteId, submissionId) {
17643
+ return `${STORAGE_PREFIX}${siteId}:${submissionId}`;
16730
17644
  }
16731
- /**
16732
- * Save pending registration data before Stripe redirect.
16733
- *
16734
- * @param siteId - Site ID
16735
- * @param checkoutAttemptId - Correlation ID included in the checkout return URL
16736
- * @param data - Registration data to save (excluding version and timestamp)
16737
- */
16738
- function savePendingRegistration(siteId, checkoutAttemptId, data) {
16739
- if (!isStorageAvailable()) {
16740
- console.warn("[sessionStorage] Storage not available, skipping save");
16741
- return;
16742
- }
17645
+ function savePendingRegistration(siteId, submissionId, data) {
16743
17646
  try {
16744
- const key = getStorageKey(siteId, checkoutAttemptId);
16745
- const ticketSelections = normalizeTicketSelectionLines(data.ticketSelections);
16746
- if (ticketSelections.length === 0) {
16747
- console.warn("[sessionStorage] No ticket selections to save, skipping registration state");
16748
- return;
16749
- }
16750
- const entry = {
17647
+ const entry = schema.safeParse({
16751
17648
  ...data,
16752
- ticketSelections,
16753
- version: 5,
17649
+ ticketSelections: normalizeTicketSelectionLines(data.ticketSelections),
17650
+ version: 6,
16754
17651
  timestamp: Date.now()
16755
- };
16756
- sessionStorage.setItem(key, JSON.stringify(entry));
16757
- } catch (error) {
16758
- console.warn("[sessionStorage] Failed to save registration:", error);
16759
- }
16760
- }
16761
- /**
16762
- * Get pending registration data after returning from Stripe.
16763
- *
16764
- * Returns null if:
16765
- * - No entry exists for this checkout attempt
16766
- * - Entry is stale (> 24 hours old)
16767
- * - Entry is corrupt or wrong version
16768
- * - Storage is unavailable
16769
- *
16770
- * @param siteId - Site ID
16771
- * @param checkoutAttemptId - Correlation ID returned from checkout.
16772
- * @returns Pending registration data or null
16773
- */
16774
- function getPendingRegistration(siteId, checkoutAttemptId) {
16775
- if (!isStorageAvailable()) return null;
16776
- try {
16777
- const key = getStorageKey(siteId, checkoutAttemptId);
16778
- const stored = sessionStorage.getItem(key);
16779
- if (stored) return parseAndValidateEntry(stored, key);
16780
- return null;
16781
- } catch (error) {
16782
- console.warn("[sessionStorage] Failed to read registration:", error);
16783
- return null;
16784
- }
17652
+ });
17653
+ if (entry.success) sessionStorage.setItem(key(siteId, submissionId), JSON.stringify(entry.data));
17654
+ } catch {}
16785
17655
  }
16786
- /**
16787
- * Internal helper to parse and validate a storage entry.
16788
- */
16789
- function parseAndValidateEntry(stored, key) {
17656
+ function getPendingRegistration(siteId, submissionId) {
16790
17657
  try {
16791
- const raw = JSON.parse(stored);
16792
- if (!raw || typeof raw !== "object") {
16793
- sessionStorage.removeItem(key);
16794
- return null;
16795
- }
16796
- const version = raw.version;
16797
- if (version !== 4 && version !== 5) {
16798
- console.warn("[sessionStorage] Outdated version, ignoring entry");
16799
- sessionStorage.removeItem(key);
16800
- return null;
16801
- }
16802
- const entry = normalizeStoredRegistration(raw);
16803
- const timestamp = typeof entry.timestamp === "number" ? entry.timestamp : NaN;
16804
- if (!Number.isFinite(timestamp)) {
16805
- sessionStorage.removeItem(key);
16806
- return null;
16807
- }
16808
- if (Date.now() - timestamp > STALE_THRESHOLD_MS) {
16809
- console.info("[sessionStorage] Entry is stale, removing");
16810
- sessionStorage.removeItem(key);
16811
- return null;
16812
- }
16813
- const ticketSelections = normalizeTicketSelectionLines(entry.ticketSelections);
16814
- if (ticketSelections.length === 0 || getTicketSelectionTotal(ticketSelections) <= 0) {
16815
- sessionStorage.removeItem(key);
17658
+ const stored = sessionStorage.getItem(key(siteId, submissionId));
17659
+ const parsed = schema.safeParse(stored ? JSON.parse(stored) : null);
17660
+ if (!parsed.success || Date.now() - parsed.data.timestamp > STALE_THRESHOLD_MS) {
17661
+ clearPendingRegistration(siteId, submissionId);
16816
17662
  return null;
16817
17663
  }
16818
- return {
16819
- ...entry,
16820
- ticketSelections
16821
- };
17664
+ return parsed.data;
16822
17665
  } catch {
16823
- console.warn("[sessionStorage] Failed to parse entry, removing");
16824
- sessionStorage.removeItem(key);
16825
17666
  return null;
16826
17667
  }
16827
17668
  }
16828
- function normalizeStoredRegistration(entry) {
16829
- if (entry.version === 5) return entry;
16830
- const { attendeeId, ...stored } = entry;
16831
- return {
16832
- ...stored,
16833
- version: 5,
16834
- reference: {
16835
- scope: "occurrence",
16836
- attendeeId
16837
- }
16838
- };
17669
+ function clearPendingRegistration(siteId, submissionId) {
17670
+ try {
17671
+ sessionStorage.removeItem(key(siteId, submissionId));
17672
+ } catch {}
16839
17673
  }
16840
- /**
16841
- * Clear pending registration data after successful verification.
16842
- *
16843
- * @param siteId - Site ID
16844
- * @param checkoutAttemptId - Checkout return correlation ID
16845
- */
16846
- function clearPendingRegistration(siteId, checkoutAttemptId) {
16847
- if (!isStorageAvailable()) return;
16848
- try {
16849
- const key = getStorageKey(siteId, checkoutAttemptId);
16850
- sessionStorage.removeItem(key);
16851
- } catch {}
16852
- }
16853
- /**
16854
- * Clean up all stale registration entries from sessionStorage.
16855
- * Should be called on component mount to prevent accumulation.
16856
- */
16857
17674
  function cleanupStaleRegistrations() {
16858
- if (!isStorageAvailable()) return;
16859
17675
  try {
16860
- const keysToRemove = [];
16861
- for (let i = 0; i < sessionStorage.length; i++) {
16862
- const key = sessionStorage.key(i);
16863
- if (!key?.startsWith(STORAGE_PREFIX)) continue;
17676
+ Array.from({ length: sessionStorage.length }, (_, index) => sessionStorage.key(index)).filter((item) => item !== null && item.startsWith(STORAGE_PREFIX)).forEach((item) => {
16864
17677
  try {
16865
- const stored = sessionStorage.getItem(key);
16866
- if (!stored) continue;
16867
- const entry = JSON.parse(stored);
16868
- const timestamp = typeof entry.timestamp === "number" ? entry.timestamp : NaN;
16869
- const age = Date.now() - timestamp;
16870
- if (!Number.isFinite(timestamp) || age > STALE_THRESHOLD_MS) keysToRemove.push(key);
17678
+ const parsed = schema.safeParse(JSON.parse(sessionStorage.getItem(item) ?? "null"));
17679
+ if (!parsed.success || Date.now() - parsed.data.timestamp > STALE_THRESHOLD_MS) sessionStorage.removeItem(item);
16871
17680
  } catch {
16872
- keysToRemove.push(key);
17681
+ sessionStorage.removeItem(item);
16873
17682
  }
16874
- }
16875
- for (const key of keysToRemove) sessionStorage.removeItem(key);
16876
- if (keysToRemove.length > 0) console.info(`[sessionStorage] Cleaned up ${keysToRemove.length} stale entries`);
16877
- } catch (error) {
16878
- console.warn("[sessionStorage] Cleanup failed:", error);
16879
- }
17683
+ });
17684
+ } catch {}
16880
17685
  }
16881
17686
  //#endregion
17687
+ //#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
17688
+ const EVENT_REGISTRATION_ANCHOR_ID = "event-registration";
17689
+ const EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM = "registration_attempt";
17690
+ //#endregion
16882
17691
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
16883
- const eventRegistrationStripeReturnDeps = {
16884
- usePaymentVerification,
16885
- readReturnParams: () => {
17692
+ function useEventRegistrationStripeReturn(options) {
17693
+ const restored = useRef(false);
17694
+ useEffect(() => {
17695
+ if (restored.current) return;
17696
+ restored.current = true;
17697
+ cleanupStaleRegistrations();
16886
17698
  const params = new URLSearchParams(window.location.search);
16887
- return {
16888
- registration: params.get("registration"),
16889
- registration_attempt: params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM),
16890
- session_id: params.get("session_id")
16891
- };
16892
- },
16893
- clearReturnParams: () => {
16894
- consumeSearchParams([
16895
- "registration",
16896
- EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
16897
- "session_id"
16898
- ]);
16899
- },
16900
- scrollToBlock,
16901
- cleanupStaleRegistrations,
16902
- clearPendingRegistration,
16903
- getPendingRegistration
16904
- };
16905
- function restorePendingPresentation(options, pending) {
16906
- options.setFormData(pending.formData);
16907
- options.setTicketSelections(pending.ticketSelections);
16908
- options.setTicketsCount(getTicketSelectionTotal(pending.ticketSelections));
16909
- if (pending.selectedEventId) {
16910
- const event = options.events.find((item) => item.selectionId === pending.selectedEventId) ?? null;
16911
- if (event) options.setSelectedEvent(event);
16912
- }
16913
- options.setSelectedAttendanceMode(pending.selectedAttendanceMode ?? null);
16914
- options.setPaymentSelection(pending.paymentSelection);
16915
- }
16916
- function showReturnReconciliation(options, message) {
16917
- options.setErrorMessage(message);
16918
- options.setStep("verifying-timeout");
16919
- }
16920
- function checkoutReturnCommand(params) {
16921
- const checkoutAttemptId = params.registration_attempt;
16922
- if (!checkoutAttemptId) return null;
16923
- if (params.registration === "cancelled") return {
16924
- kind: "abandon",
16925
- checkoutAttemptId
16926
- };
16927
- if (params.registration === "success" && params.session_id) return {
16928
- kind: "resolveSuccess",
16929
- checkoutAttemptId,
16930
- sessionId: params.session_id
16931
- };
16932
- return null;
16933
- }
16934
- function handleCheckoutReturnOutcome(options, deps, context, outcome) {
16935
- const { pending, params } = context;
16936
- if (outcome.kind === "resolved") {
16937
- deps.clearReturnParams();
16938
- options.setPendingRegistrationReference(outcome.reference);
16939
- options.setStep("verifying-payment");
16940
- return "settled";
16941
- }
16942
- if (outcome.kind === "abandoned") {
16943
- deps.clearReturnParams();
16944
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16945
- options.setStep("select-payment");
16946
- return "settled";
16947
- }
16948
- if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
16949
- deps.clearReturnParams();
16950
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16951
- options.setStep("select-payment");
16952
- return "settled";
16953
- }
16954
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
16955
- return outcome.kind === "notFound" ? "settled" : "retryable";
16956
- }
16957
- async function handleCheckoutReturn(options, deps, returnContextRef) {
16958
- deps.cleanupStaleRegistrations();
16959
- const params = deps.readReturnParams();
16960
- if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
16961
- deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
16962
- const siteId = options.api.config.siteId;
16963
- const command = checkoutReturnCommand(params);
16964
- if (!siteId) return "settled";
16965
- if (!command) {
16966
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
16967
- return "settled";
16968
- }
16969
- const { checkoutAttemptId } = command;
16970
- const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
16971
- returnContextRef.current = {
16972
- checkoutAttemptId,
16973
- mailingListSignupNote: pending?.mailingListSignupNote
16974
- };
16975
- if (pending) restorePendingPresentation(options, pending);
16976
- options.setStep("verifying-payment");
16977
- try {
16978
- const outcome = await options.api.resolveEventCheckoutReturn(command);
16979
- return handleCheckoutReturnOutcome(options, deps, {
16980
- pending,
16981
- params
16982
- }, outcome);
16983
- } catch {
16984
- showReturnReconciliation(options, "We couldn’t check your payment just now. Please check again in a moment. Don’t make another booking while we’re checking.");
16985
- }
16986
- return "retryable";
17699
+ const checkoutAttemptId = params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
17700
+ const sessionId = params.get("session_id");
17701
+ if (params.get("registration") !== "payment" || !checkoutAttemptId || !sessionId) return;
17702
+ const pending = options.siteId ? getPendingRegistration(options.siteId, checkoutAttemptId) : null;
17703
+ if (pending) options.restore(pending);
17704
+ options.verify({
17705
+ kind: "resolveSession",
17706
+ checkoutAttemptId,
17707
+ sessionId
17708
+ });
17709
+ }, [options]);
16987
17710
  }
16988
- function useEventRegistrationStripeReturn(options) {
16989
- return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
17711
+ //#endregion
17712
+ //#region ../blocks/src/system/runtime/nodes/event-registration/paymentLocation.ts
17713
+ function eventPaymentReturnUrl(submissionId) {
17714
+ const url = new URL(window.location.href);
17715
+ url.searchParams.set("registration", "payment");
17716
+ url.searchParams.set(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM, submissionId);
17717
+ url.searchParams.delete("session_id");
17718
+ url.hash = EVENT_REGISTRATION_ANCHOR_ID;
17719
+ return url.toString();
16990
17720
  }
16991
- function completeVerifiedRegistration(options, deps, returnContext) {
16992
- const siteId = options.api.config.siteId;
16993
- const checkoutAttemptId = returnContext?.checkoutAttemptId;
16994
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
16995
- options.setRegistrationResult({
16996
- status: "confirmed",
16997
- mailingListSignupNote: returnContext?.mailingListSignupNote
16998
- });
16999
- options.setStep("success");
17721
+ function rememberEventPayment(submissionId, sessionId) {
17722
+ const url = new URL(eventPaymentReturnUrl(submissionId));
17723
+ url.searchParams.set("session_id", sessionId);
17724
+ window.history.replaceState(window.history.state, "", url);
17000
17725
  }
17001
- function useEventRegistrationStripeReturnWithDeps(options, deps) {
17002
- const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
17003
- const returnContextRef = useRef(null);
17004
- const lookupInFlightRef = useRef(false);
17005
- const [lookupState, setLookupState] = useState("settled");
17006
- const resolveReturn = useCallback(async () => {
17007
- if (lookupInFlightRef.current) return;
17008
- lookupInFlightRef.current = true;
17009
- setLookupState("loading");
17010
- try {
17011
- setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
17012
- } finally {
17013
- lookupInFlightRef.current = false;
17014
- }
17015
- }, [options, deps]);
17016
- const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
17017
- const verification = deps.usePaymentVerification(verificationConfig);
17018
- const hasVerificationTimeout = step === "verifying-timeout" && pendingRegistrationReference !== null;
17019
- const retry = useCallback(() => {
17020
- if (hasVerificationTimeout) {
17021
- setStep("verifying-payment");
17022
- return;
17023
- }
17024
- verification.retry();
17025
- }, [
17026
- hasVerificationTimeout,
17027
- setStep,
17028
- verification.retry
17029
- ]);
17030
- useEffect(() => {
17031
- resolveReturn();
17032
- }, []);
17033
- useEffect(() => {
17034
- if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
17035
- else if (verification.status === "failed") {
17036
- setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
17037
- setStep("payment-failed");
17038
- } else if (verification.status === "timeout") setStep("verifying-timeout");
17039
- }, [
17040
- verification.status,
17041
- verification.attendeeStatus,
17042
- verification.waitlistPosition,
17043
- verification.error,
17044
- api.config.siteId,
17045
- setErrorMessage,
17046
- setRegistrationResult,
17047
- setStep
17048
- ]);
17049
- return {
17050
- ...verification,
17051
- status: hasVerificationTimeout ? "timeout" : verification.status,
17052
- retry,
17053
- retryReturn: lookupState === "retryable" ? () => {
17054
- resolveReturn();
17055
- } : void 0
17056
- };
17726
+ function clearEventPayment(siteId) {
17727
+ const url = new URL(window.location.href);
17728
+ const submissionId = url.searchParams.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
17729
+ if (siteId && submissionId) clearPendingRegistration(siteId, submissionId);
17730
+ url.searchParams.delete("registration");
17731
+ url.searchParams.delete(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
17732
+ url.searchParams.delete("session_id");
17733
+ window.history.replaceState(window.history.state, "", url);
17057
17734
  }
17058
17735
  //#endregion
17059
17736
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.ts
17737
+ init_purchase();
17060
17738
  function registrationErrorPresentation(error) {
17061
17739
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
17062
17740
  if (reason) return eventRegistrationErrors[reason];
@@ -17068,6 +17746,7 @@ function registrationErrorPresentation(error) {
17068
17746
  }
17069
17747
  //#endregion
17070
17748
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
17749
+ init_src();
17071
17750
  function wantsMailingListSignup(options) {
17072
17751
  return options.mailingListSignup !== null && options.formData.mailingListOptIn === true;
17073
17752
  }
@@ -17100,7 +17779,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
17100
17779
  */
17101
17780
  const { commandRef } = options;
17102
17781
  const inFlightRef = useRef(null);
17103
- const submit = async (method, passId, membershipId, selection, submitOptions) => {
17782
+ const submit = async (method, passId, membershipId, selection) => {
17104
17783
  const target = options.registrationTarget;
17105
17784
  if (!target) return {
17106
17785
  ok: false,
@@ -17110,25 +17789,21 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
17110
17789
  options.setStep("submitting");
17111
17790
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
17112
17791
  try {
17113
- let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
17114
- let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
17115
- const intentKey = registrationRequestIntentKey(request);
17116
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
17117
- prepared = {
17118
- ...prepared,
17119
- registrationCommandId: deps.createClientCommandId()
17120
- };
17121
- request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
17122
- }
17792
+ const initialPrepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
17793
+ const intentKey = registrationRequestIntentKey(buildRegistrationRequest(options, initialPrepared, method, passId, membershipId));
17794
+ const prepared = commandRef.current !== null && commandRef.current.intentKey !== intentKey ? {
17795
+ ...initialPrepared,
17796
+ registrationCommandId: deps.createClientCommandId()
17797
+ } : initialPrepared;
17798
+ const request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
17123
17799
  commandRef.current = {
17124
17800
  id: prepared.registrationCommandId,
17125
17801
  intentKey
17126
17802
  };
17127
- const result = await options.api.registerForEvent({
17803
+ return await completeRegistrationSubmission(options, deps, prepared, await options.api.registerForEvent({
17128
17804
  ...request,
17129
17805
  registrationCommandId: prepared.registrationCommandId
17130
- });
17131
- return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
17806
+ }));
17132
17807
  } catch (error) {
17133
17808
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
17134
17809
  const { message, action } = registrationErrorPresentation(error);
@@ -17152,7 +17827,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
17152
17827
  return pending;
17153
17828
  };
17154
17829
  }
17155
- async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
17830
+ async function completeRegistrationSubmission(options, deps, prepared, result) {
17156
17831
  if (result.demoBookingPass) storeDemoBookingPass(options.formData.email, result.demoBookingPass);
17157
17832
  switch (result.kind) {
17158
17833
  case "paymentStatusRequired":
@@ -17167,10 +17842,24 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
17167
17842
  outcome: { kind: "payment_status" }
17168
17843
  };
17169
17844
  case "checkoutRequired":
17170
- options.setPendingRegistrationReference(result.reference);
17171
17845
  savePendingCheckout(options, deps, prepared, result.submissionId, result.reference, result.mailingListSignupNote);
17172
- options.setStep("redirecting");
17173
- return redirectToCheckout(result.checkoutUrl, submitOptions);
17846
+ const subject = result.reference.scope === "occurrence" ? {
17847
+ scope: "occurrence",
17848
+ attendeeId: result.reference.attendeeId,
17849
+ submissionId: result.submissionId
17850
+ } : {
17851
+ scope: "wholeSeries",
17852
+ submissionId: result.submissionId
17853
+ };
17854
+ options.openPayment(result.checkout, subject, result.mailingListSignupNote);
17855
+ return {
17856
+ ok: true,
17857
+ outcome: {
17858
+ kind: "checkout_ready",
17859
+ checkout: result.checkout,
17860
+ subject
17861
+ }
17862
+ };
17174
17863
  case "waitlisted":
17175
17864
  options.setRegistrationResult({
17176
17865
  status: "waitlist",
@@ -17182,7 +17871,6 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
17182
17871
  break;
17183
17872
  case "bookingComplete":
17184
17873
  case "paymentDeferred":
17185
- options.setPendingRegistrationReference(result.reference);
17186
17874
  options.setRegistrationResult({
17187
17875
  status: "confirmed",
17188
17876
  message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0,
@@ -17255,19 +17943,12 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
17255
17943
  selectedEventId: options.registrationTarget?.selectedEventId ?? null,
17256
17944
  selectedAttendanceMode: options.selectedAttendanceMode,
17257
17945
  paymentSelection: prepared.selectionSnapshot,
17946
+ guests: options.guests,
17947
+ selectedSlidingAmount: options.selectedSlidingAmount,
17948
+ discountCode: options.discountCode,
17258
17949
  mailingListSignupNote
17259
17950
  });
17260
17951
  }
17261
- function redirectToCheckout(checkoutUrl, submitOptions) {
17262
- if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
17263
- return {
17264
- ok: true,
17265
- outcome: {
17266
- kind: "checkout_redirect",
17267
- checkoutUrl
17268
- }
17269
- };
17270
- }
17271
17952
  function registrationRequestIntentKey(request) {
17272
17953
  const { registrationCommandId: _command, altchaSolution: _proof, mailingListOptIn: _marketingConsent, checkout, ...intent } = request;
17273
17954
  return JSON.stringify({
@@ -17282,7 +17963,7 @@ function buildRegistrationRequest(options, prepared, method, passId, membershipI
17282
17963
  return {
17283
17964
  registrationCommandId: prepared.registrationCommandId,
17284
17965
  checkout: {
17285
- ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
17966
+ returnUrl: eventPaymentReturnUrl(prepared.registrationCommandId),
17286
17967
  discountCode: options.discountCode.trim() || void 0,
17287
17968
  collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
17288
17969
  },
@@ -17551,8 +18232,7 @@ function isSelectionValid(input) {
17551
18232
  function normalizeRegistrationFlowState(state) {
17552
18233
  const hasPass = Boolean(state.eligibility?.eligiblePasses.length);
17553
18234
  const hasMembership = Boolean(state.eligibility?.eligibleMemberships.length);
17554
- let nextPassOptOut = state.passOptOut;
17555
- if (nextPassOptOut && (state.step === "select-tickets" || state.ticketsCount !== 1 || !hasPass || hasMembership)) nextPassOptOut = false;
18235
+ const nextPassOptOut = state.passOptOut && !(state.step === "select-tickets" || state.ticketsCount !== 1 || !hasPass || hasMembership);
17556
18236
  const autoSelection = computeAutoSelection({
17557
18237
  isAuthenticated: state.isAuthenticated,
17558
18238
  eligibility: state.eligibility,
@@ -17577,8 +18257,27 @@ function normalizeRegistrationFlowState(state) {
17577
18257
  };
17578
18258
  }
17579
18259
  function registrationFlowReducer(state, action) {
18260
+ if ([
18261
+ "payment",
18262
+ "submitting",
18263
+ "verifying-payment",
18264
+ "verifying-timeout",
18265
+ "payment-status"
18266
+ ].includes(state.step) && action.type !== "set-step") return state;
17580
18267
  switch (action.type) {
17581
- case "set-step": return normalizeRegistrationFlowState({
18268
+ case "admission-updated":
18269
+ case "tickets-completed":
18270
+ case "recovery-checked": return reduceRegistrationAdmission(state, action);
18271
+ case "set-step": return [
18272
+ "payment",
18273
+ "submitting",
18274
+ "verifying-payment",
18275
+ "verifying-timeout",
18276
+ "payment-status"
18277
+ ].includes(action.step) ? {
18278
+ ...state,
18279
+ step: action.step
18280
+ } : normalizeRegistrationFlowState({
17582
18281
  ...state,
17583
18282
  step: action.step
17584
18283
  });
@@ -17594,18 +18293,8 @@ function registrationFlowReducer(state, action) {
17594
18293
  ...state,
17595
18294
  eligibility: action.eligibility
17596
18295
  });
17597
- case "set-manual-payment-selection": return normalizeRegistrationFlowState({
17598
- ...state,
17599
- paymentSelection: normalizePaymentSelection(action.selection),
17600
- selectionSource: "manual",
17601
- passOptOut: action.selection.method === "stripe" ? true : state.passOptOut
17602
- });
17603
- case "use-card-instead-of-pass": return normalizeRegistrationFlowState({
17604
- ...state,
17605
- passOptOut: true,
17606
- paymentSelection: computeDirectPaymentSelection(state.eligibility),
17607
- selectionSource: "manual"
17608
- });
18296
+ case "set-manual-payment-selection":
18297
+ case "use-card-instead-of-pass": return reduceRegistrationPaymentChoice(state, action);
17609
18298
  case "event-changed": return normalizeRegistrationFlowState({
17610
18299
  ...state,
17611
18300
  step: action.hasPreSelectedContext ? "select-tickets" : "select-event",
@@ -17615,7 +18304,6 @@ function registrationFlowReducer(state, action) {
17615
18304
  eligibility: null
17616
18305
  });
17617
18306
  case "reset": return createInitialRegistrationFlowState(action.hasPreSelectedContext);
17618
- default: return state;
17619
18307
  }
17620
18308
  }
17621
18309
  function isEntitlementSelection(selection) {
@@ -17625,6 +18313,38 @@ function requiresPaymentStep(params) {
17625
18313
  if (!params.eventRequiresPayment) return false;
17626
18314
  return !isEntitlementSelection(params.paymentSelection);
17627
18315
  }
18316
+ function reduceRegistrationPaymentChoice(state, action) {
18317
+ switch (action.type) {
18318
+ case "set-manual-payment-selection": return normalizeRegistrationFlowState({
18319
+ ...state,
18320
+ paymentSelection: normalizePaymentSelection(action.selection),
18321
+ selectionSource: "manual",
18322
+ passOptOut: action.selection.method === "stripe" ? true : state.passOptOut
18323
+ });
18324
+ case "use-card-instead-of-pass": return normalizeRegistrationFlowState({
18325
+ ...state,
18326
+ passOptOut: true,
18327
+ paymentSelection: computeDirectPaymentSelection(state.eligibility),
18328
+ selectionSource: "manual"
18329
+ });
18330
+ }
18331
+ }
18332
+ function reduceRegistrationAdmission(state, action) {
18333
+ switch (action.type) {
18334
+ case "admission-updated": return state.step === "fully-booked" && action.admission.kind !== "checking" ? normalizeRegistrationFlowState({
18335
+ ...state,
18336
+ step: stepAfterTickets(action.admission)
18337
+ }) : state;
18338
+ case "tickets-completed": return state.step === "select-tickets" ? normalizeRegistrationFlowState({
18339
+ ...state,
18340
+ step: stepAfterTickets(action.admission)
18341
+ }) : state;
18342
+ case "recovery-checked": return state.step === "fully-booked" && action.outcome.kind !== "unavailable" ? normalizeRegistrationFlowState({
18343
+ ...state,
18344
+ step: "enter-details"
18345
+ }) : state;
18346
+ }
18347
+ }
17628
18348
  //#endregion
17629
18349
  //#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
17630
18350
  function isRecord$1(value) {
@@ -17643,6 +18363,9 @@ function resolveRuntimeEventDestination(event) {
17643
18363
  path: typeof event.path === "string" ? event.path : ""
17644
18364
  };
17645
18365
  }
18366
+ //#endregion
18367
+ //#region ../blocks/src/system/runtime/nodes/event-registration/eventScope.ts
18368
+ init_src();
17646
18369
  const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
17647
18370
  kind: z.literal("unsupported"),
17648
18371
  reason: z.enum([
@@ -17940,7 +18663,7 @@ function resolveEventRegistrationSubmitPlan(input) {
17940
18663
  function resolveHeadlessEventRegistrationStatus(wizard) {
17941
18664
  switch (wizard.step) {
17942
18665
  case "submitting": return { tag: "submitting" };
17943
- case "redirecting": return { tag: "redirecting" };
18666
+ case "payment": return { tag: "payment" };
17944
18667
  case "verifying-payment": return { tag: "verifying-payment" };
17945
18668
  case "verifying-timeout": return { tag: "verifying-timeout" };
17946
18669
  case "payment-status": return wizard.paymentStatusRecovery ? {
@@ -17962,11 +18685,12 @@ function resolveHeadlessEventRegistrationStatus(wizard) {
17962
18685
  };
17963
18686
  case "select-event":
17964
18687
  case "select-tickets":
18688
+ case "fully-booked":
17965
18689
  case "enter-details":
17966
18690
  case "select-payment": return { tag: "ready" };
17967
18691
  }
17968
18692
  }
17969
- function resolveHeadlessEventRegistrationView(wizard) {
18693
+ function registrationSurfaceUnavailable(wizard) {
17970
18694
  if (wizard.scopedEvents.length === 0 && !wizard.occurrenceContext) return {
17971
18695
  kind: "empty",
17972
18696
  message: "No events available for registration."
@@ -17975,6 +18699,11 @@ function resolveHeadlessEventRegistrationView(wizard) {
17975
18699
  kind: "unavailable",
17976
18700
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more."
17977
18701
  };
18702
+ return null;
18703
+ }
18704
+ function resolveHeadlessEventRegistrationView(wizard) {
18705
+ const unavailable = registrationSurfaceUnavailable(wizard);
18706
+ if (unavailable) return unavailable;
17978
18707
  switch (wizard.step) {
17979
18708
  case "verifying-payment": return {
17980
18709
  kind: "verifying",
@@ -17997,26 +18726,36 @@ function resolveHeadlessEventRegistrationView(wizard) {
17997
18726
  kind: "payment-status",
17998
18727
  state: wizard.paymentStatusRecovery
17999
18728
  } : { kind: "form" };
18729
+ case "fully-booked": return fullyBookedView(wizard);
18000
18730
  case "select-event":
18001
18731
  case "select-tickets":
18002
18732
  case "enter-details":
18003
18733
  case "select-payment":
18004
18734
  case "submitting":
18005
- case "redirecting": return { kind: "form" };
18735
+ case "payment": return { kind: "form" };
18006
18736
  }
18007
18737
  }
18738
+ function fullyBookedView(wizard) {
18739
+ const admission = wizard.admission;
18740
+ return {
18741
+ kind: "fully-booked",
18742
+ recovery: admission.kind === "fullyBooked" ? admission.recovery : "none",
18743
+ recoveryMessage: wizard.recoveryMessage
18744
+ };
18745
+ }
18008
18746
  function deriveEventRegistrationSteps(input) {
18009
18747
  const ids = [];
18010
18748
  if (!input.hasPreSelectedContext) ids.push("select-event");
18011
18749
  ids.push("select-tickets", "enter-details");
18012
18750
  if (input.eventRequiresPayment && input.paymentSelection.method !== "pass" && input.paymentSelection.method !== "membership") ids.push("select-payment");
18751
+ if (input.step === "payment") ids.push("payment");
18013
18752
  const activeIndex = ids.indexOf(input.step);
18014
18753
  return ids.map((id, index) => ({
18015
18754
  id,
18016
18755
  label: getStepLabel(id),
18017
18756
  index,
18018
18757
  state: index === activeIndex ? "active" : activeIndex === -1 || index > activeIndex ? "available" : "complete",
18019
- canEnter: index <= Math.max(activeIndex + 1, 0),
18758
+ canEnter: input.step !== "payment" && index <= Math.max(activeIndex + 1, 0),
18020
18759
  canLeave: activeIndex !== index
18021
18760
  }));
18022
18761
  }
@@ -18038,7 +18777,8 @@ function getStepLabel(step) {
18038
18777
  case "select-event": return "Event";
18039
18778
  case "select-tickets": return "Tickets";
18040
18779
  case "enter-details": return "Details";
18041
- case "select-payment": return "Payment";
18780
+ case "select-payment": return "Payment options";
18781
+ case "payment": return "Payment";
18042
18782
  }
18043
18783
  }
18044
18784
  //#endregion
@@ -18084,6 +18824,7 @@ function groupPublicEventsByRun(events) {
18084
18824
  }
18085
18825
  //#endregion
18086
18826
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
18827
+ init_src();
18087
18828
  function toRegistrationEvent(event) {
18088
18829
  return {
18089
18830
  ...event,
@@ -18163,7 +18904,7 @@ function getRegistrationOccurrenceId(target) {
18163
18904
  return target?.subject.kind === "occurrence" ? target.subject.occurrenceId : "";
18164
18905
  }
18165
18906
  function shouldLoadRegistrationOptions(authState, step) {
18166
- return authState === "authenticated" || step === "select-tickets" || step === "enter-details" || step === "select-payment";
18907
+ return authState === "authenticated" || step === "select-tickets" || step === "fully-booked" || step === "enter-details" || step === "select-payment";
18167
18908
  }
18168
18909
  function getEligibilityFlowFlags(input) {
18169
18910
  const hasPass = (input.eligibility?.eligiblePasses.length ?? 0) > 0;
@@ -18262,132 +19003,545 @@ function useWaitlistClaimRestoration(input) {
18262
19003
  ]);
18263
19004
  }
18264
19005
  //#endregion
18265
- //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
18266
- function isSelectionSoldOut(availability) {
18267
- return availability?.kind === "unavailable" && availability.reason === "full";
18268
- }
18269
- function resolveRegistrationAvailabilityBlocker(input) {
18270
- if (input.hasWaitlistClaim) return null;
18271
- if (input.eligibilityError) return input.eligibilityError;
18272
- if (!input.eligibility) return "Registration is not available for this event.";
18273
- if (input.eligibility.registration.kind === "pending_payment") return null;
18274
- if (isSelectionSoldOut(input.eligibility.availability)) return null;
18275
- if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
18276
- if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
18277
- return null;
19006
+ //#region ../blocks/src/system/runtime/nodes/event-registration/useGuestRegistrationRecovery.ts
19007
+ /** Guest email is navigation permission only. Discard checks when the visitor
19008
+ * changes identity or selection before the response arrives. */
19009
+ function useGuestRegistrationRecovery(input) {
19010
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
19011
+ const [recoveryMessage, setRecoveryMessage] = useState(null);
19012
+ const request = guestNextStepRequest(input);
19013
+ const requestKey = JSON.stringify([
19014
+ request,
19015
+ input.step,
19016
+ input.portalAuthState,
19017
+ input.admission
19018
+ ]);
19019
+ const currentRequest = useRef(requestKey);
19020
+ currentRequest.current = requestKey;
19021
+ const checkDetailsNextStep = () => checkGuestNextStep(input, request, setCheckingNextStep);
19022
+ const handleRecoveryEmail = () => recoverByEmail({
19023
+ ...input,
19024
+ checkingNextStep,
19025
+ check: checkDetailsNextStep,
19026
+ setRecoveryMessage,
19027
+ isCurrent: () => currentRequest.current === requestKey
19028
+ });
19029
+ return {
19030
+ checkingNextStep,
19031
+ recoveryMessage,
19032
+ checkDetailsNextStep,
19033
+ handleRecoveryEmail
19034
+ };
18278
19035
  }
18279
- function resolvePricingSelectionBlocker(input) {
18280
- if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
18281
- return input.slidingScaleSelectionMessage;
19036
+ async function checkGuestNextStep(input, request, setCheckingNextStep) {
19037
+ const plan = resolveGuestNextStepCheck(input.admission, request);
19038
+ switch (plan.kind) {
19039
+ case "skip": return plan.outcome;
19040
+ case "blocked": return {
19041
+ kind: "unavailable",
19042
+ message: plan.message
19043
+ };
19044
+ case "check": break;
19045
+ }
19046
+ setCheckingNextStep(true);
19047
+ try {
19048
+ return await input.api.checkRegistrationNextStep(plan.request);
19049
+ } catch {
19050
+ return {
19051
+ kind: "unavailable",
19052
+ message: "We could not check availability. Please try again."
19053
+ };
19054
+ } finally {
19055
+ setCheckingNextStep(false);
19056
+ }
19057
+ }
19058
+ async function recoverByEmail(input) {
19059
+ if (input.checkingNextStep) return {
19060
+ ok: false,
19061
+ reason: "blocked",
19062
+ message: "Your booking is being checked."
19063
+ };
19064
+ const emailError = validateFormData(input.formData).email;
19065
+ input.setErrors(emailError ? { email: emailError } : {});
19066
+ input.setRecoveryMessage(null);
19067
+ if (emailError) return {
19068
+ ok: false,
19069
+ reason: "validation-failed",
19070
+ message: emailError
19071
+ };
19072
+ const next = await input.check();
19073
+ if (!input.isCurrent()) return {
19074
+ ok: false,
19075
+ reason: "blocked",
19076
+ message: "Your booking details changed. Please check again."
19077
+ };
19078
+ switch (next.kind) {
19079
+ case "continue":
19080
+ case "waitlist":
19081
+ input.onRecoveryChecked(next);
19082
+ return { ok: true };
19083
+ case "unavailable":
19084
+ input.setRecoveryMessage(next.message);
19085
+ return {
19086
+ ok: false,
19087
+ reason: "blocked",
19088
+ message: next.message
19089
+ };
19090
+ }
19091
+ }
19092
+ function guestNextStepRequest(input) {
19093
+ return input.registrationTarget ? {
19094
+ subject: toRegistrationRequestSubject(input.registrationTarget.subject, input.selectedAttendanceMode),
19095
+ selections: input.ticketSelections,
19096
+ selectedSlidingAmount: input.selectedSlidingAmount ?? void 0,
19097
+ email: input.formData.email,
19098
+ altchaSolution: input.altchaSolution
19099
+ } : null;
18282
19100
  }
18283
19101
  //#endregion
18284
- //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
18285
- function isCheckableRecovery(state) {
18286
- return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
19102
+ //#region ../blocks/src/system/runtime/nodes/event-registration/paymentResponse.ts
19103
+ /**
19104
+ * Verified response identity owns every follow-up action, including storage-free returns.
19105
+ * `requested` is the subject the client sent, if any: a subject-bound `notFound`
19106
+ * means the server lost that booking, which no amount of re-checking will fix.
19107
+ */
19108
+ function planPaymentResponse(response, intent, requested) {
19109
+ switch (response.kind) {
19110
+ case "checkout": return planCheckoutOutcome(response, intent);
19111
+ case "notFound": return requested ? assistance(requested) : { kind: "unresolved" };
19112
+ case "reconciliationRequired": return { kind: "unresolved" };
19113
+ default: return assertNever$1(response);
19114
+ }
18287
19115
  }
18288
- function assistanceRequired(recovery) {
19116
+ function assistance(subject) {
18289
19117
  return {
18290
- kind: "assistanceRequired",
18291
- subject: recovery.subject,
18292
- mailingListSignupNote: recovery.mailingListSignupNote
19118
+ kind: "recovery",
19119
+ state: {
19120
+ kind: "assistanceRequired",
19121
+ subject
19122
+ }
18293
19123
  };
18294
19124
  }
18295
- function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
18296
- if (outcome.kind === "resolved") {
18297
- setters.setPendingRegistrationReference(outcome.reference);
18298
- setters.setRegistrationResult({
18299
- status: "confirmed",
18300
- mailingListSignupNote: recovery.mailingListSignupNote
18301
- });
18302
- setRecovery(null);
18303
- setters.setStep("success");
18304
- return;
18305
- }
19125
+ function planCheckoutOutcome({ outcome, subject }, intent) {
18306
19126
  switch (outcome.kind) {
18307
- case "paymentProcessing":
18308
- setRecovery({
18309
- ...recovery,
18310
- kind: "processing"
18311
- });
18312
- return;
18313
- case "paymentAvailable":
18314
- setRecovery({
18315
- ...recovery,
19127
+ case "resolved": return { kind: "confirmed" };
19128
+ case "paymentAvailable": return intent === "resume" ? {
19129
+ kind: "payment",
19130
+ checkout: outcome.checkout,
19131
+ subject
19132
+ } : {
19133
+ kind: "recovery",
19134
+ state: {
18316
19135
  kind: "paymentAvailable",
18317
- checkoutUrl: outcome.checkoutUrl
18318
- });
18319
- return;
18320
- case "paymentCheckUnavailable":
18321
- setRecovery({
18322
- ...recovery,
18323
- kind: "temporarilyUnavailable"
18324
- });
18325
- return;
18326
- case "paymentRetryAvailable":
18327
- setRecovery({
18328
- ...recovery,
18329
- kind: "retryAvailable"
18330
- });
18331
- return;
19136
+ checkout: outcome.checkout,
19137
+ subject
19138
+ }
19139
+ };
18332
19140
  case "abandoned":
18333
- case "notFound":
19141
+ case "paymentRetryAvailable": return intent === "abandon" ? { kind: "restartBooking" } : {
19142
+ kind: "recovery",
19143
+ state: {
19144
+ kind: "retryAvailable",
19145
+ subject
19146
+ }
19147
+ };
19148
+ case "paymentProcessing": return {
19149
+ kind: "recovery",
19150
+ state: {
19151
+ kind: "processing",
19152
+ subject
19153
+ }
19154
+ };
19155
+ case "paymentCheckUnavailable": return {
19156
+ kind: "recovery",
19157
+ state: {
19158
+ kind: "temporarilyUnavailable",
19159
+ subject
19160
+ }
19161
+ };
18334
19162
  case "reconciliationRequired":
18335
- case "paymentAssistanceRequired":
18336
- setRecovery(assistanceRequired(recovery));
18337
- return;
19163
+ case "paymentAssistanceRequired": return assistance(subject);
19164
+ default: return assertNever$1(outcome);
18338
19165
  }
18339
19166
  }
18340
- function usePaymentStatusRecovery(options) {
18341
- const [recovery, setRecovery] = useState(null);
18342
- const checkRef = useRef(null);
19167
+ function paymentCheckEvidence(result) {
19168
+ switch (result.kind) {
19169
+ case "unreachable": return { kind: "inconclusive" };
19170
+ case "notFound": return { kind: "bindingLost" };
19171
+ case "reconciliationRequired": return { kind: "paymentUnderway" };
19172
+ case "checkout": return checkoutEvidence(result);
19173
+ default: return assertNever$1(result);
19174
+ }
19175
+ }
19176
+ function checkoutEvidence(response) {
19177
+ const { outcome } = response;
19178
+ switch (outcome.kind) {
19179
+ case "paymentCheckUnavailable": return { kind: "inconclusive" };
19180
+ case "paymentAvailable": return {
19181
+ kind: "payable",
19182
+ checkout: outcome.checkout,
19183
+ response
19184
+ };
19185
+ case "paymentProcessing":
19186
+ case "reconciliationRequired": return { kind: "paymentUnderway" };
19187
+ case "resolved":
19188
+ case "abandoned":
19189
+ case "paymentRetryAvailable":
19190
+ case "paymentAssistanceRequired": return {
19191
+ kind: "terminal",
19192
+ response
19193
+ };
19194
+ default: return assertNever$1(outcome);
19195
+ }
19196
+ }
19197
+ function planMountedPaymentRefresh(result, mounted) {
19198
+ const evidence = paymentCheckEvidence(result);
19199
+ switch (evidence.kind) {
19200
+ case "inconclusive": return { kind: "stay" };
19201
+ case "paymentUnderway": return { kind: "poll" };
19202
+ case "bindingLost": return {
19203
+ kind: "leave",
19204
+ transition: assistance(mounted.subject)
19205
+ };
19206
+ case "payable": return evidence.checkout.sessionId === mounted.sessionId ? { kind: "stay" } : {
19207
+ kind: "leave",
19208
+ transition: planCheckoutOutcome(evidence.response, "resume")
19209
+ };
19210
+ case "terminal": return {
19211
+ kind: "leave",
19212
+ transition: planCheckoutOutcome(evidence.response, "check")
19213
+ };
19214
+ default: return assertNever$1(evidence);
19215
+ }
19216
+ }
19217
+ function paymentResponseNeedsPolling(response) {
19218
+ if (response.kind !== "checkout") return response.kind === "reconciliationRequired";
19219
+ return paymentOutcomeNeedsPolling(response.outcome);
19220
+ }
19221
+ function paymentOutcomeNeedsPolling(outcome) {
19222
+ return outcome.kind === "paymentProcessing" || outcome.kind === "reconciliationRequired" || outcome.kind === "paymentCheckUnavailable";
19223
+ }
19224
+ //#endregion
19225
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
19226
+ function usePaymentRuntime() {
19227
+ const [state, setState] = useState({ kind: "idle" });
19228
+ const note = useRef(void 0);
19229
+ const operation = useRef(null);
19230
+ const generation = useRef(0);
19231
+ const appliedResult = useRef(null);
19232
+ const current = useRef(state);
19233
+ current.current = state;
19234
+ useEffect(() => () => {
19235
+ generation.current += 1;
19236
+ }, []);
18343
19237
  return {
18344
- recovery,
18345
- showRecovery: useCallback((next) => setRecovery(next), []),
18346
- check: useCallback(() => {
18347
- if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
18348
- const pending = (async () => {
18349
- setRecovery({
18350
- ...recovery,
18351
- kind: "checking"
19238
+ state,
19239
+ setState,
19240
+ note,
19241
+ operation,
19242
+ generation,
19243
+ appliedResult,
19244
+ current
19245
+ };
19246
+ }
19247
+ function usePaymentTransitions(options, runtime) {
19248
+ const { setState, note, generation, operation } = runtime;
19249
+ const openPayment = useCallback((checkout, subject, mailingListSignupNote) => {
19250
+ if (mailingListSignupNote) note.current = mailingListSignupNote;
19251
+ rememberEventPayment(subject.submissionId, checkout.sessionId);
19252
+ setState({
19253
+ kind: "payment",
19254
+ checkout,
19255
+ subject
19256
+ });
19257
+ options.setStep("payment");
19258
+ }, [
19259
+ options.setStep,
19260
+ setState,
19261
+ note
19262
+ ]);
19263
+ const verify = useCallback((request, resumePayment = true) => {
19264
+ if (operation.current) return;
19265
+ generation.current += 1;
19266
+ setState({
19267
+ kind: "verifying",
19268
+ request,
19269
+ resumePayment
19270
+ });
19271
+ options.setStep("verifying-payment");
19272
+ }, [
19273
+ options.setStep,
19274
+ operation,
19275
+ generation,
19276
+ setState
19277
+ ]);
19278
+ const restartFrom = useCallback((step) => {
19279
+ clearEventPayment(options.api.config.siteId);
19280
+ options.beginNewSubmission();
19281
+ setState({ kind: "idle" });
19282
+ options.setOptionsRefreshKey((value) => value + 1);
19283
+ options.setStep(step);
19284
+ }, [options, setState]);
19285
+ const resetBooking = useCallback(() => restartFrom("select-tickets"), [restartFrom]);
19286
+ const returnToPaymentOptions = useCallback(() => restartFrom(options.detailsInPage() ? "select-payment" : "select-tickets"), [restartFrom, options]);
19287
+ const applyTransition = useCallback((transition) => {
19288
+ switch (transition.kind) {
19289
+ case "confirmed":
19290
+ options.setRegistrationResult({
19291
+ status: "confirmed",
19292
+ mailingListSignupNote: note.current
18352
19293
  });
18353
- try {
18354
- applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
18355
- kind: "checkStatus",
18356
- subject: recovery.subject
18357
- }), recovery, options, setRecovery);
18358
- } catch {
18359
- setRecovery({
18360
- ...recovery,
18361
- kind: "temporarilyUnavailable"
18362
- });
19294
+ clearEventPayment(options.api.config.siteId);
19295
+ setState({ kind: "idle" });
19296
+ options.setStep("success");
19297
+ return;
19298
+ case "payment": return openPayment(transition.checkout, transition.subject);
19299
+ case "restartBooking": return resetBooking();
19300
+ case "recovery":
19301
+ setState({
19302
+ kind: "recovery",
19303
+ state: {
19304
+ ...transition.state,
19305
+ mailingListSignupNote: note.current
19306
+ }
19307
+ });
19308
+ options.setStep("payment-status");
19309
+ return;
19310
+ case "unresolved": return options.setStep("verifying-timeout");
19311
+ default: return assertNever$1(transition);
19312
+ }
19313
+ }, [
19314
+ openPayment,
19315
+ resetBooking,
19316
+ options,
19317
+ setState,
19318
+ note
19319
+ ]);
19320
+ return {
19321
+ openPayment,
19322
+ verify,
19323
+ applyOutcome: useCallback((response, intent, requested) => applyTransition(planPaymentResponse(response, intent, requested)), [applyTransition]),
19324
+ applyTransition,
19325
+ resetBooking,
19326
+ returnToPaymentOptions
19327
+ };
19328
+ }
19329
+ /** A session-only return has no client subject; the server's envelope must supply one. */
19330
+ function requestedSubject(request) {
19331
+ return request.kind === "resolveSession" ? null : request.subject;
19332
+ }
19333
+ function usePaymentChecks(options, runtime, transitions) {
19334
+ const { state, appliedResult, current } = runtime;
19335
+ const request = state.kind === "verifying" ? state.request : null;
19336
+ const polling = usePolling(request ? {
19337
+ restartKey: JSON.stringify(request),
19338
+ pollFn: () => options.api.resolveEventCheckoutReturn(request),
19339
+ isComplete: (result) => !paymentResponseNeedsPolling(result),
19340
+ maxAttempts: 10,
19341
+ interval: 1e3
19342
+ } : null);
19343
+ useEffect(() => {
19344
+ if (polling.status === "completed" && polling.result && request && appliedResult.current !== polling.result) {
19345
+ appliedResult.current = polling.result;
19346
+ transitions.applyOutcome(polling.result, state.kind === "verifying" && state.resumePayment ? "resume" : "check", requestedSubject(request));
19347
+ } else if (polling.status === "timeout") options.setStep("verifying-timeout");
19348
+ }, [
19349
+ polling.status,
19350
+ polling.result,
19351
+ request,
19352
+ transitions.applyOutcome,
19353
+ options.setStep,
19354
+ appliedResult
19355
+ ]);
19356
+ const check = useCallback((resumePayment = false) => {
19357
+ appliedResult.current = null;
19358
+ const active = current.current;
19359
+ if (active.kind === "payment") transitions.verify({
19360
+ kind: "checkStatus",
19361
+ subject: active.subject
19362
+ }, resumePayment);
19363
+ else if (active.kind === "recovery") transitions.verify({
19364
+ kind: "checkStatus",
19365
+ subject: active.state.subject
19366
+ }, resumePayment);
19367
+ else if (active.kind === "verifying") {
19368
+ options.setStep("verifying-payment");
19369
+ polling.retry();
19370
+ }
19371
+ }, [
19372
+ transitions.verify,
19373
+ polling.retry,
19374
+ options.setStep,
19375
+ appliedResult,
19376
+ current
19377
+ ]);
19378
+ const checkStatus = useCallback(() => check(), [check]);
19379
+ return {
19380
+ check: checkStatus,
19381
+ retryPaymentLoad: useCallback(() => check(true), [check]),
19382
+ verification: {
19383
+ ...polling,
19384
+ retry: checkStatus,
19385
+ retryReturn: checkStatus
19386
+ }
19387
+ };
19388
+ }
19389
+ function usePaymentAbandonment(options, runtime, transitions) {
19390
+ const { operation, generation, current, setState } = runtime;
19391
+ return useCallback(() => {
19392
+ if (operation.current) return operation.current;
19393
+ const active = current.current;
19394
+ if (active.kind !== "payment") return Promise.resolve();
19395
+ const token = ++generation.current;
19396
+ setState({
19397
+ kind: "abandoning",
19398
+ subject: active.subject
19399
+ });
19400
+ const pending = options.api.resolveEventCheckoutReturn({
19401
+ kind: "abandon",
19402
+ subject: active.subject
19403
+ }).then((outcome) => {
19404
+ if (token !== generation.current) return;
19405
+ transitions.applyOutcome(outcome, "abandon", active.subject);
19406
+ }).catch(() => {
19407
+ if (token !== generation.current) return;
19408
+ setState({
19409
+ kind: "recovery",
19410
+ state: {
19411
+ kind: "temporarilyUnavailable",
19412
+ subject: active.subject,
19413
+ mailingListSignupNote: runtime.note.current
18363
19414
  }
18364
- })();
18365
- checkRef.current = pending;
18366
- pending.finally(() => {
18367
- if (checkRef.current === pending) checkRef.current = null;
18368
19415
  });
18369
- }, [options, recovery]),
18370
- continuePayment: useCallback(() => {
18371
- if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
18372
- }, [recovery]),
18373
- returnToPayment: useCallback(() => {
18374
- if (recovery?.kind !== "retryAvailable") return;
18375
- options.beginNewSubmission();
18376
- setRecovery(null);
18377
- options.setOptionsRefreshKey((value) => value + 1);
18378
- options.setStep("select-payment");
18379
- }, [options, recovery]),
18380
- returnToBooking: useCallback(() => {
18381
- if (recovery?.kind !== "assistanceRequired") return;
18382
- options.beginNewSubmission();
18383
- setRecovery(null);
18384
- options.setOptionsRefreshKey((value) => value + 1);
18385
- options.setStep("select-tickets");
18386
- }, [options, recovery])
19416
+ options.setStep("payment-status");
19417
+ });
19418
+ operation.current = pending;
19419
+ pending.finally(() => {
19420
+ if (operation.current === pending) operation.current = null;
19421
+ });
19422
+ return pending;
19423
+ }, [
19424
+ options.api,
19425
+ transitions.applyOutcome,
19426
+ operation,
19427
+ generation,
19428
+ current,
19429
+ setState,
19430
+ options.setStep,
19431
+ runtime.note
19432
+ ]);
19433
+ }
19434
+ /**
19435
+ * Returning to the tab (often from a banking app mid-authentication) must not
19436
+ * unmount Stripe on inconclusive evidence; `planMountedPaymentRefresh` decides.
19437
+ */
19438
+ function usePaymentBackgroundCheck(options, runtime, transitions) {
19439
+ const { current, generation, operation } = runtime;
19440
+ const inFlight = useRef(false);
19441
+ return useCallback(() => {
19442
+ const active = current.current;
19443
+ if (active.kind !== "payment" || operation.current || inFlight.current) return;
19444
+ const token = generation.current;
19445
+ inFlight.current = true;
19446
+ const request = {
19447
+ kind: "checkStatus",
19448
+ subject: active.subject
19449
+ };
19450
+ const unreachable = { kind: "unreachable" };
19451
+ options.api.resolveEventCheckoutReturn(request).catch(() => unreachable).then((result) => {
19452
+ if (token !== generation.current || current.current !== active) return;
19453
+ const refresh = planMountedPaymentRefresh(result, {
19454
+ sessionId: active.checkout.sessionId,
19455
+ subject: active.subject
19456
+ });
19457
+ switch (refresh.kind) {
19458
+ case "stay": return;
19459
+ case "poll": return transitions.verify(request, false);
19460
+ case "leave": return transitions.applyTransition(refresh.transition);
19461
+ default: return assertNever$1(refresh);
19462
+ }
19463
+ }).finally(() => {
19464
+ inFlight.current = false;
19465
+ });
19466
+ }, [
19467
+ options.api,
19468
+ transitions.verify,
19469
+ transitions.applyTransition,
19470
+ current,
19471
+ generation,
19472
+ operation
19473
+ ]);
19474
+ }
19475
+ function usePaymentRefresh(state, check) {
19476
+ useEffect(() => {
19477
+ if (state.kind !== "payment") return;
19478
+ const timeout = window.setTimeout(check, Math.max(0, Date.parse(state.checkout.expiresAt) - Date.now()));
19479
+ const visible = () => {
19480
+ if (document.visibilityState === "visible") check();
19481
+ };
19482
+ const restored = (event) => {
19483
+ if (event.persisted) check();
19484
+ };
19485
+ document.addEventListener("visibilitychange", visible);
19486
+ window.addEventListener("pageshow", restored);
19487
+ return () => {
19488
+ clearTimeout(timeout);
19489
+ document.removeEventListener("visibilitychange", visible);
19490
+ window.removeEventListener("pageshow", restored);
19491
+ };
19492
+ }, [state, check]);
19493
+ }
19494
+ function usePaymentStatusRecovery(options) {
19495
+ const runtime = usePaymentRuntime();
19496
+ const transitions = usePaymentTransitions(options, runtime);
19497
+ const checks = usePaymentChecks(options, runtime, transitions);
19498
+ const backToBooking = usePaymentAbandonment(options, runtime, transitions);
19499
+ const backgroundCheck = usePaymentBackgroundCheck(options, runtime, transitions);
19500
+ const { state, setState, generation, note } = runtime;
19501
+ usePaymentRefresh(state, backgroundCheck);
19502
+ const recovery = state.kind === "recovery" ? state.state : null;
19503
+ return {
19504
+ state,
19505
+ recovery,
19506
+ showRecovery: useCallback((next) => {
19507
+ generation.current += 1;
19508
+ note.current = next?.mailingListSignupNote;
19509
+ setState(next ? {
19510
+ kind: "recovery",
19511
+ state: next
19512
+ } : { kind: "idle" });
19513
+ }, [
19514
+ generation,
19515
+ note,
19516
+ setState
19517
+ ]),
19518
+ restoreMailingListNote: (value) => {
19519
+ note.current = value;
19520
+ },
19521
+ openPayment: transitions.openPayment,
19522
+ verify: transitions.verify,
19523
+ ...checks,
19524
+ backToBooking,
19525
+ continuePayment: () => {
19526
+ if (recovery?.kind === "paymentAvailable") transitions.openPayment(recovery.checkout, recovery.subject);
19527
+ },
19528
+ returnToPayment: () => {
19529
+ if (recovery?.kind === "retryAvailable") transitions.returnToPaymentOptions();
19530
+ },
19531
+ returnToBooking: () => {
19532
+ if (recovery?.kind === "retryAvailable") transitions.resetBooking();
19533
+ }
18387
19534
  };
18388
19535
  }
18389
19536
  //#endregion
18390
19537
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
19538
+ init_src();
19539
+ function resolveAvailableAttendanceMode(event, selected) {
19540
+ if (!event) return null;
19541
+ const mode = event.deliveryMode ?? "in_person";
19542
+ if (mode === "online" || mode === "in_person") return mode;
19543
+ return selected && event.attendanceModes?.some((item) => item.mode === selected) ? selected : null;
19544
+ }
18391
19545
  function usesTieredPricing(event) {
18392
19546
  return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
18393
19547
  }
@@ -18445,19 +19599,24 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18445
19599
  const [errorAction, setErrorAction] = useState("retry");
18446
19600
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
18447
19601
  const [altchaSolution, setAltchaSolution] = useState(null);
18448
- const [checkingNextStep, setCheckingNextStep] = useState(false);
18449
19602
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
18450
19603
  const waitlistClaim = deps.useWaitlistClaim();
18451
19604
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
18452
- const [pendingRegistrationReference, setPendingRegistrationReference] = useState(null);
18453
19605
  const [paymentStepState, setPaymentStepState] = useState({
18454
19606
  status: "loading",
18455
19607
  canContinue: false,
18456
19608
  buttonText: "Continue",
18457
19609
  showLoginPrompt: false
18458
19610
  });
19611
+ const selectionLocked = [
19612
+ "payment",
19613
+ "submitting",
19614
+ "verifying-payment",
19615
+ "verifying-timeout",
19616
+ "payment-status"
19617
+ ].includes(step);
18459
19618
  useEffect(() => {
18460
- if (portalAuthState !== "authenticated" || !portalProfile) return;
19619
+ if (selectionLocked || portalAuthState !== "authenticated" || !portalProfile) return;
18461
19620
  setFormData((prev) => ({
18462
19621
  ...prev,
18463
19622
  email: portalProfile.email,
@@ -18479,16 +19638,17 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18479
19638
  step: nextStep
18480
19639
  });
18481
19640
  }, []);
18482
- const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
19641
+ const paymentController = usePaymentStatusRecovery({
18483
19642
  api,
18484
19643
  beginNewSubmission: () => {
18485
19644
  commandRef.current = null;
18486
19645
  },
18487
- setPendingRegistrationReference,
18488
19646
  setRegistrationResult,
18489
19647
  setOptionsRefreshKey,
18490
- setStep
19648
+ setStep,
19649
+ detailsInPage: () => Object.keys(validateFormData(formData)).length === 0
18491
19650
  });
19651
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = paymentController;
18492
19652
  const usesTicketTypeSelections = usesTieredPricing(currentEvent);
18493
19653
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
18494
19654
  event: currentEvent,
@@ -18590,26 +19750,14 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18590
19750
  });
18591
19751
  }, [portalAuthState]);
18592
19752
  useEffect(() => {
18593
- const event = selectedEvent ?? preSelectedEvent;
18594
- if (!event) {
18595
- if (selectedAttendanceMode !== null) setSelectedAttendanceMode(null);
18596
- return;
18597
- }
18598
- const deliveryMode = event.deliveryMode ?? "in_person";
18599
- if (deliveryMode === "online") {
18600
- if (selectedAttendanceMode !== "online") setSelectedAttendanceMode("online");
18601
- return;
18602
- }
18603
- if (deliveryMode === "in_person") {
18604
- if (selectedAttendanceMode !== "in_person") setSelectedAttendanceMode("in_person");
18605
- return;
18606
- }
18607
- if (selectedAttendanceMode && (event.attendanceModes ?? []).some((mode) => mode.mode === selectedAttendanceMode)) return;
18608
- setSelectedAttendanceMode(null);
19753
+ if (selectionLocked) return;
19754
+ const next = resolveAvailableAttendanceMode(selectedEvent ?? preSelectedEvent, selectedAttendanceMode);
19755
+ if (next !== selectedAttendanceMode) setSelectedAttendanceMode(next);
18609
19756
  }, [
18610
19757
  preSelectedEvent,
18611
19758
  selectedAttendanceMode,
18612
- selectedEvent
19759
+ selectedEvent,
19760
+ selectionLocked
18613
19761
  ]);
18614
19762
  useEffect(() => {
18615
19763
  dispatchFlow({
@@ -18617,25 +19765,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18617
19765
  eligibility
18618
19766
  });
18619
19767
  }, [eligibility]);
18620
- const verification = deps.useEventRegistrationStripeReturn({
18621
- api,
18622
- events: registrationEvents,
18623
- registrationSubject: registrationTarget?.subject ?? null,
18624
- step,
18625
- pendingRegistrationReference,
18626
- setFormData,
18627
- setTicketsCount,
18628
- setSelectedEvent,
18629
- setSelectedAttendanceMode,
18630
- setTicketSelections: (lines) => setSelectedTicketLines(normalizeTicketSelectionLines(lines)),
18631
- setPaymentSelection: (selection) => dispatchFlow({
18632
- type: "set-manual-payment-selection",
18633
- selection
18634
- }),
18635
- setPendingRegistrationReference,
18636
- setStep,
18637
- setRegistrationResult: (result) => setRegistrationResult(result),
18638
- setErrorMessage
19768
+ const verification = paymentController.verification;
19769
+ deps.useEventRegistrationStripeReturn({
19770
+ siteId: api.config.siteId,
19771
+ verify: paymentController.verify,
19772
+ restore: (pending) => {
19773
+ paymentController.restoreMailingListNote(pending.mailingListSignupNote);
19774
+ setFormData(pending.formData);
19775
+ setSelectedTicketLines(pending.ticketSelections);
19776
+ setTicketsCount(getTicketSelectionTotal(pending.ticketSelections));
19777
+ setGuests(pending.guests);
19778
+ discountUi.setDiscountCode(pending.discountCode);
19779
+ setSelectedSlidingAmountInput(pending.selectedSlidingAmount === null ? "" : formatCentsAsCurrencyInput(pending.selectedSlidingAmount));
19780
+ setSelectedAttendanceMode(pending.selectedAttendanceMode ?? null);
19781
+ const event = registrationEvents.find((item) => item.selectionId === pending.selectedEventId);
19782
+ if (event) setSelectedEvent(event);
19783
+ dispatchFlow({
19784
+ type: "set-manual-payment-selection",
19785
+ selection: pending.paymentSelection
19786
+ });
19787
+ }
18639
19788
  });
18640
19789
  const requireGuestDetails = useMemo(() => {
18641
19790
  return (selectedEvent ?? preSelectedEvent)?.requireGuestDetails === true;
@@ -18679,6 +19828,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18679
19828
  visibleOptions: visibleTicketTypes
18680
19829
  });
18681
19830
  useEffect(() => {
19831
+ if (selectionLocked) return;
18682
19832
  if (!usesTicketTypeSelections) {
18683
19833
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
18684
19834
  return;
@@ -18701,6 +19851,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18701
19851
  usesTicketTypeSelections
18702
19852
  ]);
18703
19853
  useEffect(() => {
19854
+ if (selectionLocked) return;
18704
19855
  if (!requireGuestDetails) {
18705
19856
  if (guests.length > 0) setGuests([]);
18706
19857
  return;
@@ -18710,19 +19861,16 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18710
19861
  if (guests.length > 0) setGuests([]);
18711
19862
  return;
18712
19863
  }
18713
- if (guests.length !== guestCount) {
18714
- const newGuests = [];
18715
- for (let i = 0; i < guestCount; i++) newGuests.push(guests[i] ?? {
18716
- name: "",
18717
- email: "",
18718
- phone: ""
18719
- });
18720
- setGuests(newGuests);
18721
- }
19864
+ if (guests.length !== guestCount) setGuests(Array.from({ length: guestCount }, (_, index) => guests[index] ?? {
19865
+ name: "",
19866
+ email: "",
19867
+ phone: ""
19868
+ }));
18722
19869
  }, [
18723
19870
  ticketsCount,
18724
19871
  requireGuestDetails,
18725
- guests
19872
+ guests,
19873
+ selectionLocked
18726
19874
  ]);
18727
19875
  const validateForm = () => {
18728
19876
  const newErrors = validateFormData(formData, Boolean(currentEvent?.consent));
@@ -18751,49 +19899,55 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18751
19899
  selectedEventSlidingScale,
18752
19900
  selectedSlidingAmount
18753
19901
  ]);
18754
- const checkDetailsNextStep = async () => {
18755
- if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
18756
- setCheckingNextStep(true);
18757
- try {
18758
- return await api.checkRegistrationNextStep({
18759
- subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
18760
- selections: ticketSelections,
18761
- selectedSlidingAmount: selectedSlidingAmount ?? void 0,
18762
- email: formData.email,
18763
- altchaSolution
18764
- });
18765
- } catch {
18766
- return {
18767
- kind: "unavailable",
18768
- message: "We could not check availability. Please try again."
18769
- };
18770
- } finally {
18771
- setCheckingNextStep(false);
18772
- }
18773
- };
19902
+ const { admission, ticketContinuation, handleTicketsComplete, onRecoveryChecked } = useRegistrationAdmission({
19903
+ eligibility,
19904
+ eligibilityError,
19905
+ eligibilityLoading,
19906
+ hasWaitlistClaim: waitlistClaim.claim !== null,
19907
+ isAuthenticated: portalAuthState === "authenticated",
19908
+ existingRegistrationLoading: existingRegistrationResult.isLoading,
19909
+ ticketSelectionRequired: ticketTypeSelectionRequired,
19910
+ hasValidTicketSelection,
19911
+ dispatchFlow
19912
+ });
19913
+ const { checkingNextStep, recoveryMessage, checkDetailsNextStep, handleRecoveryEmail } = useGuestRegistrationRecovery({
19914
+ api,
19915
+ formData,
19916
+ onRecoveryChecked,
19917
+ setErrors,
19918
+ admission,
19919
+ step,
19920
+ portalAuthState,
19921
+ registrationTarget,
19922
+ selectedAttendanceMode,
19923
+ ticketSelections,
19924
+ selectedSlidingAmount,
19925
+ altchaSolution
19926
+ });
18774
19927
  const handleDetailsComplete = async () => {
18775
- const blockDetailsCompletion = (message) => {
18776
- setErrorAction("places");
18777
- setErrorMessage(message);
18778
- setStep("error");
19928
+ const blockDetailsCompletion = (blocker) => {
19929
+ if (blocker.kind === "unavailable") {
19930
+ setErrorAction("places");
19931
+ setErrorMessage(blocker.message);
19932
+ setStep("error");
19933
+ }
18779
19934
  return {
18780
19935
  ok: false,
18781
19936
  reason: "blocked",
18782
- message
19937
+ message: blocker.message
18783
19938
  };
18784
19939
  };
18785
- const availabilityBlocker = resolveRegistrationAvailabilityBlocker({
18786
- hasWaitlistClaim: waitlistClaim.claim !== null,
18787
- eligibility,
18788
- eligibilityError
18789
- });
19940
+ const availabilityBlocker = resolveRegistrationAvailabilityBlocker(admission);
18790
19941
  if (availabilityBlocker) return blockDetailsCompletion(availabilityBlocker);
18791
19942
  const pricingSelectionBlocker = resolvePricingSelectionBlocker({
18792
19943
  selectionRequired: ticketTypeSelectionRequired,
18793
19944
  hasValidSelection: hasValidTicketSelection,
18794
19945
  slidingScaleSelectionMessage
18795
19946
  });
18796
- if (pricingSelectionBlocker) return blockDetailsCompletion(pricingSelectionBlocker);
19947
+ if (pricingSelectionBlocker) return blockDetailsCompletion({
19948
+ kind: "unavailable",
19949
+ message: pricingSelectionBlocker
19950
+ });
18797
19951
  if (!validateForm()) {
18798
19952
  setGuestSectionShake(true);
18799
19953
  return {
@@ -18803,7 +19957,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18803
19957
  };
18804
19958
  }
18805
19959
  const next = await checkDetailsNextStep();
18806
- if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
19960
+ if (next.kind === "unavailable") return blockDetailsCompletion({
19961
+ kind: "unavailable",
19962
+ message: next.message
19963
+ });
18807
19964
  const canJoinWaitlist = next.kind === "waitlist";
18808
19965
  if (!canJoinWaitlist && requiresPaymentStep({
18809
19966
  eventRequiresPayment,
@@ -18820,7 +19977,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18820
19977
  eventRequiresPayment,
18821
19978
  canJoinWaitlist
18822
19979
  });
18823
- if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
19980
+ if (!submitPlan.ok) return blockDetailsCompletion({
19981
+ kind: "unavailable",
19982
+ message: submitPlan.message
19983
+ });
18824
19984
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
18825
19985
  if (!submitResult.ok) return {
18826
19986
  ok: false,
@@ -18868,6 +20028,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18868
20028
  const selectionMethod = paymentSelection.method;
18869
20029
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
18870
20030
  const handleSubmit = deps.useEventRegistrationSubmit({
20031
+ openPayment: paymentController.openPayment,
18871
20032
  commandRef,
18872
20033
  setErrorAction,
18873
20034
  api,
@@ -18883,7 +20044,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18883
20044
  discountCode: discountUi.discountCode,
18884
20045
  claimToken: waitlistClaim.token,
18885
20046
  waitlistEntryId: waitlistClaim.entryId,
18886
- setPendingRegistrationReference,
18887
20047
  setStep,
18888
20048
  setRegistrationResult: (result) => setRegistrationResult(result),
18889
20049
  setErrorMessage,
@@ -18905,7 +20065,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18905
20065
  });
18906
20066
  };
18907
20067
  const handleRetry = () => recoverRegistrationError(resolveRegistrationRecoveryAction(step, errorAction), {
18908
- canJoinWaitlist: canRecoverToWaitlist(eligibility),
20068
+ canJoinWaitlist: admission.kind === "waitlist",
18909
20069
  refreshOptions: () => setOptionsRefreshKey((value) => value + 1),
18910
20070
  clearError: () => setErrorMessage(""),
18911
20071
  setStep,
@@ -18916,8 +20076,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18916
20076
  setSelectedTicketLines,
18917
20077
  setSelectedSlidingAmountInput,
18918
20078
  setSelectedAttendanceMode,
18919
- setErrorMessage,
18920
- setPendingRegistrationReference
20079
+ setErrorMessage
18921
20080
  })
18922
20081
  });
18923
20082
  const handlePaymentStepStateChange = useCallback((state) => {
@@ -18948,21 +20107,35 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18948
20107
  preSelectedEvent,
18949
20108
  hasPreSelectedContext,
18950
20109
  step,
18951
- setStep,
20110
+ setStep: (next) => {
20111
+ if (!selectionLocked) setStep(next);
20112
+ else if (step === "payment") paymentController.backToBooking();
20113
+ },
20114
+ admission,
20115
+ ticketContinuation,
20116
+ handleTicketsComplete,
18952
20117
  selectedEvent,
18953
- setSelectedEvent,
20118
+ setSelectedEvent: (value) => {
20119
+ if (!selectionLocked) setSelectedEvent(value);
20120
+ },
18954
20121
  ticketsCount,
18955
- setTicketsCount,
20122
+ setTicketsCount: (value) => {
20123
+ if (!selectionLocked) setTicketsCount(value);
20124
+ },
18956
20125
  selectedAttendanceMode,
18957
- setSelectedAttendanceMode,
20126
+ setSelectedAttendanceMode: (value) => {
20127
+ if (!selectionLocked) setSelectedAttendanceMode(value);
20128
+ },
18958
20129
  ticketSelections,
18959
20130
  selectedTicketLines: normalizedSelectedTicketLines,
18960
20131
  setSelectedTicketLines: (lines) => {
18961
- if (waitlistClaim.claim) return;
20132
+ if (selectionLocked || waitlistClaim.claim) return;
18962
20133
  setSelectedTicketLines(normalizeTicketSelectionLines(lines));
18963
20134
  },
18964
20135
  selectedSlidingAmountInput,
18965
- setSelectedSlidingAmountInput,
20136
+ setSelectedSlidingAmountInput: (value) => {
20137
+ if (!selectionLocked) setSelectedSlidingAmountInput(value);
20138
+ },
18966
20139
  selectedSlidingAmount,
18967
20140
  selectedEventSlidingScale,
18968
20141
  slidingScaleSelectionMessage,
@@ -18975,10 +20148,14 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18975
20148
  eventRequiresPayment,
18976
20149
  formData,
18977
20150
  mailingListSignup,
18978
- setFormData,
20151
+ setFormData: (value) => {
20152
+ if (!selectionLocked) setFormData(value);
20153
+ },
18979
20154
  errors,
18980
20155
  guests,
18981
- setGuests,
20156
+ setGuests: (value) => {
20157
+ if (!selectionLocked) setGuests(value);
20158
+ },
18982
20159
  guestErrors,
18983
20160
  guestSectionShake,
18984
20161
  handleGuestShakeEnd,
@@ -18995,7 +20172,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18995
20172
  handleLogout,
18996
20173
  paymentStepState,
18997
20174
  handlePaymentStepStateChange,
18998
- handlePaymentSelectionChange,
20175
+ handlePaymentSelectionChange: (value) => {
20176
+ if (!selectionLocked) handlePaymentSelectionChange(value);
20177
+ },
18999
20178
  paymentSelection,
19000
20179
  isMembershipFastTrack,
19001
20180
  waitlistClaim,
@@ -19011,7 +20190,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
19011
20190
  hasMembershipEligibility,
19012
20191
  requireGuestDetails,
19013
20192
  discountCode: discountUi.discountCode,
19014
- setDiscountCode: discountUi.setDiscountCode,
20193
+ setDiscountCode: (value) => {
20194
+ if (!selectionLocked) discountUi.setDiscountCode(value);
20195
+ },
19015
20196
  discountUiOpen: discountUi.discountUiOpen,
19016
20197
  setDiscountUiOpen: discountUi.setDiscountUiOpen,
19017
20198
  discountsAvailable: discountUi.discountsAvailable,
@@ -19021,17 +20202,27 @@ function useEventRegistrationWizardWithDeps(options, deps) {
19021
20202
  discountContext,
19022
20203
  shouldShowDiscountToggle,
19023
20204
  verification,
20205
+ paymentController,
19024
20206
  paymentStatusRecovery,
19025
20207
  handleCheckPaymentStatus,
19026
20208
  handleContinueExistingPayment,
19027
20209
  handleReturnToPayment,
19028
20210
  handleReturnToBooking,
20211
+ recoveryMessage,
20212
+ checkingNextStep,
20213
+ handleRecoveryEmail,
19029
20214
  handleDetailsComplete,
19030
20215
  handlePaymentSelect,
19031
20216
  handleUseCardInsteadOfPass,
19032
20217
  handleBookForSomeoneElse,
19033
- handleSubmit,
19034
- handleEventSelect,
20218
+ handleSubmit: (...args) => selectionLocked ? Promise.resolve({
20219
+ ok: false,
20220
+ reason: "blocked",
20221
+ message: "This registration step cannot continue."
20222
+ }) : handleSubmit(...args),
20223
+ handleEventSelect: (value) => {
20224
+ if (!selectionLocked) handleEventSelect(value);
20225
+ },
19035
20226
  handleRetry
19036
20227
  };
19037
20228
  }
@@ -19072,66 +20263,23 @@ function useEventRegistrationControllerWithDeps(options, deps) {
19072
20263
  wizard.selectedEvent,
19073
20264
  wizard.ticketsCount
19074
20265
  ]);
19075
- const submit = useCallback(async (submitOptions) => {
20266
+ const submit = useCallback(async () => {
19076
20267
  const plan = resolveEventRegistrationSubmitPlan({
19077
20268
  paymentSelection: normalizeEventRegistrationDirectPaymentSelection({
19078
20269
  options: directPaymentOptions,
19079
20270
  selection: wizard.paymentSelection
19080
20271
  }),
19081
20272
  eventRequiresPayment: wizard.eventRequiresPayment,
19082
- canJoinWaitlist: wizard.step !== "select-payment" && wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment"
20273
+ canJoinWaitlist: wizard.step !== "select-payment" && wizard.admission.kind === "waitlist"
19083
20274
  });
19084
20275
  if (!plan.ok) return {
19085
20276
  ok: false,
19086
20277
  reason: "blocked",
19087
20278
  message: plan.message
19088
20279
  };
19089
- return wizard.handleSubmit(plan.args.method, plan.args.passId, plan.args.membershipId, plan.args.selection, submitOptions);
20280
+ return wizard.handleSubmit(plan.args.method, plan.args.passId, plan.args.membershipId, plan.args.selection);
19090
20281
  }, [directPaymentOptions, wizard]);
19091
- const next = useCallback(async () => {
19092
- switch (wizard.step) {
19093
- case "select-event":
19094
- if (!wizard.selectedEvent) return {
19095
- ok: false,
19096
- reason: "blocked",
19097
- message: "Select an event to continue."
19098
- };
19099
- wizard.setStep("select-tickets");
19100
- return { ok: true };
19101
- case "select-tickets":
19102
- if (wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection) return {
19103
- ok: false,
19104
- reason: "blocked",
19105
- message: "Choose at least one available ticket to continue."
19106
- };
19107
- wizard.setStep("enter-details");
19108
- return { ok: true };
19109
- case "enter-details": {
19110
- const result = await wizard.handleDetailsComplete();
19111
- return result.ok ? { ok: true } : result;
19112
- }
19113
- case "select-payment": {
19114
- const result = await submit({ redirect: "manual" });
19115
- return result.ok ? { ok: true } : {
19116
- ok: false,
19117
- reason: result.reason === "submission-failed" ? "submission-failed" : "blocked",
19118
- message: result.message
19119
- };
19120
- }
19121
- case "error":
19122
- case "success":
19123
- case "submitting":
19124
- case "redirecting":
19125
- case "verifying-payment":
19126
- case "verifying-timeout":
19127
- case "payment-status":
19128
- case "payment-failed": return {
19129
- ok: false,
19130
- reason: "blocked",
19131
- message: "This registration step cannot continue."
19132
- };
19133
- }
19134
- }, [submit, wizard]);
20282
+ const next = useEventRegistrationNext(wizard, submit);
19135
20283
  const back = useEventRegistrationBack(wizard);
19136
20284
  const updateAttendee = useCallback((values) => {
19137
20285
  wizard.setFormData(values);
@@ -19246,6 +20394,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
19246
20394
  back,
19247
20395
  submit,
19248
20396
  retry: wizard.handleRetry,
20397
+ ...headlessPaymentActions(wizard.paymentController),
19249
20398
  checkPaymentStatus: wizard.handleCheckPaymentStatus,
19250
20399
  continueExistingPayment: wizard.handleContinueExistingPayment,
19251
20400
  returnToPayment: wizard.handleReturnToPayment,
@@ -19255,9 +20404,65 @@ function useEventRegistrationControllerWithDeps(options, deps) {
19255
20404
  wizard
19256
20405
  };
19257
20406
  }
20407
+ /** The embedded payment's headless actions all come from the one payment controller. */
20408
+ function headlessPaymentActions(payment) {
20409
+ return {
20410
+ checkPayment: payment.check,
20411
+ completePayment: payment.check,
20412
+ retryPaymentLoad: payment.retryPaymentLoad,
20413
+ backToBooking: payment.backToBooking
20414
+ };
20415
+ }
20416
+ function advanceHeadlessEvent(wizard) {
20417
+ if (!wizard.selectedEvent) return {
20418
+ ok: false,
20419
+ reason: "blocked",
20420
+ message: "Select an event to continue."
20421
+ };
20422
+ wizard.setStep("select-tickets");
20423
+ return { ok: true };
20424
+ }
20425
+ function useEventRegistrationNext(wizard, submit) {
20426
+ return useCallback(async () => {
20427
+ switch (wizard.step) {
20428
+ case "select-event": return advanceHeadlessEvent(wizard);
20429
+ case "select-tickets": return wizard.handleTicketsComplete();
20430
+ case "fully-booked": return wizard.handleRecoveryEmail();
20431
+ case "enter-details": {
20432
+ const result = await wizard.handleDetailsComplete();
20433
+ return result.ok ? { ok: true } : result;
20434
+ }
20435
+ case "select-payment": {
20436
+ const result = await submit();
20437
+ return result.ok ? { ok: true } : {
20438
+ ok: false,
20439
+ reason: result.reason === "submission-failed" ? "submission-failed" : "blocked",
20440
+ message: result.message
20441
+ };
20442
+ }
20443
+ case "error":
20444
+ case "success":
20445
+ case "submitting":
20446
+ case "payment":
20447
+ case "verifying-payment":
20448
+ case "verifying-timeout":
20449
+ case "payment-status":
20450
+ case "payment-failed": return {
20451
+ ok: false,
20452
+ reason: "blocked",
20453
+ message: "This registration step cannot continue."
20454
+ };
20455
+ }
20456
+ }, [submit, wizard]);
20457
+ }
19258
20458
  function useEventRegistrationBack(wizard) {
19259
20459
  return useCallback(() => {
20460
+ if (wizard.paymentController.state.kind !== "idle") {
20461
+ wizard.paymentController.backToBooking();
20462
+ return;
20463
+ }
19260
20464
  switch (wizard.step) {
20465
+ case "fully-booked":
19261
20466
  case "enter-details":
19262
20467
  wizard.setStep("select-tickets");
19263
20468
  return;
@@ -19271,7 +20476,7 @@ function useEventRegistrationBack(wizard) {
19271
20476
  case "error":
19272
20477
  case "success":
19273
20478
  case "submitting":
19274
- case "redirecting":
20479
+ case "payment":
19275
20480
  case "verifying-payment":
19276
20481
  case "verifying-timeout":
19277
20482
  case "payment-status":
@@ -19322,6 +20527,7 @@ function resolvePaymentModel(wizard, directPaymentOptions) {
19322
20527
  selection,
19323
20528
  directPaymentOptions,
19324
20529
  directPaymentSelectionState,
20530
+ checkout: wizard.paymentController.state,
19325
20531
  stepState: wizard.paymentStepState
19326
20532
  };
19327
20533
  return {
@@ -19329,6 +20535,7 @@ function resolvePaymentModel(wizard, directPaymentOptions) {
19329
20535
  selection,
19330
20536
  directPaymentOptions,
19331
20537
  directPaymentSelectionState,
20538
+ checkout: wizard.paymentController.state,
19332
20539
  stepState: wizard.paymentStepState,
19333
20540
  eligibility: wizard.eligibility,
19334
20541
  eligibilityError: wizard.eligibilityError
@@ -19518,6 +20725,333 @@ async function loadBookingFormServices(api, formConfig) {
19518
20725
  return [];
19519
20726
  }
19520
20727
  //#endregion
20728
+ //#region ../../node_modules/.pnpm/@stripe+stripe-js@9.17.0/node_modules/@stripe/stripe-js/dist/pure.js
20729
+ var require_pure$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
20730
+ Object.defineProperty(exports, "__esModule", { value: true });
20731
+ function _typeof(obj) {
20732
+ "@babel/helpers - typeof";
20733
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") _typeof = function(obj) {
20734
+ return typeof obj;
20735
+ };
20736
+ else _typeof = function(obj) {
20737
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
20738
+ };
20739
+ return _typeof(obj);
20740
+ }
20741
+ var RELEASE_TRAIN = "dahlia";
20742
+ var runtimeVersionToUrlVersion = function runtimeVersionToUrlVersion(version) {
20743
+ return version === 3 ? "v3" : version;
20744
+ };
20745
+ var ORIGIN = "https://js.stripe.com";
20746
+ var STRIPE_JS_URL = "".concat(ORIGIN, "/").concat(RELEASE_TRAIN, "/stripe.js");
20747
+ var V3_URL_REGEX = /^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;
20748
+ var STRIPE_JS_URL_REGEX = /^https:\/\/js\.stripe\.com\/(v3|[a-z]+)\/stripe\.js(\?.*)?$/;
20749
+ var EXISTING_SCRIPT_MESSAGE = "loadStripe.setLoadParameters was called but an existing Stripe.js script already exists in the document; existing script parameters will be used";
20750
+ var isStripeJSURL = function isStripeJSURL(url) {
20751
+ return V3_URL_REGEX.test(url) || STRIPE_JS_URL_REGEX.test(url);
20752
+ };
20753
+ var findScript = function findScript() {
20754
+ var scripts = document.querySelectorAll("script[src^=\"".concat(ORIGIN, "\"]"));
20755
+ for (var i = 0; i < scripts.length; i++) {
20756
+ var script = scripts[i];
20757
+ if (!isStripeJSURL(script.src)) continue;
20758
+ return script;
20759
+ }
20760
+ return null;
20761
+ };
20762
+ var injectScript = function injectScript(params) {
20763
+ var queryString = params && !params.advancedFraudSignals ? "?advancedFraudSignals=false" : "";
20764
+ var script = document.createElement("script");
20765
+ script.src = "".concat(STRIPE_JS_URL).concat(queryString);
20766
+ var headOrBody = document.head || document.body;
20767
+ if (!headOrBody) throw new Error("Expected document.body not to be null. Stripe.js requires a <body> element.");
20768
+ headOrBody.appendChild(script);
20769
+ return script;
20770
+ };
20771
+ var registerWrapper = function registerWrapper(stripe, startTime) {
20772
+ if (!stripe || !stripe._registerWrapper) return;
20773
+ stripe._registerWrapper({
20774
+ name: "stripe-js",
20775
+ version: "9.17.0",
20776
+ startTime
20777
+ });
20778
+ };
20779
+ var stripePromise = null;
20780
+ var onErrorListener = null;
20781
+ var onLoadListener = null;
20782
+ var onError = function onError(reject) {
20783
+ return function(cause) {
20784
+ reject(new Error("Failed to load Stripe.js", { cause }));
20785
+ };
20786
+ };
20787
+ var onLoad = function onLoad(resolve, reject) {
20788
+ return function() {
20789
+ if (window.Stripe) resolve(window.Stripe);
20790
+ else reject(/* @__PURE__ */ new Error("Stripe.js not available"));
20791
+ };
20792
+ };
20793
+ var loadScript = function loadScript(params) {
20794
+ if (stripePromise !== null) return stripePromise;
20795
+ stripePromise = new Promise(function(resolve, reject) {
20796
+ if (typeof window === "undefined" || typeof document === "undefined") {
20797
+ resolve(null);
20798
+ return;
20799
+ }
20800
+ if (window.Stripe && params) console.warn(EXISTING_SCRIPT_MESSAGE);
20801
+ if (window.Stripe) {
20802
+ resolve(window.Stripe);
20803
+ return;
20804
+ }
20805
+ try {
20806
+ var script = findScript();
20807
+ if (script && params) console.warn(EXISTING_SCRIPT_MESSAGE);
20808
+ else if (!script) script = injectScript(params);
20809
+ else if (script && onLoadListener !== null && onErrorListener !== null) {
20810
+ var _script$parentNode;
20811
+ script.removeEventListener("load", onLoadListener);
20812
+ script.removeEventListener("error", onErrorListener);
20813
+ (_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 || _script$parentNode.removeChild(script);
20814
+ script = injectScript(params);
20815
+ }
20816
+ onLoadListener = onLoad(resolve, reject);
20817
+ onErrorListener = onError(reject);
20818
+ script.addEventListener("load", onLoadListener);
20819
+ script.addEventListener("error", onErrorListener);
20820
+ } catch (error) {
20821
+ reject(error);
20822
+ return;
20823
+ }
20824
+ });
20825
+ return stripePromise["catch"](function(error) {
20826
+ stripePromise = null;
20827
+ return Promise.reject(error);
20828
+ });
20829
+ };
20830
+ var initStripe = function initStripe(maybeStripe, args, startTime) {
20831
+ if (maybeStripe === null) return null;
20832
+ var pk = args[0];
20833
+ if (typeof pk !== "string") throw new Error("Expected publishable key to be of type string, got type ".concat(_typeof(pk), " instead."));
20834
+ var isTestKey = pk.match(/^pk_test/);
20835
+ var version = runtimeVersionToUrlVersion(maybeStripe.version);
20836
+ var expectedVersion = RELEASE_TRAIN;
20837
+ if (isTestKey && version !== expectedVersion) console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("9.17.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
20838
+ var stripe = maybeStripe.apply(void 0, args);
20839
+ registerWrapper(stripe, startTime);
20840
+ return stripe;
20841
+ };
20842
+ var validateLoadParams = function validateLoadParams(params) {
20843
+ var errorMessage = "invalid load parameters; expected object of shape\n\n {advancedFraudSignals: boolean}\n\nbut received\n\n ".concat(JSON.stringify(params), "\n");
20844
+ if (params === null || _typeof(params) !== "object") throw new Error(errorMessage);
20845
+ if (Object.keys(params).length === 1 && typeof params.advancedFraudSignals === "boolean") return params;
20846
+ throw new Error(errorMessage);
20847
+ };
20848
+ var loadParams;
20849
+ var loadStripeCalled = false;
20850
+ var loadStripe = function loadStripe() {
20851
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key];
20852
+ loadStripeCalled = true;
20853
+ var startTime = Date.now();
20854
+ return loadScript(loadParams).then(function(maybeStripe) {
20855
+ return initStripe(maybeStripe, args, startTime);
20856
+ });
20857
+ };
20858
+ loadStripe.setLoadParameters = function(params) {
20859
+ if (loadStripeCalled && loadParams) {
20860
+ var validatedParams = validateLoadParams(params);
20861
+ if (Object.keys(validatedParams).reduce(function(previousValue, currentValue) {
20862
+ var _loadParams;
20863
+ return previousValue && params[currentValue] === ((_loadParams = loadParams) === null || _loadParams === void 0 ? void 0 : _loadParams[currentValue]);
20864
+ }, true)) return;
20865
+ }
20866
+ if (loadStripeCalled) throw new Error("You cannot change load parameters after calling loadStripe");
20867
+ loadParams = validateLoadParams(params);
20868
+ };
20869
+ exports.loadStripe = loadStripe;
20870
+ }));
20871
+ //#endregion
20872
+ //#region ../../node_modules/.pnpm/@stripe+stripe-js@9.17.0/node_modules/@stripe/stripe-js/pure/index.js
20873
+ var require_pure = /* @__PURE__ */ __commonJSMin(((exports, module) => {
20874
+ module.exports = require_pure$1();
20875
+ }));
20876
+ //#endregion
20877
+ //#region ../blocks/src/system/runtime/shared/stripe/browserStripe.ts
20878
+ /** Pure entry loading stays inert until a payment surface calls this function. */
20879
+ function loadBrowserStripe(context) {
20880
+ const accountId = "kind" in context && context.kind === "connect" ? context.accountId : void 0;
20881
+ const cacheKey = JSON.stringify([context.publishableKey, accountId ?? "direct"]);
20882
+ const existing = stripeByContext.get(cacheKey);
20883
+ if (existing) return existing;
20884
+ const loading = (0, import_pure.loadStripe)(context.publishableKey, ...accountId ? [{ stripeAccount: accountId }] : []).then((stripe) => {
20885
+ if (!stripe) stripeByContext.delete(cacheKey);
20886
+ return stripe;
20887
+ }, (error) => {
20888
+ stripeByContext.delete(cacheKey);
20889
+ throw error;
20890
+ });
20891
+ stripeByContext.set(cacheKey, loading);
20892
+ return loading;
20893
+ }
20894
+ var import_pure, stripeByContext;
20895
+ var init_browserStripe = __esmMin((() => {
20896
+ import_pure = require_pure();
20897
+ init_purchase();
20898
+ stripeByContext = /* @__PURE__ */ new Map();
20899
+ }));
20900
+ //#endregion
20901
+ //#region ../blocks/src/system/runtime/nodes/event-registration/EventEmbeddedCheckoutStep.tsx
20902
+ var EventEmbeddedCheckoutStep_exports = /* @__PURE__ */ __exportAll({
20903
+ EventEmbeddedCheckoutStepWithDeps: () => EventEmbeddedCheckoutStepWithDeps,
20904
+ default: () => EventEmbeddedCheckoutStep
20905
+ });
20906
+ function useStripeMount(props, container, load) {
20907
+ const [status, setStatus] = useState("loading");
20908
+ const callbacks = useRef(props);
20909
+ callbacks.current = props;
20910
+ useEffect(() => {
20911
+ const lifecycle = {
20912
+ active: true,
20913
+ instance: null
20914
+ };
20915
+ setStatus("loading");
20916
+ const fail = () => {
20917
+ if (!lifecycle.active) return;
20918
+ lifecycle.active = false;
20919
+ lifecycle.instance?.destroy();
20920
+ lifecycle.instance = null;
20921
+ setStatus("failed");
20922
+ };
20923
+ const timeout = window.setTimeout(fail, 3e4);
20924
+ const mount = async () => {
20925
+ if (checkBrowserStripeKey(props.checkout.browser.publishableKey, props.checkout.livemode).tag !== "ready") throw new Error("Invalid payment configuration");
20926
+ const stripe = await load(props.checkout.browser);
20927
+ if (!lifecycle.active) return;
20928
+ if (!stripe) throw new Error("Payment form unavailable");
20929
+ const instance = await stripe.createEmbeddedCheckoutPage({
20930
+ clientSecret: props.checkout.clientSecret,
20931
+ onComplete: () => {
20932
+ if (lifecycle.active) callbacks.current.onComplete();
20933
+ }
20934
+ });
20935
+ if (!lifecycle.active || !container.current) {
20936
+ instance.destroy();
20937
+ return;
20938
+ }
20939
+ lifecycle.instance = instance;
20940
+ instance.mount(container.current);
20941
+ clearTimeout(timeout);
20942
+ setStatus("ready");
20943
+ };
20944
+ mount().catch(fail);
20945
+ return () => {
20946
+ lifecycle.active = false;
20947
+ clearTimeout(timeout);
20948
+ lifecycle.instance?.destroy();
20949
+ };
20950
+ }, [
20951
+ props.checkout,
20952
+ container,
20953
+ load
20954
+ ]);
20955
+ return status;
20956
+ }
20957
+ function EventEmbeddedCheckoutStep(props) {
20958
+ return /* @__PURE__ */ jsx(EventEmbeddedCheckoutStepWithDeps, {
20959
+ ...props,
20960
+ load: loadBrowserStripe
20961
+ });
20962
+ }
20963
+ function EventEmbeddedCheckoutStepWithDeps(props) {
20964
+ const container = useRef(null);
20965
+ const heading = useRef(null);
20966
+ const status = useStripeMount(props, container, props.load);
20967
+ useEffect(() => {
20968
+ heading.current?.focus();
20969
+ }, []);
20970
+ return /* @__PURE__ */ jsxs("section", {
20971
+ className: "er-embedded-payment",
20972
+ children: [
20973
+ /* @__PURE__ */ jsx("h2", {
20974
+ ref: heading,
20975
+ tabIndex: -1,
20976
+ className: "er-title er-message",
20977
+ children: "Payment"
20978
+ }),
20979
+ status === "loading" && /* @__PURE__ */ jsxs("div", {
20980
+ className: "er-center er-message",
20981
+ role: "status",
20982
+ "aria-live": "polite",
20983
+ children: [/* @__PURE__ */ jsx("div", {
20984
+ className: "er-icon",
20985
+ children: /* @__PURE__ */ jsx(SpinnerNode, { size: "lg" })
20986
+ }), /* @__PURE__ */ jsx("p", {
20987
+ className: "er-text--muted",
20988
+ children: "Loading secure payment…"
20989
+ })]
20990
+ }),
20991
+ status === "failed" && /* @__PURE__ */ jsxs("div", {
20992
+ className: "er-center er-message",
20993
+ role: "alert",
20994
+ children: [/* @__PURE__ */ jsx("p", {
20995
+ className: "er-text--muted er-message",
20996
+ children: "We couldn’t load the payment form."
20997
+ }), /* @__PURE__ */ jsx("button", {
20998
+ type: "button",
20999
+ className: "er-btn er-btn--primary",
21000
+ onClick: props.onRetry,
21001
+ children: "Try again"
21002
+ })]
21003
+ }),
21004
+ /* @__PURE__ */ jsx("div", {
21005
+ ref: container,
21006
+ className: "er-message",
21007
+ style: { width: "100%" }
21008
+ }),
21009
+ /* @__PURE__ */ jsx("button", {
21010
+ type: "button",
21011
+ className: "er-back-btn",
21012
+ onClick: props.onBack,
21013
+ children: "Back to booking"
21014
+ })
21015
+ ]
21016
+ });
21017
+ }
21018
+ var init_EventEmbeddedCheckoutStep = __esmMin((() => {
21019
+ init_browserStripe();
21020
+ init_spinner();
21021
+ }));
21022
+ //#endregion
21023
+ //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationPayment.tsx
21024
+ const Payment = lazy(() => Promise.resolve().then(() => (init_EventEmbeddedCheckoutStep(), EventEmbeddedCheckoutStep_exports)));
21025
+ /** The one Stripe mount, shared by the standard wizard and headless arrangements. */
21026
+ function EventPaymentMount({ state, onComplete, onRetry, onBack }) {
21027
+ if (state.kind === "abandoning") return /* @__PURE__ */ jsx("p", {
21028
+ role: "status",
21029
+ children: "Returning to booking…"
21030
+ });
21031
+ if (state.kind !== "payment") return null;
21032
+ return /* @__PURE__ */ jsx(Suspense, {
21033
+ fallback: /* @__PURE__ */ jsx("p", {
21034
+ role: "status",
21035
+ children: "Loading secure payment…"
21036
+ }),
21037
+ children: /* @__PURE__ */ jsx(Payment, {
21038
+ checkout: state.checkout,
21039
+ onComplete,
21040
+ onRetry,
21041
+ onBack: () => void onBack()
21042
+ })
21043
+ });
21044
+ }
21045
+ /** Mount the active checkout from the same headless registration controller. */
21046
+ function EventRegistrationPayment({ flow }) {
21047
+ return /* @__PURE__ */ jsx(EventPaymentMount, {
21048
+ state: flow.payment.checkout,
21049
+ onComplete: flow.actions.completePayment,
21050
+ onRetry: flow.actions.retryPaymentLoad,
21051
+ onBack: flow.actions.backToBooking
21052
+ });
21053
+ }
21054
+ //#endregion
19521
21055
  //#region src/bookings/index.ts
19522
21056
  /**
19523
21057
  * Booking system exports for SDK consumers
@@ -19561,4 +21095,4 @@ const HeadlessBookingPaymentSelectionStep = (props) => {
19561
21095
  return React$1.createElement(HeadlessBookingPaymentSelectionStep$1, props);
19562
21096
  };
19563
21097
  //#endregion
19564
- export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow };
21098
+ export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, EventRegistrationPayment, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow };