@riverbankcms/sdk 0.136.0 → 0.137.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 (160) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/{PreviewEditorSidebar-BU5ZlhQR.mjs → PreviewEditorSidebar-Bn6cONPa.mjs} +8 -8
  3. package/dist/{PreviewEditorUI-9XkHL-bC.mjs → PreviewEditorUI-LAwXZPSx.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-wbEpXryy.mjs → PreviewQueryProvider-ztQUdsNo.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-CnWmj-2B.mjs → SdkPreviewModeRuntime-BbbGsI_v.mjs} +596 -164
  6. package/dist/{SiteChromeCustomizeContext-B6d5zkog.mjs → SiteChromeCustomizeContext-BbkNSt5a.mjs} +2888 -1404
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +12 -298
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +21 -14
  9. package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
  10. package/dist/_dts/api/src/accessAdmin.d.ts +1 -9
  11. package/dist/_dts/api/src/accountApi.d.ts +49 -2
  12. package/dist/_dts/api/src/contentRuntime.d.ts +1 -4
  13. package/dist/_dts/api/src/domainConnection.d.ts +41 -0
  14. package/dist/_dts/api/src/endpoints.d.ts +194 -181
  15. package/dist/_dts/api/src/index.d.ts +4 -3
  16. package/dist/_dts/api/src/media.d.ts +19 -2
  17. package/dist/_dts/api/src/sdkContracts.d.ts +2 -15
  18. package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
  19. package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +61 -0
  20. package/dist/_dts/api/src/sdkThemeWire.d.ts +15 -4
  21. package/dist/_dts/api/src/siteInfrastructure.d.ts +17 -23
  22. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +7 -21
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +27 -3
  24. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
  25. package/dist/_dts/api/src/types.d.ts +1 -1
  26. package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -2
  27. package/dist/_dts/blocks/src/index.d.ts +1 -1
  28. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +9 -0
  29. package/dist/_dts/blocks/src/pageRendererBlockSupport.d.ts +75 -0
  30. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +2 -0
  31. package/dist/_dts/blocks/src/server.d.ts +1 -1
  32. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -1
  33. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  34. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -3
  35. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +34 -22
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -0
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -3
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +5 -2
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +31 -0
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
  54. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +1 -1
  56. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
  57. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
  58. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
  59. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
  60. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +8 -40
  61. package/dist/_dts/db/src/index.d.ts +1 -0
  62. package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
  63. package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
  64. package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
  65. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
  66. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  67. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
  68. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
  69. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
  70. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
  71. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
  72. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
  73. package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
  74. package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
  75. package/dist/_dts/sdk/src/version.d.ts +1 -1
  76. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  77. package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
  78. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +25 -2
  79. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +3 -3
  80. package/dist/_dts/theme-core/src/schema.d.ts +12 -11
  81. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
  82. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +10 -0
  83. package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
  84. package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
  85. package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
  86. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -9
  87. package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
  88. package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
  89. package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
  90. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +10 -1
  91. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +1 -1
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +7 -0
  93. package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
  94. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
  95. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
  96. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
  97. package/dist/client/{BookingConsentAgreement-DCch21a6.mjs → BookingConsentAgreement--_fUCZe-.mjs} +2 -2
  98. package/dist/client/{DiscountCodeDisclosure-DIj1T59K.mjs → DiscountCodeDisclosure-BMipSoDJ.mjs} +1 -1
  99. package/dist/client/{EventCombined.client-BWVNlXTx.mjs → EventCombined.client-CwJOxn7A.mjs} +154 -178
  100. package/dist/client/{EventListing.client-DVFCDe3i.mjs → EventListing.client-eVwiylPW.mjs} +2 -2
  101. package/dist/client/{LeafletStaticMap-BY5mIHw9.mjs → LeafletStaticMap-IKenna5u.mjs} +1 -1
  102. package/dist/client/{accordion-CK29E8rG.mjs → accordion-MGAO3PuE.mjs} +1 -1
  103. package/dist/client/{bookingForm-DFvnet-N.mjs → bookingForm-CudlQPUu.mjs} +5 -5
  104. package/dist/client/bookings.mjs +418 -79
  105. package/dist/client/capacity-BW00PO7s.mjs +271 -0
  106. package/dist/client/{carousel-BVU5NQlb.mjs → carousel-BrbGJ2Jl.mjs} +1 -1
  107. package/dist/client/{cart-BNItcZVa.mjs → cart-Bq5eU0xZ.mjs} +3 -3
  108. package/dist/client/{checkout-Bu6iCdkP.mjs → checkout-BAFVRdrK.mjs} +3 -3
  109. package/dist/client/client.mjs +2919 -1918
  110. package/dist/client/{context-BImarOAq.mjs → context-DCkiHVdD.mjs} +8 -5
  111. package/dist/client/dates-2RPXHQy4.mjs +264 -0
  112. package/dist/client/{eventCalendar-DS2h-UXD.mjs → eventCalendar-B0O-hPF7.mjs} +10 -17
  113. package/dist/client/{eventCombined-Drt4Oq9p.mjs → eventCombined-DCkDaoDI.mjs} +3 -3
  114. package/dist/client/{eventDetails-Bl2vWgTX.mjs → eventDetails-D8GG2dnD.mjs} +5 -3
  115. package/dist/client/{eventListing-CS7PHY7v.mjs → eventListing-3ssV_bxz.mjs} +3 -3
  116. package/dist/client/{eventRegistration-D-j8eNy2.mjs → eventRegistration-bPQo3kVw.mjs} +562 -309
  117. package/dist/client/{form-RMpoLTyr.mjs → form-qMv8RDkk.mjs} +2 -2
  118. package/dist/client/{headerSection-BYE3Lb3k.mjs → headerSection-CH0Sc5hX.mjs} +2 -2
  119. package/dist/client/hooks.mjs +289 -32
  120. package/dist/client/{locationMap-BxSr7Kkh.mjs → locationMap-0_xlBnNI.mjs} +2 -2
  121. package/dist/client/{newsletterForm-DerbXwFC.mjs → newsletterForm-NUW7m9RI.mjs} +2 -2
  122. package/dist/client/{productDetail-4SZCLhAf.mjs → productDetail-FBEOM7jW.mjs} +3 -3
  123. package/dist/client/{productList-D7AP4GNq.mjs → productList-R0OSGhnn.mjs} +3 -3
  124. package/dist/client/{propsDecoder-pzBeCh14.mjs → propsDecoder-pYvx_Srl.mjs} +88 -380
  125. package/dist/client/rendering/client.mjs +2616 -1637
  126. package/dist/client/rendering/islands.mjs +17 -17
  127. package/dist/client/rendering.mjs +2710 -1702
  128. package/dist/client/{scrollToBlock-CduAKf8T.mjs → scrollToBlock-ByQv96M2.mjs} +1 -1
  129. package/dist/client/{shop-Cp5p_kGe.mjs → shop-RUG9DmRE.mjs} +6 -6
  130. package/dist/client/{shop-commerce-DicXYaYX.mjs → shop-commerce-B76Jz23B.mjs} +5 -5
  131. package/dist/client/{shop-commerce-store-CGWnpY4K.mjs → shop-commerce-store-QuQNdDsD.mjs} +1 -1
  132. package/dist/client/{shopShared-BDf9ljkm.mjs → shopShared-vXU1omwJ.mjs} +3 -3
  133. package/dist/client/{useEventFilters-DeeyGYuk.mjs → useEventFilters-ByuU6HLA.mjs} +33 -18
  134. package/dist/preview-next/before-render.mjs +79 -51
  135. package/dist/preview-next/client/runtime.mjs +4 -4
  136. package/dist/preview-next/keepAlive.mjs +79 -51
  137. package/dist/preview-next/middleware.mjs +79 -51
  138. package/dist/{previewAuthStore-DbqBol0V.mjs → previewAuthStore-L_cKW8Sb.mjs} +79 -51
  139. package/dist/{sdk-runtime-19MO27F0.mjs → sdk-runtime-sUMr5d70.mjs} +2 -2
  140. package/dist/{separator-DaPLtJ1f.mjs → separator-BIHkie5i.mjs} +1 -1
  141. package/dist/server/components.mjs +2077 -1274
  142. package/dist/server/config-validation.mjs +289 -32
  143. package/dist/server/config.mjs +289 -32
  144. package/dist/server/data.mjs +289 -32
  145. package/dist/server/index.mjs +80 -52
  146. package/dist/server/next.mjs +1822 -1111
  147. package/dist/server/page-converter.mjs +167 -31
  148. package/dist/server/prebuild.mjs +1 -1
  149. package/dist/server/rendering/server.mjs +1988 -1286
  150. package/dist/server/rendering.mjs +1943 -1182
  151. package/dist/server/routing.mjs +351 -86
  152. package/dist/server/server.mjs +293 -128
  153. package/dist/server/theme-bridge.mjs +52 -8
  154. package/dist/server/theme.mjs +27 -8
  155. package/dist/styles/index.css +15 -0
  156. package/package.json +1 -1
  157. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
  158. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
  159. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
  160. /package/dist/_dts/blocks/src/system/runtime/nodes/events/{shared → domain}/destination.d.ts +0 -0
@@ -1,10 +1,11 @@
1
1
  "use client";
