@riverbankcms/sdk 0.139.0 → 0.140.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.
- package/README.md +1 -1
- package/dist/{PreviewEditorSidebar-BDeenhi3.mjs → PreviewEditorSidebar-CUyTzd5z.mjs} +4 -4
- package/dist/{PreviewEditorUI-DSRhgjF5.mjs → PreviewEditorUI-Agkw4v5i.mjs} +3 -3
- package/dist/{PreviewQueryProvider-D2K8GLUG.mjs → PreviewQueryProvider-CN0ewic5.mjs} +1 -1
- package/dist/{SdkPreviewModeRuntime-CL7wSnYu.mjs → SdkPreviewModeRuntime-DdbeAdS8.mjs} +22 -8
- package/dist/{SiteChromeCustomizeContext-BhDn-5ir.mjs → SiteChromeCustomizeContext-CqGOz-Kv.mjs} +2053 -1110
- package/dist/_dts/ai/src/contracts/proposals.d.ts +165 -165
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +212 -212
- package/dist/_dts/api/src/accessAdmin.d.ts +74 -104
- package/dist/_dts/api/src/aiEndpoints.d.ts +5 -1
- package/dist/_dts/api/src/authSubmission.d.ts +46 -0
- package/dist/_dts/api/src/billing.d.ts +8 -4
- package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +23 -0
- package/dist/_dts/api/src/billingEndpointTypes.d.ts +26 -0
- package/dist/_dts/api/src/blocks.d.ts +2 -0
- package/dist/_dts/api/src/bookingRecords.d.ts +1 -2
- package/dist/_dts/api/src/commercePortalEndpoints.d.ts +8 -1
- package/dist/_dts/api/src/communications.d.ts +0 -1
- package/dist/_dts/api/src/contentRuntime.d.ts +8 -3
- package/dist/_dts/api/src/endpoints.d.ts +93 -64
- package/dist/_dts/api/src/event-destination-policy.d.ts +2 -1
- package/dist/_dts/api/src/footerSettings.d.ts +9 -6
- package/dist/_dts/api/src/index.d.ts +5 -6
- package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
- package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
- package/dist/_dts/api/src/mailingListIntegration.d.ts +8 -2
- package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +1 -1
- package/dist/_dts/api/src/navigation/types.d.ts +1 -1
- package/dist/_dts/api/src/onboarding/confirmationResend.d.ts +25 -0
- package/dist/_dts/api/src/onboarding/surfaceData.d.ts +32 -32
- package/dist/_dts/api/src/publicBookingAvailabilityEndpointDefinitions.d.ts +8 -0
- package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +1 -0
- package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +11 -3
- package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +3 -29
- package/dist/_dts/api/src/publicOnboardingAttemptEndpointDefinitions.d.ts +65 -0
- package/dist/_dts/api/src/saveOutcome.d.ts +20 -0
- package/dist/_dts/api/src/sdkContracts.d.ts +3 -22
- package/dist/_dts/api/src/sdkPushContracts.d.ts +18 -0
- package/dist/_dts/api/src/sdkThemeWire.d.ts +44 -44
- package/dist/_dts/api/src/settings/permissions.d.ts +12 -0
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +9 -5
- package/dist/_dts/api/src/siteOnboarding.d.ts +2 -9
- package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +2 -4
- package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +3 -1
- package/dist/_dts/api/src/siteSettings.d.ts +20 -7
- package/dist/_dts/api/src/types.d.ts +77 -77
- package/dist/_dts/api/src/wholeSeriesRuns.d.ts +2 -37
- package/dist/_dts/billing/src/membership/index.d.ts +3 -0
- package/dist/_dts/billing/src/plans/types.d.ts +3 -0
- package/dist/_dts/billing/src/site-arrangements.d.ts +14 -3
- package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +16 -4
- package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +2 -0
- package/dist/_dts/blocks/src/pageRendererContracts.d.ts +5 -0
- package/dist/_dts/blocks/src/portal/types.d.ts +2 -4
- package/dist/_dts/blocks/src/portal/waitlist-types.d.ts +35 -0
- package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +2 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +42 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +4 -0
- package/dist/_dts/blocks/src/system/data/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/data/prefetchBlockData.d.ts +2 -1
- package/dist/_dts/blocks/src/system/data/types.d.ts +9 -0
- package/dist/_dts/blocks/src/system/registry.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +0 -28
- package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +7 -3
- package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/types/waitlist-claims.d.ts +7 -2
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +30 -6
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +15 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +43 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +1 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +14 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +56 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +6 -8
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +8 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +8 -7
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +10 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventSourceRecovery.d.ts +18 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.client.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +24 -6
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +4 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -6
- package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.d.ts +2 -0
- package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -0
- package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +27 -4
- package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +2 -1
- package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +3 -1
- package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +3 -0
- package/dist/_dts/core/src/branded.d.ts +0 -8
- package/dist/_dts/core/src/index.d.ts +1 -0
- package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +1 -1
- package/dist/_dts/core/src/mailing-list-setup.d.ts +14 -1
- package/dist/_dts/core/src/mailing-list-submission.d.ts +7 -27
- package/dist/_dts/core/src/participants.d.ts +2 -29
- package/dist/_dts/core/src/public-experience.d.ts +4 -0
- package/dist/_dts/core/src/public-profile.d.ts +27 -1
- package/dist/_dts/core/src/site-route-target.d.ts +9 -2
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +293 -606
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListGlobalSettingsSummary.d.ts +10 -0
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListTargetingField.d.ts +3 -2
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/context.d.ts +3 -2
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +3 -2
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +19 -0
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +14 -20
- package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -0
- package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +2 -0
- package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +7 -1
- package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +1 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
- package/dist/_dts/theme-core/src/cards/types.d.ts +21 -21
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +8 -2
- package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -2
- package/dist/_dts/theme-core/src/inputs/types.d.ts +2 -2
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +54 -54
- package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +1 -4
- package/dist/_dts/theme-core/src/schema.d.ts +84 -84
- package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
- package/dist/_dts/theme-core/src/surfaces/foregroundInteraction.d.ts +77 -0
- package/dist/_dts/theme-core/src/surfaces/index.d.ts +1 -0
- package/dist/_dts/theme-core/src/typography/generateTypographyCss.d.ts +2 -2
- package/dist/_dts/ui/src/lib/use-delayed-flag.d.ts +9 -0
- package/dist/_dts/ui/src/pending-button.d.ts +10 -0
- package/dist/client/{BookingConsentAgreement-CZvTDtsK.mjs → BookingConsentAgreement-CuKa82V4.mjs} +4 -4
- package/dist/client/{DiscountCodeDisclosure-D-DsLCMU.mjs → DiscountCodeDisclosure-BbYieKWB.mjs} +1 -1
- package/dist/client/{EventCombined.client-dWqgd5ZO.mjs → EventCombined.client-LTfR1Aby.mjs} +6 -6
- package/dist/client/{EventListing.client-BMRa9IYp.mjs → EventListing.client-DUHpYSuo.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-D21W9kBZ.mjs → LeafletStaticMap-CHRupL6m.mjs} +1 -1
- package/dist/client/{accordion-FxF_ta47.mjs → accordion-6HiIFxNL.mjs} +1 -1
- package/dist/client/{bookingForm-YnwW4TGw.mjs → bookingForm-Dlmid43H.mjs} +7 -7
- package/dist/client/bookings.mjs +325 -140
- package/dist/client/{carousel-vng7fFT5.mjs → carousel-DmkZRRq_.mjs} +2 -2
- package/dist/client/{carousel.client-59G_WMr4.mjs → carousel.client-DQTjCVQT.mjs} +1 -1
- package/dist/client/{cart-DEPDsjNk.mjs → cart-CIC24330.mjs} +3 -3
- package/dist/client/{checkout-CZRWu9rW.mjs → checkout-D1Zw9imo.mjs} +3 -3
- package/dist/client/{checkoutUrls-BuseL0dw.mjs → checkoutUrls-FL6lRkrt.mjs} +1 -1
- package/dist/client/client.mjs +1717 -882
- package/dist/client/{colorStyles-CrxJrPjJ.mjs → colorStyles-3013aRAY.mjs} +3 -1
- package/dist/client/{context-DvU_WUmd.mjs → context-Cy1OayHx.mjs} +6 -19
- package/dist/client/{dates-wnPMiRl5.mjs → dates-aDcfoLHr.mjs} +2 -2
- package/dist/client/{eventCalendar-BA3Q5L15.mjs → eventCalendar-FQxMPAjf.mjs} +8 -8
- package/dist/client/{eventCombined-51wgR-1R.mjs → eventCombined-Dr3ac6Hb.mjs} +3 -3
- package/dist/client/{eventDetails-modaetpm.mjs → eventDetails-D-AzUHFQ.mjs} +4 -4
- package/dist/client/{eventListing-D8t2J3Kv.mjs → eventListing-B3XxBf3i.mjs} +3 -3
- package/dist/client/{eventRegistration-CYqtkCE_.mjs → eventRegistration-I6EaokFD.mjs} +500 -152
- package/dist/client/{form-CBKXN5In.mjs → form-BbWckVWY.mjs} +3 -3
- package/dist/client/{headerSection-DylDqNrs.mjs → headerSection-C9qU4Y7x.mjs} +2 -2
- package/dist/client/hooks.mjs +445 -180
- package/dist/client/{locationMap-CvWrG0vZ.mjs → locationMap-CLCShvlG.mjs} +3 -3
- package/dist/client/{media-BOHuueS5.mjs → media-DHpfFwd3.mjs} +1 -1
- package/dist/client/{newsletterForm-Btwk70zw.mjs → newsletterForm-Briukxzi.mjs} +130 -87
- package/dist/client/{pricing-Uzw-GQ6Y.mjs → pricing-Copadu-2.mjs} +1 -1
- package/dist/client/{productDetail-JLcUYKnd.mjs → productDetail-oujlRd-r.mjs} +3 -3
- package/dist/client/{productList-FM0cbUzj.mjs → productList-BRiIRUcd.mjs} +3 -3
- package/dist/client/{propsDecoder-DYzafZb2.mjs → propsDecoder-CB2KS_ko.mjs} +130 -24
- package/dist/client/rendering/client.mjs +911 -400
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +1696 -818
- package/dist/client/{scrollToBlock-CvXszexS.mjs → scrollToBlock-B1IS1_ua.mjs} +1 -1
- package/dist/client/{shop-BIcjvy5a.mjs → shop-Vn6yNFED.mjs} +6 -6
- package/dist/client/{shop-commerce-BZQsy7xw.mjs → shop-commerce-BVTqipYp.mjs} +7 -7
- package/dist/client/{shop-commerce-store-D5V7XAb5.mjs → shop-commerce-store-BVnJVy7v.mjs} +1 -1
- package/dist/client/{shopShared-DowkXevB.mjs → shopShared-COIeK77T.mjs} +4 -4
- package/dist/client/{useEventFilters-oMoTw_JE.mjs → useEventFilters-DzIUcS9n.mjs} +7 -7
- package/dist/preview-next/before-render.mjs +119 -64
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/keepAlive.mjs +119 -64
- package/dist/preview-next/middleware.mjs +119 -64
- package/dist/{previewAuthStore-COUyAKaX.mjs → previewAuthStore-Gjb6r6vz.mjs} +119 -64
- package/dist/{sdk-runtime-D4k2LSGF.mjs → sdk-runtime-CnCLvZRv.mjs} +2 -2
- package/dist/{separator-UGtpag4Z.mjs → separator-DKDRJ1oH.mjs} +1 -1
- package/dist/server/components.mjs +787 -323
- package/dist/server/config-validation.mjs +328 -79
- package/dist/server/config.mjs +332 -83
- package/dist/server/data.mjs +441 -180
- package/dist/server/index.mjs +126 -66
- package/dist/server/next.mjs +1031 -595
- package/dist/server/page-converter.mjs +183 -74
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +1068 -592
- package/dist/server/rendering.mjs +802 -324
- package/dist/server/routing.mjs +506 -214
- package/dist/server/server.mjs +468 -244
- package/dist/server/theme-bridge.mjs +433 -100
- package/dist/server/theme.mjs +8 -2
- package/dist/styles/index.css +237 -43
- package/package.json +1 -1
- package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionCompactRow.d.ts +0 -29
- package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionList.d.ts +0 -13
|
@@ -1,14 +1,14 @@
|
|
|
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-
|
|
3
|
-
import { C as
|
|
4
|
-
import { a as canJoinEventWaitlistOnAnyMode, c as formatTicketTypeRemaining, f as getRemainingPlaces, h as selectMostOpenCapacitySource, i as canJoinEventWaitlist, m as selectEventCapacitySource, o as formatEventRemainingPlaces, p as isEventFull, r as formatEventPriceDisplay, s as formatRemainingPlaces, u as getEventAvailability } from "./pricing-
|
|
5
|
-
import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-
|
|
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-CuKa82V4.mjs";
|
|
3
|
+
import { C as resolveRegistrationTarget, E as getWizardStepsForContext, Gt as formatBookingDate, Pt as assertNever, S as resolveEventRequiresPayment, T as getStepNumber, Yt as formatBookingTime, _ as toRegistrationEvents, b as findPreSelectedEvent, dn as publicEventPricingType, dt as themeButtonClassName, fn as formatCurrencyAmount, g as getRegistrationStartAt, h as buildEventRegistrationDisplayFromScopedEvents, k as resolveEventRegistrationScopedEvents, ln as publicEventPricingOptions, ot as groupPublicEventsByRun, pn as parseCurrencyCode, qt as formatBookingDateTime, rn as toScheduledBookingDateTime, sn as publicEventPricingCurrency, t as defineIslandPropsDecoder, tn as toBookingTimeZone, un as publicEventPricingStrategy, v as toWholeSeriesRegistrationEvents, w as WIZARD_STEPS, x as resolveDiscountContext, y as findEventByOccurrenceId } from "./propsDecoder-CB2KS_ko.mjs";
|
|
4
|
+
import { a as canJoinEventWaitlistOnAnyMode, c as formatTicketTypeRemaining, f as getRemainingPlaces, h as selectMostOpenCapacitySource, i as canJoinEventWaitlist, m as selectEventCapacitySource, o as formatEventRemainingPlaces, p as isEventFull, r as formatEventPriceDisplay, s as formatRemainingPlaces, u as getEventAvailability } from "./pricing-Copadu-2.mjs";
|
|
5
|
+
import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-Cy1OayHx.mjs";
|
|
6
6
|
import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
|
|
7
|
-
import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-
|
|
8
|
-
import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-
|
|
7
|
+
import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-B1IS1_ua.mjs";
|
|
8
|
+
import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-BbYieKWB.mjs";
|
|
9
9
|
import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
|
|
10
10
|
import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
|
|
11
|
-
import { t as buildCheckoutReturnUrls } from "./checkoutUrls-
|
|
11
|
+
import { t as buildCheckoutReturnUrls } from "./checkoutUrls-FL6lRkrt.mjs";
|
|
12
12
|
import { t as createBodyThemePortalRoot } from "./themePortalRoot-AGs4cE7t.mjs";
|
|
13
13
|
import { n as consumeSearchParams } from "./urlParams-D71VXFGx.mjs";
|
|
14
14
|
import { t as CrossIcon } from "./CrossIcon-Dn1KRKW5.mjs";
|
|
@@ -503,6 +503,90 @@ function missingPaymentSelection() {
|
|
|
503
503
|
};
|
|
504
504
|
}
|
|
505
505
|
//#endregion
|
|
506
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.ts
|
|
507
|
+
/** Recovery may select held places; checkout still owns admission and payment validation. */
|
|
508
|
+
function checkoutRecoveryOptionAvailability(availability) {
|
|
509
|
+
if (availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable") return {
|
|
510
|
+
kind: "available",
|
|
511
|
+
remainingPlaces: null
|
|
512
|
+
};
|
|
513
|
+
return availability;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* A form-only projection for the explicit existing-checkout path. It permits
|
|
517
|
+
* collecting the original selection without claiming a new place is available.
|
|
518
|
+
* The public checkout service identifies the customer and remains the admission
|
|
519
|
+
* authority; no reservation/customer data is exposed through this projection.
|
|
520
|
+
*/
|
|
521
|
+
function getCheckoutRecoveryFormEligibility(eligibility) {
|
|
522
|
+
if (!eligibility || eligibility.registration.kind !== "none" && eligibility.registration.kind !== "pending_payment" || eligibility.availability.kind === "unavailable" && eligibility.availability.reason !== "full" && eligibility.availability.reason !== "selectionRequired") return eligibility;
|
|
523
|
+
const amountCents = eligibility.price ?? 0;
|
|
524
|
+
if (amountCents <= 0 || !eligibility.currency || eligibility.availability.kind === "unavailable" && eligibility.availability.reason === "selectionRequired") return eligibility.registration.kind === "pending_payment" ? {
|
|
525
|
+
...eligibility,
|
|
526
|
+
registration: { kind: "none" },
|
|
527
|
+
ticketTypes: eligibility.ticketTypes.map((option) => ({
|
|
528
|
+
...option,
|
|
529
|
+
availability: checkoutRecoveryOptionAvailability(option.availability)
|
|
530
|
+
}))
|
|
531
|
+
} : eligibility;
|
|
532
|
+
const currency = eligibility.currency;
|
|
533
|
+
const paymentOptions = eligibility.paymentTerms.allowedOptions.map((option) => {
|
|
534
|
+
switch (option.kind) {
|
|
535
|
+
case "upfront": return {
|
|
536
|
+
kind: "payInFull",
|
|
537
|
+
amountCents,
|
|
538
|
+
currency
|
|
539
|
+
};
|
|
540
|
+
case "deferred_manual": return {
|
|
541
|
+
kind: "deferredManual",
|
|
542
|
+
amountCents,
|
|
543
|
+
currency
|
|
544
|
+
};
|
|
545
|
+
case "instalment_plan": return {
|
|
546
|
+
kind: "instalmentPlan",
|
|
547
|
+
amountCents,
|
|
548
|
+
currency
|
|
549
|
+
};
|
|
550
|
+
case "flexible_balance": return {
|
|
551
|
+
kind: "flexibleBalance",
|
|
552
|
+
amountCents,
|
|
553
|
+
currency
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
return {
|
|
558
|
+
...eligibility,
|
|
559
|
+
registration: { kind: "none" },
|
|
560
|
+
availability: {
|
|
561
|
+
kind: "available",
|
|
562
|
+
remainingPlaces: null,
|
|
563
|
+
waitlistEnabled: eligibility.waitlistEnabled
|
|
564
|
+
},
|
|
565
|
+
eligible: paymentOptions.length > 0,
|
|
566
|
+
isFull: false,
|
|
567
|
+
canJoinWaitlist: false,
|
|
568
|
+
isFree: false,
|
|
569
|
+
requiresPayment: true,
|
|
570
|
+
canPayDirectly: paymentOptions.length > 0,
|
|
571
|
+
paymentOptions,
|
|
572
|
+
eligiblePasses: [],
|
|
573
|
+
eligibleMemberships: [],
|
|
574
|
+
ticketTypes: eligibility.ticketTypes.map((option) => ({
|
|
575
|
+
...option,
|
|
576
|
+
availability: checkoutRecoveryOptionAvailability(option.availability)
|
|
577
|
+
}))
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function isSoldOutEventSelectable(event, waitlistAvailable) {
|
|
581
|
+
return waitlistAvailable || canRecoverEventCheckout(event);
|
|
582
|
+
}
|
|
583
|
+
function canJoinWaitlistOutsideRecovery(event, attendanceMode, checkoutRecovery) {
|
|
584
|
+
return !checkoutRecovery && event !== null && canJoinEventWaitlist(event, { attendanceMode });
|
|
585
|
+
}
|
|
586
|
+
function canRecoverEventCheckout(event) {
|
|
587
|
+
return event !== null && (event.registrationSubject.kind === "wholeSeries" || event.pricing.kind !== "free" && event.pricing.kind !== "external");
|
|
588
|
+
}
|
|
589
|
+
//#endregion
|
|
506
590
|
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
507
591
|
function getPortalSubjectEmail(profile) {
|
|
508
592
|
return profile?.email ?? null;
|
|
@@ -688,7 +772,7 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
688
772
|
const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
|
|
689
773
|
const isSoldOut = isEventFull(event);
|
|
690
774
|
const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
|
|
691
|
-
const isUnavailable = isSoldOut && !canJoinWaitlist;
|
|
775
|
+
const isUnavailable = isSoldOut && !isSoldOutEventSelectable(event, canJoinWaitlist);
|
|
692
776
|
const isLowCapacity = remaining.kind === "low";
|
|
693
777
|
const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
|
|
694
778
|
const timeZone = event.timeZone ?? null;
|
|
@@ -733,6 +817,33 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
733
817
|
});
|
|
734
818
|
};
|
|
735
819
|
//#endregion
|
|
820
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.ts
|
|
821
|
+
/** Recovery belongs to the selected booking subject; changing events resets its scope. */
|
|
822
|
+
function useCheckoutRecovery(event, setStep) {
|
|
823
|
+
const [recoveryEventId, setRecoveryEventId] = useState(null);
|
|
824
|
+
return {
|
|
825
|
+
checkoutRecovery: event !== null && recoveryEventId === event.selectionId,
|
|
826
|
+
startCheckoutRecovery: useCallback(() => {
|
|
827
|
+
if (!event) return;
|
|
828
|
+
setRecoveryEventId(event.selectionId);
|
|
829
|
+
setStep("select-tickets");
|
|
830
|
+
}, [event, setStep])
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
/** Authenticated pending bookings enter the same form-only recovery path as guests. */
|
|
834
|
+
function useCheckoutRecoveryEligibility(eligibility, step, checkoutRecovery, startCheckoutRecovery) {
|
|
835
|
+
const registrationKind = eligibility?.registration.kind;
|
|
836
|
+
useEffect(() => {
|
|
837
|
+
if ((step === "select-event" || step === "select-tickets" || step === "enter-details" || step === "select-payment") && registrationKind === "pending_payment" && !checkoutRecovery) startCheckoutRecovery();
|
|
838
|
+
}, [
|
|
839
|
+
registrationKind,
|
|
840
|
+
step,
|
|
841
|
+
checkoutRecovery,
|
|
842
|
+
startCheckoutRecovery
|
|
843
|
+
]);
|
|
844
|
+
return useMemo(() => checkoutRecovery ? getCheckoutRecoveryFormEligibility(eligibility) : eligibility, [checkoutRecovery, eligibility]);
|
|
845
|
+
}
|
|
846
|
+
//#endregion
|
|
736
847
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
|
|
737
848
|
function resolveRegistrationRecoveryAction(step, action) {
|
|
738
849
|
if (step === "payment-failed") return "payment-options";
|
|
@@ -1373,6 +1484,10 @@ const eventRegistrationErrors = {
|
|
|
1373
1484
|
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.",
|
|
1374
1485
|
action: "payment-status"
|
|
1375
1486
|
},
|
|
1487
|
+
paymentProviderUnavailable: {
|
|
1488
|
+
message: "We couldn’t reach the payment provider. Please try again in a minute.",
|
|
1489
|
+
action: "retry"
|
|
1490
|
+
},
|
|
1376
1491
|
paymentPageUnavailable: {
|
|
1377
1492
|
message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
|
|
1378
1493
|
action: "retry"
|
|
@@ -1495,11 +1610,6 @@ function ensureWaitlistClaimLocationTracking() {
|
|
|
1495
1610
|
} catch {}
|
|
1496
1611
|
window.addEventListener("popstate", emitWaitlistClaimLocationChange);
|
|
1497
1612
|
}
|
|
1498
|
-
function getWaitlistClaimTokenFromUrl() {
|
|
1499
|
-
if (typeof window === "undefined") return null;
|
|
1500
|
-
const token = new URLSearchParams(window.location.search).get("waitlist_claim")?.trim() ?? "";
|
|
1501
|
-
return token.length > 0 ? token : null;
|
|
1502
|
-
}
|
|
1503
1613
|
const useWaitlistClaimDeps = { useBlockApi };
|
|
1504
1614
|
function subscribeToWaitlistClaimToken(callback) {
|
|
1505
1615
|
if (typeof window === "undefined") return () => {};
|
|
@@ -1509,28 +1619,42 @@ function subscribeToWaitlistClaimToken(callback) {
|
|
|
1509
1619
|
window.removeEventListener(WAITLIST_CLAIM_LOCATION_EVENT, callback);
|
|
1510
1620
|
};
|
|
1511
1621
|
}
|
|
1512
|
-
function
|
|
1513
|
-
return
|
|
1622
|
+
function getWaitlistClaimLocationSnapshot() {
|
|
1623
|
+
return typeof window === "undefined" ? "" : window.location.search;
|
|
1624
|
+
}
|
|
1625
|
+
function parseWaitlistClaimCredential(search) {
|
|
1626
|
+
const params = new URLSearchParams(search);
|
|
1627
|
+
const token = params.get("waitlist_claim")?.trim();
|
|
1628
|
+
if (token) return {
|
|
1629
|
+
kind: "emailedToken",
|
|
1630
|
+
token
|
|
1631
|
+
};
|
|
1632
|
+
const entryId = params.get("waitlistEntry")?.trim();
|
|
1633
|
+
return entryId ? {
|
|
1634
|
+
kind: "portalOwnedEntry",
|
|
1635
|
+
entryId
|
|
1636
|
+
} : null;
|
|
1514
1637
|
}
|
|
1515
1638
|
function useWaitlistClaim() {
|
|
1516
1639
|
return useWaitlistClaimWithDeps(useWaitlistClaimDeps);
|
|
1517
1640
|
}
|
|
1518
1641
|
function useWaitlistClaimWithDeps(deps) {
|
|
1519
|
-
|
|
1642
|
+
const locationSearch = useSyncExternalStore(subscribeToWaitlistClaimToken, getWaitlistClaimLocationSnapshot, () => "");
|
|
1643
|
+
return useResolvedWaitlistClaim(deps, useMemo(() => parseWaitlistClaimCredential(locationSearch), [locationSearch]));
|
|
1520
1644
|
}
|
|
1521
|
-
function useResolvedWaitlistClaim(deps,
|
|
1645
|
+
function useResolvedWaitlistClaim(deps, credential) {
|
|
1522
1646
|
const api = deps.useBlockApi();
|
|
1523
|
-
const [state, dispatch] = useReducer(waitlistClaimReducer, Boolean(
|
|
1647
|
+
const [state, dispatch] = useReducer(waitlistClaimReducer, Boolean(credential), createInitialWaitlistClaimState);
|
|
1524
1648
|
useEffect(() => {
|
|
1525
1649
|
let cancelled = false;
|
|
1526
1650
|
async function resolveClaim() {
|
|
1527
|
-
if (!
|
|
1651
|
+
if (!credential) {
|
|
1528
1652
|
dispatch({ type: "cleared" });
|
|
1529
1653
|
return;
|
|
1530
1654
|
}
|
|
1531
1655
|
dispatch({ type: "started" });
|
|
1532
1656
|
try {
|
|
1533
|
-
const result = await api.resolveWaitlistClaim({ claimToken: token });
|
|
1657
|
+
const result = credential.kind === "portalOwnedEntry" ? await api.resolveWaitlistClaim({ waitlistEntryId: credential.entryId }) : await api.resolveWaitlistClaim({ claimToken: credential.token });
|
|
1534
1658
|
if (cancelled) return;
|
|
1535
1659
|
dispatch({
|
|
1536
1660
|
type: "resolved",
|
|
@@ -1548,9 +1672,10 @@ function useResolvedWaitlistClaim(deps, token) {
|
|
|
1548
1672
|
return () => {
|
|
1549
1673
|
cancelled = true;
|
|
1550
1674
|
};
|
|
1551
|
-
}, [api,
|
|
1675
|
+
}, [api, credential]);
|
|
1552
1676
|
return {
|
|
1553
|
-
token,
|
|
1677
|
+
token: credential?.kind === "emailedToken" ? credential.token : null,
|
|
1678
|
+
entryId: credential?.kind === "portalOwnedEntry" ? credential.entryId : null,
|
|
1554
1679
|
claim: getWaitlistClaim(state),
|
|
1555
1680
|
error: getWaitlistClaimError(state),
|
|
1556
1681
|
loginMessage: getWaitlistClaimLoginMessage(state),
|
|
@@ -2032,15 +2157,12 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2032
2157
|
* landed — a success, or a hand-off to checkout — because until then nobody
|
|
2033
2158
|
* knows whether the first one committed.
|
|
2034
2159
|
*
|
|
2035
|
-
*
|
|
2036
|
-
* details
|
|
2037
|
-
* anything, so a submission that already booked is answered with the booking
|
|
2038
|
-
* that exists — not refused for spending a credit or a claim that this very
|
|
2039
|
-
* command already spent, and not treated as a second booking because a name
|
|
2040
|
-
* or a note changed in between.
|
|
2160
|
+
* Identical retries retain the command after a lost response. Changed form
|
|
2161
|
+
* details get a new command so the server applies the new booking intent.
|
|
2041
2162
|
*/
|
|
2042
|
-
const
|
|
2043
|
-
|
|
2163
|
+
const commandRef = useRef(null);
|
|
2164
|
+
const inFlightRef = useRef(null);
|
|
2165
|
+
const submit = async (method, passId, membershipId, selection, submitOptions) => {
|
|
2044
2166
|
const target = options.registrationTarget;
|
|
2045
2167
|
if (!target) return {
|
|
2046
2168
|
ok: false,
|
|
@@ -2048,44 +2170,34 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2048
2170
|
message: "Select an event to continue."
|
|
2049
2171
|
};
|
|
2050
2172
|
options.setStep("submitting");
|
|
2051
|
-
const registrationCommandId =
|
|
2052
|
-
commandIdRef.current = registrationCommandId;
|
|
2173
|
+
const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
|
|
2053
2174
|
try {
|
|
2054
|
-
|
|
2175
|
+
let prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
|
|
2055
2176
|
if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
|
|
2056
|
-
|
|
2177
|
+
commandRef.current = null;
|
|
2057
2178
|
return await submitWholeSeriesCheckout(options, deps, {
|
|
2058
2179
|
...prepared,
|
|
2059
2180
|
subject: prepared.subject
|
|
2060
2181
|
}, submitOptions);
|
|
2061
2182
|
}
|
|
2183
|
+
const request = buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId);
|
|
2184
|
+
const intentKey = registrationRequestIntentKey(request);
|
|
2185
|
+
if (commandRef.current !== null && commandRef.current.intentKey !== intentKey) prepared = {
|
|
2186
|
+
...prepared,
|
|
2187
|
+
registrationCommandId: deps.createClientCommandId()
|
|
2188
|
+
};
|
|
2189
|
+
commandRef.current = {
|
|
2190
|
+
id: prepared.registrationCommandId,
|
|
2191
|
+
intentKey
|
|
2192
|
+
};
|
|
2062
2193
|
const result = await options.api.registerForEvent({
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
|
|
2066
|
-
selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
|
|
2067
|
-
email: options.formData.email.trim().toLowerCase(),
|
|
2068
|
-
name: options.formData.name.trim(),
|
|
2069
|
-
phone: options.formData.phone.trim() || void 0,
|
|
2070
|
-
notes: options.formData.notes.trim() || void 0,
|
|
2071
|
-
consentAccepted: options.formData.consentAccepted,
|
|
2072
|
-
altchaSolution: options.altchaSolution,
|
|
2073
|
-
paymentMethod: method,
|
|
2074
|
-
customerPassId: method === "pass" ? passId : void 0,
|
|
2075
|
-
customerMembershipId: method === "membership" ? membershipId : void 0,
|
|
2076
|
-
bundleProductId: prepared.bundleProductId,
|
|
2077
|
-
claimToken: options.claimToken ?? void 0,
|
|
2078
|
-
guests: prepared.guestsPayload
|
|
2194
|
+
...request,
|
|
2195
|
+
registrationCommandId: prepared.registrationCommandId
|
|
2079
2196
|
});
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
options.setRegistrationResult(toRegistrationResult(result));
|
|
2083
|
-
options.setStep("success");
|
|
2084
|
-
return {
|
|
2085
|
-
ok: true,
|
|
2086
|
-
outcome: { kind: "completed" }
|
|
2087
|
-
};
|
|
2197
|
+
commandRef.current = null;
|
|
2198
|
+
return await completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions);
|
|
2088
2199
|
} catch (error) {
|
|
2200
|
+
if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
|
|
2089
2201
|
const { message, action } = registrationErrorPresentation(error);
|
|
2090
2202
|
options.setErrorAction?.(action);
|
|
2091
2203
|
options.setErrorMessage(message);
|
|
@@ -2097,6 +2209,24 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2097
2209
|
};
|
|
2098
2210
|
}
|
|
2099
2211
|
};
|
|
2212
|
+
return (...args) => {
|
|
2213
|
+
if (inFlightRef.current) return inFlightRef.current;
|
|
2214
|
+
const pending = Promise.resolve().then(() => submit(...args));
|
|
2215
|
+
inFlightRef.current = pending;
|
|
2216
|
+
pending.finally(() => {
|
|
2217
|
+
if (inFlightRef.current === pending) inFlightRef.current = null;
|
|
2218
|
+
});
|
|
2219
|
+
return pending;
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
async function completeRegistrationSubmission(options, deps, prepared, result, method, submitOptions) {
|
|
2223
|
+
if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
|
|
2224
|
+
options.setRegistrationResult(toRegistrationResult(result));
|
|
2225
|
+
options.setStep("success");
|
|
2226
|
+
return {
|
|
2227
|
+
ok: true,
|
|
2228
|
+
outcome: { kind: "completed" }
|
|
2229
|
+
};
|
|
2100
2230
|
}
|
|
2101
2231
|
function toTicketSelectionRequests(lines) {
|
|
2102
2232
|
return lines.map((line) => ({
|
|
@@ -2171,6 +2301,7 @@ async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions)
|
|
|
2171
2301
|
altchaSolution: options.altchaSolution,
|
|
2172
2302
|
guests: prepared.guestsPayload,
|
|
2173
2303
|
claimToken: options.claimToken ?? void 0,
|
|
2304
|
+
waitlistEntryId: options.waitlistEntryId ?? void 0,
|
|
2174
2305
|
discountCode: options.discountCode.trim() || void 0,
|
|
2175
2306
|
collectionOptionKind: prepared.selectionSnapshot.collectionOptionKind,
|
|
2176
2307
|
checkoutAttemptId,
|
|
@@ -2192,14 +2323,14 @@ async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions)
|
|
|
2192
2323
|
}
|
|
2193
2324
|
if (result.bypassed) return completeBypassedCheckout(options);
|
|
2194
2325
|
if (!result.checkoutUrl) throw new Error("Checkout URL missing");
|
|
2195
|
-
savePendingCheckout(options, deps, prepared, checkoutAttemptId, {
|
|
2326
|
+
savePendingCheckout(options, deps, prepared, result.checkoutAttemptId, {
|
|
2196
2327
|
scope: "wholeSeries",
|
|
2197
2328
|
registrationId: result.registrationId
|
|
2198
2329
|
});
|
|
2199
2330
|
return redirectToCheckout(result.checkoutUrl, submitOptions);
|
|
2200
2331
|
}
|
|
2201
2332
|
function needsOccurrenceCheckout(result, method) {
|
|
2202
|
-
return result.scope === "occurrence" &&
|
|
2333
|
+
return result.scope === "occurrence" && result.status === "confirmed" && result.pendingPayment && [
|
|
2203
2334
|
"stripe",
|
|
2204
2335
|
"pass_bundle",
|
|
2205
2336
|
"membership_bundle"
|
|
@@ -2219,6 +2350,7 @@ async function submitOccurrenceCheckout(options, deps, prepared, registration, m
|
|
|
2219
2350
|
kind: "occurrence",
|
|
2220
2351
|
attendeeId: registration.attendeeId
|
|
2221
2352
|
},
|
|
2353
|
+
registrationCommandId: prepared.registrationCommandId,
|
|
2222
2354
|
checkoutType: method === "pass_bundle" ? "pass_bundle" : method === "membership_bundle" ? "membership_bundle" : "event",
|
|
2223
2355
|
productId: prepared.bundleProductId,
|
|
2224
2356
|
discountCode: options.discountCode.trim() || void 0,
|
|
@@ -2261,6 +2393,31 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
|
|
|
2261
2393
|
}
|
|
2262
2394
|
};
|
|
2263
2395
|
}
|
|
2396
|
+
function registrationRequestIntentKey(request) {
|
|
2397
|
+
const { registrationCommandId: _command, altchaSolution: _proof, ...intent } = request;
|
|
2398
|
+
return JSON.stringify(intent);
|
|
2399
|
+
}
|
|
2400
|
+
function buildOccurrenceRegistrationRequest(options, prepared, method, passId, membershipId) {
|
|
2401
|
+
return {
|
|
2402
|
+
registrationCommandId: prepared.registrationCommandId,
|
|
2403
|
+
subject: prepared.subject,
|
|
2404
|
+
ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
|
|
2405
|
+
selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
|
|
2406
|
+
email: options.formData.email.trim().toLowerCase(),
|
|
2407
|
+
name: options.formData.name.trim(),
|
|
2408
|
+
phone: options.formData.phone.trim() || void 0,
|
|
2409
|
+
notes: options.formData.notes.trim() || void 0,
|
|
2410
|
+
consentAccepted: options.formData.consentAccepted,
|
|
2411
|
+
altchaSolution: options.altchaSolution,
|
|
2412
|
+
paymentMethod: method,
|
|
2413
|
+
customerPassId: method === "pass" ? passId : void 0,
|
|
2414
|
+
customerMembershipId: method === "membership" ? membershipId : void 0,
|
|
2415
|
+
bundleProductId: prepared.bundleProductId,
|
|
2416
|
+
claimToken: options.claimToken ?? void 0,
|
|
2417
|
+
waitlistEntryId: options.waitlistEntryId ?? void 0,
|
|
2418
|
+
guests: prepared.guestsPayload
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2264
2421
|
//#endregion
|
|
2265
2422
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.ts
|
|
2266
2423
|
function getEventSelectionDefaults(event) {
|
|
@@ -2499,14 +2656,28 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2499
2656
|
}), [options.occurrenceContext, selectedEvent]);
|
|
2500
2657
|
const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
|
|
2501
2658
|
const currentEvent = selectedEvent ?? preSelectedEvent;
|
|
2659
|
+
const setStep = useCallback((nextStep) => {
|
|
2660
|
+
dispatchFlow({
|
|
2661
|
+
type: "set-step",
|
|
2662
|
+
step: nextStep
|
|
2663
|
+
});
|
|
2664
|
+
}, []);
|
|
2665
|
+
const { checkoutRecovery, startCheckoutRecovery } = useCheckoutRecovery(currentEvent, setStep);
|
|
2502
2666
|
const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
|
|
2503
|
-
const currentCanJoinWaitlist =
|
|
2667
|
+
const currentCanJoinWaitlist = canJoinWaitlistOutsideRecovery(currentEvent, selectedAttendanceMode, checkoutRecovery);
|
|
2504
2668
|
const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
|
|
2505
2669
|
const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
|
|
2506
2670
|
event: currentEvent,
|
|
2507
2671
|
eligibility: null,
|
|
2508
2672
|
selectedAttendanceMode
|
|
2509
|
-
})
|
|
2673
|
+
}).map((option) => checkoutRecovery ? {
|
|
2674
|
+
...option,
|
|
2675
|
+
availability: checkoutRecoveryOptionAvailability(option.availability)
|
|
2676
|
+
} : option), [
|
|
2677
|
+
currentEvent,
|
|
2678
|
+
selectedAttendanceMode,
|
|
2679
|
+
checkoutRecovery
|
|
2680
|
+
]);
|
|
2510
2681
|
const normalizedSelectedTicketLines = useMemo(() => normalizeTicketSelectionLines(selectedTicketLines), [selectedTicketLines]);
|
|
2511
2682
|
const ticketTypeSelectionTotal = useMemo(() => getTicketSelectionTotal(normalizedSelectedTicketLines), [normalizedSelectedTicketLines]);
|
|
2512
2683
|
const ticketsCount = usesTicketTypeSelections ? ticketTypeSelectionTotal : flowState.ticketsCount;
|
|
@@ -2544,17 +2715,11 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2544
2715
|
isAuthenticated: portalAuthState === "authenticated",
|
|
2545
2716
|
occurrenceId: registrationOccurrenceId
|
|
2546
2717
|
});
|
|
2547
|
-
const eligibility = eligibilityResult.eligibility;
|
|
2718
|
+
const eligibility = useCheckoutRecoveryEligibility(eligibilityResult.eligibility, step, checkoutRecovery, startCheckoutRecovery);
|
|
2548
2719
|
const eligibilityLoading = eligibilityResult.isLoading;
|
|
2549
2720
|
const eligibilityError = eligibilityResult.error;
|
|
2550
2721
|
const portalCreditState = eligibilityResult.creditState;
|
|
2551
2722
|
const registrationState = eligibility?.registration ?? { kind: "none" };
|
|
2552
|
-
const setStep = useCallback((nextStep) => {
|
|
2553
|
-
dispatchFlow({
|
|
2554
|
-
type: "set-step",
|
|
2555
|
-
step: nextStep
|
|
2556
|
-
});
|
|
2557
|
-
}, []);
|
|
2558
2723
|
const setTicketsCount = useCallback((nextTicketsCount) => {
|
|
2559
2724
|
dispatchFlow({
|
|
2560
2725
|
type: "set-tickets-count",
|
|
@@ -2662,10 +2827,14 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2662
2827
|
event: currentEvent,
|
|
2663
2828
|
eligibility,
|
|
2664
2829
|
selectedAttendanceMode
|
|
2665
|
-
})
|
|
2830
|
+
}).map((option) => checkoutRecovery ? {
|
|
2831
|
+
...option,
|
|
2832
|
+
availability: checkoutRecoveryOptionAvailability(option.availability)
|
|
2833
|
+
} : option), [
|
|
2666
2834
|
currentEvent,
|
|
2667
2835
|
selectedAttendanceMode,
|
|
2668
|
-
eligibility
|
|
2836
|
+
eligibility,
|
|
2837
|
+
checkoutRecovery
|
|
2669
2838
|
]);
|
|
2670
2839
|
const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
|
|
2671
2840
|
const selectedTicketType = useMemo(() => findSelectedTicketType({
|
|
@@ -2689,8 +2858,12 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2689
2858
|
const event = currentEvent;
|
|
2690
2859
|
if (!usesTieredPricing(event)) return false;
|
|
2691
2860
|
if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
|
|
2692
|
-
return !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
|
|
2693
|
-
}, [
|
|
2861
|
+
return checkoutRecovery || !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
|
|
2862
|
+
}, [
|
|
2863
|
+
currentEvent,
|
|
2864
|
+
selectedAttendanceMode,
|
|
2865
|
+
checkoutRecovery
|
|
2866
|
+
]);
|
|
2694
2867
|
const hasValidTicketSelection = hasValidPricingOptionSelection({
|
|
2695
2868
|
selectionRequired: ticketTypeSelectionRequired,
|
|
2696
2869
|
lines: normalizedSelectedTicketLines,
|
|
@@ -2894,6 +3067,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2894
3067
|
guests,
|
|
2895
3068
|
discountCode: discountUi.discountCode,
|
|
2896
3069
|
claimToken: waitlistClaim.token,
|
|
3070
|
+
waitlistEntryId: waitlistClaim.entryId,
|
|
2897
3071
|
setPendingRegistrationReference,
|
|
2898
3072
|
setStep,
|
|
2899
3073
|
setRegistrationResult: (result) => setRegistrationResult(result),
|
|
@@ -2956,6 +3130,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2956
3130
|
scopedEvents,
|
|
2957
3131
|
preSelectedEvent,
|
|
2958
3132
|
hasPreSelectedContext,
|
|
3133
|
+
checkoutRecovery,
|
|
3134
|
+
startCheckoutRecovery,
|
|
2959
3135
|
step,
|
|
2960
3136
|
setStep,
|
|
2961
3137
|
selectedEvent,
|
|
@@ -3159,6 +3335,51 @@ function getMagicLinkErrorMessage(error) {
|
|
|
3159
3335
|
return error instanceof Error ? error.message : "Failed to send. Please try again.";
|
|
3160
3336
|
}
|
|
3161
3337
|
//#endregion
|
|
3338
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/ErrorStep.tsx
|
|
3339
|
+
/**
|
|
3340
|
+
* Error Step
|
|
3341
|
+
*
|
|
3342
|
+
* Displays an error message with a retry button when registration fails.
|
|
3343
|
+
*/
|
|
3344
|
+
const labels = {
|
|
3345
|
+
none: "",
|
|
3346
|
+
retry: "Try again",
|
|
3347
|
+
places: "Choose places",
|
|
3348
|
+
start: "Start again",
|
|
3349
|
+
details: "Check my details",
|
|
3350
|
+
"payment-options": "View payment options",
|
|
3351
|
+
"payment-status": "Check payment status",
|
|
3352
|
+
portal: "View my bookings",
|
|
3353
|
+
event: "View event"
|
|
3354
|
+
};
|
|
3355
|
+
const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false }) => {
|
|
3356
|
+
const offerWaitlist = action === "places" && canJoinWaitlist;
|
|
3357
|
+
return /* @__PURE__ */ jsx(TerminalPanel, {
|
|
3358
|
+
tone: "error",
|
|
3359
|
+
className: "er-center",
|
|
3360
|
+
titleClassName: "er-title--lg er-message",
|
|
3361
|
+
icon: /* @__PURE__ */ jsx(StateIcon, {
|
|
3362
|
+
variant: "error",
|
|
3363
|
+
children: /* @__PURE__ */ jsx(CrossIcon, {})
|
|
3364
|
+
}),
|
|
3365
|
+
title: "We couldn’t complete your booking",
|
|
3366
|
+
body: /* @__PURE__ */ jsx("p", {
|
|
3367
|
+
className: "er-text--muted er-message",
|
|
3368
|
+
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
|
|
3369
|
+
}),
|
|
3370
|
+
actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
|
|
3371
|
+
href: "/portal",
|
|
3372
|
+
className: "er-retry-btn",
|
|
3373
|
+
children: labels[action]
|
|
3374
|
+
}) : /* @__PURE__ */ jsx("button", {
|
|
3375
|
+
type: "button",
|
|
3376
|
+
onClick: onRetry,
|
|
3377
|
+
className: "er-retry-btn",
|
|
3378
|
+
children: offerWaitlist ? "Join the waiting list" : labels[action]
|
|
3379
|
+
})
|
|
3380
|
+
});
|
|
3381
|
+
};
|
|
3382
|
+
//#endregion
|
|
3162
3383
|
//#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSummaryBar.tsx
|
|
3163
3384
|
function getScheduleSummary(wizard, summaryEvent) {
|
|
3164
3385
|
if (summaryEvent.registrationSubject.kind !== "wholeSeries") {
|
|
@@ -3442,7 +3663,7 @@ function SelectTicketsActions(props) {
|
|
|
3442
3663
|
const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
|
|
3443
3664
|
const registrationOptionsPending = wizard.registrationOptionsState.tag === "idle" || wizard.registrationOptionsState.tag === "loading";
|
|
3444
3665
|
const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
|
|
3445
|
-
const isSoldOutWithoutWaitlist = !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
|
|
3666
|
+
const isSoldOutWithoutWaitlist = !wizard.checkoutRecovery && !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
|
|
3446
3667
|
const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
|
|
3447
3668
|
const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
|
|
3448
3669
|
const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
|
|
@@ -4032,6 +4253,31 @@ function resolveTicketSelectionPricing(event) {
|
|
|
4032
4253
|
currency: event ? publicEventPricingCurrency(event.pricing) : null
|
|
4033
4254
|
};
|
|
4034
4255
|
}
|
|
4256
|
+
function CheckoutRecoveryEntry(props) {
|
|
4257
|
+
return props.onContinue ? /* @__PURE__ */ jsx("button", {
|
|
4258
|
+
type: "button",
|
|
4259
|
+
className: "er-back-btn",
|
|
4260
|
+
onClick: props.onContinue,
|
|
4261
|
+
children: "Continue an existing booking"
|
|
4262
|
+
}) : null;
|
|
4263
|
+
}
|
|
4264
|
+
function getTicketSelectionCapacity(event, attendanceMode, checkoutRecovery) {
|
|
4265
|
+
if (checkoutRecovery) return {
|
|
4266
|
+
availableSpots: null,
|
|
4267
|
+
isSoldOut: false,
|
|
4268
|
+
canJoinWaitlist: false,
|
|
4269
|
+
eventAvailabilityLabel: null
|
|
4270
|
+
};
|
|
4271
|
+
const source = event ? selectEventCapacitySource(event, attendanceMode) : null;
|
|
4272
|
+
const availability = source ? getEventAvailability(source) : null;
|
|
4273
|
+
const canJoinWaitlist = source ? canJoinEventWaitlist(source) : false;
|
|
4274
|
+
return {
|
|
4275
|
+
availableSpots: availability?.available,
|
|
4276
|
+
isSoldOut: availability?.isFull ?? false,
|
|
4277
|
+
canJoinWaitlist,
|
|
4278
|
+
eventAvailabilityLabel: !canJoinWaitlist && source ? formatRemainingPlaces(source) : null
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4035
4281
|
/**
|
|
4036
4282
|
* Ticket Selection Step
|
|
4037
4283
|
*
|
|
@@ -4040,15 +4286,11 @@ function resolveTicketSelectionPricing(event) {
|
|
|
4040
4286
|
*
|
|
4041
4287
|
* Can use either a full PublicEvent or just occurrence context (when on event page).
|
|
4042
4288
|
*/
|
|
4043
|
-
const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" } }) => {
|
|
4289
|
+
const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, selectedAttendanceMode = null, onAttendanceModeChange, ticketsCount, maxTickets, visibleTicketTypes: visibleTicketTypesOverride, ticketSelections = [], onTicketSelectionsChange, slidingScale = null, selectedSlidingAmountInput = "", slidingScaleSelectionMessage = null, onSlidingAmountChange, onTicketsChange, bookingUnit = { kind: "ticket" }, checkoutRecovery = false, onCheckoutRecovery }) => {
|
|
4044
4290
|
const unit = bookingUnit.kind;
|
|
4045
4291
|
const deliveryMode = event?.deliveryMode ?? "in_person";
|
|
4046
4292
|
const attendanceModes = event?.attendanceModes ?? [];
|
|
4047
|
-
const
|
|
4048
|
-
const availability = capacitySource ? getEventAvailability(capacitySource) : null;
|
|
4049
|
-
const availableSpots = availability?.available;
|
|
4050
|
-
const isSoldOut = availability?.isFull ?? false;
|
|
4051
|
-
const canJoinWaitlist = capacitySource ? canJoinEventWaitlist(capacitySource) : false;
|
|
4293
|
+
const { availableSpots, isSoldOut, canJoinWaitlist, eventAvailabilityLabel } = getTicketSelectionCapacity(event, selectedAttendanceMode, checkoutRecovery);
|
|
4052
4294
|
const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
|
|
4053
4295
|
const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
|
|
4054
4296
|
const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
|
|
@@ -4067,7 +4309,6 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
4067
4309
|
selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
|
|
4068
4310
|
hasSelectedTicketType: implicitTicketType !== null
|
|
4069
4311
|
});
|
|
4070
|
-
const eventAvailabilityLabel = !canJoinWaitlist && capacitySource ? formatRemainingPlaces(capacitySource) : null;
|
|
4071
4312
|
if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
|
|
4072
4313
|
className: "rb-reg-stack er-stack",
|
|
4073
4314
|
children: [
|
|
@@ -4088,13 +4329,17 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
4088
4329
|
});
|
|
4089
4330
|
if (isSoldOut && !canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
|
|
4090
4331
|
className: "rb-reg-stack er-stack",
|
|
4091
|
-
children: [
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4332
|
+
children: [
|
|
4333
|
+
/* @__PURE__ */ jsx("h3", {
|
|
4334
|
+
className: "er-title",
|
|
4335
|
+
children: "Sold out"
|
|
4336
|
+
}),
|
|
4337
|
+
/* @__PURE__ */ jsx("p", {
|
|
4338
|
+
className: "er-text er-text--muted",
|
|
4339
|
+
children: "Sorry you missed out! This event is fully booked."
|
|
4340
|
+
}),
|
|
4341
|
+
/* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })
|
|
4342
|
+
]
|
|
4098
4343
|
});
|
|
4099
4344
|
if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
|
|
4100
4345
|
className: "rb-reg-stack er-stack",
|
|
@@ -4162,9 +4407,13 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
4162
4407
|
})]
|
|
4163
4408
|
})
|
|
4164
4409
|
] }),
|
|
4165
|
-
canJoinWaitlist && /* @__PURE__ */ jsx("p", {
|
|
4410
|
+
canJoinWaitlist && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("p", {
|
|
4166
4411
|
className: "er-text er-text--muted",
|
|
4167
4412
|
children: "This event is currently full. Continue to join the waitlist if a place opens up."
|
|
4413
|
+
}), /* @__PURE__ */ jsx(CheckoutRecoveryEntry, { onContinue: onCheckoutRecovery })] }),
|
|
4414
|
+
checkoutRecovery && /* @__PURE__ */ jsx("p", {
|
|
4415
|
+
className: "er-text er-text--muted",
|
|
4416
|
+
children: "Enter the details from your earlier booking. We’ll check your checkout before continuing to payment."
|
|
4168
4417
|
})
|
|
4169
4418
|
]
|
|
4170
4419
|
});
|
|
@@ -5072,12 +5321,14 @@ function EventRegistrationWizardContent(props) {
|
|
|
5072
5321
|
onBookForSomeoneElse: wizard.handleBookForSomeoneElse
|
|
5073
5322
|
}), /* @__PURE__ */ jsx(TicketSelectionStep, {
|
|
5074
5323
|
event: wizard.selectedEvent,
|
|
5324
|
+
checkoutRecovery: wizard.checkoutRecovery,
|
|
5325
|
+
onCheckoutRecovery: canRecoverEventCheckout(wizard.selectedEvent) ? wizard.startCheckoutRecovery : void 0,
|
|
5075
5326
|
occurrenceContext: wizard.occurrenceContext,
|
|
5076
5327
|
selectedAttendanceMode: wizard.selectedAttendanceMode,
|
|
5077
5328
|
onAttendanceModeChange: wizard.setSelectedAttendanceMode,
|
|
5078
5329
|
ticketsCount: wizard.ticketsCount,
|
|
5079
5330
|
maxTickets: wizard.maxTicketsNum,
|
|
5080
|
-
visibleTicketTypes: wizard.
|
|
5331
|
+
visibleTicketTypes: wizard.visibleTicketTypes,
|
|
5081
5332
|
ticketSelections: wizard.selectedTicketLines,
|
|
5082
5333
|
onTicketSelectionsChange: wizard.setSelectedTicketLines,
|
|
5083
5334
|
slidingScale: wizard.selectedEventSlidingScale,
|
|
@@ -5096,66 +5347,6 @@ function EventRegistrationWizardContent(props) {
|
|
|
5096
5347
|
}
|
|
5097
5348
|
}
|
|
5098
5349
|
//#endregion
|
|
5099
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/StepIndicator.tsx
|
|
5100
|
-
/**
|
|
5101
|
-
* Step indicator component for the event registration wizard.
|
|
5102
|
-
* Thin wrapper around the shared StepIndicator: styled by the shared
|
|
5103
|
-
* registration-surface classes, with 'er'-prefixed classes kept in the
|
|
5104
|
-
* markup as the stable hook surface for per-site theme CSS.
|
|
5105
|
-
*/
|
|
5106
|
-
function StepIndicator(props) {
|
|
5107
|
-
return /* @__PURE__ */ jsx(StepIndicator$1, {
|
|
5108
|
-
...props,
|
|
5109
|
-
classPrefix: "er",
|
|
5110
|
-
emitSharedClasses: true
|
|
5111
|
-
});
|
|
5112
|
-
}
|
|
5113
|
-
//#endregion
|
|
5114
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/ErrorStep.tsx
|
|
5115
|
-
/**
|
|
5116
|
-
* Error Step
|
|
5117
|
-
*
|
|
5118
|
-
* Displays an error message with a retry button when registration fails.
|
|
5119
|
-
*/
|
|
5120
|
-
const labels = {
|
|
5121
|
-
none: "",
|
|
5122
|
-
retry: "Try again",
|
|
5123
|
-
places: "Choose places",
|
|
5124
|
-
start: "Start again",
|
|
5125
|
-
details: "Check my details",
|
|
5126
|
-
"payment-options": "View payment options",
|
|
5127
|
-
"payment-status": "Check payment status",
|
|
5128
|
-
portal: "View my bookings",
|
|
5129
|
-
event: "View event"
|
|
5130
|
-
};
|
|
5131
|
-
const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false }) => {
|
|
5132
|
-
const offerWaitlist = action === "places" && canJoinWaitlist;
|
|
5133
|
-
return /* @__PURE__ */ jsx(TerminalPanel, {
|
|
5134
|
-
tone: "error",
|
|
5135
|
-
className: "er-center",
|
|
5136
|
-
titleClassName: "er-title--lg er-message",
|
|
5137
|
-
icon: /* @__PURE__ */ jsx(StateIcon, {
|
|
5138
|
-
variant: "error",
|
|
5139
|
-
children: /* @__PURE__ */ jsx(CrossIcon, {})
|
|
5140
|
-
}),
|
|
5141
|
-
title: "We couldn’t complete your booking",
|
|
5142
|
-
body: /* @__PURE__ */ jsx("p", {
|
|
5143
|
-
className: "er-text--muted er-message",
|
|
5144
|
-
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
|
|
5145
|
-
}),
|
|
5146
|
-
actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
|
|
5147
|
-
href: "/portal",
|
|
5148
|
-
className: "er-retry-btn",
|
|
5149
|
-
children: labels[action]
|
|
5150
|
-
}) : /* @__PURE__ */ jsx("button", {
|
|
5151
|
-
type: "button",
|
|
5152
|
-
onClick: onRetry,
|
|
5153
|
-
className: "er-retry-btn",
|
|
5154
|
-
children: offerWaitlist ? "Join the waiting list" : labels[action]
|
|
5155
|
-
})
|
|
5156
|
-
});
|
|
5157
|
-
};
|
|
5158
|
-
//#endregion
|
|
5159
5350
|
//#region ../blocks/src/system/runtime/nodes/event-registration/PaymentFailedStep.tsx
|
|
5160
5351
|
/**
|
|
5161
5352
|
* Payment Failed Step
|
|
@@ -5186,6 +5377,21 @@ const PaymentFailedStep = ({ onRetry }) => {
|
|
|
5186
5377
|
});
|
|
5187
5378
|
};
|
|
5188
5379
|
//#endregion
|
|
5380
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/StepIndicator.tsx
|
|
5381
|
+
/**
|
|
5382
|
+
* Step indicator component for the event registration wizard.
|
|
5383
|
+
* Thin wrapper around the shared StepIndicator: styled by the shared
|
|
5384
|
+
* registration-surface classes, with 'er'-prefixed classes kept in the
|
|
5385
|
+
* markup as the stable hook surface for per-site theme CSS.
|
|
5386
|
+
*/
|
|
5387
|
+
function StepIndicator(props) {
|
|
5388
|
+
return /* @__PURE__ */ jsx(StepIndicator$1, {
|
|
5389
|
+
...props,
|
|
5390
|
+
classPrefix: "er",
|
|
5391
|
+
emitSharedClasses: true
|
|
5392
|
+
});
|
|
5393
|
+
}
|
|
5394
|
+
//#endregion
|
|
5189
5395
|
//#region ../blocks/src/system/runtime/nodes/event-registration/SuccessStep.tsx
|
|
5190
5396
|
/**
|
|
5191
5397
|
* Success Step
|
|
@@ -5458,7 +5664,8 @@ function EventRegistrationSurface(props) {
|
|
|
5458
5664
|
}), /* @__PURE__ */ jsx(EventRegistrationTerminalState, {
|
|
5459
5665
|
wizard,
|
|
5460
5666
|
supportEmail: props.supportEmail,
|
|
5461
|
-
successMessage: props.successMessage
|
|
5667
|
+
successMessage: props.successMessage,
|
|
5668
|
+
buttonClass: props.buttonClass
|
|
5462
5669
|
})]
|
|
5463
5670
|
});
|
|
5464
5671
|
}
|
|
@@ -5856,6 +6063,84 @@ function RegistrationClosedState({ title, body }) {
|
|
|
5856
6063
|
});
|
|
5857
6064
|
}
|
|
5858
6065
|
//#endregion
|
|
6066
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventSourceRecovery.ts
|
|
6067
|
+
const RECOVERY_DELAYS_MS = [
|
|
6068
|
+
0,
|
|
6069
|
+
250,
|
|
6070
|
+
750
|
|
6071
|
+
];
|
|
6072
|
+
const defaultRecoveryDeps = {
|
|
6073
|
+
useApi: useBlockApi,
|
|
6074
|
+
wait: waitForRetry
|
|
6075
|
+
};
|
|
6076
|
+
function useEventSourceRecovery(source, deps = defaultRecoveryDeps) {
|
|
6077
|
+
const api = deps.useApi();
|
|
6078
|
+
const wait = deps.wait;
|
|
6079
|
+
const [cycle, setCycle] = useState(0);
|
|
6080
|
+
const [state, setState] = useState(() => source.kind === "loaded" ? {
|
|
6081
|
+
kind: "ready",
|
|
6082
|
+
events: source.events
|
|
6083
|
+
} : { kind: "loading" });
|
|
6084
|
+
const retry = useCallback(() => {
|
|
6085
|
+
setState({ kind: "loading" });
|
|
6086
|
+
setCycle((value) => value + 1);
|
|
6087
|
+
}, []);
|
|
6088
|
+
useEffect(() => {
|
|
6089
|
+
if (source.kind === "loaded") {
|
|
6090
|
+
setState({
|
|
6091
|
+
kind: "ready",
|
|
6092
|
+
events: source.events
|
|
6093
|
+
});
|
|
6094
|
+
return;
|
|
6095
|
+
}
|
|
6096
|
+
if (!source.request) {
|
|
6097
|
+
setState({
|
|
6098
|
+
kind: "exhausted",
|
|
6099
|
+
retry
|
|
6100
|
+
});
|
|
6101
|
+
return;
|
|
6102
|
+
}
|
|
6103
|
+
const controller = new AbortController();
|
|
6104
|
+
const isCurrent = () => !controller.signal.aborted;
|
|
6105
|
+
(async () => {
|
|
6106
|
+
for (const delayMs of RECOVERY_DELAYS_MS) try {
|
|
6107
|
+
await wait(delayMs, controller.signal);
|
|
6108
|
+
const events = await api.getPublicEvents(source.request ?? void 0);
|
|
6109
|
+
if (isCurrent()) setState({
|
|
6110
|
+
kind: "ready",
|
|
6111
|
+
events
|
|
6112
|
+
});
|
|
6113
|
+
return;
|
|
6114
|
+
} catch {
|
|
6115
|
+
if (!isCurrent()) return;
|
|
6116
|
+
}
|
|
6117
|
+
if (isCurrent()) setState({
|
|
6118
|
+
kind: "exhausted",
|
|
6119
|
+
retry
|
|
6120
|
+
});
|
|
6121
|
+
})();
|
|
6122
|
+
return () => controller.abort();
|
|
6123
|
+
}, [
|
|
6124
|
+
api,
|
|
6125
|
+
cycle,
|
|
6126
|
+
retry,
|
|
6127
|
+
source,
|
|
6128
|
+
wait
|
|
6129
|
+
]);
|
|
6130
|
+
return state;
|
|
6131
|
+
}
|
|
6132
|
+
function waitForRetry(milliseconds, signal) {
|
|
6133
|
+
if (signal.aborted) return Promise.reject(/* @__PURE__ */ new Error("Recovery aborted"));
|
|
6134
|
+
if (milliseconds === 0) return Promise.resolve();
|
|
6135
|
+
return new Promise((resolve, reject) => {
|
|
6136
|
+
const timeout = setTimeout(resolve, milliseconds);
|
|
6137
|
+
signal.addEventListener("abort", () => {
|
|
6138
|
+
clearTimeout(timeout);
|
|
6139
|
+
reject(/* @__PURE__ */ new Error("Recovery aborted"));
|
|
6140
|
+
}, { once: true });
|
|
6141
|
+
});
|
|
6142
|
+
}
|
|
6143
|
+
//#endregion
|
|
5859
6144
|
//#region ../blocks/src/system/runtime/nodes/event-registration.client.tsx
|
|
5860
6145
|
function toEventRegistrationClientProps(props, display) {
|
|
5861
6146
|
return {
|
|
@@ -5889,8 +6174,71 @@ const EventRegistrationIslandClient = (props) => {
|
|
|
5889
6174
|
title: props.render.display.titleText,
|
|
5890
6175
|
body: props.render.display.bodyText
|
|
5891
6176
|
});
|
|
5892
|
-
return /* @__PURE__ */ jsx(
|
|
6177
|
+
return /* @__PURE__ */ jsx(RecoverableEventRegistrationClient, {
|
|
6178
|
+
props,
|
|
6179
|
+
display: props.render.display
|
|
6180
|
+
});
|
|
5893
6181
|
};
|
|
6182
|
+
function RecoverableEventRegistrationClient({ props, display }) {
|
|
6183
|
+
const recovery = useEventSourceRecovery(props.render.hydration.eventSource);
|
|
6184
|
+
if (recovery.kind === "loading") return /* @__PURE__ */ jsxs("div", {
|
|
6185
|
+
id: EVENT_REGISTRATION_ANCHOR_ID,
|
|
6186
|
+
className: "rb-reg-surface er-container er-registration-shell",
|
|
6187
|
+
"aria-busy": "true",
|
|
6188
|
+
role: "status",
|
|
6189
|
+
children: [
|
|
6190
|
+
/* @__PURE__ */ jsx("p", {
|
|
6191
|
+
className: "er-registration-shell__eyebrow",
|
|
6192
|
+
children: "Registration"
|
|
6193
|
+
}),
|
|
6194
|
+
/* @__PURE__ */ jsx("h3", {
|
|
6195
|
+
className: "er-title er-registration-shell__title",
|
|
6196
|
+
children: display.titleText
|
|
6197
|
+
}),
|
|
6198
|
+
/* @__PURE__ */ jsx("p", {
|
|
6199
|
+
className: "er-text er-text--muted",
|
|
6200
|
+
children: "Loading event dates…"
|
|
6201
|
+
}),
|
|
6202
|
+
/* @__PURE__ */ jsxs("div", {
|
|
6203
|
+
className: "er-event-grid er-registration-shell__cards",
|
|
6204
|
+
"aria-hidden": "true",
|
|
6205
|
+
children: [/* @__PURE__ */ jsx("div", { className: "er-event-card er-registration-shell__card" }), /* @__PURE__ */ jsx("div", { className: "er-event-card er-registration-shell__card" })]
|
|
6206
|
+
})
|
|
6207
|
+
]
|
|
6208
|
+
});
|
|
6209
|
+
if (recovery.kind === "exhausted") return /* @__PURE__ */ jsxs("div", {
|
|
6210
|
+
id: EVENT_REGISTRATION_ANCHOR_ID,
|
|
6211
|
+
className: "rb-reg-surface er-container er-registration-shell",
|
|
6212
|
+
role: "alert",
|
|
6213
|
+
children: [/* @__PURE__ */ jsx("p", { children: "We couldn’t load the event dates. Please try again." }), /* @__PURE__ */ jsx("button", {
|
|
6214
|
+
type: "button",
|
|
6215
|
+
className: themeButtonClassName({
|
|
6216
|
+
variant: props.render.hydration.buttonVariant ?? "primary",
|
|
6217
|
+
size: "md"
|
|
6218
|
+
}),
|
|
6219
|
+
onClick: recovery.retry,
|
|
6220
|
+
children: "Try again"
|
|
6221
|
+
})]
|
|
6222
|
+
});
|
|
6223
|
+
const events = resolveEventRegistrationScopedEvents(recovery.events, {
|
|
6224
|
+
occurrenceContext: props.render.hydration.occurrenceContext,
|
|
6225
|
+
subject: props.render.hydration.subject
|
|
6226
|
+
});
|
|
6227
|
+
const recoveredDisplay = buildEventRegistrationDisplayFromScopedEvents({
|
|
6228
|
+
...props.render.hydration,
|
|
6229
|
+
events,
|
|
6230
|
+
className: display.className,
|
|
6231
|
+
buttonText: display.summaryButtonText
|
|
6232
|
+
}, events);
|
|
6233
|
+
if (recoveredDisplay.state === "registration-closed") return /* @__PURE__ */ jsx(RegistrationClosedState, {
|
|
6234
|
+
title: recoveredDisplay.titleText,
|
|
6235
|
+
body: recoveredDisplay.bodyText
|
|
6236
|
+
});
|
|
6237
|
+
return /* @__PURE__ */ jsx(EventRegistrationClient, {
|
|
6238
|
+
...toEventRegistrationClientProps(props, display),
|
|
6239
|
+
events
|
|
6240
|
+
});
|
|
6241
|
+
}
|
|
5894
6242
|
//#endregion
|
|
5895
6243
|
//#region src/rendering/islands/enhancers/eventRegistration.tsx
|
|
5896
6244
|
const decode = defineIslandPropsDecoder("event-registration");
|