@riverbankcms/sdk 0.121.0 → 0.124.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/README.md +14 -9
  2. package/dist/{PreviewEditorSidebar-lZ600tJx.mjs → PreviewEditorSidebar-DBmAJJkQ.mjs} +24 -41
  3. package/dist/{PreviewEditorUI-CTBWzLSb.mjs → PreviewEditorUI-CfGaz9cY.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BHT8CJvZ.mjs → PreviewQueryProvider-BH-3-jSj.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-DhPU58s7.mjs → SdkPreviewModeRuntime-BW9Z8j8T.mjs} +1020 -1234
  6. package/dist/{SiteChromeCustomizeContext-BkNvpzNZ.mjs → SiteChromeCustomizeContext-2z8moxYf.mjs} +1902 -1961
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +1236 -4152
  8. package/dist/_dts/api/src/appointmentEndpointDefinitions.d.ts +435 -0
  9. package/dist/_dts/api/src/bookingClosures.d.ts +3 -3
  10. package/dist/_dts/api/src/bookingConfig.d.ts +100 -75
  11. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +26 -35
  12. package/dist/_dts/api/src/bookingRecords.d.ts +4 -15
  13. package/dist/_dts/api/src/bookingVerticalCatalog.d.ts +746 -0
  14. package/dist/_dts/api/src/bookingVerticalPreset.d.ts +38 -0
  15. package/dist/_dts/api/src/bookingVerticals.d.ts +11 -652
  16. package/dist/_dts/api/src/bookings.d.ts +11 -9
  17. package/dist/_dts/api/src/cache-tags.d.ts +2 -2
  18. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +10 -10
  19. package/dist/_dts/api/src/common/envelope.d.ts +2 -0
  20. package/dist/_dts/api/src/contentRuntime.d.ts +0 -17
  21. package/dist/_dts/api/src/courseEndpointDefinitions.d.ts +99 -0
  22. package/dist/_dts/api/src/courses.d.ts +22 -33
  23. package/dist/_dts/api/src/defineEndpointDefinitions.d.ts +14 -0
  24. package/dist/_dts/api/src/demoMutationPolicies.d.ts +4 -0
  25. package/dist/_dts/api/src/endpoints.d.ts +3740 -3733
  26. package/dist/_dts/api/src/event-destination-policy.d.ts +1 -1
  27. package/dist/_dts/api/src/event-presentation.d.ts +4 -9
  28. package/dist/_dts/api/src/index.d.ts +10 -12
  29. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +376 -0
  30. package/dist/_dts/api/src/participantMessaging.d.ts +2 -2
  31. package/dist/_dts/api/src/public/endpoints.d.ts +1 -1
  32. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +272 -0
  33. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +274 -0
  34. package/dist/_dts/api/src/publicExperience/newsletterEndpoints.d.ts +31 -0
  35. package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +152 -0
  36. package/dist/_dts/api/src/publicExperience/siteEndpoints.d.ts +95 -0
  37. package/dist/_dts/api/src/publicExperience/wholeSeriesEndpoints.d.ts +154 -0
  38. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +10 -962
  39. package/dist/_dts/api/src/publicWholeSeriesEndpointDefinitions.d.ts +52 -0
  40. package/dist/_dts/api/src/sdkContracts.d.ts +0 -51
  41. package/dist/_dts/api/src/sdkEntryReadEndpoints.d.ts +23 -0
  42. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -38
  43. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +6 -7
  44. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -15
  45. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -1
  46. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +0 -16
  47. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +6 -222
  48. package/dist/_dts/blocks/src/portal/types.d.ts +3 -3
  49. package/dist/_dts/blocks/src/subroutes/fold.d.ts +1 -14
  50. package/dist/_dts/blocks/src/subroutes/index.d.ts +1 -1
  51. package/dist/_dts/blocks/src/subroutes/kinds.d.ts +3 -3
  52. package/dist/_dts/blocks/src/system/blocks/course-details.d.ts +0 -11
  53. package/dist/_dts/blocks/src/system/blocks/course-registration.d.ts +3 -4
  54. package/dist/_dts/blocks/src/system/blocks/courses/shared/pricing.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +401 -12
  56. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +9 -10
  57. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +14 -13
  58. package/dist/_dts/blocks/src/system/blocks/events/event-listing.d.ts +1 -2
  59. package/dist/_dts/blocks/src/system/blocks/events/shared/filtering.d.ts +1 -4
  60. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +19 -18
  61. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +9 -11
  62. package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +2 -2
  63. package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
  64. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +10 -10
  65. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +10 -10
  66. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  67. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +162 -0
  68. package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +59 -0
  69. package/dist/_dts/blocks/src/system/runtime/api/types/courses.d.ts +134 -0
  70. package/dist/_dts/blocks/src/system/runtime/api/types/discounts.d.ts +85 -0
  71. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +241 -0
  72. package/dist/_dts/blocks/src/system/runtime/api/types/forms.d.ts +53 -0
  73. package/dist/_dts/blocks/src/system/runtime/api/types/newsletter.d.ts +32 -0
  74. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +220 -0
  75. package/dist/_dts/blocks/src/system/runtime/api/types/shop.d.ts +176 -0
  76. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +12 -1121
  77. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +19 -583
  78. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +9 -276
  79. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.d.ts +1 -12
  80. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +0 -1
  81. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.d.ts +0 -1
  82. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +2 -3
  83. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/logic.d.ts +1 -18
  84. package/dist/_dts/blocks/src/system/runtime/nodes/course-details/runs.d.ts +0 -2
  85. package/dist/_dts/blocks/src/system/runtime/nodes/course-details.server.d.ts +1 -5
  86. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/courseRegistrationViewState.d.ts +21 -0
  87. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/index.d.ts +1 -1
  88. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/pricing.d.ts +14 -0
  89. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/types.d.ts +0 -25
  90. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseEligibility.d.ts +24 -0
  91. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCoursePaymentVerification.d.ts +9 -0
  92. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationActions.d.ts +35 -0
  93. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationPortal.d.ts +7 -0
  94. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationSelection.d.ts +31 -0
  95. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +80 -55
  96. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseWaitlistSelection.d.ts +14 -0
  97. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/whole-series-registration.headless.contract.d.ts +4 -5
  98. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.interactive.d.ts +0 -38
  99. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.server.d.ts +1 -1
  100. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.client.d.ts +1 -2
  101. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.server.d.ts +0 -1
  102. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +12 -0
  103. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +0 -4
  104. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventScope.d.ts +0 -9
  105. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +0 -5
  106. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +0 -11
  107. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +13 -0
  108. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +0 -21
  109. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +1 -1
  110. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +24 -433
  111. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +1 -2
  112. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +52 -266
  113. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +5 -15
  114. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventFilters.d.ts +0 -8
  115. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +1573 -0
  116. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listOptions.d.ts +1 -3
  117. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +2 -3
  118. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +2 -2
  119. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +0 -5
  120. package/dist/_dts/content-model/src/content-types/builtins.d.ts +0 -5
  121. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -3
  122. package/dist/_dts/core/src/editor-state.d.ts +1 -13
  123. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +1587 -115
  124. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +6 -6
  125. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +6 -1
  126. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +27 -4
  127. package/dist/_dts/sdk/src/cli/commands/audit.d.ts +1 -2
  128. package/dist/_dts/sdk/src/cli/commands/pull-dated-offering-scope.d.ts +1 -1
  129. package/dist/_dts/sdk/src/cli/commands/pull-dry-run.d.ts +4 -6
  130. package/dist/_dts/sdk/src/cli/commands/push/consts.d.ts +1 -1
  131. package/dist/_dts/sdk/src/cli/commands/push/options.d.ts +1 -1
  132. package/dist/_dts/sdk/src/cli/commands/push/pushAllExtras.d.ts +0 -1
  133. package/dist/_dts/sdk/src/cli/commands/push/verification.d.ts +1 -1
  134. package/dist/_dts/sdk/src/cli/content/collectionWriters.d.ts +23 -0
  135. package/dist/_dts/sdk/src/cli/content/metadataAfterPush.d.ts +25 -0
  136. package/dist/_dts/sdk/src/cli/content/reader.d.ts +0 -52
  137. package/dist/_dts/sdk/src/cli/content/writer.d.ts +3 -81
  138. package/dist/_dts/sdk/src/cli/site-commands/datedOfferingCommands.d.ts +6 -9
  139. package/dist/_dts/sdk/src/client/contentReadOperations.d.ts +40 -0
  140. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -3
  141. package/dist/_dts/sdk/src/client/management/types.d.ts +3 -91
  142. package/dist/_dts/sdk/src/client/runtimeCacheKeys.d.ts +72 -0
  143. package/dist/_dts/sdk/src/client/runtimeCachePolicy.d.ts +10 -75
  144. package/dist/_dts/sdk/src/client/types.d.ts +7 -33
  145. package/dist/_dts/sdk/src/components.d.ts +1 -1
  146. package/dist/_dts/sdk/src/config/types.d.ts +1 -1
  147. package/dist/_dts/sdk/src/config/validation.d.ts +3 -6
  148. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  149. package/dist/_dts/sdk/src/contracts/page.d.ts +0 -8
  150. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +1 -34
  151. package/dist/_dts/sdk/src/data/prefetchBlockData.d.ts +4 -3
  152. package/dist/_dts/sdk/src/next/catch-all-utils.d.ts +0 -11
  153. package/dist/_dts/sdk/src/next/catch-all.d.ts +1 -76
  154. package/dist/_dts/sdk/src/next/types.d.ts +0 -19
  155. package/dist/_dts/sdk/src/public-api/contracts.d.ts +7 -207
  156. package/dist/_dts/sdk/src/public-api/runtime.d.ts +1 -1
  157. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -1
  158. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +2 -2
  159. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +0 -7
  160. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +81 -0
  161. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -1
  162. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +1 -51
  163. package/dist/_dts/sdk/src/rendering/overrides.d.ts +2 -1
  164. package/dist/_dts/sdk/src/routing/entrySubroutes.d.ts +6 -6
  165. package/dist/_dts/sdk/src/routing/index.d.ts +0 -2
  166. package/dist/_dts/sdk/src/routing/resolveOccurrence.d.ts +3 -3
  167. package/dist/_dts/sdk/src/routing/resolvePageContent.d.ts +10 -39
  168. package/dist/_dts/sdk/src/types/block-kinds.d.ts +1 -1
  169. package/dist/_dts/sdk/src/version.d.ts +1 -1
  170. package/dist/_dts/site-commands/src/adapter.d.ts +1 -1
  171. package/dist/_dts/site-commands/src/appointmentCommandSchemas.d.ts +100 -0
  172. package/dist/_dts/site-commands/src/capabilityGaps.d.ts +2 -2
  173. package/dist/_dts/site-commands/src/commandContract.d.ts +1242 -0
  174. package/dist/_dts/site-commands/src/commandDomain.d.ts +20 -0
  175. package/dist/_dts/site-commands/src/commandIdentifiers.d.ts +7 -0
  176. package/dist/_dts/site-commands/src/commandValidation.d.ts +10 -0
  177. package/dist/_dts/site-commands/src/commands.d.ts +729 -2659
  178. package/dist/_dts/site-commands/src/domain.d.ts +1 -1
  179. package/dist/_dts/site-commands/src/eventCommandContent.d.ts +11 -0
  180. package/dist/_dts/site-commands/src/exposure.d.ts +1 -1
  181. package/dist/_dts/site-commands/src/index.d.ts +6 -0
  182. package/dist/_dts/site-commands/src/metadata.d.ts +1 -27
  183. package/dist/_dts/site-commands/src/planner.d.ts +1 -1
  184. package/dist/_dts/site-commands/src/refContributions.d.ts +1 -1
  185. package/dist/_dts/site-commands/src/refs.d.ts +1 -4
  186. package/dist/_dts/site-commands/src/siteStyleCommandSchema.d.ts +378 -0
  187. package/dist/_dts/site-commands/src/siteStyleSelectionSchemaBuilder.d.ts +46 -0
  188. package/dist/_dts/site-commands/src/staticExecutionGaps.d.ts +2 -2
  189. package/dist/_dts/site-commands/src/venueCommandMapping.d.ts +21 -0
  190. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +58 -0
  191. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +1 -0
  192. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  193. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +47 -24
  194. package/dist/cli/index.mjs +7392 -10989
  195. package/dist/cli/init-docs/content/cli-reference.md +5 -21
  196. package/dist/cli/init-docs/content/content-management.md +4 -5
  197. package/dist/client/{DiscountCodeDisclosure-DIWj-P9v.mjs → DiscountCodeDisclosure-DxvjKvck.mjs} +2 -2
  198. package/dist/client/{EventCombined.client-De8YWBSr.mjs → EventCombined.client-BydMGc4c.mjs} +5 -16
  199. package/dist/client/{EventListing.client-seHTjimY.mjs → EventListing.client-vpzhhysN.mjs} +3 -10
  200. package/dist/client/{LeafletStaticMap-BmQxFcJW.mjs → LeafletStaticMap-CB07rpf8.mjs} +1 -1
  201. package/dist/client/{MagicLinkForm-OoJAIUIj.mjs → MagicLinkForm-BzyRJ8VF.mjs} +2 -2
  202. package/dist/client/{StepIndicator-CiZ8kdPk.mjs → StepIndicator-CTcGf8Be.mjs} +2 -2
  203. package/dist/client/{accordion-6lnN__XJ.mjs → accordion-B-DUDLRD.mjs} +1 -1
  204. package/dist/client/{bookingForm-5uyqhONU.mjs → bookingForm-DSbClLcZ.mjs} +6 -6
  205. package/dist/client/bookings.mjs +753 -818
  206. package/dist/client/{carousel-Dtnifil_.mjs → carousel-B6Ccdx8M.mjs} +1 -1
  207. package/dist/client/{cart-5Tc5S7NV.mjs → cart-BZh8G8wM.mjs} +3 -3
  208. package/dist/client/{checkout-CYKKN5Hr.mjs → checkout-o6zaC-kM.mjs} +3 -3
  209. package/dist/client/client.mjs +7398 -7687
  210. package/dist/client/{context-BGZNlGXB.mjs → context-CJz1Vlsz.mjs} +40 -43
  211. package/dist/client/{courseRegistration-CxCBybB4.mjs → courseRegistration-Cf11pNDs.mjs} +606 -621
  212. package/dist/client/{eventCalendar-Xj2jZS9X.mjs → eventCalendar-BeXrdsSE.mjs} +5 -13
  213. package/dist/client/{eventCombined-CgcMoOgM.mjs → eventCombined-DA76PZgG.mjs} +3 -3
  214. package/dist/client/{eventDetails-CEAH8Edc.mjs → eventDetails-BLxg0rok.mjs} +140 -116
  215. package/dist/client/{eventListing-qyPVQ0wP.mjs → eventListing-tO9LheBX.mjs} +3 -3
  216. package/dist/client/{eventRegistration-DDu79CtL.mjs → eventRegistration-Cnene9D9.mjs} +165 -68
  217. package/dist/client/{form-Bc7JKI7I.mjs → form-DZf72CHB.mjs} +2 -2
  218. package/dist/client/{headerSection-vTku_LEl.mjs → headerSection-Hioja5Cr.mjs} +2 -2
  219. package/dist/client/hooks.mjs +3452 -2365
  220. package/dist/client/{locationMap-Bg7X4Jna.mjs → locationMap-DwhUXEix.mjs} +2 -2
  221. package/dist/client/{newsletterForm-lpylVdp5.mjs → newsletterForm-C350bEQf.mjs} +2 -2
  222. package/dist/client/{pricing-DE8fjJiT.mjs → pricing-BYWN_ATa.mjs} +3 -19
  223. package/dist/client/{productDetail-D7Bo2RMH.mjs → productDetail-CCqCyXgU.mjs} +3 -3
  224. package/dist/client/{productList-VjnZqiqN.mjs → productList-BAiNJrOU.mjs} +3 -3
  225. package/dist/client/{propsDecoder-DreFXjNP.mjs → propsDecoder-DeunRj6m.mjs} +210 -378
  226. package/dist/client/rendering/client.mjs +2541 -2813
  227. package/dist/client/rendering/islands.mjs +18 -18
  228. package/dist/client/rendering.mjs +5622 -4734
  229. package/dist/client/{shop-IRsHHbf7.mjs → shop-DUmCdBtw.mjs} +6 -6
  230. package/dist/client/{shop-commerce-gnI8PieZ.mjs → shop-commerce-CY27mEUr.mjs} +5 -5
  231. package/dist/client/{shop-commerce-store-BTbrhObn.mjs → shop-commerce-store-ChXPbWfa.mjs} +1 -1
  232. package/dist/client/{shopShared-D6KS2_qk.mjs → shopShared-q0kin1cv.mjs} +3 -3
  233. package/dist/client/{useDiscountCodeUi-DCccGCxV.mjs → useDiscountCodeUi-I-92-x2V.mjs} +2 -2
  234. package/dist/client/{useEventFilters-eGs3rPZQ.mjs → useEventFilters-DlcVluZh.mjs} +59 -124
  235. package/dist/client/{usePolling-CvSU2sur.mjs → usePolling-Bz7GFV_a.mjs} +2 -2
  236. package/dist/preview-next/before-render.mjs +1115 -1043
  237. package/dist/preview-next/client/runtime.mjs +4 -4
  238. package/dist/preview-next/middleware.mjs +1116 -1044
  239. package/dist/{previewAuthStore-31xH13Jc.mjs → previewAuthStore-CJX21dGi.mjs} +1119 -1044
  240. package/dist/{sdk-runtime-BE_vcGua.mjs → sdk-runtime-OnPM8Z69.mjs} +2 -2
  241. package/dist/{separator-CiffYtk3.mjs → separator-CPtfzHqA.mjs} +1 -1
  242. package/dist/server/components.mjs +11120 -12601
  243. package/dist/server/config-validation.mjs +3454 -2356
  244. package/dist/server/config.mjs +3454 -2356
  245. package/dist/server/data.mjs +3452 -2367
  246. package/dist/server/index.mjs +1499 -1488
  247. package/dist/server/next.mjs +18291 -21201
  248. package/dist/server/page-converter.mjs +1898 -2040
  249. package/dist/server/prebuild.mjs +1 -1
  250. package/dist/server/rendering/server.mjs +19666 -21153
  251. package/dist/server/rendering.mjs +17117 -18651
  252. package/dist/server/routing.mjs +3614 -2509
  253. package/dist/server/server.mjs +3298 -3478
  254. package/package.json +1 -1
  255. package/dist/_dts/api/src/previewContentContract.d.ts +0 -4
  256. package/dist/_dts/sdk/src/cli/commands/course.d.ts +0 -6
  257. package/dist/_dts/sdk/src/cli/commands/push/scopes/courses.d.ts +0 -4
  258. package/dist/_dts/sdk/src/client/management/courses.d.ts +0 -10
  259. package/dist/_dts/sdk/src/routing/resolveEntrySubroute.d.ts +0 -36