2
- import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator$1, o as resolveBookingPaymentDueNowCents, r as SpinnerNode, s as formatPrice, t as BookingConsentAgreement } from "./BookingConsentAgreement-DCch21a6.mjs";
3
- import { $t as publicEventScalarPrice, At as assertNever, Bt as formatBookingDateTime, C as getStepNumber, Ht as formatBookingTime, Jt as toBookingTimeZone, O as resolveEventRegistrationScopedEvents, Qt as publicEventPricingType, S as WIZARD_STEPS, T as planEventRegistrationSurface, V as formatEventPriceDisplay, Xt as publicEventPricingCurrency, Y as resolveRuntimeEventPricing, Yt as toScheduledBookingDateTime, Zt as publicEventPricingMode, _ as findEventByOccurrenceId, b as resolveEventRequiresPayment, en as publicEventTicketTypes, g as toWholeSeriesRegistrationEvents, h as toRegistrationEvents, st as themeButtonClassName, t as defineIslandPropsDecoder, tn as formatCurrencyAmount, v as findPreSelectedEvent, w as getWizardStepsForContext, x as resolveRegistrationTarget, y as resolveDiscountContext, zt as formatBookingDate } from "./propsDecoder-pzBeCh14.mjs";
4
- import { n as useBlockApi, t as BlockApiProvider } from "./context-BImarOAq.mjs";
2
+ import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator$1, o as resolveBookingPaymentDueNowCents, r as SpinnerNode, s as formatPrice, t as BookingConsentAgreement } from "./BookingConsentAgreement--_fUCZe-.mjs";
3
+ import { At as formatBookingDateTime, B as formatEventPriceDisplay, Bt as toScheduledBookingDateTime, C as getStepNumber, Gt as publicEventTicketTypes, Ht as publicEventPricingMode, Kt as formatCurrencyAmount, Mt as formatBookingTime, O as resolveEventRegistrationScopedEvents, Ot as formatBookingDate, Rt as toBookingTimeZone, S as WIZARD_STEPS, T as planEventRegistrationSurface, Ut as publicEventPricingType, V as resolveRuntimeEventPricing, Vt as publicEventPricingCurrency, Wt as publicEventScalarPrice, X as themeButtonClassName, _ as findEventByOccurrenceId, b as resolveEventRequiresPayment, g as toWholeSeriesRegistrationEvents, h as toRegistrationEvents, t as defineIslandPropsDecoder, v as findPreSelectedEvent, w as getWizardStepsForContext, x as resolveRegistrationTarget, y as resolveDiscountContext, yt as assertNever } from "./propsDecoder-pYvx_Srl.mjs";
4
+ import { a as formatTicketTypeRemaining, d as selectEventCapacitySource, f as selectMostOpenCapacitySource, i as formatRemainingPlaces, l as getRemainingPlaces, n as canJoinEventWaitlistOnAnyMode, r as formatEventRemainingPlaces, s as getEventAvailability, t as canJoinEventWaitlist, u as isEventFull } from "./capacity-BW00PO7s.mjs";
5
+ import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-DCkiHVdD.mjs";
5
6
  import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
6
- import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-CduAKf8T.mjs";
7
- import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-DIj1T59K.mjs";
7
+ import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-ByQv96M2.mjs";
8
+ import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-BMipSoDJ.mjs";
8
9
  import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
9
10
  import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
10
11
  import { t as buildCheckoutReturnUrls } from "./checkoutUrls-BuseL0dw.mjs";
@@ -713,10 +714,12 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
713
714
  className: "er-event-grid",
714
715
  children: events.map((event) => {
715
716
  const isSelected = selectedEvent?.selectionId === event.selectionId;
716
- const isSoldOut = event.capacity !== null && event.availableSpots === 0;
717
- const canJoinWaitlist = isSoldOut && event.waitlistEnabled === true;
717
+ const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
718
+ const isSoldOut = isEventFull(event);
719
+ const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
718
720
  const isUnavailable = isSoldOut && !canJoinWaitlist;
719
- const isLowCapacity = event.availableSpots !== null && event.availableSpots <= 5 && !isSoldOut;
721
+ const isLowCapacity = remaining.kind === "low";
722
+ const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
720
723
  const timeZone = event.timeZone ?? null;
721
724
  const cardClasses = [
722
725
  "er-event-card",
@@ -748,9 +751,9 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
748
751
  children: " · "
749
752
  }), event.venue.name] })]
750
753
  })]
751
- }), showCapacity && event.capacity !== null && /* @__PURE__ */ jsx("span", {
754
+ }), showCapacity && capacityLabel && /* @__PURE__ */ jsx("span", {
752
755
  className: badgeClasses,
753
- children: canJoinWaitlist ? "Waitlist" : isUnavailable ? "Sold Out" : `${event.availableSpots ?? 0} spots left`
756
+ children: capacityLabel
754
757
  })]
755
758
  })
756
759
  }, event.selectionId);
@@ -759,6 +762,61 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
759
762
  });
760
763
  };
761
764
  //#endregion
