@riverbankcms/sdk 0.142.0 → 0.144.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 (187) hide show
  1. package/dist/{PreviewEditorSidebar-Dk6Dt11f.mjs → PreviewEditorSidebar-CQZNnFiM.mjs} +20 -26
  2. package/dist/{PreviewEditorUI-D6EQTsCA.mjs → PreviewEditorUI-DCNxnmI0.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-CC-EPkyQ.mjs → PreviewQueryProvider-BCYICImX.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-DH1n4ytY.mjs → SdkPreviewModeRuntime-BJolUbr1.mjs} +17 -8
  5. package/dist/{SiteChromeCustomizeContext-DunIzY0K.mjs → SiteChromeCustomizeContext-CKgEpoxi.mjs} +2406 -1988
  6. package/dist/_dts/api/src/billing.d.ts +1 -1
  7. package/dist/_dts/api/src/billingEndpointTypes.d.ts +8 -2
  8. package/dist/_dts/api/src/bookingConfig.d.ts +3 -1
  9. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  10. package/dist/_dts/api/src/index.d.ts +1 -1
  11. package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +4 -4
  12. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  13. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +49 -41
  14. package/dist/_dts/api/src/sdkContracts.d.ts +1 -1
  15. package/dist/_dts/api/src/sdkSettingsContracts.d.ts +8 -0
  16. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +2 -8
  17. package/dist/_dts/api/src/siteSettings.d.ts +17 -7
  18. package/dist/_dts/billing/src/membership/index.d.ts +3 -0
  19. package/dist/_dts/block-form/src/backend/types.d.ts +14 -0
  20. package/dist/_dts/block-form/src/client/index.d.ts +1 -0
  21. package/dist/_dts/block-form/src/context/RepeaterHostActionsContext.d.ts +30 -0
  22. package/dist/_dts/block-form/src/context/index.d.ts +1 -0
  23. package/dist/_dts/block-form/src/index.d.ts +1 -0
  24. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterList.d.ts +4 -1
  25. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterRow.d.ts +5 -2
  26. package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterRowActions.d.ts +11 -1
  27. package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/index.d.ts +1 -0
  28. package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/useEmptyStateFocusAfterRemoval.d.ts +8 -0
  29. package/dist/_dts/block-form/src/widgets/RepeaterField/utils/buildSummary.d.ts +15 -1
  30. package/dist/_dts/block-form/src/widgets/RepeaterField/utils/repeaterRowActionsDomain.d.ts +5 -2
  31. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +34 -10
  32. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +3 -0
  33. package/dist/_dts/blocks/src/system/constants/events.d.ts +10 -0
  34. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +7 -1
  35. package/dist/_dts/blocks/src/system/runtime/api/context.d.ts +3 -3
  36. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +18 -0
  37. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +3 -2
  38. package/dist/_dts/blocks/src/system/runtime/api/readAuthority.d.ts +11 -0
  39. package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +9 -0
  40. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +95 -35
  41. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +7 -13
  42. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +3 -6
  43. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +9 -4
  44. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +0 -1
  45. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.d.ts +1 -3
  46. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +7 -24
  47. package/dist/_dts/blocks/src/system/runtime/nodes/cart.server.d.ts +1 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/checkout.server.d.ts +1 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationBookingLayer.d.ts +2 -1
  50. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +2 -1
  51. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +2 -1
  52. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.d.ts +10 -0
  53. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +0 -2
  54. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +14 -1
  55. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.override.d.ts +2 -1
  56. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +2 -2
  57. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +1 -4
  58. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +12 -0
  59. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -1
  60. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +1 -0
  61. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.d.ts +4 -5
  62. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +9 -11
  63. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +56 -2
  64. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +12 -6
  65. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +23 -0
  66. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +1 -1
  67. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +8 -0
  68. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +4 -5
  69. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +7 -2
  70. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +7 -5
  71. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +5 -6
  72. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +3 -1
  73. package/dist/_dts/blocks/src/system/runtime/nodes/header-control.d.ts +10 -0
  74. package/dist/_dts/blocks/src/system/runtime/nodes/layout.d.ts +6 -21
  75. package/dist/_dts/blocks/src/system/runtime/nodes/product-detail.server.d.ts +1 -0
  76. package/dist/_dts/blocks/src/system/runtime/nodes/product-list.server.d.ts +1 -0
  77. package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +13 -0
  78. package/dist/_dts/blocks/src/system/runtime/nodes/shop.server.d.ts +1 -0
  79. package/dist/_dts/blocks/src/system/runtime/shared/components/ThemedButton.d.ts +58 -0
  80. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -0
  81. package/dist/_dts/blocks/src/system/transforms/registry/chromeLogo.d.ts +23 -0
  82. package/dist/_dts/blocks/src/system/transforms/registry/index.d.ts +2 -1
  83. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +3 -1
  84. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +4 -1
  85. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -4
  86. package/dist/_dts/commerce/src/purchase/eventCheckoutRecoveryWindow.d.ts +8 -0
  87. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -1
  88. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +1 -13
  89. package/dist/_dts/core/src/event-catalogue.d.ts +27 -0
  90. package/dist/_dts/core/src/event-preset-vocabulary.d.ts +7 -0
  91. package/dist/_dts/core/src/index.d.ts +2 -0
  92. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3126 -3077
  93. package/dist/_dts/db/src/schemas/forms.d.ts +286 -2
  94. package/dist/_dts/editor-blocks/src/block-editor/{BlockCardHeader.d.ts → BlockCardFrame.d.ts} +11 -3
  95. package/dist/_dts/logger/src/console.d.ts +3 -0
  96. package/dist/_dts/sdk/src/client/publicEventReadOperations.d.ts +1 -0
  97. package/dist/_dts/sdk/src/client/types.d.ts +3 -0
  98. package/dist/_dts/sdk/src/navigation/index.d.ts +27 -0
  99. package/dist/_dts/sdk/src/public-api/contracts.d.ts +15 -7
  100. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +1 -0
  101. package/dist/_dts/sdk/src/rendering/client.d.ts +1 -0
  102. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +1 -0
  103. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +7 -1
  104. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +2 -0
  105. package/dist/_dts/sdk/src/rendering/islands/enhancers/routeIslandApiConfig.d.ts +3 -2
  106. package/dist/_dts/sdk/src/rendering/islands/enhancers/shopShared.d.ts +2 -0
  107. package/dist/_dts/sdk/src/rendering/overrides.d.ts +1 -0
  108. package/dist/_dts/sdk/src/version.d.ts +1 -1
  109. package/dist/_dts/theme-core/src/buttons/affordanceSuppression.d.ts +1 -1
  110. package/dist/_dts/theme-core/src/buttons/classNames.d.ts +3 -13
  111. package/dist/_dts/theme-core/src/customCss/index.d.ts +1 -1
  112. package/dist/_dts/theme-core/src/customCss/patch.d.ts +0 -5
  113. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  114. package/dist/_dts/theme-core/src/surfaces/index.d.ts +1 -0
  115. package/dist/_dts/theme-core/src/surfaces/logoVariant.d.ts +26 -0
  116. package/dist/_dts/theme-core/src/utils/colorStyles.d.ts +10 -0
  117. package/dist/_dts/ui/src/editor-item-card.d.ts +116 -0
  118. package/dist/_dts/ui/src/index.d.ts +1 -0
  119. package/dist/client/{BookingConsentAgreement-CnJeq3_r.mjs → BookingConsentAgreement-DoAILrkN.mjs} +4 -55
  120. package/dist/client/{DiscountCodeDisclosure-BINEO6J9.mjs → DiscountCodeDisclosure-X528hUTf.mjs} +27 -17
  121. package/dist/client/{EventCombined.client-srxNQ6sZ.mjs → EventCombined.client-DSBVwq5m.mjs} +54 -46
  122. package/dist/client/{EventListing.client-DbyVyGkX.mjs → EventListing.client-DmFAX7Vb.mjs} +3 -4
  123. package/dist/client/{LeafletStaticMap-B-wpijzL.mjs → LeafletStaticMap-BAqXdfhq.mjs} +1 -1
  124. package/dist/client/ThemedButton-BwNFVwi4.mjs +412 -0
  125. package/dist/client/{accordion-B-iUXU7n.mjs → accordion-DRhMdkbd.mjs} +1 -1
  126. package/dist/client/{bookingForm-BXYPke5q.mjs → bookingForm-iJ_nCsNF.mjs} +26 -32
  127. package/dist/client/bookings.mjs +657 -650
  128. package/dist/client/{carousel-Cr4aj63H.mjs → carousel-D8zuffZr.mjs} +2 -2
  129. package/dist/client/{carousel.client-DQTjCVQT.mjs → carousel.client-jahpU9Vz.mjs} +1 -1
  130. package/dist/client/{cart-DibP9WWa.mjs → cart-DeMGJViN.mjs} +3 -3
  131. package/dist/client/{checkout-CrSBVnL8.mjs → checkout-DXc06Km2.mjs} +3 -3
  132. package/dist/client/{checkoutUrls-FL6lRkrt.mjs → checkoutUrls-CW3-78uu.mjs} +1 -1
  133. package/dist/client/client.mjs +2714 -2448
  134. package/dist/client/{colorStyles-3013aRAY.mjs → colorStyles-CuJBiS-1.mjs} +16 -4
  135. package/dist/client/{context-Ces-AgdR.mjs → context-CDLCfDep.mjs} +35 -8
  136. package/dist/client/{dates-BXyNeNhB.mjs → dates-ClFx7Epy.mjs} +2 -2
  137. package/dist/client/{eventCalendar-HwpPeqrH.mjs → eventCalendar-BaGpnOGN.mjs} +39 -50
  138. package/dist/client/{eventCombined-BpFUkuEI.mjs → eventCombined-ywONOx2m.mjs} +5 -4
  139. package/dist/client/{eventDetails-DK_agiWy.mjs → eventDetails-B2LlOTYY.mjs} +4 -4
  140. package/dist/client/{eventListing-DhzHqP1c.mjs → eventListing-CMgxWpqP.mjs} +5 -4
  141. package/dist/client/{eventRegistration-BdQ_Dn2d.mjs → eventRegistration-BarLDNHR.mjs} +549 -592
  142. package/dist/client/{form-B1frcuzy.mjs → form-BjqKaBJ7.mjs} +9 -10
  143. package/dist/client/{headerSection-CT5z460s.mjs → headerSection-CP4XDwz1.mjs} +23 -30
  144. package/dist/client/hooks.mjs +269 -63
  145. package/dist/client/{locationMap-CIQXB9i2.mjs → locationMap-C5gW-d-w.mjs} +9 -10
  146. package/dist/client/{media-DHpfFwd3.mjs → media-BtJ37tzS.mjs} +1 -1
  147. package/dist/client/{newsletterForm-BYNYZSes.mjs → newsletterForm-afXlVSA0.mjs} +8 -9
  148. package/dist/client/{pricing-CbTlAsmt.mjs → pricing-Bl1CAl28.mjs} +1 -1
  149. package/dist/client/{productDetail-CR7Z3yjS.mjs → productDetail-CvQ3jWQe.mjs} +3 -3
  150. package/dist/client/{productList-DXj00vzR.mjs → productList-U874PGO7.mjs} +3 -3
  151. package/dist/client/{propsDecoder-DiLiBdek.mjs → propsDecoder-DPXtCZWP.mjs} +100 -29
  152. package/dist/client/rendering/client.mjs +2397 -2279
  153. package/dist/client/rendering/islands.mjs +19 -19
  154. package/dist/client/rendering.mjs +2742 -2452
  155. package/dist/client/{routeIslandApiConfig-UNsfPcYq.mjs → routeIslandApiConfig-NGYiUWXu.mjs} +8 -1
  156. package/dist/client/{scrollToBlock-CrcbBf0h.mjs → scrollToBlock-0-C3DVhK.mjs} +1 -1
  157. package/dist/client/{shop-DgqiB_1b.mjs → shop-BXjXhM9P.mjs} +45 -58
  158. package/dist/client/{shop-commerce-D_J781in.mjs → shop-commerce-BZ6UlWJ7.mjs} +42 -55
  159. package/dist/client/{shop-commerce-store-PGUbDwqe.mjs → shop-commerce-store-DlSBXb3D.mjs} +1 -1
  160. package/dist/client/{shopShared-C_Bb2zwG.mjs → shopShared-kkEOiLPA.mjs} +6 -5
  161. package/dist/client/{useEventFilters-CM17Xpr1.mjs → useEventFilters-zvnnE1ro.mjs} +66 -355
  162. package/dist/preview-next/before-render.mjs +11 -0
  163. package/dist/preview-next/client/runtime.mjs +4 -4
  164. package/dist/preview-next/editor-chrome.css +8 -0
  165. package/dist/preview-next/keepAlive.mjs +11 -0
  166. package/dist/preview-next/middleware.mjs +11 -0
  167. package/dist/{previewAuthStore-oVttoRDO.mjs → previewAuthStore-JA6-I_sL.mjs} +11 -0
  168. package/dist/{sdk-runtime-DhmuRhIX.mjs → sdk-runtime-DFJlQt3q.mjs} +2 -2
  169. package/dist/{separator-C3hlg9LH.mjs → separator-o8GHb1xh.mjs} +1 -1
  170. package/dist/server/components.mjs +840 -625
  171. package/dist/server/config-validation.mjs +269 -63
  172. package/dist/server/config.mjs +269 -63
  173. package/dist/server/data.mjs +269 -63
  174. package/dist/server/index.mjs +20 -5
  175. package/dist/server/navigation.mjs +28 -1
  176. package/dist/server/next.mjs +14129 -13937
  177. package/dist/server/page-converter.mjs +111 -59
  178. package/dist/server/prebuild.mjs +1 -1
  179. package/dist/server/rendering/server.mjs +844 -624
  180. package/dist/server/rendering.mjs +842 -626
  181. package/dist/server/routing.mjs +306 -69
  182. package/dist/server/server.mjs +278 -68
  183. package/dist/server/theme-bridge.mjs +40 -1
  184. package/dist/styles/index.css +6 -0
  185. package/package.json +1 -1
  186. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +0 -14
  187. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +0 -8
