@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
@@ -1,22 +1,23 @@
1
1
  "use client";
2
- import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator$1, o as resolveBookingPaymentDueNowCents, r as SpinnerNode, s as formatPrice, t as BookingConsentAgreement } from "./BookingConsentAgreement-CnJeq3_r.mjs";
3
- import { C as resolveRegistrationTarget, E as getWizardStepsForContext, Gt as formatBookingDate, Pt as assertNever, S as resolveEventRequiresPayment, T as getStepNumber, Yt as formatBookingTime, _ as toRegistrationEvents, b as findPreSelectedEvent, dn as publicEventPricingType, dt as themeButtonClassName, fn as formatCurrencyAmount, g as getRegistrationStartAt, h as buildEventRegistrationDisplayFromScopedEvents, k as resolveEventRegistrationScopedEvents, ln as publicEventPricingOptions, ot as groupPublicEventsByRun, pn as parseCurrencyCode, qt as formatBookingDateTime, rn as toScheduledBookingDateTime, sn as publicEventPricingCurrency, t as defineIslandPropsDecoder, tn as toBookingTimeZone, un as publicEventPricingStrategy, v as toWholeSeriesRegistrationEvents, w as WIZARD_STEPS, x as resolveDiscountContext, y as findEventByOccurrenceId } from "./propsDecoder-DiLiBdek.mjs";
4
- import { a as canJoinEventWaitlistOnAnyMode, c as formatTicketTypeRemaining, f as getRemainingPlaces, h as selectMostOpenCapacitySource, i as canJoinEventWaitlist, m as selectEventCapacitySource, o as formatEventRemainingPlaces, p as isEventFull, r as formatEventPriceDisplay, s as formatRemainingPlaces, u as getEventAvailability } from "./pricing-CbTlAsmt.mjs";
5
- import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-Ces-AgdR.mjs";
2
+ import { a as resolveBookingPaymentDueNowCents, i as buildBookingPaymentSelectionViewModel, n as StepIndicator$1, o as formatPrice, r as usePolling, t as BookingConsentAgreement } from "./BookingConsentAgreement-DoAILrkN.mjs";
3
+ import { A as resolveEventRegistrationScopedEvents, C as resolveRegistrationTarget, D as getWizardStepsForContext, E as getStepNumber, Qt as formatBookingDateTime, S as resolveEventRequiresPayment, T as WIZARD_STEPS, Xt as formatBookingDate, _ as toRegistrationEvents, _n as formatCurrencyAmount, b as findPreSelectedEvent, cn as toScheduledBookingDateTime, en as formatBookingTime, fn as publicEventPricingCurrency, g as getRegistrationStartAt, gn as publicEventPricingType, h as buildEventRegistrationDisplayFromScopedEvents, hn as publicEventPricingStrategy, mn as publicEventPricingOptions, on as toBookingTimeZone, t as defineIslandPropsDecoder, ut as groupPublicEventsByRun, v as toWholeSeriesRegistrationEvents, vn as parseCurrencyCode, w as toRegistrationRequestSubject, x as resolveDiscountContext, y as findEventByOccurrenceId, zt as assertNever } from "./propsDecoder-DPXtCZWP.mjs";
4
+ import { a as canJoinEventWaitlistOnAnyMode, c as formatTicketTypeRemaining, f as getRemainingPlaces, h as selectMostOpenCapacitySource, i as canJoinEventWaitlist, m as selectEventCapacitySource, o as formatEventRemainingPlaces, p as isEventFull, r as formatEventPriceDisplay, s as formatRemainingPlaces, u as getEventAvailability } from "./pricing-Bl1CAl28.mjs";
5
+ import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-CDLCfDep.mjs";
6
6
  import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
7
- import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-CrcbBf0h.mjs";
8
- import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-BINEO6J9.mjs";
7
+ import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-0-C3DVhK.mjs";
8
+ import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-X528hUTf.mjs";
9
+ import { i as SpinnerNode, t as ThemedButton } from "./ThemedButton-BwNFVwi4.mjs";
9
10
  import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
10
11
  import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
11
- import { t as buildCheckoutReturnUrls } from "./checkoutUrls-FL6lRkrt.mjs";
12
+ import { t as buildCheckoutReturnUrls } from "./checkoutUrls-CW3-78uu.mjs";
12
13
  import { t as createBodyThemePortalRoot } from "./themePortalRoot-AGs4cE7t.mjs";
13
14
  import { n as consumeSearchParams } from "./urlParams-D71VXFGx.mjs";
14
15
  import { t as CrossIcon } from "./CrossIcon-Dn1KRKW5.mjs";
15
16
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
16
- import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-UNsfPcYq.mjs";
17
+ import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-NGYiUWXu.mjs";
17
18
  import { t as createLucideIcon } from "./createLucideIcon-PaLVMov4.mjs";
18
19
  import { t as ModalShell } from "./ModalShell-CqkBvBIC.mjs";