765
+ //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
766
+ function resolveRegistrationRecoveryAction(step, action) {
767
+ if (step === "payment-failed") return "payment-options";
768
+ if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
769
+ return action;
770
+ }
771
+ function canRecoverToWaitlist(eligibility) {
772
+ return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
773
+ }
774
+ function shouldRefreshAfterRegistrationError(step, action, enabled) {
775
+ return enabled || step === "error" && action === "places";
776
+ }
777
+ function resetRegistrationAfterExpiry(input) {
778
+ input.dispatchFlow({
779
+ type: "reset",
780
+ hasPreSelectedContext: input.hasPreSelectedContext
781
+ });
782
+ input.setSelectedTicketLines([]);
783
+ input.setSelectedSlidingAmountInput("");
784
+ const mode = input.preSelectedEvent?.deliveryMode;
785
+ input.setSelectedAttendanceMode(mode === "online" || mode === "in_person" ? mode : null);
786
+ input.setErrorMessage("");
787
+ input.setPendingRegistrationReference(null);
788
+ }
789
+ /** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
790
+ function recoverRegistrationError(action, handlers) {
791
+ switch (action) {
792
+ case "none": return;
793
+ case "portal":
794
+ case "payment-status":
795
+ window.location.assign("/portal");
796
+ return;
797
+ case "event":
798
+ window.location.assign(window.location.pathname);
799
+ return;
800
+ case "retry":
801
+ window.location.reload();
802
+ return;
803
+ case "details":
804
+ handlers.clearError();
805
+ handlers.setStep("enter-details");
806
+ return;
807
+ case "payment-options":
808
+ case "places":
809
+ handlers.refreshOptions();
810
+ handlers.clearError();
811
+ handlers.setStep(action === "places" ? handlers.canJoinWaitlist ? "enter-details" : "select-tickets" : "select-payment");
812
+ return;
813
+ case "start":
814
+ handlers.refreshOptions();
815
+ handlers.reset();
816
+ return;
817
+ }
818
+ }
819
+ //#endregion
762
820
  //#region ../blocks/src/system/runtime/nodes/event-registration/validation.ts
763
821
  function createInitialRegistrationFormData() {
764
822
  return {
@@ -1002,11 +1060,11 @@ function useEligibilityWithDeps(params, deps) {
1002
1060
  type: "resolved",
1003
1061
  eligibility: transformRegistrationOptionsResponse(result)
1004
1062
  });
1005
- } catch (err) {
1063
+ } catch {
1006
1064
  if (cancelled || requestIdRef.current !== requestId) return;
1007
1065
  dispatch({
1008
1066
  type: "failed",
1009
- message: err instanceof Error ? err.message : "Failed to check eligibility"
1067
+ message: "We couldn’t load the booking options for this event. Please refresh this page and try again. If this keeps happening, contact the organiser for help."
1010
1068
  });
1011
1069
  }
1012
1070
  }
@@ -1018,6 +1076,7 @@ function useEligibilityWithDeps(params, deps) {
1018
1076
  }, [
1019
1077
  api,
1020
1078
  params.enabled,
1079
+ params.refreshKey,
1021
1080
  params.subject?.kind,
1022
1081
  params.subject?.kind === "occurrence" ? params.subject.occurrenceId : params.subject?.eventSeriesId,
1023
1082
  params.attendanceMode,
@@ -1127,8 +1186,252 @@ function logoutPortal(anchorId) {
1127
1186
  form.submit();
1128
1187
  }
1129
1188
  //#endregion
1189
+ //#region ../commerce/src/purchase/checkoutPaymentFlow.ts
1190
+ function planCheckoutPaymentFlow(options) {
1191
+ const amountDueCents = toNonNegativeCents(options.amountDueCents);
1192
+ const discountCents = toNonNegativeCents(options.discountCents);
1193
+ const availableCreditCents = toNonNegativeCents(options.availableCreditCents);
1194
+ const minimumStripeChargeCents = toNonNegativeCents(options.minimumStripeChargeCents ?? 0);
1195
+ if (amountDueCents <= 0) return {
1196
+ kind: "bypass",
1197
+ bypassReason: discountCents > 0 ? "discount_free" : "free",
1198
+ reserveCreditCents: 0
1199
+ };
1200
+ if (!options.creditCurrencyMatches || availableCreditCents <= 0) return {
1201
+ kind: "stripe",
1202
+ reserveCreditCents: toNonNegativeCents(0)
1203
+ };
1204
+ if (availableCreditCents >= amountDueCents) return {
1205
+ kind: "store_credit_only",
1206
+ reserveCreditCents: amountDueCents
1207
+ };
1208
+ return {
1209
+ kind: "stripe",
1210
+ reserveCreditCents: planMixedPaymentCreditReservation({
1211
+ amountDueCents,
1212
+ availableCreditCents,
1213
+ minimumStripeChargeCents
1214
+ })
1215
+ };
1216
+ }
1217
+ function planMixedPaymentCreditReservation(input) {
1218
+ const chargeAfterFullCredit = input.amountDueCents - input.availableCreditCents;
1219
+ if (input.minimumStripeChargeCents <= 0 || chargeAfterFullCredit <= 0 || chargeAfterFullCredit >= input.minimumStripeChargeCents) return input.availableCreditCents;
1220
+ if (input.amountDueCents < input.minimumStripeChargeCents) return toNonNegativeCents(0);
1221
+ return toNonNegativeCents(input.amountDueCents - input.minimumStripeChargeCents);
1222
+ }
1223
+ /**
1224
+ * Apply site credit to a flexible-balance booking before card payment.
1225
+ *
1226
+ * Credit first reduces the configured payment due now. Once that payment is
1227
+ * covered, any remaining credit reduces the later balance. If a partial credit
1228
+ * application would leave a positive card charge below Stripe's minimum, less
1229
+ * credit is used so the configured payment can still be collected.
1230
+ */
1231
+ function planFlexibleBalanceCreditFirst(input) {
1232
+ const totalCents = toNonNegativeCents(input.totalAfterDiscountCents);
1233
+ const configuredDueNowCents = toNonNegativeCents(Math.min(input.configuredPaymentDueNowCents, totalCents));
1234
+ const availableCreditCents = toNonNegativeCents(input.creditCurrencyMatches ? input.availableCreditCents : 0);
1235
+ const minimumStripeChargeCents = toNonNegativeCents(input.minimumStripeChargeCents ?? 0);
1236
+ if (availableCreditCents >= totalCents && totalCents > 0) return {
1237
+ kind: "credit_only",
1238
+ reserveCreditCents: totalCents,
1239
+ cardDueNowCents: toNonNegativeCents(0),
1240
+ laterBalanceCents: toNonNegativeCents(0)
1241
+ };
1242
+ let reserveCreditCents = toNonNegativeCents(Math.min(availableCreditCents, totalCents));
1243
+ if (reserveCreditCents >= configuredDueNowCents) return {
1244
+ kind: "flexible_balance",
1245
+ reserveCreditCents,
1246
+ cardDueNowCents: toNonNegativeCents(0),
1247
+ laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents)
1248
+ };
1249
+ const plannedCardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
1250
+ if (plannedCardDueNowCents > 0 && plannedCardDueNowCents < minimumStripeChargeCents) {
1251
+ if (configuredDueNowCents < minimumStripeChargeCents) return {
1252
+ kind: "card_below_minimum",
1253
+ reserveCreditCents: toNonNegativeCents(0),
1254
+ cardDueNowCents: configuredDueNowCents,
1255
+ laterBalanceCents: toNonNegativeCents(totalCents - configuredDueNowCents)
1256
+ };
1257
+ reserveCreditCents = toNonNegativeCents(configuredDueNowCents - minimumStripeChargeCents);
1258
+ }
1259
+ const cardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
1260
+ return {
1261
+ kind: "flexible_balance",
1262
+ reserveCreditCents,
1263
+ cardDueNowCents,
1264
+ laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents - cardDueNowCents)
1265
+ };
1266
+ }
1267
+ //#endregion
1268
+ //#region ../commerce/src/purchase/settlement.ts
1269
+ function normalizeCurrencyCode(raw) {
1270
+ const normalized = raw.trim().toUpperCase();
1271
+ if (!/^[A-Z]{3}$/.test(normalized)) throw new Error(`Invalid currency code: ${raw}`);
1272
+ return normalized;
1273
+ }
1274
+ //#endregion
1275
+ //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
1276
+ const datedOfferingSharedEngineMetadataShape = {
1277
+ datedOfferingEngineContractVersion: z.literal("shared_v1"),
1278
+ datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
1279
+ datedOfferingCapacityHoldId: z.string().uuid(),
1280
+ datedOfferingCapacityHoldAuditRef: z.string().uuid(),
1281
+ customerId: z.string().uuid(),
1282
+ eventSeriesId: z.string().uuid()
1283
+ };
1284
+ z.object(datedOfferingSharedEngineMetadataShape);
1285
+ const orderCheckoutSessionMetadataBaseShape = {
1286
+ type: z.literal("order"),
1287
+ site_id: z.string().uuid(),
1288
+ order_id: z.string().uuid().optional(),
1289
+ customer_email: z.string().email(),
1290
+ customer_name: z.string().optional(),
1291
+ product_id: z.string().uuid().optional(),
1292
+ attendee_id: z.string().uuid().optional(),
1293
+ occurrence_id: z.string().uuid().optional(),
1294
+ tickets_count: z.string().optional(),
1295
+ notes: z.string().optional(),
1296
+ discount_redemption_id: z.string().uuid().optional(),
1297
+ discount_code_id: z.string().uuid().optional(),
1298
+ discount_code: z.string().optional(),
1299
+ discount_public_label: z.string().optional(),
1300
+ credit_reservation_id: z.string().uuid().optional(),
1301
+ credit_reserved_cents: z.string().optional(),
1302
+ discount_code_amount_cents: z.string().optional(),
1303
+ order_payment_reason: z.enum([
1304
+ "instalment_payoff",
1305
+ "flexible_balance_initial",
1306
+ "flexible_balance_paydown"
1307
+ ]).optional(),
1308
+ order_payment_plan_id: z.string().uuid().optional(),
1309
+ order_flexible_balance_contract_id: z.string().uuid().optional()
1310
+ };
1311
+ const absentDatedOfferingSharedEngineMetadataShape = {
1312
+ datedOfferingEngineContractVersion: z.never().optional(),
1313
+ datedOfferingEngineRouteKind: z.never().optional(),
1314
+ datedOfferingCapacityHoldId: z.never().optional(),
1315
+ datedOfferingCapacityHoldAuditRef: z.never().optional(),
1316
+ customerId: z.never().optional(),
1317
+ eventSeriesId: z.never().optional()
1318
+ };
1319
+ const LegacyOrderCheckoutSessionMetadataSchema = z.object({
1320
+ ...orderCheckoutSessionMetadataBaseShape,
1321
+ ...absentDatedOfferingSharedEngineMetadataShape
1322
+ });
1323
+ const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
1324
+ ...orderCheckoutSessionMetadataBaseShape,
1325
+ ...datedOfferingSharedEngineMetadataShape
1326
+ });
1327
+ z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
1328
+ toNonNegativeCents(0);
1329
+ //#endregion
1330
+ //#region ../commerce/src/purchase/stripeMinimumCharge.ts
1331
+ const STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY = {
1332
+ GBP: 30,
1333
+ USD: 50,
1334
+ EUR: 50,
1335
+ AED: 200,
1336
+ AUD: 50,
1337
+ BGN: 100,
1338
+ BRL: 50,
1339
+ CAD: 50,
1340
+ CHF: 50,
1341
+ CZK: 1500,
1342
+ DKK: 250,
1343
+ HKD: 400,
1344
+ HUF: 17500,
1345
+ JPY: 50,
1346
+ MXN: 1e3,
1347
+ MYR: 200,
1348
+ NOK: 300,
1349
+ NZD: 50,
1350
+ PLN: 200,
1351
+ RON: 200,
1352
+ SEK: 300,
1353
+ SGD: 50,
1354
+ THB: 1e3
1355
+ };
1356
+ function isStripeMinimumChargeCurrency(currency) {
1357
+ return currency in STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY;
1358
+ }
1359
+ function getStripeMinimumChargeRequirement(rawCurrency) {
1360
+ let currency;
1361
+ try {
1362
+ currency = normalizeCurrencyCode(rawCurrency);
1363
+ } catch {
1364
+ return null;
1365
+ }
1366
+ const currencyKey = currency;
1367
+ if (!isStripeMinimumChargeCurrency(currencyKey)) return null;
1368
+ return {
1369
+ currency,
1370
+ minimumAmountCents: STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY[currencyKey]
1371
+ };
1372
+ }
1373
+ //#endregion
1374
+ //#region ../commerce/src/purchase/event-registration-errors.ts
1375
+ const eventRegistrationErrors = {
1376
+ registrationClosed: {
1377
+ message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
1378
+ action: "none"
1379
+ },
1380
+ paymentUncertain: {
1381
+ 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.",
1382
+ action: "payment-status"
1383
+ },
1384
+ paymentPageUnavailable: {
1385
+ message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
1386
+ action: "retry"
1387
+ },
1388
+ paymentUnavailable: {
1389
+ message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
1390
+ action: "none"
1391
+ },
1392
+ capacityChanged: {
1393
+ message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
1394
+ action: "places"
1395
+ },
1396
+ selectionChanged: {
1397
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
1398
+ action: "places"
1399
+ },
1400
+ registrationPreparationChanged: {
1401
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
1402
+ action: "places"
1403
+ },
1404
+ registrationAlreadyExists: {
1405
+ message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
1406
+ action: "portal"
1407
+ },
1408
+ holdExpired: {
1409
+ message: "Your reservation has timed out. Please check availability and choose your places again.",
1410
+ action: "start"
1411
+ },
1412
+ waitlistUnavailable: {
1413
+ message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
1414
+ action: "event"
1415
+ },
1416
+ paymentContextMismatch: {
1417
+ message: "The payment options for this event have changed. Please check the latest options before continuing.",
1418
+ action: "payment-options"
1419
+ },
1420
+ idempotencyConflict: {
1421
+ message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
1422
+ action: "portal"
1423
+ },
1424
+ invalidCommitInput: {
1425
+ message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
1426
+ action: "details"
1427
+ }
1428
+ };
1429
+ function parseEventRegistrationErrorReason(value) {
1430
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
1431
+ }
1432
+ //#endregion
1130
1433
  //#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
1131
- const DEFAULT_WAITLIST_CLAIM_ERROR = "Failed to resolve waitlist claim";
1434
+ const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
1132
1435
  function createInitialWaitlistClaimState(hasToken) {
1133
1436
  return hasToken ? { kind: "resolving" } : { kind: "idle" };
1134
1437
  }
@@ -1144,14 +1447,13 @@ function waitlistClaimReducer(_state, action) {
1144
1447
  }
1145
1448
  }
1146
1449
  function toWaitlistClaimResolveFailure(error) {
1147
- const message = error instanceof Error ? error.message : DEFAULT_WAITLIST_CLAIM_ERROR;
1148
1450
  if (isUnauthorizedBlockApiError(error)) return {
1149
1451
  kind: "portal-login-required",
1150
- message
1452
+ message: "Please log in to continue with your waiting list invitation."
1151
1453
  };
1152
1454
  return {
1153
1455
  kind: "error",
1154
- message
1456
+ message: hasStatus(error) && (error.status === 404 || error.status === 409 || error.status === 410) ? eventRegistrationErrors.waitlistUnavailable.message : DEFAULT_WAITLIST_CLAIM_ERROR
1155
1457
  };
1156
1458
  }