@@ -2382,6 +2382,27 @@ function AltchaWidget({ challengeUrl, onSolutionChange, auto = true, hidelogo =
2382
2382
  function isSpamProtectionEnabled() {
2383
2383
  return process.env.NEXT_PUBLIC_SPAM_PROTECTION_ENABLED === "true";
2384
2384
  }
2385
+ z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
2386
+ kind: z.literal("preview"),
2387
+ token: z.string().min(1)
2388
+ }).strict()]);
2389
+ function createHostedBlockApiConfig(input) {
2390
+ const { baseUrl, siteId, readAuthority, portalToken } = input;
2391
+ return {
2392
+ baseUrl,
2393
+ siteId,
2394
+ readAuthority,
2395
+ auth: readAuthority.kind === "preview" ? {
2396
+ type: "bearer",
2397
+ token: readAuthority.token
2398
+ } : { type: "none" },
2399
+ isPreview: readAuthority.kind === "preview",
2400
+ authOverrides: { portal: portalToken ? {
2401
+ type: "bearer",
2402
+ token: portalToken
2403
+ } : { type: "none" } }
2404
+ };
2405
+ }
2385
2406
  //#endregion
2386
2407
  //#region ../blocks/src/system/runtime/api/deduplication.ts
2387
2408
  /**
@@ -3923,13 +3944,6 @@ function themeButtonVariantClassNames(variant) {
3923
3944
  function themeButtonSizeClassName(size) {
3924
3945
  return `btn-${size}`;
3925
3946
  }
3926
- function themeButtonClassName(spec) {
3927
- return [
3928
- ...themeButtonVariantClassNames(spec.variant),
3929
- themeButtonSizeClassName(spec.size),
3930
- spec.extraClassName
3931
- ].filter(Boolean).join(" ");
3932
- }
3933
3947
  shadeBackgroundEffect({
3934
3948
  id: "darken-background",
3935
3949
  name: "Darken on Hover",
@@ -8335,15 +8349,18 @@ const BOOKINGS = {
8335
8349
  const EVENTS = {
8336
8350
  calendarWindow: {
8337
8351
  path: "/public/sites/{siteId}/events/calendar-window",
8338
- method: "GET"
8352
+ method: "GET",
8353
+ previewRead: true
8339
8354
  },
8340
8355
  list: {
8341
8356
  path: "/public/sites/{siteId}/events",
8342
- method: "GET"
8357
+ method: "GET",
8358
+ previewRead: true
8343
8359
  },
8344
8360
  filters: {
8345
8361
  path: "/public/sites/{siteId}/events/filters",
8346
- method: "GET"
8362
+ method: "GET",
8363
+ previewRead: true
8347
8364
  },
8348
8365
  register: {
8349
8366
  path: "/public/sites/{siteId}/events/register",
@@ -8360,6 +8377,10 @@ const EVENTS = {
8360
8377
  method: "POST",
8361
8378
  authScope: "portal"
8362
8379
  },
8380
+ registrationNextStep: {
8381
+ path: "/public/sites/{siteId}/events/registration-next-step",
8382
+ method: "POST"
8383
+ },
8363
8384
  registrationStatus: {
8364
8385
  path: "/public/sites/{siteId}/events/registration-status",
8365
8386
  method: "GET"
@@ -8377,7 +8398,8 @@ const WHOLE_SERIES = { waitlistClaimResolve: {
8377
8398
  const SHOP = {
8378
8399
  listProducts: {
8379
8400
  path: "/public/sites/{siteId}/products",
8380
- method: "GET"
8401
+ method: "GET",
8402
+ previewRead: true
8381
8403
  },
8382
8404
  checkout: {
8383
8405
  path: "/public/sites/{siteId}/bookings/checkout",
@@ -8771,7 +8793,11 @@ function publicEventsQuery(params) {
8771
8793
  return { ...params ?? {} };
8772
8794
  }
8773
8795
  function createBlockApi(config) {
8774
- const { baseUrl, auth, authOverrides, siteId, isPreview } = config;
8796
+ const { baseUrl, authOverrides, siteId, isPreview, readAuthority } = config;
8797
+ const auth = readAuthority ? readAuthority.kind === "preview" ? {
8798
+ type: "bearer",
8799
+ token: readAuthority.token
8800
+ } : { type: "none" } : config.auth;
8775
8801
  const dedup = createDeduplicationCache({ ttl: 100 });
8776
8802
  const shouldUsePreviewStageForNonPortalRequests = isPreview && auth.type !== "none";
8777
8803
  function isPortalEndpoint(endpoint) {
@@ -8779,17 +8805,25 @@ function createBlockApi(config) {
8779
8805
  }
8780
8806
  function selectAuth(endpoint) {
8781
8807
  if (endpoint.authScope === "portal" && authOverrides?.portal) return authOverrides.portal;
8808
+ if (readAuthority && !endpoint.previewRead) return { type: "none" };
8782
8809
  return auth;
8783
8810
  }
8784
8811
  /**
8785
8812
  * Make an API request
8786
8813
  */
8814
+ function bindReadQuery(endpoint, query) {
8815
+ const queryParams = { ...query };
8816
+ if (readAuthority) {
8817
+ if (!endpoint.previewRead) delete queryParams.stage;
8818
+ else if (readAuthority.kind === "preview" || queryParams.stage != null) queryParams.stage = readAuthority.kind;
8819
+ } else if (shouldUsePreviewStageForNonPortalRequests && !isPortalEndpoint(endpoint) && queryParams.stage == null) queryParams.stage = "preview";
8820
+ return queryParams;
8821
+ }
8787
8822
  async function request(endpoint, options) {
8788
8823
  const { path, body, query, skipDedup = false } = options ?? {};
8789
8824
  let url = `${baseUrl}${path ?? endpoint.path}`;
8790
8825
  const selectedAuth = selectAuth(endpoint);
8791
- const queryParams = { ...query };
8792
- if (shouldUsePreviewStageForNonPortalRequests && !isPortalEndpoint(endpoint) && (queryParams.stage === void 0 || queryParams.stage === null)) queryParams.stage = "preview";
8826
+ const queryParams = bindReadQuery(endpoint, query);
8793
8827
  if (Object.keys(queryParams).length > 0) url = appendQuery(url, queryParams);
8794
8828
  const headers = {
8795
8829
  Accept: "application/json",
@@ -8964,6 +8998,13 @@ function createBlockApi(config) {
8964
8998
  body: data
8965
8999
  });
8966
9000
  },
9001
+ async checkRegistrationNextStep(data) {
9002
+ const path = buildPath(EVENTS.registrationNextStep.path, { siteId: requireSiteId() });
9003
+ return request(EVENTS.registrationNextStep, {
9004
+ path,
9005
+ body: data
9006
+ });
9007
+ },
8967
9008
  async getEventRegistrationStatus(params) {
8968
9009
  const sid = requireSiteId();
8969
9010
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
@@ -12702,6 +12743,114 @@ function useAppointmentCheckoutVerificationWithDeps(config, deps) {
12702
12743
  };
12703
12744
  }
12704
12745
  //#endregion