19
- import React, { useCallback, useEffect, useId, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
20
+ import React, { useCallback, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
20
21
  import { z } from "zod";
21
22
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
22
23
  import { createPortal } from "react-dom";
@@ -276,7 +277,7 @@ function resolveEventRegistrationDirectPaymentSelection(input) {
276
277
  //#endregion
277
278
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
278
279
  function hasBlockingExistingRegistration(input) {
279
- return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind !== "none";
280
+ return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
280
281
  }
281
282
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
282
283
  return {
@@ -328,7 +329,7 @@ function computeAutoSelection(input) {
328
329
  return { method: null };
329
330
  }
330
331
  function computeDirectPaymentSelection(eligibility) {
331
- if (!eligibility?.canPayDirectly) return { method: null };
332
+ if (!eligibility?.requiresPayment) return { method: null };
332
333
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
333
334
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
334
335
  return collectionOptionKind ? {
@@ -342,7 +343,7 @@ function isSelectionValid(input) {
342
343
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
343
344
  switch (selection.method) {
344
345
  case "free": return eligibility.isFree;
345
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
346
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
346
347
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
347
348
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
348
349
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -361,7 +362,7 @@ function normalizeRegistrationFlowState(state) {
361
362
  ticketsCount: state.ticketsCount,
362
363
  passOptOut: nextPassOptOut
363
364
  });
364
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
365
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
365
366
  selection: state.paymentSelection,
366
367
  isAuthenticated: state.isAuthenticated,
367
368
  eligibility: state.eligibility,
@@ -444,7 +445,7 @@ function resolveEventRegistrationSubmitPlan(input) {
444
445
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
445
446
  if (input.canJoinWaitlist) return {
446
447
  ok: true,
447
- args: withOptionalSelection({ method: "free" }, selection)
448
+ args: { method: "free" }
448
449
  };
449
450
  switch (input.paymentSelection.method) {
450
451
  case "pass": return input.paymentSelection.passId ? {
@@ -503,88 +504,53 @@ function missingPaymentSelection() {
503
504
  };
504
505
  }
505
506
  //#endregion
506
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
507
- /** Recovery may select held places; checkout still owns admission and payment validation. */
508
- function checkoutRecoveryOptionAvailability(availability) {
509
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
510
- kind: "available",
511
- remainingPlaces: null
512
- };
513
- return availability;
507
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
508
+ /** Ticket selection requests a quote; only the server admits a booking. */
509
+ function canRequestTicketOption(availability) {
510
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
514
511
  }
515
- /**
516
- * A form-only projection for the explicit existing-checkout path. It permits
517
- * collecting the original selection without claiming a new place is available.
518
- * The public checkout service identifies the customer and remains the admission
519
- * authority; no reservation/customer data is exposed through this projection.
520
- */
521
- function getCheckoutRecoveryFormEligibility(eligibility) {
522
- 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;
523
- const amountCents = eligibility.price ?? 0;
524
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
525
- ...eligibility,
526
- registration: { kind: "none" },
527
- ticketTypes: eligibility.ticketTypes.map((option) => ({
528
- ...option,
529
- availability: checkoutRecoveryOptionAvailability(option.availability)
530
- }))
531
- } : eligibility;
532
- const currency = eligibility.currency;
533
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
534
- switch (option.kind) {
535
- case "upfront": return {
536
- kind: "payInFull",
537
- amountCents,
538
- currency
539
- };
540
- case "deferred_manual": return {
541
- kind: "deferredManual",
542
- amountCents,
543
- currency
544
- };
545
- case "instalment_plan": return {
546
- kind: "instalmentPlan",
547
- amountCents,
548
- currency
549
- };
550
- case "flexible_balance": return {
551
- kind: "flexibleBalance",
552
- amountCents,
553
- currency
554
- };
555
- }
556
- });
557
- return {
558
- ...eligibility,
559
- registration: { kind: "none" },
560
- availability: {
561
- kind: "available",
562
- remainingPlaces: null,
563
- waitlistEnabled: eligibility.waitlistEnabled
564
- },
565
- eligible: paymentOptions.length > 0,
566
- isFull: false,
567
- canJoinWaitlist: false,
568
- isFree: false,
569
- requiresPayment: true,
570
- canPayDirectly: paymentOptions.length > 0,
571
- paymentOptions,
572
- eligiblePasses: [],
573
- eligibleMemberships: [],
574
- ticketTypes: eligibility.ticketTypes.map((option) => ({
575
- ...option,
576
- availability: checkoutRecoveryOptionAvailability(option.availability)
577
- }))
578
- };
512
+ function normalizeTicketSelectionLines(lines) {
513
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
514
+ for (const line of lines) {
515
+ const quantity = Math.floor(line.quantity);
516
+ if (quantity <= 0) continue;
517
+ const key = line.pricingOptionId ?? null;
518
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
519
+ }
520
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
521
+ pricingOptionId,
522
+ quantity
523
+ }));
524
+ }
525
+ function getTicketSelectionTotal(lines) {
526
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
579
527
  }
580
- function isSoldOutEventSelectable(event, waitlistAvailable) {
581
- return waitlistAvailable || canRecoverEventCheckout(event);
528
+ function getTicketLineQuantity(lines, pricingOptionId) {
529
+ return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
530
+ }
531
+ function getSingleSelectedPricingOptionId(lines) {
532
+ const normalized = normalizeTicketSelectionLines(lines);
533
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
534
+ }
535
+ function hasValidPricingOptionSelection(input) {
536
+ if (!input.selectionRequired) return true;
537
+ if (input.lines.length === 0) return false;
538
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
539
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
582
540
  }
583
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
584
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
541
+ function setTicketLineQuantity(input) {
542
+ const nextQuantity = Math.max(0, Math.floor(input.quantity));
543
+ const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
544
+ if (nextQuantity <= 0) return normalized;
545
+ return [...normalized, {
546
+ pricingOptionId: input.pricingOptionId,
547
+ quantity: nextQuantity
548
+ }];
585
549
  }
586
- function canRecoverEventCheckout(event) {
587
- return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
550
+ function getTicketTypeLineMax(input) {
551
+ const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
552
+ const maxByBlock = input.maxTickets - otherSelectedQuantity;
553
+ return Math.max(0, maxByBlock);
588
554
  }
589
555
  //#endregion
590
556
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
@@ -651,8 +617,6 @@ function formatPassCreditUsageLabel(creditsRemaining) {
651
617
  return `Uses 1 of ${creditsRemaining} credits`;
652
618
  }
653
619
  function transformRegistrationOptionsResponse(response) {
654
- const canJoinWaitlist = response.availability.kind === "waitlist";
655
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
656
620
  const eligiblePasses = response.entitlements.passes.map((pass) => ({
657
621
  id: pass.customerPassId,
658
622
  passName: pass.passName,
@@ -665,7 +629,6 @@ function transformRegistrationOptionsResponse(response) {
665
629
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
666
630
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
667
631
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
668
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
669
632
  return {
670
633
  availability: response.availability,
671
634
  registration: response.registration,
@@ -680,7 +643,6 @@ function transformRegistrationOptionsResponse(response) {
680
643
  },
681
644
  transactions: []
682
645
  } : null,
683
- eligible: response.registration.kind === "none" && registrationAvailable,
684
646
  requiresPayment: monetaryPaymentAvailable,
685
647
  pricingStrategy: response.pricing.strategy,
686
648
  paymentTerms: response.pricing.paymentTerms,
@@ -695,16 +657,12 @@ function transformRegistrationOptionsResponse(response) {
695
657
  currency: response.pricing.currency
696
658
  })),
697
659
  ticketTypes: response.pricing.options,
698
- isFull,
699
- waitlistEnabled: response.availability.waitlistEnabled,
700
- canJoinWaitlist,
701
660
  price: response.pricing.subtotalCents,
702
661
  currency: response.pricing.currency,
703
662
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
704
663
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
705
664
  eligiblePasses,
706
665
  eligibleMemberships,
707
- canPayDirectly: monetaryPaymentAvailable,
708
666
  eventAcceptsPasses,
709
667
  eventAcceptsMemberships,
710
668
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -734,8 +692,8 @@ function getVisibleTicketTypes(input) {
734
692
  })) : [];
735
693
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
736
694
  }
737
- function getImplicitSingleAvailableTicketType(ticketTypes) {
738
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
695
+ function getImplicitSingleTicketType(ticketTypes) {
696
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
739
697
  }
740
698
  function findSelectedTicketType(input) {
741
699
  if (!input.selectedPricingOptionId) return null;
@@ -772,25 +730,19 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
772
730
  const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
773
731
  const isSoldOut = isEventFull(event);
774
732
  const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
775
- const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
776
733
  const isLowCapacity = remaining.kind === "low";
777
734
  const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
778
735
  const timeZone = event.timeZone ?? null;
779
- const cardClasses = [
780
- "er-event-card",
781
- isSelected && "er-event-card--selected",
782
- isUnavailable && "er-event-card--disabled"
783
- ].filter(Boolean).join(" ");
736
+ const cardClasses = ["er-event-card", isSelected && "er-event-card--selected"].filter(Boolean).join(" ");
784
737
  const badgeClasses = [
785
738
  "er-capacity-badge",
786
- isUnavailable && "er-capacity-badge--soldout",
739
+ isSoldOut && "er-capacity-badge--soldout",
787
740
  isLowCapacity && "er-capacity-badge--low",
788
- (canJoinWaitlist || !isUnavailable && !isLowCapacity) && "er-capacity-badge--available"
741
+ (canJoinWaitlist || !isSoldOut && !isLowCapacity) && "er-capacity-badge--available"
789
742
  ].filter(Boolean).join(" ");
790
743
  return /* @__PURE__ */ jsx("button", {
791
744
  type: "button",
792
- onClick: () => !isUnavailable && onSelect(event),
793
- disabled: isUnavailable,
745
+ onClick: () => onSelect(event),
794
746
  className: cardClasses,
795
747
  children: /* @__PURE__ */ jsxs("div", {
796
748
  className: "er-event-option",
@@ -817,41 +769,15 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
817
769
  });
818
770
  };
819
771
  //#endregion
820
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
821
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
822
- function useCheckoutRecovery(event, setStep) {
823
- const [recoveryEventId, setRecoveryEventId] = useState(null);
824
- return {
825
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
826
- startCheckoutRecovery: useCallback(() => {
827
- if (!event) return;
828
- setRecoveryEventId(event.selectionId);
829
- setStep("select-tickets");
830
- }, [event, setStep])
831
- };
832
- }
833
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
834
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
835
- const registrationKind = eligibility?.registration.kind;
836
- useEffect(() => {
837
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
838
- }, [
839
- registrationKind,
840
- step,
841
- checkoutRecovery,
842
- startCheckoutRecovery
843
- ]);
844
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
845
- }
846
- //#endregion
847
772
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
848
773
  function resolveRegistrationRecoveryAction(step, action) {
849
774
  if (step === "payment-failed") return "payment-options";
850
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
775
+ if (step === "payment-status") return "none";
776
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
851
777
  return action;
852
778
  }
853
779
  function canRecoverToWaitlist(eligibility) {
854
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
780
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
855
781
  }
856
782
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
857
783
  return enabled || step === "error" && action === "places";
@@ -868,19 +794,19 @@ function resetRegistrationAfterExpiry(input) {
868
794
  input.setErrorMessage("");
869
795
  input.setPendingRegistrationReference(null);
870
796
  }
871
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
797
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
872
798
  function recoverRegistrationError(action, handlers) {
873
799
  switch (action) {
874
800
  case "none": return;
875
801
  case "portal":
876
- case "payment-status":
877
802
  window.location.assign("/portal");
878
803
  return;
879
804
  case "event":
880
805
  window.location.assign(window.location.pathname);
881
806
  return;
882
807
  case "retry":
883
- window.location.reload();
808
+ handlers.clearError();
809
+ handlers.setStep("select-payment");
884
810
  return;
885
811
  case "details":
886
812
  handlers.clearError();
@@ -918,53 +844,6 @@ function validateFormData(formData, requiresConsent = false) {
918
844
  return errors;
919
845
  }
920
846
  //#endregion
921
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
922
- function normalizeTicketSelectionLines(lines) {
923
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
924
- for (const line of lines) {
925
- const quantity = Math.floor(line.quantity);
926
- if (quantity <= 0) continue;
927
- const key = line.pricingOptionId ?? null;
928
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
929
- }
930
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
931
- pricingOptionId,
932
- quantity
933
- }));
934
- }
935
- function getTicketSelectionTotal(lines) {
936
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
937
- }
938
- function getTicketLineQuantity(lines, pricingOptionId) {
939
- return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
940
- }
941
- function getSingleSelectedPricingOptionId(lines) {
942
- const normalized = normalizeTicketSelectionLines(lines);
943
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
944
- }
945
- function hasValidPricingOptionSelection(input) {
946
- if (!input.selectionRequired) return true;
947
- if (input.lines.length === 0) return false;
948
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
949
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
950
- }
951
- function setTicketLineQuantity(input) {
952
- const nextQuantity = Math.max(0, Math.floor(input.quantity));
953
- const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
954
- if (nextQuantity <= 0) return normalized;
955
- return [...normalized, {
956
- pricingOptionId: input.pricingOptionId,
957
- quantity: nextQuantity
958
- }];
959
- }
960
- function getTicketTypeLineMax(input) {
961
- const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
962
- const maxByBlock = input.maxTickets - otherSelectedQuantity;
963
- const maxByEvent = input.availableSpots == null ? input.maxTickets : input.availableSpots - otherSelectedQuantity;
964
- const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
965
- return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
966
- }
967
- //#endregion
968
847
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
969
848
  const initialEligibilityLookupState = {
970
849
  tag: "idle",
@@ -1082,17 +961,6 @@ function usePortalAuthWithDeps(deps) {
1082
961
  logout
1083
962
  };
1084
963
  }
1085
- function toRegistrationOptionsSubject(subject, attendanceMode) {
1086
- return subject.kind === "occurrence" ? {
1087
- kind: "occurrence",
1088
- occurrenceId: subject.occurrenceId,
1089
- attendanceMode: attendanceMode ?? void 0
1090
- } : {
1091
- kind: "wholeSeries",
1092
- eventSeriesId: subject.eventSeriesId,
1093
- attendanceMode: attendanceMode ?? void 0
1094
- };
1095
- }
1096
964
  function useEligibility(params) {
1097
965
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
1098
966
  }
@@ -1133,7 +1001,7 @@ function useEligibilityWithDeps(params, deps) {
1133
1001
  requestIdRef.current = requestId;
1134
1002
  dispatch({ type: "loading-started" });
1135
1003
  try {
1136
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
1004
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
1137
1005
  const result = await api.getRegistrationOptions({
1138
1006
  subject,
1139
1007
  selections: ticketSelections.map((selection) => ({
@@ -1500,9 +1368,9 @@ const eventRegistrationErrors = {
1500
1368
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
1501
1369
  action: "none"
1502
1370
  },
1503
- paymentUncertain: {
1504
- 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.",
1505
- action: "payment-status"
1371
+ paymentInvestigationRequired: {
1372
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
1373
+ action: "none"
1506
1374
  },
1507
1375
  paymentProviderUnavailable: {
1508
1376
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -2000,7 +1868,30 @@ function checkoutReturnCommand(params) {
2000
1868
  };
2001
1869
  return null;
2002
1870
  }
2003
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
1871
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
1872
+ const { pending, params } = context;
1873
+ if (outcome.kind === "resolved") {
1874
+ deps.clearReturnParams();
1875
+ options.setPendingRegistrationReference(outcome.reference);
1876
+ options.setStep("verifying-payment");
1877
+ return "settled";
1878
+ }
1879
+ if (outcome.kind === "abandoned") {
1880
+ deps.clearReturnParams();
1881
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
1882
+ options.setStep("select-payment");
1883
+ return "settled";
1884
+ }
1885
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
1886
+ deps.clearReturnParams();
1887
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
1888
+ options.setStep("select-payment");
1889
+ return "settled";
1890
+ }
1891
+ 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.");
1892
+ return outcome.kind === "notFound" ? "settled" : "retryable";
1893
+ }
1894
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
2004
1895
  deps.cleanupStaleRegistrations();
2005
1896
  const params = deps.readReturnParams();
2006
1897
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -2014,34 +1905,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
2014
1905
  }
2015
1906
  const { checkoutAttemptId } = command;
2016
1907
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
2017
- checkoutAttemptIdRef.current = checkoutAttemptId;
1908
+ returnContextRef.current = { checkoutAttemptId };
2018
1909
  if (pending) restorePendingPresentation(options, pending);
2019
1910
  options.setStep("verifying-payment");
2020
1911
  try {
2021
1912
  const outcome = await options.api.resolveEventCheckoutReturn(command);
2022
- switch (outcome.kind) {
2023
- case "resolved":
2024
- deps.clearReturnParams();
2025
- options.setPendingRegistrationReference(outcome.reference);
2026
- options.setStep("verifying-payment");
2027
- return "settled";
2028
- case "abandoned":
2029
- deps.clearReturnParams();
2030
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
2031
- options.setStep("select-payment");
2032
- return "settled";
2033
- case "notFound":
2034
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
2035
- deps.clearReturnParams();
2036
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
2037
- options.setStep("select-payment");
2038
- return "settled";
2039
- }
2040
- 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.");
2041
- return "settled";
2042
- case "reconciliationRequired": break;
2043
- }
2044
- 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.");
1913
+ return handleCheckoutReturnOutcome(options, deps, {
1914
+ pending,
1915
+ params
1916
+ }, outcome);
2045
1917
  } catch {
2046
1918
  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.");
2047
1919
  }
@@ -2050,9 +1922,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
2050
1922
  function useEventRegistrationStripeReturn(options) {
2051
1923
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
2052
1924
  }
1925
+ function completeVerifiedRegistration(options, deps, returnContext) {
1926
+ const siteId = options.api.config.siteId;
1927
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
1928
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
1929
+ options.setRegistrationResult({ status: "confirmed" });
1930
+ options.setStep("success");
1931
+ }
2053
1932
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
2054
1933
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
2055
- const checkoutAttemptIdRef = useRef(null);
1934
+ const returnContextRef = useRef(null);
2056
1935
  const lookupInFlightRef = useRef(false);
2057
1936
  const [lookupState, setLookupState] = useState("settled");
2058
1937
  const resolveReturn = useCallback(async () => {
@@ -2060,7 +1939,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
2060
1939
  lookupInFlightRef.current = true;
2061
1940
  setLookupState("loading");
2062
1941
  try {
2063
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
1942
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
2064
1943
  } finally {
2065
1944
  lookupInFlightRef.current = false;
2066
1945
  }
@@ -2083,13 +1962,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
2083
1962
  resolveReturn();
2084
1963
  }, []);
2085
1964
  useEffect(() => {
2086
- if (verification.status === "completed") {
2087
- const siteId = api.config.siteId;
2088
- const checkoutAttemptId = checkoutAttemptIdRef.current;
2089
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
2090
- setRegistrationResult({ status: "confirmed" });
2091
- setStep("success");
2092
- } else if (verification.status === "failed") {
1965
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
1966
+ else if (verification.status === "failed") {
2093
1967
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
2094
1968
  setStep("payment-failed");
2095
1969
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -2118,7 +1992,10 @@ function registrationErrorPresentation(error) {
2118
1992
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
2119
1993
  if (reason) return eventRegistrationErrors[reason];
2120
1994
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
2121
- return eventRegistrationErrors.paymentUncertain;
1995
+ return {
1996
+ message: "Something went wrong. Please try again.",
1997
+ action: "retry"
1998
+ };
2122
1999
  }
2123
2000
  //#endregion
2124
2001
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
@@ -2147,26 +2024,6 @@ function useEventRegistrationSubmit(options) {
2147
2024
  * and the balance left, which the block's copy cannot. Every other method keeps
2148
2025
  * whatever success message the site configured.
2149
2026
  */
2150
- function toRegistrationResult(result) {
2151
- if (result.alreadyRegistered) {
2152
- const waitlisted = result.status === "waitlist";
2153
- return {
2154
- status: result.status,
2155
- variant: "info",
2156
- title: waitlisted ? "Already waitlisted" : "Already registered",
2157
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
2158
- };
2159
- }
2160
- if (result.status === "waitlist") return {
2161
- status: "waitlist",
2162
- title: "Added to waitlist",
2163
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
2164
- };
2165
- return {
2166
- status: result.status,
2167
- message: result.paymentMethod === "pass" ? result.message : void 0
2168
- };
2169
- }
2170
2027
  function useEventRegistrationSubmitWithDeps(options, deps) {
2171
2028
  /**
2172
2029
  * The command identity for the submission currently in progress.
@@ -2180,7 +2037,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
2180
2037
  * Identical retries retain the command after a lost response. Changed form
2181
2038
  * details get a new command so the server applies the new booking intent.
2182
2039
  */
2183
- const commandRef = useRef(null);
2040
+ const { commandRef } = options;
2184
2041
  const inFlightRef = useRef(null);
2185
2042
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
2186
2043
  const target = options.registrationTarget;
@@ -2193,19 +2050,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
2193
2050
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
2194
2051
  try {
2195
2052
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
2196
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
2197
- commandRef.current = null;
2198
- return await submitWholeSeriesCheckout(options, deps, {
2053
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
2054
+ const intentKey = registrationRequestIntentKey(request);
2055
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
2056
+ prepared = {
2199
2057
  ...prepared,
2200
- subject: prepared.subject
2201
- }, submitOptions);
2058
+ registrationCommandId: deps.createClientCommandId()
2059
+ };
2060
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
2202
2061
  }
2203
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
2204
- const intentKey = registrationRequestIntentKey(request);
2205
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
2206
- ...prepared,
2207
- registrationCommandId: deps.createClientCommandId()
2208
- };
2209
2062
  commandRef.current = {
2210
2063
  id: prepared.registrationCommandId,
2211
2064
  intentKey
@@ -2214,8 +2067,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
2214
2067
  ...request,
2215
2068
  registrationCommandId: prepared.registrationCommandId
2216
2069
  });
2217
- commandRef.current = null;
2218
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
2070
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
2219
2071
  } catch (error) {
2220
2072
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
2221
2073
  const { message, action } = registrationErrorPresentation(error);
@@ -2239,9 +2091,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
2239
2091
  return pending;
2240
2092
  };
2241
2093
  }
2242
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
2243
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
2244
- options.setRegistrationResult(toRegistrationResult(result));
2094
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
2095
+ switch (result.kind) {
2096
+ case "paymentStatusRequired":
2097
+ options.setPaymentStatusRecovery({
2098
+ kind: "ready",
2099
+ subject: result.subject
2100
+ });
2101
+ options.setStep("payment-status");
2102
+ return {
2103
+ ok: true,
2104
+ outcome: { kind: "payment_status" }
2105
+ };
2106
+ case "checkoutRequired":
2107
+ options.setPendingRegistrationReference(result.reference);
2108
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
2109
+ options.setStep("redirecting");
2110
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
2111
+ case "waitlisted":
2112
+ options.setRegistrationResult({
2113
+ status: "waitlist",
2114
+ title: "Added to waitlist",
2115
+ message: result.waitlist.message
2116
+ });
2117
+ break;
2118
+ case "bookingComplete":
2119
+ case "paymentDeferred":
2120
+ options.setPendingRegistrationReference(result.reference);
2121
+ options.setRegistrationResult({
2122
+ status: "confirmed",
2123
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
2124
+ });
2125
+ break;
2126
+ }
2127
+ options.commandRef.current = null;
2245
2128
  options.setStep("success");
2246
2129
  return {
2247
2130
  ok: true,
@@ -2272,15 +2155,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
2272
2155
  email: guest.email?.trim().toLowerCase() || void 0,
2273
2156
  phone: guest.phone?.trim() || void 0
2274
2157
  })) : void 0,
2275
- subject: target.subject.kind === "occurrence" ? {
2276
- kind: "occurrence",
2277
- occurrenceId: target.subject.occurrenceId,
2278
- attendanceMode: options.selectedAttendanceMode ?? void 0
2279
- } : {
2280
- kind: "wholeSeries",
2281
- eventSeriesId: target.subject.eventSeriesId,
2282
- attendanceMode: options.selectedAttendanceMode ?? void 0
2283
- }
2158
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
2284
2159
  };
2285
2160
  }
2286
2161
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -2304,85 +2179,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
2304
2179
  if (method === "free") return { method };
2305
2180
  throw new Error("Choose an available payment option.");
2306
2181
  }
2307
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
2308
- options.setStep("redirecting");
2309
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
2310
- const checkoutAttemptId = deps.createClientCommandId();
2311
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
2312
- const result = await options.api.createEventCheckout({
2313
- subject: prepared.subject,
2314
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
2315
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
2316
- email: options.formData.email.trim().toLowerCase(),
2317
- name: options.formData.name.trim(),
2318
- phone: options.formData.phone.trim() || void 0,
2319
- formData: options.formData,
2320
- consentAccepted: options.formData.consentAccepted,
2321
- altchaSolution: options.altchaSolution,
2322
- guests: prepared.guestsPayload,
2323
- claimToken: options.claimToken ?? void 0,
2324
- waitlistEntryId: options.waitlistEntryId ?? void 0,
2325
- discountCode: options.discountCode.trim() || void 0,
2326
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
2327
- checkoutAttemptId,
2328
- ...urls
2329
- });
2330
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
2331
- if ("waitlistEntryId" in result) {
2332
- options.setRegistrationResult({
2333
- status: "waitlist",
2334
- variant: result.alreadyRegistered ? "info" : void 0,
2335
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
2336
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
2337
- });
2338
- options.setStep("success");
2339
- return {
2340
- ok: true,
2341
- outcome: { kind: "completed" }
2342
- };
2343
- }
2344
- if (result.bypassed) return completeBypassedCheckout(options);
2345
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
2346
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
2347
- scope: "wholeSeries",
2348
- registrationId: result.registrationId
2349
- });
2350
- return redirectToCheckout(result.checkoutUrl, submitOptions);
2351
- }
2352
- function needsOccurrenceCheckout(result, method) {
2353
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
2354
- "stripe",
2355
- "pass_bundle",
2356
- "membership_bundle"
2357
- ].includes(method);
2358
- }
2359
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
2360
- const reference = {
2361
- scope: "occurrence",
2362
- attendeeId: registration.attendeeId
2363
- };
2364
- options.setPendingRegistrationReference(reference);
2365
- options.setStep("redirecting");
2366
- const checkoutAttemptId = deps.createClientCommandId();
2367
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
2368
- const result = await options.api.createEventCheckout({
2369
- subject: {
2370
- kind: "occurrence",
2371
- attendeeId: registration.attendeeId
2372
- },
2373
- registrationCommandId: prepared.registrationCommandId,
2374
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
2375
- productId: prepared.bundleProductId,
2376
- discountCode: options.discountCode.trim() || void 0,
2377
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
2378
- ...urls
2379
- });
2380
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
2381
- if (result.bypassed) return completeBypassedCheckout(options);
2382
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
2383
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
2384
- return redirectToCheckout(result.checkoutUrl, submitOptions);
2385
- }
2386
2182
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
2387
2183
  const siteId = options.api.config.siteId;
2388
2184
  if (!siteId) return;
@@ -2395,14 +2191,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
2395
2191
  paymentSelection: prepared.selectionSnapshot
2396
2192
  });
2397
2193
  }