1157
1459
  function isUnauthorizedBlockApiError(error) {
@@ -1512,11 +1814,21 @@ function cleanupStaleRegistrations() {
1512
1814
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
1513
1815
  const eventRegistrationStripeReturnDeps = {
1514
1816
  usePaymentVerification,
1515
- consumeReturnParams: () => consumeSearchParams([
1516
- "registration",
1517
- EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
1518
- "session_id"
1519
- ]),
1817
+ readReturnParams: () => {
1818
+ const params = new URLSearchParams(window.location.search);
1819
+ return {
1820
+ registration: params.get("registration"),
1821
+ registration_attempt: params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM),
1822
+ session_id: params.get("session_id")
1823
+ };
1824
+ },
1825
+ clearReturnParams: () => {
1826
+ consumeSearchParams([
1827
+ "registration",
1828
+ EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
1829
+ "session_id"
1830
+ ]);
1831
+ },
1520
1832
  scrollToBlock,
1521
1833
  cleanupStaleRegistrations,
1522
1834
  clearPendingRegistration,
@@ -1537,52 +1849,66 @@ function showReturnReconciliation(options, message) {
1537
1849
  options.setErrorMessage(message);
1538
1850
  options.setStep("verifying-timeout");
1539
1851
  }
1852
+ function checkoutReturnCommand(params) {
1853
+ const checkoutAttemptId = params.registration_attempt;
1854
+ if (!checkoutAttemptId) return null;
1855
+ if (params.registration === "cancelled") return {
1856
+ kind: "abandon",
1857
+ checkoutAttemptId
1858
+ };
1859
+ if (params.registration === "success" && params.session_id) return {
1860
+ kind: "resolveSuccess",
1861
+ checkoutAttemptId,
1862
+ sessionId: params.session_id
1863
+ };
1864
+ return null;
1865
+ }
1540
1866
  async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
1541
1867
  deps.cleanupStaleRegistrations();
1542
- const params = deps.consumeReturnParams();
1543
- if (params.registration !== "cancelled" && params.registration !== "success") return;
1868
+ const params = deps.readReturnParams();
1869
+ if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
1544
1870
  deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
1545
1871
  const siteId = options.api.config.siteId;
1546
- const checkoutAttemptId = params.registration_attempt;
1547
- if (!siteId) return;
1548
- if (!checkoutAttemptId) {
1549
- showReturnReconciliation(options, "We could not identify this payment attempt. Please contact us before trying again.");
1550
- return;
1872
+ const command = checkoutReturnCommand(params);
1873
+ if (!siteId) return "settled";
1874
+ if (!command) {
1875
+ 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.");
1876
+ return "settled";
1551
1877
  }
1878
+ const { checkoutAttemptId } = command;
1552
1879
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
1553
1880
  checkoutAttemptIdRef.current = checkoutAttemptId;
1554
1881
  if (pending) restorePendingPresentation(options, pending);
1882
+ options.setStep("verifying-payment");
1555
1883
  try {
1556
- const outcome = params.registration === "success" ? params.session_id ? await options.api.resolveEventCheckoutReturn({
1557
- kind: "resolveSuccess",
1558
- checkoutAttemptId,
1559
- sessionId: params.session_id
1560
- }) : { kind: "notFound" } : await options.api.resolveEventCheckoutReturn({
1561
- kind: "abandon",
1562
- checkoutAttemptId
1563
- });
1884
+ const outcome = await options.api.resolveEventCheckoutReturn(command);
1564
1885
  switch (outcome.kind) {
1565
1886
  case "resolved":
1887
+ deps.clearReturnParams();
1566
1888
  options.setPendingRegistrationReference(outcome.reference);
1567
1889
  options.setStep("verifying-payment");
1568
- return;
1890
+ return "settled";
1569
1891
  case "abandoned":
1892
+ deps.clearReturnParams();
1570
1893
  options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
1571
1894
  options.setStep("select-payment");
1572
- return;
1895
+ return "settled";
1573
1896
  case "notFound":
1574
1897
  if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
1898
+ deps.clearReturnParams();
1575
1899
  options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
1576
1900
  options.setStep("select-payment");
1577
- return;
1901
+ return "settled";
1578
1902
  }
1579
- break;
1903
+ 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.");
1904
+ return "settled";
1580
1905
  case "reconciliationRequired": break;
1581
1906
  }
1582
- showReturnReconciliation(options, "We’re checking your payment. Please wait a moment before trying again.");
1907
+ 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.");
1583
1908
  } catch {
1584
- showReturnReconciliation(options, "We could not check your payment yet. Please try again shortly.");
1909
+ 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.");
1585
1910
  }
1911
+ return "retryable";
1586
1912
  }
1587
1913
  function useEventRegistrationStripeReturn(options) {
1588
1914
  return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
@@ -1590,10 +1916,34 @@ function useEventRegistrationStripeReturn(options) {
1590
1916
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
1591
1917
  const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
1592
1918
  const checkoutAttemptIdRef = useRef(null);
1919
+ const lookupInFlightRef = useRef(false);
1920
+ const [lookupState, setLookupState] = useState("settled");
1921
+ const resolveReturn = useCallback(async () => {
1922
+ if (lookupInFlightRef.current) return;
1923
+ lookupInFlightRef.current = true;
1924
+ setLookupState("loading");
1925
+ try {
1926
+ setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
1927
+ } finally {
1928
+ lookupInFlightRef.current = false;
1929
+ }
1930
+ }, [options, deps]);
1593
1931
  const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
1594
1932
  const verification = deps.usePaymentVerification(verificationConfig);
1933
+ const hasVerificationTimeout = step === "verifying-timeout" && pendingRegistrationReference !== null;
1934
+ const retry = useCallback(() => {
1935
+ if (hasVerificationTimeout) {
1936
+ setStep("verifying-payment");
1937
+ return;
1938
+ }
1939
+ verification.retry();
1940
+ }, [
1941
+ hasVerificationTimeout,
1942
+ setStep,
1943
+ verification.retry
1944
+ ]);
1595
1945
  useEffect(() => {
1596
- handleCheckoutReturn(options, deps, checkoutAttemptIdRef);
1946
+ resolveReturn();
1597
1947
  }, []);
1598
1948
  useEffect(() => {
1599
1949
  if (verification.status === "completed") {
@@ -1603,7 +1953,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
1603
1953
  setRegistrationResult({ status: "confirmed" });
1604
1954
  setStep("success");
1605
1955
  } else if (verification.status === "failed") {
1606
- setErrorMessage(verification.error ?? "Payment failed. Please try again.");
1956
+ setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
1607
1957
  setStep("payment-failed");
1608
1958
  } else if (verification.status === "timeout") setStep("verifying-timeout");
1609
1959
  }, [
@@ -1616,7 +1966,22 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
1616
1966
  setRegistrationResult,
1617
1967
  setStep
1618
1968
  ]);
1619
- return verification;
1969
+ return {
1970
+ ...verification,
1971
+ status: hasVerificationTimeout ? "timeout" : verification.status,
1972
+ retry,
1973
+ retryReturn: lookupState === "retryable" ? () => {
1974
+ resolveReturn();
1975
+ } : void 0
1976
+ };
1977
+ }
1978
+ //#endregion
1979
+ //#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.ts
1980
+ function registrationErrorPresentation(error) {
1981
+ const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
1982
+ if (reason) return eventRegistrationErrors[reason];
1983
+ if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
1984
+ return eventRegistrationErrors.paymentUncertain;
1620
1985
  }
1621
1986
  //#endregion
1622
1987
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
@@ -1705,7 +2070,8 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
1705
2070
  outcome: { kind: "completed" }
1706
2071
  };
1707
2072
  } catch (error) {
1708
- const message = error instanceof Error ? error.message : "Registration failed";
2073
+ const { message, action } = registrationErrorPresentation(error);
2074
+ options.setErrorAction?.(action);
1709
2075
  options.setErrorMessage(message);
1710
2076
  options.setStep("error");
1711
2077
  return {
@@ -1870,6 +2236,13 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
1870
2236
  }
1871
2237
  //#endregion
1872
2238
  //#region ../blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.ts
2239
+ function getEventSelectionDefaults(event) {
2240
+ const suggestedAmount = getSlidingScaleForEvent(event)?.suggestedAmount;
2241
+ return {
2242
+ slidingAmountInput: suggestedAmount == null ? "" : formatCentsAsCurrencyInput(suggestedAmount),
2243
+ attendanceMode: event.deliveryMode === "hybrid" ? null : event.deliveryMode ?? "in_person"
2244
+ };
2245
+ }
1873
2246
  function parseCurrencyInputToCents(value) {
1874
2247
  const trimmed = value.trim();
1875
2248
  if (!trimmed) return null;
@@ -1917,7 +2290,7 @@ function resolveWaitlistClaimRestoration(input) {
1917
2290
  const event = findEventByOccurrenceId(input.scopedEvents, subject.occurrenceId);
1918
2291
  if (!event && input.occurrenceContextId !== subject.occurrenceId) return {
1919
2292
  ok: false,
1920
- message: "This waitlist claim is for a different event."
2293
+ message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
1921
2294
  };
1922
2295
  return {
1923
2296
  ok: true,
@@ -1934,7 +2307,7 @@ function resolveWaitlistClaimRestoration(input) {
1934
2307
  const event = input.scopedEvents.find((candidate) => candidate.registrationSubject.kind === "wholeSeries" && candidate.registrationSubject.eventSeriesId === subject.eventSeriesId);
1935
2308
  if (!event) return {
1936
2309
  ok: false,
1937
- message: "This waitlist claim is for a different event run."
2310
+ message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
1938
2311
  };
1939
2312
  return {
1940
2313
  ok: true,
@@ -1967,6 +2340,7 @@ function useWaitlistClaimRestoration(input) {
1967
2340
  occurrenceContextId: input.occurrenceContextId
1968
2341
  });
1969
2342
  if (!restoration.ok) {
2343
+ input.setters.setErrorAction?.("none");
1970
2344
  input.setters.setErrorMessage(restoration.message);
1971
2345
  input.setters.setStep("error");
1972
2346
  return;
@@ -2045,6 +2419,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2045
2419
  });
2046
2420
  const [registrationResult, setRegistrationResult] = useState(null);
2047
2421
  const [errorMessage, setErrorMessage] = useState("");
2422
+ const [errorAction, setErrorAction] = useState("retry");
2423
+ const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
2048
2424
  const [altchaSolution, setAltchaSolution] = useState(null);
2049
2425
  const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
2050
2426
  const waitlistClaim = deps.useWaitlistClaim();
@@ -2074,10 +2450,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2074
2450
  const currentEvent = selectedEvent ?? preSelectedEvent;
2075
2451
  const currentEventPricing = currentEvent ? resolveRuntimeEventPricing(currentEvent) : null;
2076
2452
  const currentEventUsesTicketTypes = currentEventPricing !== null && publicEventPricingMode(currentEventPricing) === "ticket_types";
2077
- const selectedModeAvailability = selectedAttendanceMode ? (currentEvent?.attendanceModes ?? []).find((mode) => mode.mode === selectedAttendanceMode) ?? null : null;
2078
- const currentAvailableSpots = selectedModeAvailability?.availableSpots ?? currentEvent?.availableSpots;
2079
- const currentWaitlistEnabled = selectedModeAvailability?.waitlistEnabled ?? currentEvent?.waitlistEnabled ?? false;
2080
- const usesTicketTypeSelections = currentEventUsesTicketTypes && !(currentAvailableSpots === 0 && currentWaitlistEnabled === true);
2453
+ const currentCanJoinWaitlist = currentEvent ? canJoinEventWaitlist(currentEvent, { attendanceMode: selectedAttendanceMode }) : false;
2454
+ const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
2081
2455
  const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
2082
2456
  event: currentEvent,
2083
2457
  eligibility: null,
@@ -2108,7 +2482,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2108
2482
  });
2109
2483
  }, [flowState.ticketsCount, ticketsCount]);