12746
+ //#region ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
12747
+ function r(e) {
12748
+ var t, f, n = "";
12749
+ if ("string" == typeof e || "number" == typeof e) n += e;
12750
+ else if ("object" == typeof e) if (Array.isArray(e)) {
12751
+ var o = e.length;
12752
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
12753
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
12754
+ return n;
12755
+ }
12756
+ function clsx() {
12757
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
12758
+ return n;
12759
+ }
12760
+ //#endregion
12761
+ //#region ../blocks/src/system/runtime/nodes/spinner.tsx
12762
+ function resolveColorStyle(color) {
12763
+ switch (color) {
12764
+ case void 0: return;
12765
+ case "inherit": return { color: "inherit" };
12766
+ case "foreground": return { color: "rgb(var(--tb-foreground))" };
12767
+ case "text": return { color: "rgb(var(--tb-text))" };
12768
+ default: return;
12769
+ }
12770
+ }
12771
+ function SpinnerNode({ className, size = "md", color, strokeWidth = 3, srLabel, style, ...rest }) {
12772
+ const hasExplicitAriaLabel = typeof rest["aria-label"] === "string" && rest["aria-label"].trim().length > 0;
12773
+ const accessibilityProps = srLabel ? {
12774
+ role: "status",
12775
+ "aria-live": "polite"
12776
+ } : hasExplicitAriaLabel ? {} : { "aria-hidden": true };
12777
+ const trackStroke = color === "inherit" ? "currentColor" : "var(--rb-spinner-track-color)";
12778
+ const trackOpacity = color === "inherit" ? .25 : 1;
12779
+ return /* @__PURE__ */ jsxs("span", {
12780
+ ...accessibilityProps,
12781
+ className: clsx("rb-spinner", size ? `rb-spinner--${size}` : null, color === "inherit" ? "rb-spinner--inherit" : null, className),
12782
+ style: {
12783
+ ...resolveColorStyle(color),
12784
+ ...style ?? {}
12785
+ },
12786
+ ...rest,
12787
+ children: [/* @__PURE__ */ jsxs("svg", {
12788
+ viewBox: "0 0 24 24",
12789
+ fill: "none",
12790
+ "aria-hidden": "true",
12791
+ children: [/* @__PURE__ */ jsx("circle", {
12792
+ cx: "12",
12793
+ cy: "12",
12794
+ r: "10",
12795
+ stroke: trackStroke,
12796
+ strokeWidth,
12797
+ opacity: trackOpacity
12798
+ }), /* @__PURE__ */ jsx("path", {
12799
+ d: "M12 2a10 10 0 0 1 10 10",
12800
+ stroke: "currentColor",
12801
+ strokeWidth,
12802
+ strokeLinecap: "round"
12803
+ })]
12804
+ }), srLabel ? /* @__PURE__ */ jsx("span", {
12805
+ className: "rb-sr-only",
12806
+ children: srLabel
12807
+ }) : null]
12808
+ });
12809
+ }
12810
+ //#endregion
12811
+ //#region ../blocks/src/system/runtime/shared/components/ThemedButton.tsx
12812
+ function themedButtonClasses(variant, size, extraClassName) {
12813
+ return [
12814
+ ...themeButtonVariantClassNames(variant),
12815
+ themeButtonSizeClassName(size),
12816
+ extraClassName
12817
+ ].filter(Boolean).join(" ");
12818
+ }
12819
+ function ThemedButtonLabel(props) {
12820
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
12821
+ props.pending ? /* @__PURE__ */ jsx(SpinnerNode, {
12822
+ size: props.pending.spinnerSize ?? "sm",
12823
+ color: "inherit",
12824
+ className: props.pending.spinnerClassName ?? "rb-mr-2",
12825
+ srLabel: props.pending.srLabel
12826
+ }) : null,
12827
+ props.labelClassName ? /* @__PURE__ */ jsx("span", {
12828
+ className: props.labelClassName,
12829
+ children: props.pending?.label ?? props.label
12830
+ }) : props.pending?.label ?? props.label,
12831
+ props.screenReaderSuffix ? /* @__PURE__ */ jsx("span", {
12832
+ className: "rb-sr-only",
12833
+ children: props.screenReaderSuffix
12834
+ }) : null
12835
+ ] });
12836
+ return props.pending?.contentClassName ? /* @__PURE__ */ jsx("span", {
12837
+ className: props.pending.contentClassName,
12838
+ children: content
12839
+ }) : content;
12840
+ }
12841
+ function ThemedButton({ variant, size, extraClassName, screenReaderSuffix, labelClassName, pending, label, ...buttonProps }) {
12842
+ return /* @__PURE__ */ jsx("button", {
12843
+ ...buttonProps,
12844
+ className: themedButtonClasses(variant, size, extraClassName),
12845
+ children: /* @__PURE__ */ jsx(ThemedButtonLabel, {
12846
+ label,
12847
+ pending,
12848
+ screenReaderSuffix,
12849
+ labelClassName
12850
+ })
12851
+ });
12852
+ }
12853
+ //#endregion
12705
12854
  //#region ../blocks/src/system/runtime/shared/components/FeedbackMessage.tsx
12706
12855
  function joinClasses(...parts) {
12707
12856
  return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
@@ -12914,71 +13063,6 @@ const TimeSlotSelector = ({ value, onChange, slots, isLoading, timezone, require
12914
13063
  });
12915
13064
  };
12916
13065
  //#endregion
12917
- //#region ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
12918
- function r(e) {
12919
- var t, f, n = "";
12920
- if ("string" == typeof e || "number" == typeof e) n += e;
12921
- else if ("object" == typeof e) if (Array.isArray(e)) {
12922
- var o = e.length;
12923
- for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
12924
- } else for (f in e) e[f] && (n && (n += " "), n += f);
12925
- return n;
12926
- }
12927
- function clsx() {
12928
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
12929
- return n;
12930
- }
12931
- //#endregion
12932
- //#region ../blocks/src/system/runtime/nodes/spinner.tsx
12933
- function resolveColorStyle(color) {
12934
- switch (color) {
12935
- case void 0: return;
12936
- case "inherit": return { color: "inherit" };
12937
- case "foreground": return { color: "rgb(var(--tb-foreground))" };
12938
- case "text": return { color: "rgb(var(--tb-text))" };
12939
- default: return;
12940
- }
12941
- }
12942
- function SpinnerNode({ className, size = "md", color, strokeWidth = 3, srLabel, style, ...rest }) {
12943
- const hasExplicitAriaLabel = typeof rest["aria-label"] === "string" && rest["aria-label"].trim().length > 0;
12944
- const accessibilityProps = srLabel ? {
12945
- role: "status",
12946
- "aria-live": "polite"
12947
- } : hasExplicitAriaLabel ? {} : { "aria-hidden": true };
12948
- const trackStroke = color === "inherit" ? "currentColor" : "var(--rb-spinner-track-color)";
12949
- const trackOpacity = color === "inherit" ? .25 : 1;
12950
- return /* @__PURE__ */ jsxs("span", {
12951
- ...accessibilityProps,
12952
- className: clsx("rb-spinner", size ? `rb-spinner--${size}` : null, color === "inherit" ? "rb-spinner--inherit" : null, className),
12953
- style: {
12954
- ...resolveColorStyle(color),
12955
- ...style ?? {}
12956
- },
12957
- ...rest,
12958
- children: [/* @__PURE__ */ jsxs("svg", {
12959
- viewBox: "0 0 24 24",
12960
- fill: "none",
12961
- "aria-hidden": "true",
12962
- children: [/* @__PURE__ */ jsx("circle", {
12963
- cx: "12",
12964
- cy: "12",
12965
- r: "10",
12966
- stroke: trackStroke,
12967
- strokeWidth,
12968
- opacity: trackOpacity
12969
- }), /* @__PURE__ */ jsx("path", {
12970
- d: "M12 2a10 10 0 0 1 10 10",
12971
- stroke: "currentColor",
12972
- strokeWidth,
12973
- strokeLinecap: "round"
12974
- })]
12975
- }), srLabel ? /* @__PURE__ */ jsx("span", {
12976
- className: "rb-sr-only",
12977
- children: srLabel
12978
- }) : null]
12979
- });
12980
- }
12981
- //#endregion
12982
13066
  //#region ../blocks/src/system/runtime/shared/components/StepIndicator.tsx
12983
13067
  /**
12984
13068
  * Shared step indicator component for registration wizards.
@@ -13063,14 +13147,8 @@ const themeFormClasses = {
13063
13147
  label: "form-label",
13064
13148
  row: "rb-flex rb-flex-col rb-gap-2 rb-sm-flex-row",
13065
13149
  input: "form-input",
13066
- apply: themeButtonClassName({
13067
- variant: "secondary",
13068
- size: "sm"
13069
- }),
13070
- remove: themeButtonClassName({
13071
- variant: "secondary",
13072
- size: "sm"
13073
- }),
13150
+ apply: "",
13151
+ remove: "",
13074
13152
  hint: "rb-caption status-muted",
13075
13153
  feedback: "rb-caption"
13076
13154
  };
@@ -13078,6 +13156,22 @@ function getDiscountCodeDisclosureClasses(surface) {
13078
13156
  if (surface === "theme-form") return themeFormClasses;
13079
13157
  return BLOCK_DISCOUNT_CODE_DISCLOSURE_CLASSES[surface];
13080
13158
  }
13159
+ function DiscountActionButton(props) {
13160
+ return props.surface === "theme-form" ? /* @__PURE__ */ jsx(ThemedButton, {
13161
+ type: "button",
13162
+ variant: "secondary",
13163
+ size: "sm",
13164
+ label: props.label,
13165
+ onClick: props.onClick,
13166
+ disabled: props.disabled
13167
+ }) : /* @__PURE__ */ jsx("button", {
13168
+ type: "button",
13169
+ className: props.className,
13170
+ onClick: props.onClick,
13171
+ disabled: props.disabled,
13172
+ children: props.label
13173
+ });
13174
+ }
13081
13175
  function DiscountCodeDisclosure({ surface, isOpen, code, onOpen, onChange, onRemove, onApply, id, toggleLabel = "Have a discount code?", label = "Discount code", placeholder = "Enter code", applyLabel = "Apply", removeLabel = "Remove", hint = "Applied at checkout.", feedback = null, isApplying = false, applyDisabled = false, disabled = false }) {
13082
13176
  const generatedId = useId();
13083
13177
  const inputId = id ?? `discount-code-${generatedId}`;
@@ -13119,19 +13213,19 @@ function DiscountCodeDisclosure({ surface, isOpen, code, onOpen, onChange, onRem
13119
13213
  autoComplete: "off",
13120
13214
  disabled: disabled || isApplying
13121
13215
  }),
13122
- onApply ? /* @__PURE__ */ jsx("button", {
13123
- type: "button",
13216
+ onApply ? /* @__PURE__ */ jsx(DiscountActionButton, {
13217
+ surface,
13124
13218
  className: classes.apply,
13219
+ label: isApplying ? "Applying..." : applyLabel,
13125
13220
  onClick: onApply,
13126
- disabled: disabled || isApplying || applyDisabled,
13127
- children: isApplying ? "Applying..." : applyLabel
13221
+ disabled: disabled || isApplying || applyDisabled
13128
13222
  }) : null,
13129
- /* @__PURE__ */ jsx("button", {
13130
- type: "button",
13223
+ /* @__PURE__ */ jsx(DiscountActionButton, {
13224
+ surface,
13131
13225
  className: classes.remove,
13226
+ label: removeLabel,
13132
13227
  onClick: onRemove,
13133
- disabled: disabled || isApplying,
13134
- children: removeLabel
13228
+ disabled: disabled || isApplying
13135
13229
  })
13136
13230
  ]
13137
13231
  }),
@@ -13979,30 +14073,25 @@ function HeadlessBookingDefaultForm({ booking, onSubmit }) {
13979
14073
  }),
13980
14074
  /* @__PURE__ */ jsxs("div", {
13981
14075
  className: "rb-wizard-actions",
13982
- children: [!isFirstStep ? /* @__PURE__ */ jsx("button", {
14076
+ children: [!isFirstStep ? /* @__PURE__ */ jsx(ThemedButton, {
13983
14077
  type: "button",
13984
14078
  onClick: booking.actions.back,
13985
- className: themeButtonClassName({
13986
- variant: "outline",
13987
- size: "md"
13988
- }),
13989
- children: "Back"
13990
- }) : null, /* @__PURE__ */ jsx("button", {
14079
+ variant: "outline",
14080
+ size: "md",
14081
+ label: "Back"
14082
+ }) : null, /* @__PURE__ */ jsx(ThemedButton, {
13991
14083
  type: "button",
13992
14084
  onClick: () => {
13993
14085
  handlePrimaryAction();
13994
14086
  },
13995
14087
  disabled: isSubmitting,
13996
- className: themeButtonClassName({
13997
- variant: "primary",
13998
- size: "md"
13999
- }),
14000
- children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerNode, {
14001
- size: "sm",
14002
- color: "inherit",
14003
- className: "rb-mr-2",
14088
+ variant: "primary",
14089
+ size: "md",
14090
+ label: isLastStep ? "Complete" : "Continue",
14091
+ pending: isSubmitting ? {
14092
+ label: "Submitting...",
14004
14093
  srLabel: "Submitting"
14005
- }), "Submitting..."] }) : isLastStep ? "Complete" : "Continue"
14094
+ } : void 0
14006
14095
  })]
14007
14096
  }),