2398
- function completeBypassedCheckout(options) {
2399
- options.setRegistrationResult({ status: "confirmed" });
2400
- options.setStep("success");
2401
- return {
2402
- ok: true,
2403
- outcome: { kind: "completed" }
2404
- };
2405
- }
2406
2194
  function redirectToCheckout(checkoutUrl, submitOptions) {
2407
2195
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
2408
2196
  return {
@@ -2414,12 +2202,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
2414
2202
  };
2415
2203
  }
2416
2204
  function registrationRequestIntentKey(request) {
2417
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
2418
- return JSON.stringify(intent);
2205
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
2206
+ return JSON.stringify({
2207
+ ...intent,
2208
+ checkout: checkout ? {
2209
+ discountCode: checkout.discountCode,
2210
+ collectionOptionKind: checkout.collectionOptionKind
2211
+ } : void 0
2212
+ });
2419
2213
  }
2420
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
2214
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
2421
2215
  return {
2422
2216
  registrationCommandId: prepared.registrationCommandId,
2217
+ checkout: {
2218
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
2219
+ discountCode: options.discountCode.trim() || void 0,
2220
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
2221
+ },
2423
2222
  subject: prepared.subject,
2424
2223
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
2425
2224
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -2637,20 +2436,124 @@ function useWaitlistClaimRestoration(input) {
2637
2436
  }
2638
2437
  //#endregion
2639
2438
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
2439
+ function isSelectionSoldOut(availability) {
2440
+ return availability?.kind === "unavailable" && availability.reason === "full";
2441
+ }
2640
2442
  function resolveRegistrationAvailabilityBlocker(input) {
2641
2443
  if (input.hasWaitlistClaim) return null;
2642
2444
  if (input.eligibilityError) return input.eligibilityError;
2643
2445
  if (!input.eligibility) return "Registration is not available for this event.";
2446
+ if (input.eligibility.registration.kind === "pending_payment") return null;
2447
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
2644
2448
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
2645
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
2449
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
2646
2450
  return null;
2647
2451
  }
2648
2452
  function resolvePricingSelectionBlocker(input) {
2649
2453
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
2650
2454
  return input.slidingScaleSelectionMessage;
2651
2455
  }
2652
- function isSoldOutWithoutWaitlist(input) {
2653
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
2456
+ //#endregion
2457
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
2458
+ function isCheckableRecovery(state) {
2459
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
2460
+ }
2461
+ function assistanceRequired(recovery) {
2462
+ return {
2463
+ kind: "assistanceRequired",
2464
+ subject: recovery.subject
2465
+ };
2466
+ }
2467
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
2468
+ if (outcome.kind === "resolved") {
2469
+ setters.setPendingRegistrationReference(outcome.reference);
2470
+ setters.setRegistrationResult({ status: "confirmed" });
2471
+ setRecovery(null);
2472
+ setters.setStep("success");
2473
+ return;
2474
+ }
2475
+ switch (outcome.kind) {
2476
+ case "paymentProcessing":
2477
+ setRecovery({
2478
+ ...recovery,
2479
+ kind: "processing"
2480
+ });
2481
+ return;
2482
+ case "paymentAvailable":
2483
+ setRecovery({
2484
+ ...recovery,
2485
+ kind: "paymentAvailable",
2486
+ checkoutUrl: outcome.checkoutUrl
2487
+ });
2488
+ return;
2489
+ case "paymentCheckUnavailable":
2490
+ setRecovery({
2491
+ ...recovery,
2492
+ kind: "temporarilyUnavailable"
2493
+ });
2494
+ return;
2495
+ case "paymentRetryAvailable":
2496
+ setRecovery({
2497
+ ...recovery,
2498
+ kind: "retryAvailable"
2499
+ });
2500
+ return;
2501
+ case "abandoned":
2502
+ case "notFound":
2503
+ case "reconciliationRequired":
2504
+ case "paymentAssistanceRequired":
2505
+ setRecovery(assistanceRequired(recovery));
2506
+ return;
2507
+ }
2508
+ }
2509
+ function usePaymentStatusRecovery(options) {
2510
+ const [recovery, setRecovery] = useState(null);
2511
+ const checkRef = useRef(null);
2512
+ return {
2513
+ recovery,
2514
+ showRecovery: useCallback((next) => setRecovery(next), []),
2515
+ check: useCallback(() => {
2516
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
2517
+ const pending = (async () => {
2518
+ setRecovery({
2519
+ ...recovery,
2520
+ kind: "checking"
2521
+ });
2522
+ try {
2523
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
2524
+ kind: "checkStatus",
2525
+ subject: recovery.subject
2526
+ }), recovery, options, setRecovery);
2527
+ } catch {
2528
+ setRecovery({
2529
+ ...recovery,
2530
+ kind: "temporarilyUnavailable"
2531
+ });
2532
+ }
2533
+ })();
2534
+ checkRef.current = pending;
2535
+ pending.finally(() => {
2536
+ if (checkRef.current === pending) checkRef.current = null;
2537
+ });
2538
+ }, [options, recovery]),
2539
+ continuePayment: useCallback(() => {
2540
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
2541
+ }, [recovery]),
2542
+ returnToPayment: useCallback(() => {
2543
+ if (recovery?.kind !== "retryAvailable") return;
2544
+ options.beginNewSubmission();
2545
+ setRecovery(null);
2546
+ options.setOptionsRefreshKey((value) => value + 1);
2547
+ options.setStep("select-payment");
2548
+ }, [options, recovery]),
2549
+ returnToBooking: useCallback(() => {
2550
+ if (recovery?.kind !== "assistanceRequired") return;
2551
+ options.beginNewSubmission();
2552
+ setRecovery(null);
2553
+ options.setOptionsRefreshKey((value) => value + 1);
2554
+ options.setStep("select-tickets");
2555
+ }, [options, recovery])
2556
+ };
2654
2557
  }
2655
2558
  //#endregion
2656
2559
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
@@ -2708,6 +2611,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2708
2611
  const [errorAction, setErrorAction] = useState("retry");
2709
2612
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
2710
2613
  const [altchaSolution, setAltchaSolution] = useState(null);
2614
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
2711
2615
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
2712
2616
  const waitlistClaim = deps.useWaitlistClaim();
2713
2617
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -2734,28 +2638,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2734
2638
  }), [options.occurrenceContext, selectedEvent]);
2735
2639
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
2736
2640
  const currentEvent = selectedEvent ?? preSelectedEvent;
2641
+ const commandRef = useRef(null);
2737
2642
  const setStep = useCallback((nextStep) => {
2738
2643
  dispatchFlow({
2739
2644
  type: "set-step",
2740
2645
  step: nextStep
2741
2646
  });
2742
2647
  }, []);
2743
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
2744
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
2745
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
2746
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
2648
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
2649
+ api,
2650
+ beginNewSubmission: () => {
2651
+ commandRef.current = null;
2652
+ },
2653
+ setPendingRegistrationReference,
2654
+ setRegistrationResult,
2655
+ setOptionsRefreshKey,
2656
+ setStep
2657
+ });
2658
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
2747
2659
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
2748
2660
  event: currentEvent,
2749
2661
  eligibility: null,
2750
2662
  selectedAttendanceMode
2751
- }).map((option) => checkoutRecovery ? {
2752
- ...option,
2753
- availability: checkoutRecoveryOptionAvailability(option.availability)
2754
- } : option), [
2755
- currentEvent,
2756
- selectedAttendanceMode,
2757
- checkoutRecovery
2758
- ]);
2663
+ }), [currentEvent, selectedAttendanceMode]);
2759
2664
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
2760
2665
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
2761
2666
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -2793,7 +2698,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2793
2698
  isAuthenticated: portalAuthState === "authenticated",
2794
2699
  occurrenceId: registrationOccurrenceId
2795
2700
  });
2796
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
2701
+ const eligibility = eligibilityResult.eligibility;
2797
2702
  const eligibilityLoading = eligibilityResult.isLoading;
2798
2703
  const eligibilityError = eligibilityResult.error;
2799
2704
  const portalCreditState = eligibilityResult.creditState;
@@ -2905,14 +2810,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2905
2810
  event: currentEvent,
2906
2811
  eligibility,
2907
2812
  selectedAttendanceMode
2908
- }).map((option) => checkoutRecovery ? {
2909
- ...option,
2910
- availability: checkoutRecoveryOptionAvailability(option.availability)
2911
- } : option), [
2813
+ }), [
2912
2814
  currentEvent,
2913
2815
  selectedAttendanceMode,
2914
- eligibility,
2915
- checkoutRecovery
2816
+ eligibility
2916
2817
  ]);
2917
2818
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
2918
2819
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -2936,12 +2837,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2936
2837
  const event = currentEvent;
2937
2838
  if (!usesTieredPricing(event)) return false;
2938
2839
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
2939
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
2940
- }, [
2941
- currentEvent,
2942
- selectedAttendanceMode,
2943
- checkoutRecovery
2944
- ]);
2840
+ return true;
2841
+ }, [currentEvent, selectedAttendanceMode]);
2945
2842
  const hasValidTicketSelection = hasValidPricingOptionSelection({
2946
2843
  selectionRequired: ticketTypeSelectionRequired,
2947
2844
  lines: normalizedSelectedTicketLines,
@@ -2952,8 +2849,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2952
2849
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
2953
2850
  return;
2954
2851
  }
2955
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
2956
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
2852
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
2853
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
2957
2854
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
2958
2855
  setSelectedTicketLines([{
2959
2856
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -3020,6 +2917,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3020
2917
  selectedEventSlidingScale,
3021
2918
  selectedSlidingAmount
3022
2919
  ]);
2920
+ const checkDetailsNextStep = async () => {
2921
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
2922
+ setCheckingNextStep(true);
2923
+ try {
2924
+ return await api.checkRegistrationNextStep({
2925
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
2926
+ selections: ticketSelections,
2927
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
2928
+ email: formData.email,
2929
+ altchaSolution
2930
+ });
2931
+ } catch {
2932
+ return {
2933
+ kind: "unavailable",
2934
+ message: "We could not check availability. Please try again."
2935
+ };
2936
+ } finally {
2937
+ setCheckingNextStep(false);
2938
+ }
2939
+ };
3023
2940
  const handleDetailsComplete = async () => {
3024
2941
  const blockDetailsCompletion = (message) => {
3025
2942
  setErrorAction("places");
@@ -3051,11 +2968,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3051
2968
  message: "Check the highlighted fields and try again."
3052
2969
  };
3053
2970
  }
3054
- if (isSoldOutWithoutWaitlist({
3055
- hasWaitlistClaim: waitlistClaim.claim !== null,
3056
- eligibility
3057
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
3058
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
2971
+ const next = await checkDetailsNextStep();
2972
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
2973
+ const canJoinWaitlist = next.kind === "waitlist";
2974
+ if (!canJoinWaitlist && requiresPaymentStep({
3059
2975
  eventRequiresPayment,
3060
2976
  paymentSelection
3061
2977
  })) {
@@ -3068,7 +2984,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3068
2984
  const submitPlan = resolveEventRegistrationSubmitPlan({
3069
2985
  paymentSelection,
3070
2986
  eventRequiresPayment,
3071
- canJoinWaitlist: eligibility?.canJoinWaitlist
2987
+ canJoinWaitlist
3072
2988
  });
3073
2989
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
3074
2990
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -3086,7 +3002,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3086
3002
  const submitPlan = resolveEventRegistrationSubmitPlan({
3087
3003
  paymentSelection,
3088
3004
  eventRequiresPayment,
3089
- canJoinWaitlist: eligibility?.canJoinWaitlist
3005
+ canJoinWaitlist: false
3090
3006
  });
3091
3007
  if (!submitPlan.ok) {
3092
3008
  setErrorMessage(submitPlan.message);
@@ -3118,6 +3034,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3118
3034
  const selectionMethod = paymentSelection.method;
3119
3035
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
3120
3036
  const handleSubmit = deps.useEventRegistrationSubmit({
3037
+ commandRef,
3121
3038
  setErrorAction,
3122
3039
  api,
3123
3040
  registrationTarget,
@@ -3134,7 +3051,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3134
3051
  setPendingRegistrationReference,
3135
3052
  setStep,
3136
3053
  setRegistrationResult: (result) => setRegistrationResult(result),
3137
- setErrorMessage
3054
+ setErrorMessage,
3055
+ setPaymentStatusRecovery
3138
3056
  });
3139
3057
  const handleEventSelect = (event) => {
3140
3058
  setSelectedEvent(event);
@@ -3193,8 +3111,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3193
3111
  scopedEvents,
3194
3112
  preSelectedEvent,
3195
3113
  hasPreSelectedContext,
3196
- checkoutRecovery,
3197
- startCheckoutRecovery,
3198
3114
  step,
3199
3115
  setStep,
3200
3116
  selectedEvent,
@@ -3248,7 +3164,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3248
3164
  waitlistClaim,
3249
3165
  eligibility,
3250
3166
  registrationOptionsState: eligibilityResult.state,
3251
- eligibilityLoading,
3167
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
3252
3168
  eligibilityError,
3253
3169
  existingRegistration: existingRegistrationResult.registration,
3254
3170
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -3268,6 +3184,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
3268
3184
  discountContext,
3269
3185
  shouldShowDiscountToggle,
3270
3186
  verification,
3187
+ paymentStatusRecovery,
3188
+ handleCheckPaymentStatus,
3189
+ handleContinueExistingPayment,
3190
+ handleReturnToPayment,
3191
+ handleReturnToBooking,
3271
3192
  handleDetailsComplete,
3272
3193
  handlePaymentSelect,
3273
3194
  handleUseCardInsteadOfPass,
@@ -3334,6 +3255,22 @@ function getMagicLinkError(state) {
3334
3255
  }
3335
3256
  //#endregion
3336
3257
  //#region ../blocks/src/system/runtime/nodes/shared/MagicLinkForm.tsx
3258
+ function MagicLinkButton(props) {
3259
+ return props.themed ? /* @__PURE__ */ jsx(ThemedButton, {
3260
+ type: props.type,
3261
+ variant: props.variant,
3262
+ size: "md",
3263
+ label: props.label,
3264
+ disabled: props.disabled,
3265
+ onClick: props.onClick
3266
+ }) : /* @__PURE__ */ jsx("button", {
3267
+ type: props.type,
3268
+ className: props.className,
3269
+ disabled: props.disabled,
3270
+ onClick: props.onClick,
3271
+ children: props.label
3272
+ });
3273
+ }
3337
3274
  /**
3338
3275
  * Reusable magic link login form.
3339
3276
  * Used by Customer Portal and Event Registration blocks.
@@ -3374,14 +3311,13 @@ function MagicLinkForm({ initialEmail = "", title, subtitle, buttonText = "Send
3374
3311
  children: [/* @__PURE__ */ jsx("p", {
3375
3312
  className: `${classPrefix}-portal-auth-text ${classPrefix}-portal-auth-text--success`,
3376
3313
  children: successMessage
3377
- }), !compact && /* @__PURE__ */ jsx("button", {
3314
+ }), !compact && /* @__PURE__ */ jsx(MagicLinkButton, {
3315
+ themed: classPrefix === "cp",
3378
3316
  type: "button",
3379
- className: classPrefix === "cp" ? themeButtonClassName({
3380
- variant: "secondary",
3381
- size: "md"
3382
- }) : `${classPrefix}-modal-btn ${classPrefix}-modal-btn--secondary`,
3383
- onClick: handleReset,
3384
- children: "Try a different email"
3317
+ variant: "secondary",
3318
+ className: `${classPrefix}-modal-btn ${classPrefix}-modal-btn--secondary`,
3319
+ label: "Try a different email",
3320
+ onClick: handleReset
3385
3321
  })]
3386
3322
  });
3387
3323
  return /* @__PURE__ */ jsxs("form", {
@@ -3410,14 +3346,13 @@ function MagicLinkForm({ initialEmail = "", title, subtitle, buttonText = "Send
3410
3346
  className: `${classPrefix}-portal-auth-text ${classPrefix}-portal-auth-text--error`,
3411
3347
  children: error
3412
3348
  }),
3413
- /* @__PURE__ */ jsx("button", {
3349
+ /* @__PURE__ */ jsx(MagicLinkButton, {
3350
+ themed: classPrefix === "cp",
3414
3351
  type: "submit",
3415
- className: classPrefix === "cp" ? themeButtonClassName({
3416
- variant: "primary",
3417
- size: "md"
3418
- }) : `${classPrefix}-modal-btn`,
3419
- disabled: !email.trim() || loading,
3420
- children: loading ? "Sending..." : buttonText
3352
+ variant: "primary",
3353
+ className: `${classPrefix}-modal-btn`,
3354
+ label: loading ? "Sending..." : buttonText,
3355
+ disabled: !email.trim() || loading
3421
3356
  })
3422
3357
  ]
3423
3358
  });
@@ -3439,7 +3374,6 @@ const labels = {
3439
3374
  start: "Start again",
3440
3375
  details: "Check my details",
3441
3376
  "payment-options": "View payment options",
3442
- "payment-status": "Check payment status",
3443
3377
  portal: "View my bookings",
3444
3378
  event: "View event"
3445
3379
  };
@@ -3458,7 +3392,7 @@ const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false
3458
3392
  className: "er-text--muted er-message",
3459
3393
  children: offerWaitlist ? "Sorry, this event is now full. You can join the waiting list, and we’ll email you if a place becomes available." : message
3460
3394
  }),
3461
- actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
3395
+ actions: action === "none" ? void 0 : action === "portal" ? /* @__PURE__ */ jsx("a", {
3462
3396
  href: "/portal",
3463
3397
  className: "er-retry-btn",
3464
3398
  children: labels[action]
@@ -3712,8 +3646,11 @@ function EventRegistrationSummaryBar(props) {
3712
3646
  */
3713
3647
  function resolveDetailsButtonText(input) {
3714
3648
  const { wizard } = input;
3715
- if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
3716
- if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
3649
+ const availability = wizard.eligibility?.availability;
3650
+ const full = availability?.kind === "waitlist" || isSelectionSoldOut(availability);
3651
+ if (wizard.portalAuthState !== "authenticated" && full) return "Continue";
3652
+ if (canRecoverToWaitlist(wizard.eligibility)) return "Join waitlist";
3653
+ if (!input.hasWaitlistClaim && full && wizard.eligibility?.registration.kind !== "pending_payment") return "Sold out";
3717
3654
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
3718
3655
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
3719
3656
  return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
@@ -3728,44 +3665,28 @@ function isExistingRegistrationBlocking$1(wizard) {
3728
3665
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
3729
3666
  });
3730
3667
  }
3731
- /**
3732
- * Full for the visitor's selected attendance mode (or the whole event when no
3733
- * mode is chosen) with no waitlist to fall back on. Reads the same capacity
3734
- * source as the steps above the action bar so the button never disagrees
3735
- * with them on a hybrid event.
3736
- */
3737
- function isFullWithNoWaitlist(event, attendanceMode) {
3738
- if (!event) return false;
3739
- const source = selectEventCapacitySource(event, attendanceMode);
3740
- return getEventAvailability(source).isFull && !source.waitlistEnabled;
3741
- }
3742
3668
  function resolveTicketSelectionContinueLabel(input) {
3743
3669
  if (input.isCheckingExistingRegistration) return "Checking registration...";
3744
3670
  if (input.registrationOptionsPending) return "Checking availability...";
3745
3671
  if (input.registrationOptionsFailed) return "Availability unavailable";
3746
3672
  if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
3747
- if (input.isSoldOutWithoutWaitlist) return "Sold out";
3748
3673
  if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
3749
3674
  return "Continue";
3750
3675
  }
3751
3676
  function SelectTicketsActions(props) {
3752
3677
  const { wizard } = props;
3753
- const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
3754
- const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
3755
3678
  const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
3756
3679
  const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
3757
- const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
3758
3680
  const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
3759
3681
  const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
3760
3682
  const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
3761
- const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
3683
+ const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
3762
3684
  const continueLabel = resolveTicketSelectionContinueLabel({
3763
3685
  wizard,
3764
3686
  registrationOptionsPending,
3765
3687
  registrationOptionsFailed,
3766
3688
  isCheckingExistingRegistration,
3767
3689
  hasExistingRegistration,
3768
- isSoldOutWithoutWaitlist,
3769
3690
  ticketTypeSelectionBlocked
3770
3691
  });
3771
3692
  return /* @__PURE__ */ jsxs("div", {
@@ -3775,20 +3696,19 @@ function SelectTicketsActions(props) {
3775
3696
  onClick: () => wizard.setStep("select-event"),
3776
3697
  className: "er-back-btn",
3777
3698
  children: "← Back"
3778
- }), /* @__PURE__ */ jsx("button", {
3699
+ }), /* @__PURE__ */ jsx(ThemedButton, {
3779
3700
  type: "button",
3780
3701
  onClick: () => wizard.setStep("enter-details"),
3781
3702
  disabled: isContinueDisabled,
3782
- className: props.buttonClass,
3783
- children: registrationOptionsPending ? /* @__PURE__ */ jsxs("span", {
3784
- className: "er-button-with-spinner",
3785
- children: [/* @__PURE__ */ jsx(SpinnerNode, {
3786
- size: "xs",
3787
- color: "inherit",
3788
- className: "er-button-spinner",
3789
- "aria-hidden": true
3790
- }), continueLabel]
3791
- }) : continueLabel
3703
+ variant: props.buttonVariant,
3704
+ size: "md",
3705
+ label: continueLabel,
3706
+ pending: registrationOptionsPending ? {
3707
+ label: continueLabel,
3708
+ spinnerSize: "xs",
3709
+ spinnerClassName: "er-button-spinner",
3710
+ contentClassName: "er-button-with-spinner"
3711
+ } : void 0
3792
3712
  })]
3793
3713
  });
3794
3714
  }
@@ -3796,8 +3716,12 @@ function EnterDetailsActions(props) {
3796
3716
  const { wizard } = props;
3797
3717
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
3798
3718
  const isCheckingEligibility = wizard.eligibilityLoading;
3799
- const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
3800
- const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
3719
+ const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker({
3720
+ hasWaitlistClaim,
3721
+ eligibility: wizard.eligibility,
3722
+ eligibilityError: wizard.eligibilityError
3723
+ }));
3724
+ const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
3801
3725
  const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
3802
3726
  const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
3803
3727
  wizard,
@@ -3811,12 +3735,13 @@ function EnterDetailsActions(props) {
3811
3735
  onClick: () => wizard.setStep("select-tickets"),
3812
3736
  className: "er-back-btn",
3813
3737
  children: "← Back"
3814
- }), /* @__PURE__ */ jsx("button", {
3738
+ }), /* @__PURE__ */ jsx(ThemedButton, {
3815
3739
  type: "button",
3816
3740
  onClick: wizard.handleDetailsComplete,
3817
3741
  disabled: isContinueDisabled,
3818
- className: props.buttonClass,
3819
- children: continueLabel
3742
+ variant: props.buttonVariant,
3743
+ size: "md",
3744
+ label: continueLabel
3820
3745
  })]
3821
3746
  });
3822
3747
  }
@@ -3830,12 +3755,13 @@ function SelectPaymentActions(props) {
3830
3755
  onClick: () => wizard.setStep("enter-details"),
3831
3756
  className: "er-back-btn",
3832
3757
  children: "← Back"
3833
- }), status === "ready" && /* @__PURE__ */ jsx("button", {
3758
+ }), status === "ready" && /* @__PURE__ */ jsx(ThemedButton, {
3834
3759
  type: "button",
3835
3760
  onClick: () => void wizard.handlePaymentSelect(),
3836
3761
  disabled: !canContinue,
3837
- className: props.buttonClass,
3838
- children: buttonText
3762
+ variant: props.buttonVariant,
3763
+ size: "md",
3764
+ label: buttonText
3839
3765
  })]
3840
3766
  });
3841
3767
  }
@@ -3848,6 +3774,7 @@ function EventRegistrationWizardActions(props) {
3848
3774
  case "redirecting":
3849
3775
  case "verifying-payment":
3850
3776
  case "verifying-timeout":
3777
+ case "payment-status":
3851
3778
  case "payment-failed": return null;
3852
3779
  case "select-event": return null;
3853
3780
  case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
@@ -3932,7 +3859,7 @@ function buildSelectedSiteCreditPreview(input) {
3932
3859
  function resolvePaymentStepStatus(input) {
3933
3860
  if (input.loading) return "loading";
3934
3861
  if (input.error || !input.eligibility) return "error";
3935
- if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
3862
+ if (input.eligibility.registration.kind === "waitlisted" || input.eligibility.paymentOptions.length === 0) return "not-eligible";
3936
3863
  return "ready";
3937
3864
  }
3938
3865
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
@@ -3967,7 +3894,7 @@ function UnavailableEntitlementMessage(props) {
3967
3894
  ] });
3968
3895
  }
3969
3896
  function IneligiblePaymentPanel(props) {
3970
- if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
3897
+ if (isSelectionSoldOut(props.eligibility.availability)) return /* @__PURE__ */ jsxs("div", {
3971
3898
  className: "rb-reg-stack er-stack",
3972
3899
  children: [/* @__PURE__ */ jsx("h3", {
3973
3900
  className: "er-title",
@@ -3993,15 +3920,13 @@ function IneligiblePaymentPanel(props) {
3993
3920
  className: "er-text er-text--muted",
3994
3921
  children: "Have a pass or membership? Log in to use it."
3995
3922
  }),
3996
- /* @__PURE__ */ jsx("button", {
3923
+ /* @__PURE__ */ jsx(ThemedButton, {
3997
3924
  type: "button",
3998
- className: themeButtonClassName({
3999
- variant: "primary",
4000
- size: "md"
4001
- }),
3925
+ variant: "primary",
3926
+ size: "md",
3927
+ label: "Email me a login link",
4002
3928
  disabled: !props.email.trim(),
4003
- onClick: props.onRequestLogin,
4004
- children: "Email me a login link"
3929
+ onClick: props.onRequestLogin
4005
3930
  }),
4006
3931
  !props.email.trim() && /* @__PURE__ */ jsx("p", {
4007
3932
  className: "er-text er-text--muted",
@@ -4036,26 +3961,23 @@ function PaymentBlockingPanel(props) {
4036
3961
  })
4037
3962
  });
4038
3963
  if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
4039
- if (props.eligibility.registration.kind !== "none") {
4040
- const isBooked = props.eligibility.registration.kind === "booked";
4041
- return /* @__PURE__ */ jsxs("div", {
4042
- className: "rb-reg-stack er-stack",
4043
- children: [/* @__PURE__ */ jsx("h3", {
4044
- className: "er-title",
4045
- children: isBooked ? "Already booked" : "Already on the waitlist"
4046
- }), /* @__PURE__ */ jsxs("div", {
4047
- className: "er-center",
4048
- children: [/* @__PURE__ */ jsx("p", {
4049
- className: "er-text er-text--muted",
4050
- children: isBooked ? "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser." : "You're already on the waitlist for this event."
4051
- }), /* @__PURE__ */ jsx("a", {
4052
- href: "/portal",
4053
- className: "er-retry-btn",
4054
- children: "View my bookings"
4055
- })]
3964
+ if (props.eligibility.registration.kind === "waitlisted") return /* @__PURE__ */ jsxs("div", {
3965
+ className: "rb-reg-stack er-stack",
3966
+ children: [/* @__PURE__ */ jsx("h3", {
3967
+ className: "er-title",
3968
+ children: "Already on the waitlist"
3969
+ }), /* @__PURE__ */ jsxs("div", {
3970
+ className: "er-center",
3971
+ children: [/* @__PURE__ */ jsx("p", {
3972
+ className: "er-text er-text--muted",
3973
+ children: "You're already on the waitlist for this event."
3974
+ }), /* @__PURE__ */ jsx("a", {
3975
+ href: "/portal",
3976
+ className: "er-retry-btn",
3977
+ children: "View my bookings"
4056
3978
  })]
4057
- });
4058
- }
3979
+ })]
3980
+ });
4059
3981
  if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
4060
3982
  className: "rb-reg-stack er-stack",
4061
3983
  children: [/* @__PURE__ */ jsx("h3", {
@@ -4076,7 +3998,7 @@ function PaymentBlockingPanel(props) {
4076
3998
  })]
4077
3999
  })]
4078
4000
  });
4079
- return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
4001
+ return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
4080
4002
  eligibility: props.eligibility,
4081
4003
  email: props.email,
4082
4004
  isAuthenticated: props.isAuthenticated,
@@ -4208,7 +4130,7 @@ function SlidingScaleAmountField(props) {
4208
4130
  }
4209
4131
  function TicketTypeQuantityRows(props) {
4210
4132
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
4211
- const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
4133
+ const effectiveMaxTickets = props.maxTickets;
4212
4134
  return /* @__PURE__ */ jsxs("div", {
4213
4135
  className: "er-ticket-lines",
4214
4136
  children: [
@@ -4218,16 +4140,14 @@ function TicketTypeQuantityRows(props) {
4218
4140
  "aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
4219
4141
  children: props.ticketTypes.map((ticketType) => {
4220
4142
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
4221
- const disabled = ticketType.availability.kind === "unavailable";
4143
+ const disabled = !canRequestTicketOption(ticketType.availability);
4222
4144
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
4223
4145
  const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
4224
4146
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
4225
4147
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
4226
4148
  currentQuantity: quantity,
4227
4149
  totalSelectedQuantity,
4228
- maxTickets: props.maxTickets,
4229
- availableSpots: props.availableSpots,
4230
- ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
4150
+ maxTickets: props.maxTickets
4231
4151
  });
4232
4152
  return /* @__PURE__ */ jsxs("div", {
4233
4153
  className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
@@ -4332,33 +4252,13 @@ function AttendanceModeTiles(props) {
4332
4252
  })
4333
4253
  });
4334
4254
  }
4335
- function getMaxAllowedTicketCount(input) {
4336
- if (input.canJoinWaitlist) return input.maxTickets;
4337
- if (!input.usesTicketTypes) return Math.min(input.maxTickets, input.availableSpots ?? input.maxTickets);
4338
- if (!input.hasSelectedTicketType) return 1;
4339
- return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
4340
- }
4341
4255
  function resolveTicketSelectionPricing(event) {
4342
4256
  return {
4343
4257
  mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
4344
4258
  currency: event ? publicEventPricingCurrency(event.pricing) : null
4345
4259
  };
4346
4260
  }
4347
- function CheckoutRecoveryEntry(props) {
4348
- return props.onContinue ? /* @__PURE__ */ jsx("button", {
4349
- type: "button",
4350
- className: "er-back-btn",
4351
- onClick: props.onContinue,
4352
- children: "Continue an existing booking"
4353
- }) : null;
4354
- }
4355
- function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
4356
- if (checkoutRecovery) return {
4357
- availableSpots: null,
4358
- isSoldOut: false,
4359
- canJoinWaitlist: false,
4360
- eventAvailabilityLabel: null
4361
- };
4261
+ function getTicketSelectionCapacity(event, attendanceMode) {
4362
4262
  const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
4363
4263
  const availability = source ? getEventAvailability(source) : null;
4364
4264
  const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
@@ -4377,29 +4277,21 @@ function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
4377
4277
  *
4378
4278
  * Can use either a full PublicEvent or just occurrence context (when on event page).
4379
4279
  */
4380
- const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" }, checkoutRecovery = false, onCheckoutRecovery }) => {
4280
+ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
4381
4281
  const unit = bookingUnit.kind;
4382
4282
  const deliveryMode = event?.deliveryMode ?? "in_person";
4383
4283
  const attendanceModes = event?.attendanceModes ?? [];
4384
- const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
4284
+ const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode);
4385
4285
  const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
4386
- const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
4286
+ const usesTicketTypes = eventPricingMode === "tiered";
4387
4287
  const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
4388
4288
  event,
4389
4289
  eligibility: null,
4390
4290
  selectedAttendanceMode
4391
4291
  }) : [];
4392
- const implicitTicketType = usesTicketTypes ? getImplicitSingleAvailableTicketType(visibleTicketTypes) : null;
4393
4292
  const noVisibleTicketTypes = usesTicketTypes && visibleTicketTypes.length === 0;
4394
- const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => ticketType.availability.kind === "available");
4395
- const maxAllowed = getMaxAllowedTicketCount({
4396
- canJoinWaitlist,
4397
- usesTicketTypes,
4398
- maxTickets,
4399
- availableSpots,
4400
- selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
4401
- hasSelectedTicketType: implicitTicketType !== null
4402
- });
4293
+ const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => canRequestTicketOption(ticketType.availability));
4294
+ const maxAllowed = maxTickets;
4403
4295
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
4404
4296
  className: "rb-reg-stack er-stack",
4405
4297
  children: [
@@ -4418,20 +4310,6 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
4418
4310
  })
4419
4311
  ]
4420
4312
  });
4421
- if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
4422
- className: "rb-reg-stack er-stack",
4423
- children: [
4424
- /* @__PURE__ */ jsx("h3", {
4425
- className: "er-title",
4426
- children: "Sold out"
4427
- }),
4428
- /* @__PURE__ */ jsx("p", {
4429
- className: "er-text er-text--muted",
4430
- children: "Sorry you missed out! This event is fully booked."
4431
- }),
4432
- /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
4433
- ]
4434
- });
4435
4313
  if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
4436
4314
  className: "rb-reg-stack er-stack",
4437
4315
  children: /* @__PURE__ */ jsx("p", {
@@ -4498,14 +4376,14 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
4498
4376
  })]
4499
4377
  })
4500
4378
  ] }),
4501
- canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
4379
+ isSoldOut && !canJoinWaitlist && /* @__PURE__ */ jsx("p", {
4502
4380
  className: "er-text er-text--muted",
4503
- children: "This event is currently full. Continue to join the waitlist if a place opens up."
4504
- }), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
4505
- checkoutRecovery && /* @__PURE__ */ jsx("p", {
4381
+ children: "This event is fully booked."
4382
+ }),
4383
+ canJoinWaitlist && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("p", {
4506
4384
  className: "er-text er-text--muted",
4507
- children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
4508
- })
4385
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
4386
+ }) })
4509
4387
  ]
4510
4388
  });
4511
4389
  };
@@ -5100,7 +4978,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
5100
4978
  const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
5101
4979
  const selectedMethod = selectedSelection.method;
5102
4980
  const totalPrice = directPaymentTotalCents;
5103
- const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
4981
+ const canShowDirectPaymentOptions = Boolean(eligibility?.requiresPayment && eligibility.price);
5104
4982
  const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
5105
4983
  eventTitle: event?.title ?? "Event",
5106
4984
  approvedPaymentOptions: eligibility.paymentOptions,
@@ -5163,7 +5041,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
5163
5041
  onRequestLogin
5164
5042
  });
5165
5043
  if (eligibilityLoading || eligibilityError || !eligibility) return blockingPanel;
5166
- if (eligibility.isFree || !eligibility.eligible) return blockingPanel;
5044
+ if (eligibility.isFree || paymentStepStatus !== "ready") return blockingPanel;
5167
5045
  const isMultiTicket = areEntitlementsDisabledForTicketCount(ticketsCount);
5168
5046
  return /* @__PURE__ */ jsxs("div", {
5169
5047
  className: "rb-reg-stack er-stack",
@@ -5397,6 +5275,7 @@ function EventRegistrationWizardContent(props) {
5397
5275
  case "redirecting":
5398
5276
  case "verifying-payment":
5399
5277
  case "verifying-timeout":
5278
+ case "payment-status":
5400
5279
  case "payment-failed": return null;
5401
5280
  case "select-event": return /* @__PURE__ */ jsx(EventSelectionStep, {
5402
5281
  events: wizard.scopedEvents,
@@ -5412,8 +5291,6 @@ function EventRegistrationWizardContent(props) {
5412
5291
  onBookForSomeoneElse: wizard.handleBookForSomeoneElse
5413
5292
  }), /* @__PURE__ */ jsx(TicketSelectionStep, {
5414
5293
  event: wizard.selectedEvent,
5415
- checkoutRecovery: wizard.checkoutRecovery,
5416
- onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
5417
5294
  occurrenceContext: wizard.occurrenceContext,
5418
5295
  selectedAttendanceMode: wizard.selectedAttendanceMode,
5419
5296
  onAttendanceModeChange: wizard.setSelectedAttendanceMode,
@@ -5468,6 +5345,81 @@ const PaymentFailedStep = ({ onRetry }) => {
5468
5345
  });
5469
5346
  };
5470
5347
  //#endregion
5348
+ //#region ../blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.tsx
5349
+ function presentation(state) {
5350
+ switch (state.kind) {
5351
+ case "ready": return {
5352
+ title: "We haven’t confirmed your payment yet",
5353
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment. Select Check payment status to get the latest update.",
5354
+ action: { label: "Check payment status" }
5355
+ };
5356
+ case "checking": return {
5357
+ title: "We haven’t confirmed your payment yet",
5358
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment.",
5359
+ action: {
5360
+ label: "Checking payment…",
5361
+ disabled: true
5362
+ }
5363
+ };
5364
+ case "processing": return {
5365
+ title: "Your payment is still being processed",
5366
+ message: "Please don’t make another payment. You can check its status again in a moment.",
5367
+ action: { label: "Check payment status" }
5368
+ };
5369
+ case "paymentAvailable": return {
5370
+ title: "Your payment hasn’t been completed",
5371
+ message: "Your booking details are still saved. Continue to payment to finish your booking.",
5372
+ action: { label: "Continue to payment" }
5373
+ };
5374
+ case "retryAvailable": return {
5375
+ title: "Continue your booking",
5376
+ message: "You can return to payment. We’ll check your booking, any existing payment and availability before starting another checkout.",
5377
+ action: { label: "Return to payment" }
5378
+ };
5379
+ case "temporarilyUnavailable": return {
5380
+ title: "We couldn’t check your payment",
5381
+ message: "Please don’t make another payment yet. Try checking again in a moment.",
5382
+ action: { label: "Check payment status" }
5383
+ };
5384
+ case "assistanceRequired": return {
5385
+ title: "We still can’t confirm your payment",
5386
+ message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
5387
+ action: { label: "Return to booking" }
5388
+ };
5389
+ }
5390
+ }
5391
+ function PaymentStatusStep(props) {
5392
+ const view = presentation(props.state);
5393
+ const onClick = props.state.kind === "paymentAvailable" ? props.onContinuePayment : props.state.kind === "retryAvailable" ? props.onReturnToPayment : props.state.kind === "assistanceRequired" ? props.onReturnToBooking : props.onCheck;
5394
+ return /* @__PURE__ */ jsx(TerminalPanel, {
5395
+ tone: "warning",
5396
+ className: "er-center",
5397
+ titleClassName: "er-title--lg er-message",
5398
+ icon: /* @__PURE__ */ jsx(StateIcon, {
5399
+ variant: "warning",
5400
+ children: /* @__PURE__ */ jsx(ClockIcon, {})
5401
+ }),
5402
+ title: view.title,
5403
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
5404
+ className: "er-text--muted er-message",
5405
+ children: view.message
5406
+ }), /* @__PURE__ */ jsx("span", {
5407
+ className: "rb-sr-only",
5408
+ "aria-live": "polite",
5409
+ "aria-atomic": "true",
5410
+ children: props.state.kind === "checking" ? "Checking payment…" : view.title
5411
+ })] }),
5412
+ actionsClassName: "er-button-group",
5413
+ actions: view.action ? /* @__PURE__ */ jsx("button", {
5414
+ type: "button",
5415
+ onClick,
5416
+ disabled: view.action.disabled,
5417
+ className: "er-btn er-btn--primary",
5418
+ children: /* @__PURE__ */ jsx("span", { children: view.action.label })
5419
+ }) : void 0
5420
+ });
5421
+ }
5422
+ //#endregion
5471
5423
  //#region ../blocks/src/system/runtime/nodes/event-registration/StepIndicator.tsx
5472
5424
  /**
5473
5425
  * Step indicator component for the event registration wizard.
@@ -5585,7 +5537,7 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re che
5585
5537
  title,
5586
5538
  body: /* @__PURE__ */ jsx("p", {
5587
5539
  className: "er-text--muted er-message",
5588
- children: message
5540
+ children: onCheckAgain ? message : "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking."
5589
5541
  }),
5590
5542
  actionsClassName: "er-button-group",
5591
5543
  actions: onCheckAgain ? /* @__PURE__ */ jsx("button", {
@@ -5593,11 +5545,7 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re che
5593
5545
  onClick: onCheckAgain,
5594
5546
  className: "er-btn er-btn--primary",
5595
5547
  children: "Check payment status"
5596
- }) : /* @__PURE__ */ jsx("a", {
5597
- href: "/portal",
5598
- className: "er-btn er-btn--primary",
5599
- children: "Check payment status"
5600
- }),
5548
+ }) : void 0,
5601
5549
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
5602
5550
  className: "er-text--sm er-text--muted er-message",
5603
5551
  children: [
@@ -5698,6 +5646,13 @@ function EventRegistrationTerminalState(props) {
5698
5646
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
5699
5647
  supportEmail: props.supportEmail
5700
5648
  });
5649
+ case "payment-status": return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
5650
+ state: wizard.paymentStatusRecovery,
5651
+ onCheck: wizard.handleCheckPaymentStatus,
5652
+ onContinuePayment: wizard.handleContinueExistingPayment,
5653
+ onReturnToPayment: wizard.handleReturnToPayment,
5654
+ onReturnToBooking: wizard.handleReturnToBooking
5655
+ }) : null;
5701
5656
  case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
5702
5657
  title: wizard.registrationResult.title,
5703
5658
  variant: wizard.registrationResult.variant,
@@ -5706,7 +5661,7 @@ function EventRegistrationTerminalState(props) {
5706
5661
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
5707
5662
  message: wizard.errorMessage,
5708
5663
  action: wizard.errorAction,
5709
- canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
5664
+ canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
5710
5665
  onRetry: wizard.handleRetry
5711
5666
  });
5712
5667
  case "select-event":
@@ -5717,12 +5672,17 @@ function EventRegistrationTerminalState(props) {
5717
5672
  }
5718
5673
  function EventRegistrationSurface(props) {
5719
5674
  const { wizard } = props;
5675
+ const mainRef = useRef(null);
5676
+ useLayoutEffect(() => {
5677
+ if (props.variant === "overlay" && mainRef.current) mainRef.current.scrollTop = 0;
5678
+ }, [props.variant, wizard.step]);
5720
5679
  return /* @__PURE__ */ jsxs("div", {
5721
5680
  className: `rb-reg-surface er-container${props.variant === "overlay" ? " er-container--overlay" : ""}`,
5722
5681
  children: [props.isWizardStep && /* @__PURE__ */ jsxs("div", {
5723
5682
  className: "er-payment-layout er-payment-layout--no-sidebar",
5724
5683
  children: [
5725
5684
  /* @__PURE__ */ jsxs("div", {
5685
+ ref: mainRef,
5726
5686
  className: "er-payment-layout-main",
5727
5687
  children: [
5728
5688
  props.totalSteps > 1 && /* @__PURE__ */ jsx(StepIndicator, {
@@ -5748,15 +5708,14 @@ function EventRegistrationSurface(props) {
5748
5708
  children: [/* @__PURE__ */ jsx(EventRegistrationSummaryBar, { wizard }), /* @__PURE__ */ jsx(EventRegistrationWizardActions, {
5749
5709
  wizard,
5750
5710
  buttonText: props.buttonText,
5751
- buttonClass: props.buttonClass
5711
+ buttonVariant: props.buttonVariant
5752
5712
  })]
5753
5713
  })
5754
5714
  ]
5755
5715
  }), /* @__PURE__ */ jsx(EventRegistrationTerminalState, {
5756
5716
  wizard,
5757
5717
  supportEmail: props.supportEmail,
5758
- successMessage: props.successMessage,
5759
- buttonClass: props.buttonClass
5718
+ successMessage: props.successMessage
5760
5719
  })]
5761
5720
  });
5762
5721
  }
@@ -5786,11 +5745,13 @@ function BookingEntry(props) {
5786
5745
  }, ticketType.pricingOptionId))
5787
5746
  }) : null
5788
5747
  ]
5789
- }), /* @__PURE__ */ jsx("button", {
5748
+ }), /* @__PURE__ */ jsx(ThemedButton, {
5790
5749
  type: "button",
5791
- className: `${base}__cta ${props.buttonClass}`,
5792
- onClick: props.onOpen,
5793
- children: "Book now"
5750
+ variant: props.buttonVariant,
5751
+ size: "md",
5752
+ extraClassName: `${base}__cta`,
5753
+ label: "Book now",
5754
+ onClick: props.onOpen
5794
5755
  })] });
5795
5756
  }
5796
5757
  function EventRegistrationBookingLayer(props) {
@@ -5798,7 +5759,7 @@ function EventRegistrationBookingLayer(props) {
5798
5759
  summary: [props.priceLabel, props.availabilityLabel].filter(Boolean).join(" · "),
5799
5760
  ticketTypes: props.ticketTypes,
5800
5761
  ticketCurrency: props.ticketCurrency,
5801
- buttonClass: props.buttonClass,
5762
+ buttonVariant: props.buttonVariant,
5802
5763
  formatTicketPrice: props.formatTicketPrice,
5803
5764
  onOpen: props.onOpen
5804
5765
  };
@@ -5900,6 +5861,7 @@ function getWizardStepLabel(input) {
5900
5861
  case "redirecting":
5901
5862
  case "verifying-payment":
5902
5863
  case "verifying-timeout":
5864
+ case "payment-status":
5903
5865
  case "payment-failed": return "";
5904
5866
  }
5905
5867
  }
@@ -5907,10 +5869,6 @@ function EventRegistrationWizard(props) {
5907
5869
  const { occurrenceContext, subject, events, maxTickets = "5", showVenue = true, showCapacity = true, successMessage = "Thank you for registering! Check your email for confirmation details.", buttonText = "Complete Registration", buttonVariant = "primary", className, spamProtectionEnabled, supportEmail } = props;
5908
5870
  const maxTicketsNum = normalizeEventRegistrationMaxTickets(maxTickets);
5909
5871
  const showSpamProtection = spamProtectionEnabled ?? isSpamProtectionEnabled();
5910
- const buttonClass = themeButtonClassName({
5911
- variant: buttonVariant,
5912
- size: "md"
5913
- });
5914
5872
  const registrationRootClassName = `event-registration ${className || ""}`;
5915
5873
  const registrationRootRef = React.useRef(null);
5916
5874
  const wizard = useEventRegistrationWizard({
@@ -6003,7 +5961,7 @@ function EventRegistrationWizard(props) {
6003
5961
  showCapacity,
6004
5962
  showSpamProtection,
6005
5963
  buttonText,
6006
- buttonClass,
5964
+ buttonVariant,
6007
5965
  supportEmail,
6008
5966
  successMessage
6009
5967
  });
@@ -6032,7 +5990,7 @@ function EventRegistrationWizard(props) {
6032
5990
  availabilityLabel: summaryAvailabilityLabel,
6033
5991
  ticketTypes: bookingTicketTypes,
6034
5992
  ticketCurrency: bookingCurrency,
6035
- buttonClass,
5993
+ buttonVariant,
6036
5994
  formatTicketPrice: (ticketType) => formatTicketPriceIfKnown(ticketType, bookingCurrency),
6037
5995
  onOpen: () => setBookingOverlayOpen(true),
6038
5996
  onClose: () => setBookingOverlayOpen(false),
@@ -6302,14 +6260,12 @@ function RecoverableEventRegistrationClient({ props, display }) {
6302
6260
  id: EVENT_REGISTRATION_ANCHOR_ID,
6303
6261
  className: "rb-reg-surface er-container er-registration-shell",
6304
6262
  role: "alert",
6305
- children: [/* @__PURE__ */ jsx("p", { children: "We couldn’t load the event dates. Please try again." }), /* @__PURE__ */ jsx("button", {
6263
+ children: [/* @__PURE__ */ jsx("p", { children: "We couldn’t load the event dates. Please try again." }), /* @__PURE__ */ jsx(ThemedButton, {
6306
6264
  type: "button",
6307
- className: themeButtonClassName({
6308
- variant: props.render.hydration.buttonVariant ?? "primary",
6309
- size: "md"
6310
- }),
6311
- onClick: recovery.retry,
6312
- children: "Try again"
6265
+ variant: props.render.hydration.buttonVariant ?? "primary",
6266
+ size: "md",
6267
+ label: "Try again",
6268
+ onClick: recovery.retry
6313
6269
  })]
6314
6270
  });
6315
6271
  const events = resolveEventRegistrationScopedEvents(recovery.events, {
@@ -6339,6 +6295,7 @@ const enhance = (root, props) => {
6339
6295
  if (!siteId) throw new Error("[sdk:islands] event-registration requires siteId");
6340
6296
  if (!apiBaseUrl) throw new Error("[sdk:islands] event-registration requires apiBaseUrl");
6341
6297
  const apiConfig = buildRouteIslandApiConfig({
6298
+ readAuthority: props.readAuthority,
6342
6299
  apiBaseUrl,
6343
6300
  portalToken,
6344
6301
  previewToken,