2110
2484
  const eligibilityResult = deps.useEligibility({
2111
- enabled: shouldLoadRegistrationOptions(portalAuthState, step),
2485
+ refreshKey: optionsRefreshKey,
2486
+ enabled: shouldRefreshAfterRegistrationError(step, errorAction, shouldLoadRegistrationOptions(portalAuthState, step)),
2112
2487
  subject: registrationTarget?.subject ?? null,
2113
2488
  attendanceMode: selectedAttendanceMode,
2114
2489
  ticketSelections,
@@ -2137,6 +2512,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2137
2512
  });
2138
2513
  }, [waitlistClaim.claim]);
2139
2514
  const waitlistRestorationSetters = useMemo(() => ({
2515
+ setErrorAction,
2140
2516
  setErrorMessage,
2141
2517
  setStep,
2142
2518
  setSelectedEvent,
@@ -2160,6 +2536,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2160
2536
  if (waitlistClaim.requiresPortalLogin) return;
2161
2537
  if (!waitlistClaim.error) return;
2162
2538
  setErrorMessage(waitlistClaim.error);
2539
+ setErrorAction("event");
2163
2540
  setStep("error");
2164
2541
  }, [
2165
2542
  waitlistClaim.error,
@@ -2262,8 +2639,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2262
2639
  const event = currentEvent;
2263
2640
  if (!event || publicEventPricingMode(resolveRuntimeEventPricing(event)) !== "ticket_types") return false;
2264
2641
  if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
2265
- const selectedModeAvailability = selectedAttendanceMode ? (event.attendanceModes ?? []).find((mode) => mode.mode === selectedAttendanceMode) ?? null : null;
2266
- return !((selectedModeAvailability?.availableSpots ?? event.availableSpots) === 0 && (selectedModeAvailability?.waitlistEnabled ?? event.waitlistEnabled) === true);
2642
+ return !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
2267
2643
  }, [currentEvent, selectedAttendanceMode]);
2268
2644
  const hasValidTicketSelection = !ticketTypeSelectionRequired || normalizedSelectedTicketLines.length > 0 && normalizedSelectedTicketLines.every((line) => {
2269
2645
  if (!line.ticketTypeId) return false;
@@ -2344,6 +2720,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2344
2720
  ]);
2345
2721
  const handleDetailsComplete = async () => {
2346
2722
  if (ticketTypeSelectionRequired && !hasValidTicketSelection) {
2723
+ setErrorAction("places");
2347
2724
  const message = "Choose at least one available ticket to continue.";
2348
2725
  setErrorMessage(message);
2349
2726
  setStep("error");
@@ -2354,6 +2731,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2354
2731
  };
2355
2732
  }
2356
2733
  if (slidingScaleSelectionMessage) {
2734
+ setErrorAction("places");
2357
2735
  setErrorMessage(slidingScaleSelectionMessage);
2358
2736
  setStep("error");
2359
2737
  return {
@@ -2371,7 +2749,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2371
2749
  };
2372
2750
  }
2373
2751
  if (waitlistClaim.claim === null && eligibility?.isFull && !eligibility.canJoinWaitlist) {
2374
- const message = "This event is sold out.";
2752
+ const message = "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.";
2753
+ setErrorAction("places");
2375
2754
  setErrorMessage(message);
2376
2755
  setStep("error");
2377
2756
  return {
@@ -2487,6 +2866,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2487
2866
  const selectionMethod = paymentSelection.method;
2488
2867
  const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
2489
2868
  const handleSubmit = deps.useEventRegistrationSubmit({
2869
+ setErrorAction,
2490
2870
  api,
2491
2871
  registrationTarget,
2492
2872
  selectedAttendanceMode,
@@ -2509,26 +2889,31 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2509
2889
  ...current,
2510
2890
  consentAccepted: false
2511
2891
  }));
2512
- const slidingScale = getSlidingScaleForEvent(event);
2513
- setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "");
2514
- setSelectedAttendanceMode((event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person");
2892
+ const defaults = getEventSelectionDefaults(event);
2893
+ setSelectedSlidingAmountInput(defaults.slidingAmountInput);
2894
+ setSelectedAttendanceMode(defaults.attendanceMode);
2515
2895
  setSelectedTicketLines([]);
2516
2896
  dispatchFlow({
2517
2897
  type: "event-changed",
2518
2898
  hasPreSelectedContext: true
2519
2899
  });
2520
2900
  };
2521
- const handleRetry = () => {
2522
- dispatchFlow({
2523
- type: "reset",
2524
- hasPreSelectedContext
2525
- });
2526
- setSelectedTicketLines([]);
2527
- setSelectedSlidingAmountInput("");
2528
- setSelectedAttendanceMode(preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null);
2529
- setErrorMessage("");
2530
- setPendingRegistrationReference(null);
2531
- };
2901
+ const handleRetry = () => recoverRegistrationError(resolveRegistrationRecoveryAction(step, errorAction), {
2902
+ canJoinWaitlist: canRecoverToWaitlist(eligibility),
2903
+ refreshOptions: () => setOptionsRefreshKey((value) => value + 1),
2904
+ clearError: () => setErrorMessage(""),
2905
+ setStep,
2906
+ reset: () => resetRegistrationAfterExpiry({
2907
+ hasPreSelectedContext,
2908
+ preSelectedEvent,
2909
+ dispatchFlow,
2910
+ setSelectedTicketLines,
2911
+ setSelectedSlidingAmountInput,
2912
+ setSelectedAttendanceMode,
2913
+ setErrorMessage,
2914
+ setPendingRegistrationReference
2915
+ })
2916
+ });
2532
2917
  const handlePaymentStepStateChange = useCallback((state) => {
2533
2918
  setPaymentStepState(state);
2534
2919
  }, []);
@@ -2591,6 +2976,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
2591
2976
  handleGuestShakeEnd,
2592
2977
  registrationResult,
2593
2978
  errorMessage,
2979
+ errorAction,
2594
2980
  altchaSolution,
2595
2981
  setAltchaSolution,
2596
2982
  portalAuthState,
@@ -2997,11 +3383,11 @@ function EventRegistrationSummaryBar(props) {
2997
3383
  */
2998
3384
  function resolveDetailsButtonText(input) {
2999
3385
  const { wizard } = input;
3000
- if (wizard.eligibility?.canJoinWaitlist) return "Join Waitlist";
3386
+ if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
3001
3387
  if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
3002
3388
  if (wizard.paymentSelection.method === "pass") return "Book using class pass";
3003
3389
  if (wizard.paymentSelection.method === "membership") return input.fallbackText;
3004
- return wizard.eventRequiresPayment ? "Continue to Payment" : input.fallbackText;
3390
+ return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
3005
3391
  }
3006
3392
  function resolveExistingRegistrationLabel(wizard) {
3007
3393
  return wizard.registrationState.kind === "waitlisted" ? "Already on waitlist" : "Already registered";
@@ -3013,13 +3399,24 @@ function isExistingRegistrationBlocking$1(wizard) {
3013
3399
  hasWaitlistClaim: wizard.waitlistClaim.claim !== null
3014
3400
  });
3015
3401
  }
3402
+ /**
3403
+ * Full for the visitor's selected attendance mode (or the whole event when no
3404
+ * mode is chosen) with no waitlist to fall back on. Reads the same capacity
3405
+ * source as the steps above the action bar so the button never disagrees
3406
+ * with them on a hybrid event.
3407
+ */
3408
+ function isFullWithNoWaitlist(event, attendanceMode) {
3409
+ if (!event) return false;
3410
+ const source = selectEventCapacitySource(event, attendanceMode);
3411
+ return getEventAvailability(source).isFull && !source.waitlistEnabled;
3412
+ }
3016
3413
  function EventRegistrationWizardActions(props) {
3017
3414
  const { wizard } = props;
3018
3415
  const nextStepAfterTickets = "enter-details";
3019
3416
  const prevStepForDetails = "select-tickets";
3020
3417
  const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
3021
3418
  const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
3022
- const isSoldOutWithoutWaitlist = !hasWaitlistClaim && currentEvent?.availableSpots === 0 && currentEvent.waitlistEnabled !== true;
3419
+ const isSoldOutWithoutWaitlist = !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
3023
3420
  const getDetailsButtonText = () => resolveDetailsButtonText({
3024
3421
  wizard,
3025
3422
  hasWaitlistClaim,
@@ -3111,191 +3508,6 @@ function EventRegistrationWizardActions(props) {
3111
3508
  }
3112
3509
  }
3113
3510
  //#endregion
3114
- //#region ../commerce/src/purchase/checkoutPaymentFlow.ts
3115
- function planCheckoutPaymentFlow(options) {
3116
- const amountDueCents = toNonNegativeCents(options.amountDueCents);
3117
- const discountCents = toNonNegativeCents(options.discountCents);
3118
- const availableCreditCents = toNonNegativeCents(options.availableCreditCents);
3119
- const minimumStripeChargeCents = toNonNegativeCents(options.minimumStripeChargeCents ?? 0);
3120
- if (amountDueCents <= 0) return {
3121
- kind: "bypass",
3122
- bypassReason: discountCents > 0 ? "discount_free" : "free",
3123
- reserveCreditCents: 0
3124
- };
3125
- if (!options.creditCurrencyMatches || availableCreditCents <= 0) return {
3126
- kind: "stripe",
3127
- reserveCreditCents: toNonNegativeCents(0)
3128
- };
3129
- if (availableCreditCents >= amountDueCents) return {
3130
- kind: "store_credit_only",
3131
- reserveCreditCents: amountDueCents
3132
- };
3133
- return {
3134
- kind: "stripe",
3135
- reserveCreditCents: planMixedPaymentCreditReservation({
3136
- amountDueCents,
3137
- availableCreditCents,
3138
- minimumStripeChargeCents
3139
- })
3140
- };
3141
- }
3142
- function planMixedPaymentCreditReservation(input) {
3143
- const chargeAfterFullCredit = input.amountDueCents - input.availableCreditCents;
3144
- if (input.minimumStripeChargeCents <= 0 || chargeAfterFullCredit <= 0 || chargeAfterFullCredit >= input.minimumStripeChargeCents) return input.availableCreditCents;
3145
- if (input.amountDueCents < input.minimumStripeChargeCents) return toNonNegativeCents(0);
3146
- return toNonNegativeCents(input.amountDueCents - input.minimumStripeChargeCents);
3147
- }
3148
- /**
3149
- * Apply site credit to a flexible-balance booking before card payment.
3150
- *
3151
- * Credit first reduces the configured payment due now. Once that payment is
3152
- * covered, any remaining credit reduces the later balance. If a partial credit
3153
- * application would leave a positive card charge below Stripe's minimum, less
3154
- * credit is used so the configured payment can still be collected.
3155
- */
3156
- function planFlexibleBalanceCreditFirst(input) {
3157
- const totalCents = toNonNegativeCents(input.totalAfterDiscountCents);
3158
- const configuredDueNowCents = toNonNegativeCents(Math.min(input.configuredPaymentDueNowCents, totalCents));
3159
- const availableCreditCents = toNonNegativeCents(input.creditCurrencyMatches ? input.availableCreditCents : 0);
3160
- const minimumStripeChargeCents = toNonNegativeCents(input.minimumStripeChargeCents ?? 0);
3161
- if (availableCreditCents >= totalCents && totalCents > 0) return {
3162
- kind: "credit_only",
3163
- reserveCreditCents: totalCents,
3164
- cardDueNowCents: toNonNegativeCents(0),
3165
- laterBalanceCents: toNonNegativeCents(0)
3166
- };
3167
- let reserveCreditCents = toNonNegativeCents(Math.min(availableCreditCents, totalCents));
3168
- if (reserveCreditCents >= configuredDueNowCents) return {
3169
- kind: "flexible_balance",
3170
- reserveCreditCents,
3171
- cardDueNowCents: toNonNegativeCents(0),
3172
- laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents)
3173
- };
3174
- const plannedCardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
3175
- if (plannedCardDueNowCents > 0 && plannedCardDueNowCents < minimumStripeChargeCents) {
3176
- if (configuredDueNowCents < minimumStripeChargeCents) return {
3177
- kind: "card_below_minimum",
3178
- reserveCreditCents: toNonNegativeCents(0),
3179
- cardDueNowCents: configuredDueNowCents,
3180
- laterBalanceCents: toNonNegativeCents(totalCents - configuredDueNowCents)
3181
- };
3182
- reserveCreditCents = toNonNegativeCents(configuredDueNowCents - minimumStripeChargeCents);
3183
- }
3184
- const cardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
3185
- return {
3186
- kind: "flexible_balance",
3187
- reserveCreditCents,
3188
- cardDueNowCents,
3189
- laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents - cardDueNowCents)
3190
- };
3191
- }
3192
- //#endregion
3193
- //#region ../commerce/src/purchase/settlement.ts
3194
- function normalizeCurrencyCode(raw) {
3195
- const normalized = raw.trim().toUpperCase();
3196
- if (!/^[A-Z]{3}$/.test(normalized)) throw new Error(`Invalid currency code: ${raw}`);
3197
- return normalized;
3198
- }
3199
- //#endregion
3200
- //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
3201
- const datedOfferingSharedEngineMetadataShape = {
3202
- datedOfferingEngineContractVersion: z.literal("shared_v1"),
3203
- datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
3204
- datedOfferingCapacityHoldId: z.string().uuid(),
3205
- datedOfferingCapacityHoldAuditRef: z.string().uuid(),
3206
- customerId: z.string().uuid(),
3207
- eventSeriesId: z.string().uuid()
3208
- };
3209
- z.object(datedOfferingSharedEngineMetadataShape);
3210
- const orderCheckoutSessionMetadataBaseShape = {
3211
- type: z.literal("order"),
3212
- site_id: z.string().uuid(),
3213
- order_id: z.string().uuid().optional(),
3214
- customer_email: z.string().email(),
3215
- customer_name: z.string().optional(),
3216
- product_id: z.string().uuid().optional(),
3217
- attendee_id: z.string().uuid().optional(),
3218
- occurrence_id: z.string().uuid().optional(),
3219
- tickets_count: z.string().optional(),
3220
- notes: z.string().optional(),
3221
- discount_redemption_id: z.string().uuid().optional(),
3222
- discount_code_id: z.string().uuid().optional(),
3223
- discount_code: z.string().optional(),
3224
- discount_public_label: z.string().optional(),
3225
- credit_reservation_id: z.string().uuid().optional(),
3226
- credit_reserved_cents: z.string().optional(),
3227
- discount_code_amount_cents: z.string().optional(),
3228
- order_payment_reason: z.enum([
3229
- "instalment_payoff",
3230
- "flexible_balance_initial",
3231
- "flexible_balance_paydown"
3232
- ]).optional(),
3233
- order_payment_plan_id: z.string().uuid().optional(),
3234
- order_flexible_balance_contract_id: z.string().uuid().optional()
3235
- };
3236
- const absentDatedOfferingSharedEngineMetadataShape = {
3237
- datedOfferingEngineContractVersion: z.never().optional(),
3238
- datedOfferingEngineRouteKind: z.never().optional(),
3239
- datedOfferingCapacityHoldId: z.never().optional(),
3240
- datedOfferingCapacityHoldAuditRef: z.never().optional(),
3241
- customerId: z.never().optional(),
3242
- eventSeriesId: z.never().optional()
3243
- };
3244
- const LegacyOrderCheckoutSessionMetadataSchema = z.object({
3245
- ...orderCheckoutSessionMetadataBaseShape,
3246
- ...absentDatedOfferingSharedEngineMetadataShape
3247
- });
3248
- const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
3249
- ...orderCheckoutSessionMetadataBaseShape,
3250
- ...datedOfferingSharedEngineMetadataShape
3251
- });
3252
- z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
3253
- toNonNegativeCents(0);
3254
- //#endregion
3255
- //#region ../commerce/src/purchase/stripeMinimumCharge.ts
3256
- const STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY = {
3257
- GBP: 30,
3258
- USD: 50,
3259
- EUR: 50,
3260
- AED: 200,
3261
- AUD: 50,
3262
- BGN: 100,
3263
- BRL: 50,
3264
- CAD: 50,
3265
- CHF: 50,
3266
- CZK: 1500,
3267
- DKK: 250,
3268
- HKD: 400,
3269
- HUF: 17500,
3270
- JPY: 50,
3271
- MXN: 1e3,
3272
- MYR: 200,
3273
- NOK: 300,
3274
- NZD: 50,
3275
- PLN: 200,
3276
- RON: 200,
3277
- SEK: 300,
3278
- SGD: 50,
3279
- THB: 1e3
3280
- };
3281
- function isStripeMinimumChargeCurrency(currency) {
3282
- return currency in STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY;
3283
- }
3284
- function getStripeMinimumChargeRequirement(rawCurrency) {
3285
- let currency;
3286
- try {
3287
- currency = normalizeCurrencyCode(rawCurrency);
3288
- } catch {
3289
- return null;
3290
- }
3291
- const currencyKey = currency;
3292
- if (!isStripeMinimumChargeCurrency(currencyKey)) return null;
3293
- return {
3294
- currency,
3295
- minimumAmountCents: STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY[currencyKey]
3296
- };
3297
- }
3298
- //#endregion
3299
3511
  //#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
