@riverbankcms/sdk 0.141.0 → 0.143.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 (123) hide show
  1. package/dist/{PreviewEditorSidebar-Q-fy9GYw.mjs → PreviewEditorSidebar-DROGfMKi.mjs} +24 -15
  2. package/dist/{PreviewEditorUI-LYGzgk85.mjs → PreviewEditorUI-BaRjhFu-.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-CN0ewic5.mjs → PreviewQueryProvider-BCYICImX.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-CoPYI5Jq.mjs → SdkPreviewModeRuntime-OIABYLES.mjs} +16 -11
  5. package/dist/{SiteChromeCustomizeContext-D8LePX8x.mjs → SiteChromeCustomizeContext-ohjTvZbc.mjs} +607 -545
  6. package/dist/_dts/api/src/billing.d.ts +6 -1
  7. package/dist/_dts/api/src/bookingConfig.d.ts +1 -1
  8. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +2 -2
  9. package/dist/_dts/api/src/endpoints.d.ts +7 -27
  10. package/dist/_dts/api/src/index.d.ts +1 -1
  11. package/dist/_dts/api/src/publicBookingService.d.ts +1 -0
  12. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  13. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +48 -41
  14. package/dist/_dts/api/src/sdkConfig/layout.d.ts +13 -0
  15. package/dist/_dts/api/src/sdkContracts.d.ts +3 -8
  16. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -31
  17. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +6 -1
  18. package/dist/_dts/billing/src/site-arrangements.d.ts +9 -5
  19. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +56 -0
  20. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +8 -0
  21. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  22. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  23. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +95 -35
  24. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.d.ts +10 -0
  25. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +0 -2
  26. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +12 -1
  27. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +2 -2
  28. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +1 -4
  29. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +12 -0
  30. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -1
  31. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +1 -0
  32. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.d.ts +4 -5
  33. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +9 -11
  34. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +56 -2
  35. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +10 -4
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +23 -0
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +1 -1
  38. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +56 -0
  39. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -4
  40. package/dist/_dts/commerce/src/purchase/eventCheckoutRecoveryWindow.d.ts +8 -0
  41. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -1
  42. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +1 -13
  43. package/dist/_dts/commerce/src/purchase/stripeCommissionMetadata.d.ts +1 -2
  44. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +58 -45
  45. package/dist/_dts/editor-blocks/src/block-editor/ColourFieldOptionsProvider.d.ts +7 -0
  46. package/dist/_dts/editor-blocks/src/block-editor/colourFieldVisibility.d.ts +7 -0
  47. package/dist/_dts/editor-blocks/src/block-editor/preparedManifest.d.ts +2 -0
  48. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  49. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -2
  50. package/dist/_dts/preview-next/src/client/preview/PreviewFooterEditorPanel.d.ts +3 -6
  51. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +2 -2
  52. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +2 -2
  53. package/dist/_dts/preview-next/src/client/preview/footerInspection.d.ts +16 -0
  54. package/dist/_dts/preview-next/src/client/preview/sdkConfig.d.ts +6 -0
  55. package/dist/_dts/sdk/src/config/types.d.ts +2 -18
  56. package/dist/_dts/sdk/src/config/validation.d.ts +6 -0
  57. package/dist/_dts/sdk/src/public-api/contracts.d.ts +3 -0
  58. package/dist/_dts/sdk/src/version.d.ts +1 -1
  59. package/dist/_dts/theme-core/src/footer/mode.d.ts +10 -1
  60. package/dist/_dts/theme-core/src/schema.d.ts +1 -7
  61. package/dist/_dts/theme-core/src/site-styles/effectivePageDesign.d.ts +32 -0
  62. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  63. package/dist/client/{BookingConsentAgreement-xJeYNdnb.mjs → BookingConsentAgreement-BoCtvzzu.mjs} +2 -2
  64. package/dist/client/{DiscountCodeDisclosure-DdT6uzl9.mjs → DiscountCodeDisclosure-B5S30nZk.mjs} +1 -1
  65. package/dist/client/{EventCombined.client-Cp28uYuM.mjs → EventCombined.client-CeZ2-zSt.mjs} +5 -5
  66. package/dist/client/{EventListing.client-CD6AJsMr.mjs → EventListing.client-DJN3j8B3.mjs} +2 -2
  67. package/dist/client/{LeafletStaticMap-DBsAi9-e.mjs → LeafletStaticMap-RjtGzDQT.mjs} +1 -1
  68. package/dist/client/{accordion-6dwbOKYR.mjs → accordion-DOmnDoyg.mjs} +1 -1
  69. package/dist/client/{bookingForm-CZE9_qPQ.mjs → bookingForm-C0vk7pgS.mjs} +5 -5
  70. package/dist/client/bookings.mjs +468 -534
  71. package/dist/client/{carousel-7VHGQARz.mjs → carousel-BZJ7pno3.mjs} +1 -1
  72. package/dist/client/{cart-Qg_mvQhh.mjs → cart-CaeVAHJl.mjs} +3 -3
  73. package/dist/client/{checkout-D84rpgdr.mjs → checkout-7wmoNDtG.mjs} +3 -3
  74. package/dist/client/client.mjs +559 -593
  75. package/dist/client/{context-Ctp3T0Wr.mjs → context-BOimxE3U.mjs} +12 -1
  76. package/dist/client/{dates-DJKFcI_N.mjs → dates-BnzVksi4.mjs} +2 -2
  77. package/dist/client/{eventCalendar-CK31z3vs.mjs → eventCalendar-l-fpaslC.mjs} +7 -7
  78. package/dist/client/{eventCombined-DiXd-ewn.mjs → eventCombined-DGGvssK6.mjs} +3 -3
  79. package/dist/client/{eventDetails-CTRgt2DK.mjs → eventDetails-DRiCm_hL.mjs} +4 -4
  80. package/dist/client/{eventListing-Dy9vi_j_.mjs → eventListing-dph8loYX.mjs} +3 -3
  81. package/dist/client/{eventRegistration-CnalYMr2.mjs → eventRegistration-ClBohmbY.mjs} +472 -531
  82. package/dist/client/{form-eUiMveTT.mjs → form-BLVVAnd3.mjs} +2 -2
  83. package/dist/client/{headerSection-Dy9kQpB1.mjs → headerSection-DHy4C8Ix.mjs} +2 -2
  84. package/dist/client/hooks.mjs +39 -13
  85. package/dist/client/{locationMap-DalCmWU0.mjs → locationMap-6HuS28ck.mjs} +2 -2
  86. package/dist/client/{newsletterForm-SDDPvhS0.mjs → newsletterForm-xOdcOhZP.mjs} +2 -2
  87. package/dist/client/{pricing-OcMz4SnX.mjs → pricing-ChinRYFt.mjs} +1 -1
  88. package/dist/client/{productDetail-BQrgHElM.mjs → productDetail-0chA5gbK.mjs} +3 -3
  89. package/dist/client/{productList-OnPn_UJj.mjs → productList-OoINA0h1.mjs} +3 -3
  90. package/dist/client/{propsDecoder-zBdsnS-N.mjs → propsDecoder-CIZ-hbIG.mjs} +33 -9
  91. package/dist/client/rendering/client.mjs +536 -550
  92. package/dist/client/rendering/islands.mjs +17 -17
  93. package/dist/client/rendering.mjs +602 -596
  94. package/dist/client/{scrollToBlock-BNM4Ob2Y.mjs → scrollToBlock-BPZl0gPZ.mjs} +1 -1
  95. package/dist/client/{shop-Bv1fPTwQ.mjs → shop-CLJFqNIq.mjs} +6 -6
  96. package/dist/client/{shop-commerce-D4KNGaW8.mjs → shop-commerce-PpANg5wB.mjs} +5 -5
  97. package/dist/client/{shop-commerce-store-2N5EV0Rc.mjs → shop-commerce-store-TA_Kz2ku.mjs} +1 -1
  98. package/dist/client/{shopShared-DvJGdHTV.mjs → shopShared-DzcFcA5g.mjs} +3 -3
  99. package/dist/client/{useEventFilters-BBBvGDHQ.mjs → useEventFilters-CFU21QZo.mjs} +5 -5
  100. package/dist/preview-next/before-render.mjs +11 -37
  101. package/dist/preview-next/client/runtime.mjs +4 -4
  102. package/dist/preview-next/keepAlive.mjs +11 -37
  103. package/dist/preview-next/middleware.mjs +11 -37
  104. package/dist/{previewAuthStore-Gjb6r6vz.mjs → previewAuthStore-JA6-I_sL.mjs} +11 -37
  105. package/dist/{sdk-runtime-Defnbfzw.mjs → sdk-runtime-CDKl0Fr7.mjs} +2 -2
  106. package/dist/{separator-CZXO3Sb0.mjs → separator-BTp96X32.mjs} +1 -1
  107. package/dist/server/components.mjs +80 -51
  108. package/dist/server/config-validation.mjs +43 -14
  109. package/dist/server/config.mjs +43 -14
  110. package/dist/server/data.mjs +39 -13
  111. package/dist/server/index.mjs +12 -38
  112. package/dist/server/next.mjs +40 -53
  113. package/dist/server/page-converter.mjs +20 -8
  114. package/dist/server/prebuild.mjs +1 -1
  115. package/dist/server/rendering/server.mjs +80 -51
  116. package/dist/server/rendering.mjs +80 -51
  117. package/dist/server/routing.mjs +52 -17
  118. package/dist/server/server.mjs +40 -51
  119. package/dist/server/theme-bridge.mjs +10 -8
  120. package/dist/server/theme.mjs +10 -8
  121. package/package.json +1 -1
  122. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +0 -14
  123. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +0 -8