@@ -1,21 +1,21 @@
1
1
  "use client";
2
- import { It as toBookingTimeZone, Kt as assertNever, Lt as toScheduledBookingDateTime, Ot as formatBookingDate, Rt as parseEventPageSurfaceSubject, Z as themeButtonClassName, jt as formatBookingTime, t as defineIslandPropsDecoder } from "./propsDecoder-DreFXjNP.mjs";
3
- import { n as formatCoursePriceDisplay, r as resolveCoursePricingState, t as formatCoursePriceAmount } from "./pricing-DE8fjJiT.mjs";
4
- import { n as useBlockApi, t as BlockApiProvider } from "./context-BGZNlGXB.mjs";
2
+ import { At as formatBookingTime, Dt as formatBookingDate, Ft as toBookingTimeZone, Gt as assertNever, It as toScheduledBookingDateTime, Lt as parseEventPageSurfaceSubject, X as themeButtonClassName, t as defineIslandPropsDecoder } from "./propsDecoder-DeunRj6m.mjs";
3
+ import { n as formatCoursePriceDisplay, r as resolveCoursePricingState, t as formatCoursePriceAmount } from "./pricing-BYWN_ATa.mjs";
4
+ import { n as useBlockApi, t as BlockApiProvider } from "./context-CJz1Vlsz.mjs";
5
5
  import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
6
- import { i as CheckIcon, n as TerminalPanel, r as StateIcon, t as useDiscountCodeUi } from "./useDiscountCodeUi-DCccGCxV.mjs";
7
- import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-DIWj-P9v.mjs";
8
- import { n as SpinnerNode, r as formatPrice, t as StepIndicator$1 } from "./StepIndicator-CiZ8kdPk.mjs";
6
+ import { i as CheckIcon, n as TerminalPanel, r as StateIcon, t as useDiscountCodeUi } from "./useDiscountCodeUi-I-92-x2V.mjs";
7
+ import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-DxvjKvck.mjs";
8
+ import { n as SpinnerNode, r as formatPrice, t as StepIndicator$1 } from "./StepIndicator-CTcGf8Be.mjs";
9
9
  import { t as FeedbackMessage } from "./FeedbackMessage-ByMrs3cr.mjs";
10
10
  import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
11
11
  import { t as buildCheckoutReturnUrls } from "./checkoutUrls-Ct8Mxna3.mjs";
12
12
  import { t as scrollToBlock } from "./scrollToBlock-C86BYkyV.mjs";
13
- import { a as ClockIcon, i as LoggedInAsUser, n as logoutPortal, r as useWaitlistClaim, t as MagicLinkForm } from "./MagicLinkForm-OoJAIUIj.mjs";
13
+ import { a as ClockIcon, i as LoggedInAsUser, n as logoutPortal, r as useWaitlistClaim, t as MagicLinkForm } from "./MagicLinkForm-BzyRJ8VF.mjs";
14
14
  import { t as CrossIcon } from "./CrossIcon-Dn1KRKW5.mjs";
15
15
  import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
16
16
  import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-UNsfPcYq.mjs";