3300
3512
  function calculateEventRegistrationPreviewTotal(input) {
3301
3513
  const discountCents = input.manualDiscountCode.trim() ? 0 : input.automaticDiscount?.computedAmountCents ?? 0;
@@ -3409,9 +3621,16 @@ function TicketCounter(props) {
3409
3621
  });
3410
3622
  }
3411
3623
  function TicketCounterLimit(props) {
3624
+ const showBookingLimit = !props.availabilityLabel || props.maxAllowed < (props.availableSpots ?? Infinity);
3412
3625
  return /* @__PURE__ */ jsxs("p", {
3413
3626
  className: "er-ticket-counter-limit",
3414
- children: [/* @__PURE__ */ jsx("span", { children: props.maximumLabel }), props.availabilityLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx("span", { children: props.availabilityLabel })] }) : null]
3627
+ children: [props.availabilityLabel ? /* @__PURE__ */ jsx("span", { children: props.availabilityLabel }) : null, showBookingLimit ? /* @__PURE__ */ jsxs(Fragment, { children: [props.availabilityLabel ? /* @__PURE__ */ jsx("br", {}) : null, /* @__PURE__ */ jsxs("span", { children: [
3628
+ "Up to ",
3629
+ props.maxAllowed,
3630
+ " ",
3631
+ props.quantityLabel,
3632
+ " per booking."
3633
+ ] })] }) : null]
3415
3634
  });
3416
3635
  }
