@riverbankcms/sdk 0.134.0 → 0.135.1

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 (258) hide show
  1. package/CHANGELOG.md +4 -3
  2. package/README.md +1 -1
  3. package/dist/{PreviewEditorSidebar-DfRhJPFQ.mjs → PreviewEditorSidebar-D4p_5TdY.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-Dppxcr_g.mjs → PreviewEditorUI-D0cRoTX1.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-D51gQaG3.mjs → PreviewQueryProvider-DcgaESkm.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-8CyGCXir.mjs → SdkPreviewModeRuntime-BKLtM3Nz.mjs} +5 -5
  7. package/dist/{SiteChromeCustomizeContext-DVMTMvqA.mjs → SiteChromeCustomizeContext-61X2m7QV.mjs} +4105 -8035
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +165 -165
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +15 -15
  10. package/dist/_dts/api/src/bookingConfig.d.ts +1 -1
  11. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +25 -60
  12. package/dist/_dts/api/src/bookingOperations.d.ts +111 -161
  13. package/dist/_dts/api/src/bookingPaymentTermSchemas.d.ts +123 -0
  14. package/dist/_dts/api/src/bookingRecords.d.ts +13 -13
  15. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +4 -4
  16. package/dist/_dts/api/src/bookingSessionSummaryTypes.d.ts +34 -0
  17. package/dist/_dts/api/src/bookings.d.ts +5 -9
  18. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +7 -7
  19. package/dist/_dts/api/src/communications.d.ts +1 -1
  20. package/dist/_dts/api/src/endpoints.d.ts +29 -109
  21. package/dist/_dts/api/src/eventManagementContracts.d.ts +1 -1
  22. package/dist/_dts/api/src/eventSeriesRegistrationEndpointDefinitions.d.ts +43 -0
  23. package/dist/_dts/api/src/index.d.ts +3 -4
  24. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  25. package/dist/_dts/api/src/participantMessaging.d.ts +2 -2
  26. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +8 -0
  27. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +32 -28
  28. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +85 -5
  29. package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +1 -1
  30. package/dist/_dts/api/src/publicExperience/wholeSeriesEndpoints.d.ts +9 -100
  31. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +7 -6
  32. package/dist/_dts/api/src/publicWholeSeriesEndpointDefinitions.d.ts +0 -32
  33. package/dist/_dts/api/src/sdk-event-payment-terms.d.ts +1 -1
  34. package/dist/_dts/api/src/sdk-event-upsert.d.ts +1 -1
  35. package/dist/_dts/api/src/siteOperations.d.ts +2 -2
  36. package/dist/_dts/api/src/types.d.ts +1 -1
  37. package/dist/_dts/api/src/{courses.d.ts → wholeSeriesOfferings.d.ts} +43 -95
  38. package/dist/_dts/blocks/src/client.d.ts +0 -5
  39. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -1
  40. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +5 -94
  41. package/dist/_dts/blocks/src/portal/dateFormatting.d.ts +3 -0
  42. package/dist/_dts/blocks/src/portal/types.d.ts +17 -20
  43. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +147 -42
  44. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +35 -10
  45. package/dist/_dts/blocks/src/system/blocks/events/whole-series/types.d.ts +3 -0
  46. package/dist/_dts/blocks/src/system/blocks/index.d.ts +0 -2
  47. package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +3 -3
  48. package/dist/_dts/blocks/src/system/blocks/offerings-preview/scheduleSummary.d.ts +3 -3
  49. package/dist/_dts/blocks/src/system/constants/blockKinds.d.ts +1 -1
  50. package/dist/_dts/blocks/src/system/node/builder.d.ts +0 -1
  51. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +9 -12
  52. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +2 -44
  53. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  54. package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +99 -59
  56. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +1 -1
  57. package/dist/_dts/blocks/src/system/runtime/api/types/shop.d.ts +19 -16
  58. package/dist/_dts/blocks/src/system/runtime/api/types/waitlist-claims.d.ts +7 -0
  59. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +1 -1
  60. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +24 -247
  61. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +13 -126
  62. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +0 -1
  63. package/dist/_dts/blocks/src/system/runtime/hooks/usePaymentVerification.d.ts +2 -3
  64. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/WholeSeriesPricingDisplay.d.ts +8 -0
  65. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationBookingLayer.d.ts +17 -0
  66. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +24 -0
  67. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentBlockingPanel.d.ts +18 -0
  68. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +5 -0
  69. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/constants.d.ts +1 -0
  70. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +1 -3
  71. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +7 -4
  72. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventScope.d.ts +0 -1
  73. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +7 -8
  74. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/index.d.ts +1 -1
  75. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +4 -4
  76. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.d.ts +3 -0
  77. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.d.ts +5 -0
  78. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +28 -0
  79. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +12 -11
  80. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +53 -45
  81. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +10 -6
  82. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +9 -1
  83. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +20 -5
  84. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +20 -0
  85. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +5 -56
  86. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/waitlistClaimRestoration.d.ts +20 -0
  87. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +6 -22
  88. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DateTimeTile.d.ts +1 -1
  89. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +16 -6
  90. package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview.d.ts +2 -2
  91. package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptions.d.ts +6 -1
  92. package/dist/_dts/blocks/src/system/runtime/shared/components/DiscountCodeDisclosure.d.ts +1 -13
  93. package/dist/_dts/blocks/src/system/runtime/shared/components/LoggedInAsUser.d.ts +1 -1
  94. package/dist/_dts/blocks/src/system/runtime/shared/components/MembershipHero.d.ts +1 -1
  95. package/dist/_dts/blocks/src/system/runtime/shared/components/StateIcon.d.ts +1 -1
  96. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +1 -1
  97. package/dist/_dts/blocks/src/system/runtime/shared/types.d.ts +1 -1
  98. package/dist/_dts/blocks/src/system/runtime/shared/utils/checkoutUrls.d.ts +2 -2
  99. package/dist/_dts/commerce/src/index.d.ts +16 -0
  100. package/dist/_dts/commerce/src/money.d.ts +122 -0
  101. package/dist/_dts/commerce/src/moneyContracts.d.ts +178 -0
  102. package/dist/_dts/commerce/src/moneyDateUtils.d.ts +22 -0
  103. package/dist/_dts/commerce/src/moneyPayments.d.ts +59 -0
  104. package/dist/_dts/commerce/src/moneyPlanningTime.d.ts +4 -0
  105. package/dist/_dts/commerce/src/moneyReceiptReadModel.d.ts +68 -0
  106. package/dist/_dts/commerce/src/moneyReport.d.ts +105 -0
  107. package/dist/_dts/commerce/src/moneyReportBreakdowns.d.ts +3 -0
  108. package/dist/_dts/commerce/src/moneyReportKindFilter.d.ts +4 -0
  109. package/dist/_dts/commerce/src/moneyReportPage.d.ts +132 -0
  110. package/dist/_dts/commerce/src/purchase/checkoutCollectionPlan.d.ts +1 -1
  111. package/dist/_dts/commerce/src/purchase/confirmationEmailPayment.d.ts +1 -1
  112. package/dist/_dts/commerce/src/purchase/orderCompletionEmailPlan.d.ts +3 -3
  113. package/dist/_dts/commerce/src/purchase/orderFulfillmentPlan.d.ts +6 -25
  114. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +4 -4
  115. package/dist/_dts/commerce/src/purchase/orderPlanningTypes.d.ts +11 -11
  116. package/dist/_dts/commerce/src/purchase/orderTypes.d.ts +1 -1
  117. package/dist/_dts/commerce/src/purchase/persistedCheckoutLines.d.ts +1 -1
  118. package/dist/_dts/commerce/src/purchase/types.d.ts +12 -8
  119. package/dist/_dts/commerce/src/shop/digitalFulfillment.d.ts +111 -0
  120. package/dist/_dts/commerce/src/shop/fulfillmentStatus.d.ts +10 -0
  121. package/dist/_dts/commerce/src/shop/inventoryRestore.d.ts +13 -0
  122. package/dist/_dts/commerce/src/shop/shippingAddress.d.ts +18 -0
  123. package/dist/_dts/commerce/src/types/json.d.ts +3 -0
  124. package/dist/_dts/commerce/src/utils/isPlainRecord.d.ts +1 -0
  125. package/dist/_dts/commerce/src/waitlists.d.ts +172 -0
  126. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +0 -30
  127. package/dist/_dts/content-model/src/content-types/builtins.d.ts +2 -39
  128. package/dist/_dts/content-model/src/metadataConfig.d.ts +0 -1
  129. package/dist/_dts/content-model/src/templates/defaults.d.ts +0 -68
  130. package/dist/_dts/core/src/branded.d.ts +3 -3
  131. package/dist/_dts/core/src/event-pricing.d.ts +6 -6
  132. package/dist/_dts/core/src/participants.d.ts +17 -17
  133. package/dist/_dts/core/src/rectification.d.ts +1 -1
  134. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +890 -2154
  135. package/dist/_dts/sdk/src/bookings/index.d.ts +4 -5
  136. package/dist/_dts/sdk/src/bookings/types.d.ts +34 -4
  137. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +4 -6
  138. package/dist/_dts/sdk/src/version.d.ts +1 -1
  139. package/dist/_dts/theme-core/src/blocks/vars/index.d.ts +0 -2
  140. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  141. package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +1 -1
  142. package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +1 -1
  143. package/dist/client/{usePolling-UN4WKnaM.mjs → BookingConsentAgreement-Bz9znbpn.mjs} +180 -4
  144. package/dist/client/{DiscountCodeDisclosure-CfuPOHD0.mjs → DiscountCodeDisclosure-35Ru8yB9.mjs} +13 -27
  145. package/dist/client/{EventCombined.client-DB8Qfzi-.mjs → EventCombined.client-BKB0ZxRR.mjs} +3 -3
  146. package/dist/client/{EventListing.client-DD4X8hp4.mjs → EventListing.client-Dx8I21ok.mjs} +2 -2
  147. package/dist/client/{LeafletStaticMap-QhgIBQbv.mjs → LeafletStaticMap-CEWx-Bhe.mjs} +1 -1
  148. package/dist/client/{accordion-DFXpLvwg.mjs → accordion-KIDsKTwS.mjs} +1 -1
  149. package/dist/client/{bookingForm-sI05d3lk.mjs → bookingForm-D96Rmp-5.mjs} +6 -7
  150. package/dist/client/bookings.mjs +913 -1906
  151. package/dist/client/{carousel-wjyWTZCh.mjs → carousel-YwUgyL66.mjs} +1 -1
  152. package/dist/client/{cart-DCwdpA4i.mjs → cart-BbwuNrUT.mjs} +3 -3
  153. package/dist/client/{checkout-DTDW3l0R.mjs → checkout-hp1ucmEY.mjs} +3 -3
  154. package/dist/client/{checkoutUrls-DQYC_Br-.mjs → checkoutUrls-BuseL0dw.mjs} +4 -2
  155. package/dist/client/client.mjs +5109 -9333
  156. package/dist/client/{context-TSK1CGx8.mjs → context-DljQn8L5.mjs} +15 -69
  157. package/dist/client/{eventCalendar-B0Zg-i_w.mjs → eventCalendar-DU4iNLpo.mjs} +5 -5
  158. package/dist/client/{eventCombined-B8Y2wizd.mjs → eventCombined-CZuupW8m.mjs} +3 -3
  159. package/dist/client/{eventDetails-DPDOwURJ.mjs → eventDetails-DPQWwCIi.mjs} +8 -8
  160. package/dist/client/{eventListing-CjBcmSLn.mjs → eventListing-C7oMidwS.mjs} +3 -3
  161. package/dist/client/{eventRegistration-CK30HsAq.mjs → eventRegistration-zEiunlUs.mjs} +4522 -3690
  162. package/dist/client/{form-CUXfsABE.mjs → form-D2KIyCVJ.mjs} +2 -2
  163. package/dist/client/{headerSection-N-mN3rjr.mjs → headerSection-CK5uChUK.mjs} +2 -2
  164. package/dist/client/hooks.mjs +459 -714
  165. package/dist/client/{locationMap-oiIDQMBt.mjs → locationMap-DLQNH1ln.mjs} +2 -2
  166. package/dist/client/{newsletterForm-CkQ2tTrM.mjs → newsletterForm-ZuhIG7fZ.mjs} +2 -2
  167. package/dist/client/{productDetail-CnidyrsN.mjs → productDetail-7hIcGeae.mjs} +3 -3
  168. package/dist/client/{productList-CttYcS_S.mjs → productList-T4Cii1ot.mjs} +3 -3
  169. package/dist/client/{propsDecoder-CeUMxI9a.mjs → propsDecoder-mB0aC_Fi.mjs} +4702 -4458
  170. package/dist/client/rendering/client.mjs +59617 -62260
  171. package/dist/client/rendering/islands.mjs +17 -19
  172. package/dist/client/rendering.mjs +5389 -9707
  173. package/dist/client/{scrollToBlock-lPr1oqxB.mjs → scrollToBlock-Du5mHgvL.mjs} +2 -2
  174. package/dist/client/{shop-DXQtMo2O.mjs → shop-B5zAcKZn.mjs} +6 -6
  175. package/dist/client/{shop-commerce-quDL411J.mjs → shop-commerce-BKBZB6l5.mjs} +6 -6
  176. package/dist/client/{shop-commerce-store-Dnu-8Iub.mjs → shop-commerce-store-Cq4qlNtQ.mjs} +1 -1
  177. package/dist/client/{shopShared-BWPUURvG.mjs → shopShared-DYGzEs9D.mjs} +3 -3
  178. package/dist/client/{useEventFilters-DRhWp2_5.mjs → useEventFilters-Bphkda8m.mjs} +3 -3
  179. package/dist/preview-next/before-render.mjs +40 -161
  180. package/dist/preview-next/client/runtime.mjs +4 -4
  181. package/dist/preview-next/keepAlive.mjs +40 -161
  182. package/dist/preview-next/middleware.mjs +40 -161
  183. package/dist/{previewAuthStore-BFKd4LrN.mjs → previewAuthStore-C7ksxt5b.mjs} +40 -161
  184. package/dist/{sdk-runtime-Ca5RD78X.mjs → sdk-runtime-BbIC8G4J.mjs} +2 -2
  185. package/dist/{separator-CMhj6BTi.mjs → separator-CadhAtI7.mjs} +1 -1
  186. package/dist/server/components.mjs +558 -2962
  187. package/dist/server/config-validation.mjs +459 -714
  188. package/dist/server/config.mjs +459 -714
  189. package/dist/server/data.mjs +459 -714
  190. package/dist/server/index.mjs +41 -162
  191. package/dist/server/next.mjs +572 -2976
  192. package/dist/server/page-converter.mjs +360 -582
  193. package/dist/server/prebuild.mjs +1 -1
  194. package/dist/server/rendering/server.mjs +569 -2879
  195. package/dist/server/rendering.mjs +558 -2962
  196. package/dist/server/routing.mjs +603 -1087
  197. package/dist/server/server.mjs +473 -728
  198. package/dist/server/theme-bridge.mjs +41 -1524
  199. package/dist/styles/index.css +41 -1348
  200. package/package.json +1 -1
  201. package/dist/_dts/api/src/courseEndpointDefinitions.d.ts +0 -99
  202. package/dist/_dts/blocks/src/client/course-registration.d.ts +0 -5
  203. package/dist/_dts/blocks/src/system/blocks/course-details.d.ts +0 -134
  204. package/dist/_dts/blocks/src/system/blocks/course-registration.d.ts +0 -130
  205. package/dist/_dts/blocks/src/system/blocks/courses/shared/index.d.ts +0 -3
  206. package/dist/_dts/blocks/src/system/blocks/courses/shared/pricing.d.ts +0 -2
  207. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +0 -1
  208. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +0 -1
  209. package/dist/_dts/blocks/src/system/runtime/api/types/courses.d.ts +0 -135
  210. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.d.ts +0 -28
  211. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/logic.d.ts +0 -11
  212. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/runs.d.ts +0 -10
  213. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/view.d.ts +0 -15
  214. package/dist/_dts/blocks/src/system/runtime/nodes/course-details.server.d.ts +0 -20
  215. package/dist/_dts/blocks/src/system/runtime/nodes/course-page-surface-scope.d.ts +0 -14
  216. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.client.d.ts +0 -10
  217. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.interactive.d.ts +0 -181
  218. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.server.d.ts +0 -12
  219. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/CoursePricingDisplay.d.ts +0 -8
  220. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/BookingModeStep.d.ts +0 -32
  221. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/CheckIcon.d.ts +0 -4
  222. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/ErrorStep.d.ts +0 -17
  223. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/MembershipHero.d.ts +0 -12
  224. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/PaymentFailedStep.d.ts +0 -17
  225. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/PortalAuthSidebar.d.ts +0 -9
  226. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/StepIndicator.d.ts +0 -6
  227. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/SuccessStep.d.ts +0 -14
  228. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/VerifyingTimeoutStep.d.ts +0 -17
  229. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WaitlistStep.d.ts +0 -12
  230. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationActiveSteps.d.ts +0 -9
  231. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationErrorBoundary.d.ts +0 -25
  232. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationTerminalContent.d.ts +0 -8
  233. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationWizard.d.ts +0 -8
  234. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/components.d.ts +0 -46
  235. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/index.d.ts +0 -18
  236. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/presentation.d.ts +0 -7
  237. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/pricing.d.ts +0 -14
  238. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/types.d.ts +0 -105
  239. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesEligibility.d.ts +0 -24
  240. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesPaymentVerification.d.ts +0 -10
  241. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationActions.d.ts +0 -35
  242. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationPortal.d.ts +0 -7
  243. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationSelection.d.ts +0 -35
  244. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationWizard.d.ts +0 -185
  245. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesWaitlistSelection.d.ts +0 -14
  246. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/utils.d.ts +0 -43
  247. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/whole-series-registration.headless.contract.d.ts +0 -325
  248. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/whole-series-registration.headless.planning.d.ts +0 -27
  249. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesPageSurfaceScope.d.ts +0 -17
  250. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesRegistrationViewState.d.ts +0 -21
  251. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/wizardSteps.d.ts +0 -30
  252. package/dist/_dts/sdk/src/rendering/islands/enhancers/courseRegistration.d.ts +0 -3
  253. package/dist/_dts/theme-core/src/blocks/vars/course-details.d.ts +0 -16
  254. package/dist/_dts/theme-core/src/blocks/vars/course-registration.d.ts +0 -21
  255. package/dist/client/BookingConsentAgreement-BxgpGEFD.mjs +0 -160
  256. package/dist/client/WholeSeriesRegistrationWizard-DwtC7bCs.mjs +0 -2546
  257. package/dist/client/courseRegistration-A-Tg7qw_.mjs +0 -52
  258. package/dist/client/pricing-Caa0QWzh.mjs +0 -195
@@ -2557,8 +2557,8 @@ const EVENTS = {
2557
2557
  path: "/public/sites/{siteId}/events/checkout",
2558
2558
  method: "POST"
2559
2559
  },
2560
- checkEligibility: {
2561
- path: "/public/sites/{siteId}/events/check-eligibility",
2560
+ registrationOptions: {
2561
+ path: "/public/sites/{siteId}/events/registration-options",
2562
2562
  method: "POST",
2563
2563
  authScope: "portal"
2564
2564
  },
@@ -2572,31 +2572,10 @@ const WHOLE_SERIES = {
2572
2572
  path: "/public/sites/{siteId}/dated-offerings/whole-series",
2573
2573
  method: "GET"
2574
2574
  },
2575
- enroll: {
2576
- path: "/public/sites/{siteId}/dated-offerings/whole-series/enroll",
2577
- method: "POST",
2578
- authScope: "portal",
2579
- skipPreviewStage: true
2580
- },
2581
- checkout: {
2582
- path: "/public/sites/{siteId}/dated-offerings/whole-series/checkout",
2583
- method: "POST",
2584
- authScope: "portal"
2585
- },
2586
- checkEligibility: {
2587
- path: "/public/sites/{siteId}/dated-offerings/whole-series/check-eligibility",
2588
- method: "POST",
2589
- authScope: "portal"
2590
- },
2591
2575
  waitlistClaimResolve: {
2592
2576
  path: "/public/sites/{siteId}/waitlists/claim/resolve",
2593
2577
  method: "POST",
2594
2578
  authScope: "portal"
2595
- },
2596
- registrationStatus: {
2597
- path: "/public/sites/{siteId}/dated-offerings/whole-series/registration-status",
2598
- method: "GET",
2599
- authScope: "portal"
2600
2579
  }
2601
2580
  };
2602
2581
  const SHOP = {
@@ -2757,19 +2736,19 @@ const PORTAL = {
2757
2736
  skipPreviewStage: true
2758
2737
  },
2759
2738
  getWholeSeriesBookingQuestions: {
2760
- path: "/portal/dated-offerings/whole-series/{enrollmentId}/booking-questions",
2739
+ path: "/portal/dated-offerings/whole-series/{registrationId}/booking-questions",
2761
2740
  method: "GET",
2762
2741
  authScope: "portal",
2763
2742
  skipPreviewStage: true
2764
2743
  },
2765
2744
  updateWholeSeriesBookingQuestions: {
2766
- path: "/portal/dated-offerings/whole-series/{enrollmentId}/booking-questions",
2745
+ path: "/portal/dated-offerings/whole-series/{registrationId}/booking-questions",
2767
2746
  method: "PUT",
2768
2747
  authScope: "portal",
2769
2748
  skipPreviewStage: true
2770
2749
  },
2771
2750
  cancelWholeSeriesRegistration: {
2772
- path: "/portal/dated-offerings/whole-series/{enrollmentId}/cancel",
2751
+ path: "/portal/dated-offerings/whole-series/{registrationId}/cancel",
2773
2752
  method: "POST",
2774
2753
  authScope: "portal",
2775
2754
  skipPreviewStage: true
@@ -3165,10 +3144,10 @@ function createBlockApi(config) {
3165
3144
  body: data
3166
3145
  });
3167
3146
  },