14008
14097
  /* @__PURE__ */ jsx(DefaultBookingDiscount, { booking }),
@@ -14630,14 +14719,12 @@ function DefaultBookingFeedback({ booking }) {
14630
14719
  children: [/* @__PURE__ */ jsx("p", {
14631
14720
  className: "ab-text",
14632
14721
  children: booking.feedback.message
14633
- }), /* @__PURE__ */ jsx("button", {
14722
+ }), /* @__PURE__ */ jsx(ThemedButton, {
14634
14723
  type: "button",
14635
- className: themeButtonClassName({
14636
- variant: "secondary",
14637
- size: "sm"
14638
- }),
14639
- onClick: booking.actions.clearFeedback,
14640
- children: "Dismiss"
14724
+ variant: "secondary",
14725
+ size: "sm",
14726
+ label: "Dismiss",
14727
+ onClick: booking.actions.clearFeedback
14641
14728
  })]
14642
14729
  });
14643
14730
  }
@@ -14911,188 +14998,15 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
14911
14998
  });
14912
14999
  };
14913
15000
  //#endregion
14914
- //#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
14915
- /**
14916
- * Compute remaining spots for an event from `availableSpots` with a fallback
14917
- * to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
14918
- * for uncapped events so call sites can render no capacity indicator at all.
14919
- *
14920
- * The single source of truth for capacity math across event cards, agenda
14921
- * rows, and timetable cells — keep wording variations in the call sites.
14922
- */
14923
- function getEventAvailability(event) {
14924
- if (event.capacity == null) return {
14925
- available: null,
14926
- isFull: false
14927
- };
14928
- const available = event.availableSpots ?? event.capacity - event.registeredCount;
14929
- if (available <= 0) return {
14930
- available: 0,
14931
- isFull: true
14932
- };
14933
- return {
14934
- available,
14935
- isFull: false
14936
- };
14937
- }
14938
- /**
14939
- * Pick the capacity row a booking decision should read: the selected
14940
- * attendance mode's availability when the visitor has chosen one and the
14941
- * event publishes it, otherwise the event-level aggregate.
14942
- *
14943
- * The mode row is used wholesale. A mode with `capacity: null` on a capped
14944
- * event is uncapped *by design*: the registration write path applies the
14945
- * same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
14946
- * back to the event's `availableSpots` here would block bookings the server
14947
- * accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
14948
- */
14949
- function selectEventCapacitySource(event, attendanceMode) {
14950
- if (!attendanceMode) return event;
14951
- return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
14952
- }
14953
- /**
14954
- * Whether the visitor's next step is the waitlist: the source is full *and*
14955
- * a waitlist is open. The one place this is decided — cards, rows, the
14956
- * wizard's steps and its action bar all route through here so they agree,
14957
- * including for producers that omit `availableSpots` and rely on the
14958
- * `capacity - registeredCount` fallback.
14959
- */
14960
- function canJoinEventWaitlist(event, options) {
14961
- const source = selectEventCapacitySource(event, options?.attendanceMode);
14962
- return getEventAvailability(source).isFull && source.waitlistEnabled === true;
14963
- }
14964
- //#endregion
14965
- //#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
14966
- function isRecord$1(value) {
14967
- return typeof value === "object" && value !== null && !Array.isArray(value);
14968
- }
14969
- function isRuntimeEventDestination(value) {
14970
- if (!isRecord$1(value) || typeof value.kind !== "string") return false;
14971
- if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
14972
- return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
14973
- }
14974
- function resolveRuntimeEventDestination(event) {
14975
- if (isRuntimeEventDestination(event.destination)) return event.destination;
14976
- return {
14977
- kind: "native",
14978
- mode: event.eventDestinationMode === "system-managed" ? "system-managed" : "cms-managed",
14979
- path: typeof event.path === "string" ? event.path : ""
14980
- };
14981
- }
14982
- //#endregion
14983
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
14984
- /** Recovery may select held places; checkout still owns admission and payment validation. */
14985
- function checkoutRecoveryOptionAvailability(availability) {
14986
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
14987
- kind: "available",
14988
- remainingPlaces: null
14989
- };
14990
- return availability;
14991
- }
14992
- /**
14993
- * A form-only projection for the explicit existing-checkout path. It permits
14994
- * collecting the original selection without claiming a new place is available.
14995
- * The public checkout service identifies the customer and remains the admission
14996
- * authority; no reservation/customer data is exposed through this projection.
14997
- */
14998
- function getCheckoutRecoveryFormEligibility(eligibility) {
14999
- if (!eligibility || eligibility.registration.kind !== "none" && eligibility.registration.kind !== "pending_payment" || eligibility.availability.kind === "unavailable" && eligibility.availability.reason !== "full" && eligibility.availability.reason !== "selectionRequired") return eligibility;
15000
- const amountCents = eligibility.price ?? 0;
15001
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
15002
- ...eligibility,
15003
- registration: { kind: "none" },
15004
- ticketTypes: eligibility.ticketTypes.map((option) => ({
15005
- ...option,
15006
- availability: checkoutRecoveryOptionAvailability(option.availability)
15007
- }))
15008
- } : eligibility;
15009
- const currency = eligibility.currency;
15010
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
15011
- switch (option.kind) {
15012
- case "upfront": return {
15013
- kind: "payInFull",
15014
- amountCents,
15015
- currency
15016
- };
15017
- case "deferred_manual": return {
15018
- kind: "deferredManual",
15019
- amountCents,
15020
- currency
15021
- };
15022
- case "instalment_plan": return {
15023
- kind: "instalmentPlan",
15024
- amountCents,
15025
- currency
15026
- };
15027
- case "flexible_balance": return {
15028
- kind: "flexibleBalance",
15029
- amountCents,
15030
- currency
15031
- };
15032
- }
15033
- });
15034
- return {
15035
- ...eligibility,
15036
- registration: { kind: "none" },
15037
- availability: {
15038
- kind: "available",
15039
- remainingPlaces: null,
15040
- waitlistEnabled: eligibility.waitlistEnabled
15041
- },
15042
- eligible: paymentOptions.length > 0,
15043
- isFull: false,
15044
- canJoinWaitlist: false,
15045
- isFree: false,
15046
- requiresPayment: true,
15047
- canPayDirectly: paymentOptions.length > 0,
15048
- paymentOptions,
15049
- eligiblePasses: [],
15050
- eligibleMemberships: [],
15051
- ticketTypes: eligibility.ticketTypes.map((option) => ({
15052
- ...option,
15053
- availability: checkoutRecoveryOptionAvailability(option.availability)
15054
- }))
15055
- };
15056
- }
15057
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
15058
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
15059
- }
15060
- //#endregion
15061
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
15062
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
15063
- function useCheckoutRecovery(event, setStep) {
15064
- const [recoveryEventId, setRecoveryEventId] = useState(null);
15065
- return {
15066
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
15067
- startCheckoutRecovery: useCallback(() => {
15068
- if (!event) return;
15069
- setRecoveryEventId(event.selectionId);
15070
- setStep("select-tickets");
15071
- }, [event, setStep])
15072
- };
15073
- }
15074
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
15075
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
15076
- const registrationKind = eligibility?.registration.kind;
15077
- useEffect(() => {
15078
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
15079
- }, [
15080
- registrationKind,
15081
- step,
15082
- checkoutRecovery,
15083
- startCheckoutRecovery
15084
- ]);
15085
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
15086
- }
15087
- //#endregion
15088
15001
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
15089
15002
  function resolveRegistrationRecoveryAction(step, action) {
15090
15003
  if (step === "payment-failed") return "payment-options";
15091
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
15004
+ if (step === "payment-status") return "none";
15005
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
15092
15006
  return action;
15093
15007
  }
15094
15008
  function canRecoverToWaitlist(eligibility) {
15095
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
15009
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
15096
15010
  }
15097
15011
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
15098
15012
  return enabled || step === "error" && action === "places";
@@ -15109,19 +15023,19 @@ function resetRegistrationAfterExpiry(input) {
15109
15023
  input.setErrorMessage("");
15110
15024
  input.setPendingRegistrationReference(null);
15111
15025
  }