3417
3636
  function BookingUnitSessionHint(props) {
@@ -3427,7 +3646,7 @@ function BookingUnitSessionHint(props) {
3427
3646
  }
3428
3647
  function bookingQuantityLabel(unit, waitlist) {
3429
3648
  if (!waitlist) return pluralizeBookingUnit(unit, 2);
3430
- return unit === "place" ? "waitlist places" : "waitlist spots";
3649
+ return "waitlist places";
3431
3650
  }
3432
3651
  function BookingQuantityPrompt(props) {
3433
3652
  return /* @__PURE__ */ jsxs("h3", {
@@ -3486,6 +3705,7 @@ function SlidingScaleAmountField(props) {
3486
3705
  }
3487
3706
  function TicketTypeQuantityRows(props) {
3488
3707
  const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
3708
+ const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
3489
3709
  return /* @__PURE__ */ jsxs("div", {
3490
3710
  className: "er-ticket-lines",
3491
3711
  children: [
@@ -3497,6 +3717,7 @@ function TicketTypeQuantityRows(props) {
3497
3717
  const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.id);
3498
3718
  const disabled = ticketType.availability.kind === "unavailable";
3499
3719
  const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
3720
+ const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingCapacity);
3500
3721
  const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
3501
3722
  const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
3502
3723
  currentQuantity: quantity,
@@ -3528,9 +3749,9 @@ function TicketTypeQuantityRows(props) {
3528
3749
  availabilityLabel ? /* @__PURE__ */ jsx("p", {
3529
3750
  className: "er-ticket-line-detail",
3530
3751
  children: availabilityLabel
3531
- }) : ticketType.availability.remainingCapacity !== null ? /* @__PURE__ */ jsxs("p", {
3752
+ }) : ticketTypeRemainingLabel ? /* @__PURE__ */ jsx("p", {
3532
3753
  className: "er-ticket-line-detail",
3533
- children: [ticketType.availability.remainingCapacity, " remaining for this ticket type"]
3754
+ children: ticketTypeRemainingLabel
3534
3755
  }) : null
3535
3756
  ]
3536
3757
  }), /* @__PURE__ */ jsx(TicketCounter, {
@@ -3550,8 +3771,10 @@ function TicketTypeQuantityRows(props) {
3550
3771
  })
3551
3772
  }),
3552
3773
  /* @__PURE__ */ jsx(TicketCounterLimit, {
3553
- maximumLabel: `${props.maxTickets} ${pluralizeBookingUnit(props.bookingUnit, props.maxTickets)} maximum`,
3554
- availabilityLabel: props.availableSpots != null ? `${props.availableSpots} spots available` : null
3774
+ maxAllowed: effectiveMaxTickets,
3775
+ quantityLabel: pluralizeBookingUnit(props.bookingUnit, effectiveMaxTickets),
3776
+ availableSpots: props.availableSpots,
3777
+ availabilityLabel: props.availabilityLabel
3555
3778
  }),
3556
3779
  totalSelectedQuantity === 0 && props.hasAvailableTicketTypes ? /* @__PURE__ */ jsxs("p", {
3557
3780
  className: "er-text er-text--muted",
@@ -3572,9 +3795,13 @@ function TicketTypeQuantityRows(props) {
3572
3795
  });
3573
3796
  }
3574
3797
  function getAttendanceModeDetail(attendanceMode) {
3575
- if (attendanceMode.availableSpots === null) return "Unlimited spots";
3576
- if (attendanceMode.availableSpots === 0) return attendanceMode.waitlistEnabled ? "Currently full, waitlist available" : "Currently full";
3577
- return `${attendanceMode.availableSpots} spots available`;
3798
+ const remaining = getRemainingPlaces(attendanceMode);
3799
+ switch (remaining.kind) {
3800
+ case "unlimited": return "Unlimited places";
3801
+ case "open": return "Places available";
3802
+ case "low": return formatRemainingPlaces(attendanceMode);
3803
+ case "full": return remaining.waitlist ? "Currently full, waitlist available" : "Currently full";
3804
+ }
3578
3805
  }
3579
3806
  function AttendanceModeTiles(props) {
3580
3807
  return /* @__PURE__ */ jsx("div", {
@@ -3620,11 +3847,11 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
3620
3847
  const unit = bookingUnit.kind;
3621
3848
  const deliveryMode = event?.deliveryMode ?? "in_person";
3622
3849
  const attendanceModes = event?.attendanceModes ?? [];
3623
- const selectedModeAvailability = selectedAttendanceMode ? attendanceModes.find((mode) => mode.mode === selectedAttendanceMode) ?? null : null;
3624
- const availableSpots = selectedModeAvailability?.availableSpots ?? event?.availableSpots;
3625
- const waitlistEnabled = selectedModeAvailability?.waitlistEnabled ?? event?.waitlistEnabled ?? false;
3626
- const isSoldOut = availableSpots === 0;
3627
- const canJoinWaitlist = isSoldOut && waitlistEnabled === true;
3850
+ const capacitySource = event ? selectEventCapacitySource(event, selectedAttendanceMode) : null;
3851
+ const availability = capacitySource ? getEventAvailability(capacitySource) : null;
3852
+ const availableSpots = availability?.available;
3853
+ const isSoldOut = availability?.isFull ?? false;
3854
+ const canJoinWaitlist = capacitySource ? canJoinEventWaitlist(capacitySource) : false;
3628
3855
  const eventPricing = event ? resolveRuntimeEventPricing(event) : null;
3629
3856
  const eventPricingMode = eventPricing ? publicEventPricingMode(eventPricing) : void 0;
3630
3857
  const eventPricingCurrency = eventPricing ? publicEventPricingCurrency(eventPricing) : null;
@@ -3645,7 +3872,7 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
3645
3872
  selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingCapacity ?? null,
3646
3873
  hasSelectedTicketType: implicitTicketType !== null
3647
3874
  });
3648
- const eventAvailabilityLabel = !canJoinWaitlist && event?.availableSpots != null ? `${event.availableSpots} spots available` : null;
3875
+ const eventAvailabilityLabel = !canJoinWaitlist && capacitySource ? formatRemainingPlaces(capacitySource) : null;
3649
3876
  if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
3650
3877
  className: "rb-reg-stack er-stack",
3651
3878
  children: [
@@ -3668,7 +3895,7 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
3668
3895
  className: "rb-reg-stack er-stack",
3669
3896
  children: [/* @__PURE__ */ jsx("h3", {
3670
3897
  className: "er-title",
3671
- children: "Sold Out"
3898
+ children: "Sold out"
3672
3899
  }), /* @__PURE__ */ jsx("p", {
3673
3900
  className: "er-text er-text--muted",
3674
3901
  children: "Sorry you missed out! This event is fully booked."
@@ -3699,6 +3926,7 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
3699
3926
  ticketSelections,
3700
3927
  maxTickets,
3701
3928
  availableSpots,
3929
+ availabilityLabel: eventAvailabilityLabel,
3702
3930
  currency: eventPricingCurrency ?? "usd",
3703
3931
  hasAvailableTicketTypes,
3704
3932
  onTicketSelectionsChange,
@@ -3725,14 +3953,16 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
3725
3953
  label: bookingQuantityLabel(unit, canJoinWaitlist),
3726
3954
  onTicketsChange
3727
3955
  }), /* @__PURE__ */ jsx(TicketCounterLimit, {
3728
- maximumLabel: `${maxAllowed} ${canJoinWaitlist ? bookingQuantityLabel(unit, true) : pluralizeBookingUnit(unit, maxAllowed)} maximum`,
3956
+ maxAllowed,
3957
+ quantityLabel: canJoinWaitlist ? bookingQuantityLabel(unit, true) : pluralizeBookingUnit(unit, maxAllowed),
3958
+ availableSpots: canJoinWaitlist ? null : availableSpots,
3729
3959
  availabilityLabel: eventAvailabilityLabel
3730
3960
  })]
3731
3961
  })
3732
3962
  ] }),
3733
3963
  canJoinWaitlist && /* @__PURE__ */ jsx("p", {
3734
3964
  className: "er-text er-text--muted",
3735
- children: "This event is currently full. Continue to join the waitlist if a spot opens up."
3965
+ children: "This event is currently full. Continue to join the waitlist if a place opens up."
3736
3966
  })
3737
3967
  ]
3738
3968
  });
@@ -4214,15 +4444,14 @@ function resolvePaymentStepStatus(input) {
4214
4444
  function shouldPromptForLogin(status, isAuthenticated, eligibility) {
4215
4445
  return Boolean(status === "not-eligible" && !isAuthenticated && eligibility && (eligibility.requiresAuthForPasses || eligibility.requiresAuthForMemberships));
4216
4446
  }
4217
- function MissingEligibilityPanel(props) {
4218
- const missing = [!props.occurrenceId && "occurrenceId", !props.email && "email"].filter((part) => Boolean(part));
4447
+ function MissingEligibilityPanel() {
4219
4448
  return /* @__PURE__ */ jsx("div", {
4220
4449
  className: "rb-reg-stack er-stack",
4221
4450
  children: /* @__PURE__ */ jsx("div", {
4222
4451
  className: "er-center",
4223
- children: /* @__PURE__ */ jsxs("p", {
4452
+ children: /* @__PURE__ */ jsx("p", {
4224
4453
  className: "er-text er-text--error",
4225
- children: ["Unable to determine payment options", missing.length > 0 && ` (missing: ${missing.join(", ")})`]
4454
+ children: "We couldn’t load the booking options for this event. Please refresh this page and try again. If this keeps happening, contact the organiser for help."
4226
4455
  })
4227
4456
  })
4228
4457
  });
@@ -4312,10 +4541,7 @@ function PaymentBlockingPanel(props) {
4312
4541
  })
4313
4542
  })
4314
4543
  });