@@ -3571,7 +3571,10 @@ var init_contentMediaSnapshotAudit = __esmMin((() => {
3571
3571
  init_contentMediaAudit();
3572
3572
  init_contentMediaAuditFieldAdapter();
3573
3573
  init_identifiers();
3574
- })), init_src$1 = __esmMin((() => {
3574
+ }));
3575
+ //#endregion
3576
+ //#region ../media-core/src/index.ts
3577
+ var init_src$1 = __esmMin((() => {
3575
3578
  init_types$15();
3576
3579
  init_fileDomain();
3577
3580
  init_fileStorage();
@@ -3622,6 +3625,56 @@ var init_contentMediaSnapshotAudit = __esmMin((() => {
3622
3625
  init_contentMediaAudit();
3623
3626
  init_contentMediaAuditFieldAdapter();
3624
3627
  init_contentMediaSnapshotAudit();
3628
+ }));
3629
+ //#endregion
3630
+ //#region ../theme-core/src/footer/mode.ts
3631
+ /** Reads only SDK footer intent; unrelated config and theme fields are not authorities. */
3632
+ function resolveSdkFooterMode(config) {
3633
+ const parsed = z$1.object({ layout: z$1.object({ footerMode: footerModeSchema.optional() }).optional() }).safeParse(config);
3634
+ return parsed.success ? parsed.data.layout?.footerMode ?? "default" : "default";
3635
+ }
3636
+ /**
3637
+ * Resolve what to render for the footer given the current mode and whether the
3638
+ * site is SDK-managed.
3639
+ *
3640
+ * Backwards compatible: missing/undefined mode is treated as 'default'.
3641
+ */
3642
+ function resolveFooterRenderPlan(params) {
3643
+ if (!params.isSdkSite) return {
3644
+ mode: "default",
3645
+ renderDefaultFooter: true,
3646
+ renderFooterBlocks: false
3647
+ };
3648
+ switch (params.mode ?? "default") {
3649
+ case "blocks": return {
3650
+ mode: "blocks",
3651
+ renderDefaultFooter: false,
3652
+ renderFooterBlocks: true
3653
+ };
3654
+ case "default+blocks": return {
3655
+ mode: "default+blocks",
3656
+ renderDefaultFooter: true,
3657
+ renderFooterBlocks: true
3658
+ };
3659
+ case "none": return {
3660
+ mode: "none",
3661
+ renderDefaultFooter: false,
3662
+ renderFooterBlocks: false
3663
+ };
3664
+ default: return {
3665
+ mode: "default",
3666
+ renderDefaultFooter: true,
3667
+ renderFooterBlocks: false
3668
+ };
3669
+ }
3670
+ }
3671
+ var footerModeSchema, init_mode = __esmMin((() => {
3672
+ footerModeSchema = z$1.enum([
3673
+ "default",
3674
+ "blocks",
3675
+ "default+blocks",
3676
+ "none"
3677
+ ]);
3625
3678
  })), hotspotSchema, rotationSchema, rectSchema, aspectCropSchema, transformSchema, mediaPosterSchema, mediaBaseSchema, mediaIdentifierSchema, imageMediaSchema, videoMediaSchema, audioMediaSchema, documentMediaSchema, spreadsheetMediaSchema, archiveMediaSchema, mediaSchema, persistableMediaBaseSchema;
3626
3679
  var init_media$2 = __esmMin((() => {
3627
3680
  hotspotSchema = z$1.object({
@@ -12487,8 +12540,9 @@ var init_boxBackgroundSchema = __esmMin((() => {
12487
12540
  showVideoOnMobile: z$1.boolean().nullable().optional()
12488
12541
  })
12489
12542
  ]);
12490
- })), axesSchema, typographyStyleSchema, bodyTypographyStyleSchema, headingSizeSchema, headingTypographyOverridesSchema, headingTypographyStyleSchema, proseLinkUnderlineStyleSchema, proseLinkUnderlineThicknessSchema, proseLinkUnderlineOffsetSchema, proseLinkStyleSchema, semanticSpacingSchema, boxRoundedSchema, noHeadingDecorationSchema, visibleHeadingDecorationSchema, headingDecorationSchema, headingDecorationOverrideSchema, accordionIconTreatmentSchema, sectionStylesOverrideSchema, containerStylesOverrideSchema, cardBorderOverrideSchema, cardStylesOverrideSchema, blockStyleOverridesSchema, blockThemeOverrideSchema, typographyScaleSchema, eyebrowTypographyStyleSchema, typographySchema, spaceSchema, corners, shadow, border, motion, inputStyle, headerPositioningValues, headerPositioning, headerNavStyle, navFontWeight, headerMaxWidth, headerBorderSchema, logoStyleSchema, headerLogoTextSchema, dropdownStyleSchema, headerCtaGapSchema, headerCtaTreatmentSchema, navContainerSchema, headerBackgroundSchema, headerSchema, footerVariant, footerMaxWidth, footerMode, footerNavLayoutMode, footerNavLayoutAlign, footerSpacing, footerLogoPlacement, footerLogoSize, footerLogoMaxHeight, footerBottomTextLinkStyleSchema, footerBottomBarSchema, footerNavLayoutSchema, footerLogoSchema, footerSchema, containerPaddingPresetSchema, layoutSchema, heroTypographySizeSchema, heroTypographyLineHeightSchema, heroResponsiveTypographySchema, heroTypographySchema, heroSchema, bodyTextIntroTypographySizeSchema, bodyTextSchema, testimonialQuoteTreatmentSchema, themeSchema;
12543
+ })), axesSchema, typographyStyleSchema, bodyTypographyStyleSchema, headingSizeSchema, headingTypographyOverridesSchema, headingTypographyStyleSchema, proseLinkUnderlineStyleSchema, proseLinkUnderlineThicknessSchema, proseLinkUnderlineOffsetSchema, proseLinkStyleSchema, semanticSpacingSchema, boxRoundedSchema, noHeadingDecorationSchema, visibleHeadingDecorationSchema, headingDecorationSchema, headingDecorationOverrideSchema, accordionIconTreatmentSchema, sectionStylesOverrideSchema, containerStylesOverrideSchema, cardBorderOverrideSchema, cardStylesOverrideSchema, blockStyleOverridesSchema, blockThemeOverrideSchema, typographyScaleSchema, eyebrowTypographyStyleSchema, typographySchema, spaceSchema, corners, shadow, border, motion, inputStyle, headerPositioningValues, headerPositioning, headerNavStyle, navFontWeight, headerMaxWidth, headerBorderSchema, logoStyleSchema, headerLogoTextSchema, dropdownStyleSchema, headerCtaGapSchema, headerCtaTreatmentSchema, navContainerSchema, headerBackgroundSchema, headerSchema, footerVariant, footerMaxWidth, footerNavLayoutMode, footerNavLayoutAlign, footerSpacing, footerLogoPlacement, footerLogoSize, footerLogoMaxHeight, footerBottomTextLinkStyleSchema, footerBottomBarSchema, footerNavLayoutSchema, footerLogoSchema, footerSchema, containerPaddingPresetSchema, layoutSchema, heroTypographySizeSchema, heroTypographyLineHeightSchema, heroResponsiveTypographySchema, heroTypographySchema, heroSchema, bodyTextIntroTypographySizeSchema, bodyTextSchema, testimonialQuoteTreatmentSchema, themeSchema;
12491
12544
  var init_schema$2 = __esmMin((() => {
12545
+ init_mode();
12492
12546
  init_media$2();
12493
12547
  init_schema$3();
12494
12548
  init_buttons();
@@ -12987,12 +13041,6 @@ var init_schema$2 = __esmMin((() => {
12987
13041
  "split"
12988
13042
  ]);
12989
13043
  footerMaxWidth = z$1.enum(["container", "full"]);
12990
- footerMode = z$1.enum([
12991
- "default",
12992
- "blocks",
12993
- "default+blocks",
12994
- "none"
12995
- ]);
12996
13044
  footerNavLayoutMode = z$1.enum([
12997
13045
  "stack",
12998
13046
  "inline",
@@ -13081,9 +13129,9 @@ var init_schema$2 = __esmMin((() => {
13081
13129
  /**
13082
13130
  * SDK-only footer rendering mode.
13083
13131
  *
13084
- * Backwards compatible: missing/undefined behaves as 'default'.
13132
+ * Historical persisted field; SDK rendering mode now lives in layout.footerMode.
13085
13133
  */
13086
- mode: footerMode.optional(),
13134
+ mode: footerModeSchema.optional(),
13087
13135
  variant: footerVariant,
13088
13136
  maxWidth: footerMaxWidth,
13089
13137
  showLogoText: z$1.boolean().optional(),
@@ -13698,6 +13746,15 @@ var init_schemas = __esmMin((() => {
13698
13746
  timeZone: z$1.string(),
13699
13747
  pricing: publicEventPricingSchema,
13700
13748
  paymentTerms: blockBookingPaymentTermsSchema,
13749
+ cancellationPolicy: z$1.object({ refunds: z$1.object({
13750
+ mode: z$1.enum([
13751
+ "never",
13752
+ "always",
13753
+ "cutoff"
13754
+ ]),
13755
+ cutoffHours: z$1.number(),
13756
+ method: z$1.enum(["original_payment_method", "site_credit"])
13757
+ }) }),
13701
13758
  consent: blockBookingConsentSchema.nullable(),
13702
13759
  accessRestriction: accessRestrictionSchema,
13703
13760
  allowedCategoryIds: z$1.array(z$1.string()),
@@ -21482,6 +21539,10 @@ var init_headerOpeningForeground = __esmMin((() => {
21482
21539
  init_colorTokenParts();
21483
21540
  init_types$8();
21484
21541
  }));
21542
+ var init_effectivePageDesign = __esmMin((() => {
21543
+ init_pageDesignIntent();
21544
+ init_siteStyleBlockPolicies();
21545
+ }));
21485
21546
  function validateBlockSequence(snapshots, ctx) {
21486
21547
  for (const issue of collectBlockSequenceIssues(snapshots)) ctx.addIssue(issue);
21487
21548
  }
@@ -21758,6 +21819,7 @@ var init_site_styles = __esmMin((() => {
21758
21819
  init_lookResolution();
21759
21820
  init_lookOptionGroups();
21760
21821
  init_logoBranding();
21822
+ init_effectivePageDesign();
21761
21823
  init_pageDesignAuthority();
21762
21824
  init_pageDesignEditorErrors();
21763
21825
  init_pageDesignEditorCapabilities();
@@ -32689,6 +32751,18 @@ var init_wizardSteps$1 = __esmMin((() => {
32689
32751
  }));
32690
32752
  //#endregion
32691
32753
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
32754
+ /** Public requests share subject identity without copying the run's display sessions. */
32755
+ function toRegistrationRequestSubject(subject, attendanceMode) {
32756
+ return subject.kind === "occurrence" ? {
32757
+ kind: "occurrence",
32758
+ occurrenceId: subject.occurrenceId,
32759
+ attendanceMode: attendanceMode ?? void 0
32760
+ } : {
32761
+ kind: "wholeSeries",
32762
+ eventSeriesId: subject.eventSeriesId,
32763
+ attendanceMode: attendanceMode ?? void 0
32764
+ };
32765
+ }
32692
32766
  function eventMatchesOccurrenceId(event, occurrenceId) {
32693
32767
  return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
32694
32768
  }
@@ -32918,6 +32992,7 @@ function shellLabelForRegistrationStep(step, events) {
32918
32992
  case "redirecting":
32919
32993
  case "verifying-payment":
32920
32994
  case "verifying-timeout":
32995
+ case "payment-status":
32921
32996
  case "payment-failed": return "Details";
32922
32997
  }
32923
32998
  }
@@ -92409,6 +92484,10 @@ var init_endpoints = __esmMin((() => {
92409
92484
  method: "POST",
92410
92485
  authScope: "portal"
92411
92486
  },
92487
+ registrationNextStep: {
92488
+ path: "/public/sites/{siteId}/events/registration-next-step",
92489
+ method: "POST"
92490
+ },
92412
92491
  registrationStatus: {
92413
92492
  path: "/public/sites/{siteId}/events/registration-status",
92414
92493
  method: "GET"
@@ -92991,6 +93070,13 @@ function createBlockApi(config) {
92991
93070
  body: data
92992
93071
  });
92993
93072
  },
93073
+ async checkRegistrationNextStep(data) {
93074
+ const path = buildPath(EVENTS.registrationNextStep.path, { siteId: requireSiteId() });
93075
+ return request(EVENTS.registrationNextStep, {
93076
+ path,
93077
+ body: data
93078
+ });
93079
+ },
92994
93080
  async getEventRegistrationStatus(params) {
92995
93081
  const sid = requireSiteId();
92996
93082
  const path = buildPath(EVENTS.registrationStatus.path, { siteId: sid });
@@ -101155,7 +101241,7 @@ var init_eventPaymentOptions = __esmMin((() => {
101155
101241
  //#endregion
101156
101242
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
101157
101243
  function hasBlockingExistingRegistration(input) {
101158
- return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind !== "none";
101244
+ return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
101159
101245
  }
101160
101246
  function createInitialRegistrationFlowState(hasPreSelectedContext) {
101161
101247
  return {
@@ -101207,7 +101293,7 @@ function computeAutoSelection(input) {
101207
101293
  return { method: null };
101208
101294
  }
101209
101295
  function computeDirectPaymentSelection(eligibility) {
101210
- if (!eligibility?.canPayDirectly) return { method: null };
101296
+ if (!eligibility?.requiresPayment) return { method: null };
101211
101297
  const approvedKinds = getApprovedDirectPaymentCollectionOptionKinds(eligibility.paymentOptions);
101212
101298
  const collectionOptionKind = approvedKinds.includes("upfront") ? "upfront" : approvedKinds[0];
101213
101299
  return collectionOptionKind ? {
@@ -101221,7 +101307,7 @@ function isSelectionValid(input) {
101221
101307
  if (!eligibility) return selection.method === "stripe" || selection.method === "pass_bundle" || selection.method === "membership_bundle";
101222
101308
  switch (selection.method) {
101223
101309
  case "free": return eligibility.isFree;
101224
- case "stripe": return Boolean(eligibility.canPayDirectly && eligibility.price);
101310
+ case "stripe": return Boolean(eligibility.requiresPayment && eligibility.price);
101225
101311
  case "pass": return isAuthenticated && ticketsCount === 1 && !!selection.passId && eligibility.eligiblePasses.some((pass) => pass.id === selection.passId);
101226
101312
  case "membership": return isAuthenticated && ticketsCount === 1 && !!selection.membershipId && eligibility.eligibleMemberships.some((membership) => membership.id === selection.membershipId);
101227
101313
  case "pass_bundle": return ticketsCount === 1 && !!selection.bundlePassId && eligibility.availablePasses.some((pass) => pass.id === selection.bundlePassId);
@@ -101240,7 +101326,7 @@ function normalizeRegistrationFlowState(state) {
101240
101326
  ticketsCount: state.ticketsCount,
101241
101327
  passOptOut: nextPassOptOut
101242
101328
  });
101243
- const canKeepManualSelection = state.step === "select-payment" && state.selectionSource === "manual" && isSelectionValid({
101329
+ const canKeepManualSelection = state.step !== "select-tickets" && state.selectionSource === "manual" && isSelectionValid({
101244
101330
  selection: state.paymentSelection,
101245
101331
  isAuthenticated: state.isAuthenticated,
101246
101332
  eligibility: state.eligibility,
@@ -101332,7 +101418,7 @@ function resolveEventRegistrationSubmitPlan(input) {
101332
101418
  const selection = input.paymentSelection.method ? input.paymentSelection : void 0;
101333
101419
  if (input.canJoinWaitlist) return {
101334
101420
  ok: true,
101335
- args: withOptionalSelection({ method: "free" }, selection)
101421
+ args: { method: "free" }
101336
101422
  };
101337
101423
  switch (input.paymentSelection.method) {
101338
101424
  case "pass": return input.paymentSelection.passId ? {
@@ -101401,92 +101487,55 @@ var init_event_registration_headless_state = __esmMin((() => {
101401
101487
  init_event_registration_headless_planning();
101402
101488
  }));
101403
101489
  //#endregion
101404
- //#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
101405
- /** Recovery may select held places; checkout still owns admission and payment validation. */
101406
- function checkoutRecoveryOptionAvailability(availability) {
101407
- if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
101408
- kind: "available",
101409
- remainingPlaces: null
101410
- };
101411
- return availability;
101490
+ //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
101491
+ /** Ticket selection requests a quote; only the server admits a booking. */
101492
+ function canRequestTicketOption(availability) {
101493
+ return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
101412
101494
  }
101413
- /**
101414
- * A form-only projection for the explicit existing-checkout path. It permits
101415
- * collecting the original selection without claiming a new place is available.
101416
- * The public checkout service identifies the customer and remains the admission
101417
- * authority; no reservation/customer data is exposed through this projection.
101418
- */
101419
- function getCheckoutRecoveryFormEligibility(eligibility) {
101420
- if (!eligibility || eligibility.registration.kind !== "none" && eligibility.registration.kind !== "pending_payment" || eligibility.availability.kind === "unavailable" && eligibility.availability.reason !== "full" && eligibility.availability.reason !== "selectionRequired") return eligibility;
101421
- const amountCents = eligibility.price ?? 0;
101422
- if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
101423
- ...eligibility,
101424
- registration: { kind: "none" },
101425
- ticketTypes: eligibility.ticketTypes.map((option) => ({
101426
- ...option,
101427
- availability: checkoutRecoveryOptionAvailability(option.availability)
101428
- }))
101429
- } : eligibility;
101430
- const currency = eligibility.currency;
101431
- const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
101432
- switch (option.kind) {
101433
- case "upfront": return {
101434
- kind: "payInFull",
101435
- amountCents,
101436
- currency
101437
- };
101438
- case "deferred_manual": return {
101439
- kind: "deferredManual",
101440
- amountCents,
101441
- currency
101442
- };
101443
- case "instalment_plan": return {
101444
- kind: "instalmentPlan",
101445
- amountCents,
101446
- currency
101447
- };
101448
- case "flexible_balance": return {
101449
- kind: "flexibleBalance",
101450
- amountCents,
101451
- currency
101452
- };
101453
- }
101454
- });
101455
- return {
101456
- ...eligibility,
101457
- registration: { kind: "none" },
101458
- availability: {
101459
- kind: "available",
101460
- remainingPlaces: null,
101461
- waitlistEnabled: eligibility.waitlistEnabled
101462
- },
101463
- eligible: paymentOptions.length > 0,
101464
- isFull: false,
101465
- canJoinWaitlist: false,
101466
- isFree: false,
101467
- requiresPayment: true,
101468
- canPayDirectly: paymentOptions.length > 0,
101469
- paymentOptions,
101470
- eligiblePasses: [],
101471
- eligibleMemberships: [],
101472
- ticketTypes: eligibility.ticketTypes.map((option) => ({
101473
- ...option,
101474
- availability: checkoutRecoveryOptionAvailability(option.availability)
101475
- }))
101476
- };
101495
+ function normalizeTicketSelectionLines(lines) {
101496
+ const quantitiesByTicketType = /* @__PURE__ */ new Map();
101497
+ for (const line of lines) {
101498
+ const quantity = Math.floor(line.quantity);
101499
+ if (quantity <= 0) continue;
101500
+ const key = line.pricingOptionId ?? null;
101501
+ quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
101502
+ }
101503
+ return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
101504
+ pricingOptionId,
101505
+ quantity
101506
+ }));
101477
101507
  }
101478
- function isSoldOutEventSelectable(event, waitlistAvailable) {
101479
- return waitlistAvailable || canRecoverEventCheckout(event);
101508
+ function getTicketSelectionTotal(lines) {
101509
+ return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
101510
+ }
101511
+ function getTicketLineQuantity(lines, pricingOptionId) {
101512
+ return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
101480
101513
  }
101481
- function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
101482
- return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
101514
+ function getSingleSelectedPricingOptionId(lines) {
101515
+ const normalized = normalizeTicketSelectionLines(lines);
101516
+ return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
101483
101517
  }
101484
- function canRecoverEventCheckout(event) {
101485
- return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
101518
+ function hasValidPricingOptionSelection(input) {
101519
+ if (!input.selectionRequired) return true;
101520
+ if (input.lines.length === 0) return false;
101521
+ const availableOptionIds = new Set(input.visibleOptions.filter((option) => canRequestTicketOption(option.availability)).map((option) => option.pricingOptionId));
101522
+ return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
101486
101523
  }
101487
- var init_checkoutRecovery = __esmMin((() => {
101488
- init_domain();
101489
- }));
101524
+ function setTicketLineQuantity(input) {
101525
+ const nextQuantity = Math.max(0, Math.floor(input.quantity));
101526
+ const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
101527
+ if (nextQuantity <= 0) return normalized;
101528
+ return [...normalized, {
101529
+ pricingOptionId: input.pricingOptionId,
101530
+ quantity: nextQuantity
101531
+ }];
101532
+ }
101533
+ function getTicketTypeLineMax(input) {
101534
+ const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
101535
+ const maxByBlock = input.maxTickets - otherSelectedQuantity;
101536
+ return Math.max(0, maxByBlock);
101537
+ }
101538
+ var init_ticketSelectionLines = __esmMin((() => {}));
101490
101539
  //#endregion
101491
101540
  //#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
101492
101541
  function getPortalSubjectEmail(profile) {
@@ -101550,8 +101599,6 @@ function formatPassCreditUsageLabel(creditsRemaining) {
101550
101599
  return `Uses 1 of ${creditsRemaining} credits`;
101551
101600
  }
101552
101601
  function transformRegistrationOptionsResponse(response) {
101553
- const canJoinWaitlist = response.availability.kind === "waitlist";
101554
- const isFull = response.availability.remainingPlaces === 0 || response.availability.kind === "unavailable" && response.availability.reason === "full";
101555
101602
  const eligiblePasses = response.entitlements.passes.map((pass) => ({
101556
101603
  id: pass.customerPassId,
101557
101604
  passName: pass.passName,
@@ -101564,7 +101611,6 @@ function transformRegistrationOptionsResponse(response) {
101564
101611
  const eventAcceptsPasses = response.entitlements.requiresLoginForPasses || eligiblePasses.length > 0 || response.entitlements.availableForPurchase.passes.length > 0;
101565
101612
  const eventAcceptsMemberships = response.entitlements.requiresLoginForMemberships || eligibleMemberships.length > 0 || response.entitlements.availableForPurchase.memberships.length > 0;
101566
101613
  const monetaryPaymentAvailable = hasMonetaryPaymentOption(response);
101567
- const registrationAvailable = response.availability.kind === "available" || response.availability.kind === "waitlist";
101568
101614
  return {
101569
101615
  availability: response.availability,
101570
101616
  registration: response.registration,
@@ -101579,7 +101625,6 @@ function transformRegistrationOptionsResponse(response) {
101579
101625
  },
101580
101626
  transactions: []
101581
101627
  } : null,
101582
- eligible: response.registration.kind === "none" && registrationAvailable,
101583
101628
  requiresPayment: monetaryPaymentAvailable,
101584
101629
  pricingStrategy: response.pricing.strategy,
101585
101630
  paymentTerms: response.pricing.paymentTerms,
@@ -101594,16 +101639,12 @@ function transformRegistrationOptionsResponse(response) {
101594
101639
  currency: response.pricing.currency
101595
101640
  })),
101596
101641
  ticketTypes: response.pricing.options,
101597
- isFull,
101598
- waitlistEnabled: response.availability.waitlistEnabled,
101599
- canJoinWaitlist,
101600
101642
  price: response.pricing.subtotalCents,
101601
101643
  currency: response.pricing.currency,
101602
101644
  requiresAuthForPasses: response.entitlements.requiresLoginForPasses,
101603
101645
  requiresAuthForMemberships: response.entitlements.requiresLoginForMemberships,
101604
101646
  eligiblePasses,
101605
101647
  eligibleMemberships,
101606
- canPayDirectly: monetaryPaymentAvailable,
101607
101648
  eventAcceptsPasses,
101608
101649
  eventAcceptsMemberships,
101609
101650
  availablePasses: [...response.entitlements.availableForPurchase.passes],
@@ -101633,8 +101674,8 @@ function getVisibleTicketTypes(input) {
101633
101674
  })) : [];
101634
101675
  return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
101635
101676
  }
101636
- function getImplicitSingleAvailableTicketType(ticketTypes) {
101637
- return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
101677
+ function getImplicitSingleTicketType(ticketTypes) {
101678
+ return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability) ? ticketTypes[0] : null;
101638
101679
  }
101639
101680
  function findSelectedTicketType(input) {
101640
101681
  if (!input.selectedPricingOptionId) return null;
@@ -101647,6 +101688,7 @@ function findSelectedTicketType(input) {
101647
101688
  var ENTITLEMENT_SINGLE_TICKET_TOOLTIP;
101648
101689
  var init_utils = __esmMin((() => {
101649
101690
  init_src$2();
101691
+ init_ticketSelectionLines();
101650
101692
  init_shared();
101651
101693
  ENTITLEMENT_SINGLE_TICKET_TOOLTIP = "Only available for single-ticket bookings";
101652
101694
  }));
@@ -101659,7 +101701,6 @@ function getEventSelectionMode(events) {
101659
101701
  }
101660
101702
  var EventSelectionStep;
101661
101703
  var init_EventSelectionStep = __esmMin((() => {
101662
- init_checkoutRecovery();
101663
101704
  init_utils();
101664
101705
  init_domain();
101665
101706
  EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCapacity }) => {
@@ -101676,25 +101717,19 @@ var init_EventSelectionStep = __esmMin((() => {
101676
101717
  const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
101677
101718
  const isSoldOut = isEventFull(event);
101678
101719
  const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
101679
- const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
101680
101720
  const isLowCapacity = remaining.kind === "low";
101681
101721
  const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
101682
101722
  const timeZone = event.timeZone ?? null;
101683
- const cardClasses = [
101684
- "er-event-card",
101685
- isSelected && "er-event-card--selected",
101686
- isUnavailable && "er-event-card--disabled"
101687
- ].filter(Boolean).join(" ");
101723
+ const cardClasses = ["er-event-card", isSelected && "er-event-card--selected"].filter(Boolean).join(" ");
101688
101724
  const badgeClasses = [
101689
101725
  "er-capacity-badge",
101690
- isUnavailable && "er-capacity-badge--soldout",
101726
+ isSoldOut && "er-capacity-badge--soldout",
101691
101727
  isLowCapacity && "er-capacity-badge--low",
101692
- (canJoinWaitlist || !isUnavailable && !isLowCapacity) && "er-capacity-badge--available"
101728
+ (canJoinWaitlist || !isSoldOut && !isLowCapacity) && "er-capacity-badge--available"
101693
101729
  ].filter(Boolean).join(" ");
101694
101730
  return /* @__PURE__ */ jsx("button", {
101695
101731
  type: "button",
101696
- onClick: () => !isUnavailable && onSelect(event),
101697
- disabled: isUnavailable,
101732
+ onClick: () => onSelect(event),
101698
101733
  className: cardClasses,
101699
101734
  children: /* @__PURE__ */ jsxs("div", {
101700
101735
  className: "er-event-option",
@@ -101722,44 +101757,15 @@ var init_EventSelectionStep = __esmMin((() => {
101722
101757
  };
101723
101758
  }));
101724
101759
  //#endregion
101725
- //#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
101726
- /** Recovery belongs to the selected booking subject; changing events resets its scope. */
101727
- function useCheckoutRecovery(event, setStep) {
101728
- const [recoveryEventId, setRecoveryEventId] = useState(null);
101729
- return {
101730
- checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
101731
- startCheckoutRecovery: useCallback(() => {
101732
- if (!event) return;
101733
- setRecoveryEventId(event.selectionId);
101734
- setStep("select-tickets");
101735
- }, [event, setStep])
101736
- };
101737
- }
101738
- /** Authenticated pending bookings enter the same form-only recovery path as guests. */
101739
- function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
101740
- const registrationKind = eligibility?.registration.kind;
101741
- useEffect(() => {
101742
- if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
101743
- }, [
101744
- registrationKind,
101745
- step,
101746
- checkoutRecovery,
101747
- startCheckoutRecovery
101748
- ]);
101749
- return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
101750
- }
101751
- var init_useCheckoutRecovery = __esmMin((() => {
101752
- init_checkoutRecovery();
101753
- }));
101754
- //#endregion
101755
101760
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
101756
101761
  function resolveRegistrationRecoveryAction(step, action) {
101757
101762
  if (step === "payment-failed") return "payment-options";
101758
- if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
101763
+ if (step === "payment-status") return "none";
101764
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "none";
101759
101765
  return action;
101760
101766
  }
101761
101767
  function canRecoverToWaitlist(eligibility) {
101762
- return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
101768
+ return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
101763
101769
  }
101764
101770
  function shouldRefreshAfterRegistrationError(step, action, enabled) {
101765
101771
  return enabled || step === "error" && action === "places";
@@ -101776,19 +101782,19 @@ function resetRegistrationAfterExpiry(input) {
101776
101782
  input.setErrorMessage("");
101777
101783
  input.setPendingRegistrationReference(null);
101778
101784
  }
101779
- /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
101785
+ /** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
101780
101786
  function recoverRegistrationError(action, handlers) {
101781
101787
  switch (action) {
101782
101788
  case "none": return;
101783
101789
  case "portal":
101784
- case "payment-status":
101785
101790
  window.location.assign("/portal");
101786
101791
  return;
101787
101792
  case "event":
101788
101793
  window.location.assign(window.location.pathname);
101789
101794
  return;
101790
101795
  case "retry":
101791
- window.location.reload();
101796
+ handlers.clearError();
101797
+ handlers.setStep("select-payment");
101792
101798
  return;
101793
101799
  case "details":
101794
101800
  handlers.clearError();
@@ -101828,54 +101834,6 @@ function validateFormData(formData, requiresConsent = false) {
101828
101834
  }
101829
101835
  var init_validation = __esmMin((() => {}));
101830
101836
  //#endregion
101831
- //#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
101832
- function normalizeTicketSelectionLines(lines) {
101833
- const quantitiesByTicketType = /* @__PURE__ */ new Map();
101834
- for (const line of lines) {
101835
- const quantity = Math.floor(line.quantity);
101836
- if (quantity <= 0) continue;
101837
- const key = line.pricingOptionId ?? null;
101838
- quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
101839
- }
101840
- return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
101841
- pricingOptionId,
101842
- quantity
101843
- }));
101844
- }
101845
- function getTicketSelectionTotal(lines) {
101846
- return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
101847
- }
101848
- function getTicketLineQuantity(lines, pricingOptionId) {
101849
- return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
101850
- }
101851
- function getSingleSelectedPricingOptionId(lines) {
101852
- const normalized = normalizeTicketSelectionLines(lines);
101853
- return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
101854
- }
101855
- function hasValidPricingOptionSelection(input) {
101856
- if (!input.selectionRequired) return true;
101857
- if (input.lines.length === 0) return false;
101858
- const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
101859
- return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
101860
- }
101861
- function setTicketLineQuantity(input) {
101862
- const nextQuantity = Math.max(0, Math.floor(input.quantity));
101863
- const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
101864
- if (nextQuantity <= 0) return normalized;
101865
- return [...normalized, {
101866
- pricingOptionId: input.pricingOptionId,
101867
- quantity: nextQuantity
101868
- }];
101869
- }
101870
- function getTicketTypeLineMax(input) {
101871
- const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
101872
- const maxByBlock = input.maxTickets - otherSelectedQuantity;
101873
- const maxByEvent = input.availableSpots == null ? input.maxTickets : input.availableSpots - otherSelectedQuantity;
101874
- const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
101875
- return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
101876
- }
101877
- var init_ticketSelectionLines = __esmMin((() => {}));
101878
- //#endregion
101879
101837
  //#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
101880
101838
  function eligibilityLookupReducer(state, action) {
101881
101839
  switch (action.type) {
@@ -101987,17 +101945,6 @@ function usePortalAuthWithDeps(deps) {
101987
101945
  logout
101988
101946
  };
101989
101947
  }
101990
- function toRegistrationOptionsSubject(subject, attendanceMode) {
101991
- return subject.kind === "occurrence" ? {
101992
- kind: "occurrence",
101993
- occurrenceId: subject.occurrenceId,
101994
- attendanceMode: attendanceMode ?? void 0
101995
- } : {
101996
- kind: "wholeSeries",
101997
- eventSeriesId: subject.eventSeriesId,
101998
- attendanceMode: attendanceMode ?? void 0
101999
- };
102000
- }
102001
101948
  function useEligibility(params) {
102002
101949
  return useEligibilityWithDeps(params, eventRegistrationHooksDeps);
102003
101950
  }
@@ -102038,7 +101985,7 @@ function useEligibilityWithDeps(params, deps) {
102038
101985
  requestIdRef.current = requestId;
102039
101986
  dispatch({ type: "loading-started" });
102040
101987
  try {
102041
- const subject = toRegistrationOptionsSubject(params.subject, params.attendanceMode);
101988
+ const subject = toRegistrationRequestSubject(params.subject, params.attendanceMode);
102042
101989
  const result = await api.getRegistrationOptions({
102043
101990
  subject,
102044
101991
  selections: ticketSelections.map((selection) => ({
@@ -102160,6 +102107,7 @@ var init_hooks = __esmMin((() => {
102160
102107
  init_api();
102161
102108
  init_utils();
102162
102109
  init_ticketSelectionLines();
102110
+ init_registrationDerivations();
102163
102111
  init_hooks_state();
102164
102112
  eventRegistrationHooksDeps = { useBlockApi };
102165
102113
  REGISTRATION_OPTIONS_DEBOUNCE_MS = 150;
@@ -102503,7 +102451,6 @@ var init_stripeCommissionMetadata = __esmMin((() => {
102503
102451
  "no_commission_plan",
102504
102452
  "billing_evidence_invalid",
102505
102453
  "fee_rounds_to_zero",
102506
- "non_commissionable_scope",
102507
102454
  "payment_not_stripe"
102508
102455
  ];
102509
102456
  historicalContext = {
@@ -102627,7 +102574,6 @@ var init_stripeMinimumCharge = __esmMin((() => {
102627
102574
  var init_stripeCheckoutReturnUrl = __esmMin((() => {}));
102628
102575
  var init_stateTransitions = __esmMin((() => {
102629
102576
  init_src$2();
102630
- init_assertNever();
102631
102577
  }));
102632
102578
  //#endregion
102633
102579
  //#region ../commerce/src/purchase/event-registration-errors.ts
@@ -102641,9 +102587,9 @@ var init_event_registration_errors = __esmMin((() => {
102641
102587
  message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
102642
102588
  action: "none"
102643
102589
  },
102644
- paymentUncertain: {
102645
- message: "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.",
102646
- action: "payment-status"
102590
+ paymentInvestigationRequired: {
102591
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
102592
+ action: "none"
102647
102593
  },
102648
102594
  paymentProviderUnavailable: {
102649
102595
  message: "We couldn’t reach the payment provider. Please try again in a minute.",
@@ -102695,6 +102641,7 @@ var init_event_registration_errors = __esmMin((() => {
102695
102641
  }
102696
102642
  };
102697
102643
  }));
102644
+ var init_eventCheckoutRecoveryWindow = __esmMin((() => {}));
102698
102645
  //#endregion
102699
102646
  //#region ../commerce/src/purchase/index.ts
102700
102647
  var init_purchase = __esmMin((() => {
@@ -102756,6 +102703,7 @@ var init_purchase = __esmMin((() => {
102756
102703
  init_stripeCheckoutReturnUrl();
102757
102704
  init_stateTransitions();
102758
102705
  init_event_registration_errors();
102706
+ init_eventCheckoutRecoveryWindow();
102759
102707
  init_stripeCommissionMetadata();
102760
102708
  }));
102761
102709
  //#endregion
@@ -103201,7 +103149,30 @@ function checkoutReturnCommand(params) {
103201
103149
  };
103202
103150
  return null;
103203
103151
  }
103204
- async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103152
+ function handleCheckoutReturnOutcome(options, deps, context, outcome) {
103153
+ const { pending, params } = context;
103154
+ if (outcome.kind === "resolved") {
103155
+ deps.clearReturnParams();
103156
+ options.setPendingRegistrationReference(outcome.reference);
103157
+ options.setStep("verifying-payment");
103158
+ return "settled";
103159
+ }
103160
+ if (outcome.kind === "abandoned") {
103161
+ deps.clearReturnParams();
103162
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103163
+ options.setStep("select-payment");
103164
+ return "settled";
103165
+ }
103166
+ if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
103167
+ deps.clearReturnParams();
103168
+ options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103169
+ options.setStep("select-payment");
103170
+ return "settled";
103171
+ }
103172
+ showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
103173
+ return outcome.kind === "notFound" ? "settled" : "retryable";
103174
+ }
103175
+ async function handleCheckoutReturn(options, deps, returnContextRef) {
103205
103176
  deps.cleanupStaleRegistrations();
103206
103177
  const params = deps.readReturnParams();
103207
103178
  if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
@@ -103215,34 +103186,15 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103215
103186
  }
103216
103187
  const { checkoutAttemptId } = command;
103217
103188
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
103218
- checkoutAttemptIdRef.current = checkoutAttemptId;
103189
+ returnContextRef.current = { checkoutAttemptId };
103219
103190
  if (pending) restorePendingPresentation(options, pending);
103220
103191
  options.setStep("verifying-payment");
103221
103192
  try {
103222
103193
  const outcome = await options.api.resolveEventCheckoutReturn(command);
103223
- switch (outcome.kind) {
103224
- case "resolved":
103225
- deps.clearReturnParams();
103226
- options.setPendingRegistrationReference(outcome.reference);
103227
- options.setStep("verifying-payment");
103228
- return "settled";
103229
- case "abandoned":
103230
- deps.clearReturnParams();
103231
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103232
- options.setStep("select-payment");
103233
- return "settled";
103234
- case "notFound":
103235
- if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
103236
- deps.clearReturnParams();
103237
- options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
103238
- options.setStep("select-payment");
103239
- return "settled";
103240
- }
103241
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
103242
- return "settled";
103243
- case "reconciliationRequired": break;
103244
- }
103245
- showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
103194
+ return handleCheckoutReturnOutcome(options, deps, {
103195
+ pending,
103196
+ params
103197
+ }, outcome);
103246
103198
  } catch {
103247
103199
  showReturnReconciliation(options, "We couldn’t check your payment just now. Please check again in a moment. Don’t make another booking while we’re checking.");
103248
103200
  }
@@ -103251,9 +103203,16 @@ async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
103251
103203
  function useEventRegistrationStripeReturn(options) {
103252
103204
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
103253
103205
  }
103206
+ function completeVerifiedRegistration(options, deps, returnContext) {
103207
+ const siteId = options.api.config.siteId;
103208
+ const checkoutAttemptId = returnContext?.checkoutAttemptId;
103209
+ if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
103210
+ options.setRegistrationResult({ status: "confirmed" });
103211
+ options.setStep("success");
103212
+ }
103254
103213
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
103255
103214
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
103256
- const checkoutAttemptIdRef = useRef(null);
103215
+ const returnContextRef = useRef(null);
103257
103216
  const lookupInFlightRef = useRef(false);
103258
103217
  const [lookupState, setLookupState] = useState("settled");
103259
103218
  const resolveReturn = useCallback(async () => {
@@ -103261,7 +103220,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
103261
103220
  lookupInFlightRef.current = true;
103262
103221
  setLookupState("loading");
103263
103222
  try {
103264
- setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
103223
+ setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
103265
103224
  } finally {
103266
103225
  lookupInFlightRef.current = false;
103267
103226
  }
@@ -103284,13 +103243,8 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
103284
103243
  resolveReturn();
103285
103244
  }, []);
103286
103245
  useEffect(() => {
103287
- if (verification.status === "completed") {
103288
- const siteId = api.config.siteId;
103289
- const checkoutAttemptId = checkoutAttemptIdRef.current;
103290
- if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
103291
- setRegistrationResult({ status: "confirmed" });
103292
- setStep("success");
103293
- } else if (verification.status === "failed") {
103246
+ if (verification.status === "completed") completeVerifiedRegistration(options, deps, returnContextRef.current);
103247
+ else if (verification.status === "failed") {
103294
103248
  setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
103295
103249
  setStep("payment-failed");
103296
103250
  } else if (verification.status === "timeout") setStep("verifying-timeout");
@@ -103349,7 +103303,10 @@ function registrationErrorPresentation(error) {
103349
103303
  const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
103350
103304
  if (reason) return eventRegistrationErrors[reason];
103351
103305
  if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
103352
- return eventRegistrationErrors.paymentUncertain;
103306
+ return {
103307
+ message: "Something went wrong. Please try again.",
103308
+ action: "retry"
103309
+ };
103353
103310
  }
103354
103311
  var init_registrationErrorPresentation = __esmMin((() => {
103355
103312
  init_purchase();
@@ -103378,26 +103335,6 @@ function useEventRegistrationSubmit(options) {
103378
103335
  * and the balance left, which the block's copy cannot. Every other method keeps
103379
103336
  * whatever success message the site configured.
103380
103337
  */
103381
- function toRegistrationResult(result) {
103382
- if (result.alreadyRegistered) {
103383
- const waitlisted = result.status === "waitlist";
103384
- return {
103385
- status: result.status,
103386
- variant: "info",
103387
- title: waitlisted ? "Already waitlisted" : "Already registered",
103388
- message: result.message ?? (waitlisted ? "You are already on the waitlist for this event." : "You are already registered for this event.")
103389
- };
103390
- }
103391
- if (result.status === "waitlist") return {
103392
- status: "waitlist",
103393
- title: "Added to waitlist",
103394
- message: result.message ?? (typeof result.waitlistPosition === "number" ? `You've been added to the waitlist (position ${result.waitlistPosition}).` : "You've been added to the waitlist.")
103395
- };
103396
- return {
103397
- status: result.status,
103398
- message: result.paymentMethod === "pass" ? result.message : void 0
103399
- };
103400
- }
103401
103338
  function useEventRegistrationSubmitWithDeps(options, deps) {
103402
103339
  /**
103403
103340
  * The command identity for the submission currently in progress.
@@ -103411,7 +103348,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103411
103348
  * Identical retries retain the command after a lost response. Changed form
103412
103349
  * details get a new command so the server applies the new booking intent.
103413
103350
  */
103414
- const commandRef = useRef(null);
103351
+ const { commandRef } = options;
103415
103352
  const inFlightRef = useRef(null);
103416
103353
  const submit = async (method, passId, membershipId, selection, submitOptions) => {
103417
103354
  const target = options.registrationTarget;
@@ -103424,19 +103361,15 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103424
103361
  const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
103425
103362
  try {
103426
103363
  let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
103427
- if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
103428
- commandRef.current = null;
103429
- return await submitWholeSeriesCheckout(options, deps, {
103364
+ let request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
103365
+ const intentKey = registrationRequestIntentKey(request);
103366
+ if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) {
103367
+ prepared = {
103430
103368
  ...prepared,
103431
- subject: prepared.subject
103432
- }, submitOptions);
103369
+ registrationCommandId: deps.createClientCommandId()
103370
+ };
103371
+ request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
103433
103372
  }
103434
- const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
103435
- const intentKey = registrationRequestIntentKey(request);
103436
- if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
103437
- ...prepared,
103438
- registrationCommandId: deps.createClientCommandId()
103439
- };
103440
103373
  commandRef.current = {
103441
103374
  id: prepared.registrationCommandId,
103442
103375
  intentKey
@@ -103445,8 +103378,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103445
103378
  ...request,
103446
103379
  registrationCommandId: prepared.registrationCommandId
103447
103380
  });
103448
- commandRef.current = null;
103449
- return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
103381
+ return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
103450
103382
  } catch (error) {
103451
103383
  if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
103452
103384
  const { message, action } = registrationErrorPresentation(error);
@@ -103470,9 +103402,40 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
103470
103402
  return pending;
103471
103403
  };
103472
103404
  }
103473
- async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
103474
- if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
103475
- options.setRegistrationResult(toRegistrationResult(result));
103405
+ async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
103406
+ switch (result.kind) {
103407
+ case "paymentStatusRequired":
103408
+ options.setPaymentStatusRecovery({
103409
+ kind: "ready",
103410
+ subject: result.subject
103411
+ });
103412
+ options.setStep("payment-status");
103413
+ return {
103414
+ ok: true,
103415
+ outcome: { kind: "payment_status" }
103416
+ };
103417
+ case "checkoutRequired":
103418
+ options.setPendingRegistrationReference(result.reference);
103419
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
103420
+ options.setStep("redirecting");
103421
+ return redirectToCheckout(result.checkoutUrl, submitOptions);
103422
+ case "waitlisted":
103423
+ options.setRegistrationResult({
103424
+ status: "waitlist",
103425
+ title: "Added to waitlist",
103426
+ message: result.waitlist.message
103427
+ });
103428
+ break;
103429
+ case "bookingComplete":
103430
+ case "paymentDeferred":
103431
+ options.setPendingRegistrationReference(result.reference);
103432
+ options.setRegistrationResult({
103433
+ status: "confirmed",
103434
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
103435
+ });
103436
+ break;
103437
+ }
103438
+ options.commandRef.current = null;
103476
103439
  options.setStep("success");
103477
103440
  return {
103478
103441
  ok: true,
@@ -103503,15 +103466,7 @@ function prepareSubmitContext(options, registrationCommandId, target, method, pa
103503
103466
  email: guest.email?.trim().toLowerCase() || void 0,
103504
103467
  phone: guest.phone?.trim() || void 0
103505
103468
  })) : void 0,
103506
- subject: target.subject.kind === "occurrence" ? {
103507
- kind: "occurrence",
103508
- occurrenceId: target.subject.occurrenceId,
103509
- attendanceMode: options.selectedAttendanceMode ?? void 0
103510
- } : {
103511
- kind: "wholeSeries",
103512
- eventSeriesId: target.subject.eventSeriesId,
103513
- attendanceMode: options.selectedAttendanceMode ?? void 0
103514
- }
103469
+ subject: toRegistrationRequestSubject(target.subject, options.selectedAttendanceMode)
103515
103470
  };
103516
103471
  }
103517
103472
  function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection) {
@@ -103535,85 +103490,6 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
103535
103490
  if (method === "free") return { method };
103536
103491
  throw new Error("Choose an available payment option.");
103537
103492
  }
103538
- async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
103539
- options.setStep("redirecting");
103540
- if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
103541
- const checkoutAttemptId = deps.createClientCommandId();
103542
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
103543
- const result = await options.api.createEventCheckout({
103544
- subject: prepared.subject,
103545
- ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
103546
- selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
103547
- email: options.formData.email.trim().toLowerCase(),
103548
- name: options.formData.name.trim(),
103549
- phone: options.formData.phone.trim() || void 0,
103550
- formData: options.formData,
103551
- consentAccepted: options.formData.consentAccepted,
103552
- altchaSolution: options.altchaSolution,
103553
- guests: prepared.guestsPayload,
103554
- claimToken: options.claimToken ?? void 0,
103555
- waitlistEntryId: options.waitlistEntryId ?? void 0,
103556
- discountCode: options.discountCode.trim() || void 0,
103557
- collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
103558
- checkoutAttemptId,
103559
- ...urls
103560
- });
103561
- if (result.scope !== "wholeSeries") throw new Error("Unexpected registration scope for event checkout.");
103562
- if ("waitlistEntryId" in result) {
103563
- options.setRegistrationResult({
103564
- status: "waitlist",
103565
- variant: result.alreadyRegistered ? "info" : void 0,
103566
- title: result.alreadyRegistered ? "Already waitlisted" : "Added to waitlist",
103567
- message: result.alreadyRegistered ? "You are already on the waitlist for this event." : "You've been added to the waitlist."
103568
- });
103569
- options.setStep("success");
103570
- return {
103571
- ok: true,
103572
- outcome: { kind: "completed" }
103573
- };
103574
- }
103575
- if (result.bypassed) return completeBypassedCheckout(options);
103576
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
103577
- savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
103578
- scope: "wholeSeries",
103579
- registrationId: result.registrationId
103580
- });
103581
- return redirectToCheckout(result.checkoutUrl, submitOptions);
103582
- }
103583
- function needsOccurrenceCheckout(result, method) {
103584
- return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
103585
- "stripe",
103586
- "pass_bundle",
103587
- "membership_bundle"
103588
- ].includes(method);
103589
- }
103590
- async function submitOccurrenceCheckout(options, deps, prepared, registration, method, submitOptions) {
103591
- const reference = {
103592
- scope: "occurrence",
103593
- attendeeId: registration.attendeeId
103594
- };
103595
- options.setPendingRegistrationReference(reference);
103596
- options.setStep("redirecting");
103597
- const checkoutAttemptId = deps.createClientCommandId();
103598
- const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
103599
- const result = await options.api.createEventCheckout({
103600
- subject: {
103601
- kind: "occurrence",
103602
- attendeeId: registration.attendeeId
103603
- },
103604
- registrationCommandId: prepared.registrationCommandId,
103605
- checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
103606
- productId: prepared.bundleProductId,
103607
- discountCode: options.discountCode.trim() || void 0,
103608
- collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0,
103609
- ...urls
103610
- });
103611
- if (result.scope !== "occurrence") throw new Error("Unexpected registration scope for event checkout.");
103612
- if (result.bypassed) return completeBypassedCheckout(options);
103613
- if (!result.checkoutUrl) throw new Error("Checkout URL missing");
103614
- if (prepared.subject.kind === "occurrence") savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference);
103615
- return redirectToCheckout(result.checkoutUrl, submitOptions);
103616
- }
103617
103493
  function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
103618
103494
  const siteId = options.api.config.siteId;
103619
103495
  if (!siteId) return;
@@ -103626,14 +103502,6 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
103626
103502
  paymentSelection: prepared.selectionSnapshot
103627
103503
  });
103628
103504
  }
103629
- function completeBypassedCheckout(options) {
103630
- options.setRegistrationResult({ status: "confirmed" });
103631
- options.setStep("success");
103632
- return {
103633
- ok: true,
103634
- outcome: { kind: "completed" }
103635
- };
103636
- }
103637
103505
  function redirectToCheckout(checkoutUrl, submitOptions) {
103638
103506
  if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
103639
103507
  return {
@@ -103645,12 +103513,23 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
103645
103513
  };
103646
103514
  }
103647
103515
  function registrationRequestIntentKey(request) {
103648
- const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
103649
- return JSON.stringify(intent);
103516
+ const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
103517
+ return JSON.stringify({
103518
+ ...intent,
103519
+ checkout: checkout ? {
103520
+ discountCode: checkout.discountCode,
103521
+ collectionOptionKind: checkout.collectionOptionKind
103522
+ } : void 0
103523
+ });
103650
103524
  }
103651
- function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
103525
+ function buildRegistrationRequest(options, prepared, method, passId, membershipId) {
103652
103526
  return {
103653
103527
  registrationCommandId: prepared.registrationCommandId,
103528
+ checkout: {
103529
+ ...buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: prepared.registrationCommandId }),
103530
+ discountCode: options.discountCode.trim() || void 0,
103531
+ collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
103532
+ },
103654
103533
  subject: prepared.subject,
103655
103534
  ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
103656
103535
  selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
@@ -103675,6 +103554,7 @@ var init_useEventRegistrationSubmit = __esmMin((() => {
103675
103554
  init_shared();
103676
103555
  init_registrationErrorPresentation();
103677
103556
  init_constants();
103557
+ init_registrationDerivations();
103678
103558
  init_sessionStorage();
103679
103559
  init_ticketSelectionLines();
103680
103560
  eventRegistrationSubmitDeps = {
@@ -103892,23 +103772,128 @@ var init_useWaitlistClaimRestoration = __esmMin((() => {
103892
103772
  }));
103893
103773
  //#endregion
103894
103774
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
103775
+ function isSelectionSoldOut(availability) {
103776
+ return availability?.kind === "unavailable" && availability.reason === "full";
103777
+ }
103895
103778
  function resolveRegistrationAvailabilityBlocker(input) {
103896
103779
  if (input.hasWaitlistClaim) return null;
103897
103780
  if (input.eligibilityError) return input.eligibilityError;
103898
103781
  if (!input.eligibility) return "Registration is not available for this event.";
103782
+ if (input.eligibility.registration.kind === "pending_payment") return null;
103783
+ if (isSelectionSoldOut(input.eligibility.availability)) return null;
103899
103784
  if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
103900
- if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
103785
+ if (input.eligibility.availability.kind === "unavailable" || input.eligibility.registration.kind === "waitlisted") return "Registration is not available for this event.";
103901
103786
  return null;
103902
103787
  }
103903
103788
  function resolvePricingSelectionBlocker(input) {
103904
103789
  if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
103905
103790
  return input.slidingScaleSelectionMessage;
103906
103791
  }
103907
- function isSoldOutWithoutWaitlist(input) {
103908
- return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
103909
- }
103910
103792
  var init_registrationCompletion = __esmMin((() => {}));
103911
103793
  //#endregion
103794
+ //#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
103795
+ function isCheckableRecovery(state) {
103796
+ return state.kind === "ready" || state.kind === "processing" || state.kind === "temporarilyUnavailable";
103797
+ }
103798
+ function assistanceRequired(recovery) {
103799
+ return {
103800
+ kind: "assistanceRequired",
103801
+ subject: recovery.subject
103802
+ };
103803
+ }
103804
+ function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
103805
+ if (outcome.kind === "resolved") {
103806
+ setters.setPendingRegistrationReference(outcome.reference);
103807
+ setters.setRegistrationResult({ status: "confirmed" });
103808
+ setRecovery(null);
103809
+ setters.setStep("success");
103810
+ return;
103811
+ }
103812
+ switch (outcome.kind) {
103813
+ case "paymentProcessing":
103814
+ setRecovery({
103815
+ ...recovery,
103816
+ kind: "processing"
103817
+ });
103818
+ return;
103819
+ case "paymentAvailable":
103820
+ setRecovery({
103821
+ ...recovery,
103822
+ kind: "paymentAvailable",
103823
+ checkoutUrl: outcome.checkoutUrl
103824
+ });
103825
+ return;
103826
+ case "paymentCheckUnavailable":
103827
+ setRecovery({
103828
+ ...recovery,
103829
+ kind: "temporarilyUnavailable"
103830
+ });
103831
+ return;
103832
+ case "paymentRetryAvailable":
103833
+ setRecovery({
103834
+ ...recovery,
103835
+ kind: "retryAvailable"
103836
+ });
103837
+ return;
103838
+ case "abandoned":
103839
+ case "notFound":
103840
+ case "reconciliationRequired":
103841
+ case "paymentAssistanceRequired":
103842
+ setRecovery(assistanceRequired(recovery));
103843
+ return;
103844
+ }
103845
+ }
103846
+ function usePaymentStatusRecovery(options) {
103847
+ const [recovery, setRecovery] = useState(null);
103848
+ const checkRef = useRef(null);
103849
+ return {
103850
+ recovery,
103851
+ showRecovery: useCallback((next) => setRecovery(next), []),
103852
+ check: useCallback(() => {
103853
+ if (!recovery || !isCheckableRecovery(recovery) || checkRef.current) return;
103854
+ const pending = (async () => {
103855
+ setRecovery({
103856
+ ...recovery,
103857
+ kind: "checking"
103858
+ });
103859
+ try {
103860
+ applyStatusOutcome(await options.api.resolveEventCheckoutReturn({
103861
+ kind: "checkStatus",
103862
+ subject: recovery.subject
103863
+ }), recovery, options, setRecovery);
103864
+ } catch {
103865
+ setRecovery({
103866
+ ...recovery,
103867
+ kind: "temporarilyUnavailable"
103868
+ });
103869
+ }
103870
+ })();
103871
+ checkRef.current = pending;
103872
+ pending.finally(() => {
103873
+ if (checkRef.current === pending) checkRef.current = null;
103874
+ });
103875
+ }, [options, recovery]),
103876
+ continuePayment: useCallback(() => {
103877
+ if (recovery?.kind === "paymentAvailable") window.location.assign(recovery.checkoutUrl);
103878
+ }, [recovery]),
103879
+ returnToPayment: useCallback(() => {
103880
+ if (recovery?.kind !== "retryAvailable") return;
103881
+ options.beginNewSubmission();
103882
+ setRecovery(null);
103883
+ options.setOptionsRefreshKey((value) => value + 1);
103884
+ options.setStep("select-payment");
103885
+ }, [options, recovery]),
103886
+ returnToBooking: useCallback(() => {
103887
+ if (recovery?.kind !== "assistanceRequired") return;
103888
+ options.beginNewSubmission();
103889
+ setRecovery(null);
103890
+ options.setOptionsRefreshKey((value) => value + 1);
103891
+ options.setStep("select-tickets");
103892
+ }, [options, recovery])
103893
+ };
103894
+ }
103895
+ var init_usePaymentStatusRecovery = __esmMin((() => {}));
103896
+ //#endregion
103912
103897
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
103913
103898
  function usesTieredPricing(event) {
103914
103899
  return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
@@ -103955,6 +103940,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
103955
103940
  const [errorAction, setErrorAction] = useState("retry");
103956
103941
  const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
103957
103942
  const [altchaSolution, setAltchaSolution] = useState(null);
103943
+ const [checkingNextStep, setCheckingNextStep] = useState(false);
103958
103944
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
103959
103945
  const waitlistClaim = deps.useWaitlistClaim();
103960
103946
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
@@ -103981,28 +103967,29 @@ function useEventRegistrationWizardWithDeps(options, deps) {
103981
103967
  }), [options.occurrenceContext, selectedEvent]);
103982
103968
  const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
103983
103969
  const currentEvent = selectedEvent ?? preSelectedEvent;
103970
+ const commandRef = useRef(null);
103984
103971
  const setStep = useCallback((nextStep) => {
103985
103972
  dispatchFlow({
103986
103973
  type: "set-step",
103987
103974
  step: nextStep
103988
103975
  });
103989
103976
  }, []);
103990
- const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
103991
- const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
103992
- const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
103993
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
103977
+ const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = usePaymentStatusRecovery({
103978
+ api,
103979
+ beginNewSubmission: () => {
103980
+ commandRef.current = null;
103981
+ },
103982
+ setPendingRegistrationReference,
103983
+ setRegistrationResult,
103984
+ setOptionsRefreshKey,
103985
+ setStep
103986
+ });
103987
+ const usesTicketTypeSelections = usesTieredPricing(currentEvent);
103994
103988
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
103995
103989
  event: currentEvent,
103996
103990
  eligibility: null,
103997
103991
  selectedAttendanceMode
103998
- }).map((option) => checkoutRecovery ? {
103999
- ...option,
104000
- availability: checkoutRecoveryOptionAvailability(option.availability)
104001
- } : option), [
104002
- currentEvent,
104003
- selectedAttendanceMode,
104004
- checkoutRecovery
104005
- ]);
103992
+ }), [currentEvent, selectedAttendanceMode]);
104006
103993
  const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
104007
103994
  const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
104008
103995
  const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
@@ -104040,7 +104027,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104040
104027
  isAuthenticated: portalAuthState === "authenticated",
104041
104028
  occurrenceId: registrationOccurrenceId
104042
104029
  });
104043
- const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
104030
+ const eligibility = eligibilityResult.eligibility;
104044
104031
  const eligibilityLoading = eligibilityResult.isLoading;
104045
104032
  const eligibilityError = eligibilityResult.error;
104046
104033
  const portalCreditState = eligibilityResult.creditState;
@@ -104152,14 +104139,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104152
104139
  event: currentEvent,
104153
104140
  eligibility,
104154
104141
  selectedAttendanceMode
104155
- }).map((option) => checkoutRecovery ? {
104156
- ...option,
104157
- availability: checkoutRecoveryOptionAvailability(option.availability)
104158
- } : option), [
104142
+ }), [
104159
104143
  currentEvent,
104160
104144
  selectedAttendanceMode,
104161
- eligibility,
104162
- checkoutRecovery
104145
+ eligibility
104163
104146
  ]);
104164
104147
  const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
104165
104148
  const selectedTicketType = useMemo(() => findSelectedTicketType({
@@ -104183,12 +104166,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104183
104166
  const event = currentEvent;
104184
104167
  if (!usesTieredPricing(event)) return false;
104185
104168
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
104186
- return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
104187
- }, [
104188
- currentEvent,
104189
- selectedAttendanceMode,
104190
- checkoutRecovery
104191
- ]);
104169
+ return true;
104170
+ }, [currentEvent, selectedAttendanceMode]);
104192
104171
  const hasValidTicketSelection = hasValidPricingOptionSelection({
104193
104172
  selectionRequired: ticketTypeSelectionRequired,
104194
104173
  lines: normalizedSelectedTicketLines,
@@ -104199,8 +104178,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104199
104178
  if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
104200
104179
  return;
104201
104180
  }
104202
- const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => ticketType.availability.kind === "available");
104203
- const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
104181
+ const availableTicketTypes = eventTicketTypesForSelection.filter((ticketType) => canRequestTicketOption(ticketType.availability));
104182
+ const implicitTicketType = getImplicitSingleTicketType(eventTicketTypesForSelection);
104204
104183
  if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
104205
104184
  setSelectedTicketLines([{
104206
104185
  pricingOptionId: implicitTicketType.pricingOptionId,
@@ -104267,6 +104246,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104267
104246
  selectedEventSlidingScale,
104268
104247
  selectedSlidingAmount
104269
104248
  ]);
104249
+ const checkDetailsNextStep = async () => {
104250
+ if (portalAuthState === "authenticated" || waitlistClaim.claim || eligibility?.availability.kind === "available" || !registrationTarget) return { kind: canRecoverToWaitlist(eligibility) ? "waitlist" : "continue" };
104251
+ setCheckingNextStep(true);
104252
+ try {
104253
+ return await api.checkRegistrationNextStep({
104254
+ subject: toRegistrationRequestSubject(registrationTarget.subject, selectedAttendanceMode),
104255
+ selections: ticketSelections,
104256
+ selectedSlidingAmount: selectedSlidingAmount ?? void 0,
104257
+ email: formData.email,
104258
+ altchaSolution
104259
+ });
104260
+ } catch {
104261
+ return {
104262
+ kind: "unavailable",
104263
+ message: "We could not check availability. Please try again."
104264
+ };
104265
+ } finally {
104266
+ setCheckingNextStep(false);
104267
+ }
104268
+ };
104270
104269
  const handleDetailsComplete = async () => {
104271
104270
  const blockDetailsCompletion = (message) => {
104272
104271
  setErrorAction("places");
@@ -104298,11 +104297,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104298
104297
  message: "Check the highlighted fields and try again."
104299
104298
  };
104300
104299
  }
104301
- if (isSoldOutWithoutWaitlist({
104302
- hasWaitlistClaim: waitlistClaim.claim !== null,
104303
- eligibility
104304
- })) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
104305
- if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
104300
+ const next = await checkDetailsNextStep();
104301
+ if (next.kind === "unavailable") return blockDetailsCompletion(next.message);
104302
+ const canJoinWaitlist = next.kind === "waitlist";
104303
+ if (!canJoinWaitlist && requiresPaymentStep({
104306
104304
  eventRequiresPayment,
104307
104305
  paymentSelection
104308
104306
  })) {
@@ -104315,7 +104313,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104315
104313
  const submitPlan = resolveEventRegistrationSubmitPlan({
104316
104314
  paymentSelection,
104317
104315
  eventRequiresPayment,
104318
- canJoinWaitlist: eligibility?.canJoinWaitlist
104316
+ canJoinWaitlist
104319
104317
  });
104320
104318
  if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
104321
104319
  const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
@@ -104333,7 +104331,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104333
104331
  const submitPlan = resolveEventRegistrationSubmitPlan({
104334
104332
  paymentSelection,
104335
104333
  eventRequiresPayment,
104336
- canJoinWaitlist: eligibility?.canJoinWaitlist
104334
+ canJoinWaitlist: false
104337
104335
  });
104338
104336
  if (!submitPlan.ok) {
104339
104337
  setErrorMessage(submitPlan.message);
@@ -104365,6 +104363,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104365
104363
  const selectionMethod = paymentSelection.method;
104366
104364
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
104367
104365
  const handleSubmit = deps.useEventRegistrationSubmit({
104366
+ commandRef,
104368
104367
  setErrorAction,
104369
104368
  api,
104370
104369
  registrationTarget,
@@ -104381,7 +104380,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104381
104380
  setPendingRegistrationReference,
104382
104381
  setStep,
104383
104382
  setRegistrationResult: (result) => setRegistrationResult(result),
104384
- setErrorMessage
104383
+ setErrorMessage,
104384
+ setPaymentStatusRecovery
104385
104385
  });
104386
104386
  const handleEventSelect = (event) => {
104387
104387
  setSelectedEvent(event);
@@ -104440,8 +104440,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104440
104440
  scopedEvents,
104441
104441
  preSelectedEvent,
104442
104442
  hasPreSelectedContext,
104443
- checkoutRecovery,
104444
- startCheckoutRecovery,
104445
104443
  step,
104446
104444
  setStep,
104447
104445
  selectedEvent,
@@ -104495,7 +104493,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104495
104493
  waitlistClaim,
104496
104494
  eligibility,
104497
104495
  registrationOptionsState: eligibilityResult.state,
104498
- eligibilityLoading,
104496
+ eligibilityLoading: eligibilityLoading || checkingNextStep,
104499
104497
  eligibilityError,
104500
104498
  existingRegistration: existingRegistrationResult.registration,
104501
104499
  existingRegistrationLoading: existingRegistrationResult.isLoading || portalAuthState === "authenticated" && eligibilityLoading,
@@ -104515,6 +104513,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104515
104513
  discountContext,
104516
104514
  shouldShowDiscountToggle,
104517
104515
  verification,
104516
+ paymentStatusRecovery,
104517
+ handleCheckPaymentStatus,
104518
+ handleContinueExistingPayment,
104519
+ handleReturnToPayment,
104520
+ handleReturnToBooking,
104518
104521
  handleDetailsComplete,
104519
104522
  handlePaymentSelect,
104520
104523
  handleUseCardInsteadOfPass,
@@ -104526,12 +104529,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
104526
104529
  }
104527
104530
  var eventRegistrationWizardDeps;
104528
104531
  var init_useEventRegistrationWizard = __esmMin((() => {
104529
- init_checkoutRecovery();
104530
- init_useCheckoutRecovery();
104531
104532
  init_src$2();
104532
104533
  init_registrationErrorRecovery();
104533
104534
  init_api();
104534
- init_domain();
104535
104535
  init_validation();
104536
104536
  init_hooks();
104537
104537
  init_portalLogout();
@@ -104551,6 +104551,7 @@ var init_useEventRegistrationWizard = __esmMin((() => {
104551
104551
  init_waitlistClaimRestoration();
104552
104552
  init_useWaitlistClaimRestoration();
104553
104553
  init_registrationCompletion();
104554
+ init_usePaymentStatusRecovery();
104554
104555
  eventRegistrationWizardDeps = {
104555
104556
  usePortalAuth,
104556
104557
  useEligibility,
@@ -104734,7 +104735,6 @@ var init_ErrorStep = __esmMin((() => {
104734
104735
  start: "Start again",
104735
104736
  details: "Check my details",
104736
104737
  "payment-options": "View payment options",
104737
- "payment-status": "Check payment status",
104738
104738
  portal: "View my bookings",
104739
104739
  event: "View event"
104740
104740
  };
@@ -104753,7 +104753,7 @@ var init_ErrorStep = __esmMin((() => {
104753
104753
  className: "er-text--muted er-message",
104754
104754
  children: offerWaitlist ? "Sorry, this event is now full. You can join the waiting list, and we’ll email you if a place becomes available." : message
104755
104755
  }),
104756
- actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
104756
+ actions: action === "none" ? void 0 : action === "portal" ? /* @__PURE__ */ jsx("a", {
104757
104757
  href: "/portal",
104758
104758
  className: "er-retry-btn",
104759
104759
  children: labels[action]
@@ -105014,8 +105014,11 @@ var init_EventRegistrationSummaryBar = __esmMin((() => {
105014
105014
  */
105015
105015
  function resolveDetailsButtonText(input) {
105016
105016
  const { wizard } = input;
105017
- if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
105018
- if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
105017
+ const availability = wizard.eligibility?.availability;
105018
+ const full = availability?.kind === "waitlist" || isSelectionSoldOut(availability);
105019
+ if (wizard.portalAuthState !== "authenticated" && full) return "Continue";
105020
+ if (canRecoverToWaitlist(wizard.eligibility)) return "Join waitlist";
105021
+ if (!input.hasWaitlistClaim && full && wizard.eligibility?.registration.kind !== "pending_payment") return "Sold out";
105019
105022
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
105020
105023
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
105021
105024
  return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
@@ -105030,44 +105033,28 @@ function isExistingRegistrationBlocking$1(wizard) {
105030
105033
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
105031
105034
  });
105032
105035
  }
105033
- /**
105034
- * Full for the visitor's selected attendance mode (or the whole event when no
105035
- * mode is chosen) with no waitlist to fall back on. Reads the same capacity
105036
- * source as the steps above the action bar so the button never disagrees
105037
- * with them on a hybrid event.
105038
- */
105039
- function isFullWithNoWaitlist(event, attendanceMode) {
105040
- if (!event) return false;
105041
- const source = selectEventCapacitySource(event, attendanceMode);
105042
- return getEventAvailability(source).isFull && !source.waitlistEnabled;
105043
- }
105044
105036
  function resolveTicketSelectionContinueLabel(input) {
105045
105037
  if (input.isCheckingExistingRegistration) return "Checking registration...";
105046
105038
  if (input.registrationOptionsPending) return "Checking availability...";
105047
105039
  if (input.registrationOptionsFailed) return "Availability unavailable";
105048
105040
  if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
105049
- if (input.isSoldOutWithoutWaitlist) return "Sold out";
105050
105041
  if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
105051
105042
  return "Continue";
105052
105043
  }
105053
105044
  function SelectTicketsActions(props) {
105054
105045
  const { wizard } = props;
105055
- const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
105056
- const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
105057
105046
  const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
105058
105047
  const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
105059
- const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
105060
105048
  const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
105061
105049
  const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
105062
105050
  const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
105063
- const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
105051
+ const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
105064
105052
  const continueLabel = resolveTicketSelectionContinueLabel({
105065
105053
  wizard,
105066
105054
  registrationOptionsPending,
105067
105055
  registrationOptionsFailed,
105068
105056
  isCheckingExistingRegistration,
105069
105057
  hasExistingRegistration,
105070
- isSoldOutWithoutWaitlist,
105071
105058
  ticketTypeSelectionBlocked
105072
105059
  });
105073
105060
  return /* @__PURE__ */ jsxs("div", {
@@ -105098,8 +105085,12 @@ function EnterDetailsActions(props) {
105098
105085
  const { wizard } = props;
105099
105086
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
105100
105087
  const isCheckingEligibility = wizard.eligibilityLoading;
105101
- const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
105102
- const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
105088
+ const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker({
105089
+ hasWaitlistClaim,
105090
+ eligibility: wizard.eligibility,
105091
+ eligibilityError: wizard.eligibilityError
105092
+ }));
105093
+ const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
105103
105094
  const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
105104
105095
  const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
105105
105096
  wizard,
@@ -105150,6 +105141,7 @@ function EventRegistrationWizardActions(props) {
105150
105141
  case "redirecting":
105151
105142
  case "verifying-payment":
105152
105143
  case "verifying-timeout":
105144
+ case "payment-status":
105153
105145
  case "payment-failed": return null;
105154
105146
  case "select-event": return null;
105155
105147
  case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
@@ -105161,7 +105153,8 @@ function EventRegistrationWizardActions(props) {
105161
105153
  var init_EventRegistrationWizardActions = __esmMin((() => {
105162
105154
  init_registrationStateMachine();
105163
105155
  init_spinner();
105164
- init_domain();
105156
+ init_registrationCompletion();
105157
+ init_registrationErrorRecovery();
105165
105158
  }));
105166
105159
  //#endregion
105167
105160
  //#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
@@ -105242,7 +105235,7 @@ var init_siteCreditPreview = __esmMin((() => {
105242
105235
  function resolvePaymentStepStatus(input) {
105243
105236
  if (input.loading) return "loading";
105244
105237
  if (input.error || !input.eligibility) return "error";
105245
- if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
105238
+ if (input.eligibility.registration.kind === "waitlisted" || input.eligibility.paymentOptions.length === 0) return "not-eligible";
105246
105239
  return "ready";
105247
105240
  }
105248
105241
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
@@ -105277,7 +105270,7 @@ function UnavailableEntitlementMessage(props) {
105277
105270
  ] });
105278
105271
  }
105279
105272
  function IneligiblePaymentPanel(props) {
105280
- if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
105273
+ if (isSelectionSoldOut(props.eligibility.availability)) return /* @__PURE__ */ jsxs("div", {
105281
105274
  className: "rb-reg-stack er-stack",
105282
105275
  children: [/* @__PURE__ */ jsx("h3", {
105283
105276
  className: "er-title",
@@ -105346,26 +105339,23 @@ function PaymentBlockingPanel(props) {
105346
105339
  })
105347
105340
  });
105348
105341
  if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
105349
- if (props.eligibility.registration.kind !== "none") {
105350
- const isBooked = props.eligibility.registration.kind === "booked";
105351
- return /* @__PURE__ */ jsxs("div", {
105352
- className: "rb-reg-stack er-stack",
105353
- children: [/* @__PURE__ */ jsx("h3", {
105354
- className: "er-title",
105355
- children: isBooked ? "Already booked" : "Already on the waitlist"
105356
- }), /* @__PURE__ */ jsxs("div", {
105357
- className: "er-center",
105358
- children: [/* @__PURE__ */ jsx("p", {
105359
- className: "er-text er-text--muted",
105360
- children: isBooked ? "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser." : "You're already on the waitlist for this event."
105361
- }), /* @__PURE__ */ jsx("a", {
105362
- href: "/portal",
105363
- className: "er-retry-btn",
105364
- children: "View my bookings"
105365
- })]
105342
+ if (props.eligibility.registration.kind === "waitlisted") return /* @__PURE__ */ jsxs("div", {
105343
+ className: "rb-reg-stack er-stack",
105344
+ children: [/* @__PURE__ */ jsx("h3", {
105345
+ className: "er-title",
105346
+ children: "Already on the waitlist"
105347
+ }), /* @__PURE__ */ jsxs("div", {
105348
+ className: "er-center",
105349
+ children: [/* @__PURE__ */ jsx("p", {
105350
+ className: "er-text er-text--muted",
105351
+ children: "You're already on the waitlist for this event."
105352
+ }), /* @__PURE__ */ jsx("a", {
105353
+ href: "/portal",
105354
+ className: "er-retry-btn",
105355
+ children: "View my bookings"
105366
105356
  })]
105367
- });
105368
- }
105357
+ })]
105358
+ });
105369
105359
  if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
105370
105360
  className: "rb-reg-stack er-stack",
105371
105361
  children: [/* @__PURE__ */ jsx("h3", {
@@ -105386,7 +105376,7 @@ function PaymentBlockingPanel(props) {
105386
105376
  })]
105387
105377
  })]
105388
105378
  });
105389
- return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
105379
+ return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
105390
105380
  eligibility: props.eligibility,
105391
105381
  email: props.email,
105392
105382
  isAuthenticated: props.isAuthenticated,
@@ -105396,6 +105386,7 @@ function PaymentBlockingPanel(props) {
105396
105386
  var init_PaymentBlockingPanel = __esmMin((() => {
105397
105387
  init_buttons();
105398
105388
  init_spinner();
105389
+ init_registrationCompletion();
105399
105390
  }));
105400
105391
  //#endregion
105401
105392
  //#region ../blocks/src/system/runtime/nodes/event-registration/types.ts
@@ -105525,7 +105516,7 @@ function SlidingScaleAmountField(props) {
105525
105516
  }
105526
105517
  function TicketTypeQuantityRows(props) {
105527
105518
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
105528
- const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
105519
+ const effectiveMaxTickets = props.maxTickets;
105529
105520
  return /* @__PURE__ */ jsxs("div", {
105530
105521
  className: "er-ticket-lines",
105531
105522
  children: [
@@ -105535,16 +105526,14 @@ function TicketTypeQuantityRows(props) {
105535
105526
  "aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
105536
105527
  children: props.ticketTypes.map((ticketType) => {
105537
105528
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
105538
- const disabled = ticketType.availability.kind === "unavailable";
105529
+ const disabled = !canRequestTicketOption(ticketType.availability);
105539
105530
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
105540
105531
  const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
105541
105532
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
105542
105533
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
105543
105534
  currentQuantity: quantity,
105544
105535
  totalSelectedQuantity,
105545
- maxTickets: props.maxTickets,
105546
- availableSpots: props.availableSpots,
105547
- ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
105536
+ maxTickets: props.maxTickets
105548
105537
  });
105549
105538
  return /* @__PURE__ */ jsxs("div", {
105550
105539
  className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
@@ -105649,33 +105638,13 @@ function AttendanceModeTiles(props) {
105649
105638
  })
105650
105639
  });
105651
105640
  }
105652
- function getMaxAllowedTicketCount(input) {
105653
- if (input.canJoinWaitlist) return input.maxTickets;
105654
- if (!input.usesTicketTypes) return Math.min(input.maxTickets, input.availableSpots ?? input.maxTickets);
105655
- if (!input.hasSelectedTicketType) return 1;
105656
- return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
105657
- }
105658
105641
  function resolveTicketSelectionPricing(event) {
105659
105642
  return {
105660
105643
  mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
105661
105644
  currency: event ? publicEventPricingCurrency(event.pricing) : null
105662
105645
  };
105663
105646
  }
105664
- function CheckoutRecoveryEntry(props) {
105665
- return props.onContinue ? /* @__PURE__ */ jsx("button", {
105666
- type: "button",
105667
- className: "er-back-btn",
105668
- onClick: props.onContinue,
105669
- children: "Continue an existing booking"
105670
- }) : null;
105671
- }
105672
- function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
105673
- if (checkoutRecovery) return {
105674
- availableSpots: null,
105675
- isSoldOut: false,
105676
- canJoinWaitlist: false,
105677
- eventAvailabilityLabel: null
105678
- };
105647
+ function getTicketSelectionCapacity(event, attendanceMode) {
105679
105648
  const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
105680
105649
  const availability = source ? getEventAvailability(source) : null;
105681
105650
  const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
@@ -105692,29 +105661,21 @@ var init_TicketSelectionStep = __esmMin((() => {
105692
105661
  init_domain();
105693
105662
  init_utils();
105694
105663
  init_ticketSelectionLines();
105695
- TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" }, checkoutRecovery = false, onCheckoutRecovery }) => {
105664
+ TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
105696
105665
  const unit = bookingUnit.kind;
105697
105666
  const deliveryMode = event?.deliveryMode ?? "in_person";
105698
105667
  const attendanceModes = event?.attendanceModes ?? [];
105699
- const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
105668
+ const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode);
105700
105669
  const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
105701
- const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
105670
+ const usesTicketTypes = eventPricingMode === "tiered";
105702
105671
  const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
105703
105672
  event,
105704
105673
  eligibility: null,
105705
105674
  selectedAttendanceMode
105706
105675
  }) : [];
105707
- const implicitTicketType = usesTicketTypes ? getImplicitSingleAvailableTicketType(visibleTicketTypes) : null;
105708
105676
  const noVisibleTicketTypes = usesTicketTypes && visibleTicketTypes.length === 0;
105709
- const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => ticketType.availability.kind === "available");
105710
- const maxAllowed = getMaxAllowedTicketCount({
105711
- canJoinWaitlist,
105712
- usesTicketTypes,
105713
- maxTickets,
105714
- availableSpots,
105715
- selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
105716
- hasSelectedTicketType: implicitTicketType !== null
105717
- });
105677
+ const hasAvailableTicketTypes = usesTicketTypes && visibleTicketTypes.some((ticketType) => canRequestTicketOption(ticketType.availability));
105678
+ const maxAllowed = maxTickets;
105718
105679
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
105719
105680
  className: "rb-reg-stack er-stack",
105720
105681
  children: [
@@ -105733,20 +105694,6 @@ var init_TicketSelectionStep = __esmMin((() => {
105733
105694
  })
105734
105695
  ]
105735
105696
  });
105736
- if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
105737
- className: "rb-reg-stack er-stack",
105738
- children: [
105739
- /* @__PURE__ */ jsx("h3", {
105740
- className: "er-title",
105741
- children: "Sold out"
105742
- }),
105743
- /* @__PURE__ */ jsx("p", {
105744
- className: "er-text er-text--muted",
105745
- children: "Sorry you missed out! This event is fully booked."
105746
- }),
105747
- /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
105748
- ]
105749
- });
105750
105697
  if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
105751
105698
  className: "rb-reg-stack er-stack",
105752
105699
  children: /* @__PURE__ */ jsx("p", {
@@ -105813,14 +105760,14 @@ var init_TicketSelectionStep = __esmMin((() => {
105813
105760
  })]
105814
105761
  })
105815
105762
  ] }),
105816
- canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
105763
+ isSoldOut && !canJoinWaitlist && /* @__PURE__ */ jsx("p", {
105817
105764
  className: "er-text er-text--muted",
105818
- children: "This event is currently full. Continue to join the waitlist if a place opens up."
105819
- }), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
105820
- checkoutRecovery && /* @__PURE__ */ jsx("p", {
105765
+ children: "This event is fully booked."
105766
+ }),
105767
+ canJoinWaitlist && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("p", {
105821
105768
  className: "er-text er-text--muted",
105822
- children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
105823
- })
105769
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
105770
+ }) })
105824
105771
  ]
105825
105772
  });
105826
105773
  };
@@ -106408,7 +106355,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106408
106355
  const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
106409
106356
  const selectedMethod = selectedSelection.method;
106410
106357
  const totalPrice = directPaymentTotalCents;
106411
- const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
106358
+ const canShowDirectPaymentOptions = Boolean(eligibility?.requiresPayment && eligibility.price);
106412
106359
  const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
106413
106360
  eventTitle: event?.title ?? "Event",
106414
106361
  approvedPaymentOptions: eligibility.paymentOptions,
@@ -106471,7 +106418,7 @@ var init_PaymentSelectionStep = __esmMin((() => {
106471
106418
  onRequestLogin
106472
106419
  });
106473
106420
  if (eligibilityLoading || eligibilityError || !eligibility) return blockingPanel;
106474
- if (eligibility.isFree || !eligibility.eligible) return blockingPanel;
106421
+ if (eligibility.isFree || paymentStepStatus !== "ready") return blockingPanel;
106475
106422
  const isMultiTicket = areEntitlementsDisabledForTicketCount(ticketsCount);
106476
106423
  return /* @__PURE__ */ jsxs("div", {
106477
106424
  className: "rb-reg-stack er-stack",
@@ -106690,7 +106637,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106690
106637
  title,
106691
106638
  body: /* @__PURE__ */ jsx("p", {
106692
106639
  className: "er-text--muted er-message",
106693
- children: message
106640
+ children: onCheckAgain ? message : "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking."
106694
106641
  }),
106695
106642
  actionsClassName: "er-button-group",
106696
106643
  actions: onCheckAgain ? /* @__PURE__ */ jsx("button", {
@@ -106698,11 +106645,7 @@ var init_VerifyingTimeoutStep = __esmMin((() => {
106698
106645
  onClick: onCheckAgain,
106699
106646
  className: "er-btn er-btn--primary",
106700
106647
  children: "Check payment status"
106701
- }) : /* @__PURE__ */ jsx("a", {
106702
- href: "/portal",
106703
- className: "er-btn er-btn--primary",
106704
- children: "Check payment status"
106705
- }),
106648
+ }) : void 0,
106706
106649
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
106707
106650
  className: "er-text--sm er-text--muted er-message",
106708
106651
  children: [
@@ -106892,6 +106835,7 @@ function EventRegistrationWizardContent(props) {
106892
106835
  case "redirecting":
106893
106836
  case "verifying-payment":
106894
106837
  case "verifying-timeout":
106838
+ case "payment-status":
106895
106839
  case "payment-failed": return null;
106896
106840
  case "select-event": return /* @__PURE__ */ jsx(EventSelectionStep, {
106897
106841
  events: wizard.scopedEvents,
@@ -106907,8 +106851,6 @@ function EventRegistrationWizardContent(props) {
106907
106851
  onBookForSomeoneElse: wizard.handleBookForSomeoneElse
106908
106852
  }), /* @__PURE__ */ jsx(TicketSelectionStep, {
106909
106853
  event: wizard.selectedEvent,
106910
- checkoutRecovery: wizard.checkoutRecovery,
106911
- onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
106912
106854
  occurrenceContext: wizard.occurrenceContext,
106913
106855
  selectedAttendanceMode: wizard.selectedAttendanceMode,
106914
106856
  onAttendanceModeChange: wizard.setSelectedAttendanceMode,
@@ -106936,13 +106878,90 @@ var init_EventRegistrationWizardContent = __esmMin((() => {
106936
106878
  init_client();
106937
106879
  init_src();
106938
106880
  init_shared();
106939
- init_checkoutRecovery();
106940
106881
  init_registrationStateMachine();
106941
106882
  init_siteCreditPreview();
106942
106883
  init_PaymentBlockingPanel();
106943
106884
  init_event_registration();
106944
106885
  }));
106945
106886
  //#endregion
106887
+ //#region ../blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.tsx
106888
+ function presentation(state) {
106889
+ switch (state.kind) {
106890
+ case "ready": return {
106891
+ title: "We haven’t confirmed your payment yet",
106892
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment. Select Check payment status to get the latest update.",
106893
+ action: { label: "Check payment status" }
106894
+ };
106895
+ case "checking": return {
106896
+ title: "We haven’t confirmed your payment yet",
106897
+ message: "We’ve saved your booking details, but we haven’t been able to confirm that your payment was successful. Please don’t make another payment.",
106898
+ action: {
106899
+ label: "Checking payment…",
106900
+ disabled: true
106901
+ }
106902
+ };
106903
+ case "processing": return {
106904
+ title: "Your payment is still being processed",
106905
+ message: "Please don’t make another payment. You can check its status again in a moment.",
106906
+ action: { label: "Check payment status" }
106907
+ };
106908
+ case "paymentAvailable": return {
106909
+ title: "Your payment hasn’t been completed",
106910
+ message: "Your booking details are still saved. Continue to payment to finish your booking.",
106911
+ action: { label: "Continue to payment" }
106912
+ };
106913
+ case "retryAvailable": return {
106914
+ title: "Continue your booking",
106915
+ message: "You can return to payment. We’ll check your booking, any existing payment and availability before starting another checkout.",
106916
+ action: { label: "Return to payment" }
106917
+ };
106918
+ case "temporarilyUnavailable": return {
106919
+ title: "We couldn’t check your payment",
106920
+ message: "Please don’t make another payment yet. Try checking again in a moment.",
106921
+ action: { label: "Check payment status" }
106922
+ };
106923
+ case "assistanceRequired": return {
106924
+ title: "We still can’t confirm your payment",
106925
+ message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
106926
+ action: { label: "Return to booking" }
106927
+ };
106928
+ }
106929
+ }
106930
+ function PaymentStatusStep(props) {
106931
+ const view = presentation(props.state);
106932
+ const onClick = props.state.kind === "paymentAvailable" ? props.onContinuePayment : props.state.kind === "retryAvailable" ? props.onReturnToPayment : props.state.kind === "assistanceRequired" ? props.onReturnToBooking : props.onCheck;
106933
+ return /* @__PURE__ */ jsx(TerminalPanel, {
106934
+ tone: "warning",
106935
+ className: "er-center",
106936
+ titleClassName: "er-title--lg er-message",
106937
+ icon: /* @__PURE__ */ jsx(StateIcon, {
106938
+ variant: "warning",
106939
+ children: /* @__PURE__ */ jsx(ClockIcon, {})
106940
+ }),
106941
+ title: view.title,
106942
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
106943
+ className: "er-text--muted er-message",
106944
+ children: view.message
106945
+ }), /* @__PURE__ */ jsx("span", {
106946
+ className: "rb-sr-only",
106947
+ "aria-live": "polite",
106948
+ "aria-atomic": "true",
106949
+ children: props.state.kind === "checking" ? "Checking payment…" : view.title
106950
+ })] }),
106951
+ actionsClassName: "er-button-group",
106952
+ actions: view.action ? /* @__PURE__ */ jsx("button", {
106953
+ type: "button",
106954
+ onClick,
106955
+ disabled: view.action.disabled,
106956
+ className: "er-btn er-btn--primary",
106957
+ children: /* @__PURE__ */ jsx("span", { children: view.action.label })
106958
+ }) : void 0
106959
+ });
106960
+ }
106961
+ var init_PaymentStatusStep = __esmMin((() => {
106962
+ init_shared();
106963
+ }));
106964
+ //#endregion
106946
106965
  //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.tsx
106947
106966
  function EventPortalAuthPrompt(props) {
106948
106967
  return /* @__PURE__ */ jsxs("div", {
@@ -107027,6 +107046,13 @@ function EventRegistrationTerminalState(props) {
107027
107046
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
107028
107047
  supportEmail: props.supportEmail
107029
107048
  });
107049
+ case "payment-status": return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
107050
+ state: wizard.paymentStatusRecovery,
107051
+ onCheck: wizard.handleCheckPaymentStatus,
107052
+ onContinuePayment: wizard.handleContinueExistingPayment,
107053
+ onReturnToPayment: wizard.handleReturnToPayment,
107054
+ onReturnToBooking: wizard.handleReturnToBooking
107055
+ }) : null;
107030
107056
  case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
107031
107057
  title: wizard.registrationResult.title,
107032
107058
  variant: wizard.registrationResult.variant,
@@ -107035,7 +107061,7 @@ function EventRegistrationTerminalState(props) {
107035
107061
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
107036
107062
  message: wizard.errorMessage,
107037
107063
  action: wizard.errorAction,
107038
- canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
107064
+ canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
107039
107065
  onRetry: wizard.handleRetry
107040
107066
  });
107041
107067
  case "select-event":
@@ -107097,6 +107123,7 @@ var init_EventRegistrationSurface = __esmMin((() => {
107097
107123
  init_EventRegistrationWizardActions();
107098
107124
  init_EventRegistrationWizardContent();
107099
107125
  init_PaymentFailedStep();
107126
+ init_PaymentStatusStep();
107100
107127
  init_StepIndicator();
107101
107128
  init_SuccessStep();
107102
107129
  init_VerifyingPaymentStep();
@@ -107234,6 +107261,7 @@ function getWizardStepLabel(input) {
107234
107261
  case "redirecting":
107235
107262
  case "verifying-payment":
107236
107263
  case "verifying-timeout":
107264
+ case "payment-status":
107237
107265
  case "payment-failed": return "";
107238
107266
  }
107239
107267
  }
@@ -153475,44 +153503,10 @@ function ThemeScope$1({ theme, children, themeId = "theme-default", responsiveMo
153475
153503
  //#endregion
153476
153504
  //#region ../blocks/src/system/blocks/site-footer-runtime.ts
153477
153505
  init_src$2();
153478
- /**
153479
- * Resolve what to render for the footer given the current mode and whether the
153480
- * site is SDK-managed.
153481
- *
153482
- * Backwards compatible: missing/undefined mode is treated as 'default'.
153483
- */
153484
- function resolveFooterRenderPlan(params) {
153485
- if (!params.isSdkSite) return {
153486
- mode: "default",
153487
- renderDefaultFooter: true,
153488
- renderFooterBlocks: false
153489
- };
153490
- switch (params.mode ?? "default") {
153491
- case "blocks": return {
153492
- mode: "blocks",
153493
- renderDefaultFooter: false,
153494
- renderFooterBlocks: true
153495
- };
153496
- case "default+blocks": return {
153497
- mode: "default+blocks",
153498
- renderDefaultFooter: true,
153499
- renderFooterBlocks: true
153500
- };
153501
- case "none": return {
153502
- mode: "none",
153503
- renderDefaultFooter: false,
153504
- renderFooterBlocks: false
153505
- };
153506
- default: return {
153507
- mode: "default",
153508
- renderDefaultFooter: true,
153509
- renderFooterBlocks: false
153510
- };
153511
- }
153512
- }
153513
153506
  //#endregion
153514
153507
  //#region ../blocks/src/rendering/server.ts
153515
153508
  init_schema();
153509
+ init_mode();
153516
153510
  //#endregion
153517
153511
  //#region ../theme-core/src/ResponsiveScope.tsx
153518
153512
  /**
@@ -156006,6 +156000,7 @@ init_buttons();
156006
156000
  init_cards();
156007
156001
  init_tokens();
156008
156002
  init_gradients();
156003
+ init_mode();
156009
156004
  init_richTextSchema();
156010
156005
  init_media();
156011
156006
  init_media$1();
@@ -156181,11 +156176,7 @@ function buildFooterRenderablePageOutline(siteData, blocks) {
156181
156176
  }
156182
156177
  //#endregion
156183
156178
  //#region src/rendering/components/Layout.tsx
156184
- /**
156185
- * Layout component with header and footer
156186
- *
156187
- * Renders site header and footer around content. Fetches site data if not provided.
156188
- */
156179
+ init_mode();
156189
156180
  function isOverrideOnlyLayout(props) {
156190
156181
  return props.rendering?.kind === "overrides-only";
156191
156182
  }
@@ -156360,7 +156351,7 @@ async function Layout(props) {
156360
156351
  if (footer === true) {
156361
156352
  const footerPlan = resolveFooterRenderPlan({
156362
156353
  isSdkSite: Boolean(site.is_sdk_site),
156363
- mode: theme.footer?.mode
156354
+ mode: resolveSdkFooterMode(siteData.sdkConfig)
156364
156355
  });
156365
156356
  const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
156366
156357
  theme,
@@ -157688,6 +157679,17 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
157688
157679
  //#region ../api/src/publicEventEndpointDefinitions.ts
157689
157680
  init_src$2();
157690
157681
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
157682
+ checkPublicEventRegistrationNextStep: {
157683
+ path: "/public/sites/{siteId}/events/registration-next-step",
157684
+ method: "POST",
157685
+ auth: "public",
157686
+ responseKind: "json",
157687
+ errors: [
157688
+ "validation:invalid_input",
157689
+ "auth:forbidden",
157690
+ "server:internal_error"
157691
+ ]
157692
+ },
157691
157693
  listPublicEventCalendarWindow: {
157692
157694
  path: "/public/sites/{siteId}/events/calendar-window",
157693
157695
  method: "GET",
@@ -158748,6 +158750,7 @@ function internalNavigationLinkToLocalLink(item) {
158748
158750
  }
158749
158751
  //#endregion
158750
158752
  //#region ../api/src/sdkConfig/contracts.ts
158753
+ init_mode();
158751
158754
  init_src$2();
158752
158755
  /**
158753
158756
  * Canonical SDK config Zod contracts.
@@ -158920,11 +158923,14 @@ const sdkSiteStyleConfigSchema = z$1.object({
158920
158923
  sectionOptions: sdkSectionOptionsConfigSchema.optional(),
158921
158924
  containerOptions: sdkContainerOptionsConfigSchema.optional()
158922
158925
  });
158923
- const sdkSiteLayoutConfigSchema = z$1.object({ footerBlocks: z$1.array(z$1.object({
158924
- id: z$1.string().min(1).optional(),
158925
- kind: z$1.string().min(1),
158926
- content: z$1.record(z$1.string(), z$1.unknown()).optional()
158927
- })).optional() });
158926
+ const sdkSiteLayoutConfigSchema = z$1.object({
158927
+ footerMode: footerModeSchema.optional(),
158928
+ footerBlocks: z$1.array(z$1.object({
158929
+ id: z$1.string().min(1).optional(),
158930
+ kind: z$1.string().min(1),
158931
+ content: z$1.record(z$1.string(), z$1.unknown()).optional()
158932
+ })).optional()
158933
+ });
158928
158934
  const sdkFieldSelectOptionSchema = z$1.object({
158929
158935
  value: z$1.string(),
158930
158936
  label: z$1.string()