15112
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
15026
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
15113
15027
  function recoverRegistrationError(action, handlers) {
15114
15028
  switch (action) {
15115
15029
  case "none": return;
15116
15030
  case "portal":
15117
- case "payment-status":
15118
15031
  window.location.assign("/portal");
15119
15032
  return;
15120
15033
  case "event":
15121
15034
  window.location.assign(window.location.pathname);
15122
15035
  return;
15123
15036
  case "retry":
15124
- window.location.reload();
15037
+ handlers.clearError();
15038
+ handlers.setStep("select-payment");
15125
15039
  return;
15126
15040
  case "details":
15127
15041
  handlers.clearError();
@@ -15159,16 +15073,46 @@ function validateFormData(formData, requiresConsent = false) {
15159
15073
  return errors;
15160
15074
  }
15161
15075
  //#endregion
15162
- //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
15163
- function getPortalSubjectEmail(profile) {
15164
- return profile?.email ?? null;
15076
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
15077
+ /** Ticket selection requests a quote; only the server admits a booking. */
15078
+ function canRequestTicketOption(availability) {
15079
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
15165
15080
  }
15166
- function transformRegistrationOptionsResponse(response) {
15167
- const canJoinWaitlist = response.availability.kind === "waitlist";
15168
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
15169
- const eligiblePasses = response.entitlements.passes.map((pass) => ({
15170
- id: pass.customerPassId,
15171
- passName: pass.passName,
15081
+ function normalizeTicketSelectionLines(lines) {
15082
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
15083
+ for (const line of lines) {
15084
+ const quantity = Math.floor(line.quantity);
15085
+ if (quantity <= 0) continue;
15086
+ const key = line.pricingOptionId ?? null;
15087
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
15088
+ }
15089
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
15090
+ pricingOptionId,
15091
+ quantity
15092
+ }));
15093
+ }
15094
+ function getTicketSelectionTotal(lines) {
15095
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
15096
+ }
15097
+ function getSingleSelectedPricingOptionId(lines) {
15098
+ const normalized = normalizeTicketSelectionLines(lines);
15099
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
15100
+ }
15101
+ function hasValidPricingOptionSelection(input) {
15102
+ if (!input.selectionRequired) return true;
15103
+ if (input.lines.length === 0) return false;
15104
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
15105
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
15106
+ }
15107
+ //#endregion
15108
+ //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
15109
+ function getPortalSubjectEmail(profile) {
15110
+ return profile?.email ?? null;
15111
+ }
15112
+ function transformRegistrationOptionsResponse(response) {
15113
+ const eligiblePasses = response.entitlements.passes.map((pass) => ({
15114
+ id: pass.customerPassId,
15115
+ passName: pass.passName,
15172
15116
  creditsRemaining: pass.creditsRemaining
15173
15117
  }));
15174
15118
  const eligibleMemberships = response.entitlements.memberships.map((membership) => ({
@@ -15178,7 +15122,6 @@ function transformRegistrationOptionsResponse(response) {
15178
15122
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
15179
15123
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
15180
15124
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
15181
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
15182
15125
  return {
15183
15126
  availability: response.availability,
15184
15127
  registration: response.registration,
@@ -15193,7 +15136,6 @@ function transformRegistrationOptionsResponse(response) {
15193
15136
  },
15194
15137
  transactions: []
15195
15138
  } : null,
15196
- eligible: response.registration.kind === "none" && registrationAvailable,
15197
15139
  requiresPayment: monetaryPaymentAvailable,
15198
15140
  pricingStrategy: response.pricing.strategy,
15199
15141
  paymentTerms: response.pricing.paymentTerms,
@@ -15208,16 +15150,12 @@ function transformRegistrationOptionsResponse(response) {
15208
15150
  currency: response.pricing.currency
15209
15151
  })),
15210
15152
  ticketTypes: response.pricing.options,
15211
- isFull,
15212
- waitlistEnabled: response.availability.waitlistEnabled,
15213
- canJoinWaitlist,
15214
15153
  price: response.pricing.subtotalCents,
15215
15154
  currency: response.pricing.currency,
15216
15155
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
15217
15156
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
15218
15157
  eligiblePasses,
15219
15158
  eligibleMemberships,
15220
- canPayDirectly: monetaryPaymentAvailable,
15221
15159
  eventAcceptsPasses,
15222
15160
  eventAcceptsMemberships,
15223
15161
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -15234,8 +15172,8 @@ function getVisibleTicketTypes(input) {
15234
15172
  })) : [];
15235
15173
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
15236
15174
  }
15237
- function getImplicitSingleAvailableTicketType(ticketTypes) {
15238
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
15175
+ function getImplicitSingleTicketType(ticketTypes) {
15176
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
15239
15177
  }
15240
15178
  function findSelectedTicketType(input) {
15241
15179
  if (!input.selectedPricingOptionId) return null;
@@ -15246,32 +15184,74 @@ function findSelectedTicketType(input) {
15246
15184
  }).find((ticketType) => ticketType.pricingOptionId === input.selectedPricingOptionId) ?? null;
15247
15185
  }
15248
15186
  //#endregion
15249
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
15250
- function normalizeTicketSelectionLines(lines) {
15251
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
15252
- for (const line of lines) {
15253
- const quantity = Math.floor(line.quantity);
15254
- if (quantity <= 0) continue;
15255
- const key = line.pricingOptionId ?? null;
15256
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
15257
- }
15258
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
15259
- pricingOptionId,
15260
- quantity
15187
+ //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
15188
+ /** Public requests share subject identity without copying the run's display sessions. */
15189
+ function toRegistrationRequestSubject(subject, attendanceMode) {
15190
+ return subject.kind === "occurrence" ? {
15191
+ kind: "occurrence",
15192
+ occurrenceId: subject.occurrenceId,
15193
+ attendanceMode: attendanceMode ?? void 0
15194
+ } : {
15195
+ kind: "wholeSeries",
15196
+ eventSeriesId: subject.eventSeriesId,
15197
+ attendanceMode: attendanceMode ?? void 0
15198
+ };
15199
+ }
15200
+ function eventMatchesOccurrenceId(event, occurrenceId) {
15201
+ return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
15202
+ }
15203
+ function findEventByOccurrenceId(events, occurrenceId) {
15204
+ return events.find((event) => eventMatchesOccurrenceId(event, occurrenceId)) ?? null;
15205
+ }
15206
+ function findPreSelectedEvent(input) {
15207
+ const occurrenceContext = input.occurrenceContext;
15208
+ if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
15209
+ const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
15210
+ startsAt: occurrenceContext.startsAt,
15211
+ timeZone: occurrenceContext.timeZone
15261
15212
  }));
15213
+ return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
15214
+ startsAt: event.startsAt,
15215
+ timeZone: event.timeZone
15216
+ })) === contextDate) ?? null;
15262
15217
  }
15263
- function getTicketSelectionTotal(lines) {
15264
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
15218
+ function resolveRegistrationTarget(input) {
15219
+ const subject = input.occurrenceContext ? {
15220
+ kind: "occurrence",
15221
+ occurrenceId: input.occurrenceContext.id
15222
+ } : input.selectedEvent?.registrationSubject ?? null;
15223
+ if (!subject) return null;
15224
+ return {
15225
+ subject,
15226
+ selectedEventId: input.selectedEvent?.selectionId ?? null
15227
+ };
15265
15228
  }
15266
- function getSingleSelectedPricingOptionId(lines) {
15267
- const normalized = normalizeTicketSelectionLines(lines);
15268
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
15229
+ function resolveEventRequiresPayment(input) {
15230
+ if (input.eligibility) return input.eligibility.requiresPayment;
15231
+ if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
15232
+ if (!input.event) return false;
15233
+ return publicEventPricingType(input.event.pricing) === "paid";
15269
15234
  }
15270
- function hasValidPricingOptionSelection(input) {
15271
- if (!input.selectionRequired) return true;
15272
- if (input.lines.length === 0) return false;
15273
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
15274
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
15235
+ function resolveDiscountContext(input) {
15236
+ const selection = input.paymentSelection.method ? input.paymentSelection : null;
15237
+ if (!input.event) return null;
15238
+ if (selection?.method === "pass_bundle" && selection.bundlePassId) return {
15239
+ type: "pass",
15240
+ passId: selection.bundlePassId
15241
+ };
15242
+ if (selection?.method === "membership_bundle" && selection.bundleMembershipId) return {
15243
+ type: "membership",
15244
+ membershipId: selection.bundleMembershipId
15245
+ };
15246
+ if (!input.eventRequiresPayment) return null;
15247
+ if (input.ticketsCount <= 0) return null;
15248
+ if (selection?.method && selection.method !== "stripe") return null;
15249
+ return {
15250
+ type: "event",
15251
+ eventSeriesId: input.event.seriesId,
15252
+ eventCategoryId: input.event.eventCategory?.id ?? null,
15253
+ ticketsCount: input.ticketsCount
15254
+ };
15275
15255
  }
15276
15256
  //#endregion
15277
15257
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
@@ -15391,17 +15371,6 @@ function usePortalAuthWithDeps(deps) {
15391
15371
  logout
15392
15372
  };
15393
15373
  }
15394
- function toRegistrationOptionsSubject(subject, attendanceMode) {
15395
- return subject.kind === "occurrence" ? {
15396
- kind: "occurrence",
15397
- occurrenceId: subject.occurrenceId,
15398
- attendanceMode: attendanceMode ?? void 0
15399
- } : {
15400
- kind: "wholeSeries",
15401
- eventSeriesId: subject.eventSeriesId,
15402
- attendanceMode: attendanceMode ?? void 0
15403
- };
15404
- }
15405
15374
  function useEligibility(params) {
15406
15375
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
15407
15376
  }
@@ -15442,7 +15411,7 @@ function useEligibilityWithDeps(params, deps) {
15442
15411
  requestIdRef.current = requestId;
15443
15412
  dispatch({ type: "loading-started" });
15444
15413
  try {
15445
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
15414
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
15446
15415
  const result = await api.getRegistrationOptions({
15447
15416
  subject,
15448
15417
  selections: ticketSelections.map((selection) => ({
@@ -15679,9 +15648,9 @@ const eventRegistrationErrors = {
15679
15648
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
15680
15649
  action: "none"
15681
15650
  },
15682
- paymentUncertain: {
15683
- message: "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.",
15684
- action: "payment-status"
15651
+ paymentInvestigationRequired: {
15652
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
15653
+ action: "none"
15685
15654
  },
15686
15655
  paymentProviderUnavailable: {
15687
15656
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -16179,7 +16148,30 @@ function checkoutReturnCommand(params) {
16179
16148
  };
16180
16149
  return null;
16181
16150
  }
16182
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
16151
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
16152
+ const { pending, params } = context;
16153
+ if (outcome.kind === "resolved") {
16154
+ deps.clearReturnParams();
16155
+ options.setPendingRegistrationReference(outcome.reference);
16156
+ options.setStep("verifying-payment");
16157
+ return "settled";
16158
+ }
16159
+ if (outcome.kind === "abandoned") {
16160
+ deps.clearReturnParams();
16161
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16162
+ options.setStep("select-payment");
16163
+ return "settled";
16164
+ }
16165
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
16166
+ deps.clearReturnParams();
16167
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16168
+ options.setStep("select-payment");
16169
+ return "settled";
16170
+ }
16171
+ 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.");
16172
+ return outcome.kind === "notFound" ? "settled" : "retryable";
16173
+ }
16174
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
16183
16175
  deps.cleanupStaleRegistrations();
16184
16176
  const params = deps.readReturnParams();
16185
16177
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -16193,34 +16185,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
16193
16185
  }
16194
16186
  const { checkoutAttemptId } = command;
16195
16187
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
16196
- checkoutAttemptIdRef.current = checkoutAttemptId;
16188
+ returnContextRef.current = { checkoutAttemptId };
16197
16189
  if (pending) restorePendingPresentation(options, pending);
16198
16190
  options.setStep("verifying-payment");
16199
16191
  try {
16200
16192
  const outcome = await options.api.resolveEventCheckoutReturn(command);
16201
- switch (outcome.kind) {
16202
- case "resolved":
16203
- deps.clearReturnParams();
16204
- options.setPendingRegistrationReference(outcome.reference);
16205
- options.setStep("verifying-payment");
16206
- return "settled";
16207
- case "abandoned":
16208
- deps.clearReturnParams();
16209
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16210
- options.setStep("select-payment");
16211
- return "settled";
16212
- case "notFound":
16213
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
16214
- deps.clearReturnParams();
16215
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
16216
- options.setStep("select-payment");
16217
- return "settled";
16218
- }
16219
- 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.");
16220
- return "settled";
16221
- case "reconciliationRequired": break;
16222
- }
16223
- 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.");
16193
+ return handleCheckoutReturnOutcome(options, deps, {
16194
+ pending,
16195
+ params
16196
+ }, outcome);
16224
16197
  } catch {
16225
16198
  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.");
16226
16199
  }
@@ -16229,9 +16202,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
16229
16202
  function useEventRegistrationStripeReturn(options) {
16230
16203
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
16231
16204
  }
16205
+ function completeVerifiedRegistration(options, deps, returnContext) {
16206
+ const siteId = options.api.config.siteId;
16207
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
16208
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
16209
+ options.setRegistrationResult({ status: "confirmed" });
16210
+ options.setStep("success");
16211
+ }
16232
16212
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
16233
16213
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
16234
- const checkoutAttemptIdRef = useRef(null);
16214
+ const returnContextRef = useRef(null);
16235
16215
  const lookupInFlightRef = useRef(false);
16236
16216
  const [lookupState, setLookupState] = useState("settled");
16237
16217
  const resolveReturn = useCallback(async () => {
@@ -16239,7 +16219,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
16239
16219
  lookupInFlightRef.current = true;
16240
16220
  setLookupState("loading");
16241
16221
  try {
16242
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
16222
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
16243
16223
  } finally {
16244
16224
  lookupInFlightRef.current = false;
16245
16225
  }
@@ -16262,13 +16242,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
16262
16242
  resolveReturn();
16263
16243
  }, []);
16264
16244
  useEffect(() => {
16265
- if (verification.status === "completed") {
16266
- const siteId = api.config.siteId;
16267
- const checkoutAttemptId = checkoutAttemptIdRef.current;
16268
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
16269
- setRegistrationResult({ status: "confirmed" });
16270
- setStep("success");
16271
- } else if (verification.status === "failed") {
16245
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
16246
+ else if (verification.status === "failed") {
16272
16247
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
16273
16248
  setStep("payment-failed");
16274
16249
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -16297,7 +16272,10 @@ function registrationErrorPresentation(error) {
16297
16272
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
16298
16273
  if (reason) return eventRegistrationErrors[reason];
16299
16274
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
16300
- return eventRegistrationErrors.paymentUncertain;
16275
+ return {
16276
+ message: "Something went wrong. Please try again.",
16277
+ action: "retry"
16278
+ };
16301
16279
  }
16302
16280
  //#endregion
16303
16281
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
@@ -16326,26 +16304,6 @@ function useEventRegistrationSubmit(options) {
16326
16304
  * and the balance left, which the block's copy cannot. Every other method keeps
16327
16305
  * whatever success message the site configured.
16328
16306
  */
16329
- function toRegistrationResult(result) {
16330
- if (result.alreadyRegistered) {
16331
- const waitlisted = result.status === "waitlist";
16332
- return {
16333
- status: result.status,
16334
- variant: "info",
16335
- title: waitlisted ? "Already waitlisted" : "Already registered",
16336
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
16337
- };
16338
- }
16339
- if (result.status === "waitlist") return {
16340
- status: "waitlist",
16341
- title: "Added to waitlist",
16342
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
16343
- };
16344
- return {
16345
- status: result.status,
16346
- message: result.paymentMethod === "pass" ? result.message : void 0
16347
- };
16348
- }
16349
16307
  function useEventRegistrationSubmitWithDeps(options, deps) {
16350
16308
  /**
16351
16309
  * The command identity for the submission currently in progress.
@@ -16359,7 +16317,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
16359
16317
  * Identical retries retain the command after a lost response. Changed form
16360
16318
  * details get a new command so the server applies the new booking intent.
16361
16319
  */
16362
- const commandRef = useRef(null);
16320
+ const { commandRef } = options;
16363
16321
  const inFlightRef = useRef(null);
16364
16322
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
16365
16323
  const target = options.registrationTarget;
@@ -16372,19 +16330,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
16372
16330
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
16373
16331
  try {
16374
16332
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
16375
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
16376
- commandRef.current = null;
16377
- return await submitWholeSeriesCheckout(options, deps, {
16333
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
16334
+ const intentKey = registrationRequestIntentKey(request);
16335
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
16336
+ prepared = {
16378
16337
  ...prepared,
16379
- subject: prepared.subject
16380
- }, submitOptions);
16338
+ registrationCommandId: deps.createClientCommandId()
16339
+ };
16340
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
16381
16341
  }
16382
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
16383
- const intentKey = registrationRequestIntentKey(request);
16384
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
16385
- ...prepared,
16386
- registrationCommandId: deps.createClientCommandId()
16387
- };
16388
16342
  commandRef.current = {
16389
16343
  id: prepared.registrationCommandId,
16390
16344
  intentKey
@@ -16393,8 +16347,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
16393
16347
  ...request,
16394
16348
  registrationCommandId: prepared.registrationCommandId
16395
16349
  });
16396
- commandRef.current = null;
16397
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
16350
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
16398
16351
  } catch (error) {
16399
16352
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
16400
16353
  const { message, action } = registrationErrorPresentation(error);
@@ -16418,9 +16371,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
16418
16371
  return pending;
16419
16372
  };
16420
16373
  }
16421
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
16422
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
16423
- options.setRegistrationResult(toRegistrationResult(result));
16374
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
16375
+ switch (result.kind) {
16376
+ case "paymentStatusRequired":
16377
+ options.setPaymentStatusRecovery({
16378
+ kind: "ready",
16379
+ subject: result.subject
16380
+ });
16381
+ options.setStep("payment-status");
16382
+ return {
16383
+ ok: true,
16384
+ outcome: { kind: "payment_status" }
16385
+ };
16386
+ case "checkoutRequired":
16387
+ options.setPendingRegistrationReference(result.reference);
16388
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
16389
+ options.setStep("redirecting");
16390
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
16391
+ case "waitlisted":
16392
+ options.setRegistrationResult({
16393
+ status: "waitlist",
16394
+ title: "Added to waitlist",
16395
+ message: result.waitlist.message
16396
+ });
16397
+ break;
16398
+ case "bookingComplete":
16399
+ case "paymentDeferred":
16400
+ options.setPendingRegistrationReference(result.reference);
16401
+ options.setRegistrationResult({
16402
+ status: "confirmed",
16403
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
16404
+ });
16405
+ break;
16406
+ }
16407
+ options.commandRef.current = null;
16424
16408
  options.setStep("success");
16425
16409
  return {
16426
16410
  ok: true,
@@ -16451,15 +16435,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
16451
16435
  email: guest.email?.trim().toLowerCase() || void 0,
16452
16436
  phone: guest.phone?.trim() || void 0
16453
16437
  })) : void 0,
16454
- subject: target.subject.kind === "occurrence" ? {
16455
- kind: "occurrence",
16456
- occurrenceId: target.subject.occurrenceId,
16457
- attendanceMode: options.selectedAttendanceMode ?? void 0
16458
- } : {
16459
- kind: "wholeSeries",
16460
- eventSeriesId: target.subject.eventSeriesId,
16461
- attendanceMode: options.selectedAttendanceMode ?? void 0
16462
- }
16438
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
16463
16439
  };
16464
16440
  }
16465
16441
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -16483,85 +16459,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
16483
16459
  if (method === "free") return { method };
16484
16460
  throw new Error("Choose an available payment option.");
16485
16461
  }
16486
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
16487
- options.setStep("redirecting");
16488
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
16489
- const checkoutAttemptId = deps.createClientCommandId();
16490
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
16491
- const result = await options.api.createEventCheckout({
16492
- subject: prepared.subject,
16493
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
16494
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
16495
- email: options.formData.email.trim().toLowerCase(),
16496
- name: options.formData.name.trim(),
16497
- phone: options.formData.phone.trim() || void 0,
16498
- formData: options.formData,
16499
- consentAccepted: options.formData.consentAccepted,
16500
- altchaSolution: options.altchaSolution,
16501
- guests: prepared.guestsPayload,
16502
- claimToken: options.claimToken ?? void 0,
16503
- waitlistEntryId: options.waitlistEntryId ?? void 0,
16504
- discountCode: options.discountCode.trim() || void 0,
16505
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
16506
- checkoutAttemptId,
16507
- ...urls
16508
- });
16509
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
16510
- if ("waitlistEntryId" in result) {
16511
- options.setRegistrationResult({
16512
- status: "waitlist",
16513
- variant: result.alreadyRegistered ? "info" : void 0,
16514
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
16515
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
16516
- });
16517
- options.setStep("success");
16518
- return {
16519
- ok: true,
16520
- outcome: { kind: "completed" }
16521
- };
16522
- }
16523
- if (result.bypassed) return completeBypassedCheckout(options);
16524
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
16525
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
16526
- scope: "wholeSeries",
16527
- registrationId: result.registrationId
16528
- });
16529
- return redirectToCheckout(result.checkoutUrl, submitOptions);
16530
- }
16531
- function needsOccurrenceCheckout(result, method) {
16532
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
16533
- "stripe",
16534
- "pass_bundle",
16535
- "membership_bundle"
16536
- ].includes(method);
16537
- }
16538
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
16539
- const reference = {
16540
- scope: "occurrence",
16541
- attendeeId: registration.attendeeId
16542
- };
16543
- options.setPendingRegistrationReference(reference);
16544
- options.setStep("redirecting");
16545
- const checkoutAttemptId = deps.createClientCommandId();
16546
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
16547
- const result = await options.api.createEventCheckout({
16548
- subject: {
16549
- kind: "occurrence",
16550
- attendeeId: registration.attendeeId
16551
- },
16552
- registrationCommandId: prepared.registrationCommandId,
16553
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
16554
- productId: prepared.bundleProductId,
16555
- discountCode: options.discountCode.trim() || void 0,
16556
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
16557
- ...urls
16558
- });
16559
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
16560
- if (result.bypassed) return completeBypassedCheckout(options);
16561
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
16562
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
16563
- return redirectToCheckout(result.checkoutUrl, submitOptions);
16564
- }
16565
16462
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
16566
16463
  const siteId = options.api.config.siteId;