4315
- if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {
4316
- occurrenceId: props.occurrenceId,
4317
- email: props.email
4318
- });
4544
+ if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
4319
4545
  if (props.eligibility.registration.kind !== "none") {
4320
4546
  const isBooked = props.eligibility.registration.kind === "booked";
4321
4547
  return /* @__PURE__ */ jsxs("div", {
@@ -4323,12 +4549,16 @@ function PaymentBlockingPanel(props) {
4323
4549
  children: [/* @__PURE__ */ jsx("h3", {
4324
4550
  className: "er-title",
4325
4551
  children: isBooked ? "Already booked" : "Already on the waitlist"
4326
- }), /* @__PURE__ */ jsx("div", {
4552
+ }), /* @__PURE__ */ jsxs("div", {
4327
4553
  className: "er-center",
4328
- children: /* @__PURE__ */ jsx("p", {
4554
+ children: [/* @__PURE__ */ jsx("p", {
4329
4555
  className: "er-text er-text--muted",
4330
- children: isBooked ? "You're already booked on this event." : "You're already on the waitlist for this event."
4331
- })
4556
+ 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."
4557
+ }), /* @__PURE__ */ jsx("a", {
4558
+ href: "/portal",
4559
+ className: "er-retry-btn",
4560
+ children: "View my bookings"
4561
+ })]
4332
4562
  })]
4333
4563
  });
4334
4564
  }
@@ -4451,7 +4681,7 @@ function resolvePaymentButtonText(method, siteCreditPreview, eligibility, select
4451
4681
  const currency = eligibility?.currency ?? "GBP";
4452
4682
  switch (method) {
4453
4683
  case "stripe":
4454
- if (siteCreditPreview.kind !== "applied") return selectedDirectOption?.ctaLabel ?? "Continue to Payment";
4684
+ if (siteCreditPreview.kind !== "applied") return selectedDirectOption?.ctaLabel ?? "Continue to payment";
4455
4685
  if (siteCreditPreview.cardDueNowCents > 0) return `Pay ${formatPrice(siteCreditPreview.cardDueNowCents, currency)} by card`;
4456
4686
  return `Book with ${formatPrice(siteCreditPreview.appliedCreditCents, currency)} site credit`;
4457
4687
  case "pass": return "Book using class pass";
@@ -4827,7 +5057,19 @@ function StepIndicator(props) {
4827
5057
  *
4828
5058
  * Displays an error message with a retry button when registration fails.
4829
5059
  */
4830
- const ErrorStep = ({ message, onRetry }) => {
5060
+ const labels = {
5061
+ none: "",
5062
+ retry: "Try again",
5063
+ places: "Choose places",
5064
+ start: "Start again",
5065
+ details: "Check my details",
5066
+ "payment-options": "View payment options",
5067
+ "payment-status": "Check payment status",
5068
+ portal: "View my bookings",
5069
+ event: "View event"
5070
+ };
5071
+ const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false }) => {
5072
+ const offerWaitlist = action === "places" && canJoinWaitlist;
4831
5073
  return /* @__PURE__ */ jsx(TerminalPanel, {
4832
5074
  tone: "error",
4833
5075
  className: "er-center",
@@ -4836,16 +5078,20 @@ const ErrorStep = ({ message, onRetry }) => {
4836
5078
  variant: "error",
4837
5079
  children: /* @__PURE__ */ jsx(CrossIcon, {})
4838
5080
  }),
4839
- title: "Registration Failed",
5081
+ title: "We couldn’t complete your booking",
4840
5082
  body: /* @__PURE__ */ jsx("p", {
4841
5083
  className: "er-text--muted er-message",
4842
- children: message
5084
+ 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
4843
5085
  }),
4844
- actions: /* @__PURE__ */ jsx("button", {
5086
+ actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
5087
+ href: "/portal",
5088
+ className: "er-retry-btn",
5089
+ children: labels[action]
5090
+ }) : /* @__PURE__ */ jsx("button", {
4845
5091
  type: "button",
4846
5092
  onClick: onRetry,
4847
5093
  className: "er-retry-btn",
4848
- children: "Try Again"
5094
+ children: offerWaitlist ? "Join the waiting list" : labels[action]
4849
5095
  })
4850
5096
  });
4851
5097
  };
@@ -4857,7 +5103,7 @@ const ErrorStep = ({ message, onRetry }) => {
4857
5103
  * Displays when the payment was definitively declined/failed.
4858
5104
  * Provides a retry option that returns to payment selection with form state preserved.
4859
5105
  */
4860
- const PaymentFailedStep = ({ message, onRetry }) => {
5106
+ const PaymentFailedStep = ({ onRetry }) => {
4861
5107
  return /* @__PURE__ */ jsx(TerminalPanel, {
4862
5108
  tone: "error",
4863
5109
  className: "er-center",
@@ -4866,16 +5112,16 @@ const PaymentFailedStep = ({ message, onRetry }) => {
4866
5112
  variant: "error",
4867
5113
  children: /* @__PURE__ */ jsx(CrossIcon, {})
4868
5114
  }),
4869
- title: "Payment Failed",
5115
+ title: "Your payment didn’t go through",
4870
5116
  body: /* @__PURE__ */ jsx("p", {
4871
5117
  className: "er-text--muted er-message",
4872
- children: message
5118
+ children: "Please try again or choose another payment option. If this keeps happening, contact the organiser for help."
4873
5119
  }),
4874
5120
  actions: /* @__PURE__ */ jsx("button", {
4875
5121
  type: "button",
4876
5122
  onClick: onRetry,
4877
5123
  className: "er-retry-btn",
4878
- children: "Try Again"
5124
+ children: "View payment options"
4879
5125
  })
4880
5126
  });
4881
5127
  };
@@ -4970,7 +5216,7 @@ const VerifyingPaymentStep = () => {
4970
5216
  * - "Check Again" button to restart polling
4971
5217
  * - Contact support option for user reassurance
4972
5218
  */
4973
- const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "Your registration is saved", message = "We're still confirming your payment. This usually resolves within a few minutes. You'll receive a confirmation email once everything is verified." }) => {
5219
+ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re checking your payment", message = "Your booking is not confirmed yet. Please don’t make another booking while we check. You can check your payment status again in a moment." }) => {
4974
5220
  return /* @__PURE__ */ jsx(TerminalPanel, {
4975
5221
  tone: "warning",
4976
5222
  className: "er-center",
@@ -4989,8 +5235,12 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "Your regist
4989
5235
  type: "button",
4990
5236
  onClick: onCheckAgain,
4991
5237
  className: "er-btn er-btn--primary",
4992
- children: "Check Again"
4993
- }) : void 0,
5238
+ children: "Check payment status"
5239
+ }) : /* @__PURE__ */ jsx("a", {
5240
+ href: "/portal",
5241
+ className: "er-btn er-btn--primary",
5242
+ children: "Check payment status"
5243
+ }),
4994
5244
  secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
4995
5245
  className: "er-text--sm er-text--muted er-message",
4996
5246
  children: [
@@ -5086,7 +5336,7 @@ function EventRegistrationTerminalState(props) {
5086
5336
  onRetry: () => wizard.setStep("select-payment")
5087
5337
  });
5088
5338
  case "verifying-timeout": return /* @__PURE__ */ jsx(VerifyingTimeoutStep, {
5089
- onCheckAgain: wizard.verification.status === "timeout" ? wizard.verification.retry : void 0,
5339
+ onCheckAgain: wizard.verification.status === "timeout" ? wizard.verification.retry : wizard.verification.retryReturn,
5090
5340
  title: wizard.verification.status === "timeout" ? void 0 : "We’re checking your payment",
5091
5341
  message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
5092
5342
  supportEmail: props.supportEmail
@@ -5098,6 +5348,8 @@ function EventRegistrationTerminalState(props) {
5098
5348
  }) : null;
5099
5349
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
5100
5350
  message: wizard.errorMessage,
5351
+ action: wizard.errorAction,
5352
+ canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
5101
5353
  onRetry: wizard.handleRetry
5102
5354
  });
5103
5355
  case "select-event":
@@ -5255,7 +5507,7 @@ const EVENT_PORTAL_AUTH_COPY = {
5255
5507
  buttonText: "Email me a login link →"
5256
5508
  },
5257
5509
  "waitlist-claim": {
5258
- title: "Log in to claim your waitlist spot",
5510
+ title: "Log in to claim your waitlist place",
5259
5511
  buttonText: "Email me a login link to continue →"
5260
5512
  }
5261
5513
  };
@@ -5265,11 +5517,12 @@ function getActiveTicketTypes(event) {
5265
5517
  function formatTicketTypePrice(ticketType, currency) {
5266
5518
  return formatCurrencyAmount(ticketType.priceAmount, currency, { decimals: "auto" });
5267
5519
  }
5268
- function getAvailabilityLabel(event) {
5269
- const availableSpots = event?.availableSpots;
5270
- if (availableSpots === null || availableSpots === void 0) return null;
5271
- if (availableSpots > 0) return `${availableSpots} spots left`;
5272
- return event?.waitlistEnabled ? "Waitlist available" : "Fully booked";
5520
+ function getAvailabilityLabel(event, attendanceMode) {
5521
+ if (!event) return null;
5522
+ return formatRemainingPlaces(selectEventCapacitySource(event, attendanceMode), {
5523
+ full: "Fully booked",
5524
+ waitlist: "Waitlist available"
5525
+ });
5273
5526
  }
5274
5527
  function getWizardStepLabel(input) {
5275
5528
  switch (input.step) {
@@ -5366,7 +5619,7 @@ function EventRegistrationWizard(props) {
5366
5619
  const currentStepNumber = getStepNumber(wizard.step, activeWizardSteps);
5367
5620
  const summaryEventPricingType = summaryEvent ? publicEventPricingType(summaryEvent.pricing) : "free";
5368
5621
  const summaryPriceLabel = summaryEvent ? formatEventPriceDisplay(summaryEvent.pricing) : null;
5369
- const summaryAvailabilityLabel = getAvailabilityLabel(summaryEvent);
5622
+ const summaryAvailabilityLabel = getAvailabilityLabel(summaryEvent, wizard.selectedAttendanceMode);
5370
5623
  const waitlistClaimRequiresPortalLogin = wizard.waitlistClaim.requiresPortalLogin && wizard.portalAuthState !== "authenticated" && wizard.portalAuthState !== "checking";
5371
5624
  const portalAuthCopy = waitlistClaimRequiresPortalLogin ? {
5372
5625
  ...EVENT_PORTAL_AUTH_COPY["waitlist-claim"],