17
17
  import { t as ModalShell } from "./ModalShell-CqkBvBIC.mjs";
18
- import React, { Component, useEffect, useMemo, useState } from "react";
18
+ import React, { Component, useCallback, useEffect, useMemo, useState } from "react";
19
19
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
20
20
  //#region ../blocks/src/system/runtime/shared/utils/validation.ts
21
21
  const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -491,6 +491,37 @@ function EnrollmentForm({ formData, errors, onChange, isEmailLocked, isLoading,
491
491
  ] });
492
492
  }
493
493
  //#endregion
494
+ //#region ../blocks/src/system/runtime/nodes/course-registration/pricing.ts
495
+ function parseCurrencyInputToCents(value) {
496
+ const trimmed = value.trim();
497
+ if (!trimmed) return null;
498
+ const amount = Number(trimmed);
499
+ if (!Number.isFinite(amount) || amount < 0) return null;
500
+ return Math.round(amount * 100);
501
+ }
502
+ function formatCentsAsCurrencyInput(amount) {
503
+ const major = amount / 100;
504
+ return Number.isInteger(major) ? String(major) : major.toFixed(2);
505
+ }
506
+ function getMissingCoursePricingSelectionMessage(pricing) {
507
+ if (pricing?.requiresSelection && !pricing.selectedOption) return pricing.slidingScale ? "Choose an amount to continue." : "Choose a pricing option to continue.";
508
+ const selectedAmount = pricing?.selectedSlidingAmount;
509
+ const scale = pricing?.slidingScale;
510
+ if (scale && selectedAmount !== null && selectedAmount !== void 0 && (selectedAmount < scale.minAmount || selectedAmount > scale.maxAmount)) return "Choose an amount within the sliding scale.";
511
+ return null;
512
+ }
513
+ function buildCoursePricingOptionPayload(pricing) {
514
+ if (pricing?.selectedOption) return { pricingOptionId: pricing.selectedOption.id };
515
+ if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) return { selectedSlidingAmount: pricing.selectedSlidingAmount };
516
+ return {};
517
+ }
518
+ function defaultCoursePricingSelection(pricing, previousOptionId) {
519
+ return {
520
+ pricingOptionId: previousOptionId && pricing.selectableOptions.some((option) => option.id === previousOptionId) ? previousOptionId : pricing.selectedOption?.id ?? null,
521
+ slidingAmountInput: pricing.slidingScale?.suggestedAmount !== null && pricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(pricing.slidingScale.suggestedAmount) : ""
522
+ };
523
+ }
524
+ //#endregion
494
525
  //#region ../blocks/src/system/runtime/nodes/course-registration/wizardSteps.ts
495
526
  /**
496
527
  * Steps that are part of the main wizard and should show the step indicator.
@@ -563,6 +594,110 @@ function getStepLabels(steps) {
563
594
  return steps.map((step) => STEP_LABELS[step] ?? step);
564
595
  }
565
596
  //#endregion
597
+ //#region ../blocks/src/system/runtime/nodes/course-registration/courseRegistrationViewState.ts
598
+ function deriveCourseRegistrationViewState(input) {
599
+ const hasCoursePayment = resolveCoursePaymentRequirement(input.pricing);
600
+ const canUseMembership = hasCoursePayment && input.selectedCourse?.acceptsMemberships === true && input.portalAuthState === "authenticated" && input.eligibleMembershipCount > 0;
601
+ const hasPreSelectedCourse = input.scopedCourses.length === 1;
602
+ const fastTrack = canUseMembership && input.eligibleMembershipCount === 1 && input.bookingMode === "membership";
603
+ const wizardSteps = getWizardStepsForContext(hasPreSelectedCourse, hasCoursePayment, canUseMembership, input.bookingMode, fastTrack);
604
+ const showPortalAuthSidebar = shouldShowPortalAuthSidebar({
605
+ ...input,
606
+ hasCoursePayment
607
+ });
608
+ return {
609
+ hasCoursePayment,
610
+ canUseMembership,
611
+ hasPreSelectedCourse,
612
+ wizardSteps,
613
+ currentStepNumber: getStepNumber(input.step, wizardSteps),
614
+ totalSteps: wizardSteps.length,
615
+ stepLabels: getStepLabels(wizardSteps),
616
+ showPortalAuthSidebar
617
+ };
618
+ }
619
+ function resolveCoursePaymentRequirement(pricing) {
620
+ if (!pricing) return false;
621
+ return pricing.selectedOption ? pricing.selectedRequiresPayment : pricing.hasPaidSelection;
622
+ }
623
+ function shouldShowPortalAuthSidebar(input) {
624
+ if (input.portalAuthState !== "unauthenticated") return false;
625
+ if (input.step === "success" || input.step === "waitlist" || input.step === "error") return false;
626
+ return input.waitlistRequiresPortalLogin || input.hasCoursePayment && input.selectedCourse?.acceptsMemberships === true && input.step !== "select-course";
627
+ }
628
+ //#endregion
629
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseEligibility.ts
630
+ function shouldFetchEligibility(input) {
631
+ if (!input.course || input.portalAuthState === "checking" || input.hasWaitlistClaimToken) return false;
632
+ const membershipCheck = input.portalAuthState === "authenticated" && input.hasPaidSelection && input.course.acceptsMemberships;
633
+ const capacityCheck = input.course.availableSpots !== null && input.course.availableSpots <= 0;
634
+ return membershipCheck || capacityCheck;
635
+ }
636
+ function useCourseEligibility(input) {
637
+ const [loading, setLoading] = useState(false);
638
+ const [error, setError] = useState(null);
639
+ const [eligibility, setEligibility] = useState(null);
640
+ const [memberships, setMemberships] = useState([]);
641
+ const [paymentChoice, setPaymentChoice] = useState("checkout");
642
+ const [selectedMembershipId, setSelectedMembershipId] = useState(null);
643
+ const choosePaymentChoice = useCallback((choice) => {
644
+ setPaymentChoice(choice);
645
+ }, []);
646
+ const chooseMembership = useCallback((membershipId) => {
647
+ setSelectedMembershipId(membershipId);
648
+ }, []);
649
+ useEffect(() => {
650
+ let cancelled = false;
651
+ setEligibility(null);
652
+ setMemberships([]);
653
+ setSelectedMembershipId(null);
654
+ setError(null);
655
+ setPaymentChoice("checkout");
656
+ const eligibilityInput = {
657
+ course: input.selectedCourse,
658
+ hasPaidSelection: input.hasPaidSelection,
659
+ portalAuthState: input.portalAuthState,
660
+ hasWaitlistClaimToken: input.waitlistClaimToken !== null
661
+ };
662
+ if (!shouldFetchEligibility(eligibilityInput)) return;
663
+ const course = eligibilityInput.course;
664
+ setLoading(true);
665
+ input.api.checkWholeSeriesEligibility({ eventSeriesId: course.eventSeriesId }).then((result) => {
666
+ if (cancelled) return;
667
+ const eligibleMemberships = result.eligibleMemberships ?? [];
668
+ setEligibility(result);
669
+ setMemberships(eligibleMemberships);
670
+ if (input.portalAuthState === "authenticated" && eligibleMemberships.length > 0) {
671
+ setPaymentChoice("membership");
672
+ if (eligibleMemberships.length === 1) setSelectedMembershipId(eligibleMemberships[0]?.customerMembershipId ?? null);
673
+ }
674
+ }).catch((cause) => {
675
+ if (!cancelled) setError(cause instanceof Error ? cause.message : "Failed to check membership eligibility");
676
+ }).finally(() => {
677
+ if (!cancelled) setLoading(false);
678
+ });
679
+ return () => {
680
+ cancelled = true;
681
+ };
682
+ }, [
683
+ input.api,
684
+ input.hasPaidSelection,
685
+ input.portalAuthState,
686
+ input.selectedCourse,
687
+ input.waitlistClaimToken
688
+ ]);
689
+ return {
690
+ eligibilityLoading: loading,
691
+ eligibilityError: error,
692
+ courseEligibility: eligibility,
693
+ eligibleMemberships: memberships,
694
+ paymentChoice,
695
+ choosePaymentChoice,
696
+ selectedMembershipId,
697
+ chooseMembership
698
+ };
699
+ }
700
+ //#endregion
566
701
  //#region ../blocks/src/system/runtime/nodes/course-page-surface-scope.ts
567
702
  /**
568
703
  * Resolves native course-page ownership without falling back to entry or slug
@@ -580,7 +715,7 @@ function resolveCoursePageSurfaceScope(courses, subjectValue) {
580
715
  return {
581
716
  kind: "scoped",
582
717
  subject: parsed.value,
583
- courses: courses.filter((course) => allowedSeriesIds.has(course.seriesId))
718
+ courses: courses.filter((course) => allowedSeriesIds.has(course.eventSeriesId))
584
719
  };
585
720
  }
586
721
  function eventSeriesIdsForSubject(subject) {
@@ -591,654 +726,504 @@ function eventSeriesIdsForSubject(subject) {
591
726
  }
592
727
  }
593
728
  //#endregion
594
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.ts
595
- function parseCurrencyInputToCents(value) {
596
- const trimmed = value.trim();
597
- if (!trimmed) return null;
598
- const amount = Number(trimmed);
599
- if (!Number.isFinite(amount) || amount < 0) return null;
600
- return Math.round(amount * 100);
601
- }
602
- function formatCentsAsCurrencyInput(amount) {
603
- const major = amount / 100;
604
- return Number.isInteger(major) ? String(major) : major.toFixed(2);
729
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationSelection.ts
730
+ function selectScopedCourses(props) {
731
+ const surfaceScope = resolveCoursePageSurfaceScope(props.courses ?? [], props.subject);
732
+ if (surfaceScope.kind === "unsupported") return [];
733
+ if (surfaceScope.kind === "scoped") return surfaceScope.courses;
734
+ return [];
605
735
  }
606
- function shouldFetchCourseEligibility(course, hasPaidSelection, portalAuthState, hasWaitlistClaimToken) {
607
- if (!course || portalAuthState === "checking") return false;
608
- if (hasWaitlistClaimToken) return false;
609
- const needsMembershipEligibility = portalAuthState === "authenticated" && hasPaidSelection && course.acceptsMemberships;
610
- const needsWaitlistAvailabilityCheck = course.availableSpots !== null && course.availableSpots <= 0;
611
- return needsMembershipEligibility || needsWaitlistAvailabilityCheck;
612
- }
613
- /**
614
- * Extracts session_id from URL, checking both query params and hash fragment.
615
- *
616
- * Stripe appends session_id to the success URL, but if our URL contains a hash
617
- * (e.g., #course-registration), Stripe ends up appending session_id after the hash:
618
- * Expected: ?enrollment=success&session_id=cs_test_...#course-registration
619
- * Actual: ?enrollment=success#course-registration&session_id=cs_test_...
620
- *
621
- * This helper checks both locations to handle this edge case.
622
- */
623
- function getSessionIdFromUrl() {
736
+ function getCourseCheckoutSessionId() {
624
737
  const fromSearch = new URLSearchParams(window.location.search).get("session_id");
625
738
  if (fromSearch) return fromSearch;
626
739
  return window.location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
627
740
  }
628
- function getMissingCoursePricingSelectionMessage(pricing) {
629
- if (pricing?.requiresSelection && !pricing.selectedOption) {
630
- if (pricing.slidingScale) return "Choose an amount to continue.";
631
- return "Choose a pricing option to continue.";
632
- }
633
- if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount < pricing.slidingScale.minAmount) return "Choose an amount within the sliding scale.";
634
- if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) return "Choose an amount within the sliding scale.";
635
- return null;
741
+ function initialStep(courses) {
742
+ if (new URLSearchParams(window.location.search).get("enrollment") === "success" && getCourseCheckoutSessionId()) return "verifying-payment";
743
+ return courses.length === 1 ? "enter-details" : "select-course";
636
744
  }
637
- function buildCoursePricingOptionPayload(pricing) {
638
- if (pricing?.selectedOption) return { pricingOptionId: pricing.selectedOption.id };
639
- if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) return { selectedSlidingAmount: pricing.selectedSlidingAmount };
640
- return {};
641
- }
642
- function resolveHasCoursePayment(pricing) {
643
- if (!pricing) return false;
644
- if (pricing.selectedOption) return pricing.selectedRequiresPayment;
645
- return pricing.hasPaidSelection;
646
- }
647
- function useCourseRegistrationWizard(props, options = {}) {
648
- const api = useBlockApi();
649
- const { contentEntry, courses, entrySubrouteContext, subject } = props;
650
- const scopedCourses = useMemo(() => {
651
- const allCourses = courses ?? [];
652
- if (entrySubrouteContext?.kind === "course-run") {
653
- const matched = allCourses.find((c) => c.id === entrySubrouteContext.run.courseId) ?? null;
654
- if (matched) return [matched];
655
- }
656
- const pageSurfaceScope = resolveCoursePageSurfaceScope(allCourses, subject);
657
- if (pageSurfaceScope.kind === "unsupported") return [];
658
- if (pageSurfaceScope.kind === "scoped") return [...pageSurfaceScope.courses];
659
- if (contentEntry?.id) {
660
- const matchedCourses = allCourses.filter((c) => c.contentEntryId === contentEntry.id);
661
- if (matchedCourses.length > 0) return matchedCourses;
662
- }
663
- if (contentEntry?.slug) {
664
- const matchedCourse = allCourses.find((c) => c.slug === contentEntry.slug);
665
- if (matchedCourse) return [matchedCourse];
666
- }
667
- return allCourses;
668
- }, [
669
- courses,
670
- contentEntry?.id,
671
- contentEntry?.slug,
672
- entrySubrouteContext,
673
- subject
674
- ]);
675
- const [step, setStep] = useState(() => {
676
- const enrollment = new URLSearchParams(window.location.search).get("enrollment");
677
- const sessionId = getSessionIdFromUrl();
678
- if (enrollment === "success" && sessionId) return "verifying-payment";
679
- return scopedCourses.length === 1 ? "enter-details" : "select-course";
680
- });
745
+ function useCourseRegistrationSelection(props) {
746
+ const scopedCourses = useMemo(() => selectScopedCourses(props), [props.courses, props.subject]);
747
+ const [step, setStep] = useState(() => initialStep(scopedCourses));
681
748
  const [selectedCourse, setSelectedCourse] = useState(scopedCourses.length === 1 ? scopedCourses[0] ?? null : null);
682
749
  const [selectedPricingOptionId, setSelectedPricingOptionId] = useState(null);
683
750
  const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState("");
684
- const [formData, setFormData] = useState({
685
- name: "",
686
- email: "",
687
- phone: "",
688
- notes: ""
689
- });
690
- const [errors, setErrors] = useState({});
691
- const [enrollmentResult, setEnrollmentResult] = useState(null);
692
- const [errorMessage, setErrorMessage] = useState("");
693
- const [portalAuthState, setPortalAuthState] = useState("checking");
694
- const [altchaSolution, setAltchaSolution] = useState(null);
695
- const showSpamProtection = isSpamProtectionEnabled();
696
- const [eligibilityLoading, setEligibilityLoading] = useState(false);
697
- const [eligibilityError, setEligibilityError] = useState(null);
698
- const [courseEligibility, setCourseEligibility] = useState(null);
699
- const [eligibleMemberships, setEligibleMemberships] = useState([]);
700
- const [paymentChoice, setPaymentChoice] = useState("checkout");
701
- const [selectedMembershipId, setSelectedMembershipId] = useState(null);
702
- const [bookingMode, setBookingMode] = useState(null);
703
- const waitlistClaim = useWaitlistClaim();
751
+ const goToStep = useCallback((nextStep) => {
752
+ setStep(nextStep);
753
+ }, []);
754
+ const chooseCourse = useCallback((course) => {
755
+ setSelectedCourse(course);
756
+ }, []);
757
+ const choosePricingOption = useCallback((pricingOptionId) => {
758
+ setSelectedPricingOptionId(pricingOptionId);
759
+ }, []);
760
+ const changeSlidingAmount = useCallback((amount) => {
761
+ setSelectedSlidingAmountInput(amount);
762
+ }, []);
704
763
  const selectedCoursePricing = useMemo(() => selectedCourse ? resolveCoursePricingState(selectedCourse, selectedPricingOptionId, parseCurrencyInputToCents(selectedSlidingAmountInput)) : null, [
705
764
  selectedCourse,
706
765
  selectedPricingOptionId,
707
766
  selectedSlidingAmountInput
708
767
  ]);
709
- const missingPricingSelectionMessage = getMissingCoursePricingSelectionMessage(selectedCoursePricing);
710
- const selectedCoursePricingPayload = buildCoursePricingOptionPayload(selectedCoursePricing);
711
- const showSoldOutCourseError = () => {
712
- setErrorMessage(courseEligibility?.reason ?? "This course is fully booked.");
713
- setStep("error");
714
- return true;
715
- };
716
- useEffect(() => {
717
- let cancelled = false;
718
- async function checkPortalAuth() {
719
- if (!(api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer")) {
720
- setPortalAuthState("unauthenticated");
721
- return;
722
- }
723
- setPortalAuthState("checking");
724
- try {
725
- const me = await api.getPortalProfile();
726
- if (cancelled) return;
727
- setPortalAuthState("authenticated");
728
- setFormData((prev) => ({
729
- ...prev,
730
- email: me.profile.email,
731
- name: prev.name || me.profile.name,
732
- phone: prev.phone || me.profile.phone || ""
733
- }));
734
- } catch {
735
- if (cancelled) return;
736
- setPortalAuthState("unauthenticated");
737
- }
738
- }
739
- checkPortalAuth();
740
- return () => {
741
- cancelled = true;
742
- };
743
- }, [api]);
744
- useEffect(() => {
745
- const claim = waitlistClaim.claim;
746
- if (!claim || claim.subject.kind !== "course") return;
747
- const courseId = claim.subject.courseId;
748
- const matchedCourse = scopedCourses.find((course) => course.id === courseId) ?? null;
749
- if (!matchedCourse) {
750
- setErrorMessage("This waitlist claim is for a different course.");
751
- setStep("error");
752
- return;
753
- }
754
- setSelectedCourse(matchedCourse);
755
- setFormData((prev) => ({
756
- ...prev,
757
- email: claim.prefill.email,
758
- name: claim.prefill.name,
759
- phone: claim.prefill.phone ?? "",
760
- notes: claim.prefill.notes ?? ""
761
- }));
762
- if (step === "select-course") setStep("enter-details");
763
- }, [
764
- waitlistClaim.claim,
765
- scopedCourses,
766
- step
767
- ]);
768
- useEffect(() => {
769
- if (waitlistClaim.requiresPortalLogin) return;
770
- if (!waitlistClaim.error) return;
771
- setErrorMessage(waitlistClaim.error);
772
- setStep("error");
773
- }, [waitlistClaim.error, waitlistClaim.requiresPortalLogin]);
774
768
  useEffect(() => {
775
769
  if (!selectedCourse) {
776
770
  setSelectedPricingOptionId(null);
777
771
  setSelectedSlidingAmountInput("");
778
772
  return;
779
773
  }
780
- const defaultPricing = resolveCoursePricingState(selectedCourse, null);
781
- setSelectedSlidingAmountInput(defaultPricing.slidingScale?.suggestedAmount !== null && defaultPricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(defaultPricing.slidingScale.suggestedAmount) : "");
782
- setSelectedPricingOptionId((previous) => {
783
- if (previous && defaultPricing.selectableOptions.some((option) => option.id === previous)) return previous;
784
- return defaultPricing.selectedOption?.id ?? null;
785
- });
774
+ const selection = defaultCoursePricingSelection(resolveCoursePricingState(selectedCourse, null), selectedPricingOptionId);
775
+ setSelectedPricingOptionId(selection.pricingOptionId);
776
+ setSelectedSlidingAmountInput(selection.slidingAmountInput);
786
777
  }, [selectedCourse]);
787
- useEffect(() => {
788
- let cancelled = false;
789
- async function fetchEligibility() {
790
- setCourseEligibility(null);
791
- setEligibleMemberships([]);
792
- setSelectedMembershipId(null);
793
- setEligibilityError(null);
794
- setPaymentChoice("checkout");
795
- const course = selectedCourse;
796
- if (!shouldFetchCourseEligibility(course, selectedCoursePricing?.hasPaidSelection ?? false, portalAuthState, waitlistClaim.token !== null)) return;
797
- if (!course) return;
798
- setEligibilityLoading(true);
799
- try {
800
- const res = await api.checkCourseEligibility({ courseId: course.id });
801
- if (cancelled) return;
802
- setCourseEligibility(res);
803
- const memberships = res.eligibleMemberships ?? [];
804
- setEligibleMemberships(memberships);
805
- if (portalAuthState === "authenticated" && memberships.length > 0) {
806
- setPaymentChoice("membership");
807
- if (memberships.length === 1) setSelectedMembershipId(memberships[0]?.customerMembershipId ?? null);
808
- }
809
- } catch (error) {
810
- if (cancelled) return;
811
- setEligibilityError(error instanceof Error ? error.message : "Failed to check membership eligibility");
812
- } finally {
813
- if (!cancelled) setEligibilityLoading(false);
778
+ return {
779
+ scopedCourses,
780
+ step,
781
+ goToStep,
782
+ selectedCourse,
783
+ chooseCourse,
784
+ selectedPricingOptionId,
785
+ choosePricingOption,
786
+ selectedSlidingAmountInput,
787
+ changeSlidingAmount,
788
+ selectedCoursePricing
789
+ };
790
+ }
791
+ //#endregion
792
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCoursePaymentVerification.ts
793
+ function applyTerminalStatus(status, setters) {
794
+ if (status === "enrolled" || status === "completed") {
795
+ setters.setEnrollmentResult({
796
+ status: "enrolled",
797
+ usedMembership: false
798
+ });
799
+ setters.setStep("success");
800
+ return true;
801
+ }
802
+ if (status === "waitlist") {
803
+ setters.setEnrollmentResult({
804
+ status: "waitlist",
805
+ usedMembership: false
806
+ });
807
+ setters.setStep("waitlist");
808
+ return true;
809
+ }
810
+ setters.setErrorMessage("Payment did not complete. Please try again.");
811
+ setters.setStep("error");
812
+ return true;
813
+ }
814
+ async function pollCourseRegistrationStatus(api, sessionId, setters, isCancelled) {
815
+ const startedAt = Date.now();
816
+ while (!isCancelled()) {
817
+ try {
818
+ const result = await api.getWholeSeriesRegistrationStatus({ sessionId });
819
+ if (isCancelled()) return;
820
+ if (result.status !== "pending_payment") {
821
+ applyTerminalStatus(result.status, setters);
822
+ return;
814
823
  }
824
+ } catch (cause) {
825
+ setters.setErrorMessage(cause instanceof Error ? cause.message : "Failed to verify payment");
815
826
  }
816
- fetchEligibility();
817
- return () => {
818
- cancelled = true;
819
- };
820
- }, [
821
- api,
822
- selectedCourse,
823
- selectedCoursePricing?.hasPaidSelection,
824
- portalAuthState,
825
- waitlistClaim.token
826
- ]);
827
+ if (Date.now() - startedAt > 3e4) {
828
+ setters.setErrorMessage("Payment is still processing. Please check your email for confirmation.");
829
+ setters.setStep("error");
830
+ return;
831
+ }
832
+ await new Promise((resolve) => setTimeout(resolve, 1500));
833
+ }
834
+ }
835
+ function useCoursePaymentVerification(api, setters) {
827
836
  useEffect(() => {
828
837
  let cancelled = false;
829
- async function verifyAfterCheckout() {
830
- const enrollment = new URLSearchParams(window.location.search).get("enrollment");
831
- const sessionId = getSessionIdFromUrl();
832
- if (enrollment === "cancelled") {
833
- scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
834
- setErrorMessage("Payment was cancelled. You can try again.");
835
- setStep("error");
836
- return;
837
- }
838
- if (enrollment !== "success" || !sessionId) return;
838
+ const enrollment = new URLSearchParams(window.location.search).get("enrollment");
839
+ const sessionId = getCourseCheckoutSessionId();
840
+ if (enrollment === "cancelled") {
839
841
  scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
840
- setStep("verifying-payment");
841
- const startedAt = Date.now();
842
- const timeoutMs = 3e4;
843
- while (!cancelled) {
844
- try {
845
- const status = await api.getCourseRegistrationStatus({ sessionId });
846
- if (cancelled) return;
847
- if (status.status === "enrolled" || status.status === "completed") {
848
- setEnrollmentResult({
849
- status: "enrolled",
850
- usedMembership: false
851
- });
852
- setStep("success");
853
- return;
854
- }
855
- if (status.status === "waitlist") {
856
- setEnrollmentResult({
857
- status: "waitlist",
858
- usedMembership: false
859
- });
860
- setStep("waitlist");
861
- return;
862
- }
863
- if (status.status === "cancelled") {
864
- setErrorMessage("Payment did not complete. Please try again.");
865
- setStep("error");
866
- return;
867
- }
868
- } catch (error) {
869
- setErrorMessage(error instanceof Error ? error.message : "Failed to verify payment");
870
- }
871
- if (Date.now() - startedAt > timeoutMs) {
872
- setErrorMessage("Payment is still processing. Please check your email for confirmation.");
873
- setStep("error");
874
- return;
875
- }
876
- await new Promise((r) => setTimeout(r, 1500));
877
- }
842
+ setters.setErrorMessage("Payment was cancelled. You can try again.");
843
+ setters.setStep("error");
844
+ return;
878
845
  }
879
- verifyAfterCheckout();
846
+ if (enrollment !== "success" || !sessionId) return;
847
+ scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
848
+ setters.setStep("verifying-payment");
849
+ pollCourseRegistrationStatus(api, sessionId, setters, () => cancelled);
880
850
  return () => {
881
851
  cancelled = true;
882
852
  };
883
- }, [api]);
884
- const handleValidateForm = () => {
885
- const newErrors = validateFormData(formData);
886
- setErrors(newErrors);
887
- return Object.keys(newErrors).length === 0;
853
+ }, [
854
+ api,
855
+ setters.setEnrollmentResult,
856
+ setters.setErrorMessage,
857
+ setters.setStep
858
+ ]);
859
+ }
860
+ //#endregion
861
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationActions.ts
862
+ function blocked(message, setters) {
863
+ setters.setErrorMessage(message);
864
+ setters.setStep("error");
865
+ return {
866
+ kind: "blocked",
867
+ message
888
868
  };
889
- const handleCourseSelect = (course) => {
890
- setSelectedCourse(course);
891
- setStep("enter-details");
869
+ }
870
+ function validateSubmission(state, setters) {
871
+ if (!state.selectedCourse) return {
872
+ kind: "blocked",
873
+ message: "Choose an available set of dates to continue."
892
874
  };
893
- const handleSubmit = async () => {
894
- if (!selectedCourse) return {
895
- kind: "blocked",
896
- message: "Choose an available set of dates to continue."
897
- };
898
- if (!handleValidateForm()) return { kind: "validation-failed" };
899
- if (missingPricingSelectionMessage) {
900
- setErrorMessage(missingPricingSelectionMessage);
901
- setStep("error");
902
- return {
903
- kind: "blocked",
904
- message: missingPricingSelectionMessage
905
- };
906
- }
907
- const requiresPayment = selectedCoursePricing?.selectedRequiresPayment ?? false;
908
- const canUseMembership = requiresPayment && selectedCourse.acceptsMemberships && portalAuthState === "authenticated" && eligibleMemberships.length > 0;
909
- if (showSpamProtection && !altchaSolution) {
910
- const message = "Please complete the verification check.";
911
- setErrorMessage(message);
912
- setStep("error");
913
- return {
914
- kind: "blocked",
915
- message
916
- };
917
- }
918
- if (!waitlistClaim.claim && courseEligibility?.isFull && !courseEligibility.canJoinWaitlist && showSoldOutCourseError()) return {
919
- kind: "blocked",
920
- message: courseEligibility.reason ?? "This course is fully booked."
875
+ const errors = validateFormData(state.formData);
876
+ setters.setErrors(errors);
877
+ if (Object.keys(errors).length > 0) return { kind: "validation-failed" };
878
+ const pricingMessage = getMissingCoursePricingSelectionMessage(state.pricing);
879
+ if (pricingMessage) return blocked(pricingMessage, setters);
880
+ if (!state.hasClaim && state.eligibility?.isFull && !state.eligibility.canJoinWaitlist) return blocked(state.eligibility.reason ?? "This course is fully booked.", setters);
881
+ if (isSpamProtectionEnabled() && !state.altchaSolution) return blocked("Please complete the verification check.", setters);
882
+ return null;
883
+ }
884
+ function enrollmentPayload(state, payment) {
885
+ return {
886
+ ...registrantPayload(state),
887
+ paymentMethod: payment.method,
888
+ ...payment.method === "membership" ? { customerMembershipId: payment.membershipId } : {}
889
+ };
890
+ }
891
+ function registrantPayload(state) {
892
+ return {
893
+ eventSeriesId: state.selectedCourse.eventSeriesId,
894
+ ...buildCoursePricingOptionPayload(state.pricing),
895
+ email: state.formData.email.trim().toLowerCase(),
896
+ name: state.formData.name.trim(),
897
+ phone: state.formData.phone.trim() || void 0,
898
+ formData: { notes: state.formData.notes.trim() || void 0 },
899
+ altchaSolution: state.altchaSolution,
900
+ claimToken: state.claimToken ?? void 0
901
+ };
902
+ }
903
+ async function enroll(state, setters, payment) {
904
+ setters.setStep("submitting");
905
+ try {
906
+ const result = await state.api.registerForWholeSeries(enrollmentPayload(state, payment));
907
+ setters.setEnrollmentResult({
908
+ status: result.status,
909
+ waitlistPosition: result.waitlistPosition ?? void 0,
910
+ usedMembership: payment.method === "membership"
911
+ });
912
+ setters.setStep(result.status === "waitlist" ? "waitlist" : "success");
913
+ return { kind: "state-updated" };
914
+ } catch (cause) {
915
+ const message = cause instanceof Error ? cause.message : "Booking failed";
916
+ setters.setErrorMessage(message);
917
+ setters.setStep("error");
918
+ return {
919
+ kind: "failed",
920
+ message
921
921
  };
922
- if (courseEligibility?.canJoinWaitlist) {
923
- setStep("submitting");
924
- try {
925
- const result = await api.enrollInCourse({
926
- courseId: selectedCourse.id,
927
- ...selectedCoursePricingPayload,
928
- email: formData.email.trim().toLowerCase(),
929
- name: formData.name.trim(),
930
- phone: formData.phone.trim() || void 0,
931
- formData: { notes: formData.notes.trim() || void 0 },
932
- altchaSolution,
933
- paymentMethod: "free",
934
- claimToken: waitlistClaim.token ?? void 0
935
- });
936
- setEnrollmentResult({
937
- status: result.status,
938
- waitlistPosition: result.waitlistPosition ?? void 0,
939
- usedMembership: false
940
- });
941
- setStep(result.status === "waitlist" ? "waitlist" : "success");
942
- return { kind: "state-updated" };
943
- } catch (error) {
944
- const message = error instanceof Error ? error.message : "Booking failed";
945
- setErrorMessage(message);
946
- setStep("error");
947
- return {
948
- kind: "failed",
949
- message
950
- };
951
- }
952
- }
953
- if (requiresPayment && canUseMembership) {
954
- setStep("select-payment");
955
- return { kind: "state-updated" };
956
- }
957
- if (requiresPayment) {
958
- setStep("submitting");
959
- try {
960
- const { successUrl, cancelUrl } = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
961
- const checkoutResult = await api.createCourseCheckout({
962
- courseId: selectedCourse.id,
963
- ...selectedCoursePricingPayload,
964
- email: formData.email.trim().toLowerCase(),
965
- name: formData.name.trim(),
966
- phone: formData.phone.trim() || void 0,
967
- formData: { notes: formData.notes.trim() || void 0 },
968
- altchaSolution,
969
- discountCode: discountCode.trim() ? discountCode.trim() : void 0,
970
- successUrl,
971
- cancelUrl,
972
- claimToken: waitlistClaim.token ?? void 0
973
- });
974
- if (checkoutResult.bypassed) {
975
- setEnrollmentResult({
976
- status: "enrolled",
977
- waitlistPosition: void 0,
978
- usedMembership: false
979
- });
980
- setStep("success");
981
- return { kind: "state-updated" };
982
- }
983
- if (!checkoutResult.checkoutUrl) throw new Error("Checkout URL missing");
984
- setStep("redirecting");
985
- if (options.onCheckoutRedirect) options.onCheckoutRedirect(checkoutResult.checkoutUrl);
986
- else window.location.href = checkoutResult.checkoutUrl;
987
- return {
988
- kind: "checkout-redirect",
989
- checkoutUrl: checkoutResult.checkoutUrl
990
- };
991
- } catch (error) {
992
- const message = error instanceof Error ? error.message : "Checkout failed";
993
- setErrorMessage(message);
994
- setStep("error");
995
- return {
996
- kind: "failed",
997
- message
998
- };
999
- }
1000
- }
1001
- setStep("submitting");
1002
- try {
1003
- const result = await api.enrollInCourse({
1004
- courseId: selectedCourse.id,
1005
- ...selectedCoursePricingPayload,
1006
- email: formData.email.trim().toLowerCase(),
1007
- name: formData.name.trim(),
1008
- phone: formData.phone.trim() || void 0,
1009
- formData: { notes: formData.notes.trim() || void 0 },
1010
- altchaSolution,
1011
- paymentMethod: "free",
1012
- claimToken: waitlistClaim.token ?? void 0
1013
- });
1014
- setEnrollmentResult({
1015
- status: result.status,
1016
- waitlistPosition: result.waitlistPosition ?? void 0,
1017
- usedMembership: result.paymentMethod === "membership"
922
+ }
923
+ }
924
+ async function checkout(state, setters) {
925
+ setters.setStep("submitting");
926
+ try {
927
+ const urls = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
928
+ const result = await state.api.createWholeSeriesCheckout({
929
+ ...registrantPayload(state),
930
+ discountCode: state.discountCode.trim() || void 0,
931
+ successUrl: urls.successUrl,
932
+ cancelUrl: urls.cancelUrl
933
+ });
934
+ if (result.bypassed) {
935
+ setters.setEnrollmentResult({
936
+ status: "enrolled",
937
+ usedMembership: false
1018
938
  });
1019
- setStep(result.status === "waitlist" ? "waitlist" : "success");
939
+ setters.setStep("success");
1020
940
  return { kind: "state-updated" };
1021
- } catch (error) {
1022
- const message = error instanceof Error ? error.message : "Booking failed";
1023
- setErrorMessage(message);
1024
- setStep("error");
1025
- return {
1026
- kind: "failed",
1027
- message
1028
- };
1029
941
  }
1030
- };
1031
- const handlePaymentContinue = async () => {
1032
- if (!selectedCourse) return {
1033
- kind: "blocked",
1034
- message: "Choose an available set of dates to continue."
942
+ if (!result.checkoutUrl) throw new Error("Checkout URL missing");
943
+ setters.setStep("redirecting");
944
+ if (state.options.onCheckoutRedirect) state.options.onCheckoutRedirect(result.checkoutUrl);
945
+ else window.location.href = result.checkoutUrl;
946
+ return {
947
+ kind: "checkout-redirect",
948
+ checkoutUrl: result.checkoutUrl
1035
949
  };
1036
- if (!handleValidateForm()) return { kind: "validation-failed" };
1037
- if (missingPricingSelectionMessage) {
1038
- setErrorMessage(missingPricingSelectionMessage);
1039
- setStep("error");
1040
- return {
1041
- kind: "blocked",
1042
- message: missingPricingSelectionMessage
1043
- };
1044
- }
1045
- const requiresPayment = selectedCoursePricing?.selectedRequiresPayment ?? false;
1046
- if (!waitlistClaim.claim && courseEligibility?.isFull && !courseEligibility.canJoinWaitlist && showSoldOutCourseError()) return {
1047
- kind: "blocked",
1048
- message: courseEligibility.reason ?? "This course is fully booked."
950
+ } catch (cause) {
951
+ const message = cause instanceof Error ? cause.message : "Checkout failed";
952
+ setters.setErrorMessage(message);
953
+ setters.setStep("error");
954
+ return {
955
+ kind: "failed",
956
+ message
1049
957
  };
1050
- if (!requiresPayment) {
1051
- setStep("enter-details");
1052
- return { kind: "state-updated" };
1053
- }
1054
- if (showSpamProtection && !altchaSolution) {
1055
- const message = "Please complete the verification check.";
1056
- setErrorMessage(message);
1057
- setStep("error");
1058
- return {
1059
- kind: "blocked",
1060
- message
1061
- };
1062
- }
1063
- if (paymentChoice === "membership") {
1064
- if (!selectedMembershipId) {
1065
- const message = "Select a membership to sign up.";
1066
- setErrorMessage(message);
1067
- setStep("error");
1068
- return {
1069
- kind: "blocked",
1070
- message
1071
- };
1072
- }
1073
- setStep("submitting");
1074
- try {
1075
- const result = await api.enrollInCourse({
1076
- courseId: selectedCourse.id,
1077
- ...selectedCoursePricingPayload,
1078
- email: formData.email.trim().toLowerCase(),
1079
- name: formData.name.trim(),
1080
- phone: formData.phone.trim() || void 0,
1081
- formData: { notes: formData.notes.trim() || void 0 },
1082
- altchaSolution,
1083
- paymentMethod: "membership",
1084
- customerMembershipId: selectedMembershipId,
1085
- claimToken: waitlistClaim.token ?? void 0
1086
- });
1087
- setEnrollmentResult({
1088
- status: result.status,
1089
- waitlistPosition: result.waitlistPosition ?? void 0,
1090
- usedMembership: true
1091
- });
1092
- setStep(result.status === "waitlist" ? "waitlist" : "success");
1093
- return { kind: "state-updated" };
1094
- } catch (error) {
1095
- const message = error instanceof Error ? error.message : "Booking failed";
1096
- setErrorMessage(message);
1097
- setStep("error");
1098
- return {
1099
- kind: "failed",
1100
- message
1101
- };
1102
- }
1103
- }
1104
- setStep("submitting");
1105
- try {
1106
- const { successUrl, cancelUrl } = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
1107
- const checkoutResult = await api.createCourseCheckout({
1108
- courseId: selectedCourse.id,
1109
- ...selectedCoursePricingPayload,
1110
- email: formData.email.trim().toLowerCase(),
1111
- name: formData.name.trim(),
1112
- phone: formData.phone.trim() || void 0,
1113
- formData: { notes: formData.notes.trim() || void 0 },
1114
- altchaSolution,
1115
- discountCode: discountCode.trim() ? discountCode.trim() : void 0,
1116
- successUrl,
1117
- cancelUrl,
1118
- claimToken: waitlistClaim.token ?? void 0
1119
- });
1120
- if (checkoutResult.bypassed) {
1121
- setEnrollmentResult({
1122
- status: "enrolled",
1123
- waitlistPosition: void 0,
1124
- usedMembership: false
1125
- });
1126
- setStep("success");
1127
- return { kind: "state-updated" };
1128
- }
1129
- if (!checkoutResult.checkoutUrl) throw new Error("Checkout URL missing");
1130
- setStep("redirecting");
1131
- if (options.onCheckoutRedirect) options.onCheckoutRedirect(checkoutResult.checkoutUrl);
1132
- else window.location.href = checkoutResult.checkoutUrl;
1133
- return {
1134
- kind: "checkout-redirect",
1135
- checkoutUrl: checkoutResult.checkoutUrl
1136
- };
1137
- } catch (error) {
1138
- const message = error instanceof Error ? error.message : "Checkout failed";
1139
- setErrorMessage(message);
1140
- setStep("error");
1141
- return {
1142
- kind: "failed",
1143
- message
1144
- };
1145
- }
958
+ }
959
+ }
960
+ async function submitDetails(state, setters) {
961
+ const invalid = validateSubmission(state, setters);
962
+ if (invalid || !state.selectedCourse) return invalid ?? { kind: "validation-failed" };
963
+ if (state.eligibility?.canJoinWaitlist) return enroll(state, setters, { method: "free" });
964
+ const requiresPayment = state.pricing?.selectedRequiresPayment ?? false;
965
+ const canUseMembership = requiresPayment && state.selectedCourse.acceptsMemberships && state.portalAuthState === "authenticated" && state.eligibleMemberships.length > 0;
966
+ if (requiresPayment && canUseMembership) {
967
+ setters.setStep("select-payment");
968
+ return { kind: "state-updated" };
969
+ }
970
+ if (requiresPayment) return checkout(state, setters);
971
+ return enroll(state, setters, { method: "free" });
972
+ }
973
+ async function continuePayment(state, setters) {
974
+ const invalid = validateSubmission(state, setters);
975
+ if (invalid || !state.selectedCourse) return invalid ?? { kind: "validation-failed" };
976
+ if (!state.pricing?.selectedRequiresPayment) {
977
+ setters.setStep("enter-details");
978
+ return { kind: "state-updated" };
979
+ }
980
+ const selectedState = state;
981
+ if (state.paymentChoice === "membership") {
982
+ if (!state.selectedMembershipId) return blocked("Select a membership to sign up.", setters);
983
+ return enroll(selectedState, setters, {
984
+ method: "membership",
985
+ membershipId: state.selectedMembershipId
986
+ });
987
+ }
988
+ return checkout(selectedState, setters);
989
+ }
990
+ function useCourseRegistrationActions(state, setStep) {
991
+ const [errors, setErrors] = useState({});
992
+ const [enrollmentResult, setEnrollmentResult] = useState(null);
993
+ const [errorMessage, setErrorMessage] = useState("");
994
+ const reportError = useCallback((message) => {
995
+ setErrorMessage(message);
996
+ }, []);
997
+ const recordEnrollmentResult = useCallback((result) => {
998
+ setEnrollmentResult(result);
999
+ }, []);
1000
+ const setters = {
1001
+ setStep,
1002
+ setErrors,
1003
+ setEnrollmentResult,
1004
+ setErrorMessage
1146
1005
  };
1147
- const handleRetry = () => {
1148
- setStep(scopedCourses.length === 1 ? "enter-details" : "select-course");
1149
- setErrorMessage("");
1006
+ return {
1007
+ errors,
1008
+ enrollmentResult,
1009
+ errorMessage,
1010
+ reportError,
1011
+ recordEnrollmentResult,
1012
+ handleSubmit: () => submitDetails(state, setters),
1013
+ handlePaymentContinue: () => continuePayment(state, setters)
1150
1014
  };
1151
- const handleBookingModeChange = (mode) => {
1152
- setBookingMode(mode);
1153
- if (mode === "membership") setPaymentChoice("membership");
1154
- else setPaymentChoice("checkout");
1015
+ }
1016
+ //#endregion
1017
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationPortal.ts
1018
+ const EMPTY_FORM = {
1019
+ name: "",
1020
+ email: "",
1021
+ phone: "",
1022
+ notes: ""
1023
+ };
1024
+ function useCourseRegistrationPortal(api) {
1025
+ const [formData, setFormData] = useState(EMPTY_FORM);
1026
+ const [portalAuthState, setPortalAuthState] = useState("checking");
1027
+ const updateFormData = useCallback((updater) => {
1028
+ setFormData(updater);
1029
+ }, []);
1030
+ useEffect(() => {
1031
+ let cancelled = false;
1032
+ if (!(api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer")) {
1033
+ setPortalAuthState("unauthenticated");
1034
+ return;
1035
+ }
1036
+ setPortalAuthState("checking");
1037
+ api.getPortalProfile().then((result) => {
1038
+ if (cancelled) return;
1039
+ setPortalAuthState("authenticated");
1040
+ setFormData((current) => ({
1041
+ ...current,
1042
+ email: result.profile.email,
1043
+ name: current.name || result.profile.name,
1044
+ phone: current.phone || result.profile.phone || ""
1045
+ }));
1046
+ }).catch(() => {
1047
+ if (!cancelled) setPortalAuthState("unauthenticated");
1048
+ });
1049
+ return () => {
1050
+ cancelled = true;
1051
+ };
1052
+ }, [api]);
1053
+ return {
1054
+ formData,
1055
+ updateFormData,
1056
+ portalAuthState
1155
1057
  };
1058
+ }
1059
+ //#endregion
1060
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseWaitlistSelection.ts
1061
+ function useCourseWaitlistSelection(input) {
1062
+ useEffect(() => {
1063
+ const claim = input.waitlistClaim.claim;
1064
+ if (!claim || claim.subject.kind !== "whole_series") return;
1065
+ const eventSeriesId = claim.subject.eventSeriesId;
1066
+ const course = input.scopedCourses.find((candidate) => candidate.eventSeriesId === eventSeriesId);
1067
+ if (!course) {
1068
+ input.reportError("This waitlist claim is for a different course.");
1069
+ input.goToStep("error");
1070
+ return;
1071
+ }
1072
+ input.chooseCourse(course);
1073
+ input.updateFormData((current) => ({
1074
+ ...current,
1075
+ email: claim.prefill.email,
1076
+ name: claim.prefill.name,
1077
+ phone: claim.prefill.phone ?? "",
1078
+ notes: claim.prefill.notes ?? ""
1079
+ }));
1080
+ if (input.step === "select-course") input.goToStep("enter-details");
1081
+ }, [
1082
+ input.chooseCourse,
1083
+ input.goToStep,
1084
+ input.reportError,
1085
+ input.scopedCourses,
1086
+ input.step,
1087
+ input.updateFormData,
1088
+ input.waitlistClaim.claim
1089
+ ]);
1090
+ useEffect(() => {
1091
+ if (input.waitlistClaim.requiresPortalLogin || !input.waitlistClaim.error) return;
1092
+ input.reportError(input.waitlistClaim.error);
1093
+ input.goToStep("error");
1094
+ }, [
1095
+ input.goToStep,
1096
+ input.reportError,
1097
+ input.waitlistClaim.error,
1098
+ input.waitlistClaim.requiresPortalLogin
1099
+ ]);
1100
+ }
1101
+ //#endregion
1102
+ //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.ts
1103
+ function useCourseRegistrationWizard(props, options = {}) {
1104
+ const api = useBlockApi();
1105
+ const selection = useCourseRegistrationSelection(props);
1106
+ const portal = useCourseRegistrationPortal(api);
1107
+ const waitlistClaim = useWaitlistClaim();
1108
+ const [bookingMode, setBookingMode] = useState(null);
1109
+ const [altchaSolution, setAltchaSolution] = useState(null);
1110
+ const eligibility = useCourseEligibility({
1111
+ api,
1112
+ selectedCourse: selection.selectedCourse,
1113
+ hasPaidSelection: selection.selectedCoursePricing?.hasPaidSelection ?? false,
1114
+ portalAuthState: portal.portalAuthState,
1115
+ waitlistClaimToken: waitlistClaim.token
1116
+ });
1156
1117
  const discountUi = useDiscountCodeUi({
1157
1118
  api,
1158
- discountContext: useMemo(() => {
1159
- if (!selectedCourse) return null;
1160
- if (!selectedCoursePricing?.selectedRequiresPayment) return null;
1161
- if (paymentChoice !== "checkout") return null;
1162
- return {
1163
- type: "course",
1164
- courseId: selectedCourse.id
1165
- };
1166
- }, [
1167
- selectedCourse,
1168
- selectedCoursePricing?.selectedRequiresPayment,
1169
- paymentChoice
1119
+ discountContext: useMemo(() => selection.selectedCourse && selection.selectedCoursePricing?.selectedRequiresPayment && eligibility.paymentChoice === "checkout" ? {
1120
+ type: "whole_series",
1121
+ eventSeriesId: selection.selectedCourse.eventSeriesId
1122
+ } : null, [
1123
+ eligibility.paymentChoice,
1124
+ selection.selectedCourse,
1125
+ selection.selectedCoursePricing?.selectedRequiresPayment
1170
1126
  ]),
1171
- subtotalCents: selectedCoursePricing?.selectedPriceAmount ?? void 0
1127
+ subtotalCents: selection.selectedCoursePricing?.selectedPriceAmount ?? void 0
1172
1128
  });
1173
- const discountCode = discountUi.discountCode;
1174
- const hasCoursePayment = resolveHasCoursePayment(selectedCoursePricing);
1175
- const canUseMembership = hasCoursePayment && selectedCourse?.acceptsMemberships === true && portalAuthState === "authenticated" && eligibleMemberships.length > 0;
1176
- const hasPreSelectedCourse = scopedCourses.length === 1;
1177
- const isMembershipFastTrack = canUseMembership && eligibleMemberships.length === 1 && bookingMode === "membership";
1178
- const wizardSteps = useMemo(() => getWizardStepsForContext(hasPreSelectedCourse, hasCoursePayment, canUseMembership, bookingMode, isMembershipFastTrack), [
1179
- hasPreSelectedCourse,
1180
- hasCoursePayment,
1181
- canUseMembership,
1182
- bookingMode,
1183
- isMembershipFastTrack
1184
- ]);
1185
- const currentStepNumber = getStepNumber(step, wizardSteps);
1186
- const totalSteps = wizardSteps.length;
1187
- const stepLabels = getStepLabels(wizardSteps);
1188
- const canShowPortalAuthSidebarOnCurrentStep = step !== "success" && step !== "waitlist" && step !== "error";
1189
- const showPortalAuthSidebar = portalAuthState === "unauthenticated" && waitlistClaim.requiresPortalLogin && canShowPortalAuthSidebarOnCurrentStep || portalAuthState === "unauthenticated" && hasCoursePayment && selectedCourse?.acceptsMemberships === true && step !== "select-course" && canShowPortalAuthSidebarOnCurrentStep;
1190
- return {
1129
+ const actions = useCourseRegistrationActions({
1191
1130
  api,
1192
- scopedCourses,
1193
- step,
1194
- setStep,
1195
- selectedCourse,
1196
- selectedPricingOptionId,
1197
- setSelectedPricingOptionId,
1198
- selectedSlidingAmountInput,
1199
- setSelectedSlidingAmountInput,
1200
- selectedCoursePricing,
1201
- setSelectedCourse,
1202
- formData,
1203
- setFormData,
1204
- errors,
1205
- enrollmentResult,
1206
- errorMessage,
1207
- portalAuthState,
1208
- handleLogout: portalAuthState === "authenticated" ? () => logoutPortal(COURSE_REGISTRATION_ANCHOR_ID) : void 0,
1131
+ selectedCourse: selection.selectedCourse,
1132
+ pricing: selection.selectedCoursePricing,
1133
+ formData: portal.formData,
1134
+ portalAuthState: portal.portalAuthState,
1135
+ eligibility: eligibility.courseEligibility,
1136
+ eligibleMemberships: eligibility.eligibleMemberships,
1137
+ paymentChoice: eligibility.paymentChoice,
1138
+ selectedMembershipId: eligibility.selectedMembershipId,
1139
+ claimToken: waitlistClaim.token,
1140
+ hasClaim: waitlistClaim.claim !== null,
1209
1141
  altchaSolution,
1210
- setAltchaSolution,
1211
- showSpamProtection,
1212
- eligibilityLoading,
1213
- eligibilityError,
1214
- courseEligibility,
1215
- eligibleMemberships,
1216
- paymentChoice,
1217
- setPaymentChoice,
1218
- selectedMembershipId,
1219
- setSelectedMembershipId,
1220
- discountUiOpen: discountUi.discountUiOpen,
1221
- setDiscountUiOpen: discountUi.setDiscountUiOpen,
1222
1142
  discountCode: discountUi.discountCode,
1223
- setDiscountCode: discountUi.setDiscountCode,
1224
- discountsAvailable: discountUi.discountsAvailable,
1225
- manualCodeEntryAllowed: discountUi.manualCodeEntryAllowed,
1226
- discountsAvailableLoading: discountUi.discountsAvailableLoading,
1227
- canUseMembership,
1143
+ options
1144
+ }, selection.goToStep);
1145
+ useCourseRegistrationEffects({
1146
+ api,
1147
+ actions,
1148
+ portal,
1149
+ selection,
1150
+ waitlistClaim
1151
+ });
1152
+ return buildCourseRegistrationWizardResult({
1153
+ api,
1154
+ selection,
1155
+ portal,
1156
+ eligibility,
1157
+ actions,
1158
+ discountUi,
1228
1159
  waitlistClaim,
1160
+ view: deriveCourseRegistrationViewState({
1161
+ scopedCourses: selection.scopedCourses,
1162
+ selectedCourse: selection.selectedCourse,
1163
+ pricing: selection.selectedCoursePricing,
1164
+ portalAuthState: portal.portalAuthState,
1165
+ eligibleMembershipCount: eligibility.eligibleMemberships.length,
1166
+ bookingMode,
1167
+ step: selection.step,
1168
+ waitlistRequiresPortalLogin: waitlistClaim.requiresPortalLogin
1169
+ }),
1229
1170
  bookingMode,
1230
- wizardSteps,
1231
- currentStepNumber,
1232
- totalSteps,
1233
- stepLabels,
1234
- showPortalAuthSidebar,
1235
- hasPreSelectedCourse,
1236
- hasCoursePayment,
1237
- handleCourseSelect,
1238
- handleSubmit,
1239
- handlePaymentContinue,
1240
- handleRetry,
1241
- handleBookingModeChange
1171
+ setBookingMode,
1172
+ altchaSolution,
1173
+ setAltchaSolution
1174
+ });
1175
+ }
1176
+ function useCourseRegistrationEffects(input) {
1177
+ useCoursePaymentVerification(input.api, {
1178
+ setStep: input.selection.goToStep,
1179
+ setErrorMessage: input.actions.reportError,
1180
+ setEnrollmentResult: input.actions.recordEnrollmentResult
1181
+ });
1182
+ useCourseWaitlistSelection({
1183
+ waitlistClaim: input.waitlistClaim,
1184
+ scopedCourses: input.selection.scopedCourses,
1185
+ step: input.selection.step,
1186
+ goToStep: input.selection.goToStep,
1187
+ chooseCourse: input.selection.chooseCourse,
1188
+ updateFormData: input.portal.updateFormData,
1189
+ reportError: input.actions.reportError
1190
+ });
1191
+ }
1192
+ function buildCourseRegistrationWizardResult(parts) {
1193
+ const handleBookingModeChange = (mode) => {
1194
+ parts.setBookingMode(mode);
1195
+ parts.eligibility.choosePaymentChoice(mode === "membership" ? "membership" : "checkout");
1196
+ };
1197
+ return {
1198
+ api: parts.api,
1199
+ ...parts.selection,
1200
+ ...parts.portal,
1201
+ ...parts.eligibility,
1202
+ ...parts.actions,
1203
+ waitlistClaim: parts.waitlistClaim,
1204
+ bookingMode: parts.bookingMode,
1205
+ altchaSolution: parts.altchaSolution,
1206
+ setAltchaSolution: parts.setAltchaSolution,
1207
+ showSpamProtection: isSpamProtectionEnabled(),
1208
+ discountUiOpen: parts.discountUi.discountUiOpen,
1209
+ setDiscountUiOpen: parts.discountUi.setDiscountUiOpen,
1210
+ discountCode: parts.discountUi.discountCode,
1211
+ setDiscountCode: parts.discountUi.setDiscountCode,
1212
+ discountsAvailable: parts.discountUi.discountsAvailable,
1213
+ manualCodeEntryAllowed: parts.discountUi.manualCodeEntryAllowed,
1214
+ discountsAvailableLoading: parts.discountUi.discountsAvailableLoading,
1215
+ ...parts.view,
1216
+ handleCourseSelect: (course) => {
1217
+ parts.selection.chooseCourse(course);
1218
+ parts.selection.goToStep("enter-details");
1219
+ },
1220
+ handleRetry: () => {
1221
+ parts.selection.goToStep(parts.selection.scopedCourses.length === 1 ? "enter-details" : "select-course");
1222
+ parts.actions.reportError("");
1223
+ },
1224
+ handleBookingModeChange,
1225
+ handleLogout: parts.portal.portalAuthState === "authenticated" ? () => logoutPortal(COURSE_REGISTRATION_ANCHOR_ID) : void 0,
1226
+ selectedCoursePricingPayload: buildCoursePricingOptionPayload(parts.selection.selectedCoursePricing)
1242
1227
  };
1243
1228
  }
1244
1229
  //#endregion
@@ -1654,7 +1639,7 @@ function getCourseSlidingScaleMessage(pricing) {
1654
1639
  }
1655
1640
  function CourseRegistrationWizard(props) {
1656
1641
  const { showSessions = true, showPrice = true, showCapacity = true, showVenue = true, successMessage = "You're booked in! Check your email for confirmation and session details.", waitlistMessage = "You've been added to the waitlist. We'll email you a claim link if a spot opens up.", membershipMessage = "Booked using your membership! Check your email for session details.", buttonText = "Sign up", buttonVariant = "primary", className } = props;
1657
- const { api, scopedCourses, step, setStep, selectedCourse, selectedPricingOptionId, setSelectedPricingOptionId, selectedSlidingAmountInput, setSelectedSlidingAmountInput, selectedCoursePricing, formData, setFormData, errors, enrollmentResult, errorMessage, portalAuthState, handleLogout, altchaSolution: _altchaSolution, setAltchaSolution, showSpamProtection, eligibilityLoading, eligibilityError, courseEligibility, eligibleMemberships, paymentChoice, setPaymentChoice, selectedMembershipId, setSelectedMembershipId, discountUiOpen, setDiscountUiOpen, discountCode, setDiscountCode, discountsAvailable, manualCodeEntryAllowed, discountsAvailableLoading, waitlistClaim, canUseMembership: _canUseMembership, bookingMode, currentStepNumber, totalSteps, stepLabels, showPortalAuthSidebar, hasPreSelectedCourse: _hasPreSelectedCourse, hasCoursePayment: _hasCoursePayment, handleCourseSelect, handleSubmit, handlePaymentContinue, handleRetry, handleBookingModeChange } = useCourseRegistrationWizard(props);
1642
+ const { api, scopedCourses, step, goToStep, selectedCourse, selectedPricingOptionId, choosePricingOption, selectedSlidingAmountInput, changeSlidingAmount, selectedCoursePricing, formData, updateFormData, errors, enrollmentResult, errorMessage, portalAuthState, handleLogout, altchaSolution: _altchaSolution, setAltchaSolution, showSpamProtection, eligibilityLoading, eligibilityError, courseEligibility, eligibleMemberships, paymentChoice, choosePaymentChoice, selectedMembershipId, chooseMembership, discountUiOpen, setDiscountUiOpen, discountCode, setDiscountCode, discountsAvailable, manualCodeEntryAllowed, discountsAvailableLoading, waitlistClaim, canUseMembership: _canUseMembership, bookingMode, currentStepNumber, totalSteps, stepLabels, showPortalAuthSidebar, hasPreSelectedCourse: _hasPreSelectedCourse, hasCoursePayment: _hasCoursePayment, handleCourseSelect, handleSubmit, handlePaymentContinue, handleRetry, handleBookingModeChange } = useCourseRegistrationWizard(props);
1658
1643
  const buttonClass = themeButtonClassName({
1659
1644
  variant: buttonVariant,
1660
1645
  size: "md"
@@ -1719,13 +1704,13 @@ function CourseRegistrationWizard(props) {
1719
1704
  className: "cr-course-list",
1720
1705
  children: scopedCourses.map((course) => /* @__PURE__ */ jsx(CourseCard, {
1721
1706
  course,
1722
- isSelected: selectedCourse?.id === course.id,
1707
+ isSelected: selectedCourse?.eventSeriesId === course.eventSeriesId,
1723
1708
  onSelect: () => handleCourseSelect(course),
1724
1709
  showSessions,
1725
1710
  showPrice,
1726
1711
  showCapacity,
1727
1712
  showVenue
1728
- }, course.id))
1713
+ }, course.eventSeriesId))
1729
1714
  }),
1730
1715
  step === "enter-details" && selectedCourseWithPricing && /* @__PURE__ */ jsxs("div", {
1731
1716
  className: "cr-details",
@@ -1742,7 +1727,7 @@ function CourseRegistrationWizard(props) {
1742
1727
  className: "cr-actions",
1743
1728
  children: /* @__PURE__ */ jsx("button", {
1744
1729
  type: "button",
1745
- onClick: () => setStep("select-course"),
1730
+ onClick: () => goToStep("select-course"),
1746
1731
  className: "cr-back-btn",
1747
1732
  children: "← Back"
1748
1733
  })
@@ -1761,7 +1746,7 @@ function CourseRegistrationWizard(props) {
1761
1746
  /* @__PURE__ */ jsx(EnrollmentForm, {
1762
1747
  formData,
1763
1748
  errors,
1764
- onChange: setFormData,
1749
+ onChange: updateFormData,
1765
1750
  isEmailLocked: portalAuthState === "authenticated" || waitlistClaim.claim !== null,
1766
1751
  isLoading: portalAuthState === "checking" || waitlistClaim.isLoading,
1767
1752
  onLogout: handleLogout
@@ -1769,12 +1754,12 @@ function CourseRegistrationWizard(props) {
1769
1754
  /* @__PURE__ */ jsx(CoursePricingSelector, {
1770
1755
  pricing: selectedCourseWithPricing.pricing,
1771
1756
  selectedPricingOptionId,
1772
- onSelect: setSelectedPricingOptionId
1757
+ onSelect: choosePricingOption
1773
1758
  }),
1774
1759
  /* @__PURE__ */ jsx(CourseSlidingScaleInput, {
1775
1760
  pricing: selectedCourseWithPricing.pricing,
1776
1761
  value: selectedSlidingAmountInput,
1777
- onChange: setSelectedSlidingAmountInput
1762
+ onChange: changeSlidingAmount
1778
1763
  }),
1779
1764
  showSpamProtection && /* @__PURE__ */ jsx("div", {
1780
1765
  className: "cr-altcha",
@@ -1799,7 +1784,7 @@ function CourseRegistrationWizard(props) {
1799
1784
  className: "cr-actions",
1800
1785
  children: [scopedCourses.length > 1 && /* @__PURE__ */ jsx("button", {
1801
1786
  type: "button",
1802
- onClick: () => setStep("select-course"),
1787
+ onClick: () => goToStep("select-course"),
1803
1788
  className: "cr-back-btn",
1804
1789
  children: "← Back"
1805
1790
  }), /* @__PURE__ */ jsx("button", {
@@ -1849,7 +1834,7 @@ function CourseRegistrationWizard(props) {
1849
1834
  onBookingModeChange: handleBookingModeChange,
1850
1835
  eligibleMemberships,
1851
1836
  selectedMembershipId,
1852
- onMembershipSelect: setSelectedMembershipId,
1837
+ onMembershipSelect: chooseMembership,
1853
1838
  priceCents: selectedCoursePricing?.selectedPriceAmount ?? null,
1854
1839
  currency: selectedCourseWithPricing.course.currency ?? "GBP"
1855
1840
  }),
@@ -1857,7 +1842,7 @@ function CourseRegistrationWizard(props) {
1857
1842
  className: "cr-actions",
1858
1843
  children: [/* @__PURE__ */ jsx("button", {
1859
1844
  type: "button",
1860
- onClick: () => setStep("enter-details"),
1845
+ onClick: () => goToStep("enter-details"),
1861
1846
  className: "cr-back-btn",
1862
1847
  children: "← Back"
1863
1848
  }), /* @__PURE__ */ jsx("button", {
@@ -1896,7 +1881,7 @@ function CourseRegistrationWizard(props) {
1896
1881
  type: "radio",
1897
1882
  name: "paymentChoice",
1898
1883
  checked: paymentChoice === "membership",
1899
- onChange: () => setPaymentChoice("membership")
1884
+ onChange: () => choosePaymentChoice("membership")
1900
1885
  }), /* @__PURE__ */ jsx("span", { children: "Use a membership (free)" })]
1901
1886
  }),
1902
1887
  paymentChoice === "membership" && eligibleMemberships.length > 1 && /* @__PURE__ */ jsxs("div", {
@@ -1909,7 +1894,7 @@ function CourseRegistrationWizard(props) {
1909
1894
  id: "cr-membership",
1910
1895
  className: "cr-form__input",
1911
1896
  value: selectedMembershipId ?? "",
1912
- onChange: (e) => setSelectedMembershipId(e.target.value || null),
1897
+ onChange: (e) => chooseMembership(e.target.value || null),
1913
1898
  children: [/* @__PURE__ */ jsx("option", {
1914
1899
  value: "",
1915
1900
  disabled: true,
@@ -1926,7 +1911,7 @@ function CourseRegistrationWizard(props) {
1926
1911
  type: "radio",
1927
1912
  name: "paymentChoice",
1928
1913
  checked: paymentChoice === "checkout",
1929
- onChange: () => setPaymentChoice("checkout")
1914
+ onChange: () => choosePaymentChoice("checkout")
1930
1915
  }), /* @__PURE__ */ jsx("span", { children: "Pay by card" })]
1931
1916
  })
1932
1917
  ]
@@ -1948,7 +1933,7 @@ function CourseRegistrationWizard(props) {
1948
1933
  className: "cr-actions",
1949
1934
  children: [/* @__PURE__ */ jsx("button", {
1950
1935
  type: "button",
1951
- onClick: () => setStep("enter-details"),
1936
+ onClick: () => goToStep("enter-details"),
1952
1937
  className: "cr-back-btn",
1953
1938
  children: "← Back"
1954
1939
  }), /* @__PURE__ */ jsx("button", {