16567
16464
  if (!siteId) return;
@@ -16574,14 +16471,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
16574
16471
  paymentSelection: prepared.selectionSnapshot
16575
16472
  });
16576
16473
  }
16577
- function completeBypassedCheckout(options) {
16578
- options.setRegistrationResult({ status: "confirmed" });
16579
- options.setStep("success");
16580
- return {
16581
- ok: true,
16582
- outcome: { kind: "completed" }
16583
- };
16584
- }
16585
16474
  function redirectToCheckout(checkoutUrl, submitOptions) {
16586
16475
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
16587
16476
  return {
@@ -16593,12 +16482,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
16593
16482
  };
16594
16483
  }
16595
16484
  function registrationRequestIntentKey(request) {
16596
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
16597
- return JSON.stringify(intent);
16485
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
16486
+ return JSON.stringify({
16487
+ ...intent,
16488
+ checkout: checkout ? {
16489
+ discountCode: checkout.discountCode,
16490
+ collectionOptionKind: checkout.collectionOptionKind
16491
+ } : void 0
16492
+ });
16598
16493
  }
16599
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
16494
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
16600
16495
  return {
16601
16496
  registrationCommandId: prepared.registrationCommandId,
16497
+ checkout: {
16498
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
16499
+ discountCode: options.discountCode.trim() || void 0,
16500
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
16501
+ },
16602
16502
  subject: prepared.subject,
16603
16503
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
16604
16504
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -16618,64 +16518,6 @@ function buildOccurrenceRegistrationRequest(options, prepared, method, passId, m
16618
16518
  };
16619
16519
  }
16620
16520
  //#endregion
16621
- //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
16622
- function eventMatchesOccurrenceId(event, occurrenceId) {
16623
- return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
16624
- }
16625
- function findEventByOccurrenceId(events, occurrenceId) {
16626
- return events.find((event) => eventMatchesOccurrenceId(event, occurrenceId)) ?? null;
16627
- }
16628
- function findPreSelectedEvent(input) {
16629
- const occurrenceContext = input.occurrenceContext;
16630
- if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
16631
- const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
16632
- startsAt: occurrenceContext.startsAt,
16633
- timeZone: occurrenceContext.timeZone
16634
- }));
16635
- return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
16636
- startsAt: event.startsAt,
16637
- timeZone: event.timeZone
16638
- })) === contextDate) ?? null;
16639
- }
16640
- function resolveRegistrationTarget(input) {
16641
- const subject = input.occurrenceContext ? {
16642
- kind: "occurrence",
16643
- occurrenceId: input.occurrenceContext.id
16644
- } : input.selectedEvent?.registrationSubject ?? null;
16645
- if (!subject) return null;
16646
- return {
16647
- subject,
16648
- selectedEventId: input.selectedEvent?.selectionId ?? null
16649
- };
16650
- }
16651
- function resolveEventRequiresPayment(input) {
16652
- if (input.eligibility) return input.eligibility.requiresPayment;
16653
- if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
16654
- if (!input.event) return false;
16655
- return publicEventPricingType(input.event.pricing) === "paid";
16656
- }
16657
- function resolveDiscountContext(input) {
16658
- const selection = input.paymentSelection.method ? input.paymentSelection : null;
16659
- if (!input.event) return null;
16660
- if (selection?.method === "pass_bundle" && selection.bundlePassId) return {
16661
- type: "pass",
16662
- passId: selection.bundlePassId
16663
- };
16664
- if (selection?.method === "membership_bundle" && selection.bundleMembershipId) return {
16665
- type: "membership",
16666
- membershipId: selection.bundleMembershipId
16667
- };
16668
- if (!input.eventRequiresPayment) return null;
16669
- if (input.ticketsCount <= 0) return null;
16670
- if (selection?.method && selection.method !== "stripe") return null;
16671
- return {
16672
- type: "event",
16673
- eventSeriesId: input.event.seriesId,
16674
- eventCategoryId: input.event.eventCategory?.id ?? null,
16675
- ticketsCount: input.ticketsCount
16676
- };
16677
- }
16678
- //#endregion
16679
16521
  //#region ../blocks/src/system/runtime/nodes/event-registration/useSettledCommerceView.ts
16680
16522
  function buildCandidate(input) {
16681
16523
  if (!input.eligibilityIsSettled || !input.eligibility || !input.currentEvent) return null;
@@ -16896,7 +16738,7 @@ function computeAutoSelection(input) {
16896
16738
  return { method: null };
16897
16739
  }
16898
16740
  function computeDirectPaymentSelection(eligibility) {
16899
- if (!eligibility?.canPayDirectly) return { method: null };
16741
+ if (!eligibility?.requiresPayment) return { method: null };
16900
16742
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
16901
16743
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
16902
16744
  return collectionOptionKind ? {
@@ -16910,7 +16752,7 @@ function isSelectionValid(input) {
16910
16752
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
16911
16753
  switch (selection.method) {
16912
16754
  case "free": return eligibility.isFree;
16913
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
16755
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
16914
16756
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
16915
16757
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
16916
16758
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -16929,7 +16771,7 @@ function normalizeRegistrationFlowState(state) {
16929
16771
  ticketsCount: state.ticketsCount,
16930
16772
  passOptOut: nextPassOptOut
16931
16773
  });
16932
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
16774
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
16933
16775
  selection: state.paymentSelection,
16934
16776
  isAuthenticated: state.isAuthenticated,
16935
16777
  eligibility: state.eligibility,
@@ -16995,6 +16837,24 @@ function requiresPaymentStep(params) {
16995
16837
  if (!params.eventRequiresPayment) return false;
16996
16838
  return !isEntitlementSelection(params.paymentSelection);
16997
16839
  }
16840
+ //#endregion
16841
+ //#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
16842
+ function isRecord$1(value) {
16843
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16844
+ }
16845
+ function isRuntimeEventDestination(value) {
16846
+ if (!isRecord$1(value) || typeof value.kind !== "string") return false;
16847
+ if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
16848
+ return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
16849
+ }
16850
+ function resolveRuntimeEventDestination(event) {
16851
+ if (isRuntimeEventDestination(event.destination)) return event.destination;
16852
+ return {
16853
+ kind: "native",
16854
+ mode: event.eventDestinationMode === "system-managed" ? "system-managed" : "cms-managed",
16855
+ path: typeof event.path === "string" ? event.path : ""
16856
+ };
16857
+ }
16998
16858
  const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
16999
16859
  kind: z.literal("unsupported"),
17000
16860
  reason: z.enum([
@@ -17088,6 +16948,12 @@ function resolveEventRegistrationScopedEvents(events, context) {
17088
16948
  //#endregion
17089
16949
  //#region ../blocks/src/system/runtime/nodes/event-registration/event-registration.headless.override.ts
17090
16950
  function createEventRegistrationBlockApiConfig(input) {
16951
+ if (input.readAuthority) return createHostedBlockApiConfig({
16952
+ baseUrl: input.apiBaseUrl,
16953
+ siteId: input.siteId,
16954
+ readAuthority: input.readAuthority,
16955
+ portalToken: input.portalToken
16956
+ });
17091
16957
  return {
17092
16958
  baseUrl: input.apiBaseUrl,
17093
16959
  auth: input.previewToken ? {
@@ -17124,6 +16990,7 @@ function getEventRegistrationOverrideInput(props) {
17124
16990
  apiBaseUrl: props.apiBaseUrl,
17125
16991
  portalToken: props.portalToken ?? null,
17126
16992
  previewToken: props.previewToken ?? null,
16993
+ readAuthority: props.readAuthority,
17127
16994
  events,
17128
16995
  ...props.stage ? { stage: props.stage } : {},
17129
16996
  ...props.occurrenceContext ? { occurrenceContext: props.occurrenceContext } : {},
@@ -17237,7 +17104,7 @@ function resolveEventRegistrationSubmitPlan(input) {
17237
17104
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
17238
17105
  if (input.canJoinWaitlist) return {
17239
17106
  ok: true,
17240
- args: withOptionalSelection({ method: "free" }, selection)
17107
+ args: { method: "free" }
17241
17108
  };
17242
17109
  switch (input.paymentSelection.method) {
17243
17110
  case "pass": return input.paymentSelection.passId ? {
@@ -17288,6 +17155,10 @@ function resolveHeadlessEventRegistrationStatus(wizard) {
17288
17155
  case "redirecting": return { tag: "redirecting" };
17289
17156
  case "verifying-payment": return { tag: "verifying-payment" };
17290
17157
  case "verifying-timeout": return { tag: "verifying-timeout" };
17158
+ case "payment-status": return wizard.paymentStatusRecovery ? {
17159
+ tag: "payment-status",
17160
+ state: wizard.paymentStatusRecovery
17161
+ } : { tag: "ready" };
17291
17162
  case "payment-failed": return {
17292
17163
  tag: "payment-failed",
17293
17164
  message: wizard.errorMessage
@@ -17334,6 +17205,10 @@ function resolveHeadlessEventRegistrationView(wizard) {
17334
17205
  kind: "verifying",
17335
17206
  message: "Your booking is not confirmed yet. Please don’t make another booking while we check. You can check your payment status again in a moment."
17336
17207
  };
17208
+ case "payment-status": return wizard.paymentStatusRecovery ? {
17209
+ kind: "payment-status",
17210
+ state: wizard.paymentStatusRecovery
17211
+ } : { kind: "form" };
17337
17212
  case "select-event":
17338
17213
  case "select-tickets":
17339
17214
  case "enter-details":
@@ -17600,20 +17475,124 @@ function useWaitlistClaimRestoration(input) {
17600
17475
  }
17601
17476
  //#endregion
17602
17477
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
17478
+ function isSelectionSoldOut(availability) {
17479
+ return availability?.kind === "unavailable" && availability.reason === "full";
17480
+ }
17603
17481
  function resolveRegistrationAvailabilityBlocker(input) {
17604
17482
  if (input.hasWaitlistClaim) return null;
17605
17483
  if (input.eligibilityError) return input.eligibilityError;
17606
17484
  if (!input.eligibility) return "Registration is not available for this event.";
17485
+ if (input.eligibility.registration.kind === "pending_payment") return null;
17486
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
17607
17487
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
17608
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
17488
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
17609
17489
  return null;
17610
17490
  }
17611
17491
  function resolvePricingSelectionBlocker(input) {
17612
17492
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
17613
17493
  return input.slidingScaleSelectionMessage;
17614
17494
  }
17615
- function isSoldOutWithoutWaitlist(input) {
17616
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
17495
+ //#endregion
17496
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
17497
+ function isCheckableRecovery(state) {
17498
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
17499
+ }
17500
+ function assistanceRequired(recovery) {
17501
+ return {
17502
+ kind: "assistanceRequired",
17503
+ subject: recovery.subject
17504
+ };
17505
+ }
17506
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
17507
+ if (outcome.kind === "resolved") {
17508
+ setters.setPendingRegistrationReference(outcome.reference);
17509
+ setters.setRegistrationResult({ status: "confirmed" });
17510
+ setRecovery(null);
17511
+ setters.setStep("success");
17512
+ return;
17513
+ }
17514
+ switch (outcome.kind) {
17515
+ case "paymentProcessing":
17516
+ setRecovery({
17517
+ ...recovery,
17518
+ kind: "processing"
17519
+ });
17520
+ return;
17521
+ case "paymentAvailable":
17522
+ setRecovery({
17523
+ ...recovery,
17524
+ kind: "paymentAvailable",
17525
+ checkoutUrl: outcome.checkoutUrl
17526
+ });
17527
+ return;
17528
+ case "paymentCheckUnavailable":
17529
+ setRecovery({
17530
+ ...recovery,
17531
+ kind: "temporarilyUnavailable"
17532
+ });
17533
+ return;
17534
+ case "paymentRetryAvailable":
17535
+ setRecovery({
17536
+ ...recovery,
17537
+ kind: "retryAvailable"
17538
+ });
17539
+ return;
17540
+ case "abandoned":
17541
+ case "notFound":
17542
+ case "reconciliationRequired":
17543
+ case "paymentAssistanceRequired":
17544
+ setRecovery(assistanceRequired(recovery));
17545
+ return;
17546
+ }
17547
+ }
17548
+ function usePaymentStatusRecovery(options) {
17549
+ const [recovery, setRecovery] = useState(null);
17550
+ const checkRef = useRef(null);
17551
+ return {
17552
+ recovery,
17553
+ showRecovery: useCallback((next) => setRecovery(next), []),
17554
+ check: useCallback(() => {
17555
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
17556
+ const pending = (async () => {
17557
+ setRecovery({
17558
+ ...recovery,
17559
+ kind: "checking"
17560
+ });
17561
+ try {
17562
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
17563
+ kind: "checkStatus",
17564
+ subject: recovery.subject
17565
+ }), recovery, options, setRecovery);
17566
+ } catch {
17567
+ setRecovery({
17568
+ ...recovery,
17569
+ kind: "temporarilyUnavailable"
17570
+ });
17571
+ }
17572
+ })();
17573
+ checkRef.current = pending;
17574
+ pending.finally(() => {
17575
+ if (checkRef.current === pending) checkRef.current = null;
17576
+ });
17577
+ }, [options, recovery]),
17578
+ continuePayment: useCallback(() => {
17579
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
17580
+ }, [recovery]),
17581
+ returnToPayment: useCallback(() => {
17582
+ if (recovery?.kind !== "retryAvailable") return;
17583
+ options.beginNewSubmission();
17584
+ setRecovery(null);
17585
+ options.setOptionsRefreshKey((value) => value + 1);
17586
+ options.setStep("select-payment");
17587
+ }, [options, recovery]),
17588
+ returnToBooking: useCallback(() => {
17589
+ if (recovery?.kind !== "assistanceRequired") return;
17590
+ options.beginNewSubmission();
17591
+ setRecovery(null);
17592
+ options.setOptionsRefreshKey((value) => value + 1);
17593
+ options.setStep("select-tickets");
17594
+ }, [options, recovery])
17595
+ };
17617
17596
  }
17618
17597
  //#endregion
17619
17598
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
@@ -17671,6 +17650,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17671
17650
  const [errorAction, setErrorAction] = useState("retry");
17672
17651
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
17673
17652
  const [altchaSolution, setAltchaSolution] = useState(null);
17653
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
17674
17654
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
17675
17655
  const waitlistClaim = deps.useWaitlistClaim();
17676
17656
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -17697,28 +17677,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17697
17677
  }), [options.occurrenceContext, selectedEvent]);
17698
17678
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
17699
17679
  const currentEvent = selectedEvent ?? preSelectedEvent;
17680
+ const commandRef = useRef(null);
17700
17681
  const setStep = useCallback((nextStep) => {
17701
17682
  dispatchFlow({
17702
17683
  type: "set-step",
17703
17684
  step: nextStep
17704
17685
  });
17705
17686
  }, []);
17706
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
17707
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
17708
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
17709
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
17687
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
17688
+ api,
17689
+ beginNewSubmission: () => {
17690
+ commandRef.current = null;
17691
+ },
17692
+ setPendingRegistrationReference,
17693
+ setRegistrationResult,
17694
+ setOptionsRefreshKey,
17695
+ setStep
17696
+ });
17697
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
17710
17698
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
17711
17699
  event: currentEvent,
17712
17700
  eligibility: null,
17713
17701
  selectedAttendanceMode
17714
- }).map((option) => checkoutRecovery ? {
17715
- ...option,
17716
- availability: checkoutRecoveryOptionAvailability(option.availability)
17717
- } : option), [
17718
- currentEvent,
17719
- selectedAttendanceMode,
17720
- checkoutRecovery
17721
- ]);
17702
+ }), [currentEvent, selectedAttendanceMode]);
17722
17703
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
17723
17704
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
17724
17705
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -17756,7 +17737,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17756
17737
  isAuthenticated: portalAuthState === "authenticated",
17757
17738
  occurrenceId: registrationOccurrenceId
17758
17739
  });
17759
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
17740
+ const eligibility = eligibilityResult.eligibility;
17760
17741
  const eligibilityLoading = eligibilityResult.isLoading;
17761
17742
  const eligibilityError = eligibilityResult.error;
17762
17743
  const portalCreditState = eligibilityResult.creditState;
@@ -17868,14 +17849,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17868
17849
  event: currentEvent,
17869
17850
  eligibility,
17870
17851
  selectedAttendanceMode
17871
- }).map((option) => checkoutRecovery ? {
17872
- ...option,
17873
- availability: checkoutRecoveryOptionAvailability(option.availability)
17874
- } : option), [
17852
+ }), [
17875
17853
  currentEvent,
17876
17854
  selectedAttendanceMode,
17877
- eligibility,
17878
- checkoutRecovery
17855
+ eligibility
17879
17856
  ]);
17880
17857
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
17881
17858
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -17899,12 +17876,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17899
17876
  const event = currentEvent;
17900
17877
  if (!usesTieredPricing(event)) return false;
17901
17878
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
17902
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
17903
- }, [
17904
- currentEvent,
17905
- selectedAttendanceMode,
17906
- checkoutRecovery
17907
- ]);
17879
+ return true;
17880
+ }, [currentEvent, selectedAttendanceMode]);
17908
17881
  const hasValidTicketSelection = hasValidPricingOptionSelection({
17909
17882
  selectionRequired: ticketTypeSelectionRequired,
17910
17883
  lines: normalizedSelectedTicketLines,
@@ -17915,8 +17888,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17915
17888
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
17916
17889
  return;
17917
17890
  }
17918
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
17919
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
17891
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
17892
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
17920
17893
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
17921
17894
  setSelectedTicketLines([{
17922
17895
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -17983,6 +17956,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17983
17956
  selectedEventSlidingScale,
17984
17957
  selectedSlidingAmount
17985
17958
  ]);
17959
+ const checkDetailsNextStep = async () => {
17960
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
17961
+ setCheckingNextStep(true);
17962
+ try {
17963
+ return await api.checkRegistrationNextStep({
17964
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
17965
+ selections: ticketSelections,
17966
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
17967
+ email: formData.email,
17968
+ altchaSolution
17969
+ });
17970
+ } catch {
17971
+ return {
17972
+ kind: "unavailable",
17973
+ message: "We could not check availability. Please try again."
17974
+ };
17975
+ } finally {
17976
+ setCheckingNextStep(false);
17977
+ }
17978
+ };
17986
17979
  const handleDetailsComplete = async () => {
17987
17980
  const blockDetailsCompletion = (message) => {
17988
17981
  setErrorAction("places");
@@ -18014,11 +18007,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18014
18007
  message: "Check the highlighted fields and try again."
18015
18008
  };
18016
18009
  }
18017
- if (isSoldOutWithoutWaitlist({
18018
- hasWaitlistClaim: waitlistClaim.claim !== null,
18019
- eligibility
18020
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
18021
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
18010
+ const next = await checkDetailsNextStep();
18011
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
18012
+ const canJoinWaitlist = next.kind === "waitlist";
18013
+ if (!canJoinWaitlist && requiresPaymentStep({
18022
18014
  eventRequiresPayment,
18023
18015
  paymentSelection
18024
18016
  })) {
@@ -18031,7 +18023,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18031
18023
  const submitPlan = resolveEventRegistrationSubmitPlan({
18032
18024
  paymentSelection,
18033
18025
  eventRequiresPayment,
18034
- canJoinWaitlist: eligibility?.canJoinWaitlist
18026
+ canJoinWaitlist
18035
18027
  });
18036
18028
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
18037
18029
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -18049,7 +18041,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18049
18041
  const submitPlan = resolveEventRegistrationSubmitPlan({
18050
18042
  paymentSelection,
18051
18043
  eventRequiresPayment,
18052
- canJoinWaitlist: eligibility?.canJoinWaitlist
18044
+ canJoinWaitlist: false
18053
18045
  });
18054
18046
  if (!submitPlan.ok) {
18055
18047
  setErrorMessage(submitPlan.message);
@@ -18081,6 +18073,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18081
18073
  const selectionMethod = paymentSelection.method;
18082
18074
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
18083
18075
  const handleSubmit = deps.useEventRegistrationSubmit({
18076
+ commandRef,
18084
18077
  setErrorAction,
18085
18078
  api,
18086
18079
  registrationTarget,
@@ -18097,7 +18090,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18097
18090
  setPendingRegistrationReference,
18098
18091
  setStep,
18099
18092
  setRegistrationResult: (result) => setRegistrationResult(result),
18100
- setErrorMessage
18093
+ setErrorMessage,
18094
+ setPaymentStatusRecovery
18101
18095
  });
18102
18096
  const handleEventSelect = (event) => {
18103
18097
  setSelectedEvent(event);
@@ -18156,8 +18150,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18156
18150
  scopedEvents,
18157
18151
  preSelectedEvent,
18158
18152
  hasPreSelectedContext,
18159
- checkoutRecovery,
18160
- startCheckoutRecovery,
18161
18153
  step,
18162
18154
  setStep,
18163
18155
  selectedEvent,
@@ -18211,7 +18203,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18211
18203
  waitlistClaim,
18212
18204
  eligibility,
18213
18205
  registrationOptionsState: eligibilityResult.state,
18214
- eligibilityLoading,
18206
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
18215
18207
  eligibilityError,
18216
18208
  existingRegistration: existingRegistrationResult.registration,
18217
18209
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -18231,6 +18223,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18231
18223
  discountContext,
18232
18224
  shouldShowDiscountToggle,
18233
18225
  verification,
18226
+ paymentStatusRecovery,
18227
+ handleCheckPaymentStatus,
18228
+ handleContinueExistingPayment,
18229
+ handleReturnToPayment,
18230
+ handleReturnToBooking,
18234
18231
  handleDetailsComplete,
18235
18232
  handlePaymentSelect,
18236
18233
  handleUseCardInsteadOfPass,
@@ -18283,7 +18280,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18283
18280
  selection: wizard.paymentSelection
18284
18281
  }),
18285
18282
  eventRequiresPayment: wizard.eventRequiresPayment,
18286
- canJoinWaitlist: wizard.eligibility?.canJoinWaitlist
18283
+ canJoinWaitlist: wizard.step !== "select-payment" && wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment"
18287
18284
  });
18288
18285
  if (!plan.ok) return {
18289
18286
  ok: false,
@@ -18328,6 +18325,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18328
18325
  case "redirecting":
18329
18326
  case "verifying-payment":
18330
18327
  case "verifying-timeout":
18328
+ case "payment-status":
18331
18329
  case "payment-failed": return {
18332
18330
  ok: false,
18333
18331
  reason: "blocked",
@@ -18335,27 +18333,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18335
18333
  };
18336
18334
  }
18337
18335
  }, [submit, wizard]);
18338
- const back = useCallback(() => {
18339
- switch (wizard.step) {
18340
- case "enter-details":
18341
- wizard.setStep("select-tickets");
18342
- return;
18343
- case "select-payment":
18344
- wizard.setStep("enter-details");
18345
- return;
18346
- case "select-tickets":
18347
- if (!wizard.hasPreSelectedContext) wizard.setStep("select-event");
18348
- return;
18349
- case "select-event":
18350
- case "error":
18351
- case "success":
18352
- case "submitting":
18353
- case "redirecting":
18354
- case "verifying-payment":
18355
- case "verifying-timeout":
18356
- case "payment-failed": return;
18357
- }
18358
- }, [wizard]);
18336
+ const back = useEventRegistrationBack(wizard);
18359
18337
  const updateAttendee = useCallback((values) => {
18360
18338
  wizard.setFormData(values);
18361
18339
  }, [wizard]);
@@ -18442,7 +18420,8 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18442
18420
  terminal: {
18443
18421
  result: wizard.registrationResult,
18444
18422
  errorMessage: wizard.errorMessage,
18445
- verification: wizard.verification
18423
+ verification: wizard.verification,
18424
+ paymentStatusRecovery: wizard.paymentStatusRecovery
18446
18425
  },
18447
18426
  actions: {
18448
18427
  selectEvent: wizard.handleEventSelect,
@@ -18466,12 +18445,40 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18466
18445
  next,
18467
18446
  back,
18468
18447
  submit,
18469
- retry: wizard.handleRetry
18448
+ retry: wizard.handleRetry,
18449
+ checkPaymentStatus: wizard.handleCheckPaymentStatus,
18450
+ continueExistingPayment: wizard.handleContinueExistingPayment,
18451
+ returnToPayment: wizard.handleReturnToPayment,
18452
+ returnToBooking: wizard.handleReturnToBooking
18470
18453
  }
18471
18454
  },
18472
18455
  wizard
18473
18456
  };
18474
18457
  }
18458
+ function useEventRegistrationBack(wizard) {
18459
+ return useCallback(() => {
18460
+ switch (wizard.step) {
18461
+ case "enter-details":
18462
+ wizard.setStep("select-tickets");
18463
+ return;
18464
+ case "select-payment":
18465
+ wizard.setStep("enter-details");
18466
+ return;
18467
+ case "select-tickets":
18468
+ if (!wizard.hasPreSelectedContext) wizard.setStep("select-event");
18469
+ return;
18470
+ case "select-event":
18471
+ case "error":
18472
+ case "success":
18473
+ case "submitting":
18474
+ case "redirecting":
18475
+ case "verifying-payment":
18476
+ case "verifying-timeout":
18477
+ case "payment-status":
18478
+ case "payment-failed": return;
18479
+ }
18480
+ }, [wizard]);
18481
+ }
18475
18482
  function useEventRegistrationWizardControllerWithDeps(options, deps) {
18476
18483
  const maxTicketsNum = normalizeEventRegistrationMaxTickets(options.maxTickets);
18477
18484
  return { wizard: deps.useEventRegistrationWizard({
@@ -18527,7 +18534,7 @@ function resolvePaymentModel(wizard, directPaymentOptions) {
18527
18534
  }
18528
18535
  function resolveHeadlessDirectPaymentOptions(wizard) {
18529
18536
  const eligibility = wizard.eligibility;
18530
- if (!eligibility?.eligible || !eligibility.canPayDirectly || !eligibility.price) return [];
18537
+ if (!eligibility?.requiresPayment || !eligibility.price) return [];
18531
18538
  const event = wizard.selectedEvent ?? wizard.preSelectedEvent;
18532
18539
  return buildEventRegistrationPaymentOptionsViewModel({
18533
18540
  eventTitle: event?.title ?? "Event",