3168
- async checkEligibility(data) {
3147
+ async getRegistrationOptions(data) {
3169
3148
  const sid = requireSiteId();
3170
- const path = buildPath(EVENTS.checkEligibility.path, { siteId: sid });
3171
- return request(EVENTS.checkEligibility, {
3149
+ const path = buildPath(EVENTS.registrationOptions.path, { siteId: sid });
3150
+ return request(EVENTS.registrationOptions, {
3172
3151
  path,
3173
3152
  body: data
3174
3153
  });
@@ -3178,26 +3157,10 @@ function createBlockApi(config) {
3178
3157
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
3179
3158
  return request(EVENTS.registrationStatus, {
3180
3159
  path,
3181
- query: { attendeeId: params.attendeeId },
3160
+ query: params,
3182
3161
  skipDedup: true
3183
3162
  });
3184
3163
  },
3185
- async registerForWholeSeries(data) {
3186
- const sid = requireSiteId();
3187
- const path = buildPath(WHOLE_SERIES.enroll.path, { siteId: sid });
3188
- return request(WHOLE_SERIES.enroll, {
3189
- path,
3190
- body: data
3191
- });
3192
- },
3193
- async checkWholeSeriesEligibility(data) {
3194
- const sid = requireSiteId();
3195
- const path = buildPath(WHOLE_SERIES.checkEligibility.path, { siteId: sid });
3196
- return request(WHOLE_SERIES.checkEligibility, {
3197
- path,
3198
- body: data
3199
- });
3200
- },
3201
3164
  async resolveWaitlistClaim(data) {
3202
3165
  const sid = requireSiteId();
3203
3166
  const path = buildPath(WHOLE_SERIES.waitlistClaimResolve.path, { siteId: sid });
@@ -3206,23 +3169,6 @@ function createBlockApi(config) {
3206
3169
  body: { claimToken: data.claimToken }
3207
3170
  });
3208
3171
  },
3209
- async createWholeSeriesCheckout(data) {
3210
- const sid = requireSiteId();
3211
- const path = buildPath(WHOLE_SERIES.checkout.path, { siteId: sid });
3212
- return request(WHOLE_SERIES.checkout, {
3213
- path,
3214
- body: data
3215
- });
3216
- },
3217
- async getWholeSeriesRegistrationStatus(params) {
3218
- const sid = requireSiteId();
3219
- const path = buildPath(WHOLE_SERIES.registrationStatus.path, { siteId: sid });
3220
- return request(WHOLE_SERIES.registrationStatus, {
3221
- path,
3222
- query: { sessionId: params.sessionId },
3223
- skipDedup: true
3224
- });
3225
- },
3226
3172
  async getDiscountsAvailable(data) {
3227
3173
  const sid = requireSiteId();
3228
3174
  const path = buildPath(DISCOUNTS.available.path, { siteId: sid });
@@ -3393,19 +3339,19 @@ function createBlockApi(config) {
3393
3339
  async getPortalWholeSeriesRegistrations() {
3394
3340
  return (await request(PORTAL.getWholeSeriesRegistrations)).enrollments;
3395
3341
  },
3396
- async getPortalWholeSeriesBookingQuestions(enrollmentId) {
3397
- const path = buildPath(PORTAL.getWholeSeriesBookingQuestions.path, { enrollmentId });
3342
+ async getPortalWholeSeriesBookingQuestions(registrationId) {
3343
+ const path = buildPath(PORTAL.getWholeSeriesBookingQuestions.path, { registrationId });
3398
3344
  return (await request(PORTAL.getWholeSeriesBookingQuestions, { path })).task;
3399
3345
  },
3400
- async updatePortalWholeSeriesBookingQuestions(enrollmentId, data) {
3401
- const path = buildPath(PORTAL.updateWholeSeriesBookingQuestions.path, { enrollmentId });
3346
+ async updatePortalWholeSeriesBookingQuestions(registrationId, data) {
3347
+ const path = buildPath(PORTAL.updateWholeSeriesBookingQuestions.path, { registrationId });
3402
3348
  return (await request(PORTAL.updateWholeSeriesBookingQuestions, {
3403
3349
  path,
3404
3350
  body: data
3405
3351
  })).task;
3406
3352
  },
3407
- async cancelWholeSeriesRegistration(enrollmentId, options) {
3408
- const path = buildPath(PORTAL.cancelWholeSeriesRegistration.path, { enrollmentId });
3353
+ async cancelWholeSeriesRegistration(registrationId, options) {
3354
+ const path = buildPath(PORTAL.cancelWholeSeriesRegistration.path, { registrationId });
3409
3355
  return (await request(PORTAL.cancelWholeSeriesRegistration, {
3410
3356
  path,
3411
3357
  body: options ?? {}
@@ -3560,7 +3506,7 @@ function CheckIcon({ className, strokeWidth = 2 }) {
3560
3506
  * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
3561
3507
  *
3562
3508
  * Layout is provided by shared `rb-state-icon` CSS; color variants are
3563
- * block-scoped (e.g., scoped to `[data-block="course-registration"]`).
3509
+ * block-scoped by the owning registration surface.
3564
3510
  */
3565
3511
  function StateIcon({ variant, children }) {
3566
3512
  return /* @__PURE__ */ jsx("div", {
@@ -3714,11 +3660,6 @@ function subtractDaysFromIso(isoString, dayCount) {
3714
3660
  return addDaysToIso(isoString, -dayCount);
3715
3661
  }
3716
3662
  //#endregion
3717
- //#region ../core/src/assert-never.ts
3718
- function assertNever$3(value, message = "Unexpected variant") {
3719
- throw new Error(`${message}: ${String(value)}`);
3720
- }
3721
- //#endregion
3722
3663
  //#region ../core/src/currency-format.ts
3723
3664
  const CURRENCY_LOCALE_BY_CODE = {
3724
3665
  USD: "en-US",
@@ -3773,7 +3714,7 @@ function publicEventPricingType(pricing) {
3773
3714
  case "single_paid":
3774
3715
  case "ticket_types":
3775
3716
  case "sliding_scale":
3776
- case "course": return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
3717
+ case "whole_series": return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
3777
3718
  case "external": return "external";
3778
3719
  }
3779
3720
  }
@@ -3787,7 +3728,7 @@ function publicEventPricingMode(pricing) {
3787
3728
  case "ticket_types": return "ticket_types";
3788
3729
  case "sliding_scale": return "sliding_scale";
3789
3730
  case "drop_in":
3790
- case "course":
3731
+ case "whole_series":
3791
3732
  case "external": return;
3792
3733
  }
3793
3734
  }
@@ -3797,7 +3738,7 @@ function publicEventTicketTypes(pricing) {
3797
3738
  function isFreePublicEventPriceDisplay(display) {
3798
3739
  switch (display.kind) {
3799
3740
  case "free": return true;
3800
- case "course": return display.display.kind === "free";
3741
+ case "whole_series": return display.display.kind === "free";
3801
3742
  case "exact":
3802
3743
  case "from":
3803
3744
  case "range":
@@ -5629,6 +5570,22 @@ function formatPrice(cents, currency = "GBP", locale) {
5629
5570
  }
5630
5571
  //#endregion
5631
5572
  //#region ../blocks/src/system/runtime/shared/bookingPaymentOptions.ts
5573
+ function resolveBookingPaymentDueNowCents(input) {
5574
+ switch (input.option.kind) {
5575
+ case "upfront": return input.totalCents;
5576
+ case "deferred_manual": return 0;
5577
+ case "instalment_plan": return buildInstalmentSchedulePreview({
5578
+ totalCents: input.totalCents,
5579
+ option: input.option,
5580
+ bookingStartAt: input.bookingStartAt
5581
+ })[0]?.amountCents ?? input.totalCents;
5582
+ case "flexible_balance": return resolveFlexibleBalanceInitialPaymentCents({
5583
+ totalAmountCents: input.totalCents,
5584
+ config: input.option.config
5585
+ });
5586
+ default: return assertNever(input.option);
5587
+ }
5588
+ }
5632
5589
  function buildBookingPaymentSelectionViewModel(input) {
5633
5590
  const currency = input.priceCurrency ?? "USD";
5634
5591
  const totalCents = Math.max(0, input.priceAmount ?? 0);
@@ -5690,7 +5647,11 @@ function buildBookingPaymentOptionViewModel(input) {
5690
5647
  option: input.option,
5691
5648
  bookingStartAt: input.bookingStartAt
5692
5649
  });
5693
- const dueToday = schedulePreview[0]?.amountCents ?? input.totalCents;
5650
+ const dueToday = resolveBookingPaymentDueNowCents({
5651
+ option: input.option,
5652
+ totalCents: input.totalCents,
5653
+ bookingStartAt: input.bookingStartAt
5654
+ });
5694
5655
  const futureRows = schedulePreview.slice(1);
5695
5656
  const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
5696
5657
  const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
@@ -12412,32 +12373,18 @@ function StepIndicator({ currentStep, totalSteps, stepLabels, classPrefix, emitS
12412
12373
  }
12413
12374
  //#endregion
12414
12375
  //#region ../blocks/src/system/runtime/shared/components/DiscountCodeDisclosure.tsx
12415
- const BLOCK_DISCOUNT_CODE_DISCLOSURE_CLASSES = {
12416
- "whole-series-registration": {
12417
- root: "er-whole-series-discount",
12418
- toggle: "er-whole-series-discount__toggle",
12419
- form: "er-whole-series-discount__form",
12420
- label: "er-whole-series-discount__label",
12421
- row: "er-whole-series-discount__row",
12422
- input: "er-whole-series-discount__input",
12423
- apply: "er-whole-series-discount__apply",
12424
- remove: "er-whole-series-discount__remove",
12425
- hint: "er-whole-series-discount__hint",
12426
- feedback: "er-whole-series-discount__feedback"
12427
- },
12428
- "event-registration": {
12429
- root: "er-discount",
12430
- toggle: "er-discount__toggle",
12431
- form: "er-discount__form",
12432
- label: "er-discount__label",
12433
- row: "er-discount__row",
12434
- input: "er-discount__input",
12435
- apply: "er-discount__apply",
12436
- remove: "er-discount__remove",
12437
- hint: "er-discount__hint",
12438
- feedback: "er-discount__feedback"
12439
- }
12440
- };
12376
+ const BLOCK_DISCOUNT_CODE_DISCLOSURE_CLASSES = { "event-registration": {
12377
+ root: "er-discount",
12378
+ toggle: "er-discount__toggle",
12379
+ form: "er-discount__form",
12380
+ label: "er-discount__label",
12381
+ row: "er-discount__row",
12382
+ input: "er-discount__input",
12383
+ apply: "er-discount__apply",
12384
+ remove: "er-discount__remove",
12385
+ hint: "er-discount__hint",
12386
+ feedback: "er-discount__feedback"
12387
+ } };
12441
12388
  const themeFormClasses = {
12442
12389
  root: "rb-flex rb-flex-col rb-gap-2 rb-mb-4",
12443
12390
  toggle: `${["button", "link"].join("-")} rb-self-start`,
@@ -14121,17 +14068,19 @@ const blockBookingPaymentTermsSchema = z.object({ allowedOptions: z.array(blockB
14121
14068
  * and include the block anchor hash for post-redirect scroll targeting.
14122
14069
  *
14123
14070
  * @param paramName - Query parameter name to add (e.g., 'enrollment', 'registration')
14124
- * @param anchorId - Block anchor ID for hash fragment (e.g., 'course-registration')
14071
+ * @param anchorId - Block anchor ID for the return URL hash fragment.
14125
14072
  * @returns Object with success and cancel URLs
14126
14073
  */
14127
- function buildCheckoutReturnUrls(paramName, anchorId) {
14074
+ function buildCheckoutReturnUrls(paramName, anchorId, returnParams = {}) {
14128
14075
  const currentUrl = new URL(window.location.href);
14129
14076
  const hash = `#${anchorId}`;
14130
14077
  const successParams = new URLSearchParams(currentUrl.search);
14131
14078
  successParams.set(paramName, "success");
14079
+ for (const [name, value] of Object.entries(returnParams)) successParams.set(name, value);
14132
14080
  const successUrl = `${currentUrl.origin}${currentUrl.pathname}?${successParams.toString()}${hash}`;
14133
14081
  const cancelParams = new URLSearchParams(currentUrl.search);
14134
14082
  cancelParams.set(paramName, "cancelled");
14083
+ for (const [name, value] of Object.entries(returnParams)) cancelParams.set(name, value);
14135
14084
  return {
14136
14085
  successUrl,
14137
14086
  cancelUrl: `${currentUrl.origin}${currentUrl.pathname}?${cancelParams.toString()}${hash}`
@@ -14156,65 +14105,24 @@ function scrollToBlock(anchorId) {
14156
14105
  //#endregion
14157
14106
  //#region ../blocks/src/system/runtime/shared/utils/urlParams.ts
14158
14107
  /**
14159
- * URL param helpers for client-side "return from redirect" flows.
14160
- *
14161
- * Used for flows like magic-link login or Stripe checkout return URLs where
14162
- * we want to:
14163
- * - read a query param once
14164
- * - remove it from the URL (so refresh doesn't re-trigger)
14165
- * - preserve hash fragments
14166
- */
14167
- /**
14168
- * Consume a query param from the current URL's search string.
14108
+ * Consume multiple query params from the current URL's search string.
14169
14109
  *
14170
- * Returns the param value (if present) and removes it from the URL via
14171
- * history.replaceState, preserving hash.
14110
+ * Returns a record of consumed values (missing params are null) and removes
14111
+ * all provided params from the URL in a single replaceState call.
14172
14112
  */
14173
- function consumeSearchParam(paramName) {
14113
+ function consumeSearchParams(paramNames) {
14174
14114
  const url = new URL(window.location.href);
14175
- const value = url.searchParams.get(paramName);
14176
- if (value === null) return null;
14177
- url.searchParams.delete(paramName);
14178
- const newUrl = url.pathname + (url.search ? url.search : "") + url.hash;
14179
- window.history.replaceState({}, "", newUrl);
14180
- return value;
14181
- }
14182
- //#endregion
14183
- //#region ../blocks/src/system/runtime/shared/utils/validation.ts
14184
- const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
14185
- /**
14186
- * Validate registration form data.
14187
- *
14188
- * Only `name` and `email` are required fields. The `phone` and `notes` fields
14189
- * are optional and not validated by this function.
14190
- *
14191
- * @param data - Form data to validate
14192
- * @returns Object with field errors (empty if valid)
14193
- */
14194
- function validateFormData$1(data) {
14195
- const errors = {};
14196
- if (!data.name.trim()) errors.name = "Name is required";
14197
- if (!data.email.trim()) errors.email = "Email is required";
14198
- else if (!EMAIL_REGEX.test(data.email.trim())) errors.email = "Please enter a valid email";
14199
- return errors;
14200
- }
14201
- //#endregion
14202
- //#region ../blocks/src/system/runtime/shared/utils/wizardSteps.ts
14203
- /**
14204
- * Shared Wizard Step Utilities
14205
- *
14206
- * Helpers for wizard step navigation in registration blocks.
14207
- */
14208
- /**
14209
- * Get the 1-based step number for a step in the wizard.
14210
- *
14211
- * @param step - The step to find
14212
- * @param wizardSteps - Array of wizard steps
14213
- * @returns 1-based step number, or 1 if step not found
14214
- */
14215
- function getStepNumber(step, wizardSteps) {
14216
- const index = wizardSteps.indexOf(step);
14217
- return index >= 0 ? index + 1 : 1;
14115
+ const values = Object.fromEntries(paramNames.map((name) => [name, url.searchParams.get(name)]));
14116
+ let changed = false;
14117
+ for (const name of paramNames) if (url.searchParams.has(name)) {
14118
+ url.searchParams.delete(name);
14119
+ changed = true;
14120
+ }
14121
+ if (changed) {
14122
+ const newUrl = url.pathname + (url.search ? url.search : "") + url.hash;
14123
+ window.history.replaceState({}, "", newUrl);
14124
+ }
14125
+ return values;
14218
14126
  }
14219
14127
  //#endregion
14220
14128
  //#region ../blocks/src/system/runtime/nodes/booking-form.client.tsx
@@ -14414,7 +14322,7 @@ function resolveRuntimeEventDestination(event) {
14414
14322
  }
14415
14323
  //#endregion
14416
14324
  //#region ../blocks/src/system/runtime/nodes/events/shared/pricing.ts
14417
- const DEFAULT_EVENT_CURRENCY$1 = "USD";
14325
+ const DEFAULT_EVENT_CURRENCY = "USD";
14418
14326
  function resolveRuntimeEventPricing(event) {
14419
14327
  if (isPublicEventPricing(event.pricing)) return event.pricing;
14420
14328
  if (resolveRuntimeEventDestination(event).kind === "external") return {
@@ -14461,21 +14369,21 @@ function resolveRuntimeEventPricing(event) {
14461
14369
  };
14462
14370
  }
14463
14371
  function readCurrency(value) {
14464
- return typeof value === "string" && value.trim().length > 0 ? value : DEFAULT_EVENT_CURRENCY$1;
14372
+ return typeof value === "string" && value.trim().length > 0 ? value : DEFAULT_EVENT_CURRENCY;
14465
14373
  }
14466
14374
  function isRecord$1(value) {
14467
14375
  return typeof value === "object" && value !== null && !Array.isArray(value);
14468
14376
  }
14469
14377
  function isPublicEventPricing(value) {
14470
14378
  if (!isRecord$1(value) || typeof value.kind !== "string") return false;
14471
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
14379
+ return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "whole_series" || value.kind === "external";
14472
14380
  }
14473
14381
  function isPublicEventTicketType(value) {
14474
14382
  return isRecord$1(value) && typeof value.id === "string";
14475
14383
  }
14476
14384
  function readTicketTypePriceDisplay(value, currency) {
14477
14385
  const display = readLegacyPriceDisplay(value, currency);
14478
- return display.kind === "course" || display.kind === "external" ? {
14386
+ return display.kind === "whole_series" || display.kind === "external" ? {
14479
14387
  kind: "unavailable",
14480
14388
  currency
14481
14389
  } : display;
@@ -14533,11 +14441,11 @@ function readLegacyPriceDisplay(value, currency) {
14533
14441
  kind: "unavailable",
14534
14442
  currency: displayCurrency
14535
14443
  };
14536
- case "course": return isRecord$1(value.display) ? {
14537
- kind: "course",
14444
+ case "whole_series": return isRecord$1(value.display) ? {
14445
+ kind: "whole_series",
14538
14446
  display: readCoursePriceDisplay(value.display, displayCurrency)
14539
14447
  } : {
14540
- kind: "course",
14448
+ kind: "whole_series",
14541
14449
  display: {
14542
14450
  kind: "unavailable",
14543
14451
  currency: displayCurrency
@@ -14599,50 +14507,107 @@ function validateFormData(formData, requiresConsent = false) {
14599
14507
  if (requiresConsent && formData.consentAccepted !== true) errors.consentAccepted = "Please read and accept the agreement before continuing.";
14600
14508
  return errors;
14601
14509
  }
14602
- /**
14603
- * Transform API eligibility response to internal eligibility data.
14604
- *
14605
- * @param response - The raw API response from checkEligibility
14606
- * @returns Transformed eligibility data for component use
14607
- */
14608
- function transformEligibilityResponse(response) {
14609
- const { eligibility } = response;
14610
- const eligiblePasses = eligibility.passes.map((p) => ({
14611
- id: p.customerPassId,
14612
- passName: p.passName,
14613
- creditsRemaining: p.creditsRemaining
14510
+ //#endregion
14511
+ //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
14512
+ function getPortalSubjectEmail(profile) {
14513
+ return profile?.email ?? null;
14514
+ }
14515
+ function transformRegistrationOptionsResponse(response) {
14516
+ const canJoinWaitlist = response.availability.kind === "waitlist";
14517
+ const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
14518
+ const eligiblePasses = response.entitlements.passes.map((pass) => ({
14519
+ id: pass.customerPassId,
14520
+ passName: pass.passName,
14521
+ creditsRemaining: pass.creditsRemaining
14614
14522
  }));
14615
- const eligibleMemberships = eligibility.membership ? [{
14616
- id: eligibility.membership.customerMembershipId,
14617
- membershipName: eligibility.membership.membershipName
14618
- }] : [];
14619
- const isFree = !eligibility.requiresPayment && !eligibility.eventPrice;
14620
- const canPayDirectly = eligibility.eventPrice !== null && eligibility.eventPrice > 0;
14621
- const hasPaymentOptions = eligiblePasses.length > 0 || eligibleMemberships.length > 0 || canPayDirectly;
14622
- const hasUpsellOptions = eligibility.availableForPurchase.passes.length > 0 || eligibility.availableForPurchase.memberships.length > 0;
14523
+ const eligibleMemberships = response.entitlements.memberships.map((membership) => ({
14524
+ id: membership.customerMembershipId,
14525
+ membershipName: membership.membershipName
14526
+ }));
14527
+ const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
14528
+ const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
14529
+ const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
14530
+ const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
14623
14531
  return {
14624
- isFree,
14625
- eligible: eligibility.canJoinWaitlist || !eligibility.isFull && (isFree || hasPaymentOptions || hasUpsellOptions),
14626
- requiresPayment: eligibility.requiresPayment,
14627
- pricingMode: eligibility.pricingMode,
14628
- selectedTicketTypeId: eligibility.selectedTicketTypeId ?? null,
14629
- ticketLines: eligibility.ticketLines ?? [],
14630
- ticketTypes: eligibility.ticketTypes ?? [],
14631
- isFull: eligibility.isFull,
14632
- waitlistEnabled: eligibility.waitlistEnabled,
14633
- canJoinWaitlist: eligibility.canJoinWaitlist,
14634
- price: eligibility.eventPrice,
14635
- currency: eligibility.eventPriceCurrency ?? "usd",
14636
- requiresAuthForPasses: eligibility.requiresAuthForPasses,
14637
- requiresAuthForMemberships: eligibility.requiresAuthForMemberships,
14532
+ availability: response.availability,
14533
+ registration: response.registration,
14534
+ paymentOptions: response.paymentOptions,
14535
+ isFree: response.paymentOptions.some((option) => option.kind === "free"),
14536
+ credit: response.customer.credit ? {
14537
+ summary: {
14538
+ currency: response.customer.credit.currency,
14539
+ balanceCents: response.customer.credit.availableCents,
14540
+ reservedCents: 0,
14541
+ availableCents: response.customer.credit.availableCents
14542
+ },
14543
+ transactions: []
14544
+ } : null,
14545
+ eligible: response.registration.kind === "none" && registrationAvailable,
14546
+ requiresPayment: monetaryPaymentAvailable,
14547
+ pricingMode: response.pricing.mode,
14548
+ paymentTerms: response.pricing.paymentTerms,
14549
+ selectedTicketTypeId: response.pricing.lines.length === 1 ? response.pricing.lines[0]?.pricingOptionId ?? null : null,
14550
+ ticketLines: response.pricing.lines.map((line) => ({
14551
+ ticketTypeId: line.pricingOptionId,
14552
+ label: line.label,
14553
+ description: line.description,
14554
+ quantity: line.quantity,
14555
+ unitPriceCents: line.unitPriceCents,
14556
+ subtotalCents: line.subtotalCents,
14557
+ currency: response.pricing.currency
14558
+ })),
14559
+ ticketTypes: projectRegistrationPricingOptions(response.pricing.options),
14560
+ isFull,
14561
+ waitlistEnabled: response.availability.waitlistEnabled,
14562
+ canJoinWaitlist,
14563
+ price: response.pricing.subtotalCents,
14564
+ currency: response.pricing.currency,
14565
+ requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
14566
+ requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
14638
14567
  eligiblePasses,
14639
14568
  eligibleMemberships,
14640
- canPayDirectly,
14641
- eventAcceptsPasses: eligibility.eventAcceptsPasses,
14642
- eventAcceptsMemberships: eligibility.eventAcceptsMemberships,
14643
- availablePasses: eligibility.availableForPurchase.passes,
14644
- availableMemberships: eligibility.availableForPurchase.memberships
14645
- };
14569
+ canPayDirectly: monetaryPaymentAvailable,
14570
+ eventAcceptsPasses,
14571
+ eventAcceptsMemberships,
14572
+ availablePasses: [...response.entitlements.availableForPurchase.passes],
14573
+ availableMemberships: [...response.entitlements.availableForPurchase.memberships]
14574
+ };
14575
+ }
14576
+ function hasMonetaryPaymentOption(response) {
14577
+ return response.paymentOptions.some((option) => option.kind === "payInFull" || option.kind === "deferredManual" || option.kind === "instalmentPlan" || option.kind === "flexibleBalance");
14578
+ }
14579
+ function projectRegistrationPricingOptions(options) {
14580
+ return options.map((option) => ({
14581
+ id: option.pricingOptionId,
14582
+ name: option.label,
14583
+ description: option.description,
14584
+ priceAmount: option.unitPriceCents,
14585
+ isActive: option.availability.kind === "available" || option.availability.reason !== "inactive",
14586
+ sortOrder: option.sortOrder,
14587
+ capacityMode: option.availability.remainingPlaces === null ? "unlimited" : "limited",
14588
+ capacityLimit: option.capacityLimit,
14589
+ attendanceScope: option.attendanceScope,
14590
+ saleStartsAt: option.saleStartsAt,
14591
+ saleEndsAt: option.saleEndsAt,
14592
+ availability: option.availability.kind === "available" ? {
14593
+ kind: "available",
14594
+ remainingCapacity: option.availability.remainingPlaces
14595
+ } : {
14596
+ kind: "unavailable",
14597
+ reason: toLegacyAvailabilityReason(option.availability.reason),
14598
+ remainingCapacity: option.availability.remainingPlaces
14599
+ }
14600
+ }));
14601
+ }
14602
+ function toLegacyAvailabilityReason(reason) {
14603
+ switch (reason) {
14604
+ case "inactive": return "inactive";
14605
+ case "notOnSaleYet": return "not_on_sale_yet";
14606
+ case "saleEnded": return "sale_ended";
14607
+ case "soldOut":
14608
+ case "attendanceModeUnavailable": return "sold_out";
14609
+ case "overallCapacityUnavailable": return "event_sold_out";
14610
+ }
14646
14611
  }
14647
14612
  function getVisibleTicketTypes(input) {
14648
14613
  const eligibilityTicketTypes = input.eligibility?.ticketTypes;
@@ -14755,16 +14720,8 @@ function existingRegistrationLookupReducer(state, action) {
14755
14720
  * Custom hooks for portal authentication and eligibility checking.
14756
14721
  * Extracted from the main EventRegistrationClient for better separation of concerns.
14757
14722
  */
14758
- function scopePortalCreditStateToSubject(state, subjectEmail) {
14759
- if (!subjectEmail) return { kind: "not_authenticated" };
14760
- if (state.kind === "not_authenticated") return state;
14761
- const normalizedSubject = subjectEmail.trim().toLowerCase();
14762
- return state.subjectEmail === normalizedSubject ? state : {
14763
- kind: "loading",
14764
- subjectEmail: normalizedSubject
14765
- };
14766
- }
14767
14723
  const eventRegistrationHooksDeps = { useBlockApi };
14724
+ const REGISTRATION_OPTIONS_DEBOUNCE_MS = 150;
14768
14725
  /**
14769
14726
  * Hook for managing portal authentication state.
14770
14727
  *
@@ -14778,54 +14735,29 @@ function usePortalAuthWithDeps(deps) {
14778
14735
  const api = deps.useBlockApi();
14779
14736
  const [authState, setAuthState] = useState("checking");
14780
14737
  const [profile, setProfile] = useState(null);
14781
- const [creditState, setCreditState] = useState({ kind: "not_authenticated" });
14782
14738
  useEffect(() => {
14783
14739
  let cancelled = false;
14784
14740
  async function checkPortalAuth() {
14785
14741
  if ((api.config.authOverrides?.portal ?? api.config.auth).type !== "bearer") {
14786
14742
  setAuthState("unauthenticated");
14787
14743
  setProfile(null);
14788
- setCreditState({ kind: "not_authenticated" });
14789
14744
  return;
14790
14745
  }
14791
14746
  setAuthState("checking");
14792
14747
  setProfile(null);
14793
- setCreditState({ kind: "not_authenticated" });
14794
14748
  try {
14795
14749
  const me = await api.getPortalProfile();
14796
14750
  if (cancelled) return;
14797
- const nextProfile = {
14751
+ setProfile({
14798
14752
  email: me.profile.email,
14799
14753
  name: me.profile.name,
14800
14754
  phone: me.profile.phone || ""
14801
- };
14802
- const subjectEmail = nextProfile.email.trim().toLowerCase();
14803
- setProfile(nextProfile);
14804
- setCreditState({
14805
- kind: "loading",
14806
- subjectEmail
14807
14755
  });
14808
14756
  setAuthState("authenticated");
14809
- try {
14810
- const credit = await api.getPortalCredit();
14811
- if (cancelled) return;
14812
- setCreditState({
14813
- kind: "loaded",
14814
- subjectEmail,
14815
- credit
14816
- });
14817
- } catch {
14818
- if (cancelled) return;
14819
- setCreditState({
14820
- kind: "unavailable",
14821
- subjectEmail
14822
- });
14823
- }
14824
14757
  } catch {
14825
14758
  if (cancelled) return;
14826
14759
  setAuthState("unauthenticated");
14827
14760
  setProfile(null);
14828
- setCreditState({ kind: "not_authenticated" });
14829
14761
  }
14830
14762
  }
14831
14763
  checkPortalAuth();
@@ -14845,10 +14777,20 @@ function usePortalAuthWithDeps(deps) {
14845
14777
  isAuthenticated: authState === "authenticated",
14846
14778
  isChecking: authState === "checking",
14847
14779
  profile,
14848
- creditState: scopePortalCreditStateToSubject(creditState, authState === "authenticated" ? profile?.email ?? null : null),
14849
14780
  logout
14850
14781
  };
14851
14782
  }
14783
+ function toRegistrationOptionsSubject(subject, attendanceMode) {
14784
+ return subject.kind === "occurrence" ? {
14785
+ kind: "occurrence",
14786
+ occurrenceId: subject.occurrenceId,
14787
+ attendanceMode: attendanceMode ?? void 0
14788
+ } : {
14789
+ kind: "wholeSeries",
14790
+ eventSeriesId: subject.eventSeriesId,
14791
+ attendanceMode: attendanceMode ?? void 0
14792
+ };
14793
+ }
14852
14794
  function useEligibility(params) {
14853
14795
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
14854
14796
  }
@@ -14866,7 +14808,7 @@ function useEligibilityWithDeps(params, deps) {
14866
14808
  return;
14867
14809
  }
14868
14810
  const ticketSelections = JSON.parse(ticketSelectionsKey);
14869
- if (!params.occurrenceId || !params.email.trim() || ticketSelections.length === 0) {
14811
+ if (!params.subject || ticketSelections.length === 0) {
14870
14812
  requestIdRef.current += 1;
14871
14813
  dispatch({ type: "reset" });
14872
14814
  return;
@@ -14875,17 +14817,19 @@ function useEligibilityWithDeps(params, deps) {
14875
14817
  requestIdRef.current = requestId;
14876
14818
  dispatch({ type: "loading-started" });
14877
14819
  try {
14878
- const result = await api.checkEligibility({
14879
- occurrenceId: params.occurrenceId,
14880
- attendanceMode: params.attendanceMode ?? void 0,
14881
- ticketSelections,
14882
- selectedSlidingAmount: params.selectedSlidingAmount ?? void 0,
14883
- email: params.email.trim().toLowerCase()
14820
+ const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
14821
+ const result = await api.getRegistrationOptions({
14822
+ subject,
14823
+ selections: ticketSelections.map((selection) => ({
14824
+ pricingOptionId: selection.ticketTypeId,
14825
+ quantity: selection.quantity
14826
+ })),
14827
+ selectedSlidingAmount: params.selectedSlidingAmount ?? void 0
14884
14828
  });
14885
14829
  if (cancelled || requestIdRef.current !== requestId) return;
14886
14830
  dispatch({
14887
14831
  type: "resolved",
14888
- eligibility: transformEligibilityResponse(result)
14832
+ eligibility: transformRegistrationOptionsResponse(result)
14889
14833
  });
14890
14834
  } catch (err) {
14891
14835
  if (cancelled || requestIdRef.current !== requestId) return;
@@ -14895,24 +14839,44 @@ function useEligibilityWithDeps(params, deps) {
14895
14839
  });
14896
14840
  }
14897
14841
  }
14898
- fetchEligibility();
14842
+ const timeoutId = window.setTimeout(() => void fetchEligibility(), REGISTRATION_OPTIONS_DEBOUNCE_MS);
14899
14843
  return () => {
14900
14844
  cancelled = true;
14845
+ window.clearTimeout(timeoutId);
14901
14846
  };
14902
14847
  }, [
14903
14848
  api,
14904
14849
  params.enabled,
14905
- params.occurrenceId,
14850
+ params.subject?.kind,
14851
+ params.subject?.kind === "occurrence" ? params.subject.occurrenceId : params.subject?.eventSeriesId,
14906
14852
  params.attendanceMode,
14907
14853
  ticketSelectionsKey,
14908
- params.selectedSlidingAmount,
14909
- params.email
14854
+ params.selectedSlidingAmount
14910
14855
  ]);
14856
+ const creditState = registrationOptionsCreditState(state, params.subjectEmail);
14911
14857
  return {
14912
14858
  state,
14913
14859
  eligibility: state.eligibility,
14914
14860
  isLoading: state.tag === "loading",
14915
- error: state.error
14861
+ error: state.error,
14862
+ creditState
14863
+ };
14864
+ }
14865
+ function registrationOptionsCreditState(state, subjectEmail) {
14866
+ if (!subjectEmail) return { kind: "not_authenticated" };
14867
+ const normalizedEmail = subjectEmail.trim().toLowerCase();
14868
+ if (state.tag === "idle" || state.tag === "loading") return {
14869
+ kind: "loading",
14870
+ subjectEmail: normalizedEmail
14871
+ };
14872
+ if (state.tag === "failed") return {
14873
+ kind: "unavailable",
14874
+ subjectEmail: normalizedEmail
14875
+ };
14876
+ return {
14877
+ kind: "loaded",
14878
+ subjectEmail: normalizedEmail,
14879
+ credit: state.eligibility.credit ?? null
14916
14880
  };
14917
14881
  }
14918
14882
  function useExistingEventRegistration({ isAuthenticated, occurrenceId }) {
@@ -15086,9 +15050,6 @@ function getWaitlistClaimTokenSnapshot() {
15086
15050
  function useWaitlistClaim() {
15087
15051
  return useWaitlistClaimWithDeps(useWaitlistClaimDeps);
15088
15052
  }
15089
- function useWaitlistClaimForToken(token) {
15090
- return useResolvedWaitlistClaim(useWaitlistClaimDeps, token);
15091
- }
15092
15053
  function useWaitlistClaimWithDeps(deps) {
15093
15054
  return useResolvedWaitlistClaim(deps, useSyncExternalStore(subscribeToWaitlistClaimToken, getWaitlistClaimTokenSnapshot, () => null));
15094
15055
  }
@@ -15177,7 +15138,7 @@ function usePaymentVerificationWithDeps(config, deps) {
15177
15138
  const polling = usePolling(useMemo(() => {
15178
15139
  if (!config) return null;
15179
15140
  return {
15180
- pollFn: () => api.getEventRegistrationStatus({ attendeeId: config.transactionId }),
15141
+ pollFn: () => api.getEventRegistrationStatus(config.reference),
15181
15142
  isComplete: (result) => result.paymentStatus === "completed" || result.paymentStatus === "not_required",
15182
15143
  isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "refunded",
15183
15144
  maxAttempts: config.maxAttempts,
@@ -15201,6 +15162,7 @@ function usePaymentVerificationWithDeps(config, deps) {
15201
15162
  //#endregion
15202
15163
  //#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
15203
15164
  const EVENT_REGISTRATION_ANCHOR_ID = "event-registration";
15165
+ const EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM = "registration_attempt";
15204
15166
  //#endregion
15205
15167
  //#region ../blocks/src/system/runtime/nodes/event-registration/sessionStorage.ts
15206
15168
  const STORAGE_PREFIX = "riverbank:event-registration:";
@@ -15208,8 +15170,8 @@ const STALE_THRESHOLD_MS = 1440 * 60 * 1e3;
15208
15170
  /**
15209
15171
  * Build the sessionStorage key for a specific registration.
15210
15172
  */
15211
- function getStorageKey(siteId, occurrenceId) {
15212
- return `${STORAGE_PREFIX}${siteId}:${occurrenceId}`;
15173
+ function getStorageKey(siteId, checkoutAttemptId) {
15174
+ return `${STORAGE_PREFIX}${siteId}:${checkoutAttemptId}`;
15213
15175
  }
15214
15176
  /**
15215
15177
  * Check if sessionStorage is available.
@@ -15229,16 +15191,16 @@ function isStorageAvailable() {
15229
15191
  * Save pending registration data before Stripe redirect.
15230
15192
  *
15231
15193
  * @param siteId - Site ID
15232
- * @param occurrenceId - Event occurrence ID
15194
+ * @param checkoutAttemptId - Correlation ID included in the checkout return URL
15233
15195
  * @param data - Registration data to save (excluding version and timestamp)
15234
15196
  */
15235
- function savePendingRegistration(siteId, occurrenceId, data) {
15197
+ function savePendingRegistration(siteId, checkoutAttemptId, data) {
15236
15198
  if (!isStorageAvailable()) {
15237
15199
  console.warn("[sessionStorage] Storage not available, skipping save");
15238
15200
  return;
15239
15201
  }
15240
15202
  try {
15241
- const key = getStorageKey(siteId, occurrenceId);
15203
+ const key = getStorageKey(siteId, checkoutAttemptId);
15242
15204
  const ticketSelections = normalizeTicketSelectionLines(data.ticketSelections);
15243
15205
  if (ticketSelections.length === 0) {
15244
15206
  console.warn("[sessionStorage] No ticket selections to save, skipping registration state");
@@ -15247,7 +15209,7 @@ function savePendingRegistration(siteId, occurrenceId, data) {
15247
15209
  const entry = {
15248
15210
  ...data,
15249
15211
  ticketSelections,
15250
- version: 4,
15212
+ version: 5,
15251
15213
  timestamp: Date.now()
15252
15214
  };
15253
15215
  sessionStorage.setItem(key, JSON.stringify(entry));
@@ -15259,35 +15221,21 @@ function savePendingRegistration(siteId, occurrenceId, data) {
15259
15221
  * Get pending registration data after returning from Stripe.
15260
15222
  *
15261
15223
  * Returns null if:
15262
- * - No entry exists for this site/occurrence
15224
+ * - No entry exists for this checkout attempt
15263
15225
  * - Entry is stale (> 24 hours old)
15264
15226
  * - Entry is corrupt or wrong version
15265
15227
  * - Storage is unavailable
15266
15228
  *
15267
15229
  * @param siteId - Site ID
15268
- * @param occurrenceId - Optional event occurrence ID. If missing, scans for any entry for this site.
15230
+ * @param checkoutAttemptId - Correlation ID returned from checkout.
15269
15231
  * @returns Pending registration data or null
15270
15232
  */
15271
- function getPendingRegistration(siteId, occurrenceId) {
15233
+ function getPendingRegistration(siteId, checkoutAttemptId) {
15272
15234
  if (!isStorageAvailable()) return null;
15273
15235
  try {
15274
- if (occurrenceId) {
15275
- const key = getStorageKey(siteId, occurrenceId);
15276
- const stored = sessionStorage.getItem(key);
15277
- if (stored) return parseAndValidateEntry(stored, key);
15278
- return null;
15279
- }
15280
- const sitePrefix = `${STORAGE_PREFIX}${siteId}:`;
15281
- for (let i = 0; i < sessionStorage.length; i++) {
15282
- const key = sessionStorage.key(i);
15283
- if (key?.startsWith(sitePrefix)) {
15284
- const stored = sessionStorage.getItem(key);
15285
- if (stored) {
15286
- const entry = parseAndValidateEntry(stored, key);
15287
- if (entry) return entry;
15288
- }
15289
- }
15290
- }
15236
+ const key = getStorageKey(siteId, checkoutAttemptId);
15237
+ const stored = sessionStorage.getItem(key);
15238
+ if (stored) return parseAndValidateEntry(stored, key);
15291
15239
  return null;
15292
15240
  } catch (error) {
15293
15241
  console.warn("[sessionStorage] Failed to read registration:", error);
@@ -15304,12 +15252,13 @@ function parseAndValidateEntry(stored, key) {
15304
15252
  sessionStorage.removeItem(key);
15305
15253
  return null;
15306
15254
  }
15307
- if (raw.version !== 4) {
15255
+ const version = raw.version;
15256
+ if (version !== 4 && version !== 5) {
15308
15257
  console.warn("[sessionStorage] Outdated version, ignoring entry");
15309
15258
  sessionStorage.removeItem(key);
15310
15259
  return null;
15311
15260
  }
15312
- const entry = raw;
15261
+ const entry = normalizeStoredRegistration(raw);
15313
15262
  const timestamp = typeof entry.timestamp === "number" ? entry.timestamp : NaN;
15314
15263
  if (!Number.isFinite(timestamp)) {
15315
15264
  sessionStorage.removeItem(key);
@@ -15335,16 +15284,28 @@ function parseAndValidateEntry(stored, key) {
15335
15284
  return null;
15336
15285
  }
15337
15286
  }
15287
+ function normalizeStoredRegistration(entry) {
15288
+ if (entry.version === 5) return entry;
15289
+ const { attendeeId, ...stored } = entry;
15290
+ return {
15291
+ ...stored,
15292
+ version: 5,
15293
+ reference: {
15294
+ scope: "occurrence",
15295
+ attendeeId
15296
+ }
15297
+ };
15298
+ }
15338
15299
  /**
15339
15300
  * Clear pending registration data after successful verification.
15340
15301
  *
15341
15302
  * @param siteId - Site ID
15342
- * @param occurrenceId - Event occurrence ID
15303
+ * @param checkoutAttemptId - Checkout return correlation ID
15343
15304
  */
15344
- function clearPendingRegistration(siteId, occurrenceId) {
15305
+ function clearPendingRegistration(siteId, checkoutAttemptId) {
15345
15306
  if (!isStorageAvailable()) return;
15346
15307
  try {
15347
- const key = getStorageKey(siteId, occurrenceId);
15308
+ const key = getStorageKey(siteId, checkoutAttemptId);
15348
15309
  sessionStorage.removeItem(key);
15349
15310
  } catch {}
15350
15311
  }
@@ -15380,7 +15341,7 @@ function cleanupStaleRegistrations() {
15380
15341
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
15381
15342
  const eventRegistrationStripeReturnDeps = {
15382
15343
  usePaymentVerification,
15383
- consumeSearchParam,
15344
+ consumeReturnParams: () => consumeSearchParams(["registration", EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]),
15384
15345
  scrollToBlock,
15385
15346
  cleanupStaleRegistrations,
15386
15347
  clearPendingRegistration,
@@ -15390,37 +15351,43 @@ function useEventRegistrationStripeReturn(options) {
15390
15351
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
15391
15352
  }
15392
15353
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
15393
- const { api, events, occurrenceId, pendingAttendeeId, setErrorMessage, setFormData, setPaymentSelection, setPendingAttendeeId, setRegistrationResult, setSelectedEvent, setSelectedAttendanceMode, setTicketSelections, setStep, setTicketsCount, step } = options;
15394
- const verificationConfig = useMemo(() => step === "verifying-payment" && pendingAttendeeId ? { transactionId: pendingAttendeeId } : null, [step, pendingAttendeeId]);
15354
+ const { api, events, pendingRegistrationReference, setErrorMessage, setFormData, setPaymentSelection, setPendingRegistrationReference, setRegistrationResult, setSelectedEvent, setSelectedAttendanceMode, setTicketSelections, setStep, setTicketsCount, step } = options;
15355
+ const checkoutAttemptIdRef = useRef(null);
15356
+ const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
15395
15357
  const verification = deps.usePaymentVerification(verificationConfig);
15396
15358
  useEffect(() => {
15397
15359
  deps.cleanupStaleRegistrations();
15398
- const registrationStatus = deps.consumeSearchParam("registration");
15360
+ const returnParams = deps.consumeReturnParams();
15361
+ const registrationStatus = returnParams.registration;
15399
15362
  if (registrationStatus !== "cancelled" && registrationStatus !== "success") return;
15400
15363
  deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
15401
15364
  const siteId = api.config.siteId;
15402
15365
  if (!siteId) return;
15403
- const pending = deps.getPendingRegistration(siteId, occurrenceId || void 0);
15366
+ const checkoutAttemptId = returnParams[EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM];
15367
+ if (!checkoutAttemptId) return;
15368
+ const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
15404
15369
  if (!pending) return;
15370
+ checkoutAttemptIdRef.current = checkoutAttemptId;
15405
15371
  setFormData(pending.formData);
15406
15372
  setTicketSelections(pending.ticketSelections);
15407
15373
  setTicketsCount(getTicketSelectionTotal(pending.ticketSelections));
15408
15374
  if (pending.selectedEventId) {
15409
- const event = events.find((e) => e.publicEventId === pending.selectedEventId) ?? null;
15375
+ const event = events.find((e) => e.selectionId === pending.selectedEventId) ?? null;
15410
15376
  if (event) setSelectedEvent(event);
15411
15377
  }
15412
15378
  setSelectedAttendanceMode(pending.selectedAttendanceMode ?? null);
15413
15379
  setPaymentSelection(pending.paymentSelection);
15414
15380
  if (registrationStatus === "cancelled") setStep("select-payment");
15415
15381
  else if (registrationStatus === "success") {
15416
- setPendingAttendeeId(pending.attendeeId);
15382
+ setPendingRegistrationReference(pending.reference);
15417
15383
  setStep("verifying-payment");
15418
15384
  }
15419
15385
  }, []);
15420
15386
  useEffect(() => {
15421
15387
  if (verification.status === "completed") {
15422
15388
  const siteId = api.config.siteId;
15423
- if (siteId && occurrenceId) deps.clearPendingRegistration(siteId, occurrenceId);
15389
+ const checkoutAttemptId = checkoutAttemptIdRef.current;
15390
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
15424
15391
  setRegistrationResult({ status: "confirmed" });
15425
15392
  setStep("success");
15426
15393
  } else if (verification.status === "failed") {
@@ -15433,7 +15400,6 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
15433
15400
  verification.waitlistPosition,
15434
15401
  verification.error,
15435
15402
  api.config.siteId,
15436
- occurrenceId,
15437
15403
  setErrorMessage,
15438
15404
  setRegistrationResult,
15439
15405
  setStep
@@ -15442,7 +15408,21 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
15442
15408
  }
15443
15409
  //#endregion
15444
15410
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
15445
- const eventRegistrationSubmitDeps = { savePendingRegistration };
15411
+ function createCheckoutAttemptId(cryptoSource = {
15412
+ randomUUID: globalThis.crypto.randomUUID?.bind(globalThis.crypto),
15413
+ getRandomValues: (bytes) => globalThis.crypto.getRandomValues(bytes)
15414
+ }) {
15415
+ if (cryptoSource.randomUUID) return cryptoSource.randomUUID();
15416
+ const bytes = cryptoSource.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
15417
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
15418
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
15419
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
15420
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
15421
+ }
15422
+ const eventRegistrationSubmitDeps = {
15423
+ savePendingRegistration,
15424
+ createCheckoutAttemptId
15425
+ };
15446
15426
  function useEventRegistrationSubmit(options) {
15447
15427
  return useEventRegistrationSubmitWithDeps(options, eventRegistrationSubmitDeps);
15448
15428
  }
@@ -15475,46 +15455,22 @@ function toRegistrationResult(result) {
15475
15455
  }
15476
15456
  function useEventRegistrationSubmitWithDeps(options, deps) {
15477
15457
  return async (method, passId, membershipId, selection, submitOptions) => {
15478
- const submitOccurrenceId = options.registrationTarget?.occurrenceId;
15479
- if (!submitOccurrenceId) return {
15458
+ const target = options.registrationTarget;
15459
+ if (!target) return {
15480
15460
  ok: false,
15481
15461
  reason: "missing-target",
15482
15462
  message: "Select an event to continue."
15483
15463
  };
15484
15464
  options.setStep("submitting");
15485
15465
  try {
15486
- const ticketSelections = normalizeTicketSelectionLines(options.ticketSelections);
15487
- if (ticketSelections.length === 0) throw new Error("Choose at least one ticket to continue.");
15488
- const bundleProductId = method === "pass_bundle" || method === "membership_bundle" ? passId || membershipId : void 0;
15489
- const selectionSnapshot = (() => {
15490
- if (selection?.method) return selection;
15491
- if (method === "pass") return {
15492
- method: "pass",
15493
- passId: passId ?? void 0
15494
- };
15495
- if (method === "membership") return {
15496
- method: "membership",
15497
- membershipId: membershipId ?? void 0
15498
- };
15499
- if (method === "pass_bundle") return {
15500
- method: "pass_bundle",
15501
- bundlePassId: bundleProductId ?? void 0
15502
- };
15503
- if (method === "membership_bundle") return {
15504
- method: "membership_bundle",
15505
- bundleMembershipId: bundleProductId ?? void 0
15506
- };
15507
- return { method };
15508
- })();
15509
- const guestsPayload = options.requireGuestDetails && options.guests.length > 0 ? options.guests.map((guest) => ({
15510
- name: guest.name.trim(),
15511
- email: guest.email?.trim().toLowerCase() || void 0,
15512
- phone: guest.phone?.trim() || void 0
15513
- })) : void 0;
15466
+ const prepared = prepareSubmitContext(options, target, method, passId, membershipId, selection);
15467
+ if (prepared.subject.kind === "wholeSeries" && method === "stripe") return submitWholeSeriesCheckout(options, deps, {
15468
+ ...prepared,
15469
+ subject: prepared.subject
15470
+ }, submitOptions);
15514
15471
  const result = await options.api.registerForEvent({
15515
- occurrenceId: submitOccurrenceId,
15516
- attendanceMode: options.selectedAttendanceMode ?? void 0,
15517
- ticketSelections,
15472
+ subject: prepared.subject,
15473
+ ticketSelections: prepared.ticketSelections,
15518
15474
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
15519
15475
  email: options.formData.email.trim().toLowerCase(),
15520
15476
  name: options.formData.name.trim(),
@@ -15525,58 +15481,11 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
15525
15481
  paymentMethod: method,
15526
15482
  customerPassId: method === "pass" ? passId : void 0,
15527
15483
  customerMembershipId: method === "membership" ? membershipId : void 0,
15528
- bundleProductId,
15484
+ bundleProductId: prepared.bundleProductId,
15529
15485
  claimToken: options.claimToken ?? void 0,
15530
- guests: guestsPayload
15486
+ guests: prepared.guestsPayload
15531
15487
  });
15532
- if (!result.alreadyRegistered && result.status === "confirmed" && result.pendingPayment && (method === "stripe" || method === "pass_bundle" || method === "membership_bundle")) {
15533
- options.setPendingAttendeeId(result.attendeeId);
15534
- options.setStep("redirecting");
15535
- const { successUrl, cancelUrl } = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID);
15536
- const checkoutType = method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event";
15537
- const checkoutResult = await options.api.createEventCheckout({
15538
- attendeeId: result.attendeeId,
15539
- checkoutType,
15540
- productId: bundleProductId,
15541
- discountCode: options.discountCode.trim() ? options.discountCode.trim() : void 0,
15542
- collectionOptionKind: selectionSnapshot.collectionOptionKind,
15543
- successUrl,
15544
- cancelUrl
15545
- });
15546
- if (checkoutResult.bypassed) {
15547
- options.setRegistrationResult({ status: "confirmed" });
15548
- options.setStep("success");
15549
- return {
15550
- ok: true,
15551
- outcome: { kind: "completed" }
15552
- };
15553
- }
15554
- if (!checkoutResult.checkoutUrl) throw new Error("Checkout URL missing");
15555
- const siteId = options.api.config.siteId;
15556
- if (siteId && submitOccurrenceId) deps.savePendingRegistration(siteId, submitOccurrenceId, {
15557
- attendeeId: result.attendeeId,
15558
- formData: options.formData,
15559
- ticketSelections,
15560
- selectedEventId: options.registrationTarget?.selectedEventId ?? null,
15561
- selectedAttendanceMode: options.selectedAttendanceMode,
15562
- paymentSelection: selectionSnapshot
15563
- });
15564
- if (submitOptions?.redirect === "manual") return {
15565
- ok: true,
15566
- outcome: {
15567
- kind: "checkout_redirect",
15568
- checkoutUrl: checkoutResult.checkoutUrl
15569
- }
15570
- };
15571
- window.location.href = checkoutResult.checkoutUrl;
15572
- return {
15573
- ok: true,
15574
- outcome: {
15575
- kind: "checkout_redirect",
15576
- checkoutUrl: checkoutResult.checkoutUrl
15577
- }
15578
- };
15579
- }
15488
+ if (needsOccurrenceCheckout(result, method)) return submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
15580
15489
  options.setRegistrationResult(toRegistrationResult(result));
15581
15490
  options.setStep("success");
15582
15491
  return {
@@ -15595,6 +15504,264 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
15595
15504
  }
15596
15505
  };
15597
15506
  }
15507
+ function prepareSubmitContext(options, target, method, passId, membershipId, selection) {
15508
+ const ticketSelections = normalizeTicketSelectionLines(options.ticketSelections);
15509
+ if (ticketSelections.length === 0) throw new Error("Choose at least one ticket to continue.");
15510
+ const bundleProductId = method === "pass_bundle" || method === "membership_bundle" ? passId || membershipId : void 0;
15511
+ return {
15512
+ ticketSelections,
15513
+ bundleProductId,
15514
+ selectionSnapshot: resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection),
15515
+ guestsPayload: options.requireGuestDetails && options.guests.length > 0 ? options.guests.map((guest) => ({
15516
+ name: guest.name.trim(),
15517
+ email: guest.email?.trim().toLowerCase() || void 0,
15518
+ phone: guest.phone?.trim() || void 0
15519
+ })) : void 0,
15520
+ subject: target.subject.kind === "occurrence" ? {
15521
+ kind: "occurrence",
15522
+ occurrenceId: target.subject.occurrenceId,
15523
+ attendanceMode: options.selectedAttendanceMode ?? void 0
15524
+ } : {
15525
+ kind: "wholeSeries",
15526
+ eventSeriesId: target.subject.eventSeriesId,
15527
+ attendanceMode: options.selectedAttendanceMode ?? void 0
15528
+ }
15529
+ };
15530
+ }
15531
+ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
15532
+ if (selection?.method) return selection;
15533
+ if (method === "pass" && passId) return {
15534
+ method,
15535
+ passId
15536
+ };
15537
+ if (method === "membership" && membershipId) return {
15538
+ method,
15539
+ membershipId
15540
+ };
15541
+ if (method === "pass_bundle" && bundleProductId) return {
15542
+ method,
15543
+ bundlePassId: bundleProductId
15544
+ };
15545
+ if (method === "membership_bundle" && bundleProductId) return {
15546
+ method,
15547
+ bundleMembershipId: bundleProductId
15548
+ };
15549
+ if (method === "free") return { method };
15550
+ throw new Error("Choose an available payment option.");
15551
+ }
15552
+ async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
15553
+ options.setStep("redirecting");
15554
+ if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
15555
+ const checkoutAttemptId = deps.createCheckoutAttemptId();
15556
+ const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
15557
+ const result = await options.api.createEventCheckout({
15558
+ subject: prepared.subject,
15559
+ ticketSelections: prepared.ticketSelections,
15560
+ selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
15561
+ email: options.formData.email.trim().toLowerCase(),
15562
+ name: options.formData.name.trim(),
15563
+ phone: options.formData.phone.trim() || void 0,
15564
+ formData: options.formData,
15565
+ consentAccepted: options.formData.consentAccepted,
15566
+ altchaSolution: options.altchaSolution,
15567
+ guests: prepared.guestsPayload,
15568
+ claimToken: options.claimToken ?? void 0,
15569
+ discountCode: options.discountCode.trim() || void 0,
15570
+ collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
15571
+ ...urls
15572
+ });
15573
+ if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
15574
+ if ("waitlistEntryId" in result) {
15575
+ options.setRegistrationResult({
15576
+ status: "waitlist",
15577
+ variant: result.alreadyRegistered ? "info" : void 0,
15578
+ title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
15579
+ message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
15580
+ });
15581
+ options.setStep("success");
15582
+ return {
15583
+ ok: true,
15584
+ outcome: { kind: "completed" }
15585
+ };
15586
+ }
15587
+ if (result.bypassed) return completeBypassedCheckout(options);
15588
+ if (!result.checkoutUrl) throw new Error("Checkout URL missing");
15589
+ savePendingCheckout(options, deps, prepared, checkoutAttemptId, {
15590
+ scope: "wholeSeries",
15591
+ registrationId: result.registrationId
15592
+ });
15593
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
15594
+ }
15595
+ function needsOccurrenceCheckout(result, method) {
15596
+ return result.scope === "occurrence" && !result.alreadyRegistered && result.status === "confirmed" && result.pendingPayment && [
15597
+ "stripe",
15598
+ "pass_bundle",
15599
+ "membership_bundle"
15600
+ ].includes(method);
15601
+ }
15602
+ async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
15603
+ const reference = {
15604
+ scope: "occurrence",
15605
+ attendeeId: registration.attendeeId
15606
+ };
15607
+ options.setPendingRegistrationReference(reference);
15608
+ options.setStep("redirecting");
15609
+ const checkoutAttemptId = deps.createCheckoutAttemptId();
15610
+ const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
15611
+ const result = await options.api.createEventCheckout({
15612
+ subject: {
15613
+ kind: "occurrence",
15614
+ attendeeId: registration.attendeeId
15615
+ },
15616
+ checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
15617
+ productId: prepared.bundleProductId,
15618
+ discountCode: options.discountCode.trim() || void 0,
15619
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
15620
+ ...urls
15621
+ });
15622
+ if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
15623
+ if (result.bypassed) return completeBypassedCheckout(options);
15624
+ if (!result.checkoutUrl) throw new Error("Checkout URL missing");
15625
+ if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
15626
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
15627
+ }
15628
+ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
15629
+ const siteId = options.api.config.siteId;
15630
+ if (!siteId) return;
15631
+ deps.savePendingRegistration(siteId, checkoutAttemptId, {
15632
+ reference,
15633
+ formData: options.formData,
15634
+ ticketSelections: prepared.ticketSelections,
15635
+ selectedEventId: options.registrationTarget?.selectedEventId ?? null,
15636
+ selectedAttendanceMode: options.selectedAttendanceMode,
15637
+ paymentSelection: prepared.selectionSnapshot
15638
+ });
15639
+ }
15640
+ function completeBypassedCheckout(options) {
15641
+ options.setRegistrationResult({ status: "confirmed" });
15642
+ options.setStep("success");
15643
+ return {
15644
+ ok: true,
15645
+ outcome: { kind: "completed" }
15646
+ };
15647
+ }
15648
+ function redirectToCheckout(checkoutUrl, submitOptions) {
15649
+ if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
15650
+ return {
15651
+ ok: true,
15652
+ outcome: {
15653
+ kind: "checkout_redirect",
15654
+ checkoutUrl
15655
+ }
15656
+ };
15657
+ }
15658
+ //#endregion
15659
+ //#region ../blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.ts
15660
+ function getApprovedDirectPaymentCollectionOptionKinds(paymentOptions) {
15661
+ return paymentOptions.flatMap((option) => {
15662
+ switch (option.kind) {
15663
+ case "payInFull": return ["upfront"];
15664
+ case "deferredManual": return ["deferred_manual"];
15665
+ case "instalmentPlan": return ["instalment_plan"];
15666
+ case "flexibleBalance": return ["flexible_balance"];
15667
+ case "free":
15668
+ case "ownedMembership":
15669
+ case "ownedPass":
15670
+ case "buyMembership":
15671
+ case "buyPass": return [];
15672
+ }
15673
+ });
15674
+ }
15675
+ function buildEventRegistrationPaymentOptionsViewModel(input) {
15676
+ const approvedOptions = selectApprovedEventDirectPaymentOptions(input.approvedPaymentOptions, input.paymentTerms);
15677
+ const selection = buildBookingPaymentSelectionViewModel({
15678
+ serviceTitle: input.eventTitle,
15679
+ paymentTerms: { allowedOptions: [...approvedOptions] },
15680
+ priceAmount: input.totalPriceCents,
15681
+ priceCurrency: input.currency,
15682
+ bookingStartAt: input.startsAt,
15683
+ locale: input.locale
15684
+ });
15685
+ return {
15686
+ mode: selection.mode,
15687
+ sectionTitle: selection.sectionTitle,
15688
+ options: selection.options.flatMap((option, index) => {
15689
+ const sourceOption = approvedOptions[index];
15690
+ return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents, input.startsAt)] : [];
15691
+ })
15692
+ };
15693
+ }
15694
+ function selectApprovedEventDirectPaymentOptions(approvedPaymentOptions, paymentTerms) {
15695
+ const approvedKinds = new Set(getApprovedDirectPaymentCollectionOptionKinds(approvedPaymentOptions));
15696
+ return paymentTerms.allowedOptions.filter((option) => approvedKinds.has(option.kind));
15697
+ }
15698
+ function toEventDirectPaymentOption(option, sourceOption, mode, totalCents, startsAt) {
15699
+ const configuredPaymentDueNowCents = resolveBookingPaymentDueNowCents({
15700
+ option: sourceOption,
15701
+ totalCents,
15702
+ bookingStartAt: startsAt
15703
+ });
15704
+ switch (option.kind) {
15705
+ case "upfront": return {
15706
+ ...option,
15707
+ kind: "upfront",
15708
+ label: mode === "choice_required" ? "Pay in full now" : "Pay by card",
15709
+ totalCents,
15710
+ configuredPaymentDueNowCents
15711
+ };
15712
+ case "deferred_manual": return {
15713
+ ...option,
15714
+ kind: "deferred_manual",
15715
+ label: option.title,
15716
+ totalCents,
15717
+ configuredPaymentDueNowCents
15718
+ };
15719
+ case "instalment_plan": return {
15720
+ ...option,
15721
+ kind: "instalment_plan",
15722
+ label: option.title,
15723
+ totalCents,
15724
+ configuredPaymentDueNowCents
15725
+ };
15726
+ case "flexible_balance": return {
15727
+ ...option,
15728
+ kind: "flexible_balance",
15729
+ label: "Pay deposit now",
15730
+ totalCents,
15731
+ configuredPaymentDueNowCents
15732
+ };
15733
+ }
15734
+ }
15735
+ function resolveEventRegistrationDirectPaymentSelection(input) {
15736
+ if (input.selection.method !== "stripe") return { kind: "not-stripe" };
15737
+ const fallbackOption = input.options[0];
15738
+ if (!fallbackOption) return { kind: "unavailable" };
15739
+ const requestedKind = input.selection.collectionOptionKind;
15740
+ const selectedOption = input.options.find((option) => option.kind === requestedKind);
15741
+ if (selectedOption) return {
15742
+ kind: "valid",
15743
+ selection: {
15744
+ method: "stripe",
15745
+ collectionOptionKind: selectedOption.kind
15746
+ }
15747
+ };
15748
+ return {
15749
+ kind: "invalid",
15750
+ fallbackSelection: {
15751
+ method: "stripe",
15752
+ collectionOptionKind: fallbackOption.kind
15753
+ }
15754
+ };
15755
+ }
15756
+ function normalizeEventRegistrationDirectPaymentSelection(input) {
15757
+ const selectionState = resolveEventRegistrationDirectPaymentSelection(input);
15758
+ switch (selectionState.kind) {
15759
+ case "valid": return selectionState.selection;
15760
+ case "invalid": return selectionState.fallbackSelection;
15761
+ case "not-stripe":
15762
+ case "unavailable": return input.selection;
15763
+ }
15764
+ }
15598
15765
  //#endregion
15599
15766
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
15600
15767
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
@@ -15609,14 +15776,19 @@ function createInitialRegistrationFlowState(hasPreSelectedContext) {
15609
15776
  };
15610
15777
  }
15611
15778
  function selectionEquals(a, b) {
15612
- return a.method === b.method && a.passId === b.passId && a.membershipId === b.membershipId && a.bundlePassId === b.bundlePassId && a.bundleMembershipId === b.bundleMembershipId && a.productName === b.productName && a.productDescription === b.productDescription && a.productPrice === b.productPrice && a.productCurrency === b.productCurrency && a.productInterval === b.productInterval && a.collectionOptionKind === b.collectionOptionKind;
15779
+ if (a.method !== b.method) return false;
15780
+ switch (a.method) {
15781
+ case null:
15782
+ case "free": return true;
15783
+ case "stripe": return b.method === "stripe" && a.collectionOptionKind === b.collectionOptionKind;
15784
+ case "pass": return b.method === "pass" && a.passId === b.passId;
15785
+ case "membership": return b.method === "membership" && a.membershipId === b.membershipId;
15786
+ case "pass_bundle": return b.method === "pass_bundle" && a.bundlePassId === b.bundlePassId;
15787
+ case "membership_bundle": return b.method === "membership_bundle" && a.bundleMembershipId === b.bundleMembershipId;
15788
+ }
15613
15789
  }
15614
- function withDefaultSelection(selection) {
15790
+ function normalizePaymentSelection(selection) {
15615
15791
  if (!selection || !selection.method) return { method: null };
15616
- if (selection.method === "stripe") return {
15617
- ...selection,
15618
- collectionOptionKind: selection.collectionOptionKind ?? "upfront"
15619
- };
15620
15792
  return selection;
15621
15793
  }
15622
15794
  function computeAutoSelection(input) {
@@ -15637,12 +15809,19 @@ function computeAutoSelection(input) {
15637
15809
  productName: pass.passName
15638
15810
  };
15639
15811
  }
15640
- if (eligibility.canPayDirectly && eligibility.price) return {
15641
- method: "stripe",
15642
- collectionOptionKind: "upfront"
15643
- };
15812
+ const directPaymentSelection = computeDirectPaymentSelection(eligibility);
15813
+ if (directPaymentSelection.method === "stripe" && eligibility.price) return directPaymentSelection;
15644
15814
  return { method: null };
15645
15815
  }
15816
+ function computeDirectPaymentSelection(eligibility) {
15817
+ if (!eligibility?.canPayDirectly) return { method: null };
15818
+ const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
15819
+ const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
15820
+ return collectionOptionKind ? {
15821
+ method: "stripe",
15822
+ collectionOptionKind
15823
+ } : { method: null };
15824
+ }
15646
15825
  function isSelectionValid(input) {
15647
15826
  const { selection, isAuthenticated, eligibility, ticketsCount } = input;
15648
15827
  if (!selection.method) return false;
@@ -15676,7 +15855,7 @@ function normalizeRegistrationFlowState(state) {
15676
15855
  });
15677
15856
  const nextSelection = canKeepManualSelection ? state.paymentSelection : autoSelection;
15678
15857
  const nextSource = canKeepManualSelection ? "manual" : "auto";
15679
- const normalizedSelection = withDefaultSelection(nextSelection);
15858
+ const normalizedSelection = normalizePaymentSelection(nextSelection);
15680
15859
  if (nextPassOptOut === state.passOptOut && nextSource === state.selectionSource && selectionEquals(normalizedSelection, state.paymentSelection)) return state;
15681
15860
  return {
15682
15861
  ...state,
@@ -15705,17 +15884,14 @@ function registrationFlowReducer(state, action) {
15705
15884
  });
15706
15885
  case "set-manual-payment-selection": return normalizeRegistrationFlowState({
15707
15886
  ...state,
15708
- paymentSelection: withDefaultSelection(action.selection),
15887
+ paymentSelection: normalizePaymentSelection(action.selection),
15709
15888
  selectionSource: "manual",
15710
15889
  passOptOut: action.selection.method === "stripe" ? true : state.passOptOut
15711
15890
  });
15712
15891
  case "use-card-instead-of-pass": return normalizeRegistrationFlowState({
15713
15892
  ...state,
15714
15893
  passOptOut: true,
15715
- paymentSelection: {
15716
- method: "stripe",
15717
- collectionOptionKind: "upfront"
15718
- },
15894
+ paymentSelection: computeDirectPaymentSelection(state.eligibility),
15719
15895
  selectionSource: "manual"
15720
15896
  });
15721
15897
  case "event-changed": return normalizeRegistrationFlowState({
@@ -15955,6 +16131,13 @@ const publicWholeSeriesOfferingSchema = z.object({
15955
16131
  title: z.string(),
15956
16132
  slug: z.string(),
15957
16133
  description: z.unknown().nullable(),
16134
+ deliveryMode: z.enum([
16135
+ "in_person",
16136
+ "online",
16137
+ "hybrid"
16138
+ ]),
16139
+ waitlistEnabled: z.boolean(),
16140
+ requireGuestDetails: z.boolean(),
15958
16141
  teamMembers: z.array(wholeSeriesTeamMemberSummarySchema).optional(),
15959
16142
  enrollmentOpen: z.boolean(),
15960
16143
  pricing: wholeSeriesPricingSchema,
@@ -16070,10 +16253,11 @@ const mixedPriceDisplaySchema = z.object({
16070
16253
  paidToAmount: z.number(),
16071
16254
  currency: z.string()
16072
16255
  });
16073
- const publicCoursePriceDisplaySchema = z.discriminatedUnion("kind", [
16256
+ const publicWholeSeriesPriceDisplaySchema = z.discriminatedUnion("kind", [
16074
16257
  freePriceDisplaySchema,
16075
16258
  exactPriceDisplaySchema,
16076
16259
  fromPriceDisplaySchema,
16260
+ rangePriceDisplaySchema,
16077
16261
  unavailablePriceDisplaySchema
16078
16262
  ]);
16079
16263
  z.discriminatedUnion("kind", [
@@ -16088,8 +16272,8 @@ z.discriminatedUnion("kind", [
16088
16272
  label: z.string()
16089
16273
  }),
16090
16274
  z.object({
16091
- kind: z.literal("course"),
16092
- display: publicCoursePriceDisplaySchema
16275
+ kind: z.literal("whole_series"),
16276
+ display: publicWholeSeriesPriceDisplaySchema
16093
16277
  })
16094
16278
  ]);
16095
16279
  const publicEventTicketTypePriceDisplaySchema = z.union([
@@ -16191,10 +16375,10 @@ const publicEventPricingSchema = z.discriminatedUnion("kind", [
16191
16375
  })
16192
16376
  }),
16193
16377
  z.object({
16194
- kind: z.literal("course"),
16378
+ kind: z.literal("whole_series"),
16195
16379
  display: z.object({
16196
- kind: z.literal("course"),
16197
- display: publicCoursePriceDisplaySchema
16380
+ kind: z.literal("whole_series"),
16381
+ display: publicWholeSeriesPriceDisplaySchema
16198
16382
  })
16199
16383
  }),
16200
16384
  z.object({
@@ -16359,7 +16543,8 @@ function resolveEventRegistrationScope(context) {
16359
16543
  };
16360
16544
  return { kind: "unscoped" };
16361
16545
  }
16362
- function applyEventRegistrationScope(events, scope) {
16546
+ function resolveEventRegistrationScopedEvents(events, context) {
16547
+ const scope = resolveEventRegistrationScope(context);
16363
16548
  switch (scope.kind) {
16364
16549
  case "occurrenceSeries":
16365
16550
  case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
@@ -16371,9 +16556,6 @@ function applyEventRegistrationScope(events, scope) {
16371
16556
  case "unscoped": return [...events];
16372
16557
  }
16373
16558
  }
16374
- function resolveEventRegistrationScopedEvents(events, context) {
16375
- return applyEventRegistrationScope(events, resolveEventRegistrationScope(context));
16376
- }
16377
16559
  //#endregion
16378
16560
  //#region ../blocks/src/system/runtime/nodes/event-registration/event-registration.headless.override.ts
16379
16561
  function createEventRegistrationBlockApiConfig(input) {
@@ -16421,7 +16603,6 @@ function getEventRegistrationOverrideInput(props) {
16421
16603
  ...content.showVenue != null ? { showVenue: content.showVenue } : {},
16422
16604
  ...content.showCapacity != null ? { showCapacity: content.showCapacity } : {},
16423
16605
  ...content.successMessage ? { successMessage: content.successMessage } : {},
16424
- ...content.waitlistMessage ? { waitlistMessage: content.waitlistMessage } : {},
16425
16606
  ...content.buttonText != null ? { buttonText: content.buttonText } : {},
16426
16607
  ...content.buttonVariant ? { buttonVariant: content.buttonVariant } : {},
16427
16608
  ...content.spamProtectionEnabled != null ? { spamProtectionEnabled: content.spamProtectionEnabled } : {},
@@ -16499,7 +16680,7 @@ function toInternalPaymentSelection(selection) {
16499
16680
  case "free": return { method: "free" };
16500
16681
  case "stripe": return {
16501
16682
  method: "stripe",
16502
- collectionOptionKind: selection.collectionOptionKind ?? "upfront"
16683
+ collectionOptionKind: selection.collectionOptionKind
16503
16684
  };
16504
16685
  case "pass": return {
16505
16686
  method: "pass",
@@ -16670,7 +16851,7 @@ function getStepLabel(step) {
16670
16851
  //#endregion
16671
16852
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
16672
16853
  function eventMatchesOccurrenceId(event, occurrenceId) {
16673
- return event.registrationOccurrenceId === occurrenceId || event.publicEventId === occurrenceId;
16854
+ return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
16674
16855
  }
16675
16856
  function findEventByOccurrenceId(events, occurrenceId) {
16676
16857
  return events.find((event) => eventMatchesOccurrenceId(event, occurrenceId)) ?? null;
@@ -16688,11 +16869,14 @@ function findPreSelectedEvent(input) {
16688
16869
  })) === contextDate) ?? null;
16689
16870
  }
16690
16871
  function resolveRegistrationTarget(input) {
16691
- const occurrenceId = input.occurrenceContext?.id ?? input.selectedEvent?.registrationOccurrenceId ?? null;
16692
- if (!occurrenceId) return null;
16872
+ const subject = input.occurrenceContext ? {
16873
+ kind: "occurrence",
16874
+ occurrenceId: input.occurrenceContext.id
16875
+ } : input.selectedEvent?.registrationSubject ?? null;
16876
+ if (!subject) return null;
16693
16877
  return {
16694
- occurrenceId,
16695
- selectedEventId: input.selectedEvent?.publicEventId ?? null
16878
+ subject,
16879
+ selectedEventId: input.selectedEvent?.selectionId ?? null
16696
16880
  };
16697
16881
  }
16698
16882
  function resolveEventRequiresPayment(input) {
@@ -16728,32 +16912,140 @@ function toRegistrationEvent(event) {
16728
16912
  return {
16729
16913
  ...event,
16730
16914
  pricing: resolveRuntimeEventPricing(event),
16731
- publicEventId: event.id,
16732
- registrationOccurrenceId: event.occurrenceId
16915
+ selectionId: event.id,
16916
+ registrationSubject: {
16917
+ kind: "occurrence",
16918
+ occurrenceId: event.occurrenceId
16919
+ }
16733
16920
  };
16734
16921
  }
16735
16922
  function toRegistrationEvents(events) {
16736
- return events.map(toRegistrationEvent);
16923
+ return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
16924
+ }
16925
+ function toWholeSeriesTicketType(option) {
16926
+ return {
16927
+ ...option,
16928
+ capacityMode: option.capacityLimit === null ? "unlimited" : "limited",
16929
+ attendanceScope: option.attendanceScope ?? void 0,
16930
+ availability: {
16931
+ kind: "available",
16932
+ remainingCapacity: option.capacityLimit
16933
+ }
16934
+ };
16935
+ }
16936
+ function toWholeSeriesPricing(offering) {
16937
+ const resolved = resolveWholeSeriesPricingState(offering);
16938
+ switch (offering.pricing.pricingStrategy) {
16939
+ case "free": return {
16940
+ kind: "free_registration",
16941
+ currency: offering.currency,
16942
+ display: {
16943
+ kind: "free",
16944
+ currency: offering.currency
16945
+ }
16946
+ };
16947
+ case "single": {
16948
+ const amount = offering.pricing.singlePriceAmount ?? 0;
16949
+ return amount === 0 ? {
16950
+ kind: "free_registration",
16951
+ currency: offering.currency,
16952
+ display: {
16953
+ kind: "free",
16954
+ currency: offering.currency
16955
+ }
16956
+ } : {
16957
+ kind: "single_paid",
16958
+ amount,
16959
+ currency: offering.currency,
16960
+ display: {
16961
+ kind: "exact",
16962
+ amount,
16963
+ currency: offering.currency
16964
+ }
16965
+ };
16966
+ }
16967
+ case "tiered": return {
16968
+ kind: "ticket_types",
16969
+ currency: offering.currency,
16970
+ ticketTypes: resolved.selectableOptions.map((option) => toWholeSeriesTicketType(option)),
16971
+ display: resolved.display
16972
+ };
16973
+ case "sliding_scale": return {
16974
+ kind: "sliding_scale",
16975
+ minAmount: offering.pricing.slidingMinAmount ?? 0,
16976
+ maxAmount: offering.pricing.slidingMaxAmount ?? 0,
16977
+ suggestedAmount: offering.pricing.slidingSuggestedAmount ?? null,
16978
+ currency: offering.currency,
16979
+ display: {
16980
+ kind: "range",
16981
+ minAmount: offering.pricing.slidingMinAmount ?? 0,
16982
+ maxAmount: offering.pricing.slidingMaxAmount ?? 0,
16983
+ currency: offering.currency
16984
+ }
16985
+ };
16986
+ }
16987
+ }
16988
+ function toAttendanceModes(offering) {
16989
+ return (offering.deliveryMode === "hybrid" ? ["in_person", "online"] : [offering.deliveryMode]).map((mode) => ({
16990
+ mode,
16991
+ capacity: offering.enrollmentCapacity,
16992
+ registeredCount: offering.enrolledCount,
16993
+ availableSpots: offering.availableSpots,
16994
+ waitlistEnabled: offering.waitlistEnabled
16995
+ }));
16996
+ }
16997
+ function toWholeSeriesRegistrationEvent(offering) {
16998
+ const firstSession = offering.sessions[0];
16999
+ const lastSession = offering.sessions[offering.sessions.length - 1];
17000
+ return {
17001
+ selectionId: offering.eventSeriesId,
17002
+ registrationSubject: {
17003
+ kind: "wholeSeries",
17004
+ eventSeriesId: offering.eventSeriesId,
17005
+ sessions: offering.sessions
17006
+ },
17007
+ seriesId: offering.eventSeriesId,
17008
+ title: offering.title,
17009
+ startsAt: firstSession?.startsAt ?? "",
17010
+ endsAt: lastSession?.endsAt ?? firstSession?.endsAt ?? "",
17011
+ bookingAvailability: offering.enrollmentOpen ? { kind: "open" } : {
17012
+ kind: "closed",
17013
+ reason: "enrollment_closed"
17014
+ },
17015
+ deliveryMode: offering.deliveryMode,
17016
+ attendanceModes: toAttendanceModes(offering),
17017
+ capacity: offering.enrollmentCapacity,
17018
+ registeredCount: offering.enrolledCount,
17019
+ availableSpots: offering.availableSpots,
17020
+ waitlistEnabled: offering.waitlistEnabled,
17021
+ venue: offering.venue ? {
17022
+ ...offering.venue,
17023
+ location: null
17024
+ } : null,
17025
+ eventCategory: null,
17026
+ teamMembers: offering.teamMembers,
17027
+ status: offering.status,
17028
+ timeZone: firstSession?.timeZone ?? "UTC",
17029
+ pricing: toWholeSeriesPricing(offering),
17030
+ paymentTerms: offering.paymentTerms,
17031
+ consent: offering.consent,
17032
+ requireGuestDetails: offering.requireGuestDetails,
17033
+ acceptsPasses: false,
17034
+ acceptsMemberships: offering.acceptsMemberships
17035
+ };
17036
+ }
17037
+ function toWholeSeriesRegistrationEvents(offerings) {
17038
+ return offerings.map(toWholeSeriesRegistrationEvent);
16737
17039
  }
16738
17040
  //#endregion
16739
- //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
16740
- const eventRegistrationWizardDeps = {
16741
- usePortalAuth,
16742
- useEligibility,
16743
- useExistingEventRegistration,
16744
- useWaitlistClaim,
16745
- useEventRegistrationStripeReturn,
16746
- useEventRegistrationSubmit,
16747
- useDiscountCodeUi
16748
- };
16749
- function parseCurrencyInputToCents$1(value) {
17041
+ //#region ../blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.ts
17042
+ function parseCurrencyInputToCents(value) {
16750
17043
  const trimmed = value.trim();
16751
17044
  if (!trimmed) return null;
16752
17045
  const amount = Number(trimmed);
16753
- if (!Number.isFinite(amount) || amount < 0) return null;
16754
- return Math.round(amount * 100);
17046
+ return Number.isFinite(amount) && amount >= 0 ? Math.round(amount * 100) : null;
16755
17047
  }
16756
- function formatCentsAsCurrencyInput$1(amount) {
17048
+ function formatCentsAsCurrencyInput(amount) {
16757
17049
  const major = amount / 100;
16758
17050
  return Number.isInteger(major) ? String(major) : major.toFixed(2);
16759
17051
  }
@@ -16768,15 +17060,127 @@ function getSlidingScaleForEvent(event) {
16768
17060
  function getSlidingScaleSelectionMessage(input) {
16769
17061
  if (!input.slidingScale) return null;
16770
17062
  if (input.selectedAmount === null) return "Choose an amount to continue.";
16771
- if (input.selectedAmount < input.slidingScale.minAmount || input.selectedAmount > input.slidingScale.maxAmount) return "Choose an amount within the sliding scale.";
16772
- return null;
17063
+ const { minAmount, maxAmount } = input.slidingScale;
17064
+ return input.selectedAmount < minAmount || input.selectedAmount > maxAmount ? "Choose an amount within the sliding scale." : null;
17065
+ }
17066
+ function getRegistrationOccurrenceId(target) {
17067
+ return target?.subject.kind === "occurrence" ? target.subject.occurrenceId : "";
17068
+ }
17069
+ function shouldLoadRegistrationOptions(authState, step) {
17070
+ return authState === "authenticated" || step === "select-tickets" || step === "enter-details" || step === "select-payment";
17071
+ }
17072
+ function getEligibilityFlowFlags(input) {
17073
+ const hasPass = (input.eligibility?.eligiblePasses.length ?? 0) > 0;
17074
+ const hasMembership = (input.eligibility?.eligibleMemberships.length ?? 0) > 0;
17075
+ return {
17076
+ hasEligibility: hasPass || hasMembership,
17077
+ hasMembershipEligibility: hasMembership,
17078
+ isMembershipFastTrack: input.portalAuthState === "authenticated" && hasMembership && input.ticketsCount === 1 && input.paymentMethod === "membership"
17079
+ };
17080
+ }
17081
+ //#endregion
17082
+ //#region ../blocks/src/system/runtime/nodes/event-registration/waitlistClaimRestoration.ts
17083
+ function resolveWaitlistClaimRestoration(input) {
17084
+ const { subject } = input.claim;
17085
+ if (subject.kind === "event_occurrence") {
17086
+ const event = findEventByOccurrenceId(input.scopedEvents, subject.occurrenceId);
17087
+ if (!event && input.occurrenceContextId !== subject.occurrenceId) return {
17088
+ ok: false,
17089
+ message: "This waitlist claim is for a different event."
17090
+ };
17091
+ return {
17092
+ ok: true,
17093
+ event,
17094
+ attendanceMode: subject.attendanceMode,
17095
+ ticketSelections: [{
17096
+ ticketTypeId: null,
17097
+ quantity: 1
17098
+ }],
17099
+ ticketsCount: 1,
17100
+ slidingAmountInput: null
17101
+ };
17102
+ }
17103
+ const event = input.scopedEvents.find((candidate) => candidate.registrationSubject.kind === "wholeSeries" && candidate.registrationSubject.eventSeriesId === subject.eventSeriesId);
17104
+ if (!event) return {
17105
+ ok: false,
17106
+ message: "This waitlist claim is for a different event run."
17107
+ };
17108
+ return {
17109
+ ok: true,
17110
+ event,
17111
+ attendanceMode: subject.attendanceMode,
17112
+ ticketSelections: subject.ticketSelections,
17113
+ ticketsCount: subject.seatCount,
17114
+ slidingAmountInput: subject.selectedSlidingAmount === null ? null : formatCentsAsCurrencyInput(subject.selectedSlidingAmount)
17115
+ };
17116
+ }
17117
+ function resolveClaimedTicketSelections(claim) {
17118
+ if (!claim) return null;
17119
+ return claim.subject.kind === "whole_series" ? claim.subject.ticketSelections : [{
17120
+ ticketTypeId: null,
17121
+ quantity: 1
17122
+ }];
17123
+ }
17124
+ function resolveClaimTicketCount(claim, fallback) {
17125
+ if (!claim) return fallback;
17126
+ return claim.subject.kind === "whole_series" ? claim.subject.seatCount : 1;
17127
+ }
17128
+ //#endregion
17129
+ //#region ../blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.ts
17130
+ function useWaitlistClaimRestoration(input) {
17131
+ useEffect(() => {
17132
+ if (!input.claim) return;
17133
+ const restoration = resolveWaitlistClaimRestoration({
17134
+ claim: input.claim,
17135
+ scopedEvents: input.scopedEvents,
17136
+ occurrenceContextId: input.occurrenceContextId
17137
+ });
17138
+ if (!restoration.ok) {
17139
+ input.setters.setErrorMessage(restoration.message);
17140
+ input.setters.setStep("error");
17141
+ return;
17142
+ }
17143
+ if (restoration.event) input.setters.setSelectedEvent(restoration.event);
17144
+ input.setters.setAttendanceMode(restoration.attendanceMode);
17145
+ input.setters.setTicketSelections([...restoration.ticketSelections]);
17146
+ if (restoration.slidingAmountInput !== null) input.setters.setSlidingAmountInput(restoration.slidingAmountInput);
17147
+ input.setters.setTicketsCount(restoration.ticketsCount);
17148
+ input.setters.setFormData((previous) => ({
17149
+ ...previous,
17150
+ email: input.claim?.prefill.email ?? "",
17151
+ name: input.claim?.prefill.name ?? "",
17152
+ phone: input.claim?.prefill.phone ?? "",
17153
+ notes: input.claim?.prefill.notes ?? ""
17154
+ }));
17155
+ input.setters.setGuests(input.claim.prefill.guests.map((guest) => ({
17156
+ name: guest.name,
17157
+ email: guest.email ?? "",
17158
+ phone: guest.phone ?? ""
17159
+ })));
17160
+ }, [
17161
+ input.claim,
17162
+ input.occurrenceContextId,
17163
+ input.scopedEvents,
17164
+ input.setters
17165
+ ]);
16773
17166
  }
17167
+ //#endregion
17168
+ //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
17169
+ const eventRegistrationWizardDeps = {
17170
+ usePortalAuth,
17171
+ useEligibility,
17172
+ useExistingEventRegistration,
17173
+ useWaitlistClaim,
17174
+ useEventRegistrationStripeReturn,
17175
+ useEventRegistrationSubmit,
17176
+ useDiscountCodeUi
17177
+ };
16774
17178
  function useEventRegistrationWizard(options) {
16775
17179
  return useEventRegistrationWizardWithDeps(options, eventRegistrationWizardDeps);
16776
17180
  }
16777
17181
  function useEventRegistrationWizardWithDeps(options, deps) {
16778
17182
  const api = useBlockApi();
16779
- const registrationEvents = useMemo(() => toRegistrationEvents(options.events ?? []), [options.events]);
17183
+ const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.wholeSeriesOfferings ?? [])], [options.events, options.wholeSeriesOfferings]);
16780
17184
  const scopedEvents = useMemo(() => {
16781
17185
  return resolveEventRegistrationScopedEvents(registrationEvents, {
16782
17186
  occurrenceContext: options.occurrenceContext,
@@ -16806,15 +17210,15 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16806
17210
  const [selectedTicketLines, setSelectedTicketLines] = useState([]);
16807
17211
  const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState(() => {
16808
17212
  const slidingScale = getSlidingScaleForEvent(preSelectedEvent ?? null);
16809
- return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput$1(slidingScale.suggestedAmount) : "";
17213
+ return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "";
16810
17214
  });
16811
17215
  const [registrationResult, setRegistrationResult] = useState(null);
16812
17216
  const [errorMessage, setErrorMessage] = useState("");
16813
17217
  const [altchaSolution, setAltchaSolution] = useState(null);
16814
- const { authState: portalAuthState, profile: portalProfile, creditState: portalCreditState } = deps.usePortalAuth();
17218
+ const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
16815
17219
  const waitlistClaim = deps.useWaitlistClaim();
16816
17220
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
16817
- const [pendingAttendeeId, setPendingAttendeeId] = useState(null);
17221
+ const [pendingRegistrationReference, setPendingRegistrationReference] = useState(null);
16818
17222
  const [paymentStepState, setPaymentStepState] = useState({
16819
17223
  status: "loading",
16820
17224
  canContinue: false,
@@ -16835,7 +17239,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16835
17239
  occurrenceContext: options.occurrenceContext,
16836
17240
  selectedEvent
16837
17241
  }), [options.occurrenceContext, selectedEvent]);
16838
- const occurrenceId = registrationTarget?.occurrenceId ?? "";
17242
+ const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
16839
17243
  const currentEvent = selectedEvent ?? preSelectedEvent;
16840
17244
  const currentEventPricing = currentEvent ? resolveRuntimeEventPricing(currentEvent) : null;
16841
17245
  const currentEventUsesTicketTypes = currentEventPricing !== null && publicEventPricingMode(currentEventPricing) === "ticket_types";
@@ -16851,11 +17255,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16851
17255
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
16852
17256
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
16853
17257
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
17258
+ const claimedTicketSelections = useMemo(() => resolveClaimedTicketSelections(waitlistClaim.claim), [waitlistClaim.claim]);
16854
17259
  const ticketSelections = useMemo(() => {
16855
- if (waitlistClaim.claim) return [{
16856
- ticketTypeId: null,
16857
- quantity: 1
16858
- }];
17260
+ if (claimedTicketSelections) return [...claimedTicketSelections];
16859
17261
  if (usesTicketTypeSelections) return normalizedSelectedTicketLines;
16860
17262
  return [{
16861
17263
  ticketTypeId: null,
@@ -16865,7 +17267,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16865
17267
  normalizedSelectedTicketLines,
16866
17268
  ticketsCount,
16867
17269
  usesTicketTypeSelections,
16868
- waitlistClaim.claim
17270
+ claimedTicketSelections
16869
17271
  ]);
16870
17272
  useEffect(() => {
16871
17273
  if (flowState.ticketsCount === ticketsCount) return;
@@ -16875,20 +17277,22 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16875
17277
  });
16876
17278
  }, [flowState.ticketsCount, ticketsCount]);
16877
17279
  const eligibilityResult = deps.useEligibility({
16878
- enabled: portalAuthState === "authenticated" || step === "enter-details" || step === "select-payment",
16879
- occurrenceId,
17280
+ enabled: shouldLoadRegistrationOptions(portalAuthState, step),
17281
+ subject: registrationTarget?.subject ?? null,
16880
17282
  attendanceMode: selectedAttendanceMode,
16881
17283
  ticketSelections,
16882
- selectedSlidingAmount: parseCurrencyInputToCents$1(selectedSlidingAmountInput),
16883
- email: formData.email
17284
+ selectedSlidingAmount: parseCurrencyInputToCents(selectedSlidingAmountInput),
17285
+ subjectEmail: getPortalSubjectEmail(portalProfile)
16884
17286
  });
16885
17287
  const existingRegistrationResult = deps.useExistingEventRegistration({
16886
17288
  isAuthenticated: portalAuthState === "authenticated",
16887
- occurrenceId
17289
+ occurrenceId: registrationOccurrenceId
16888
17290
  });
16889
17291
  const eligibility = eligibilityResult.eligibility;
16890
17292
  const eligibilityLoading = eligibilityResult.isLoading;
16891
17293
  const eligibilityError = eligibilityResult.error;
17294
+ const portalCreditState = eligibilityResult.creditState;
17295
+ const registrationState = eligibility?.registration ?? { kind: "none" };
16892
17296
  const setStep = useCallback((nextStep) => {
16893
17297
  dispatchFlow({
16894
17298
  type: "set-step",
@@ -16898,43 +17302,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16898
17302
  const setTicketsCount = useCallback((nextTicketsCount) => {
16899
17303
  dispatchFlow({
16900
17304
  type: "set-tickets-count",
16901
- ticketsCount: waitlistClaim.claim ? 1 : nextTicketsCount
17305
+ ticketsCount: resolveClaimTicketCount(waitlistClaim.claim, nextTicketsCount)
16902
17306
  });
16903
17307
  }, [waitlistClaim.claim]);
16904
- useEffect(() => {
16905
- const claim = waitlistClaim.claim;
16906
- if (!claim || claim.subject.kind !== "event_occurrence") return;
16907
- const occurrenceId = claim.subject.occurrenceId;
16908
- const matchedEvent = findEventByOccurrenceId(scopedEvents, occurrenceId);
16909
- if (!matchedEvent && options.occurrenceContext?.id !== occurrenceId) {
16910
- setErrorMessage("This waitlist claim is for a different event.");
16911
- setStep("error");
16912
- return;
16913
- }
16914
- if (matchedEvent) setSelectedEvent(matchedEvent);
16915
- setSelectedAttendanceMode(claim.subject.attendanceMode);
16916
- dispatchFlow({
17308
+ const waitlistRestorationSetters = useMemo(() => ({
17309
+ setErrorMessage,
17310
+ setStep,
17311
+ setSelectedEvent,
17312
+ setAttendanceMode: setSelectedAttendanceMode,
17313
+ setTicketSelections: setSelectedTicketLines,
17314
+ setSlidingAmountInput: setSelectedSlidingAmountInput,
17315
+ setTicketsCount: (count) => dispatchFlow({
16917
17316
  type: "set-tickets-count",
16918
- ticketsCount: 1
16919
- });
16920
- setFormData((prev) => ({
16921
- ...prev,
16922
- email: claim.prefill.email,
16923
- name: claim.prefill.name,
16924
- phone: claim.prefill.phone ?? "",
16925
- notes: claim.prefill.notes ?? ""
16926
- }));
16927
- setGuests(claim.prefill.guests.map((guest) => ({
16928
- name: guest.name,
16929
- email: guest.email ?? "",
16930
- phone: guest.phone ?? ""
16931
- })));
16932
- }, [
16933
- waitlistClaim.claim,
17317
+ ticketsCount: count
17318
+ }),
17319
+ setFormData,
17320
+ setGuests
17321
+ }), [setStep]);
17322
+ useWaitlistClaimRestoration({
17323
+ claim: waitlistClaim.claim,
16934
17324
  scopedEvents,
16935
- options.occurrenceContext?.id,
16936
- setStep
16937
- ]);
17325
+ occurrenceContextId: options.occurrenceContext?.id,
17326
+ setters: waitlistRestorationSetters
17327
+ });
16938
17328
  useEffect(() => {
16939
17329
  if (waitlistClaim.requiresPortalLogin) return;
16940
17330
  if (!waitlistClaim.error) return;
@@ -16990,9 +17380,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16990
17380
  const verification = deps.useEventRegistrationStripeReturn({
16991
17381
  api,
16992
17382
  events: registrationEvents,
16993
- occurrenceId,
17383
+ registrationSubject: registrationTarget?.subject ?? null,
16994
17384
  step,
16995
- pendingAttendeeId,
17385
+ pendingRegistrationReference,
16996
17386
  setFormData,
16997
17387
  setTicketsCount,
16998
17388
  setSelectedEvent,
@@ -17002,7 +17392,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17002
17392
  type: "set-manual-payment-selection",
17003
17393
  selection
17004
17394
  }),
17005
- setPendingAttendeeId,
17395
+ setPendingRegistrationReference,
17006
17396
  setStep,
17007
17397
  setRegistrationResult: (result) => setRegistrationResult(result),
17008
17398
  setErrorMessage
@@ -17031,7 +17421,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17031
17421
  selectedAttendanceMode,
17032
17422
  singleSelectedTicketTypeId
17033
17423
  ]);
17034
- const selectedSlidingAmount = useMemo(() => parseCurrencyInputToCents$1(selectedSlidingAmountInput), [selectedSlidingAmountInput]);
17424
+ const selectedSlidingAmount = useMemo(() => parseCurrencyInputToCents(selectedSlidingAmountInput), [selectedSlidingAmountInput]);
17035
17425
  const selectedEventSlidingScale = useMemo(() => getSlidingScaleForEvent(selectedEvent ?? preSelectedEvent), [selectedEvent, preSelectedEvent]);
17036
17426
  const slidingScaleSelectionMessage = getSlidingScaleSelectionMessage({
17037
17427
  slidingScale: selectedEventSlidingScale,
@@ -17277,7 +17667,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17277
17667
  guests,
17278
17668
  discountCode: discountUi.discountCode,
17279
17669
  claimToken: waitlistClaim.token,
17280
- setPendingAttendeeId: (id) => setPendingAttendeeId(id),
17670
+ setPendingRegistrationReference,
17281
17671
  setStep,
17282
17672
  setRegistrationResult: (result) => setRegistrationResult(result),
17283
17673
  setErrorMessage
@@ -17289,7 +17679,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17289
17679
  consentAccepted: false
17290
17680
  }));
17291
17681
  const slidingScale = getSlidingScaleForEvent(event);
17292
- setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput$1(slidingScale.suggestedAmount) : "");
17682
+ setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "");
17293
17683
  setSelectedAttendanceMode((event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person");
17294
17684
  setSelectedTicketLines([]);
17295
17685
  dispatchFlow({
@@ -17306,7 +17696,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17306
17696
  setSelectedSlidingAmountInput("");
17307
17697
  setSelectedAttendanceMode(preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null);
17308
17698
  setErrorMessage("");
17309
- setPendingAttendeeId(null);
17699
+ setPendingRegistrationReference(null);
17310
17700
  };
17311
17701
  const handlePaymentStepStateChange = useCallback((state) => {
17312
17702
  setPaymentStepState(state);
@@ -17317,9 +17707,12 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17317
17707
  selection
17318
17708
  });
17319
17709
  }, []);
17320
- const hasEligibility = eligibility !== null && (eligibility.eligiblePasses.length > 0 || eligibility.eligibleMemberships.length > 0);
17321
- const hasMembershipEligibility = eligibility !== null && eligibility.eligibleMemberships.length > 0;
17322
- const isMembershipFastTrack = portalAuthState === "authenticated" && hasMembershipEligibility && ticketsCount === 1 && paymentSelection.method === "membership";
17710
+ const { hasEligibility, hasMembershipEligibility, isMembershipFastTrack } = getEligibilityFlowFlags({
17711
+ eligibility,
17712
+ portalAuthState,
17713
+ ticketsCount,
17714
+ paymentMethod: paymentSelection.method
17715
+ });
17323
17716
  return {
17324
17717
  api,
17325
17718
  anchorId: options.anchorId,
@@ -17327,7 +17720,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17327
17720
  registrationTarget,
17328
17721
  subject: options.subject,
17329
17722
  events: options.events,
17330
- maxTicketsNum: waitlistClaim.claim ? 1 : options.maxTicketsNum,
17723
+ maxTicketsNum: resolveClaimTicketCount(waitlistClaim.claim, options.maxTicketsNum),
17331
17724
  scopedEvents,
17332
17725
  preSelectedEvent,
17333
17726
  hasPreSelectedContext,
@@ -17341,7 +17734,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17341
17734
  setSelectedAttendanceMode,
17342
17735
  ticketSelections,
17343
17736
  selectedTicketLines: normalizedSelectedTicketLines,
17344
- setSelectedTicketLines: (lines) => setSelectedTicketLines(normalizeTicketSelectionLines(lines)),
17737
+ setSelectedTicketLines: (lines) => {
17738
+ if (waitlistClaim.claim) return;
17739
+ setSelectedTicketLines(normalizeTicketSelectionLines(lines));
17740
+ },
17345
17741
  selectedSlidingAmountInput,
17346
17742
  setSelectedSlidingAmountInput,
17347
17743
  selectedSlidingAmount,
@@ -17382,8 +17778,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17382
17778
  eligibilityLoading,
17383
17779
  eligibilityError,
17384
17780
  existingRegistration: existingRegistrationResult.registration,
17385
- existingRegistrationLoading: existingRegistrationResult.isLoading,
17781
+ existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
17386
17782
  existingRegistrationState: existingRegistrationResult.state,
17783
+ registrationState,
17387
17784
  hasEligibility,
17388
17785
  hasMembershipEligibility,
17389
17786
  requireGuestDetails,
@@ -17408,85 +17805,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
17408
17805
  };
17409
17806
  }
17410
17807
  //#endregion
17411
- //#region ../blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.ts
17412
- const DEFAULT_EVENT_DIRECT_PAYMENT_OPTION = { kind: "upfront" };
17413
- function buildEventRegistrationPaymentOptionsViewModel(input) {
17414
- const supportedOptions = selectSupportedEventDirectPaymentOptions(input.paymentTerms);
17415
- const selection = buildBookingPaymentSelectionViewModel({
17416
- serviceTitle: input.eventTitle,
17417
- paymentTerms: { allowedOptions: [...supportedOptions] },
17418
- priceAmount: input.totalPriceCents,
17419
- priceCurrency: input.currency,
17420
- bookingStartAt: input.startsAt,
17421
- locale: input.locale
17422
- });
17423
- return {
17424
- mode: selection.mode,
17425
- sectionTitle: selection.sectionTitle,
17426
- options: selection.options.map((option, index) => toEventDirectPaymentOption(option, supportedOptions[index] ?? DEFAULT_EVENT_DIRECT_PAYMENT_OPTION, selection.mode, input.totalPriceCents))
17427
- };
17428
- }
17429
- function selectSupportedEventDirectPaymentOptions(paymentTerms) {
17430
- const supported = paymentTerms?.allowedOptions.filter(isSupportedEventDirectPaymentOption) ?? [];
17431
- return supported.length > 0 ? supported : [DEFAULT_EVENT_DIRECT_PAYMENT_OPTION];
17432
- }
17433
- function isSupportedEventDirectPaymentOption(option) {
17434
- return option.kind === "upfront" || option.kind === "flexible_balance";
17435
- }
17436
- function toEventDirectPaymentOption(option, sourceOption, mode, totalCents) {
17437
- switch (option.kind) {
17438
- case "upfront": return {
17439
- ...option,
17440
- kind: "upfront",
17441
- label: mode === "choice_required" ? "Pay in full now" : "Pay by card",
17442
- totalCents,
17443
- configuredPaymentDueNowCents: totalCents
17444
- };
17445
- case "flexible_balance": return {
17446
- ...option,
17447
- kind: "flexible_balance",
17448
- label: "Pay deposit now",
17449
- totalCents,
17450
- configuredPaymentDueNowCents: sourceOption.kind === "flexible_balance" ? resolveFlexibleBalanceInitialPaymentCents({
17451
- totalAmountCents: totalCents,
17452
- config: sourceOption.config
17453
- }) : totalCents
17454
- };
17455
- case "deferred_manual":
17456
- case "instalment_plan": throw new Error(`Unsupported event registration payment option: ${option.kind}`);
17457
- }
17458
- }
17459
- function resolveEventRegistrationDirectPaymentSelection(input) {
17460
- if (input.selection.method !== "stripe") return { kind: "not-stripe" };
17461
- const fallbackOption = input.options[0];
17462
- if (!fallbackOption) return { kind: "unavailable" };
17463
- const requestedKind = input.selection.collectionOptionKind;
17464
- const selectedOption = requestedKind == null ? input.options.find((option) => option.kind === "upfront") : input.options.find((option) => option.kind === requestedKind);
17465
- if (selectedOption) return {
17466
- kind: "valid",
17467
- selection: {
17468
- method: "stripe",
17469
- collectionOptionKind: selectedOption.kind
17470
- }
17471
- };
17472
- return {
17473
- kind: "invalid",
17474
- fallbackSelection: {
17475
- method: "stripe",
17476
- collectionOptionKind: fallbackOption.kind
17477
- }
17478
- };
17479
- }
17480
- function normalizeEventRegistrationDirectPaymentSelection(input) {
17481
- const selectionState = resolveEventRegistrationDirectPaymentSelection(input);
17482
- switch (selectionState.kind) {
17483
- case "valid": return selectionState.selection;
17484
- case "invalid": return selectionState.fallbackSelection;
17485
- case "not-stripe":
17486
- case "unavailable": return input.selection;
17487
- }
17488
- }
17489
- //#endregion
17490
17808
  //#region ../blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.ts
17491
17809
  const eventRegistrationControllerDeps = { useEventRegistrationWizard };
17492
17810
  function HeadlessEventRegistrationProvider$1({ config, children }) {
@@ -17776,1338 +18094,30 @@ function resolveHeadlessDirectPaymentOptions(wizard) {
17776
18094
  const event = wizard.selectedEvent ?? wizard.preSelectedEvent;
17777
18095
  return buildEventRegistrationPaymentOptionsViewModel({
17778
18096
  eventTitle: event?.title ?? "Event",
17779
- paymentTerms: event?.paymentTerms,
18097
+ approvedPaymentOptions: eligibility.paymentOptions,
18098
+ paymentTerms: eligibility.paymentTerms,
17780
18099
  totalPriceCents: eligibility.price,
17781
18100
  currency: eligibility.currency,
17782
18101
  startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt
17783
18102
  }).options;
17784
18103
  }
17785
18104
  //#endregion
17786
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/utils.ts
17787
- /**
17788
- * Anchor ID for the registration block, used for scroll targeting.
17789
- */
17790
- const WHOLE_SERIES_REGISTRATION_ANCHOR_ID = "event-registration";
17791
- //#endregion
17792
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/pricing.ts
17793
- function parseCurrencyInputToCents(value) {
17794
- const trimmed = value.trim();
17795
- if (!trimmed) return null;
17796
- const amount = Number(trimmed);
17797
- if (!Number.isFinite(amount) || amount < 0) return null;
17798
- return Math.round(amount * 100);
17799
- }
17800
- function formatCentsAsCurrencyInput(amount) {
17801
- const major = amount / 100;
17802
- return Number.isInteger(major) ? String(major) : major.toFixed(2);
17803
- }
17804
- function getMissingWholeSeriesPricingSelectionMessage(pricing) {
17805
- if (pricing?.requiresSelection && !pricing.selectedOption) return pricing.slidingScale ? "Choose an amount to continue." : "Choose a pricing option to continue.";
17806
- const selectedAmount = pricing?.selectedSlidingAmount;
17807
- const scale = pricing?.slidingScale;
17808
- if (scale && selectedAmount !== null && selectedAmount !== void 0 && (selectedAmount < scale.minAmount || selectedAmount > scale.maxAmount)) return "Choose an amount within the sliding scale.";
17809
- return null;
17810
- }
17811
- function buildWholeSeriesPricingOptionPayload(pricing) {
17812
- if (pricing?.selectedOption) return { pricingOptionId: pricing.selectedOption.id };
17813
- if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) return { selectedSlidingAmount: pricing.selectedSlidingAmount };
17814
- return {};
17815
- }
17816
- function defaultWholeSeriesPricingSelection(pricing, previousOptionId) {
17817
- return {
17818
- pricingOptionId: previousOptionId && pricing.selectableOptions.some((option) => option.id === previousOptionId) ? previousOptionId : pricing.selectedOption?.id ?? null,
17819
- slidingAmountInput: pricing.slidingScale?.suggestedAmount !== null && pricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(pricing.slidingScale.suggestedAmount) : ""
17820
- };
17821
- }
17822
- //#endregion
17823
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wizardSteps.ts
17824
- /**
17825
- * Step labels for the wizard indicator
17826
- */
17827
- const STEP_LABELS = {
17828
- "select-run": "Run",
17829
- "enter-details": "Details",
17830
- "booking-mode": "Method",
17831
- "select-payment": "Payment",
17832
- submitting: "Booking",
17833
- redirecting: "Redirecting",
17834
- "verifying-payment": "Verifying",
17835
- "verifying-timeout": "Timeout",
17836
- "payment-failed": "Failed",
17837
- success: "Complete",
17838
- waitlist: "Waitlist",
17839
- error: "Error"
17840
- };
17841
- /**
17842
- * Determine which wizard steps to show based on context and eligibility.
17843
- *
17844
- * @param hasPreSelectedRun - Whether run is pre-selected (skips run selection)
17845
- * @param requiresPayment - Whether the run requires payment
17846
- * @param hasEligibleMemberships - Whether user has eligible memberships
17847
- * @param bookingMode - Current booking mode selection
17848
- * @param isMembershipFastTrack - Whether user qualifies for single-step membership flow
17849
- * @returns Array of wizard steps to display
17850
- */
17851
- function getWizardStepsForContext(hasPreSelectedRun, requiresPayment, hasEligibleMemberships, bookingMode, isMembershipFastTrack) {
17852
- if (isMembershipFastTrack) return hasPreSelectedRun ? ["enter-details"] : ["select-run", "enter-details"];
17853
- if (!requiresPayment) return hasPreSelectedRun ? ["enter-details"] : ["select-run", "enter-details"];
17854
- if (hasEligibleMemberships) {
17855
- const skipPayment = bookingMode === "membership";
17856
- if (hasPreSelectedRun) return skipPayment ? ["enter-details", "booking-mode"] : [
17857
- "enter-details",
17858
- "booking-mode",
17859
- "select-payment"
17860
- ];
17861
- return skipPayment ? [
17862
- "select-run",
17863
- "enter-details",
17864
- "booking-mode"
17865
- ] : [
17866
- "select-run",
17867
- "enter-details",
17868
- "booking-mode",
17869
- "select-payment"
17870
- ];
17871
- }
17872
- return hasPreSelectedRun ? ["enter-details", "select-payment"] : [
17873
- "select-run",
17874
- "enter-details",
17875
- "select-payment"
17876
- ];
17877
- }
17878
- /**
17879
- * Get labels for a list of wizard steps
17880
- */
17881
- function getStepLabels(steps) {
17882
- return steps.map((step) => STEP_LABELS[step] ?? step);
17883
- }
17884
- //#endregion
17885
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesRegistrationViewState.ts
17886
- function deriveWholeSeriesRegistrationViewState(input) {
17887
- const hasRunPayment = resolveWholeSeriesPaymentRequirement(input.pricing);
17888
- const canUseMembership = hasRunPayment && input.selectedRun?.acceptsMemberships === true && input.portalAuthState === "authenticated" && input.eligibleMembershipCount > 0;
17889
- const hasPreSelectedRun = input.scopedRuns.length === 1;
17890
- const fastTrack = canUseMembership && input.eligibleMembershipCount === 1 && input.bookingMode === "membership";
17891
- const wizardSteps = getWizardStepsForContext(hasPreSelectedRun, hasRunPayment, canUseMembership, input.bookingMode, fastTrack);
17892
- const showPortalAuthSidebar = shouldShowPortalAuthSidebar({
17893
- ...input,
17894
- hasRunPayment
17895
- });
18105
+ //#region ../blocks/src/system/runtime/hooks/useBookingFormConfig.state.ts
18106
+ const EMPTY_SNAPSHOT = Object.freeze({
18107
+ formConfig: null,
18108
+ services: []
18109
+ });
18110
+ function createInitialBookingFormConfigState() {
17896
18111
  return {
17897
- hasRunPayment,
17898
- canUseMembership,
17899
- hasPreSelectedRun,
17900
- wizardSteps,
17901
- currentStepNumber: getStepNumber(input.step, wizardSteps),
17902
- totalSteps: wizardSteps.length,
17903
- stepLabels: getStepLabels(wizardSteps),
17904
- showPortalAuthSidebar
18112
+ tag: "loading",
18113
+ previous: EMPTY_SNAPSHOT
17905
18114
  };
17906
18115
  }
17907
- function resolveWholeSeriesPaymentRequirement(pricing) {
17908
- if (!pricing) return false;
17909
- return pricing.selectedOption ? pricing.selectedRequiresPayment : pricing.hasPaidSelection;
17910
- }
17911
- function shouldShowPortalAuthSidebar(input) {
17912
- if (input.portalAuthState !== "unauthenticated") return false;
17913
- if (input.step === "success" || input.step === "waitlist" || input.step === "error") return false;
17914
- return input.waitlistRequiresPortalLogin || input.hasRunPayment && input.selectedRun?.acceptsMemberships === true && input.step !== "select-run";
17915
- }
17916
- //#endregion
17917
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesEligibility.ts
17918
- function shouldFetchEligibility(input) {
17919
- if (!input.run || input.portalAuthState === "checking" || input.hasWaitlistClaimToken) return false;
17920
- const membershipCheck = input.portalAuthState === "authenticated" && input.hasPaidSelection && input.run.acceptsMemberships;
17921
- const capacityCheck = input.run.availableSpots !== null && input.run.availableSpots <= 0;
17922
- return membershipCheck || capacityCheck;
17923
- }
17924
- function useWholeSeriesEligibility(input) {
17925
- const [loading, setLoading] = useState(false);
17926
- const [error, setError] = useState(null);
17927
- const [eligibility, setEligibility] = useState(null);
17928
- const [memberships, setMemberships] = useState([]);
17929
- const [paymentChoice, setPaymentChoice] = useState("checkout");
17930
- const [selectedMembershipId, setSelectedMembershipId] = useState(null);
17931
- const choosePaymentChoice = useCallback((choice) => {
17932
- setPaymentChoice(choice);
17933
- }, []);
17934
- const chooseMembership = useCallback((membershipId) => {
17935
- setSelectedMembershipId(membershipId);
17936
- }, []);
17937
- useEffect(() => {
17938
- let cancelled = false;
17939
- setEligibility(null);
17940
- setMemberships([]);
17941
- setSelectedMembershipId(null);
17942
- setError(null);
17943
- setPaymentChoice("checkout");
17944
- const eligibilityInput = {
17945
- run: input.selectedRun,
17946
- hasPaidSelection: input.hasPaidSelection,
17947
- portalAuthState: input.portalAuthState,
17948
- hasWaitlistClaimToken: input.waitlistClaimToken !== null
17949
- };
17950
- if (!shouldFetchEligibility(eligibilityInput)) return;
17951
- const run = eligibilityInput.run;
17952
- setLoading(true);
17953
- input.api.checkWholeSeriesEligibility({ eventSeriesId: run.eventSeriesId }).then((result) => {
17954
- if (cancelled) return;
17955
- const eligibleMemberships = result.eligibleMemberships ?? [];
17956
- setEligibility(result);
17957
- setMemberships(eligibleMemberships);
17958
- if (input.portalAuthState === "authenticated" && eligibleMemberships.length > 0) {
17959
- setPaymentChoice("membership");
17960
- if (eligibleMemberships.length === 1) setSelectedMembershipId(eligibleMemberships[0]?.customerMembershipId ?? null);
17961
- }
17962
- }).catch((cause) => {
17963
- if (!cancelled) setError(cause instanceof Error ? cause.message : "Failed to check membership eligibility");
17964
- }).finally(() => {
17965
- if (!cancelled) setLoading(false);
17966
- });
17967
- return () => {
17968
- cancelled = true;
17969
- };
17970
- }, [
17971
- input.api,
17972
- input.hasPaidSelection,
17973
- input.portalAuthState,
17974
- input.selectedRun,
17975
- input.waitlistClaimToken
17976
- ]);
17977
- return {
17978
- eligibilityLoading: loading,
17979
- eligibilityError: error,
17980
- runEligibility: eligibility,
17981
- eligibleMemberships: memberships,
17982
- paymentChoice,
17983
- choosePaymentChoice,
17984
- selectedMembershipId,
17985
- chooseMembership
17986
- };
17987
- }
17988
- //#endregion
17989
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesPageSurfaceScope.ts
17990
- /**
17991
- * Resolves native run-page ownership without falling back to entry or slug
17992
- * coincidence when a page-surface subject is present but invalid.
17993
- */
17994
- function resolveWholeSeriesPageSurfaceScope(runs, subjectValue) {
17995
- if (subjectValue === null || subjectValue === void 0) return { kind: "absent" };
17996
- const parsed = parseEventPageSurfaceSubject(subjectValue);
17997
- if (!parsed.ok) return {
17998
- kind: "unsupported",
17999
- reason: parsed.error.kind
18000
- };
18001
- const seriesIds = eventSeriesIdsForSubject(parsed.value);
18002
- const allowedSeriesIds = new Set(seriesIds);
18003
- return {
18004
- kind: "scoped",
18005
- subject: parsed.value,
18006
- runs: runs.filter((run) => allowedSeriesIds.has(run.eventSeriesId))
18007
- };
18008
- }
18009
- function eventSeriesIdsForSubject(subject) {
18010
- switch (subject.kind) {
18011
- case "eventSeries": return [subject.eventSeriesId];
18012
- case "eventOffering": return subject.availableEventSeriesIds;
18013
- default: return assertNever$3(subject);
18014
- }
18015
- }
18016
- //#endregion
18017
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationSelection.ts
18018
- function selectScopedRuns(props) {
18019
- const surfaceScope = resolveWholeSeriesPageSurfaceScope(props.runs ?? [], props.subject);
18020
- if (surfaceScope.kind === "unsupported") return [];
18021
- if (surfaceScope.kind === "scoped") return surfaceScope.runs;
18022
- return [];
18023
- }
18024
- function getWholeSeriesCheckoutSessionId(location = window.location) {
18025
- const fromSearch = new URLSearchParams(location.search).get("session_id");
18026
- if (fromSearch) return fromSearch;
18027
- return location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
18028
- }
18029
- function initialStep(runs, location) {
18030
- if (new URLSearchParams(location.search).get("enrollment") === "success" && getWholeSeriesCheckoutSessionId(location)) return "verifying-payment";
18031
- return runs.length === 1 ? "enter-details" : "select-run";
18032
- }
18033
- function useWholeSeriesRegistrationSelection(props, location = window.location) {
18034
- const scopeSnapshot = JSON.stringify({
18035
- runs: props.runs ?? [],
18036
- subject: props.subject ?? null
18037
- });
18038
- const stableScope = useRef(null);
18039
- if (stableScope.current?.snapshot !== scopeSnapshot) stableScope.current = {
18040
- snapshot: scopeSnapshot,
18041
- runs: selectScopedRuns(props)
18042
- };
18043
- const scopedRuns = stableScope.current.runs;
18044
- const [step, setStep] = useState(() => initialStep(scopedRuns, location));
18045
- const [selectedRunId, setSelectedRunId] = useState(scopedRuns.length === 1 ? scopedRuns[0]?.eventSeriesId ?? null : null);
18046
- const selectedRun = useMemo(() => scopedRuns.find((run) => run.eventSeriesId === selectedRunId) ?? (scopedRuns.length === 1 ? scopedRuns[0] ?? null : null), [scopedRuns, selectedRunId]);
18047
- const [selectedPricingOptionId, setSelectedPricingOptionId] = useState(null);
18048
- const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState("");
18049
- const goToStep = useCallback((nextStep) => {
18050
- setStep(nextStep);
18051
- }, []);
18052
- const chooseRun = useCallback((run) => {
18053
- setSelectedRunId(run.eventSeriesId);
18054
- }, []);
18055
- const choosePricingOption = useCallback((pricingOptionId) => {
18056
- setSelectedPricingOptionId(pricingOptionId);
18057
- }, []);
18058
- const changeSlidingAmount = useCallback((amount) => {
18059
- setSelectedSlidingAmountInput(amount);
18060
- }, []);
18061
- const selectedRunPricing = useMemo(() => selectedRun ? resolveWholeSeriesPricingState(selectedRun, selectedPricingOptionId, parseCurrencyInputToCents(selectedSlidingAmountInput)) : null, [
18062
- selectedRun,
18063
- selectedPricingOptionId,
18064
- selectedSlidingAmountInput
18065
- ]);
18066
- useEffect(() => {
18067
- if (!selectedRun) {
18068
- setSelectedPricingOptionId(null);
18069
- setSelectedSlidingAmountInput("");
18070
- return;
18071
- }
18072
- const selection = defaultWholeSeriesPricingSelection(resolveWholeSeriesPricingState(selectedRun, null), selectedPricingOptionId);
18073
- setSelectedPricingOptionId(selection.pricingOptionId);
18074
- setSelectedSlidingAmountInput(selection.slidingAmountInput);
18075
- }, [selectedRun?.eventSeriesId]);
18076
- return {
18077
- scopedRuns,
18078
- step,
18079
- goToStep,
18080
- selectedRun,
18081
- chooseRun,
18082
- selectedPricingOptionId,
18083
- choosePricingOption,
18084
- selectedSlidingAmountInput,
18085
- changeSlidingAmount,
18086
- selectedRunPricing
18087
- };
18088
- }
18089
- //#endregion
18090
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesPaymentVerification.ts
18091
- function applyTerminalStatus(status, setters) {
18092
- if (status === "enrolled" || status === "completed") {
18093
- setters.setEnrollmentResult({
18094
- status: "enrolled",
18095
- usedMembership: false
18096
- });
18097
- setters.setStep("success");
18098
- return true;
18099
- }
18100
- if (status === "waitlist") {
18101
- setters.setEnrollmentResult({
18102
- status: "waitlist",
18103
- usedMembership: false
18104
- });
18105
- setters.setStep("waitlist");
18106
- return true;
18107
- }
18108
- setters.setErrorMessage("Payment did not complete. Please try again.");
18109
- setters.setStep("error");
18110
- return true;
18111
- }
18112
- async function pollWholeSeriesRegistrationStatus(api, sessionId, setters, isCancelled) {
18113
- const startedAt = Date.now();
18114
- while (!isCancelled()) {
18115
- try {
18116
- const result = await api.getWholeSeriesRegistrationStatus({ sessionId });
18117
- if (isCancelled()) return;
18118
- if (result.status !== "pending_payment") {
18119
- applyTerminalStatus(result.status, setters);
18120
- return;
18121
- }
18122
- } catch (cause) {
18123
- setters.setErrorMessage(cause instanceof Error ? cause.message : "Failed to verify payment");
18124
- }
18125
- if (Date.now() - startedAt > 3e4) {
18126
- setters.setErrorMessage("Payment is still processing. Please check your email for confirmation.");
18127
- setters.setStep("error");
18128
- return;
18129
- }
18130
- await new Promise((resolve) => setTimeout(resolve, 1500));
18131
- }
18132
- }
18133
- function useWholeSeriesPaymentVerification(api, setters, anchorId = WHOLE_SERIES_REGISTRATION_ANCHOR_ID, location = window.location) {
18134
- useEffect(() => {
18135
- let cancelled = false;
18136
- const enrollment = new URLSearchParams(location.search).get("enrollment");
18137
- const sessionId = getWholeSeriesCheckoutSessionId(location);
18138
- if (enrollment === "cancelled") {
18139
- scrollToBlock(anchorId);
18140
- setters.setErrorMessage("Payment was cancelled. You can try again.");
18141
- setters.setStep("error");
18142
- return;
18143
- }
18144
- if (enrollment !== "success" || !sessionId) return;
18145
- scrollToBlock(anchorId);
18146
- setters.setStep("verifying-payment");
18147
- pollWholeSeriesRegistrationStatus(api, sessionId, setters, () => cancelled);
18148
- return () => {
18149
- cancelled = true;
18150
- };
18151
- }, [
18152
- api,
18153
- setters.setEnrollmentResult,
18154
- setters.setErrorMessage,
18155
- setters.setStep,
18156
- anchorId,
18157
- location
18158
- ]);
18159
- }
18160
- //#endregion
18161
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationActions.ts
18162
- function blocked(message, setters) {
18163
- setters.setErrorMessage(message);
18164
- setters.setStep("error");
18165
- return {
18166
- kind: "blocked",
18167
- message
18168
- };
18169
- }
18170
- function validateSubmission(state, setters) {
18171
- if (!state.selectedRun) return {
18172
- kind: "blocked",
18173
- message: "Choose an available set of dates to continue."
18174
- };
18175
- const errors = validateFormData$1(state.formData);
18176
- if (state.selectedRun.consent && state.formData.consentAccepted !== true) errors.consentAccepted = "Please read and accept the agreement before continuing.";
18177
- setters.setErrors(errors);
18178
- if (Object.keys(errors).length > 0) return { kind: "validation-failed" };
18179
- const pricingMessage = getMissingWholeSeriesPricingSelectionMessage(state.pricing);
18180
- if (pricingMessage) return blocked(pricingMessage, setters);
18181
- if (!state.hasClaim && state.eligibility?.isFull && !state.eligibility.canJoinWaitlist) return blocked(state.eligibility.reason ?? "This run is fully booked.", setters);
18182
- if (isSpamProtectionEnabled() && !state.altchaSolution) return blocked("Please complete the verification check.", setters);
18183
- return null;
18184
- }
18185
- function enrollmentPayload(state, payment) {
18186
- return {
18187
- ...registrantPayload(state),
18188
- paymentMethod: payment.method,
18189
- ...payment.method === "membership" ? { customerMembershipId: payment.membershipId } : {}
18190
- };
18191
- }
18192
- function registrantPayload(state) {
18193
- return {
18194
- eventSeriesId: state.selectedRun.eventSeriesId,
18195
- ...buildWholeSeriesPricingOptionPayload(state.pricing),
18196
- email: state.formData.email.trim().toLowerCase(),
18197
- name: state.formData.name.trim(),
18198
- phone: state.formData.phone.trim() || void 0,
18199
- formData: { notes: state.formData.notes.trim() || void 0 },
18200
- consentAccepted: state.formData.consentAccepted,
18201
- altchaSolution: state.altchaSolution,
18202
- claimToken: state.claimToken ?? void 0
18203
- };
18204
- }
18205
- async function enroll(state, setters, payment) {
18206
- setters.setStep("submitting");
18207
- try {
18208
- const result = await state.api.registerForWholeSeries(enrollmentPayload(state, payment));
18209
- setters.setEnrollmentResult({
18210
- status: result.status,
18211
- waitlistPosition: result.waitlistPosition ?? void 0,
18212
- usedMembership: payment.method === "membership"
18213
- });
18214
- setters.setStep(result.status === "waitlist" ? "waitlist" : "success");
18215
- return { kind: "state-updated" };
18216
- } catch (cause) {
18217
- const message = cause instanceof Error ? cause.message : "Booking failed";
18218
- setters.setErrorMessage(message);
18219
- setters.setStep("error");
18220
- return {
18221
- kind: "failed",
18222
- message
18223
- };
18224
- }
18225
- }
18226
- async function checkout(state, setters) {
18227
- setters.setStep("submitting");
18228
- try {
18229
- const urls = buildCheckoutReturnUrls("enrollment", state.options.anchorId ?? "event-registration");
18230
- const result = await state.api.createWholeSeriesCheckout({
18231
- ...registrantPayload(state),
18232
- discountCode: state.discountCode.trim() || void 0,
18233
- successUrl: urls.successUrl,
18234
- cancelUrl: urls.cancelUrl
18235
- });
18236
- if (result.bypassed) {
18237
- setters.setEnrollmentResult({
18238
- status: "enrolled",
18239
- usedMembership: false
18240
- });
18241
- setters.setStep("success");
18242
- return { kind: "state-updated" };
18243
- }
18244
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
18245
- setters.setStep("redirecting");
18246
- if (state.options.onCheckoutRedirect) state.options.onCheckoutRedirect(result.checkoutUrl);
18247
- else window.location.href = result.checkoutUrl;
18248
- return {
18249
- kind: "checkout-redirect",
18250
- checkoutUrl: result.checkoutUrl
18251
- };
18252
- } catch (cause) {
18253
- const message = cause instanceof Error ? cause.message : "Checkout failed";
18254
- setters.setErrorMessage(message);
18255
- setters.setStep("error");
18256
- return {
18257
- kind: "failed",
18258
- message
18259
- };
18260
- }
18261
- }
18262
- async function submitDetails(state, setters) {
18263
- const invalid = validateSubmission(state, setters);
18264
- if (invalid || !state.selectedRun) return invalid ?? { kind: "validation-failed" };
18265
- if (state.eligibility?.canJoinWaitlist) return enroll(state, setters, { method: "free" });
18266
- const requiresPayment = state.pricing?.selectedRequiresPayment ?? false;
18267
- const canUseMembership = requiresPayment && state.selectedRun.acceptsMemberships && state.portalAuthState === "authenticated" && state.eligibleMemberships.length > 0;
18268
- if (requiresPayment && canUseMembership) {
18269
- setters.setStep("select-payment");
18270
- return { kind: "state-updated" };
18271
- }
18272
- if (requiresPayment) return checkout(state, setters);
18273
- return enroll(state, setters, { method: "free" });
18274
- }
18275
- async function continuePayment(state, setters) {
18276
- const invalid = validateSubmission(state, setters);
18277
- if (invalid || !state.selectedRun) return invalid ?? { kind: "validation-failed" };
18278
- if (!state.pricing?.selectedRequiresPayment) {
18279
- setters.setStep("enter-details");
18280
- return { kind: "state-updated" };
18281
- }
18282
- const selectedState = state;
18283
- if (state.paymentChoice === "membership") {
18284
- if (!state.selectedMembershipId) return blocked("Select a membership to sign up.", setters);
18285
- return enroll(selectedState, setters, {
18286
- method: "membership",
18287
- membershipId: state.selectedMembershipId
18288
- });
18289
- }
18290
- return checkout(selectedState, setters);
18291
- }
18292
- function useWholeSeriesRegistrationActions(state, setStep) {
18293
- const [errors, setErrors] = useState({});
18294
- const [enrollmentResult, setEnrollmentResult] = useState(null);
18295
- const [errorMessage, setErrorMessage] = useState("");
18296
- const reportError = useCallback((message) => {
18297
- setErrorMessage(message);
18298
- }, []);
18299
- const recordEnrollmentResult = useCallback((result) => {
18300
- setEnrollmentResult(result);
18301
- }, []);
18302
- const setters = {
18303
- setStep,
18304
- setErrors,
18305
- setEnrollmentResult,
18306
- setErrorMessage
18307
- };
18308
- return {
18309
- errors,
18310
- enrollmentResult,
18311
- errorMessage,
18312
- reportError,
18313
- recordEnrollmentResult,
18314
- handleSubmit: () => submitDetails(state, setters),
18315
- handlePaymentContinue: () => continuePayment(state, setters)
18316
- };
18317
- }
18318
- //#endregion
18319
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationPortal.ts
18320
- const EMPTY_FORM = {
18321
- name: "",
18322
- email: "",
18323
- phone: "",
18324
- notes: "",
18325
- consentAccepted: false
18326
- };
18327
- function useWholeSeriesRegistrationPortal(api) {
18328
- const [formData, setFormData] = useState(EMPTY_FORM);
18329
- const [portalAuthState, setPortalAuthState] = useState("checking");
18330
- const updateFormData = useCallback((updater) => {
18331
- setFormData(updater);
18332
- }, []);
18333
- useEffect(() => {
18334
- let cancelled = false;
18335
- if (!(api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer")) {
18336
- setPortalAuthState("unauthenticated");
18337
- return;
18338
- }
18339
- setPortalAuthState("checking");
18340
- api.getPortalProfile().then((result) => {
18341
- if (cancelled) return;
18342
- setPortalAuthState("authenticated");
18343
- setFormData((current) => ({
18344
- ...current,
18345
- email: result.profile.email,
18346
- name: current.name || result.profile.name,
18347
- phone: current.phone || result.profile.phone || ""
18348
- }));
18349
- }).catch(() => {
18350
- if (!cancelled) setPortalAuthState("unauthenticated");
18351
- });
18352
- return () => {
18353
- cancelled = true;
18354
- };
18355
- }, [api]);
18356
- return {
18357
- formData,
18358
- updateFormData,
18359
- portalAuthState
18360
- };
18361
- }
18362
- //#endregion
18363
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesWaitlistSelection.ts
18364
- function useWholeSeriesWaitlistSelection(input) {
18365
- useEffect(() => {
18366
- const claim = input.waitlistClaim.claim;
18367
- if (!claim || claim.subject.kind !== "whole_series") return;
18368
- const eventSeriesId = claim.subject.eventSeriesId;
18369
- const run = input.scopedRuns.find((candidate) => candidate.eventSeriesId === eventSeriesId);
18370
- if (!run) {
18371
- input.reportError("This waitlist claim is for a different run.");
18372
- input.goToStep("error");
18373
- return;
18374
- }
18375
- input.chooseRun(run);
18376
- input.updateFormData((current) => ({
18377
- ...current,
18378
- email: claim.prefill.email,
18379
- name: claim.prefill.name,
18380
- phone: claim.prefill.phone ?? "",
18381
- notes: claim.prefill.notes ?? ""
18382
- }));
18383
- if (input.step === "select-run") input.goToStep("enter-details");
18384
- }, [
18385
- input.chooseRun,
18386
- input.goToStep,
18387
- input.reportError,
18388
- input.scopedRuns,
18389
- input.step,
18390
- input.updateFormData,
18391
- input.waitlistClaim.claim
18392
- ]);
18393
- useEffect(() => {
18394
- if (input.waitlistClaim.requiresPortalLogin || !input.waitlistClaim.error) return;
18395
- input.reportError(input.waitlistClaim.error);
18396
- input.goToStep("error");
18397
- }, [
18398
- input.goToStep,
18399
- input.reportError,
18400
- input.waitlistClaim.error,
18401
- input.waitlistClaim.requiresPortalLogin
18402
- ]);
18403
- }
18404
- //#endregion
18405
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationWizard.ts
18406
- function useWholeSeriesRegistrationWizard(props, options = {}) {
18407
- return useWholeSeriesRegistrationWizardWithDeps(wholeSeriesRegistrationWizardDeps, props, options);
18408
- }
18409
- const wholeSeriesRegistrationWizardDeps = { readLocation: () => ({
18410
- search: window.location.search,
18411
- hash: window.location.hash
18412
- }) };
18413
- function useWholeSeriesRegistrationWizardWithDeps(deps, props, options = {}) {
18414
- const api = useBlockApi();
18415
- const [location] = useState(deps.readLocation);
18416
- const selection = useWholeSeriesRegistrationSelection(props, location);
18417
- const portal = useWholeSeriesRegistrationPortal(api);
18418
- const waitlistClaim = useWaitlistClaimForToken(new URLSearchParams(location.search).get("waitlist_claim")?.trim() || null);
18419
- const [bookingMode, setBookingMode] = useState(null);
18420
- const [altchaSolution, setAltchaSolution] = useState(null);
18421
- const eligibility = useWholeSeriesEligibility({
18422
- api,
18423
- selectedRun: selection.selectedRun,
18424
- hasPaidSelection: selection.selectedRunPricing?.hasPaidSelection ?? false,
18425
- portalAuthState: portal.portalAuthState,
18426
- waitlistClaimToken: waitlistClaim.token
18427
- });
18428
- const discountUi = useDiscountCodeUi({
18429
- api,
18430
- discountContext: useMemo(() => selection.selectedRun && selection.selectedRunPricing?.selectedRequiresPayment && eligibility.paymentChoice === "checkout" ? {
18431
- type: "whole_series",
18432
- eventSeriesId: selection.selectedRun.eventSeriesId
18433
- } : null, [
18434
- eligibility.paymentChoice,
18435
- selection.selectedRun,
18436
- selection.selectedRunPricing?.selectedRequiresPayment
18437
- ]),
18438
- subtotalCents: selection.selectedRunPricing?.selectedPriceAmount ?? void 0
18439
- });
18440
- const actions = useWholeSeriesRegistrationActions({
18441
- api,
18442
- selectedRun: selection.selectedRun,
18443
- pricing: selection.selectedRunPricing,
18444
- formData: portal.formData,
18445
- portalAuthState: portal.portalAuthState,
18446
- eligibility: eligibility.runEligibility,
18447
- eligibleMemberships: eligibility.eligibleMemberships,
18448
- paymentChoice: eligibility.paymentChoice,
18449
- selectedMembershipId: eligibility.selectedMembershipId,
18450
- claimToken: waitlistClaim.token,
18451
- hasClaim: waitlistClaim.claim !== null,
18452
- altchaSolution,
18453
- discountCode: discountUi.discountCode,
18454
- options
18455
- }, selection.goToStep);
18456
- useWholeSeriesRegistrationEffects({
18457
- api,
18458
- actions,
18459
- portal,
18460
- selection,
18461
- waitlistClaim,
18462
- anchorId: options.anchorId ?? "event-registration",
18463
- location
18464
- });
18465
- return buildWholeSeriesRegistrationWizardResult({
18466
- api,
18467
- selection,
18468
- portal,
18469
- eligibility,
18470
- actions,
18471
- discountUi,
18472
- waitlistClaim,
18473
- view: deriveWholeSeriesRegistrationViewState({
18474
- scopedRuns: selection.scopedRuns,
18475
- selectedRun: selection.selectedRun,
18476
- pricing: selection.selectedRunPricing,
18477
- portalAuthState: portal.portalAuthState,
18478
- eligibleMembershipCount: eligibility.eligibleMemberships.length,
18479
- bookingMode,
18480
- step: selection.step,
18481
- waitlistRequiresPortalLogin: waitlistClaim.requiresPortalLogin
18482
- }),
18483
- bookingMode,
18484
- setBookingMode,
18485
- altchaSolution,
18486
- setAltchaSolution,
18487
- anchorId: options.anchorId ?? "event-registration"
18488
- });
18489
- }
18490
- function useWholeSeriesRegistrationEffects(input) {
18491
- useWholeSeriesPaymentVerification(input.api, {
18492
- setStep: input.selection.goToStep,
18493
- setErrorMessage: input.actions.reportError,
18494
- setEnrollmentResult: input.actions.recordEnrollmentResult
18495
- }, input.anchorId, input.location);
18496
- useWholeSeriesWaitlistSelection({
18497
- waitlistClaim: input.waitlistClaim,
18498
- scopedRuns: input.selection.scopedRuns,
18499
- step: input.selection.step,
18500
- goToStep: input.selection.goToStep,
18501
- chooseRun: input.selection.chooseRun,
18502
- updateFormData: input.portal.updateFormData,
18503
- reportError: input.actions.reportError
18504
- });
18505
- }
18506
- function buildWholeSeriesRegistrationWizardResult(parts) {
18507
- const handleBookingModeChange = (mode) => {
18508
- parts.setBookingMode(mode);
18509
- parts.eligibility.choosePaymentChoice(mode === "membership" ? "membership" : "checkout");
18510
- };
18511
- return {
18512
- api: parts.api,
18513
- ...parts.selection,
18514
- ...parts.portal,
18515
- ...parts.eligibility,
18516
- ...parts.actions,
18517
- waitlistClaim: parts.waitlistClaim,
18518
- bookingMode: parts.bookingMode,
18519
- altchaSolution: parts.altchaSolution,
18520
- setAltchaSolution: parts.setAltchaSolution,
18521
- showSpamProtection: isSpamProtectionEnabled(),
18522
- discountUiOpen: parts.discountUi.discountUiOpen,
18523
- setDiscountUiOpen: parts.discountUi.setDiscountUiOpen,
18524
- discountCode: parts.discountUi.discountCode,
18525
- setDiscountCode: parts.discountUi.setDiscountCode,
18526
- discountsAvailable: parts.discountUi.discountsAvailable,
18527
- manualCodeEntryAllowed: parts.discountUi.manualCodeEntryAllowed,
18528
- discountsAvailableLoading: parts.discountUi.discountsAvailableLoading,
18529
- ...parts.view,
18530
- handleRunSelect: (run) => {
18531
- parts.selection.chooseRun(run);
18532
- parts.selection.goToStep("enter-details");
18533
- },
18534
- handleRetry: () => {
18535
- parts.selection.goToStep(parts.selection.scopedRuns.length === 1 ? "enter-details" : "select-run");
18536
- parts.actions.reportError("");
18537
- },
18538
- handleBookingModeChange,
18539
- handleLogout: parts.portal.portalAuthState === "authenticated" ? () => logoutPortal(parts.anchorId) : void 0,
18540
- selectedRunPricingPayload: buildWholeSeriesPricingOptionPayload(parts.selection.selectedRunPricing)
18541
- };
18542
- }
18543
- //#endregion
18544
- //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/whole-series-registration.headless.planning.ts
18545
- const STEP_IDS = {
18546
- "select-run": "select-run",
18547
- "enter-details": "enter-details",
18548
- "booking-mode": "select-booking-method",
18549
- "select-payment": "select-payment"
18550
- };
18551
- function toPublicStepId(step) {
18552
- switch (step) {
18553
- case "select-run":
18554
- case "enter-details":
18555
- case "booking-mode":
18556
- case "select-payment": return STEP_IDS[step];
18557
- case "submitting":
18558
- case "redirecting":
18559
- case "verifying-payment":
18560
- case "verifying-timeout":
18561
- case "payment-failed":
18562
- case "success":
18563
- case "waitlist":
18564
- case "error": return null;
18565
- }
18566
- }
18567
- function deriveWholeSeriesRegistrationSteps(input) {
18568
- const currentId = toPublicStepId(input.step);
18569
- const currentIndex = currentId ? input.wizardSteps.findIndex((step) => toPublicStepId(step) === currentId) : input.step === "success" || input.step === "waitlist" ? input.wizardSteps.length : -1;
18570
- return input.wizardSteps.flatMap((step, index) => {
18571
- const id = toPublicStepId(step);
18572
- if (!id) return [];
18573
- const state = index < currentIndex ? "complete" : index === currentIndex ? "active" : currentIndex >= 0 ? "available" : "blocked";
18574
- return [{
18575
- id,
18576
- state,
18577
- index,
18578
- canEnter: state === "active" || state === "complete"
18579
- }];
18580
- });
18581
- }
18582
- function resolveWholeSeriesRegistrationStatus(wizard) {
18583
- switch (wizard.step) {
18584
- case "submitting": return { tag: "submitting" };
18585
- case "redirecting": return { tag: "redirecting" };
18586
- case "verifying-payment": return { tag: "verifying-payment" };
18587
- case "verifying-timeout": return {
18588
- tag: "verifying-timeout",
18589
- message: wizard.errorMessage
18590
- };
18591
- case "payment-failed": return {
18592
- tag: "payment-failed",
18593
- message: wizard.errorMessage
18594
- };
18595
- case "success": return wizard.enrollmentResult ? {
18596
- tag: "success",
18597
- result: wizard.enrollmentResult
18598
- } : {
18599
- tag: "error",
18600
- message: "Registration completed without a result."
18601
- };
18602
- case "waitlist": return wizard.enrollmentResult ? {
18603
- tag: "waitlist",
18604
- result: wizard.enrollmentResult
18605
- } : {
18606
- tag: "error",
18607
- message: "Waitlist registration completed without a result."
18608
- };
18609
- case "error": return {
18610
- tag: "error",
18611
- message: wizard.errorMessage
18612
- };
18613
- case "select-run":
18614
- case "enter-details":
18615
- case "booking-mode":
18616
- case "select-payment": return { tag: "ready" };
18617
- }
18618
- }
18619
- function resolveWholeSeriesRegistrationView(wizard) {
18620
- switch (wizard.step) {
18621
- case "submitting":
18622
- case "redirecting":
18623
- case "verifying-payment": return {
18624
- kind: "verifying",
18625
- message: "Completing your sign-up."
18626
- };
18627
- case "verifying-timeout":
18628
- case "payment-failed":
18629
- case "error": return {
18630
- kind: "error",
18631
- message: wizard.errorMessage
18632
- };
18633
- case "success": return wizard.enrollmentResult ? {
18634
- kind: "success",
18635
- result: wizard.enrollmentResult
18636
- } : {
18637
- kind: "error",
18638
- message: "Registration completed without a result."
18639
- };
18640
- case "waitlist": return wizard.enrollmentResult ? {
18641
- kind: "waitlist",
18642
- result: wizard.enrollmentResult
18643
- } : {
18644
- kind: "error",
18645
- message: "Waitlist registration completed without a result."
18646
- };
18647
- case "select-run":
18648
- case "enter-details":
18649
- case "booking-mode":
18650
- case "select-payment":
18651
- if (wizard.scopedRunsCount === 0) return {
18652
- kind: "empty",
18653
- message: "There are no dates available to sign up for."
18654
- };
18655
- if (wizard.selectedRun && !wizard.selectedRun.enrollmentOpen) return {
18656
- kind: "unavailable",
18657
- message: "Sign-up is closed."
18658
- };
18659
- return { kind: "form" };
18660
- }
18661
- }
18662
- function resolveWholeSeriesPricingSelection(pricing) {
18663
- if (!pricing) return { tag: "not-required" };
18664
- if (pricing.display.kind === "unavailable") return { tag: "unavailable" };
18665
- if (pricing.slidingScale && pricing.selectedSlidingAmount !== null) {
18666
- if (pricing.selectedSlidingAmount < pricing.slidingScale.minAmount || pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) return {
18667
- tag: "invalid",
18668
- message: "Choose an amount within the available range."
18669
- };
18670
- }
18671
- if (pricing.requiresSelection && !pricing.selectedOption && pricing.selectedSlidingAmount === null) return { tag: "required" };
18672
- return pricing.requiresSelection || pricing.selectedOption || pricing.selectedSlidingAmount !== null ? { tag: "valid" } : { tag: "not-required" };
18673
- }
18674
- function resolveWholeSeriesPaymentSelection(input) {
18675
- if (!input.required) return { method: "none" };
18676
- if (input.paymentChoice === "membership") return {
18677
- method: "membership",
18678
- membershipId: input.selectedMembershipId
18679
- };
18680
- return { method: "card" };
18681
- }
18682
- //#endregion
18683
- //#region ../blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.ts
18684
- const wholeSeriesRegistrationControllerDeps = { useWholeSeriesRegistrationWizard };
18685
- function createWholeSeriesRegistrationBlockApiConfig(input) {
18686
- return {
18687
- baseUrl: input.apiBaseUrl,
18688
- auth: input.previewToken ? {
18689
- type: "bearer",
18690
- token: input.previewToken
18691
- } : { type: "none" },
18692
- siteId: input.siteId,
18693
- isPreview: input.stage === "preview",
18694
- ...input.portalToken ? { authOverrides: { portal: {
18695
- type: "bearer",
18696
- token: input.portalToken
18697
- } } } : {}
18698
- };
18699
- }
18700
- function HeadlessWholeSeriesRegistrationProvider$1({ config, children }) {
18701
- return React.createElement(BlockApiProvider, {
18702
- config,
18703
- children
18704
- });
18705
- }
18706
- function useHeadlessWholeSeriesRegistrationFlow(options) {
18707
- return useWholeSeriesRegistrationControllerWithDeps(options, wholeSeriesRegistrationControllerDeps);
18708
- }
18709
- function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
18710
- const wizard = deps.useWholeSeriesRegistrationWizard({
18711
- runs: (options.runs ?? []).map(toPublicWholeSeriesOffering),
18712
- subject: options.subject ?? null
18713
- }, { onCheckoutRedirect: () => {} });
18714
- const steps = useMemo(() => deriveWholeSeriesRegistrationSteps({
18715
- wizardSteps: wizard.wizardSteps,
18716
- step: wizard.step
18717
- }), [wizard.step, wizard.wizardSteps]);
18718
- const currentStep = steps.find((step) => step.state === "active") ?? null;
18719
- const pricingSelection = resolveWholeSeriesPricingSelection(wizard.selectedRunPricing);
18720
- const paymentSelection = resolveWholeSeriesPaymentSelection({
18721
- paymentChoice: wizard.paymentChoice,
18722
- selectedMembershipId: wizard.selectedMembershipId,
18723
- required: wizard.selectedRunPricing?.selectedRequiresPayment ?? false
18724
- });
18725
- const updateRegistrant = useCallback((values) => wizard.updateFormData(values), [wizard]);
18726
- const setSlidingAmountCents = useCallback((amount) => {
18727
- wizard.changeSlidingAmount(amount === null || !Number.isFinite(amount) || amount < 0 ? "" : String(amount / 100));
18728
- }, [wizard]);
18729
- const selectPayment = useCallback((selection) => {
18730
- switch (selection.method) {
18731
- case "none":
18732
- wizard.handleBookingModeChange(null);
18733
- wizard.chooseMembership(null);
18734
- return;
18735
- case "card":
18736
- wizard.handleBookingModeChange("card");
18737
- wizard.chooseMembership(null);
18738
- return;
18739
- case "membership":
18740
- wizard.handleBookingModeChange("membership");
18741
- wizard.chooseMembership(selection.membershipId);
18742
- return;
18743
- }
18744
- }, [wizard]);
18745
- const runCurrentAction = useCallback(async () => {
18746
- const blocked = resolveActionBlocker(wizard);
18747
- if (blocked) return blocked;
18748
- switch (wizard.step) {
18749
- case "select-run":
18750
- if (!wizard.selectedRun) return {
18751
- ok: false,
18752
- reason: "blocked",
18753
- message: "Choose an available set of dates to continue."
18754
- };
18755
- wizard.goToStep("enter-details");
18756
- return {
18757
- ok: true,
18758
- outcome: { kind: "state-updated" }
18759
- };
18760
- case "enter-details": return toHeadlessActionResult(await wizard.handleSubmit());
18761
- case "booking-mode":
18762
- case "select-payment": return toHeadlessActionResult(await wizard.handlePaymentContinue());
18763
- case "submitting":
18764
- case "redirecting":
18765
- case "verifying-payment":
18766
- case "verifying-timeout":
18767
- case "payment-failed":
18768
- case "success":
18769
- case "waitlist":
18770
- case "error": return {
18771
- ok: false,
18772
- reason: "blocked",
18773
- message: "This registration step cannot continue."
18774
- };
18775
- }
18776
- }, [pricingSelection, wizard]);
18777
- const back = useCallback(() => {
18778
- switch (wizard.step) {
18779
- case "enter-details":
18780
- if (!wizard.hasPreSelectedRun) wizard.goToStep("select-run");
18781
- return;
18782
- case "booking-mode":
18783
- wizard.goToStep("enter-details");
18784
- return;
18785
- case "select-payment":
18786
- wizard.goToStep(wizard.canUseMembership ? "booking-mode" : "enter-details");
18787
- return;
18788
- case "select-run":
18789
- case "submitting":
18790
- case "redirecting":
18791
- case "verifying-payment":
18792
- case "verifying-timeout":
18793
- case "payment-failed":
18794
- case "success":
18795
- case "waitlist":
18796
- case "error": return;
18797
- }
18798
- }, [wizard]);
18799
- const payment = {
18800
- required: wizard.selectedRunPricing?.selectedRequiresPayment ?? false,
18801
- selection: paymentSelection,
18802
- canUseMembership: wizard.canUseMembership,
18803
- eligibleMemberships: wizard.eligibleMemberships.map((membership) => ({
18804
- id: membership.customerMembershipId,
18805
- name: membership.membershipName
18806
- })),
18807
- eligibility: wizard.eligibilityLoading ? { tag: "loading" } : wizard.eligibilityError ? {
18808
- tag: "error",
18809
- message: wizard.eligibilityError
18810
- } : wizard.runEligibility || wizard.portalAuthState !== "checking" ? { tag: "loaded" } : { tag: "idle" }
18811
- };
18812
- const spamProtection = wizard.showSpamProtection ? {
18813
- enabled: true,
18814
- provider: "altcha",
18815
- challenge: {
18816
- url: getChallengeUrl(),
18817
- auto: "onfocus"
18818
- },
18819
- solution: wizard.altchaSolution
18820
- } : { enabled: false };
18821
- const selectedRun = wizard.selectedRun;
18822
- const isFull = wizard.runEligibility?.isFull ?? (selectedRun?.availableSpots !== null && selectedRun?.availableSpots !== void 0 ? selectedRun.availableSpots <= 0 : false);
18823
- return {
18824
- status: resolveWholeSeriesRegistrationStatus(wizard),
18825
- view: resolveWholeSeriesRegistrationView({
18826
- step: wizard.step,
18827
- scopedRunsCount: wizard.scopedRuns.length,
18828
- selectedRun,
18829
- enrollmentResult: wizard.enrollmentResult,
18830
- errorMessage: wizard.errorMessage
18831
- }),
18832
- steps,
18833
- currentStep,
18834
- runs: {
18835
- items: (options.runs ?? []).map((run) => toWholeSeriesRegistrationRun(toPublicWholeSeriesOffering(run))),
18836
- scoped: wizard.scopedRuns.map(toWholeSeriesRegistrationRun),
18837
- selected: selectedRun ? toWholeSeriesRegistrationRun(selectedRun) : null,
18838
- hasPreSelectedRun: wizard.hasPreSelectedRun,
18839
- subject: options.subject ?? null
18840
- },
18841
- registrant: {
18842
- values: wizard.formData,
18843
- errors: wizard.errors
18844
- },
18845
- pricing: {
18846
- ...toWholeSeriesRegistrationPricing(wizard.selectedRunPricing),
18847
- selectedOptionId: wizard.selectedPricingOptionId,
18848
- selection: pricingSelection
18849
- },
18850
- payment,
18851
- discount: {
18852
- code: wizard.discountCode,
18853
- isOpen: wizard.discountUiOpen,
18854
- available: wizard.discountsAvailable,
18855
- manualCodeEntryAllowed: wizard.manualCodeEntryAllowed,
18856
- loading: wizard.discountsAvailableLoading
18857
- },
18858
- availability: {
18859
- enrollmentOpen: selectedRun?.enrollmentOpen ?? false,
18860
- availableSpots: selectedRun?.availableSpots ?? null,
18861
- isFull,
18862
- canJoinWaitlist: wizard.runEligibility?.canJoinWaitlist ?? false,
18863
- message: wizard.runEligibility?.reason ?? null
18864
- },
18865
- portalAuth: {
18866
- state: wizard.portalAuthState,
18867
- isAuthenticated: wizard.portalAuthState === "authenticated"
18868
- },
18869
- waitlistClaim: resolveWaitlistClaim(wizard),
18870
- spamProtection,
18871
- terminal: {
18872
- result: wizard.enrollmentResult,
18873
- errorMessage: wizard.errorMessage
18874
- },
18875
- actions: {
18876
- selectRun: (runId) => {
18877
- const run = wizard.scopedRuns.find((candidate) => candidate.eventSeriesId === runId) ?? null;
18878
- if (run) wizard.handleRunSelect(run);
18879
- },
18880
- updateRegistrant,
18881
- selectPricingOption: wizard.choosePricingOption,
18882
- setSlidingAmountCents,
18883
- selectPayment,
18884
- setDiscountCode: wizard.setDiscountCode,
18885
- setDiscountOpen: wizard.setDiscountUiOpen,
18886
- setAltchaSolution: wizard.setAltchaSolution,
18887
- continue: runCurrentAction,
18888
- back,
18889
- submit: runCurrentAction,
18890
- retry: wizard.handleRetry,
18891
- logout: () => wizard.handleLogout?.()
18892
- }
18893
- };
18894
- }
18895
- function toHeadlessActionResult(result) {
18896
- switch (result.kind) {
18897
- case "state-updated": return {
18898
- ok: true,
18899
- outcome: result
18900
- };
18901
- case "checkout-redirect": return {
18902
- ok: true,
18903
- outcome: result
18904
- };
18905
- case "validation-failed": return {
18906
- ok: false,
18907
- reason: "validation-failed",
18908
- message: "Check the highlighted fields and try again."
18909
- };
18910
- case "blocked": return {
18911
- ok: false,
18912
- reason: "blocked",
18913
- message: result.message
18914
- };
18915
- case "failed": return {
18916
- ok: false,
18917
- reason: "failed",
18918
- message: result.message
18919
- };
18920
- }
18921
- }
18922
- function toPublicWholeSeriesOffering(run) {
18923
- const pricing = toWholeSeriesPricing(run.pricing);
18924
- return {
18925
- eventSeriesId: run.registrationTarget.eventSeriesId,
18926
- eventOfferingId: run.eventOfferingId,
18927
- title: run.title,
18928
- slug: run.slug,
18929
- description: run.description,
18930
- teamMembers: run.teamMembers ? [...run.teamMembers] : void 0,
18931
- consent: run.consent,
18932
- enrollmentOpen: run.registrationOpen,
18933
- pricing,
18934
- currency: run.pricing.currency,
18935
- paymentTerms: run.pricing.paymentTerms,
18936
- enrollmentCapacity: run.capacity,
18937
- acceptsMemberships: run.acceptsMemberships,
18938
- status: run.lifecycleStatus,
18939
- sessionsCount: run.includedDates.length,
18940
- enrolledCount: run.registeredCount,
18941
- availableSpots: run.availableSpots,
18942
- sessions: run.includedDates.map((date) => ({
18943
- ...date,
18944
- overrides: date.overrides ? { ...date.overrides } : date.overrides
18945
- })),
18946
- venue: run.venue
18947
- };
18948
- }
18949
- function toWholeSeriesPricing(pricing) {
18950
- const common = {
18951
- bookingRequirement: pricing.bookingRequirement,
18952
- pricingStrategy: pricing.pricingStrategy,
18953
- currency: pricing.currency,
18954
- paymentTerms: pricing.paymentTerms
18955
- };
18956
- switch (pricing.pricingStrategy) {
18957
- case "free": return {
18958
- ...common,
18959
- singlePriceAmount: null,
18960
- options: []
18961
- };
18962
- case "single": return {
18963
- ...common,
18964
- singlePriceAmount: pricing.amountCents,
18965
- options: []
18966
- };
18967
- case "tiered": return {
18968
- ...common,
18969
- singlePriceAmount: null,
18970
- options: pricing.options
18971
- };
18972
- case "sliding_scale": return {
18973
- ...common,
18974
- singlePriceAmount: null,
18975
- slidingMinAmount: pricing.minAmountCents,
18976
- slidingMaxAmount: pricing.maxAmountCents,
18977
- slidingSuggestedAmount: pricing.suggestedAmountCents,
18978
- options: []
18979
- };
18980
- }
18981
- }
18982
- function toWholeSeriesRegistrationRun(run) {
18983
- return {
18984
- id: run.eventSeriesId,
18985
- title: run.title,
18986
- slug: run.slug,
18987
- description: run.description,
18988
- registrationOpen: run.enrollmentOpen,
18989
- capacity: run.enrollmentCapacity,
18990
- registeredCount: run.enrolledCount,
18991
- availableSpots: run.availableSpots,
18992
- includedDates: run.sessions.map((session) => ({
18993
- id: session.id,
18994
- startsAt: session.startsAt,
18995
- endsAt: session.endsAt,
18996
- timeZone: session.timeZone
18997
- })),
18998
- venue: run.venue
18999
- };
19000
- }
19001
- function toWholeSeriesRegistrationPricing(pricing) {
19002
- if (!pricing) return {
19003
- currency: null,
19004
- display: null,
19005
- options: [],
19006
- slidingScale: null,
19007
- selectedAmountCents: null,
19008
- selectedPriceCents: null,
19009
- requiresPayment: false
19010
- };
19011
- return {
19012
- currency: pricing.currency,
19013
- display: toWholeSeriesPriceDisplay(pricing.display),
19014
- options: pricing.selectableOptions.map((option) => ({
19015
- id: option.id,
19016
- name: option.name,
19017
- description: option.description,
19018
- amountCents: option.priceAmount
19019
- })),
19020
- slidingScale: pricing.slidingScale ? {
19021
- minAmountCents: pricing.slidingScale.minAmount,
19022
- maxAmountCents: pricing.slidingScale.maxAmount,
19023
- suggestedAmountCents: pricing.slidingScale.suggestedAmount
19024
- } : null,
19025
- selectedAmountCents: pricing.selectedSlidingAmount,
19026
- selectedPriceCents: pricing.selectedPriceAmount,
19027
- requiresPayment: pricing.selectedRequiresPayment
19028
- };
19029
- }
19030
- function toWholeSeriesPriceDisplay(display) {
19031
- switch (display.kind) {
19032
- case "free": return display;
19033
- case "exact": return {
19034
- kind: "exact",
19035
- amountCents: display.amount,
19036
- currency: display.currency
19037
- };
19038
- case "from": return {
19039
- kind: "from",
19040
- amountCents: display.amount,
19041
- currency: display.currency
19042
- };
19043
- case "range": return {
19044
- kind: "range",
19045
- minAmountCents: display.minAmount,
19046
- maxAmountCents: display.maxAmount,
19047
- currency: display.currency
19048
- };
19049
- case "unavailable": return display;
19050
- }
19051
- }
19052
- function resolveWaitlistClaim(wizard) {
19053
- const waitlistClaim = wizard.waitlistClaim;
19054
- if (waitlistClaim.isLoading) return { tag: "loading" };
19055
- if (waitlistClaim.requiresPortalLogin) return {
19056
- tag: "login-required",
19057
- message: waitlistClaim.loginMessage ?? "Log in to continue with your waitlist place."
19058
- };
19059
- if (waitlistClaim.error) return {
19060
- tag: "error",
19061
- message: waitlistClaim.error
19062
- };
19063
- if (waitlistClaim.claim) return {
19064
- tag: "ready",
19065
- expiresAt: waitlistClaim.claim.expiresAt,
19066
- prefill: {
19067
- email: waitlistClaim.claim.prefill.email,
19068
- name: waitlistClaim.claim.prefill.name,
19069
- phone: waitlistClaim.claim.prefill.phone,
19070
- notes: waitlistClaim.claim.prefill.notes
19071
- }
19072
- };
19073
- return { tag: "none" };
19074
- }
19075
- function resolveActionBlocker(wizard) {
19076
- if (!wizard.selectedRun) return null;
19077
- if (!wizard.selectedRun.enrollmentOpen) return {
19078
- ok: false,
19079
- reason: "blocked",
19080
- message: "Sign-up is closed."
19081
- };
19082
- if (wizard.eligibilityLoading || wizard.portalAuthState === "checking") return {
19083
- ok: false,
19084
- reason: "blocked",
19085
- message: "Availability is still being checked."
19086
- };
19087
- if (wizard.runEligibility?.isFull && !wizard.runEligibility.canJoinWaitlist) return {
19088
- ok: false,
19089
- reason: "blocked",
19090
- message: wizard.runEligibility.reason ?? "There are no places available."
19091
- };
19092
- return null;
19093
- }
19094
- //#endregion
19095
- //#region ../blocks/src/system/runtime/hooks/useBookingFormConfig.state.ts
19096
- const EMPTY_SNAPSHOT = Object.freeze({
19097
- formConfig: null,
19098
- services: []
19099
- });
19100
- function createInitialBookingFormConfigState() {
19101
- return {
19102
- tag: "loading",
19103
- previous: EMPTY_SNAPSHOT
19104
- };
19105
- }
19106
- function bookingFormConfigReducer(state, action) {
19107
- switch (action.type) {
19108
- case "load-started": return {
19109
- tag: "loading",
19110
- previous: toBookingFormConfigSnapshot(state)
18116
+ function bookingFormConfigReducer(state, action) {
18117
+ switch (action.type) {
18118
+ case "load-started": return {
18119
+ tag: "loading",
18120
+ previous: toBookingFormConfigSnapshot(state)
19111
18121
  };
19112
18122
  case "form-loaded": {
19113
18123
  const previous = toBookingFormConfigSnapshot(state);
@@ -19300,11 +18310,8 @@ const HeadlessBookingProvider = (props) => {
19300
18310
  const HeadlessEventRegistrationProvider = (props) => {
19301
18311
  return React$1.createElement(HeadlessEventRegistrationProvider$1, props);
19302
18312
  };
19303
- const HeadlessWholeSeriesRegistrationProvider = (props) => {
19304
- return React$1.createElement(HeadlessWholeSeriesRegistrationProvider$1, props);
19305
- };
19306
18313
  const HeadlessBookingPaymentSelectionStep = (props) => {
19307
18314
  return React$1.createElement(HeadlessBookingPaymentSelectionStep$1, props);
19308
18315
  };
19309
18316
  //#endregion
19310
- export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, AltchaWidget as HeadlessWholeSeriesRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, HeadlessWholeSeriesRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, createWholeSeriesRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow, useHeadlessWholeSeriesRegistrationFlow };
18317
+ export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow };