@riverbankcms/sdk 0.148.0 → 0.150.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/EventEmbeddedCheckoutStep-D00Kc8Zj.mjs +285 -0
- package/dist/{PreviewEditorSidebar-DvEPG3Z2.mjs → PreviewEditorSidebar-7ZhmmnBB.mjs} +103 -66
- package/dist/{PreviewEditorUI-D6eb6fkx.mjs → PreviewEditorUI-BIJucTRd.mjs} +3 -6
- package/dist/{PreviewQueryProvider-5znTyJuz.mjs → PreviewQueryProvider-C0mndwHB.mjs} +3 -3
- package/dist/{SdkPreviewModeRuntime-DJ6utQ_R.mjs → SdkPreviewModeRuntime-tj45gmCX.mjs} +96 -67
- package/dist/{SiteChromeCustomizeContext-CFJYh6vo.mjs → SiteChromeCustomizeContext-BFOt0ss-.mjs} +4804 -4161
- package/dist/_dts/ai/src/contracts/proposals.d.ts +660 -0
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +510 -0
- package/dist/_dts/api/src/billing.d.ts +2 -2
- package/dist/_dts/api/src/bookingConfig.d.ts +33 -48
- package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +2 -6
- package/dist/_dts/api/src/bookingOperations.d.ts +5 -7
- package/dist/_dts/api/src/bookingRecords.d.ts +15 -11
- package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +5 -5
- package/dist/_dts/api/src/clientErrorReporting.d.ts +11 -0
- package/dist/_dts/api/src/commercePortalEndpoints.d.ts +0 -2
- package/dist/_dts/api/src/common/cancellation.d.ts +23 -0
- package/dist/_dts/api/src/contentRuntime.d.ts +5 -1
- package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +1 -1
- package/dist/_dts/api/src/endpoints.d.ts +2 -10
- package/dist/_dts/api/src/eventManagementContracts.d.ts +4 -7
- package/dist/_dts/api/src/footerCompositionContracts.d.ts +9 -0
- package/dist/_dts/api/src/footerSettings.d.ts +3 -3
- package/dist/_dts/api/src/index.d.ts +4 -4
- package/dist/_dts/api/src/navigation/bookingPortalLink.d.ts +13 -0
- package/dist/_dts/api/src/navigation.d.ts +1 -0
- package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +2 -2
- package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +2 -29
- package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +9 -173
- package/dist/_dts/api/src/request.d.ts +1 -1
- package/dist/_dts/api/src/sdk-event-upsert.d.ts +1 -1
- package/dist/_dts/api/src/sdkPullEventContracts.d.ts +1 -1
- package/dist/_dts/api/src/sdkThemeWire.d.ts +12 -0
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +3 -3
- package/dist/_dts/api/src/siteOperations.d.ts +6 -2
- package/dist/_dts/api/src/siteSettings.d.ts +2 -0
- package/dist/_dts/blocks/src/client/site-chrome.d.ts +1 -1
- package/dist/_dts/blocks/src/client.d.ts +2 -1
- package/dist/_dts/blocks/src/contracts/index.d.ts +1 -1
- package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +2 -2
- package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +38 -10
- package/dist/_dts/blocks/src/portal/types.d.ts +9 -6
- package/dist/_dts/blocks/src/rendering/server.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +24 -24
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/shared/bookingPaymentTerms.d.ts +84 -160
- package/dist/_dts/blocks/src/system/blocks/shop.d.ts +2 -2
- package/dist/_dts/blocks/src/system/blocks/shop.shared.d.ts +31 -4
- package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +30 -3
- package/dist/_dts/blocks/src/system/designCapabilities.d.ts +10 -1
- package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +3 -1
- package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +38 -18
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +48 -6
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -3
- package/dist/_dts/blocks/src/system/runtime/hooks/useBookingNowIso.d.ts +8 -0
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.server.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/commerce/shared/display.d.ts +9 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +14 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventEmbeddedCheckoutStep.d.ts +13 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationPayment.d.ts +15 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +0 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/FullyBookedStep.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentBlockingPanel.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +15 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +4 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +3 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/paymentLocation.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/paymentResponse.d.ts +72 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +66 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.d.ts +13 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +11 -52
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +19 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -42
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +7 -8
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +94 -24
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useGuestRegistrationRecovery.d.ts +30 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +24 -12
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useRegistrationAdmission.d.ts +18 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/wizardSteps.d.ts +6 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +24 -24
- package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +41 -6
- package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptions.d.ts +7 -2
- package/dist/_dts/blocks/src/system/runtime/shared/stripe/browserStripe.d.ts +8 -0
- package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +8 -0
- package/dist/_dts/commerce/src/purchase/bookingPaymentSelection.d.ts +54 -0
- package/dist/_dts/commerce/src/purchase/checkoutCommitPlan.d.ts +58 -13
- package/dist/_dts/commerce/src/purchase/checkoutCopy.d.ts +10 -0
- package/dist/_dts/commerce/src/purchase/checkoutErrorCodes.d.ts +1 -1
- package/dist/_dts/commerce/src/purchase/checkoutPaymentPlanPlanning.d.ts +16 -21
- package/dist/_dts/commerce/src/purchase/checkoutPaymentTerms.d.ts +23 -40
- package/dist/_dts/commerce/src/purchase/checkoutPresentation.d.ts +49 -0
- package/dist/_dts/commerce/src/purchase/checkoutSessionMetadata.d.ts +6 -6
- package/dist/_dts/commerce/src/purchase/checkoutStripeFinalizationPlanning.d.ts +5 -1
- package/dist/_dts/commerce/src/purchase/checkoutStripeSessionPlanning.d.ts +5 -4
- package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +9 -0
- package/dist/_dts/commerce/src/purchase/index.d.ts +3 -3
- package/dist/_dts/commerce/src/purchase/membershipOrderItemMetadata.d.ts +4 -0
- package/dist/_dts/commerce/src/purchase/oneTimeCheckoutPlanning.d.ts +9 -4
- package/dist/_dts/commerce/src/purchase/orderInstalmentClosure.d.ts +13 -1
- package/dist/_dts/commerce/src/purchase/orderInstalmentLifecycle.d.ts +5 -0
- package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +4 -1
- package/dist/_dts/commerce/src/purchase/orderTypes.d.ts +7 -1
- package/dist/_dts/commerce/src/purchase/refundRailSplit.d.ts +1 -1
- package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +2 -2
- package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +9 -2
- package/dist/_dts/commerce/src/purchase/stripeMinimumCharge.d.ts +6 -0
- package/dist/_dts/commerce/src/purchase/types.d.ts +7 -7
- package/dist/_dts/content-editor/src/FooterComposerOverview.d.ts +3 -2
- package/dist/_dts/content-editor/src/controller/editLeaseHandover.d.ts +30 -0
- package/dist/_dts/content-editor/src/footerPreviewRuntime.d.ts +6 -1
- package/dist/_dts/content-editor/src/lib/browserStorage.d.ts +5 -0
- package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +7 -0
- package/dist/_dts/core/src/booking-flexible-balance.d.ts +2 -2
- package/dist/_dts/core/src/booking-instalment-deposit.d.ts +20 -0
- package/dist/_dts/core/src/booking-live-payment-terms.d.ts +72 -0
- package/dist/_dts/core/src/booking-payment-options.d.ts +24 -0
- package/dist/_dts/core/src/booking-payment-schemas.d.ts +522 -0
- package/dist/_dts/core/src/branded.d.ts +3 -0
- package/dist/_dts/core/src/edit-lease.d.ts +5 -0
- package/dist/_dts/core/src/index.d.ts +4 -0
- package/dist/_dts/core/src/patch/index.d.ts +30 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +326 -36
- package/dist/_dts/media-editor/src/MediaPickerDialog.d.ts +3 -1
- package/dist/_dts/media-editor/src/MediaPickerMiniDialog.d.ts +10 -0
- package/dist/_dts/media-editor/src/index.d.ts +2 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +0 -1
- package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -1
- package/dist/_dts/preview-next/src/client/previewAuthStore.d.ts +7 -0
- package/dist/_dts/preview-next/src/constants.d.ts +4 -0
- package/dist/_dts/preview-next/src/keepAlive.d.ts +1 -0
- package/dist/_dts/sdk/src/bookings/index.d.ts +2 -1
- package/dist/_dts/sdk/src/bookings/types.d.ts +1 -1
- package/dist/_dts/sdk/src/rendering/islands/types.d.ts +2 -12
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/blocks/index.d.ts +1 -0
- package/dist/_dts/theme-core/src/blocks/opaquePanels.d.ts +147 -0
- package/dist/_dts/theme-core/src/boxBackgroundSchema.d.ts +22 -0
- package/dist/_dts/theme-core/src/buttons/buttonSurfaceContext.d.ts +22 -0
- package/dist/_dts/theme-core/src/cards/roles.d.ts +12 -0
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +198 -0
- package/dist/_dts/theme-core/src/palette/utils/index.d.ts +2 -0
- package/dist/_dts/theme-core/src/palette/utils/scrimContrast.d.ts +22 -0
- package/dist/_dts/theme-core/src/runtime/bridgeColourTokens.d.ts +10 -0
- package/dist/_dts/theme-core/src/schema.d.ts +330 -0
- package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +0 -51
- package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +0 -51
- package/dist/_dts/theme-core/src/site-styles/lookResolution.d.ts +11 -0
- package/dist/_dts/theme-core/src/site-styles/pageDesignEditorCapabilities.d.ts +7 -1
- package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +7 -1
- package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +0 -5
- package/dist/_dts/theme-core/src/site-styles/previewRuntimeCapabilities.d.ts +12 -6
- package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +7 -4
- package/dist/_dts/theme-core/src/site-styles/sectionSurfaceBackgrounds.d.ts +65 -0
- package/dist/_dts/theme-core/src/site-styles/types.d.ts +17 -0
- package/dist/_dts/theme-core/src/surfaces/opaqueSurface.d.ts +43 -0
- package/dist/_dts/ui/src/color-picker.d.ts +1 -1
- package/dist/_dts/ui/src/palette/useHexDraft.d.ts +7 -0
- package/dist/client/{BookingMailingListNote-CzRt2dF_.mjs → BookingMailingListNote-CYHOufsI.mjs} +33 -124
- package/dist/client/{CheckboxChoice-B33MqoUo.mjs → CheckboxChoice-M-3HycLw.mjs} +1 -1
- package/dist/client/{DemoBookingPortalAccess-mxqwap3f.mjs → DemoBookingPortalAccess-Cvr9O_ca.mjs} +2 -2
- package/dist/client/{EventCombined.client-CDb11igO.mjs → EventCombined.client-m5UZIobP.mjs} +7 -7
- package/dist/client/EventEmbeddedCheckoutStep-DL6zFAkA.mjs +289 -0
- package/dist/client/{EventListing.client-EgYhzKPa.mjs → EventListing.client-DeMfCM04.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-gtmtaA2b.mjs → LeafletStaticMap-CvZ3gOdD.mjs} +1 -1
- package/dist/client/{checkoutUrls-CXhko2Rv.mjs → RichText-BtfNvQV6.mjs} +2 -29
- package/dist/client/{TerminalPanel-DvNUP5ot.mjs → TerminalPanel-CUCNEwlH.mjs} +2 -18
- package/dist/client/{ThemedButton-C7CeUJjW.mjs → ThemedButton-C7WhXuRl.mjs} +2 -2
- package/dist/client/{accordion-kjvt49rA.mjs → accordion-cQm5mjqs.mjs} +1 -1
- package/dist/client/{bookingForm-pbRZordh.mjs → bookingForm-BVPJE5RQ.mjs} +15 -11
- package/dist/client/bookings.mjs +2860 -1222
- package/dist/client/{carousel-f4Zbmicv.mjs → carousel-3vgnY7LC.mjs} +2 -2
- package/dist/client/{carousel.client-A2lG-9od.mjs → carousel.client-CISsdZvg.mjs} +1 -1
- package/dist/client/{cart-DO20An50.mjs → cart-BGK4oOjm.mjs} +3 -3
- package/dist/client/{checkout-Du5amDR_.mjs → checkout-GsBLUNJD.mjs} +3 -3
- package/dist/client/checkoutUrls-ChxwaNtO.mjs +28 -0
- package/dist/client/client.mjs +3324 -2053
- package/dist/client/{colorStyles-j5U9v5JA.mjs → colorStyles-D-32xHZh.mjs} +2 -30
- package/dist/client/{context-eW97E945.mjs → context-D_8s12Fp.mjs} +1 -1
- package/dist/client/{dates-jPCirRea.mjs → dates-DeJQbQ9T.mjs} +2 -2
- package/dist/client/{eventCalendar-C2M-iE4j.mjs → eventCalendar-cmucD4NR.mjs} +10 -10
- package/dist/client/{eventCombined-W6ns3LHg.mjs → eventCombined-ku3E9FTl.mjs} +4 -4
- package/dist/client/{eventDetails-CR-GT0f0.mjs → eventDetails-CyKZ61sF.mjs} +5 -5
- package/dist/client/{eventListing-BK8AfYZz.mjs → eventListing-B7yxGIhX.mjs} +4 -4
- package/dist/client/{eventRegistration-BJSd4KUu.mjs → eventRegistration-BoXfSFgZ.mjs} +1455 -1184
- package/dist/client/{form-BvpfbQaT.mjs → form-CNQOWhJo.mjs} +5 -5
- package/dist/client/{headerSection-I5sUQ8x-.mjs → headerSection-DahaBJGQ.mjs} +3 -3
- package/dist/client/hooks.mjs +283 -193
- package/dist/client/{locationMap-BLvwf9_f.mjs → locationMap-BoDjqYlW.mjs} +4 -4
- package/dist/client/{media-Cl38iOMI.mjs → media-BFY0y2rb.mjs} +2 -1
- package/dist/client/{newsletterForm-DrQ2weE8.mjs → newsletterForm-DtzXDklw.mjs} +4 -4
- package/dist/client/{pricing-BES87mrR.mjs → pricing-DXEh2Lhh.mjs} +1 -1
- package/dist/client/{productDetail-Url9jcc5.mjs → productDetail-D7cPa-00.mjs} +3 -3
- package/dist/client/{productList-DE7ngEZJ.mjs → productList-D1XMap66.mjs} +3 -3
- package/dist/client/{propsDecoder-D1OtGXDV.mjs → propsDecoder-DiIeBopB.mjs} +913 -322
- package/dist/client/rendering/client.mjs +3913 -2260
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +3302 -2013
- package/dist/client/result-DRW7JWXz.mjs +30 -0
- package/dist/client/{routeIslandApiConfig-BG9Y-SHg.mjs → routeIslandApiConfig-wzR4lKAY.mjs} +1 -1
- package/dist/client/scrollToBlock-C86BYkyV.mjs +17 -0
- package/dist/client/{shop-CJkuySJ3.mjs → shop-CYT5P-S5.mjs} +13 -14
- package/dist/client/{shop-commerce-store-Bxm75Pg6.mjs → shop-commerce-store-wKhsJQxI.mjs} +1 -1
- package/dist/client/{shop-commerce-4rKj5n9h.mjs → shop-commerce-ypBu_dx4.mjs} +9 -9
- package/dist/client/{shopShared-DpoQDWfz.mjs → shopShared-DFGhYrf2.mjs} +52 -6
- package/dist/client/{useEventFilters-D8HliSqR.mjs → useEventFilters-blSbN5o7.mjs} +8 -8
- package/dist/preview-next/before-render.mjs +15 -22
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/constants.mjs +5 -1
- package/dist/preview-next/index.mjs +5 -1
- package/dist/preview-next/keepAlive.mjs +149 -82
- package/dist/preview-next/middleware.mjs +15 -22
- package/dist/{previewAuthStore-BXXF3hhW.mjs → previewAuthStore-BBmV7UsW.mjs} +49 -29
- package/dist/{sdk-runtime-C2a05WjL.mjs → sdk-runtime-2p8uQk1V.mjs} +2 -2
- package/dist/{separator-CuNhBAhS.mjs → separator-Cvvzk0Oo.mjs} +1 -1
- package/dist/server/components.mjs +4041 -3704
- package/dist/server/config-validation.mjs +345 -255
- package/dist/server/config.mjs +345 -255
- package/dist/server/data.mjs +283 -193
- package/dist/server/index.mjs +20 -27
- package/dist/server/next.mjs +788 -469
- package/dist/server/page-converter.mjs +245 -121
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +4018 -3690
- package/dist/server/rendering.mjs +4044 -3707
- package/dist/server/routing.mjs +314 -190
- package/dist/server/server.mjs +290 -218
- package/dist/server/theme-bridge.mjs +1122 -310
- package/dist/server/theme.mjs +126 -116
- package/dist/spinner-CDo6AkDz.mjs +658 -0
- package/dist/styles/index.css +75 -212
- package/package.json +1 -1
- package/dist/_dts/api/src/bookingPaymentTermSchemas.d.ts +0 -123
- package/dist/_dts/billing/src/checkout/platform.d.ts +0 -77
- package/dist/_dts/billing/src/config/env.d.ts +0 -29
- package/dist/_dts/billing/src/stripe/client.d.ts +0 -29
- package/dist/_dts/blocks/src/system/runtime/hooks/usePaymentVerification.d.ts +0 -63
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.d.ts +0 -9
- package/dist/_dts/commerce/src/purchase/checkoutPaymentTermPlanning.d.ts +0 -10
- package/dist/_dts/commerce/src/purchase/checkoutValidatedItemPlanning.d.ts +0 -55
- package/dist/_dts/commerce/src/purchase/orderInstalmentPayoff.d.ts +0 -24
- package/dist/client/urlParams-D71VXFGx.mjs +0 -47
|
@@ -1,39 +1,25 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as BookingConsentAgreement, o as resolveBookingPaymentDueNowCents, r as StepIndicator$1, s as formatPrice, t as BookingMailingListNote } from "./BookingMailingListNote-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { a as buildBookingPaymentSelectionViewModel, c as useBookingNowIso, i as usePolling, n as BookingConsentAgreement, o as resolveBookingPaymentDueNowCents, r as StepIndicator$1, s as formatPrice, t as BookingMailingListNote } from "./BookingMailingListNote-CYHOufsI.mjs";
|
|
3
|
+
import { $t as parseEventRegistrationErrorReason, An as publicEventPricingOptions, C as resolveDiscountContext, D as getRegistrationStepPresentation, E as toRegistrationRequestSubject, M as resolveEventRegistrationScopedEvents, Mn as publicEventPricingType, Nn as formatCurrencyAmount, O as getStepNumber, On as publicEventPricingCurrency, Ot as getRegistrationSuccessCopy, Qt as eventRegistrationErrors, S as findPreSelectedEvent, Sn as toScheduledBookingDateTime, T as resolveRegistrationTarget, Wt as assertNever, _ as buildEventRegistrationDisplayFromScopedEvents, b as toWholeSeriesRegistrationEvents, bn as toBookingTimeZone, cn as resolveBookingSignupOffer, en as getStripeMinimumChargeRequirement, fn as formatBookingDateTime, ft as groupPublicEventsByRun, jn as publicEventPricingStrategy, k as getWizardStepsForContext, mn as formatBookingTime, nn as planFlexibleBalanceCreditFirst, t as defineIslandPropsDecoder, tn as planCheckoutPaymentFlow, un as formatBookingDate, v as getRegistrationStartAt, w as resolveEventRequiresPayment, x as findEventByOccurrenceId, y as toRegistrationEvents } from "./propsDecoder-DiIeBopB.mjs";
|
|
4
|
+
import { i as SpinnerNode, n as ThemedButtonLink, t as ThemedButton } from "./ThemedButton-C7WhXuRl.mjs";
|
|
5
|
+
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-DXEh2Lhh.mjs";
|
|
6
|
+
import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-D_8s12Fp.mjs";
|
|
6
7
|
import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
|
|
7
|
-
import { a as requestDemoPortalMagicLink, f as storeDemoBookingPass, i as buildPortalCallbackUrl, o as DiscountCodeDisclosure, r as CUSTOMER_PORTAL_PATH, t as BookingConfirmation } from "./DemoBookingPortalAccess-
|
|
8
|
-
import {
|
|
9
|
-
import { i as SpinnerNode, n as ThemedButtonLink, t as ThemedButton } from "./ThemedButton-C7CeUJjW.mjs";
|
|
8
|
+
import { a as requestDemoPortalMagicLink, f as storeDemoBookingPass, i as buildPortalCallbackUrl, o as DiscountCodeDisclosure, r as CUSTOMER_PORTAL_PATH, t as BookingConfirmation } from "./DemoBookingPortalAccess-Cvr9O_ca.mjs";
|
|
9
|
+
import { i as useDiscountCodeUi, n as StateIcon, r as CheckIcon, t as TerminalPanel } from "./TerminalPanel-CUCNEwlH.mjs";
|
|
10
10
|
import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
|
|
11
11
|
import { i as getFieldValidationControlProps, r as FieldValidationMessage } from "./mailingListSignupCopy-DZSHZrm6.mjs";
|
|
12
|
-
import { t as
|
|
13
|
-
import { t as CheckboxChoice } from "./CheckboxChoice-B33MqoUo.mjs";
|
|
12
|
+
import { t as CheckboxChoice } from "./CheckboxChoice-M-3HycLw.mjs";
|
|
14
13
|
import { t as createBodyThemePortalRoot } from "./themePortalRoot-AGs4cE7t.mjs";
|
|
15
|
-
import { n as consumeSearchParams } from "./urlParams-D71VXFGx.mjs";
|
|
16
14
|
import { t as CrossIcon } from "./CrossIcon-Dn1KRKW5.mjs";
|
|
17
15
|
import { t as mountReactIsland } from "./reactMount-SY8AVRof.mjs";
|
|
18
|
-
import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-
|
|
16
|
+
import { t as buildRouteIslandApiConfig } from "./routeIslandApiConfig-wzR4lKAY.mjs";
|
|
19
17
|
import { t as createLucideIcon } from "./createLucideIcon-PaLVMov4.mjs";
|
|
20
18
|
import { t as ModalShell } from "./ModalShell-CqkBvBIC.mjs";
|
|
21
|
-
import React, { useCallback, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
19
|
+
import React, { Suspense, lazy, useCallback, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
22
20
|
import { z } from "zod";
|
|
23
21
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
24
22
|
import { createPortal } from "react-dom";
|
|
25
|
-
//#region ../core/src/money-input.ts
|
|
26
|
-
function unsafeAsNonNegativeCents(value) {
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Normalizes a derived amount to non-negative whole cents. This intentionally
|
|
31
|
-
* clamps negatives to zero; use parseNonNegativeCents for validation.
|
|
32
|
-
*/
|
|
33
|
-
function toNonNegativeCents(value) {
|
|
34
|
-
return unsafeAsNonNegativeCents(Math.max(0, Math.trunc(value)));
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
37
23
|
//#region ../core/src/uuid.ts
|
|
38
24
|
function generateUuidV4(cryptoSource = globalThis.crypto) {
|
|
39
25
|
if (typeof cryptoSource.randomUUID === "function") return cryptoSource.randomUUID();
|
|
@@ -188,6 +174,161 @@ const Wallet = createLucideIcon("wallet", [["path", {
|
|
|
188
174
|
key: "xoc0q4"
|
|
189
175
|
}]]);
|
|
190
176
|
//#endregion
|
|
177
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
|
|
178
|
+
/** One admission decision for navigation, labels and completion. Email recovery
|
|
179
|
+
* permits navigation only; submission remains the owner of payment recovery. */
|
|
180
|
+
function resolveRegistrationAdmission(input) {
|
|
181
|
+
if (input.hasWaitlistClaim) return { kind: "resume" };
|
|
182
|
+
if (input.eligibilityLoading) return { kind: "checking" };
|
|
183
|
+
if (input.eligibilityError) return {
|
|
184
|
+
kind: "closed",
|
|
185
|
+
reason: "optionsUnavailable",
|
|
186
|
+
message: input.eligibilityError
|
|
187
|
+
};
|
|
188
|
+
if (!input.eligibility) return { kind: "checking" };
|
|
189
|
+
const { registration, availability } = input.eligibility;
|
|
190
|
+
if (registration.kind === "pending_payment") return { kind: "resume" };
|
|
191
|
+
if (registration.kind === "waitlisted") return {
|
|
192
|
+
kind: "closed",
|
|
193
|
+
reason: "alreadyWaitlisted",
|
|
194
|
+
message: "You're already on the waitlist for this event."
|
|
195
|
+
};
|
|
196
|
+
return admissionFromAvailability(availability, input.isAuthenticated);
|
|
197
|
+
}
|
|
198
|
+
function admissionFromAvailability(availability, isAuthenticated) {
|
|
199
|
+
switch (availability.kind) {
|
|
200
|
+
case "available": return { kind: "open" };
|
|
201
|
+
case "waitlist": return {
|
|
202
|
+
kind: "waitlist",
|
|
203
|
+
recovery: isAuthenticated ? "none" : "byEmail"
|
|
204
|
+
};
|
|
205
|
+
case "unavailable": switch (availability.reason) {
|
|
206
|
+
case "full": return {
|
|
207
|
+
kind: "fullyBooked",
|
|
208
|
+
recovery: isAuthenticated ? "none" : "byEmail"
|
|
209
|
+
};
|
|
210
|
+
case "paymentUnavailable": return {
|
|
211
|
+
kind: "closed",
|
|
212
|
+
reason: "unavailable",
|
|
213
|
+
message: "Payment options are not available for this event."
|
|
214
|
+
};
|
|
215
|
+
case "selectionRequired": return { kind: "open" };
|
|
216
|
+
case "bookingClosed": return {
|
|
217
|
+
kind: "closed",
|
|
218
|
+
reason: "unavailable",
|
|
219
|
+
message: "Registration is not available for this event."
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function stepAfterTickets(admission) {
|
|
225
|
+
switch (admission.kind) {
|
|
226
|
+
case "open":
|
|
227
|
+
case "resume":
|
|
228
|
+
case "waitlist": return "enter-details";
|
|
229
|
+
case "fullyBooked": return "fully-booked";
|
|
230
|
+
case "checking":
|
|
231
|
+
case "closed": return "select-tickets";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function resolveRegistrationAvailabilityBlocker(admission) {
|
|
235
|
+
switch (admission.kind) {
|
|
236
|
+
case "open":
|
|
237
|
+
case "resume":
|
|
238
|
+
case "waitlist": return null;
|
|
239
|
+
case "fullyBooked": return admission.recovery === "none" ? {
|
|
240
|
+
kind: "unavailable",
|
|
241
|
+
message: "This event is fully booked."
|
|
242
|
+
} : null;
|
|
243
|
+
case "checking": return {
|
|
244
|
+
kind: "pending",
|
|
245
|
+
message: "Checking availability..."
|
|
246
|
+
};
|
|
247
|
+
case "closed": return {
|
|
248
|
+
kind: "unavailable",
|
|
249
|
+
message: admission.message
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function resolvePricingSelectionBlocker(input) {
|
|
254
|
+
if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
|
|
255
|
+
return input.slidingScaleSelectionMessage;
|
|
256
|
+
}
|
|
257
|
+
/** Submit owns fresh admission. Open quotes do not depend on an email lookup. */
|
|
258
|
+
function resolveGuestNextStepCheck(admission, request) {
|
|
259
|
+
switch (admission.kind) {
|
|
260
|
+
case "open":
|
|
261
|
+
case "resume": return {
|
|
262
|
+
kind: "skip",
|
|
263
|
+
outcome: { kind: "continue" }
|
|
264
|
+
};
|
|
265
|
+
case "checking": return {
|
|
266
|
+
kind: "blocked",
|
|
267
|
+
message: "Checking availability..."
|
|
268
|
+
};
|
|
269
|
+
case "closed": return {
|
|
270
|
+
kind: "blocked",
|
|
271
|
+
message: admission.message
|
|
272
|
+
};
|
|
273
|
+
case "fullyBooked":
|
|
274
|
+
if (admission.recovery === "none") return {
|
|
275
|
+
kind: "blocked",
|
|
276
|
+
message: "This event is fully booked."
|
|
277
|
+
};
|
|
278
|
+
return recoveryCheckRequest(request);
|
|
279
|
+
case "waitlist": return admission.recovery === "none" ? {
|
|
280
|
+
kind: "skip",
|
|
281
|
+
outcome: { kind: "waitlist" }
|
|
282
|
+
} : recoveryCheckRequest(request);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function recoveryCheckRequest(request) {
|
|
286
|
+
return request ? {
|
|
287
|
+
kind: "check",
|
|
288
|
+
request
|
|
289
|
+
} : {
|
|
290
|
+
kind: "blocked",
|
|
291
|
+
message: "Choose an event before checking your booking."
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function resolveRegistrationTicketContinuation(input) {
|
|
295
|
+
if (input.isCheckingExistingRegistration) return {
|
|
296
|
+
kind: "blocked",
|
|
297
|
+
label: "Checking registration...",
|
|
298
|
+
pending: true,
|
|
299
|
+
message: "Your booking options are being checked."
|
|
300
|
+
};
|
|
301
|
+
if (input.ticketSelectionRequired && !input.hasValidTicketSelection) return {
|
|
302
|
+
kind: "blocked",
|
|
303
|
+
label: "Choose a ticket",
|
|
304
|
+
pending: false,
|
|
305
|
+
message: "Choose at least one available ticket to continue."
|
|
306
|
+
};
|
|
307
|
+
switch (input.admission.kind) {
|
|
308
|
+
case "checking": return {
|
|
309
|
+
kind: "blocked",
|
|
310
|
+
label: "Checking availability...",
|
|
311
|
+
pending: true,
|
|
312
|
+
message: "Your booking options are being checked."
|
|
313
|
+
};
|
|
314
|
+
case "closed": return {
|
|
315
|
+
kind: "blocked",
|
|
316
|
+
label: input.admission.reason === "alreadyWaitlisted" ? "Already on waitlist" : input.admission.reason === "optionsUnavailable" ? "Availability unavailable" : "Registration unavailable",
|
|
317
|
+
pending: false,
|
|
318
|
+
message: input.admission.message
|
|
319
|
+
};
|
|
320
|
+
case "open":
|
|
321
|
+
case "resume":
|
|
322
|
+
case "waitlist":
|
|
323
|
+
case "fullyBooked": return {
|
|
324
|
+
kind: "advance",
|
|
325
|
+
admission: input.admission,
|
|
326
|
+
label: "Continue",
|
|
327
|
+
pending: false
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
191
332
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.ts
|
|
192
333
|
function getApprovedDirectPaymentCollectionOptionKinds(paymentOptions) {
|
|
193
334
|
return paymentOptions.flatMap((option) => {
|
|
@@ -212,6 +353,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
|
|
|
212
353
|
priceAmount: input.totalPriceCents,
|
|
213
354
|
priceCurrency: input.currency,
|
|
214
355
|
bookingStartAt: input.startsAt,
|
|
356
|
+
nowIso: input.nowIso,
|
|
215
357
|
locale: input.locale
|
|
216
358
|
});
|
|
217
359
|
return {
|
|
@@ -219,7 +361,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
|
|
|
219
361
|
sectionTitle: selection.sectionTitle,
|
|
220
362
|
options: selection.options.flatMap((option, index) => {
|
|
221
363
|
const sourceOption = approvedOptions[index];
|
|
222
|
-
return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents
|
|
364
|
+
return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents)] : [];
|
|
223
365
|
})
|
|
224
366
|
};
|
|
225
367
|
}
|
|
@@ -227,11 +369,10 @@ function selectApprovedEventDirectPaymentOptions(approvedPaymentOptions, payment
|
|
|
227
369
|
const approvedKinds = new Set(getApprovedDirectPaymentCollectionOptionKinds(approvedPaymentOptions));
|
|
228
370
|
return paymentTerms.allowedOptions.filter((option) => approvedKinds.has(option.kind));
|
|
229
371
|
}
|
|
230
|
-
function toEventDirectPaymentOption(option, sourceOption, mode, totalCents
|
|
372
|
+
function toEventDirectPaymentOption(option, sourceOption, mode, totalCents) {
|
|
231
373
|
const configuredPaymentDueNowCents = resolveBookingPaymentDueNowCents({
|
|
232
374
|
option: sourceOption,
|
|
233
|
-
totalCents
|
|
234
|
-
bookingStartAt: startsAt
|
|
375
|
+
totalCents
|
|
235
376
|
});
|
|
236
377
|
switch (option.kind) {
|
|
237
378
|
case "upfront": return {
|
|
@@ -287,9 +428,6 @@ function resolveEventRegistrationDirectPaymentSelection(input) {
|
|
|
287
428
|
}
|
|
288
429
|
//#endregion
|
|
289
430
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.ts
|
|
290
|
-
function hasBlockingExistingRegistration(input) {
|
|
291
|
-
return !input.hasWaitlistClaim && input.isAuthenticated && input.registration.kind === "waitlisted";
|
|
292
|
-
}
|
|
293
431
|
function createInitialRegistrationFlowState(hasPreSelectedContext) {
|
|
294
432
|
return {
|
|
295
433
|
step: hasPreSelectedContext ? "select-tickets" : "select-event",
|
|
@@ -365,8 +503,7 @@ function isSelectionValid(input) {
|
|
|
365
503
|
function normalizeRegistrationFlowState(state) {
|
|
366
504
|
const hasPass = Boolean(state.eligibility?.eligiblePasses.length);
|
|
367
505
|
const hasMembership = Boolean(state.eligibility?.eligibleMemberships.length);
|
|
368
|
-
|
|
369
|
-
if (nextPassOptOut && (state.step === "select-tickets" || state.ticketsCount !== 1 || !hasPass || hasMembership)) nextPassOptOut = false;
|
|
506
|
+
const nextPassOptOut = state.passOptOut && !(state.step === "select-tickets" || state.ticketsCount !== 1 || !hasPass || hasMembership);
|
|
370
507
|
const autoSelection = computeAutoSelection({
|
|
371
508
|
isAuthenticated: state.isAuthenticated,
|
|
372
509
|
eligibility: state.eligibility,
|
|
@@ -391,8 +528,27 @@ function normalizeRegistrationFlowState(state) {
|
|
|
391
528
|
};
|
|
392
529
|
}
|
|
393
530
|
function registrationFlowReducer(state, action) {
|
|
531
|
+
if ([
|
|
532
|
+
"payment",
|
|
533
|
+
"submitting",
|
|
534
|
+
"verifying-payment",
|
|
535
|
+
"verifying-timeout",
|
|
536
|
+
"payment-status"
|
|
537
|
+
].includes(state.step) && action.type !== "set-step") return state;
|
|
394
538
|
switch (action.type) {
|
|
395
|
-
case "
|
|
539
|
+
case "admission-updated":
|
|
540
|
+
case "tickets-completed":
|
|
541
|
+
case "recovery-checked": return reduceRegistrationAdmission(state, action);
|
|
542
|
+
case "set-step": return [
|
|
543
|
+
"payment",
|
|
544
|
+
"submitting",
|
|
545
|
+
"verifying-payment",
|
|
546
|
+
"verifying-timeout",
|
|
547
|
+
"payment-status"
|
|
548
|
+
].includes(action.step) ? {
|
|
549
|
+
...state,
|
|
550
|
+
step: action.step
|
|
551
|
+
} : normalizeRegistrationFlowState({
|
|
396
552
|
...state,
|
|
397
553
|
step: action.step
|
|
398
554
|
});
|
|
@@ -408,18 +564,8 @@ function registrationFlowReducer(state, action) {
|
|
|
408
564
|
...state,
|
|
409
565
|
eligibility: action.eligibility
|
|
410
566
|
});
|
|
411
|
-
case "set-manual-payment-selection":
|
|
412
|
-
|
|
413
|
-
paymentSelection: normalizePaymentSelection(action.selection),
|
|
414
|
-
selectionSource: "manual",
|
|
415
|
-
passOptOut: action.selection.method === "stripe" ? true : state.passOptOut
|
|
416
|
-
});
|
|
417
|
-
case "use-card-instead-of-pass": return normalizeRegistrationFlowState({
|
|
418
|
-
...state,
|
|
419
|
-
passOptOut: true,
|
|
420
|
-
paymentSelection: computeDirectPaymentSelection(state.eligibility),
|
|
421
|
-
selectionSource: "manual"
|
|
422
|
-
});
|
|
567
|
+
case "set-manual-payment-selection":
|
|
568
|
+
case "use-card-instead-of-pass": return reduceRegistrationPaymentChoice(state, action);
|
|
423
569
|
case "event-changed": return normalizeRegistrationFlowState({
|
|
424
570
|
...state,
|
|
425
571
|
step: action.hasPreSelectedContext ? "select-tickets" : "select-event",
|
|
@@ -429,7 +575,6 @@ function registrationFlowReducer(state, action) {
|
|
|
429
575
|
eligibility: null
|
|
430
576
|
});
|
|
431
577
|
case "reset": return createInitialRegistrationFlowState(action.hasPreSelectedContext);
|
|
432
|
-
default: return state;
|
|
433
578
|
}
|
|
434
579
|
}
|
|
435
580
|
function isEntitlementSelection(selection) {
|
|
@@ -439,6 +584,38 @@ function requiresPaymentStep(params) {
|
|
|
439
584
|
if (!params.eventRequiresPayment) return false;
|
|
440
585
|
return !isEntitlementSelection(params.paymentSelection);
|
|
441
586
|
}
|
|
587
|
+
function reduceRegistrationPaymentChoice(state, action) {
|
|
588
|
+
switch (action.type) {
|
|
589
|
+
case "set-manual-payment-selection": return normalizeRegistrationFlowState({
|
|
590
|
+
...state,
|
|
591
|
+
paymentSelection: normalizePaymentSelection(action.selection),
|
|
592
|
+
selectionSource: "manual",
|
|
593
|
+
passOptOut: action.selection.method === "stripe" ? true : state.passOptOut
|
|
594
|
+
});
|
|
595
|
+
case "use-card-instead-of-pass": return normalizeRegistrationFlowState({
|
|
596
|
+
...state,
|
|
597
|
+
passOptOut: true,
|
|
598
|
+
paymentSelection: computeDirectPaymentSelection(state.eligibility),
|
|
599
|
+
selectionSource: "manual"
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function reduceRegistrationAdmission(state, action) {
|
|
604
|
+
switch (action.type) {
|
|
605
|
+
case "admission-updated": return state.step === "fully-booked" && action.admission.kind !== "checking" ? normalizeRegistrationFlowState({
|
|
606
|
+
...state,
|
|
607
|
+
step: stepAfterTickets(action.admission)
|
|
608
|
+
}) : state;
|
|
609
|
+
case "tickets-completed": return state.step === "select-tickets" ? normalizeRegistrationFlowState({
|
|
610
|
+
...state,
|
|
611
|
+
step: stepAfterTickets(action.admission)
|
|
612
|
+
}) : state;
|
|
613
|
+
case "recovery-checked": return state.step === "fully-booked" && action.outcome.kind !== "unavailable" ? normalizeRegistrationFlowState({
|
|
614
|
+
...state,
|
|
615
|
+
step: "enter-details"
|
|
616
|
+
}) : state;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
442
619
|
//#endregion
|
|
443
620
|
//#region ../blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.ts
|
|
444
621
|
function isEventRegistrationAvailable(event) {
|
|
@@ -780,16 +957,66 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
780
957
|
});
|
|
781
958
|
};
|
|
782
959
|
//#endregion
|
|
960
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/useRegistrationAdmission.ts
|
|
961
|
+
/** Owns admission and its navigation commands; renderers receive decisions. */
|
|
962
|
+
function useRegistrationAdmission(input) {
|
|
963
|
+
const { eligibility, eligibilityError, eligibilityLoading, hasWaitlistClaim, isAuthenticated, dispatchFlow } = input;
|
|
964
|
+
const admission = useMemo(() => resolveRegistrationAdmission({
|
|
965
|
+
eligibility,
|
|
966
|
+
eligibilityError,
|
|
967
|
+
eligibilityLoading,
|
|
968
|
+
hasWaitlistClaim,
|
|
969
|
+
isAuthenticated
|
|
970
|
+
}), [
|
|
971
|
+
eligibility,
|
|
972
|
+
eligibilityError,
|
|
973
|
+
eligibilityLoading,
|
|
974
|
+
hasWaitlistClaim,
|
|
975
|
+
isAuthenticated
|
|
976
|
+
]);
|
|
977
|
+
useEffect(() => {
|
|
978
|
+
dispatchFlow({
|
|
979
|
+
type: "admission-updated",
|
|
980
|
+
admission
|
|
981
|
+
});
|
|
982
|
+
}, [admission, dispatchFlow]);
|
|
983
|
+
const ticketContinuation = resolveRegistrationTicketContinuation({
|
|
984
|
+
admission,
|
|
985
|
+
ticketSelectionRequired: input.ticketSelectionRequired,
|
|
986
|
+
hasValidTicketSelection: input.hasValidTicketSelection,
|
|
987
|
+
isCheckingExistingRegistration: isAuthenticated && input.existingRegistrationLoading
|
|
988
|
+
});
|
|
989
|
+
const handleTicketsComplete = () => {
|
|
990
|
+
if (ticketContinuation.kind === "blocked") return {
|
|
991
|
+
ok: false,
|
|
992
|
+
reason: "blocked",
|
|
993
|
+
message: ticketContinuation.message
|
|
994
|
+
};
|
|
995
|
+
dispatchFlow({
|
|
996
|
+
type: "tickets-completed",
|
|
997
|
+
admission: ticketContinuation.admission
|
|
998
|
+
});
|
|
999
|
+
return { ok: true };
|
|
1000
|
+
};
|
|
1001
|
+
const onRecoveryChecked = (outcome) => dispatchFlow({
|
|
1002
|
+
type: "recovery-checked",
|
|
1003
|
+
outcome
|
|
1004
|
+
});
|
|
1005
|
+
return {
|
|
1006
|
+
admission,
|
|
1007
|
+
ticketContinuation,
|
|
1008
|
+
handleTicketsComplete,
|
|
1009
|
+
onRecoveryChecked
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
//#endregion
|
|
783
1013
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
|
|
784
1014
|
function resolveRegistrationRecoveryAction(step, action) {
|
|
785
1015
|
if (step === "payment-failed") return "payment-options";
|
|
786
1016
|
if (step === "payment-status") return "none";
|
|
787
|
-
if (step === "verifying-payment" || step === "verifying-timeout" || step === "
|
|
1017
|
+
if (step === "verifying-payment" || step === "verifying-timeout" || step === "payment") return "none";
|
|
788
1018
|
return action;
|
|
789
1019
|
}
|
|
790
|
-
function canRecoverToWaitlist(eligibility) {
|
|
791
|
-
return eligibility?.availability.kind === "waitlist" && eligibility.registration.kind !== "pending_payment";
|
|
792
|
-
}
|
|
793
1020
|
function shouldRefreshAfterRegistrationError(step, action, enabled) {
|
|
794
1021
|
return enabled || step === "error" && action === "places";
|
|
795
1022
|
}
|
|
@@ -803,7 +1030,6 @@ function resetRegistrationAfterExpiry(input) {
|
|
|
803
1030
|
const mode = input.preSelectedEvent?.deliveryMode;
|
|
804
1031
|
input.setSelectedAttendanceMode(mode === "online" || mode === "in_person" ? mode : null);
|
|
805
1032
|
input.setErrorMessage("");
|
|
806
|
-
input.setPendingRegistrationReference(null);
|
|
807
1033
|
}
|
|
808
1034
|
/** Retry the retained submission in place; explicit payment uncertainty stays status-only. */
|
|
809
1035
|
function recoverRegistrationError(action, handlers) {
|
|
@@ -1156,291 +1382,6 @@ function logoutPortal(anchorId) {
|
|
|
1156
1382
|
form.submit();
|
|
1157
1383
|
}
|
|
1158
1384
|
//#endregion
|
|
1159
|
-
//#region ../commerce/src/purchase/checkoutPaymentFlow.ts
|
|
1160
|
-
function planCheckoutPaymentFlow(options) {
|
|
1161
|
-
const amountDueCents = toNonNegativeCents(options.amountDueCents);
|
|
1162
|
-
const discountCents = toNonNegativeCents(options.discountCents);
|
|
1163
|
-
const availableCreditCents = toNonNegativeCents(options.availableCreditCents);
|
|
1164
|
-
const minimumStripeChargeCents = toNonNegativeCents(options.minimumStripeChargeCents ?? 0);
|
|
1165
|
-
if (amountDueCents <= 0) return {
|
|
1166
|
-
kind: "bypass",
|
|
1167
|
-
bypassReason: discountCents > 0 ? "discount_free" : "free",
|
|
1168
|
-
reserveCreditCents: 0
|
|
1169
|
-
};
|
|
1170
|
-
if (!options.creditCurrencyMatches || availableCreditCents <= 0) return {
|
|
1171
|
-
kind: "stripe",
|
|
1172
|
-
reserveCreditCents: toNonNegativeCents(0)
|
|
1173
|
-
};
|
|
1174
|
-
if (availableCreditCents >= amountDueCents) return {
|
|
1175
|
-
kind: "store_credit_only",
|
|
1176
|
-
reserveCreditCents: amountDueCents
|
|
1177
|
-
};
|
|
1178
|
-
return {
|
|
1179
|
-
kind: "stripe",
|
|
1180
|
-
reserveCreditCents: planMixedPaymentCreditReservation({
|
|
1181
|
-
amountDueCents,
|
|
1182
|
-
availableCreditCents,
|
|
1183
|
-
minimumStripeChargeCents
|
|
1184
|
-
})
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
function planMixedPaymentCreditReservation(input) {
|
|
1188
|
-
const chargeAfterFullCredit = input.amountDueCents - input.availableCreditCents;
|
|
1189
|
-
if (input.minimumStripeChargeCents <= 0 || chargeAfterFullCredit <= 0 || chargeAfterFullCredit >= input.minimumStripeChargeCents) return input.availableCreditCents;
|
|
1190
|
-
if (input.amountDueCents < input.minimumStripeChargeCents) return toNonNegativeCents(0);
|
|
1191
|
-
return toNonNegativeCents(input.amountDueCents - input.minimumStripeChargeCents);
|
|
1192
|
-
}
|
|
1193
|
-
/**
|
|
1194
|
-
* Apply site credit to a flexible-balance booking before card payment.
|
|
1195
|
-
*
|
|
1196
|
-
* Credit first reduces the configured payment due now. Once that payment is
|
|
1197
|
-
* covered, any remaining credit reduces the later balance. If a partial credit
|
|
1198
|
-
* application would leave a positive card charge below Stripe's minimum, less
|
|
1199
|
-
* credit is used so the configured payment can still be collected.
|
|
1200
|
-
*/
|
|
1201
|
-
function planFlexibleBalanceCreditFirst(input) {
|
|
1202
|
-
const totalCents = toNonNegativeCents(input.totalAfterDiscountCents);
|
|
1203
|
-
const configuredDueNowCents = toNonNegativeCents(Math.min(input.configuredPaymentDueNowCents, totalCents));
|
|
1204
|
-
const availableCreditCents = toNonNegativeCents(input.creditCurrencyMatches ? input.availableCreditCents : 0);
|
|
1205
|
-
const minimumStripeChargeCents = toNonNegativeCents(input.minimumStripeChargeCents ?? 0);
|
|
1206
|
-
if (availableCreditCents >= totalCents && totalCents > 0) return {
|
|
1207
|
-
kind: "credit_only",
|
|
1208
|
-
reserveCreditCents: totalCents,
|
|
1209
|
-
cardDueNowCents: toNonNegativeCents(0),
|
|
1210
|
-
laterBalanceCents: toNonNegativeCents(0)
|
|
1211
|
-
};
|
|
1212
|
-
let reserveCreditCents = toNonNegativeCents(Math.min(availableCreditCents, totalCents));
|
|
1213
|
-
if (reserveCreditCents >= configuredDueNowCents) return {
|
|
1214
|
-
kind: "flexible_balance",
|
|
1215
|
-
reserveCreditCents,
|
|
1216
|
-
cardDueNowCents: toNonNegativeCents(0),
|
|
1217
|
-
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents)
|
|
1218
|
-
};
|
|
1219
|
-
const plannedCardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
1220
|
-
if (plannedCardDueNowCents > 0 && plannedCardDueNowCents < minimumStripeChargeCents) {
|
|
1221
|
-
if (configuredDueNowCents < minimumStripeChargeCents) return {
|
|
1222
|
-
kind: "card_below_minimum",
|
|
1223
|
-
reserveCreditCents: toNonNegativeCents(0),
|
|
1224
|
-
cardDueNowCents: configuredDueNowCents,
|
|
1225
|
-
laterBalanceCents: toNonNegativeCents(totalCents - configuredDueNowCents)
|
|
1226
|
-
};
|
|
1227
|
-
reserveCreditCents = toNonNegativeCents(configuredDueNowCents - minimumStripeChargeCents);
|
|
1228
|
-
}
|
|
1229
|
-
const cardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
1230
|
-
return {
|
|
1231
|
-
kind: "flexible_balance",
|
|
1232
|
-
reserveCreditCents,
|
|
1233
|
-
cardDueNowCents,
|
|
1234
|
-
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents - cardDueNowCents)
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
//#endregion
|
|
1238
|
-
//#region ../commerce/src/purchase/settlement.ts
|
|
1239
|
-
function normalizeCurrencyCode(raw) {
|
|
1240
|
-
const normalized = raw.trim().toUpperCase();
|
|
1241
|
-
if (!/^[A-Z]{3}$/.test(normalized)) throw new Error(`Invalid currency code: ${raw}`);
|
|
1242
|
-
return normalized;
|
|
1243
|
-
}
|
|
1244
|
-
//#endregion
|
|
1245
|
-
//#region ../commerce/src/purchase/checkoutSessionMetadata.ts
|
|
1246
|
-
const datedOfferingSharedEngineMetadataShape = {
|
|
1247
|
-
datedOfferingEngineContractVersion: z.literal("shared_v1"),
|
|
1248
|
-
datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
|
|
1249
|
-
datedOfferingCapacityHoldId: z.string().uuid(),
|
|
1250
|
-
datedOfferingCapacityHoldAuditRef: z.string().uuid(),
|
|
1251
|
-
customerId: z.string().uuid(),
|
|
1252
|
-
eventSeriesId: z.string().uuid()
|
|
1253
|
-
};
|
|
1254
|
-
z.object(datedOfferingSharedEngineMetadataShape);
|
|
1255
|
-
const orderCheckoutSessionMetadataBaseShape = {
|
|
1256
|
-
type: z.literal("order"),
|
|
1257
|
-
site_id: z.string().uuid(),
|
|
1258
|
-
order_id: z.string().uuid().optional(),
|
|
1259
|
-
customer_email: z.string().email(),
|
|
1260
|
-
customer_name: z.string().optional(),
|
|
1261
|
-
product_id: z.string().uuid().optional(),
|
|
1262
|
-
attendee_id: z.string().uuid().optional(),
|
|
1263
|
-
occurrence_id: z.string().uuid().optional(),
|
|
1264
|
-
tickets_count: z.string().optional(),
|
|
1265
|
-
notes: z.string().optional(),
|
|
1266
|
-
discount_redemption_id: z.string().uuid().optional(),
|
|
1267
|
-
discount_code_id: z.string().uuid().optional(),
|
|
1268
|
-
discount_code: z.string().optional(),
|
|
1269
|
-
discount_public_label: z.string().optional(),
|
|
1270
|
-
credit_reservation_id: z.string().uuid().optional(),
|
|
1271
|
-
credit_reserved_cents: z.string().optional(),
|
|
1272
|
-
discount_code_amount_cents: z.string().optional(),
|
|
1273
|
-
order_payment_reason: z.enum([
|
|
1274
|
-
"instalment_payoff",
|
|
1275
|
-
"flexible_balance_initial",
|
|
1276
|
-
"flexible_balance_paydown"
|
|
1277
|
-
]).optional(),
|
|
1278
|
-
order_payment_plan_id: z.string().uuid().optional(),
|
|
1279
|
-
order_flexible_balance_contract_id: z.string().uuid().optional()
|
|
1280
|
-
};
|
|
1281
|
-
const absentDatedOfferingSharedEngineMetadataShape = {
|
|
1282
|
-
datedOfferingEngineContractVersion: z.never().optional(),
|
|
1283
|
-
datedOfferingEngineRouteKind: z.never().optional(),
|
|
1284
|
-
datedOfferingCapacityHoldId: z.never().optional(),
|
|
1285
|
-
datedOfferingCapacityHoldAuditRef: z.never().optional(),
|
|
1286
|
-
customerId: z.never().optional(),
|
|
1287
|
-
eventSeriesId: z.never().optional()
|
|
1288
|
-
};
|
|
1289
|
-
const LegacyOrderCheckoutSessionMetadataSchema = z.object({
|
|
1290
|
-
...orderCheckoutSessionMetadataBaseShape,
|
|
1291
|
-
...absentDatedOfferingSharedEngineMetadataShape
|
|
1292
|
-
});
|
|
1293
|
-
const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
|
|
1294
|
-
...orderCheckoutSessionMetadataBaseShape,
|
|
1295
|
-
...datedOfferingSharedEngineMetadataShape
|
|
1296
|
-
});
|
|
1297
|
-
z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
|
|
1298
|
-
//#endregion
|
|
1299
|
-
//#region ../commerce/src/purchase/stripeCommissionMetadata.ts
|
|
1300
|
-
/** Reasons are payment evidence, not an independent pricing policy. */
|
|
1301
|
-
const STRIPE_COMMISSION_FREE_REASONS = [
|
|
1302
|
-
"managed_billing",
|
|
1303
|
-
"no_commission_plan",
|
|
1304
|
-
"billing_evidence_invalid",
|
|
1305
|
-
"fee_rounds_to_zero",
|
|
1306
|
-
"payment_not_stripe"
|
|
1307
|
-
];
|
|
1308
|
-
const historicalContext = {
|
|
1309
|
-
currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
|
|
1310
|
-
sourcePlanId: z.string().trim().min(1).optional()
|
|
1311
|
-
};
|
|
1312
|
-
const percentSchema = z.number().finite().min(0).max(100);
|
|
1313
|
-
z.discriminatedUnion("kind", [
|
|
1314
|
-
z.object({
|
|
1315
|
-
kind: z.literal("commission_free"),
|
|
1316
|
-
reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
|
|
1317
|
-
...historicalContext
|
|
1318
|
-
}),
|
|
1319
|
-
z.object({
|
|
1320
|
-
kind: z.literal("application_fee_amount"),
|
|
1321
|
-
amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
1322
|
-
percent: percentSchema,
|
|
1323
|
-
...historicalContext
|
|
1324
|
-
}),
|
|
1325
|
-
z.object({
|
|
1326
|
-
kind: z.literal("application_fee_percent"),
|
|
1327
|
-
percent: percentSchema,
|
|
1328
|
-
...historicalContext
|
|
1329
|
-
})
|
|
1330
|
-
]);
|
|
1331
|
-
toNonNegativeCents(0);
|
|
1332
|
-
//#endregion
|
|
1333
|
-
//#region ../commerce/src/purchase/stripeMinimumCharge.ts
|
|
1334
|
-
const STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY = {
|
|
1335
|
-
GBP: 30,
|
|
1336
|
-
USD: 50,
|
|
1337
|
-
EUR: 50,
|
|
1338
|
-
AED: 200,
|
|
1339
|
-
AUD: 50,
|
|
1340
|
-
BGN: 100,
|
|
1341
|
-
BRL: 50,
|
|
1342
|
-
CAD: 50,
|
|
1343
|
-
CHF: 50,
|
|
1344
|
-
CZK: 1500,
|
|
1345
|
-
DKK: 250,
|
|
1346
|
-
HKD: 400,
|
|
1347
|
-
HUF: 17500,
|
|
1348
|
-
JPY: 50,
|
|
1349
|
-
MXN: 1e3,
|
|
1350
|
-
MYR: 200,
|
|
1351
|
-
NOK: 300,
|
|
1352
|
-
NZD: 50,
|
|
1353
|
-
PLN: 200,
|
|
1354
|
-
RON: 200,
|
|
1355
|
-
SEK: 300,
|
|
1356
|
-
SGD: 50,
|
|
1357
|
-
THB: 1e3
|
|
1358
|
-
};
|
|
1359
|
-
function isStripeMinimumChargeCurrency(currency) {
|
|
1360
|
-
return currency in STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY;
|
|
1361
|
-
}
|
|
1362
|
-
function getStripeMinimumChargeRequirement(rawCurrency) {
|
|
1363
|
-
let currency;
|
|
1364
|
-
try {
|
|
1365
|
-
currency = normalizeCurrencyCode(rawCurrency);
|
|
1366
|
-
} catch {
|
|
1367
|
-
return null;
|
|
1368
|
-
}
|
|
1369
|
-
const currencyKey = currency;
|
|
1370
|
-
if (!isStripeMinimumChargeCurrency(currencyKey)) return null;
|
|
1371
|
-
return {
|
|
1372
|
-
currency,
|
|
1373
|
-
minimumAmountCents: STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY[currencyKey]
|
|
1374
|
-
};
|
|
1375
|
-
}
|
|
1376
|
-
//#endregion
|
|
1377
|
-
//#region ../commerce/src/purchase/event-registration-errors.ts
|
|
1378
|
-
const eventRegistrationErrors = {
|
|
1379
|
-
registrationClosed: {
|
|
1380
|
-
message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
|
|
1381
|
-
action: "none"
|
|
1382
|
-
},
|
|
1383
|
-
paymentInvestigationRequired: {
|
|
1384
|
-
message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
|
|
1385
|
-
action: "none"
|
|
1386
|
-
},
|
|
1387
|
-
paymentProviderUnavailable: {
|
|
1388
|
-
message: "We couldn’t reach the payment provider. Please try again in a minute.",
|
|
1389
|
-
action: "retry"
|
|
1390
|
-
},
|
|
1391
|
-
paymentPageUnavailable: {
|
|
1392
|
-
message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
|
|
1393
|
-
action: "retry"
|
|
1394
|
-
},
|
|
1395
|
-
paymentUnavailable: {
|
|
1396
|
-
message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
|
|
1397
|
-
action: "none"
|
|
1398
|
-
},
|
|
1399
|
-
capacityChanged: {
|
|
1400
|
-
message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
|
|
1401
|
-
action: "places"
|
|
1402
|
-
},
|
|
1403
|
-
selectionChanged: {
|
|
1404
|
-
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
1405
|
-
action: "places"
|
|
1406
|
-
},
|
|
1407
|
-
registrationPreparationChanged: {
|
|
1408
|
-
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
1409
|
-
action: "places"
|
|
1410
|
-
},
|
|
1411
|
-
registrationAlreadyExists: {
|
|
1412
|
-
message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
|
|
1413
|
-
action: "portal"
|
|
1414
|
-
},
|
|
1415
|
-
holdExpired: {
|
|
1416
|
-
message: "Your reservation has timed out. Please check availability and choose your places again.",
|
|
1417
|
-
action: "start"
|
|
1418
|
-
},
|
|
1419
|
-
waitlistUnavailable: {
|
|
1420
|
-
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.",
|
|
1421
|
-
action: "event"
|
|
1422
|
-
},
|
|
1423
|
-
paymentContextMismatch: {
|
|
1424
|
-
message: "The payment options for this event have changed. Please check the latest options before continuing.",
|
|
1425
|
-
action: "payment-options"
|
|
1426
|
-
},
|
|
1427
|
-
verificationFailed: {
|
|
1428
|
-
message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
|
|
1429
|
-
action: "none"
|
|
1430
|
-
},
|
|
1431
|
-
idempotencyConflict: {
|
|
1432
|
-
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.",
|
|
1433
|
-
action: "portal"
|
|
1434
|
-
},
|
|
1435
|
-
invalidCommitInput: {
|
|
1436
|
-
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.",
|
|
1437
|
-
action: "details"
|
|
1438
|
-
}
|
|
1439
|
-
};
|
|
1440
|
-
function parseEventRegistrationErrorReason(value) {
|
|
1441
|
-
return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
|
|
1442
|
-
}
|
|
1443
|
-
//#endregion
|
|
1444
1385
|
//#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
|
|
1445
1386
|
const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
|
|
1446
1387
|
function createInitialWaitlistClaimState(hasToken) {
|
|
@@ -1588,441 +1529,174 @@ function useResolvedWaitlistClaim(deps, credential) {
|
|
|
1588
1529
|
};
|
|
1589
1530
|
}
|
|
1590
1531
|
//#endregion
|
|
1591
|
-
//#region ../blocks/src/system/runtime/hooks/usePaymentVerification.ts
|
|
1592
|
-
/**
|
|
1593
|
-
* Hook for polling payment status after Stripe redirects.
|
|
1594
|
-
*
|
|
1595
|
-
* Built on top of the generic usePolling hook, this provides
|
|
1596
|
-
* a specialized interface for verifying event registration payments.
|
|
1597
|
-
*
|
|
1598
|
-
* @example
|
|
1599
|
-
* ```tsx
|
|
1600
|
-
* const verification = usePaymentVerification(
|
|
1601
|
-
* step === 'verifying-payment' && attendeeId
|
|
1602
|
-
* ? { transactionId: attendeeId }
|
|
1603
|
-
* : null
|
|
1604
|
-
* );
|
|
1605
|
-
*
|
|
1606
|
-
* useEffect(() => {
|
|
1607
|
-
* if (verification.status === 'completed') {
|
|
1608
|
-
* setStep('success');
|
|
1609
|
-
* } else if (verification.status === 'failed') {
|
|
1610
|
-
* setStep('payment-failed');
|
|
1611
|
-
* } else if (verification.status === 'timeout') {
|
|
1612
|
-
* setStep('verifying-timeout');
|
|
1613
|
-
* }
|
|
1614
|
-
* }, [verification.status]);
|
|
1615
|
-
* ```
|
|
1616
|
-
*/
|
|
1617
|
-
const paymentVerificationDeps = { useBlockApi };
|
|
1618
|
-
function resolvePaymentPollingTarget(config) {
|
|
1619
|
-
const reference = config.reference;
|
|
1620
|
-
return reference.scope === "occurrence" ? {
|
|
1621
|
-
key: `occurrence:${reference.attendeeId}`,
|
|
1622
|
-
reference
|
|
1623
|
-
} : {
|
|
1624
|
-
key: `wholeSeries:${reference.registrationId}`,
|
|
1625
|
-
reference
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
function createPaymentPollingConfig(api, settings) {
|
|
1629
|
-
if (settings === null) return null;
|
|
1630
|
-
const target = resolvePaymentPollingTarget(settings);
|
|
1631
|
-
return {
|
|
1632
|
-
restartKey: target.key,
|
|
1633
|
-
pollFn: () => api.getEventRegistrationStatus(target.reference),
|
|
1634
|
-
isComplete: (result) => result.paymentStatus === "completed" || result.paymentStatus === "not_required",
|
|
1635
|
-
isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "refunded",
|
|
1636
|
-
maxAttempts: settings.maxAttempts,
|
|
1637
|
-
interval: settings.pollInterval
|
|
1638
|
-
};
|
|
1639
|
-
}
|
|
1640
|
-
function getPaymentVerificationError(polling, paymentStatus) {
|
|
1641
|
-
if (polling.status === "timeout") return "Could not verify payment. If you were charged, please contact support.";
|
|
1642
|
-
if (polling.status === "failed" && paymentStatus !== null) return paymentStatus === "refunded" ? "Payment was refunded. Please contact support." : "Payment was declined. Please try again.";
|
|
1643
|
-
return polling.error?.message ?? null;
|
|
1644
|
-
}
|
|
1645
|
-
function mapPaymentVerificationResult(polling) {
|
|
1646
|
-
const paymentStatus = polling.result?.paymentStatus ?? null;
|
|
1647
|
-
return {
|
|
1648
|
-
status: polling.status,
|
|
1649
|
-
paymentStatus,
|
|
1650
|
-
attendeeStatus: polling.result?.attendeeStatus ?? null,
|
|
1651
|
-
waitlistPosition: polling.result?.waitlistPosition ?? null,
|
|
1652
|
-
error: getPaymentVerificationError(polling, paymentStatus),
|
|
1653
|
-
retry: polling.retry
|
|
1654
|
-
};
|
|
1655
|
-
}
|
|
1656
|
-
/**
|
|
1657
|
-
* Hook for polling payment status after Stripe redirects.
|
|
1658
|
-
*
|
|
1659
|
-
* Pass config to start polling, or null to stop/idle.
|
|
1660
|
-
* The hook handles cleanup on unmount and starts a new cycle when the status
|
|
1661
|
-
* reference changes.
|
|
1662
|
-
*
|
|
1663
|
-
* @param config - Configuration for polling, or null to stop
|
|
1664
|
-
* @returns Verification result with status, data, and retry function
|
|
1665
|
-
*/
|
|
1666
|
-
function usePaymentVerification(config) {
|
|
1667
|
-
return usePaymentVerificationWithDeps(config, paymentVerificationDeps);
|
|
1668
|
-
}
|
|
1669
|
-
function usePaymentVerificationWithDeps(config, deps) {
|
|
1670
|
-
return mapPaymentVerificationResult(usePolling(createPaymentPollingConfig(deps.useBlockApi(), config)));
|
|
1671
|
-
}
|
|
1672
|
-
//#endregion
|
|
1673
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
|
|
1674
|
-
const EVENT_REGISTRATION_ANCHOR_ID = "event-registration";
|
|
1675
|
-
const EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM = "registration_attempt";
|
|
1676
|
-
//#endregion
|
|
1677
1532
|
//#region ../blocks/src/system/runtime/nodes/event-registration/sessionStorage.ts
|
|
1678
1533
|
const STORAGE_PREFIX = "riverbank:event-registration:";
|
|
1679
1534
|
const STALE_THRESHOLD_MS = 1440 * 60 * 1e3;
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1535
|
+
const paymentSelection = z.discriminatedUnion("method", [
|
|
1536
|
+
z.object({ method: z.literal("free") }),
|
|
1537
|
+
z.object({
|
|
1538
|
+
method: z.literal("stripe"),
|
|
1539
|
+
collectionOptionKind: z.enum([
|
|
1540
|
+
"upfront",
|
|
1541
|
+
"deferred_manual",
|
|
1542
|
+
"instalment_plan",
|
|
1543
|
+
"flexible_balance"
|
|
1544
|
+
])
|
|
1545
|
+
}),
|
|
1546
|
+
z.object({
|
|
1547
|
+
method: z.literal("pass"),
|
|
1548
|
+
passId: z.string(),
|
|
1549
|
+
productName: z.string().optional()
|
|
1550
|
+
}),
|
|
1551
|
+
z.object({
|
|
1552
|
+
method: z.literal("membership"),
|
|
1553
|
+
membershipId: z.string(),
|
|
1554
|
+
productName: z.string().optional()
|
|
1555
|
+
}),
|
|
1556
|
+
z.object({
|
|
1557
|
+
method: z.literal("pass_bundle"),
|
|
1558
|
+
bundlePassId: z.string(),
|
|
1559
|
+
productName: z.string().optional(),
|
|
1560
|
+
productDescription: z.string().optional(),
|
|
1561
|
+
productPrice: z.number().optional(),
|
|
1562
|
+
productCurrency: z.string().optional()
|
|
1563
|
+
}),
|
|
1564
|
+
z.object({
|
|
1565
|
+
method: z.literal("membership_bundle"),
|
|
1566
|
+
bundleMembershipId: z.string(),
|
|
1567
|
+
productName: z.string().optional(),
|
|
1568
|
+
productDescription: z.string().optional(),
|
|
1569
|
+
productPrice: z.number().optional(),
|
|
1570
|
+
productCurrency: z.string().optional(),
|
|
1571
|
+
productInterval: z.string().optional()
|
|
1572
|
+
})
|
|
1573
|
+
]);
|
|
1574
|
+
const schema = z.object({
|
|
1575
|
+
version: z.literal(6),
|
|
1576
|
+
reference: z.discriminatedUnion("scope", [z.object({
|
|
1577
|
+
scope: z.literal("occurrence"),
|
|
1578
|
+
attendeeId: z.string()
|
|
1579
|
+
}), z.object({
|
|
1580
|
+
scope: z.literal("wholeSeries"),
|
|
1581
|
+
registrationId: z.string()
|
|
1582
|
+
})]),
|
|
1583
|
+
formData: z.object({
|
|
1584
|
+
name: z.string(),
|
|
1585
|
+
email: z.string(),
|
|
1586
|
+
phone: z.string(),
|
|
1587
|
+
notes: z.string(),
|
|
1588
|
+
consentAccepted: z.boolean().optional(),
|
|
1589
|
+
mailingListOptIn: z.boolean().optional()
|
|
1590
|
+
}),
|
|
1591
|
+
ticketSelections: z.array(z.object({
|
|
1592
|
+
pricingOptionId: z.string().nullable(),
|
|
1593
|
+
quantity: z.number().int().positive()
|
|
1594
|
+
})).min(1),
|
|
1595
|
+
selectedEventId: z.string().nullable(),
|
|
1596
|
+
selectedAttendanceMode: z.enum(["in_person", "online"]).nullable().optional(),
|
|
1597
|
+
paymentSelection,
|
|
1598
|
+
guests: z.array(z.object({
|
|
1599
|
+
name: z.string(),
|
|
1600
|
+
email: z.string().nullable(),
|
|
1601
|
+
phone: z.string().nullable()
|
|
1602
|
+
})),
|
|
1603
|
+
selectedSlidingAmount: z.number().nullable(),
|
|
1604
|
+
discountCode: z.string(),
|
|
1605
|
+
mailingListSignupNote: z.enum(["confirmation_required", "not_confirmed"]).optional(),
|
|
1606
|
+
timestamp: z.number().finite()
|
|
1607
|
+
});
|
|
1608
|
+
function key(siteId, submissionId) {
|
|
1609
|
+
return `${STORAGE_PREFIX}${siteId}:${submissionId}`;
|
|
1699
1610
|
}
|
|
1700
|
-
|
|
1701
|
-
* Save pending registration data before Stripe redirect.
|
|
1702
|
-
*
|
|
1703
|
-
* @param siteId - Site ID
|
|
1704
|
-
* @param checkoutAttemptId - Correlation ID included in the checkout return URL
|
|
1705
|
-
* @param data - Registration data to save (excluding version and timestamp)
|
|
1706
|
-
*/
|
|
1707
|
-
function savePendingRegistration(siteId, checkoutAttemptId, data) {
|
|
1708
|
-
if (!isStorageAvailable()) {
|
|
1709
|
-
console.warn("[sessionStorage] Storage not available, skipping save");
|
|
1710
|
-
return;
|
|
1711
|
-
}
|
|
1611
|
+
function savePendingRegistration(siteId, submissionId, data) {
|
|
1712
1612
|
try {
|
|
1713
|
-
const
|
|
1714
|
-
const ticketSelections = normalizeTicketSelectionLines(data.ticketSelections);
|
|
1715
|
-
if (ticketSelections.length === 0) {
|
|
1716
|
-
console.warn("[sessionStorage] No ticket selections to save, skipping registration state");
|
|
1717
|
-
return;
|
|
1718
|
-
}
|
|
1719
|
-
const entry = {
|
|
1613
|
+
const entry = schema.safeParse({
|
|
1720
1614
|
...data,
|
|
1721
|
-
ticketSelections,
|
|
1722
|
-
version:
|
|
1615
|
+
ticketSelections: normalizeTicketSelectionLines(data.ticketSelections),
|
|
1616
|
+
version: 6,
|
|
1723
1617
|
timestamp: Date.now()
|
|
1724
|
-
};
|
|
1725
|
-
sessionStorage.setItem(key, JSON.stringify(entry));
|
|
1726
|
-
} catch
|
|
1727
|
-
console.warn("[sessionStorage] Failed to save registration:", error);
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
/**
|
|
1731
|
-
* Get pending registration data after returning from Stripe.
|
|
1732
|
-
*
|
|
1733
|
-
* Returns null if:
|
|
1734
|
-
* - No entry exists for this checkout attempt
|
|
1735
|
-
* - Entry is stale (> 24 hours old)
|
|
1736
|
-
* - Entry is corrupt or wrong version
|
|
1737
|
-
* - Storage is unavailable
|
|
1738
|
-
*
|
|
1739
|
-
* @param siteId - Site ID
|
|
1740
|
-
* @param checkoutAttemptId - Correlation ID returned from checkout.
|
|
1741
|
-
* @returns Pending registration data or null
|
|
1742
|
-
*/
|
|
1743
|
-
function getPendingRegistration(siteId, checkoutAttemptId) {
|
|
1744
|
-
if (!isStorageAvailable()) return null;
|
|
1745
|
-
try {
|
|
1746
|
-
const key = getStorageKey(siteId, checkoutAttemptId);
|
|
1747
|
-
const stored = sessionStorage.getItem(key);
|
|
1748
|
-
if (stored) return parseAndValidateEntry(stored, key);
|
|
1749
|
-
return null;
|
|
1750
|
-
} catch (error) {
|
|
1751
|
-
console.warn("[sessionStorage] Failed to read registration:", error);
|
|
1752
|
-
return null;
|
|
1753
|
-
}
|
|
1618
|
+
});
|
|
1619
|
+
if (entry.success) sessionStorage.setItem(key(siteId, submissionId), JSON.stringify(entry.data));
|
|
1620
|
+
} catch {}
|
|
1754
1621
|
}
|
|
1755
|
-
|
|
1756
|
-
* Internal helper to parse and validate a storage entry.
|
|
1757
|
-
*/
|
|
1758
|
-
function parseAndValidateEntry(stored, key) {
|
|
1622
|
+
function getPendingRegistration(siteId, submissionId) {
|
|
1759
1623
|
try {
|
|
1760
|
-
const
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
}
|
|
1765
|
-
const version = raw.version;
|
|
1766
|
-
if (version !== 4 && version !== 5) {
|
|
1767
|
-
console.warn("[sessionStorage] Outdated version, ignoring entry");
|
|
1768
|
-
sessionStorage.removeItem(key);
|
|
1624
|
+
const stored = sessionStorage.getItem(key(siteId, submissionId));
|
|
1625
|
+
const parsed = schema.safeParse(stored ? JSON.parse(stored) : null);
|
|
1626
|
+
if (!parsed.success || Date.now() - parsed.data.timestamp > STALE_THRESHOLD_MS) {
|
|
1627
|
+
clearPendingRegistration(siteId, submissionId);
|
|
1769
1628
|
return null;
|
|
1770
1629
|
}
|
|
1771
|
-
|
|
1772
|
-
const timestamp = typeof entry.timestamp === "number" ? entry.timestamp : NaN;
|
|
1773
|
-
if (!Number.isFinite(timestamp)) {
|
|
1774
|
-
sessionStorage.removeItem(key);
|
|
1775
|
-
return null;
|
|
1776
|
-
}
|
|
1777
|
-
if (Date.now() - timestamp > STALE_THRESHOLD_MS) {
|
|
1778
|
-
console.info("[sessionStorage] Entry is stale, removing");
|
|
1779
|
-
sessionStorage.removeItem(key);
|
|
1780
|
-
return null;
|
|
1781
|
-
}
|
|
1782
|
-
const ticketSelections = normalizeTicketSelectionLines(entry.ticketSelections);
|
|
1783
|
-
if (ticketSelections.length === 0 || getTicketSelectionTotal(ticketSelections) <= 0) {
|
|
1784
|
-
sessionStorage.removeItem(key);
|
|
1785
|
-
return null;
|
|
1786
|
-
}
|
|
1787
|
-
return {
|
|
1788
|
-
...entry,
|
|
1789
|
-
ticketSelections
|
|
1790
|
-
};
|
|
1630
|
+
return parsed.data;
|
|
1791
1631
|
} catch {
|
|
1792
|
-
console.warn("[sessionStorage] Failed to parse entry, removing");
|
|
1793
|
-
sessionStorage.removeItem(key);
|
|
1794
1632
|
return null;
|
|
1795
1633
|
}
|
|
1796
1634
|
}
|
|
1797
|
-
function
|
|
1798
|
-
if (entry.version === 5) return entry;
|
|
1799
|
-
const { attendeeId, ...stored } = entry;
|
|
1800
|
-
return {
|
|
1801
|
-
...stored,
|
|
1802
|
-
version: 5,
|
|
1803
|
-
reference: {
|
|
1804
|
-
scope: "occurrence",
|
|
1805
|
-
attendeeId
|
|
1806
|
-
}
|
|
1807
|
-
};
|
|
1808
|
-
}
|
|
1809
|
-
/**
|
|
1810
|
-
* Clear pending registration data after successful verification.
|
|
1811
|
-
*
|
|
1812
|
-
* @param siteId - Site ID
|
|
1813
|
-
* @param checkoutAttemptId - Checkout return correlation ID
|
|
1814
|
-
*/
|
|
1815
|
-
function clearPendingRegistration(siteId, checkoutAttemptId) {
|
|
1816
|
-
if (!isStorageAvailable()) return;
|
|
1635
|
+
function clearPendingRegistration(siteId, submissionId) {
|
|
1817
1636
|
try {
|
|
1818
|
-
|
|
1819
|
-
sessionStorage.removeItem(key);
|
|
1637
|
+
sessionStorage.removeItem(key(siteId, submissionId));
|
|
1820
1638
|
} catch {}
|
|
1821
1639
|
}
|
|
1822
|
-
/**
|
|
1823
|
-
* Clean up all stale registration entries from sessionStorage.
|
|
1824
|
-
* Should be called on component mount to prevent accumulation.
|
|
1825
|
-
*/
|
|
1826
1640
|
function cleanupStaleRegistrations() {
|
|
1827
|
-
if (!isStorageAvailable()) return;
|
|
1828
1641
|
try {
|
|
1829
|
-
|
|
1830
|
-
for (let i = 0; i < sessionStorage.length; i++) {
|
|
1831
|
-
const key = sessionStorage.key(i);
|
|
1832
|
-
if (!key?.startsWith(STORAGE_PREFIX)) continue;
|
|
1642
|
+
Array.from({ length: sessionStorage.length }, (_, index) => sessionStorage.key(index)).filter((item) => item !== null && item.startsWith(STORAGE_PREFIX)).forEach((item) => {
|
|
1833
1643
|
try {
|
|
1834
|
-
const
|
|
1835
|
-
if (!
|
|
1836
|
-
const entry = JSON.parse(stored);
|
|
1837
|
-
const timestamp = typeof entry.timestamp === "number" ? entry.timestamp : NaN;
|
|
1838
|
-
const age = Date.now() - timestamp;
|
|
1839
|
-
if (!Number.isFinite(timestamp) || age > STALE_THRESHOLD_MS) keysToRemove.push(key);
|
|
1644
|
+
const parsed = schema.safeParse(JSON.parse(sessionStorage.getItem(item) ?? "null"));
|
|
1645
|
+
if (!parsed.success || Date.now() - parsed.data.timestamp > STALE_THRESHOLD_MS) sessionStorage.removeItem(item);
|
|
1840
1646
|
} catch {
|
|
1841
|
-
|
|
1647
|
+
sessionStorage.removeItem(item);
|
|
1842
1648
|
}
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
if (keysToRemove.length > 0) console.info(`[sessionStorage] Cleaned up ${keysToRemove.length} stale entries`);
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
console.warn("[sessionStorage] Cleanup failed:", error);
|
|
1848
|
-
}
|
|
1649
|
+
});
|
|
1650
|
+
} catch {}
|
|
1849
1651
|
}
|
|
1850
1652
|
//#endregion
|
|
1653
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
|
|
1654
|
+
const EVENT_REGISTRATION_ANCHOR_ID = "event-registration";
|
|
1655
|
+
const EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM = "registration_attempt";
|
|
1656
|
+
//#endregion
|
|
1851
1657
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
|
|
1852
|
-
const eventRegistrationStripeReturnDeps = {
|
|
1853
|
-
usePaymentVerification,
|
|
1854
|
-
readReturnParams: () => {
|
|
1855
|
-
const params = new URLSearchParams(window.location.search);
|
|
1856
|
-
return {
|
|
1857
|
-
registration: params.get("registration"),
|
|
1858
|
-
registration_attempt: params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM),
|
|
1859
|
-
session_id: params.get("session_id")
|
|
1860
|
-
};
|
|
1861
|
-
},
|
|
1862
|
-
clearReturnParams: () => {
|
|
1863
|
-
consumeSearchParams([
|
|
1864
|
-
"registration",
|
|
1865
|
-
EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
|
|
1866
|
-
"session_id"
|
|
1867
|
-
]);
|
|
1868
|
-
},
|
|
1869
|
-
scrollToBlock,
|
|
1870
|
-
cleanupStaleRegistrations,
|
|
1871
|
-
clearPendingRegistration,
|
|
1872
|
-
getPendingRegistration
|
|
1873
|
-
};
|
|
1874
|
-
function restorePendingPresentation(options, pending) {
|
|
1875
|
-
options.setFormData(pending.formData);
|
|
1876
|
-
options.setTicketSelections(pending.ticketSelections);
|
|
1877
|
-
options.setTicketsCount(getTicketSelectionTotal(pending.ticketSelections));
|
|
1878
|
-
if (pending.selectedEventId) {
|
|
1879
|
-
const event = options.events.find((item) => item.selectionId === pending.selectedEventId) ?? null;
|
|
1880
|
-
if (event) options.setSelectedEvent(event);
|
|
1881
|
-
}
|
|
1882
|
-
options.setSelectedAttendanceMode(pending.selectedAttendanceMode ?? null);
|
|
1883
|
-
options.setPaymentSelection(pending.paymentSelection);
|
|
1884
|
-
}
|
|
1885
|
-
function showReturnReconciliation(options, message) {
|
|
1886
|
-
options.setErrorMessage(message);
|
|
1887
|
-
options.setStep("verifying-timeout");
|
|
1888
|
-
}
|
|
1889
|
-
function checkoutReturnCommand(params) {
|
|
1890
|
-
const checkoutAttemptId = params.registration_attempt;
|
|
1891
|
-
if (!checkoutAttemptId) return null;
|
|
1892
|
-
if (params.registration === "cancelled") return {
|
|
1893
|
-
kind: "abandon",
|
|
1894
|
-
checkoutAttemptId
|
|
1895
|
-
};
|
|
1896
|
-
if (params.registration === "success" && params.session_id) return {
|
|
1897
|
-
kind: "resolveSuccess",
|
|
1898
|
-
checkoutAttemptId,
|
|
1899
|
-
sessionId: params.session_id
|
|
1900
|
-
};
|
|
1901
|
-
return null;
|
|
1902
|
-
}
|
|
1903
|
-
function handleCheckoutReturnOutcome(options, deps, context, outcome) {
|
|
1904
|
-
const { pending, params } = context;
|
|
1905
|
-
if (outcome.kind === "resolved") {
|
|
1906
|
-
deps.clearReturnParams();
|
|
1907
|
-
options.setPendingRegistrationReference(outcome.reference);
|
|
1908
|
-
options.setStep("verifying-payment");
|
|
1909
|
-
return "settled";
|
|
1910
|
-
}
|
|
1911
|
-
if (outcome.kind === "abandoned") {
|
|
1912
|
-
deps.clearReturnParams();
|
|
1913
|
-
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
1914
|
-
options.setStep("select-payment");
|
|
1915
|
-
return "settled";
|
|
1916
|
-
}
|
|
1917
|
-
if (outcome.kind === "notFound" && params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
|
|
1918
|
-
deps.clearReturnParams();
|
|
1919
|
-
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
1920
|
-
options.setStep("select-payment");
|
|
1921
|
-
return "settled";
|
|
1922
|
-
}
|
|
1923
|
-
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.");
|
|
1924
|
-
return outcome.kind === "notFound" ? "settled" : "retryable";
|
|
1925
|
-
}
|
|
1926
|
-
async function handleCheckoutReturn(options, deps, returnContextRef) {
|
|
1927
|
-
deps.cleanupStaleRegistrations();
|
|
1928
|
-
const params = deps.readReturnParams();
|
|
1929
|
-
if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
|
|
1930
|
-
deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
|
|
1931
|
-
const siteId = options.api.config.siteId;
|
|
1932
|
-
const command = checkoutReturnCommand(params);
|
|
1933
|
-
if (!siteId) return "settled";
|
|
1934
|
-
if (!command) {
|
|
1935
|
-
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.");
|
|
1936
|
-
return "settled";
|
|
1937
|
-
}
|
|
1938
|
-
const { checkoutAttemptId } = command;
|
|
1939
|
-
const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
|
|
1940
|
-
returnContextRef.current = {
|
|
1941
|
-
checkoutAttemptId,
|
|
1942
|
-
mailingListSignupNote: pending?.mailingListSignupNote
|
|
1943
|
-
};
|
|
1944
|
-
if (pending) restorePendingPresentation(options, pending);
|
|
1945
|
-
options.setStep("verifying-payment");
|
|
1946
|
-
try {
|
|
1947
|
-
const outcome = await options.api.resolveEventCheckoutReturn(command);
|
|
1948
|
-
return handleCheckoutReturnOutcome(options, deps, {
|
|
1949
|
-
pending,
|
|
1950
|
-
params
|
|
1951
|
-
}, outcome);
|
|
1952
|
-
} catch {
|
|
1953
|
-
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.");
|
|
1954
|
-
}
|
|
1955
|
-
return "retryable";
|
|
1956
|
-
}
|
|
1957
1658
|
function useEventRegistrationStripeReturn(options) {
|
|
1958
|
-
|
|
1959
|
-
}
|
|
1960
|
-
function completeVerifiedRegistration(options, deps, returnContext) {
|
|
1961
|
-
const siteId = options.api.config.siteId;
|
|
1962
|
-
const checkoutAttemptId = returnContext?.checkoutAttemptId;
|
|
1963
|
-
if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
|
|
1964
|
-
options.setRegistrationResult({
|
|
1965
|
-
status: "confirmed",
|
|
1966
|
-
mailingListSignupNote: returnContext?.mailingListSignupNote
|
|
1967
|
-
});
|
|
1968
|
-
options.setStep("success");
|
|
1969
|
-
}
|
|
1970
|
-
function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
1971
|
-
const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
|
|
1972
|
-
const returnContextRef = useRef(null);
|
|
1973
|
-
const lookupInFlightRef = useRef(false);
|
|
1974
|
-
const [lookupState, setLookupState] = useState("settled");
|
|
1975
|
-
const resolveReturn = useCallback(async () => {
|
|
1976
|
-
if (lookupInFlightRef.current) return;
|
|
1977
|
-
lookupInFlightRef.current = true;
|
|
1978
|
-
setLookupState("loading");
|
|
1979
|
-
try {
|
|
1980
|
-
setLookupState(await handleCheckoutReturn(options, deps, returnContextRef));
|
|
1981
|
-
} finally {
|
|
1982
|
-
lookupInFlightRef.current = false;
|
|
1983
|
-
}
|
|
1984
|
-
}, [options, deps]);
|
|
1985
|
-
const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
|
|
1986
|
-
const verification = deps.usePaymentVerification(verificationConfig);
|
|
1987
|
-
const hasVerificationTimeout = step === "verifying-timeout" && pendingRegistrationReference !== null;
|
|
1988
|
-
const retry = useCallback(() => {
|
|
1989
|
-
if (hasVerificationTimeout) {
|
|
1990
|
-
setStep("verifying-payment");
|
|
1991
|
-
return;
|
|
1992
|
-
}
|
|
1993
|
-
verification.retry();
|
|
1994
|
-
}, [
|
|
1995
|
-
hasVerificationTimeout,
|
|
1996
|
-
setStep,
|
|
1997
|
-
verification.retry
|
|
1998
|
-
]);
|
|
1999
|
-
useEffect(() => {
|
|
2000
|
-
resolveReturn();
|
|
2001
|
-
}, []);
|
|
1659
|
+
const restored = useRef(false);
|
|
2002
1660
|
useEffect(() => {
|
|
2003
|
-
if (
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
]);
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
1661
|
+
if (restored.current) return;
|
|
1662
|
+
restored.current = true;
|
|
1663
|
+
cleanupStaleRegistrations();
|
|
1664
|
+
const params = new URLSearchParams(window.location.search);
|
|
1665
|
+
const checkoutAttemptId = params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
|
|
1666
|
+
const sessionId = params.get("session_id");
|
|
1667
|
+
if (params.get("registration") !== "payment" || !checkoutAttemptId || !sessionId) return;
|
|
1668
|
+
const pending = options.siteId ? getPendingRegistration(options.siteId, checkoutAttemptId) : null;
|
|
1669
|
+
if (pending) options.restore(pending);
|
|
1670
|
+
options.verify({
|
|
1671
|
+
kind: "resolveSession",
|
|
1672
|
+
checkoutAttemptId,
|
|
1673
|
+
sessionId
|
|
1674
|
+
});
|
|
1675
|
+
}, [options]);
|
|
1676
|
+
}
|
|
1677
|
+
//#endregion
|
|
1678
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/paymentLocation.ts
|
|
1679
|
+
function eventPaymentReturnUrl(submissionId) {
|
|
1680
|
+
const url = new URL(window.location.href);
|
|
1681
|
+
url.searchParams.set("registration", "payment");
|
|
1682
|
+
url.searchParams.set(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM, submissionId);
|
|
1683
|
+
url.searchParams.delete("session_id");
|
|
1684
|
+
url.hash = EVENT_REGISTRATION_ANCHOR_ID;
|
|
1685
|
+
return url.toString();
|
|
1686
|
+
}
|
|
1687
|
+
function rememberEventPayment(submissionId, sessionId) {
|
|
1688
|
+
const url = new URL(eventPaymentReturnUrl(submissionId));
|
|
1689
|
+
url.searchParams.set("session_id", sessionId);
|
|
1690
|
+
window.history.replaceState(window.history.state, "", url);
|
|
1691
|
+
}
|
|
1692
|
+
function clearEventPayment(siteId) {
|
|
1693
|
+
const url = new URL(window.location.href);
|
|
1694
|
+
const submissionId = url.searchParams.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
|
|
1695
|
+
if (siteId && submissionId) clearPendingRegistration(siteId, submissionId);
|
|
1696
|
+
url.searchParams.delete("registration");
|
|
1697
|
+
url.searchParams.delete(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM);
|
|
1698
|
+
url.searchParams.delete("session_id");
|
|
1699
|
+
window.history.replaceState(window.history.state, "", url);
|
|
2026
1700
|
}
|
|
2027
1701
|
//#endregion
|
|
2028
1702
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.ts
|
|
@@ -2069,7 +1743,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2069
1743
|
*/
|
|
2070
1744
|
const { commandRef } = options;
|
|
2071
1745
|
const inFlightRef = useRef(null);
|
|
2072
|
-
const submit = async (method, passId, membershipId, selection
|
|
1746
|
+
const submit = async (method, passId, membershipId, selection) => {
|
|
2073
1747
|
const target = options.registrationTarget;
|
|
2074
1748
|
if (!target) return {
|
|
2075
1749
|
ok: false,
|
|
@@ -2079,25 +1753,21 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2079
1753
|
options.setStep("submitting");
|
|
2080
1754
|
const registrationCommandId = commandRef.current?.id ?? deps.createClientCommandId();
|
|
2081
1755
|
try {
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
const
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
};
|
|
2090
|
-
request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
|
|
2091
|
-
}
|
|
1756
|
+
const initialPrepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
|
|
1757
|
+
const intentKey = registrationRequestIntentKey(buildRegistrationRequest(options, initialPrepared, method, passId, membershipId));
|
|
1758
|
+
const prepared = commandRef.current !== null && commandRef.current.intentKey !== intentKey ? {
|
|
1759
|
+
...initialPrepared,
|
|
1760
|
+
registrationCommandId: deps.createClientCommandId()
|
|
1761
|
+
} : initialPrepared;
|
|
1762
|
+
const request = buildRegistrationRequest(options, prepared, method, passId, membershipId);
|
|
2092
1763
|
commandRef.current = {
|
|
2093
1764
|
id: prepared.registrationCommandId,
|
|
2094
1765
|
intentKey
|
|
2095
1766
|
};
|
|
2096
|
-
|
|
1767
|
+
return await completeRegistrationSubmission(options, deps, prepared, await options.api.registerForEvent({
|
|
2097
1768
|
...request,
|
|
2098
1769
|
registrationCommandId: prepared.registrationCommandId
|
|
2099
|
-
});
|
|
2100
|
-
return await completeRegistrationSubmission(options, deps, prepared, result, submitOptions);
|
|
1770
|
+
}));
|
|
2101
1771
|
} catch (error) {
|
|
2102
1772
|
if (error instanceof BlockApiError && error.tag === "registrationPreparationChanged") commandRef.current = null;
|
|
2103
1773
|
const { message, action } = registrationErrorPresentation(error);
|
|
@@ -2121,7 +1791,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
2121
1791
|
return pending;
|
|
2122
1792
|
};
|
|
2123
1793
|
}
|
|
2124
|
-
async function completeRegistrationSubmission(options, deps, prepared, result
|
|
1794
|
+
async function completeRegistrationSubmission(options, deps, prepared, result) {
|
|
2125
1795
|
if (result.demoBookingPass) storeDemoBookingPass(options.formData.email, result.demoBookingPass);
|
|
2126
1796
|
switch (result.kind) {
|
|
2127
1797
|
case "paymentStatusRequired":
|
|
@@ -2136,10 +1806,24 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
|
|
|
2136
1806
|
outcome: { kind: "payment_status" }
|
|
2137
1807
|
};
|
|
2138
1808
|
case "checkoutRequired":
|
|
2139
|
-
options.setPendingRegistrationReference(result.reference);
|
|
2140
1809
|
savePendingCheckout(options, deps, prepared, result.submissionId, result.reference, result.mailingListSignupNote);
|
|
2141
|
-
|
|
2142
|
-
|
|
1810
|
+
const subject = result.reference.scope === "occurrence" ? {
|
|
1811
|
+
scope: "occurrence",
|
|
1812
|
+
attendeeId: result.reference.attendeeId,
|
|
1813
|
+
submissionId: result.submissionId
|
|
1814
|
+
} : {
|
|
1815
|
+
scope: "wholeSeries",
|
|
1816
|
+
submissionId: result.submissionId
|
|
1817
|
+
};
|
|
1818
|
+
options.openPayment(result.checkout, subject, result.mailingListSignupNote);
|
|
1819
|
+
return {
|
|
1820
|
+
ok: true,
|
|
1821
|
+
outcome: {
|
|
1822
|
+
kind: "checkout_ready",
|
|
1823
|
+
checkout: result.checkout,
|
|
1824
|
+
subject
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
2143
1827
|
case "waitlisted":
|
|
2144
1828
|
options.setRegistrationResult({
|
|
2145
1829
|
status: "waitlist",
|
|
@@ -2151,7 +1835,6 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
|
|
|
2151
1835
|
break;
|
|
2152
1836
|
case "bookingComplete":
|
|
2153
1837
|
case "paymentDeferred":
|
|
2154
|
-
options.setPendingRegistrationReference(result.reference);
|
|
2155
1838
|
options.setRegistrationResult({
|
|
2156
1839
|
status: "confirmed",
|
|
2157
1840
|
message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0,
|
|
@@ -2224,19 +1907,12 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
|
|
|
2224
1907
|
selectedEventId: options.registrationTarget?.selectedEventId ?? null,
|
|
2225
1908
|
selectedAttendanceMode: options.selectedAttendanceMode,
|
|
2226
1909
|
paymentSelection: prepared.selectionSnapshot,
|
|
1910
|
+
guests: options.guests,
|
|
1911
|
+
selectedSlidingAmount: options.selectedSlidingAmount,
|
|
1912
|
+
discountCode: options.discountCode,
|
|
2227
1913
|
mailingListSignupNote
|
|
2228
1914
|
});
|
|
2229
1915
|
}
|
|
2230
|
-
function redirectToCheckout(checkoutUrl, submitOptions) {
|
|
2231
|
-
if (submitOptions?.redirect !== "manual") window.location.href = checkoutUrl;
|
|
2232
|
-
return {
|
|
2233
|
-
ok: true,
|
|
2234
|
-
outcome: {
|
|
2235
|
-
kind: "checkout_redirect",
|
|
2236
|
-
checkoutUrl
|
|
2237
|
-
}
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
1916
|
function registrationRequestIntentKey(request) {
|
|
2241
1917
|
const { registrationCommandId: _command, altchaSolution: _proof, mailingListOptIn: _marketingConsent, checkout, ...intent } = request;
|
|
2242
1918
|
return JSON.stringify({
|
|
@@ -2251,7 +1927,7 @@ function buildRegistrationRequest(options, prepared, method, passId, membershipI
|
|
|
2251
1927
|
return {
|
|
2252
1928
|
registrationCommandId: prepared.registrationCommandId,
|
|
2253
1929
|
checkout: {
|
|
2254
|
-
|
|
1930
|
+
returnUrl: eventPaymentReturnUrl(prepared.registrationCommandId),
|
|
2255
1931
|
discountCode: options.discountCode.trim() || void 0,
|
|
2256
1932
|
collectionOptionKind: prepared.selectionSnapshot.method === "stripe" ? prepared.selectionSnapshot.collectionOptionKind : void 0
|
|
2257
1933
|
},
|
|
@@ -2373,7 +2049,7 @@ function getRegistrationOccurrenceId(target) {
|
|
|
2373
2049
|
return target?.subject.kind === "occurrence" ? target.subject.occurrenceId : "";
|
|
2374
2050
|
}
|
|
2375
2051
|
function shouldLoadRegistrationOptions(authState, step) {
|
|
2376
|
-
return authState === "authenticated" || step === "select-tickets" || step === "enter-details" || step === "select-payment";
|
|
2052
|
+
return authState === "authenticated" || step === "select-tickets" || step === "fully-booked" || step === "enter-details" || step === "select-payment";
|
|
2377
2053
|
}
|
|
2378
2054
|
function getEligibilityFlowFlags(input) {
|
|
2379
2055
|
const hasPass = (input.eligibility?.eligiblePasses.length ?? 0) > 0;
|
|
@@ -2472,132 +2148,544 @@ function useWaitlistClaimRestoration(input) {
|
|
|
2472
2148
|
]);
|
|
2473
2149
|
}
|
|
2474
2150
|
//#endregion
|
|
2475
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2151
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/useGuestRegistrationRecovery.ts
|
|
2152
|
+
/** Guest email is navigation permission only. Discard checks when the visitor
|
|
2153
|
+
* changes identity or selection before the response arrives. */
|
|
2154
|
+
function useGuestRegistrationRecovery(input) {
|
|
2155
|
+
const [checkingNextStep, setCheckingNextStep] = useState(false);
|
|
2156
|
+
const [recoveryMessage, setRecoveryMessage] = useState(null);
|
|
2157
|
+
const request = guestNextStepRequest(input);
|
|
2158
|
+
const requestKey = JSON.stringify([
|
|
2159
|
+
request,
|
|
2160
|
+
input.step,
|
|
2161
|
+
input.portalAuthState,
|
|
2162
|
+
input.admission
|
|
2163
|
+
]);
|
|
2164
|
+
const currentRequest = useRef(requestKey);
|
|
2165
|
+
currentRequest.current = requestKey;
|
|
2166
|
+
const checkDetailsNextStep = () => checkGuestNextStep(input, request, setCheckingNextStep);
|
|
2167
|
+
const handleRecoveryEmail = () => recoverByEmail({
|
|
2168
|
+
...input,
|
|
2169
|
+
checkingNextStep,
|
|
2170
|
+
check: checkDetailsNextStep,
|
|
2171
|
+
setRecoveryMessage,
|
|
2172
|
+
isCurrent: () => currentRequest.current === requestKey
|
|
2173
|
+
});
|
|
2174
|
+
return {
|
|
2175
|
+
checkingNextStep,
|
|
2176
|
+
recoveryMessage,
|
|
2177
|
+
checkDetailsNextStep,
|
|
2178
|
+
handleRecoveryEmail
|
|
2179
|
+
};
|
|
2488
2180
|
}
|
|
2489
|
-
function
|
|
2490
|
-
|
|
2491
|
-
|
|
2181
|
+
async function checkGuestNextStep(input, request, setCheckingNextStep) {
|
|
2182
|
+
const plan = resolveGuestNextStepCheck(input.admission, request);
|
|
2183
|
+
switch (plan.kind) {
|
|
2184
|
+
case "skip": return plan.outcome;
|
|
2185
|
+
case "blocked": return {
|
|
2186
|
+
kind: "unavailable",
|
|
2187
|
+
message: plan.message
|
|
2188
|
+
};
|
|
2189
|
+
case "check": break;
|
|
2190
|
+
}
|
|
2191
|
+
setCheckingNextStep(true);
|
|
2192
|
+
try {
|
|
2193
|
+
return await input.api.checkRegistrationNextStep(plan.request);
|
|
2194
|
+
} catch {
|
|
2195
|
+
return {
|
|
2196
|
+
kind: "unavailable",
|
|
2197
|
+
message: "We could not check availability. Please try again."
|
|
2198
|
+
};
|
|
2199
|
+
} finally {
|
|
2200
|
+
setCheckingNextStep(false);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
async function recoverByEmail(input) {
|
|
2204
|
+
if (input.checkingNextStep) return {
|
|
2205
|
+
ok: false,
|
|
2206
|
+
reason: "blocked",
|
|
2207
|
+
message: "Your booking is being checked."
|
|
2208
|
+
};
|
|
2209
|
+
const emailError = validateFormData(input.formData).email;
|
|
2210
|
+
input.setErrors(emailError ? { email: emailError } : {});
|
|
2211
|
+
input.setRecoveryMessage(null);
|
|
2212
|
+
if (emailError) return {
|
|
2213
|
+
ok: false,
|
|
2214
|
+
reason: "validation-failed",
|
|
2215
|
+
message: emailError
|
|
2216
|
+
};
|
|
2217
|
+
const next = await input.check();
|
|
2218
|
+
if (!input.isCurrent()) return {
|
|
2219
|
+
ok: false,
|
|
2220
|
+
reason: "blocked",
|
|
2221
|
+
message: "Your booking details changed. Please check again."
|
|
2222
|
+
};
|
|
2223
|
+
switch (next.kind) {
|
|
2224
|
+
case "continue":
|
|
2225
|
+
case "waitlist":
|
|
2226
|
+
input.onRecoveryChecked(next);
|
|
2227
|
+
return { ok: true };
|
|
2228
|
+
case "unavailable":
|
|
2229
|
+
input.setRecoveryMessage(next.message);
|
|
2230
|
+
return {
|
|
2231
|
+
ok: false,
|
|
2232
|
+
reason: "blocked",
|
|
2233
|
+
message: next.message
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
function guestNextStepRequest(input) {
|
|
2238
|
+
return input.registrationTarget ? {
|
|
2239
|
+
subject: toRegistrationRequestSubject(input.registrationTarget.subject, input.selectedAttendanceMode),
|
|
2240
|
+
selections: input.ticketSelections,
|
|
2241
|
+
selectedSlidingAmount: input.selectedSlidingAmount ?? void 0,
|
|
2242
|
+
email: input.formData.email,
|
|
2243
|
+
altchaSolution: input.altchaSolution
|
|
2244
|
+
} : null;
|
|
2492
2245
|
}
|
|
2493
2246
|
//#endregion
|
|
2494
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/
|
|
2495
|
-
|
|
2496
|
-
|
|
2247
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/paymentResponse.ts
|
|
2248
|
+
/**
|
|
2249
|
+
* Verified response identity owns every follow-up action, including storage-free returns.
|
|
2250
|
+
* `requested` is the subject the client sent, if any: a subject-bound `notFound`
|
|
2251
|
+
* means the server lost that booking, which no amount of re-checking will fix.
|
|
2252
|
+
*/
|
|
2253
|
+
function planPaymentResponse(response, intent, requested) {
|
|
2254
|
+
switch (response.kind) {
|
|
2255
|
+
case "checkout": return planCheckoutOutcome(response, intent);
|
|
2256
|
+
case "notFound": return requested ? assistance(requested) : { kind: "unresolved" };
|
|
2257
|
+
case "reconciliationRequired": return { kind: "unresolved" };
|
|
2258
|
+
default: return assertNever(response);
|
|
2259
|
+
}
|
|
2497
2260
|
}
|
|
2498
|
-
function
|
|
2261
|
+
function assistance(subject) {
|
|
2499
2262
|
return {
|
|
2500
|
-
kind: "
|
|
2501
|
-
|
|
2502
|
-
|
|
2263
|
+
kind: "recovery",
|
|
2264
|
+
state: {
|
|
2265
|
+
kind: "assistanceRequired",
|
|
2266
|
+
subject
|
|
2267
|
+
}
|
|
2503
2268
|
};
|
|
2504
2269
|
}
|
|
2505
|
-
function
|
|
2506
|
-
if (outcome.kind === "resolved") {
|
|
2507
|
-
setters.setPendingRegistrationReference(outcome.reference);
|
|
2508
|
-
setters.setRegistrationResult({
|
|
2509
|
-
status: "confirmed",
|
|
2510
|
-
mailingListSignupNote: recovery.mailingListSignupNote
|
|
2511
|
-
});
|
|
2512
|
-
setRecovery(null);
|
|
2513
|
-
setters.setStep("success");
|
|
2514
|
-
return;
|
|
2515
|
-
}
|
|
2270
|
+
function planCheckoutOutcome({ outcome, subject }, intent) {
|
|
2516
2271
|
switch (outcome.kind) {
|
|
2517
|
-
case "
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
...recovery,
|
|
2272
|
+
case "resolved": return { kind: "confirmed" };
|
|
2273
|
+
case "paymentAvailable": return intent === "resume" ? {
|
|
2274
|
+
kind: "payment",
|
|
2275
|
+
checkout: outcome.checkout,
|
|
2276
|
+
subject
|
|
2277
|
+
} : {
|
|
2278
|
+
kind: "recovery",
|
|
2279
|
+
state: {
|
|
2526
2280
|
kind: "paymentAvailable",
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
setRecovery({
|
|
2532
|
-
...recovery,
|
|
2533
|
-
kind: "temporarilyUnavailable"
|
|
2534
|
-
});
|
|
2535
|
-
return;
|
|
2536
|
-
case "paymentRetryAvailable":
|
|
2537
|
-
setRecovery({
|
|
2538
|
-
...recovery,
|
|
2539
|
-
kind: "retryAvailable"
|
|
2540
|
-
});
|
|
2541
|
-
return;
|
|
2281
|
+
checkout: outcome.checkout,
|
|
2282
|
+
subject
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2542
2285
|
case "abandoned":
|
|
2543
|
-
case "
|
|
2286
|
+
case "paymentRetryAvailable": return intent === "abandon" ? { kind: "restartBooking" } : {
|
|
2287
|
+
kind: "recovery",
|
|
2288
|
+
state: {
|
|
2289
|
+
kind: "retryAvailable",
|
|
2290
|
+
subject
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
case "paymentProcessing": return {
|
|
2294
|
+
kind: "recovery",
|
|
2295
|
+
state: {
|
|
2296
|
+
kind: "processing",
|
|
2297
|
+
subject
|
|
2298
|
+
}
|
|
2299
|
+
};
|
|
2300
|
+
case "paymentCheckUnavailable": return {
|
|
2301
|
+
kind: "recovery",
|
|
2302
|
+
state: {
|
|
2303
|
+
kind: "temporarilyUnavailable",
|
|
2304
|
+
subject
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2544
2307
|
case "reconciliationRequired":
|
|
2545
|
-
case "paymentAssistanceRequired":
|
|
2546
|
-
|
|
2547
|
-
return;
|
|
2308
|
+
case "paymentAssistanceRequired": return assistance(subject);
|
|
2309
|
+
default: return assertNever(outcome);
|
|
2548
2310
|
}
|
|
2549
2311
|
}
|
|
2550
|
-
function
|
|
2551
|
-
|
|
2552
|
-
|
|
2312
|
+
function paymentCheckEvidence(result) {
|
|
2313
|
+
switch (result.kind) {
|
|
2314
|
+
case "unreachable": return { kind: "inconclusive" };
|
|
2315
|
+
case "notFound": return { kind: "bindingLost" };
|
|
2316
|
+
case "reconciliationRequired": return { kind: "paymentUnderway" };
|
|
2317
|
+
case "checkout": return checkoutEvidence(result);
|
|
2318
|
+
default: return assertNever(result);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
function checkoutEvidence(response) {
|
|
2322
|
+
const { outcome } = response;
|
|
2323
|
+
switch (outcome.kind) {
|
|
2324
|
+
case "paymentCheckUnavailable": return { kind: "inconclusive" };
|
|
2325
|
+
case "paymentAvailable": return {
|
|
2326
|
+
kind: "payable",
|
|
2327
|
+
checkout: outcome.checkout,
|
|
2328
|
+
response
|
|
2329
|
+
};
|
|
2330
|
+
case "paymentProcessing":
|
|
2331
|
+
case "reconciliationRequired": return { kind: "paymentUnderway" };
|
|
2332
|
+
case "resolved":
|
|
2333
|
+
case "abandoned":
|
|
2334
|
+
case "paymentRetryAvailable":
|
|
2335
|
+
case "paymentAssistanceRequired": return {
|
|
2336
|
+
kind: "terminal",
|
|
2337
|
+
response
|
|
2338
|
+
};
|
|
2339
|
+
default: return assertNever(outcome);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
function planMountedPaymentRefresh(result, mounted) {
|
|
2343
|
+
const evidence = paymentCheckEvidence(result);
|
|
2344
|
+
switch (evidence.kind) {
|
|
2345
|
+
case "inconclusive": return { kind: "stay" };
|
|
2346
|
+
case "paymentUnderway": return { kind: "poll" };
|
|
2347
|
+
case "bindingLost": return {
|
|
2348
|
+
kind: "leave",
|
|
2349
|
+
transition: assistance(mounted.subject)
|
|
2350
|
+
};
|
|
2351
|
+
case "payable": return evidence.checkout.sessionId === mounted.sessionId ? { kind: "stay" } : {
|
|
2352
|
+
kind: "leave",
|
|
2353
|
+
transition: planCheckoutOutcome(evidence.response, "resume")
|
|
2354
|
+
};
|
|
2355
|
+
case "terminal": return {
|
|
2356
|
+
kind: "leave",
|
|
2357
|
+
transition: planCheckoutOutcome(evidence.response, "check")
|
|
2358
|
+
};
|
|
2359
|
+
default: return assertNever(evidence);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
function paymentResponseNeedsPolling(response) {
|
|
2363
|
+
if (response.kind !== "checkout") return response.kind === "reconciliationRequired";
|
|
2364
|
+
return paymentOutcomeNeedsPolling(response.outcome);
|
|
2365
|
+
}
|
|
2366
|
+
function paymentOutcomeNeedsPolling(outcome) {
|
|
2367
|
+
return outcome.kind === "paymentProcessing" || outcome.kind === "reconciliationRequired" || outcome.kind === "paymentCheckUnavailable";
|
|
2368
|
+
}
|
|
2369
|
+
//#endregion
|
|
2370
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.ts
|
|
2371
|
+
function usePaymentRuntime() {
|
|
2372
|
+
const [state, setState] = useState({ kind: "idle" });
|
|
2373
|
+
const note = useRef(void 0);
|
|
2374
|
+
const operation = useRef(null);
|
|
2375
|
+
const generation = useRef(0);
|
|
2376
|
+
const appliedResult = useRef(null);
|
|
2377
|
+
const current = useRef(state);
|
|
2378
|
+
current.current = state;
|
|
2379
|
+
useEffect(() => () => {
|
|
2380
|
+
generation.current += 1;
|
|
2381
|
+
}, []);
|
|
2553
2382
|
return {
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2383
|
+
state,
|
|
2384
|
+
setState,
|
|
2385
|
+
note,
|
|
2386
|
+
operation,
|
|
2387
|
+
generation,
|
|
2388
|
+
appliedResult,
|
|
2389
|
+
current
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
function usePaymentTransitions(options, runtime) {
|
|
2393
|
+
const { setState, note, generation, operation } = runtime;
|
|
2394
|
+
const openPayment = useCallback((checkout, subject, mailingListSignupNote) => {
|
|
2395
|
+
if (mailingListSignupNote) note.current = mailingListSignupNote;
|
|
2396
|
+
rememberEventPayment(subject.submissionId, checkout.sessionId);
|
|
2397
|
+
setState({
|
|
2398
|
+
kind: "payment",
|
|
2399
|
+
checkout,
|
|
2400
|
+
subject
|
|
2401
|
+
});
|
|
2402
|
+
options.setStep("payment");
|
|
2403
|
+
}, [
|
|
2404
|
+
options.setStep,
|
|
2405
|
+
setState,
|
|
2406
|
+
note
|
|
2407
|
+
]);
|
|
2408
|
+
const verify = useCallback((request, resumePayment = true) => {
|
|
2409
|
+
if (operation.current) return;
|
|
2410
|
+
generation.current += 1;
|
|
2411
|
+
setState({
|
|
2412
|
+
kind: "verifying",
|
|
2413
|
+
request,
|
|
2414
|
+
resumePayment
|
|
2415
|
+
});
|
|
2416
|
+
options.setStep("verifying-payment");
|
|
2417
|
+
}, [
|
|
2418
|
+
options.setStep,
|
|
2419
|
+
operation,
|
|
2420
|
+
generation,
|
|
2421
|
+
setState
|
|
2422
|
+
]);
|
|
2423
|
+
const restartFrom = useCallback((step) => {
|
|
2424
|
+
clearEventPayment(options.api.config.siteId);
|
|
2425
|
+
options.beginNewSubmission();
|
|
2426
|
+
setState({ kind: "idle" });
|
|
2427
|
+
options.setOptionsRefreshKey((value) => value + 1);
|
|
2428
|
+
options.setStep(step);
|
|
2429
|
+
}, [options, setState]);
|
|
2430
|
+
const resetBooking = useCallback(() => restartFrom("select-tickets"), [restartFrom]);
|
|
2431
|
+
const returnToPaymentOptions = useCallback(() => restartFrom(options.detailsInPage() ? "select-payment" : "select-tickets"), [restartFrom, options]);
|
|
2432
|
+
const applyTransition = useCallback((transition) => {
|
|
2433
|
+
switch (transition.kind) {
|
|
2434
|
+
case "confirmed":
|
|
2435
|
+
options.setRegistrationResult({
|
|
2436
|
+
status: "confirmed",
|
|
2437
|
+
mailingListSignupNote: note.current
|
|
2562
2438
|
});
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2439
|
+
clearEventPayment(options.api.config.siteId);
|
|
2440
|
+
setState({ kind: "idle" });
|
|
2441
|
+
options.setStep("success");
|
|
2442
|
+
return;
|
|
2443
|
+
case "payment": return openPayment(transition.checkout, transition.subject);
|
|
2444
|
+
case "restartBooking": return resetBooking();
|
|
2445
|
+
case "recovery":
|
|
2446
|
+
setState({
|
|
2447
|
+
kind: "recovery",
|
|
2448
|
+
state: {
|
|
2449
|
+
...transition.state,
|
|
2450
|
+
mailingListSignupNote: note.current
|
|
2451
|
+
}
|
|
2452
|
+
});
|
|
2453
|
+
options.setStep("payment-status");
|
|
2454
|
+
return;
|
|
2455
|
+
case "unresolved": return options.setStep("verifying-timeout");
|
|
2456
|
+
default: return assertNever(transition);
|
|
2457
|
+
}
|
|
2458
|
+
}, [
|
|
2459
|
+
openPayment,
|
|
2460
|
+
resetBooking,
|
|
2461
|
+
options,
|
|
2462
|
+
setState,
|
|
2463
|
+
note
|
|
2464
|
+
]);
|
|
2465
|
+
return {
|
|
2466
|
+
openPayment,
|
|
2467
|
+
verify,
|
|
2468
|
+
applyOutcome: useCallback((response, intent, requested) => applyTransition(planPaymentResponse(response, intent, requested)), [applyTransition]),
|
|
2469
|
+
applyTransition,
|
|
2470
|
+
resetBooking,
|
|
2471
|
+
returnToPaymentOptions
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2474
|
+
/** A session-only return has no client subject; the server's envelope must supply one. */
|
|
2475
|
+
function requestedSubject(request) {
|
|
2476
|
+
return request.kind === "resolveSession" ? null : request.subject;
|
|
2477
|
+
}
|
|
2478
|
+
function usePaymentChecks(options, runtime, transitions) {
|
|
2479
|
+
const { state, appliedResult, current } = runtime;
|
|
2480
|
+
const request = state.kind === "verifying" ? state.request : null;
|
|
2481
|
+
const polling = usePolling(request ? {
|
|
2482
|
+
restartKey: JSON.stringify(request),
|
|
2483
|
+
pollFn: () => options.api.resolveEventCheckoutReturn(request),
|
|
2484
|
+
isComplete: (result) => !paymentResponseNeedsPolling(result),
|
|
2485
|
+
maxAttempts: 10,
|
|
2486
|
+
interval: 1e3
|
|
2487
|
+
} : null);
|
|
2488
|
+
useEffect(() => {
|
|
2489
|
+
if (polling.status === "completed" && polling.result && request && appliedResult.current !== polling.result) {
|
|
2490
|
+
appliedResult.current = polling.result;
|
|
2491
|
+
transitions.applyOutcome(polling.result, state.kind === "verifying" && state.resumePayment ? "resume" : "check", requestedSubject(request));
|
|
2492
|
+
} else if (polling.status === "timeout") options.setStep("verifying-timeout");
|
|
2493
|
+
}, [
|
|
2494
|
+
polling.status,
|
|
2495
|
+
polling.result,
|
|
2496
|
+
request,
|
|
2497
|
+
transitions.applyOutcome,
|
|
2498
|
+
options.setStep,
|
|
2499
|
+
appliedResult
|
|
2500
|
+
]);
|
|
2501
|
+
const check = useCallback((resumePayment = false) => {
|
|
2502
|
+
appliedResult.current = null;
|
|
2503
|
+
const active = current.current;
|
|
2504
|
+
if (active.kind === "payment") transitions.verify({
|
|
2505
|
+
kind: "checkStatus",
|
|
2506
|
+
subject: active.subject
|
|
2507
|
+
}, resumePayment);
|
|
2508
|
+
else if (active.kind === "recovery") transitions.verify({
|
|
2509
|
+
kind: "checkStatus",
|
|
2510
|
+
subject: active.state.subject
|
|
2511
|
+
}, resumePayment);
|
|
2512
|
+
else if (active.kind === "verifying") {
|
|
2513
|
+
options.setStep("verifying-payment");
|
|
2514
|
+
polling.retry();
|
|
2515
|
+
}
|
|
2516
|
+
}, [
|
|
2517
|
+
transitions.verify,
|
|
2518
|
+
polling.retry,
|
|
2519
|
+
options.setStep,
|
|
2520
|
+
appliedResult,
|
|
2521
|
+
current
|
|
2522
|
+
]);
|
|
2523
|
+
const checkStatus = useCallback(() => check(), [check]);
|
|
2524
|
+
return {
|
|
2525
|
+
check: checkStatus,
|
|
2526
|
+
retryPaymentLoad: useCallback(() => check(true), [check]),
|
|
2527
|
+
verification: {
|
|
2528
|
+
...polling,
|
|
2529
|
+
retry: checkStatus,
|
|
2530
|
+
retryReturn: checkStatus
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
function usePaymentAbandonment(options, runtime, transitions) {
|
|
2535
|
+
const { operation, generation, current, setState } = runtime;
|
|
2536
|
+
return useCallback(() => {
|
|
2537
|
+
if (operation.current) return operation.current;
|
|
2538
|
+
const active = current.current;
|
|
2539
|
+
if (active.kind !== "payment") return Promise.resolve();
|
|
2540
|
+
const token = ++generation.current;
|
|
2541
|
+
setState({
|
|
2542
|
+
kind: "abandoning",
|
|
2543
|
+
subject: active.subject
|
|
2544
|
+
});
|
|
2545
|
+
const pending = options.api.resolveEventCheckoutReturn({
|
|
2546
|
+
kind: "abandon",
|
|
2547
|
+
subject: active.subject
|
|
2548
|
+
}).then((outcome) => {
|
|
2549
|
+
if (token !== generation.current) return;
|
|
2550
|
+
transitions.applyOutcome(outcome, "abandon", active.subject);
|
|
2551
|
+
}).catch(() => {
|
|
2552
|
+
if (token !== generation.current) return;
|
|
2553
|
+
setState({
|
|
2554
|
+
kind: "recovery",
|
|
2555
|
+
state: {
|
|
2556
|
+
kind: "temporarilyUnavailable",
|
|
2557
|
+
subject: active.subject,
|
|
2558
|
+
mailingListSignupNote: runtime.note.current
|
|
2573
2559
|
}
|
|
2574
|
-
})();
|
|
2575
|
-
checkRef.current = pending;
|
|
2576
|
-
pending.finally(() => {
|
|
2577
|
-
if (checkRef.current === pending) checkRef.current = null;
|
|
2578
2560
|
});
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2561
|
+
options.setStep("payment-status");
|
|
2562
|
+
});
|
|
2563
|
+
operation.current = pending;
|
|
2564
|
+
pending.finally(() => {
|
|
2565
|
+
if (operation.current === pending) operation.current = null;
|
|
2566
|
+
});
|
|
2567
|
+
return pending;
|
|
2568
|
+
}, [
|
|
2569
|
+
options.api,
|
|
2570
|
+
transitions.applyOutcome,
|
|
2571
|
+
operation,
|
|
2572
|
+
generation,
|
|
2573
|
+
current,
|
|
2574
|
+
setState,
|
|
2575
|
+
options.setStep,
|
|
2576
|
+
runtime.note
|
|
2577
|
+
]);
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* Returning to the tab (often from a banking app mid-authentication) must not
|
|
2581
|
+
* unmount Stripe on inconclusive evidence; `planMountedPaymentRefresh` decides.
|
|
2582
|
+
*/
|
|
2583
|
+
function usePaymentBackgroundCheck(options, runtime, transitions) {
|
|
2584
|
+
const { current, generation, operation } = runtime;
|
|
2585
|
+
const inFlight = useRef(false);
|
|
2586
|
+
return useCallback(() => {
|
|
2587
|
+
const active = current.current;
|
|
2588
|
+
if (active.kind !== "payment" || operation.current || inFlight.current) return;
|
|
2589
|
+
const token = generation.current;
|
|
2590
|
+
inFlight.current = true;
|
|
2591
|
+
const request = {
|
|
2592
|
+
kind: "checkStatus",
|
|
2593
|
+
subject: active.subject
|
|
2594
|
+
};
|
|
2595
|
+
const unreachable = { kind: "unreachable" };
|
|
2596
|
+
options.api.resolveEventCheckoutReturn(request).catch(() => unreachable).then((result) => {
|
|
2597
|
+
if (token !== generation.current || current.current !== active) return;
|
|
2598
|
+
const refresh = planMountedPaymentRefresh(result, {
|
|
2599
|
+
sessionId: active.checkout.sessionId,
|
|
2600
|
+
subject: active.subject
|
|
2601
|
+
});
|
|
2602
|
+
switch (refresh.kind) {
|
|
2603
|
+
case "stay": return;
|
|
2604
|
+
case "poll": return transitions.verify(request, false);
|
|
2605
|
+
case "leave": return transitions.applyTransition(refresh.transition);
|
|
2606
|
+
default: return assertNever(refresh);
|
|
2607
|
+
}
|
|
2608
|
+
}).finally(() => {
|
|
2609
|
+
inFlight.current = false;
|
|
2610
|
+
});
|
|
2611
|
+
}, [
|
|
2612
|
+
options.api,
|
|
2613
|
+
transitions.verify,
|
|
2614
|
+
transitions.applyTransition,
|
|
2615
|
+
current,
|
|
2616
|
+
generation,
|
|
2617
|
+
operation
|
|
2618
|
+
]);
|
|
2619
|
+
}
|
|
2620
|
+
function usePaymentRefresh(state, check) {
|
|
2621
|
+
useEffect(() => {
|
|
2622
|
+
if (state.kind !== "payment") return;
|
|
2623
|
+
const timeout = window.setTimeout(check, Math.max(0, Date.parse(state.checkout.expiresAt) - Date.now()));
|
|
2624
|
+
const visible = () => {
|
|
2625
|
+
if (document.visibilityState === "visible") check();
|
|
2626
|
+
};
|
|
2627
|
+
const restored = (event) => {
|
|
2628
|
+
if (event.persisted) check();
|
|
2629
|
+
};
|
|
2630
|
+
document.addEventListener("visibilitychange", visible);
|
|
2631
|
+
window.addEventListener("pageshow", restored);
|
|
2632
|
+
return () => {
|
|
2633
|
+
clearTimeout(timeout);
|
|
2634
|
+
document.removeEventListener("visibilitychange", visible);
|
|
2635
|
+
window.removeEventListener("pageshow", restored);
|
|
2636
|
+
};
|
|
2637
|
+
}, [state, check]);
|
|
2638
|
+
}
|
|
2639
|
+
function usePaymentStatusRecovery(options) {
|
|
2640
|
+
const runtime = usePaymentRuntime();
|
|
2641
|
+
const transitions = usePaymentTransitions(options, runtime);
|
|
2642
|
+
const checks = usePaymentChecks(options, runtime, transitions);
|
|
2643
|
+
const backToBooking = usePaymentAbandonment(options, runtime, transitions);
|
|
2644
|
+
const backgroundCheck = usePaymentBackgroundCheck(options, runtime, transitions);
|
|
2645
|
+
const { state, setState, generation, note } = runtime;
|
|
2646
|
+
usePaymentRefresh(state, backgroundCheck);
|
|
2647
|
+
const recovery = state.kind === "recovery" ? state.state : null;
|
|
2648
|
+
return {
|
|
2649
|
+
state,
|
|
2650
|
+
recovery,
|
|
2651
|
+
showRecovery: useCallback((next) => {
|
|
2652
|
+
generation.current += 1;
|
|
2653
|
+
note.current = next?.mailingListSignupNote;
|
|
2654
|
+
setState(next ? {
|
|
2655
|
+
kind: "recovery",
|
|
2656
|
+
state: next
|
|
2657
|
+
} : { kind: "idle" });
|
|
2658
|
+
}, [
|
|
2659
|
+
generation,
|
|
2660
|
+
note,
|
|
2661
|
+
setState
|
|
2662
|
+
]),
|
|
2663
|
+
restoreMailingListNote: (value) => {
|
|
2664
|
+
note.current = value;
|
|
2665
|
+
},
|
|
2666
|
+
openPayment: transitions.openPayment,
|
|
2667
|
+
verify: transitions.verify,
|
|
2668
|
+
...checks,
|
|
2669
|
+
backToBooking,
|
|
2670
|
+
continuePayment: () => {
|
|
2671
|
+
if (recovery?.kind === "paymentAvailable") transitions.openPayment(recovery.checkout, recovery.subject);
|
|
2672
|
+
},
|
|
2673
|
+
returnToPayment: () => {
|
|
2674
|
+
if (recovery?.kind === "retryAvailable") transitions.returnToPaymentOptions();
|
|
2675
|
+
},
|
|
2676
|
+
returnToBooking: () => {
|
|
2677
|
+
if (recovery?.kind === "retryAvailable") transitions.resetBooking();
|
|
2678
|
+
}
|
|
2597
2679
|
};
|
|
2598
2680
|
}
|
|
2599
2681
|
//#endregion
|
|
2600
2682
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
|
|
2683
|
+
function resolveAvailableAttendanceMode(event, selected) {
|
|
2684
|
+
if (!event) return null;
|
|
2685
|
+
const mode = event.deliveryMode ?? "in_person";
|
|
2686
|
+
if (mode === "online" || mode === "in_person") return mode;
|
|
2687
|
+
return selected && event.attendanceModes?.some((item) => item.mode === selected) ? selected : null;
|
|
2688
|
+
}
|
|
2601
2689
|
function usesTieredPricing(event) {
|
|
2602
2690
|
return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
|
|
2603
2691
|
}
|
|
@@ -2608,13 +2696,15 @@ const eventRegistrationWizardDeps = {
|
|
|
2608
2696
|
useWaitlistClaim,
|
|
2609
2697
|
useEventRegistrationStripeReturn,
|
|
2610
2698
|
useEventRegistrationSubmit,
|
|
2611
|
-
useDiscountCodeUi
|
|
2699
|
+
useDiscountCodeUi,
|
|
2700
|
+
useBookingNowIso
|
|
2612
2701
|
};
|
|
2613
2702
|
function useEventRegistrationWizard(options) {
|
|
2614
2703
|
return useEventRegistrationWizardWithDeps(options, eventRegistrationWizardDeps);
|
|
2615
2704
|
}
|
|
2616
2705
|
function useEventRegistrationWizardWithDeps(options, deps) {
|
|
2617
2706
|
const api = useBlockApi();
|
|
2707
|
+
const nowIso = deps.useBookingNowIso();
|
|
2618
2708
|
const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.events ?? [])], [options.events]);
|
|
2619
2709
|
const scopedEvents = useMemo(() => {
|
|
2620
2710
|
return resolveEventRegistrationScopedEvents(registrationEvents, {
|
|
@@ -2653,19 +2743,24 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2653
2743
|
const [errorAction, setErrorAction] = useState("retry");
|
|
2654
2744
|
const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
|
|
2655
2745
|
const [altchaSolution, setAltchaSolution] = useState(null);
|
|
2656
|
-
const [checkingNextStep, setCheckingNextStep] = useState(false);
|
|
2657
2746
|
const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
|
|
2658
2747
|
const waitlistClaim = deps.useWaitlistClaim();
|
|
2659
2748
|
const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
|
|
2660
|
-
const [pendingRegistrationReference, setPendingRegistrationReference] = useState(null);
|
|
2661
2749
|
const [paymentStepState, setPaymentStepState] = useState({
|
|
2662
2750
|
status: "loading",
|
|
2663
2751
|
canContinue: false,
|
|
2664
2752
|
buttonText: "Continue",
|
|
2665
2753
|
showLoginPrompt: false
|
|
2666
2754
|
});
|
|
2755
|
+
const selectionLocked = [
|
|
2756
|
+
"payment",
|
|
2757
|
+
"submitting",
|
|
2758
|
+
"verifying-payment",
|
|
2759
|
+
"verifying-timeout",
|
|
2760
|
+
"payment-status"
|
|
2761
|
+
].includes(step);
|
|
2667
2762
|
useEffect(() => {
|
|
2668
|
-
if (portalAuthState !== "authenticated" || !portalProfile) return;
|
|
2763
|
+
if (selectionLocked || portalAuthState !== "authenticated" || !portalProfile) return;
|
|
2669
2764
|
setFormData((prev) => ({
|
|
2670
2765
|
...prev,
|
|
2671
2766
|
email: portalProfile.email,
|
|
@@ -2687,16 +2782,17 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2687
2782
|
step: nextStep
|
|
2688
2783
|
});
|
|
2689
2784
|
}, []);
|
|
2690
|
-
const
|
|
2785
|
+
const paymentController = usePaymentStatusRecovery({
|
|
2691
2786
|
api,
|
|
2692
2787
|
beginNewSubmission: () => {
|
|
2693
2788
|
commandRef.current = null;
|
|
2694
2789
|
},
|
|
2695
|
-
setPendingRegistrationReference,
|
|
2696
2790
|
setRegistrationResult,
|
|
2697
2791
|
setOptionsRefreshKey,
|
|
2698
|
-
setStep
|
|
2792
|
+
setStep,
|
|
2793
|
+
detailsInPage: () => Object.keys(validateFormData(formData)).length === 0
|
|
2699
2794
|
});
|
|
2795
|
+
const { recovery: paymentStatusRecovery, showRecovery: setPaymentStatusRecovery, check: handleCheckPaymentStatus, continuePayment: handleContinueExistingPayment, returnToPayment: handleReturnToPayment, returnToBooking: handleReturnToBooking } = paymentController;
|
|
2700
2796
|
const usesTicketTypeSelections = usesTieredPricing(currentEvent);
|
|
2701
2797
|
const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
|
|
2702
2798
|
event: currentEvent,
|
|
@@ -2795,29 +2891,17 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2795
2891
|
dispatchFlow({
|
|
2796
2892
|
type: "set-authenticated",
|
|
2797
2893
|
isAuthenticated: portalAuthState === "authenticated"
|
|
2798
|
-
});
|
|
2799
|
-
}, [portalAuthState]);
|
|
2800
|
-
useEffect(() => {
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
return;
|
|
2805
|
-
}
|
|
2806
|
-
const deliveryMode = event.deliveryMode ?? "in_person";
|
|
2807
|
-
if (deliveryMode === "online") {
|
|
2808
|
-
if (selectedAttendanceMode !== "online") setSelectedAttendanceMode("online");
|
|
2809
|
-
return;
|
|
2810
|
-
}
|
|
2811
|
-
if (deliveryMode === "in_person") {
|
|
2812
|
-
if (selectedAttendanceMode !== "in_person") setSelectedAttendanceMode("in_person");
|
|
2813
|
-
return;
|
|
2814
|
-
}
|
|
2815
|
-
if (selectedAttendanceMode && (event.attendanceModes ?? []).some((mode) => mode.mode === selectedAttendanceMode)) return;
|
|
2816
|
-
setSelectedAttendanceMode(null);
|
|
2894
|
+
});
|
|
2895
|
+
}, [portalAuthState]);
|
|
2896
|
+
useEffect(() => {
|
|
2897
|
+
if (selectionLocked) return;
|
|
2898
|
+
const next = resolveAvailableAttendanceMode(selectedEvent ?? preSelectedEvent, selectedAttendanceMode);
|
|
2899
|
+
if (next !== selectedAttendanceMode) setSelectedAttendanceMode(next);
|
|
2817
2900
|
}, [
|
|
2818
2901
|
preSelectedEvent,
|
|
2819
2902
|
selectedAttendanceMode,
|
|
2820
|
-
selectedEvent
|
|
2903
|
+
selectedEvent,
|
|
2904
|
+
selectionLocked
|
|
2821
2905
|
]);
|
|
2822
2906
|
useEffect(() => {
|
|
2823
2907
|
dispatchFlow({
|
|
@@ -2825,25 +2909,26 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2825
2909
|
eligibility
|
|
2826
2910
|
});
|
|
2827
2911
|
}, [eligibility]);
|
|
2828
|
-
const verification =
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2912
|
+
const verification = paymentController.verification;
|
|
2913
|
+
deps.useEventRegistrationStripeReturn({
|
|
2914
|
+
siteId: api.config.siteId,
|
|
2915
|
+
verify: paymentController.verify,
|
|
2916
|
+
restore: (pending) => {
|
|
2917
|
+
paymentController.restoreMailingListNote(pending.mailingListSignupNote);
|
|
2918
|
+
setFormData(pending.formData);
|
|
2919
|
+
setSelectedTicketLines(pending.ticketSelections);
|
|
2920
|
+
setTicketsCount(getTicketSelectionTotal(pending.ticketSelections));
|
|
2921
|
+
setGuests(pending.guests);
|
|
2922
|
+
discountUi.setDiscountCode(pending.discountCode);
|
|
2923
|
+
setSelectedSlidingAmountInput(pending.selectedSlidingAmount === null ? "" : formatCentsAsCurrencyInput(pending.selectedSlidingAmount));
|
|
2924
|
+
setSelectedAttendanceMode(pending.selectedAttendanceMode ?? null);
|
|
2925
|
+
const event = registrationEvents.find((item) => item.selectionId === pending.selectedEventId);
|
|
2926
|
+
if (event) setSelectedEvent(event);
|
|
2927
|
+
dispatchFlow({
|
|
2928
|
+
type: "set-manual-payment-selection",
|
|
2929
|
+
selection: pending.paymentSelection
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2847
2932
|
});
|
|
2848
2933
|
const requireGuestDetails = useMemo(() => {
|
|
2849
2934
|
return (selectedEvent ?? preSelectedEvent)?.requireGuestDetails === true;
|
|
@@ -2887,6 +2972,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2887
2972
|
visibleOptions: visibleTicketTypes
|
|
2888
2973
|
});
|
|
2889
2974
|
useEffect(() => {
|
|
2975
|
+
if (selectionLocked) return;
|
|
2890
2976
|
if (!usesTicketTypeSelections) {
|
|
2891
2977
|
if (selectedTicketLines.length > 0) setSelectedTicketLines([]);
|
|
2892
2978
|
return;
|
|
@@ -2909,6 +2995,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2909
2995
|
usesTicketTypeSelections
|
|
2910
2996
|
]);
|
|
2911
2997
|
useEffect(() => {
|
|
2998
|
+
if (selectionLocked) return;
|
|
2912
2999
|
if (!requireGuestDetails) {
|
|
2913
3000
|
if (guests.length > 0) setGuests([]);
|
|
2914
3001
|
return;
|
|
@@ -2918,19 +3005,16 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2918
3005
|
if (guests.length > 0) setGuests([]);
|
|
2919
3006
|
return;
|
|
2920
3007
|
}
|
|
2921
|
-
if (guests.length !== guestCount) {
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
phone: ""
|
|
2927
|
-
});
|
|
2928
|
-
setGuests(newGuests);
|
|
2929
|
-
}
|
|
3008
|
+
if (guests.length !== guestCount) setGuests(Array.from({ length: guestCount }, (_, index) => guests[index] ?? {
|
|
3009
|
+
name: "",
|
|
3010
|
+
email: "",
|
|
3011
|
+
phone: ""
|
|
3012
|
+
}));
|
|
2930
3013
|
}, [
|
|
2931
3014
|
ticketsCount,
|
|
2932
3015
|
requireGuestDetails,
|
|
2933
|
-
guests
|
|
3016
|
+
guests,
|
|
3017
|
+
selectionLocked
|
|
2934
3018
|
]);
|
|
2935
3019
|
const validateForm = () => {
|
|
2936
3020
|
const newErrors = validateFormData(formData, Boolean(currentEvent?.consent));
|
|
@@ -2959,49 +3043,55 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2959
3043
|
selectedEventSlidingScale,
|
|
2960
3044
|
selectedSlidingAmount
|
|
2961
3045
|
]);
|
|
2962
|
-
const
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3046
|
+
const { admission, ticketContinuation, handleTicketsComplete, onRecoveryChecked } = useRegistrationAdmission({
|
|
3047
|
+
eligibility,
|
|
3048
|
+
eligibilityError,
|
|
3049
|
+
eligibilityLoading,
|
|
3050
|
+
hasWaitlistClaim: waitlistClaim.claim !== null,
|
|
3051
|
+
isAuthenticated: portalAuthState === "authenticated",
|
|
3052
|
+
existingRegistrationLoading: existingRegistrationResult.isLoading,
|
|
3053
|
+
ticketSelectionRequired: ticketTypeSelectionRequired,
|
|
3054
|
+
hasValidTicketSelection,
|
|
3055
|
+
dispatchFlow
|
|
3056
|
+
});
|
|
3057
|
+
const { checkingNextStep, recoveryMessage, checkDetailsNextStep, handleRecoveryEmail } = useGuestRegistrationRecovery({
|
|
3058
|
+
api,
|
|
3059
|
+
formData,
|
|
3060
|
+
onRecoveryChecked,
|
|
3061
|
+
setErrors,
|
|
3062
|
+
admission,
|
|
3063
|
+
step,
|
|
3064
|
+
portalAuthState,
|
|
3065
|
+
registrationTarget,
|
|
3066
|
+
selectedAttendanceMode,
|
|
3067
|
+
ticketSelections,
|
|
3068
|
+
selectedSlidingAmount,
|
|
3069
|
+
altchaSolution
|
|
3070
|
+
});
|
|
2982
3071
|
const handleDetailsComplete = async () => {
|
|
2983
|
-
const blockDetailsCompletion = (
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
3072
|
+
const blockDetailsCompletion = (blocker) => {
|
|
3073
|
+
if (blocker.kind === "unavailable") {
|
|
3074
|
+
setErrorAction("places");
|
|
3075
|
+
setErrorMessage(blocker.message);
|
|
3076
|
+
setStep("error");
|
|
3077
|
+
}
|
|
2987
3078
|
return {
|
|
2988
3079
|
ok: false,
|
|
2989
3080
|
reason: "blocked",
|
|
2990
|
-
message
|
|
3081
|
+
message: blocker.message
|
|
2991
3082
|
};
|
|
2992
3083
|
};
|
|
2993
|
-
const availabilityBlocker = resolveRegistrationAvailabilityBlocker(
|
|
2994
|
-
hasWaitlistClaim: waitlistClaim.claim !== null,
|
|
2995
|
-
eligibility,
|
|
2996
|
-
eligibilityError
|
|
2997
|
-
});
|
|
3084
|
+
const availabilityBlocker = resolveRegistrationAvailabilityBlocker(admission);
|
|
2998
3085
|
if (availabilityBlocker) return blockDetailsCompletion(availabilityBlocker);
|
|
2999
3086
|
const pricingSelectionBlocker = resolvePricingSelectionBlocker({
|
|
3000
3087
|
selectionRequired: ticketTypeSelectionRequired,
|
|
3001
3088
|
hasValidSelection: hasValidTicketSelection,
|
|
3002
3089
|
slidingScaleSelectionMessage
|
|
3003
3090
|
});
|
|
3004
|
-
if (pricingSelectionBlocker) return blockDetailsCompletion(
|
|
3091
|
+
if (pricingSelectionBlocker) return blockDetailsCompletion({
|
|
3092
|
+
kind: "unavailable",
|
|
3093
|
+
message: pricingSelectionBlocker
|
|
3094
|
+
});
|
|
3005
3095
|
if (!validateForm()) {
|
|
3006
3096
|
setGuestSectionShake(true);
|
|
3007
3097
|
return {
|
|
@@ -3011,7 +3101,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3011
3101
|
};
|
|
3012
3102
|
}
|
|
3013
3103
|
const next = await checkDetailsNextStep();
|
|
3014
|
-
if (next.kind === "unavailable") return blockDetailsCompletion(
|
|
3104
|
+
if (next.kind === "unavailable") return blockDetailsCompletion({
|
|
3105
|
+
kind: "unavailable",
|
|
3106
|
+
message: next.message
|
|
3107
|
+
});
|
|
3015
3108
|
const canJoinWaitlist = next.kind === "waitlist";
|
|
3016
3109
|
if (!canJoinWaitlist && requiresPaymentStep({
|
|
3017
3110
|
eventRequiresPayment,
|
|
@@ -3028,7 +3121,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3028
3121
|
eventRequiresPayment,
|
|
3029
3122
|
canJoinWaitlist
|
|
3030
3123
|
});
|
|
3031
|
-
if (!submitPlan.ok) return blockDetailsCompletion(
|
|
3124
|
+
if (!submitPlan.ok) return blockDetailsCompletion({
|
|
3125
|
+
kind: "unavailable",
|
|
3126
|
+
message: submitPlan.message
|
|
3127
|
+
});
|
|
3032
3128
|
const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
|
|
3033
3129
|
if (!submitResult.ok) return {
|
|
3034
3130
|
ok: false,
|
|
@@ -3076,6 +3172,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3076
3172
|
const selectionMethod = paymentSelection.method;
|
|
3077
3173
|
const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
|
|
3078
3174
|
const handleSubmit = deps.useEventRegistrationSubmit({
|
|
3175
|
+
openPayment: paymentController.openPayment,
|
|
3079
3176
|
commandRef,
|
|
3080
3177
|
setErrorAction,
|
|
3081
3178
|
api,
|
|
@@ -3091,7 +3188,6 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3091
3188
|
discountCode: discountUi.discountCode,
|
|
3092
3189
|
claimToken: waitlistClaim.token,
|
|
3093
3190
|
waitlistEntryId: waitlistClaim.entryId,
|
|
3094
|
-
setPendingRegistrationReference,
|
|
3095
3191
|
setStep,
|
|
3096
3192
|
setRegistrationResult: (result) => setRegistrationResult(result),
|
|
3097
3193
|
setErrorMessage,
|
|
@@ -3113,7 +3209,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3113
3209
|
});
|
|
3114
3210
|
};
|
|
3115
3211
|
const handleRetry = () => recoverRegistrationError(resolveRegistrationRecoveryAction(step, errorAction), {
|
|
3116
|
-
canJoinWaitlist:
|
|
3212
|
+
canJoinWaitlist: admission.kind === "waitlist",
|
|
3117
3213
|
refreshOptions: () => setOptionsRefreshKey((value) => value + 1),
|
|
3118
3214
|
clearError: () => setErrorMessage(""),
|
|
3119
3215
|
setStep,
|
|
@@ -3124,8 +3220,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3124
3220
|
setSelectedTicketLines,
|
|
3125
3221
|
setSelectedSlidingAmountInput,
|
|
3126
3222
|
setSelectedAttendanceMode,
|
|
3127
|
-
setErrorMessage
|
|
3128
|
-
setPendingRegistrationReference
|
|
3223
|
+
setErrorMessage
|
|
3129
3224
|
})
|
|
3130
3225
|
});
|
|
3131
3226
|
const handlePaymentStepStateChange = useCallback((state) => {
|
|
@@ -3145,6 +3240,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3145
3240
|
});
|
|
3146
3241
|
return {
|
|
3147
3242
|
api,
|
|
3243
|
+
nowIso,
|
|
3148
3244
|
anchorId: options.anchorId,
|
|
3149
3245
|
occurrenceContext: options.occurrenceContext,
|
|
3150
3246
|
registrationTarget,
|
|
@@ -3155,21 +3251,35 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3155
3251
|
preSelectedEvent,
|
|
3156
3252
|
hasPreSelectedContext,
|
|
3157
3253
|
step,
|
|
3158
|
-
setStep
|
|
3254
|
+
setStep: (next) => {
|
|
3255
|
+
if (!selectionLocked) setStep(next);
|
|
3256
|
+
else if (step === "payment") paymentController.backToBooking();
|
|
3257
|
+
},
|
|
3258
|
+
admission,
|
|
3259
|
+
ticketContinuation,
|
|
3260
|
+
handleTicketsComplete,
|
|
3159
3261
|
selectedEvent,
|
|
3160
|
-
setSelectedEvent
|
|
3262
|
+
setSelectedEvent: (value) => {
|
|
3263
|
+
if (!selectionLocked) setSelectedEvent(value);
|
|
3264
|
+
},
|
|
3161
3265
|
ticketsCount,
|
|
3162
|
-
setTicketsCount
|
|
3266
|
+
setTicketsCount: (value) => {
|
|
3267
|
+
if (!selectionLocked) setTicketsCount(value);
|
|
3268
|
+
},
|
|
3163
3269
|
selectedAttendanceMode,
|
|
3164
|
-
setSelectedAttendanceMode
|
|
3270
|
+
setSelectedAttendanceMode: (value) => {
|
|
3271
|
+
if (!selectionLocked) setSelectedAttendanceMode(value);
|
|
3272
|
+
},
|
|
3165
3273
|
ticketSelections,
|
|
3166
3274
|
selectedTicketLines: normalizedSelectedTicketLines,
|
|
3167
3275
|
setSelectedTicketLines: (lines) => {
|
|
3168
|
-
if (waitlistClaim.claim) return;
|
|
3276
|
+
if (selectionLocked || waitlistClaim.claim) return;
|
|
3169
3277
|
setSelectedTicketLines(normalizeTicketSelectionLines(lines));
|
|
3170
3278
|
},
|
|
3171
3279
|
selectedSlidingAmountInput,
|
|
3172
|
-
setSelectedSlidingAmountInput
|
|
3280
|
+
setSelectedSlidingAmountInput: (value) => {
|
|
3281
|
+
if (!selectionLocked) setSelectedSlidingAmountInput(value);
|
|
3282
|
+
},
|
|
3173
3283
|
selectedSlidingAmount,
|
|
3174
3284
|
selectedEventSlidingScale,
|
|
3175
3285
|
slidingScaleSelectionMessage,
|
|
@@ -3182,10 +3292,14 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3182
3292
|
eventRequiresPayment,
|
|
3183
3293
|
formData,
|
|
3184
3294
|
mailingListSignup,
|
|
3185
|
-
setFormData
|
|
3295
|
+
setFormData: (value) => {
|
|
3296
|
+
if (!selectionLocked) setFormData(value);
|
|
3297
|
+
},
|
|
3186
3298
|
errors,
|
|
3187
3299
|
guests,
|
|
3188
|
-
setGuests
|
|
3300
|
+
setGuests: (value) => {
|
|
3301
|
+
if (!selectionLocked) setGuests(value);
|
|
3302
|
+
},
|
|
3189
3303
|
guestErrors,
|
|
3190
3304
|
guestSectionShake,
|
|
3191
3305
|
handleGuestShakeEnd,
|
|
@@ -3202,7 +3316,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3202
3316
|
handleLogout,
|
|
3203
3317
|
paymentStepState,
|
|
3204
3318
|
handlePaymentStepStateChange,
|
|
3205
|
-
handlePaymentSelectionChange
|
|
3319
|
+
handlePaymentSelectionChange: (value) => {
|
|
3320
|
+
if (!selectionLocked) handlePaymentSelectionChange(value);
|
|
3321
|
+
},
|
|
3206
3322
|
paymentSelection,
|
|
3207
3323
|
isMembershipFastTrack,
|
|
3208
3324
|
waitlistClaim,
|
|
@@ -3218,7 +3334,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3218
3334
|
hasMembershipEligibility,
|
|
3219
3335
|
requireGuestDetails,
|
|
3220
3336
|
discountCode: discountUi.discountCode,
|
|
3221
|
-
setDiscountCode:
|
|
3337
|
+
setDiscountCode: (value) => {
|
|
3338
|
+
if (!selectionLocked) discountUi.setDiscountCode(value);
|
|
3339
|
+
},
|
|
3222
3340
|
discountUiOpen: discountUi.discountUiOpen,
|
|
3223
3341
|
setDiscountUiOpen: discountUi.setDiscountUiOpen,
|
|
3224
3342
|
discountsAvailable: discountUi.discountsAvailable,
|
|
@@ -3228,49 +3346,31 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
3228
3346
|
discountContext,
|
|
3229
3347
|
shouldShowDiscountToggle,
|
|
3230
3348
|
verification,
|
|
3349
|
+
paymentController,
|
|
3231
3350
|
paymentStatusRecovery,
|
|
3232
3351
|
handleCheckPaymentStatus,
|
|
3233
3352
|
handleContinueExistingPayment,
|
|
3234
3353
|
handleReturnToPayment,
|
|
3235
3354
|
handleReturnToBooking,
|
|
3355
|
+
recoveryMessage,
|
|
3356
|
+
checkingNextStep,
|
|
3357
|
+
handleRecoveryEmail,
|
|
3236
3358
|
handleDetailsComplete,
|
|
3237
3359
|
handlePaymentSelect,
|
|
3238
3360
|
handleUseCardInsteadOfPass,
|
|
3239
3361
|
handleBookForSomeoneElse,
|
|
3240
|
-
handleSubmit
|
|
3241
|
-
|
|
3362
|
+
handleSubmit: (...args) => selectionLocked ? Promise.resolve({
|
|
3363
|
+
ok: false,
|
|
3364
|
+
reason: "blocked",
|
|
3365
|
+
message: "This registration step cannot continue."
|
|
3366
|
+
}) : handleSubmit(...args),
|
|
3367
|
+
handleEventSelect: (value) => {
|
|
3368
|
+
if (!selectionLocked) handleEventSelect(value);
|
|
3369
|
+
},
|
|
3242
3370
|
handleRetry
|
|
3243
3371
|
};
|
|
3244
3372
|
}
|
|
3245
3373
|
//#endregion
|
|
3246
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.ts
|
|
3247
|
-
function eventRegistrationReloadTarget(location) {
|
|
3248
|
-
return `${location.pathname}${location.search}#${EVENT_REGISTRATION_ANCHOR_ID}`;
|
|
3249
|
-
}
|
|
3250
|
-
function reloadAtEventRegistration() {
|
|
3251
|
-
const target = eventRegistrationReloadTarget(window.location);
|
|
3252
|
-
window.history.replaceState(window.history.state, "", target);
|
|
3253
|
-
window.location.reload();
|
|
3254
|
-
}
|
|
3255
|
-
const browserCheckoutHandoffRestoreDeps = {
|
|
3256
|
-
addPageShowListener: (listener) => window.addEventListener("pageshow", listener),
|
|
3257
|
-
removePageShowListener: (listener) => window.removeEventListener("pageshow", listener),
|
|
3258
|
-
reloadAtRegistration: reloadAtEventRegistration
|
|
3259
|
-
};
|
|
3260
|
-
function useEventCheckoutHandoffRestore(active) {
|
|
3261
|
-
useEventCheckoutHandoffRestoreWithDeps(active, browserCheckoutHandoffRestoreDeps);
|
|
3262
|
-
}
|
|
3263
|
-
function useEventCheckoutHandoffRestoreWithDeps(active, deps) {
|
|
3264
|
-
useEffect(() => {
|
|
3265
|
-
if (!active) return;
|
|
3266
|
-
const handlePageShow = (event) => {
|
|
3267
|
-
if (event.persisted) deps.reloadAtRegistration();
|
|
3268
|
-
};
|
|
3269
|
-
deps.addPageShowListener(handlePageShow);
|
|
3270
|
-
return () => deps.removePageShowListener(handlePageShow);
|
|
3271
|
-
}, [active, deps]);
|
|
3272
|
-
}
|
|
3273
|
-
//#endregion
|
|
3274
3374
|
//#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationBookingLayer.tsx
|
|
3275
3375
|
function BookingEntry(props) {
|
|
3276
3376
|
const base = props.variant === "teaser" ? "er-booking-teaser" : "er-booking-bar";
|
|
@@ -3693,6 +3793,16 @@ function resolveEntitlementSummaryCopy(method, passCreditsRemaining) {
|
|
|
3693
3793
|
function getSummaryRow(option, label) {
|
|
3694
3794
|
return option.summaryRows.find((row) => row.label === label)?.value ?? null;
|
|
3695
3795
|
}
|
|
3796
|
+
function getFlexibleBalanceSummary(option) {
|
|
3797
|
+
if (option?.kind !== "flexible_balance") return null;
|
|
3798
|
+
return {
|
|
3799
|
+
total: getSummaryRow(option, "Total"),
|
|
3800
|
+
dueToday: getSummaryRow(option, "Due today"),
|
|
3801
|
+
remainingBalance: getSummaryRow(option, "Remaining balance"),
|
|
3802
|
+
balanceDueBy: getSummaryRow(option, "Balance due by"),
|
|
3803
|
+
depositPolicy: getSummaryRow(option, "Deposit policy")
|
|
3804
|
+
};
|
|
3805
|
+
}
|
|
3696
3806
|
function getSelectedDirectPaymentOption(input) {
|
|
3697
3807
|
const summaryEvent = input.wizard.selectedEvent ?? input.wizard.preSelectedEvent;
|
|
3698
3808
|
const eligibility = input.wizard.eligibility;
|
|
@@ -3703,7 +3813,8 @@ function getSelectedDirectPaymentOption(input) {
|
|
|
3703
3813
|
paymentTerms: eligibility.paymentTerms,
|
|
3704
3814
|
totalPriceCents: input.totalCents,
|
|
3705
3815
|
currency: input.currency,
|
|
3706
|
-
startsAt: getRegistrationStartAt(summaryEvent, input.wizard.occurrenceContext)
|
|
3816
|
+
startsAt: getRegistrationStartAt(summaryEvent, input.wizard.occurrenceContext),
|
|
3817
|
+
nowIso: input.wizard.nowIso
|
|
3707
3818
|
}).options;
|
|
3708
3819
|
const requestedKind = input.wizard.paymentSelection.collectionOptionKind;
|
|
3709
3820
|
return options.find((option) => option.kind === requestedKind) ?? options.find((option) => option.kind === "upfront") ?? options[0] ?? null;
|
|
@@ -3753,18 +3864,11 @@ function EventRegistrationSummaryBar(props) {
|
|
|
3753
3864
|
const autoAppliedDiscount = wizard.discountCode.trim().length > 0 ? null : wizard.autoAppliedDiscount;
|
|
3754
3865
|
const autoAppliedDiscountCents = Math.max(0, autoAppliedDiscount?.computedAmountCents ?? 0);
|
|
3755
3866
|
const discountedTotalCents = Math.max(0, subtotalCents - autoAppliedDiscountCents);
|
|
3756
|
-
const
|
|
3867
|
+
const flexibleBalanceSummary = getFlexibleBalanceSummary(getSelectedDirectPaymentOption({
|
|
3757
3868
|
wizard,
|
|
3758
3869
|
totalCents: discountedTotalCents,
|
|
3759
3870
|
currency: summaryCurrency
|
|
3760
|
-
});
|
|
3761
|
-
const flexibleBalanceSummary = selectedDirectPaymentOption?.kind === "flexible_balance" ? {
|
|
3762
|
-
total: getSummaryRow(selectedDirectPaymentOption, "Total"),
|
|
3763
|
-
dueToday: getSummaryRow(selectedDirectPaymentOption, "Due today"),
|
|
3764
|
-
remainingBalance: getSummaryRow(selectedDirectPaymentOption, "Remaining balance"),
|
|
3765
|
-
balanceDueBy: getSummaryRow(selectedDirectPaymentOption, "Balance due by"),
|
|
3766
|
-
depositPolicy: getSummaryRow(selectedDirectPaymentOption, "Deposit policy")
|
|
3767
|
-
} : null;
|
|
3871
|
+
}));
|
|
3768
3872
|
const scheduleSummary = summaryEvent ? getScheduleSummary(wizard, summaryEvent) : null;
|
|
3769
3873
|
const bookingUnit = summaryEvent?.registrationSubject.kind === "wholeSeries" ? "place" : "ticket";
|
|
3770
3874
|
const productMethod = isProductMethod(wizard.paymentSelection.method);
|
|
@@ -3868,49 +3972,23 @@ function EventRegistrationSummaryBar(props) {
|
|
|
3868
3972
|
*/
|
|
3869
3973
|
function resolveDetailsButtonText(input) {
|
|
3870
3974
|
const { wizard } = input;
|
|
3871
|
-
const
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3975
|
+
const admission = wizard.admission;
|
|
3976
|
+
switch (admission.kind) {
|
|
3977
|
+
case "checking": return "Checking availability...";
|
|
3978
|
+
case "closed": return admission.reason === "alreadyWaitlisted" ? "Already on waitlist" : "Registration unavailable";
|
|
3979
|
+
case "fullyBooked": return admission.recovery === "byEmail" ? "Continue" : "Sold out";
|
|
3980
|
+
case "waitlist": return admission.recovery === "byEmail" ? "Continue" : "Join waitlist";
|
|
3981
|
+
case "open":
|
|
3982
|
+
case "resume": break;
|
|
3983
|
+
}
|
|
3876
3984
|
if (wizard.paymentSelection.method === "pass") return "Book using class pass";
|
|
3877
3985
|
if (wizard.paymentSelection.method === "membership") return input.fallbackText;
|
|
3878
3986
|
return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
|
|
3879
3987
|
}
|
|
3880
|
-
function resolveExistingRegistrationLabel(wizard) {
|
|
3881
|
-
return wizard.registrationState.kind === "waitlisted" ? "Already on waitlist" : "Already registered";
|
|
3882
|
-
}
|
|
3883
|
-
function isExistingRegistrationBlocking$1(wizard) {
|
|
3884
|
-
return hasBlockingExistingRegistration({
|
|
3885
|
-
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
3886
|
-
registration: wizard.registrationState,
|
|
3887
|
-
hasWaitlistClaim: wizard.waitlistClaim.claim !== null
|
|
3888
|
-
});
|
|
3889
|
-
}
|
|
3890
|
-
function resolveTicketSelectionContinueLabel(input) {
|
|
3891
|
-
if (input.isCheckingExistingRegistration) return "Checking registration...";
|
|
3892
|
-
if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
|
|
3893
|
-
if (input.registrationOptionsPending) return "Checking availability...";
|
|
3894
|
-
if (input.registrationOptionsFailed) return "Availability unavailable";
|
|
3895
|
-
if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
|
|
3896
|
-
return "Continue";
|
|
3897
|
-
}
|
|
3898
3988
|
function SelectTicketsActions(props) {
|
|
3899
3989
|
const { wizard } = props;
|
|
3900
|
-
const
|
|
3901
|
-
const
|
|
3902
|
-
const registrationOptionsFailed = wizard.registrationOptionsState.tag === "failed";
|
|
3903
|
-
const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
|
|
3904
|
-
const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
|
|
3905
|
-
const isContinueDisabled = registrationOptionsPending || registrationOptionsFailed || isCheckingExistingRegistration || hasExistingRegistration || ticketTypeSelectionBlocked;
|
|
3906
|
-
const continueLabel = resolveTicketSelectionContinueLabel({
|
|
3907
|
-
wizard,
|
|
3908
|
-
registrationOptionsPending,
|
|
3909
|
-
registrationOptionsFailed,
|
|
3910
|
-
isCheckingExistingRegistration,
|
|
3911
|
-
hasExistingRegistration,
|
|
3912
|
-
ticketTypeSelectionBlocked
|
|
3913
|
-
});
|
|
3990
|
+
const { label: continueLabel, pending: registrationOptionsPending } = wizard.ticketContinuation;
|
|
3991
|
+
const isContinueDisabled = wizard.ticketContinuation.kind === "blocked";
|
|
3914
3992
|
return /* @__PURE__ */ jsxs("div", {
|
|
3915
3993
|
className: "rb-wizard-actions er-actions",
|
|
3916
3994
|
children: [!wizard.hasPreSelectedContext && /* @__PURE__ */ jsx("button", {
|
|
@@ -3920,7 +3998,7 @@ function SelectTicketsActions(props) {
|
|
|
3920
3998
|
children: "← Back"
|
|
3921
3999
|
}), /* @__PURE__ */ jsx(ThemedButton, {
|
|
3922
4000
|
type: "button",
|
|
3923
|
-
onClick:
|
|
4001
|
+
onClick: wizard.handleTicketsComplete,
|
|
3924
4002
|
disabled: isContinueDisabled,
|
|
3925
4003
|
variant: props.buttonVariant,
|
|
3926
4004
|
size: "md",
|
|
@@ -3936,18 +4014,11 @@ function SelectTicketsActions(props) {
|
|
|
3936
4014
|
}
|
|
3937
4015
|
function EnterDetailsActions(props) {
|
|
3938
4016
|
const { wizard } = props;
|
|
3939
|
-
const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
|
|
3940
4017
|
const isCheckingEligibility = wizard.eligibilityLoading;
|
|
3941
|
-
const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker(
|
|
3942
|
-
|
|
3943
|
-
eligibility: wizard.eligibility,
|
|
3944
|
-
eligibilityError: wizard.eligibilityError
|
|
3945
|
-
}));
|
|
3946
|
-
const isSoldOut = !hasWaitlistClaim && wizard.portalAuthState === "authenticated" && wizard.eligibility?.registration.kind !== "pending_payment" && isSelectionSoldOut(wizard.eligibility?.availability);
|
|
3947
|
-
const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
|
|
4018
|
+
const eligibilityUnavailable = Boolean(resolveRegistrationAvailabilityBlocker(wizard.admission));
|
|
4019
|
+
const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable;
|
|
3948
4020
|
const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
|
|
3949
4021
|
wizard,
|
|
3950
|
-
hasWaitlistClaim,
|
|
3951
4022
|
fallbackText: props.buttonText
|
|
3952
4023
|
});
|
|
3953
4024
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -3990,10 +4061,11 @@ function SelectPaymentActions(props) {
|
|
|
3990
4061
|
function EventRegistrationWizardActions(props) {
|
|
3991
4062
|
const { wizard } = props;
|
|
3992
4063
|
switch (wizard.step) {
|
|
4064
|
+
case "fully-booked":
|
|
3993
4065
|
case "error":
|
|
3994
4066
|
case "success":
|
|
3995
4067
|
case "submitting":
|
|
3996
|
-
case "
|
|
4068
|
+
case "payment":
|
|
3997
4069
|
case "verifying-payment":
|
|
3998
4070
|
case "verifying-timeout":
|
|
3999
4071
|
case "payment-status":
|
|
@@ -4006,6 +4078,118 @@ function EventRegistrationWizardActions(props) {
|
|
|
4006
4078
|
}
|
|
4007
4079
|
}
|
|
4008
4080
|
//#endregion
|
|
4081
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationPayment.tsx
|
|
4082
|
+
const Payment = lazy(() => import("./EventEmbeddedCheckoutStep-DL6zFAkA.mjs"));
|
|
4083
|
+
/** The one Stripe mount, shared by the standard wizard and headless arrangements. */
|
|
4084
|
+
function EventPaymentMount({ state, onComplete, onRetry, onBack }) {
|
|
4085
|
+
if (state.kind === "abandoning") return /* @__PURE__ */ jsx("p", {
|
|
4086
|
+
role: "status",
|
|
4087
|
+
children: "Returning to booking…"
|
|
4088
|
+
});
|
|
4089
|
+
if (state.kind !== "payment") return null;
|
|
4090
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
4091
|
+
fallback: /* @__PURE__ */ jsx("p", {
|
|
4092
|
+
role: "status",
|
|
4093
|
+
children: "Loading secure payment…"
|
|
4094
|
+
}),
|
|
4095
|
+
children: /* @__PURE__ */ jsx(Payment, {
|
|
4096
|
+
checkout: state.checkout,
|
|
4097
|
+
onComplete,
|
|
4098
|
+
onRetry,
|
|
4099
|
+
onBack: () => void onBack()
|
|
4100
|
+
})
|
|
4101
|
+
});
|
|
4102
|
+
}
|
|
4103
|
+
//#endregion
|
|
4104
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/FullyBookedStep.tsx
|
|
4105
|
+
function RecoveryEmailField({ wizard }) {
|
|
4106
|
+
const id = useId();
|
|
4107
|
+
const errorId = `${id}-error`;
|
|
4108
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4109
|
+
className: "er-field",
|
|
4110
|
+
children: [
|
|
4111
|
+
/* @__PURE__ */ jsx("label", {
|
|
4112
|
+
className: "er-label",
|
|
4113
|
+
htmlFor: id,
|
|
4114
|
+
children: "Email"
|
|
4115
|
+
}),
|
|
4116
|
+
/* @__PURE__ */ jsx("input", {
|
|
4117
|
+
id,
|
|
4118
|
+
type: "email",
|
|
4119
|
+
autoComplete: "email",
|
|
4120
|
+
className: "er-input",
|
|
4121
|
+
value: wizard.formData.email,
|
|
4122
|
+
onChange: (event) => wizard.setFormData({
|
|
4123
|
+
...wizard.formData,
|
|
4124
|
+
email: event.target.value
|
|
4125
|
+
}),
|
|
4126
|
+
...getFieldValidationControlProps({
|
|
4127
|
+
message: wizard.errors.email,
|
|
4128
|
+
messageId: errorId
|
|
4129
|
+
})
|
|
4130
|
+
}),
|
|
4131
|
+
wizard.errors.email && /* @__PURE__ */ jsx(FieldValidationMessage, {
|
|
4132
|
+
id: errorId,
|
|
4133
|
+
className: "er-error",
|
|
4134
|
+
children: wizard.errors.email
|
|
4135
|
+
})
|
|
4136
|
+
]
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4139
|
+
function RecoveryEmail(props) {
|
|
4140
|
+
const { wizard } = props;
|
|
4141
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4142
|
+
className: "rb-reg-stack er-stack",
|
|
4143
|
+
children: [
|
|
4144
|
+
/* @__PURE__ */ jsx("p", {
|
|
4145
|
+
className: "er-text",
|
|
4146
|
+
children: "Already started a booking? Enter your email to finish paying."
|
|
4147
|
+
}),
|
|
4148
|
+
/* @__PURE__ */ jsx(RecoveryEmailField, { wizard }),
|
|
4149
|
+
props.showSpamProtection && /* @__PURE__ */ jsx("div", {
|
|
4150
|
+
className: "er-altcha",
|
|
4151
|
+
children: /* @__PURE__ */ jsx(AltchaWidget, {
|
|
4152
|
+
challengeUrl: getChallengeUrl(),
|
|
4153
|
+
onSolutionChange: wizard.setAltchaSolution
|
|
4154
|
+
})
|
|
4155
|
+
}),
|
|
4156
|
+
wizard.recoveryMessage && /* @__PURE__ */ jsx("p", {
|
|
4157
|
+
role: "alert",
|
|
4158
|
+
className: "er-error",
|
|
4159
|
+
children: wizard.recoveryMessage
|
|
4160
|
+
}),
|
|
4161
|
+
/* @__PURE__ */ jsx("button", {
|
|
4162
|
+
type: "button",
|
|
4163
|
+
className: "er-btn er-btn--primary",
|
|
4164
|
+
disabled: wizard.checkingNextStep || props.showSpamProtection && !wizard.altchaSolution,
|
|
4165
|
+
onClick: () => void wizard.handleRecoveryEmail(),
|
|
4166
|
+
children: wizard.checkingNextStep ? "Checking booking..." : "Continue"
|
|
4167
|
+
})
|
|
4168
|
+
]
|
|
4169
|
+
});
|
|
4170
|
+
}
|
|
4171
|
+
function FullyBookedStep(props) {
|
|
4172
|
+
const { wizard } = props;
|
|
4173
|
+
const admission = wizard.admission;
|
|
4174
|
+
const byEmail = admission.kind === "fullyBooked" && admission.recovery === "byEmail";
|
|
4175
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4176
|
+
className: "rb-reg-stack er-stack",
|
|
4177
|
+
children: [
|
|
4178
|
+
/* @__PURE__ */ jsx("h3", {
|
|
4179
|
+
className: "er-title",
|
|
4180
|
+
children: "This event is fully booked"
|
|
4181
|
+
}),
|
|
4182
|
+
byEmail && /* @__PURE__ */ jsx(RecoveryEmail, { ...props }),
|
|
4183
|
+
/* @__PURE__ */ jsx("button", {
|
|
4184
|
+
type: "button",
|
|
4185
|
+
className: "er-back-btn",
|
|
4186
|
+
onClick: () => wizard.setStep("select-tickets"),
|
|
4187
|
+
children: "← Back"
|
|
4188
|
+
})
|
|
4189
|
+
]
|
|
4190
|
+
});
|
|
4191
|
+
}
|
|
4192
|
+
//#endregion
|
|
4009
4193
|
//#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
|
|
4010
4194
|
function calculateEventRegistrationPreviewTotal(input) {
|
|
4011
4195
|
const discountCents = input.manualDiscountCode.trim() ? 0 : input.automaticDiscount?.computedAmountCents ?? 0;
|
|
@@ -4081,7 +4265,7 @@ function buildSelectedSiteCreditPreview(input) {
|
|
|
4081
4265
|
function resolvePaymentStepStatus(input) {
|
|
4082
4266
|
if (input.loading) return "loading";
|
|
4083
4267
|
if (input.error || !input.eligibility) return "error";
|
|
4084
|
-
if (input.
|
|
4268
|
+
if (resolveRegistrationAvailabilityBlocker(input.admission) !== null || input.eligibility.paymentOptions.length === 0) return "not-eligible";
|
|
4085
4269
|
return "ready";
|
|
4086
4270
|
}
|
|
4087
4271
|
function shouldPromptForLogin(status, isAuthenticated, eligibility) {
|
|
@@ -4115,8 +4299,8 @@ function UnavailableEntitlementMessage(props) {
|
|
|
4115
4299
|
})
|
|
4116
4300
|
] });
|
|
4117
4301
|
}
|
|
4118
|
-
function
|
|
4119
|
-
|
|
4302
|
+
function SoldOutPaymentPanel() {
|
|
4303
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4120
4304
|
className: "rb-reg-stack er-stack",
|
|
4121
4305
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
4122
4306
|
className: "er-title",
|
|
@@ -4129,6 +4313,8 @@ function IneligiblePaymentPanel(props) {
|
|
|
4129
4313
|
})
|
|
4130
4314
|
})]
|
|
4131
4315
|
});
|
|
4316
|
+
}
|
|
4317
|
+
function IneligiblePaymentPanel(props) {
|
|
4132
4318
|
const promptLogin = shouldPromptForLogin("not-eligible", props.isAuthenticated, props.eligibility);
|
|
4133
4319
|
return /* @__PURE__ */ jsxs("div", {
|
|
4134
4320
|
className: "rb-reg-stack er-stack",
|
|
@@ -4158,6 +4344,12 @@ function IneligiblePaymentPanel(props) {
|
|
|
4158
4344
|
})]
|
|
4159
4345
|
});
|
|
4160
4346
|
}
|
|
4347
|
+
function renderRegistrationAvailabilityBlocker(admission) {
|
|
4348
|
+
const blocker = resolveRegistrationAvailabilityBlocker(admission);
|
|
4349
|
+
if (blocker?.kind !== "unavailable") return null;
|
|
4350
|
+
if (admission.kind === "closed" && admission.reason === "alreadyWaitlisted") return /* @__PURE__ */ jsx(AlreadyWaitlistedPaymentPanel, {});
|
|
4351
|
+
return admission.kind === "fullyBooked" ? /* @__PURE__ */ jsx(SoldOutPaymentPanel, {}) : /* @__PURE__ */ jsx(ClosedPaymentPanel, { message: blocker.message });
|
|
4352
|
+
}
|
|
4161
4353
|
function PaymentBlockingPanel(props) {
|
|
4162
4354
|
if (props.eligibilityLoading) return /* @__PURE__ */ jsx("div", {
|
|
4163
4355
|
className: "rb-reg-stack er-stack",
|
|
@@ -4183,7 +4375,18 @@ function PaymentBlockingPanel(props) {
|
|
|
4183
4375
|
})
|
|
4184
4376
|
});
|
|
4185
4377
|
if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
|
|
4186
|
-
|
|
4378
|
+
const availabilityPanel = renderRegistrationAvailabilityBlocker(props.admission);
|
|
4379
|
+
if (availabilityPanel) return availabilityPanel;
|
|
4380
|
+
if (props.eligibility.isFree) return /* @__PURE__ */ jsx(FreePaymentSummary, { ticketsCount: props.ticketsCount });
|
|
4381
|
+
return props.eligibility.paymentOptions.length > 0 ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
|
|
4382
|
+
eligibility: props.eligibility,
|
|
4383
|
+
email: props.email,
|
|
4384
|
+
isAuthenticated: props.isAuthenticated,
|
|
4385
|
+
onRequestLogin: props.onRequestLogin
|
|
4386
|
+
});
|
|
4387
|
+
}
|
|
4388
|
+
function AlreadyWaitlistedPaymentPanel() {
|
|
4389
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4187
4390
|
className: "rb-reg-stack er-stack",
|
|
4188
4391
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
4189
4392
|
className: "er-title",
|
|
@@ -4200,7 +4403,9 @@ function PaymentBlockingPanel(props) {
|
|
|
4200
4403
|
})]
|
|
4201
4404
|
})]
|
|
4202
4405
|
});
|
|
4203
|
-
|
|
4406
|
+
}
|
|
4407
|
+
function FreePaymentSummary({ ticketsCount }) {
|
|
4408
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4204
4409
|
className: "rb-reg-stack er-stack",
|
|
4205
4410
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
4206
4411
|
className: "er-title",
|
|
@@ -4213,18 +4418,24 @@ function PaymentBlockingPanel(props) {
|
|
|
4213
4418
|
}), /* @__PURE__ */ jsxs("p", {
|
|
4214
4419
|
className: "er-text er-text--muted",
|
|
4215
4420
|
children: [
|
|
4216
|
-
|
|
4421
|
+
ticketsCount,
|
|
4217
4422
|
" ticket",
|
|
4218
|
-
|
|
4423
|
+
ticketsCount > 1 ? "s" : ""
|
|
4219
4424
|
]
|
|
4220
4425
|
})]
|
|
4221
4426
|
})]
|
|
4222
4427
|
});
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4428
|
+
}
|
|
4429
|
+
function ClosedPaymentPanel({ message }) {
|
|
4430
|
+
return /* @__PURE__ */ jsx("div", {
|
|
4431
|
+
className: "rb-reg-stack er-stack",
|
|
4432
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
4433
|
+
className: "er-center",
|
|
4434
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
4435
|
+
className: "er-text er-text--error",
|
|
4436
|
+
children: message
|
|
4437
|
+
})
|
|
4438
|
+
})
|
|
4228
4439
|
});
|
|
4229
4440
|
}
|
|
4230
4441
|
//#endregion
|
|
@@ -5210,6 +5421,29 @@ function canContinueWithPaymentSelection(selection, directPaymentSelection) {
|
|
|
5210
5421
|
case null: return false;
|
|
5211
5422
|
}
|
|
5212
5423
|
}
|
|
5424
|
+
function buildEventPaymentSelectionView(input) {
|
|
5425
|
+
const canShowDirectPaymentOptions = Boolean(input.eligibility?.requiresPayment && input.eligibility.price);
|
|
5426
|
+
const directPaymentOptions = input.eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
|
|
5427
|
+
eventTitle: input.event?.title ?? "Event",
|
|
5428
|
+
approvedPaymentOptions: input.eligibility.paymentOptions,
|
|
5429
|
+
paymentTerms: input.eligibility.paymentTerms,
|
|
5430
|
+
totalPriceCents: input.totalPriceCents,
|
|
5431
|
+
currency: input.eligibility.currency,
|
|
5432
|
+
startsAt: getRegistrationStartAt(input.event, input.occurrenceContext),
|
|
5433
|
+
nowIso: input.nowIso
|
|
5434
|
+
}).options : [];
|
|
5435
|
+
const directPaymentSelectionState = resolveEventRegistrationDirectPaymentSelection({
|
|
5436
|
+
options: directPaymentOptions,
|
|
5437
|
+
selection: input.selection
|
|
5438
|
+
});
|
|
5439
|
+
return {
|
|
5440
|
+
canShowDirectPaymentOptions,
|
|
5441
|
+
directPaymentOptions,
|
|
5442
|
+
directPaymentSelectionState,
|
|
5443
|
+
directPaymentFallbackKind: directPaymentSelectionState.kind === "invalid" ? directPaymentSelectionState.fallbackSelection.collectionOptionKind : void 0,
|
|
5444
|
+
selectedDirectOption: directPaymentSelectionState.kind === "valid" ? directPaymentOptions.find((option) => option.kind === directPaymentSelectionState.selection.collectionOptionKind) ?? null : null
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5213
5447
|
/**
|
|
5214
5448
|
* Payment Selection Step
|
|
5215
5449
|
*
|
|
@@ -5217,25 +5451,17 @@ function canContinueWithPaymentSelection(selection, directPaymentSelection) {
|
|
|
5217
5451
|
* Fetches eligible passes/memberships using the user's email.
|
|
5218
5452
|
* Also shows available passes/memberships for purchase (upsell).
|
|
5219
5453
|
*/
|
|
5220
|
-
const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, isAuthenticated = false, creditState = { kind: "not_authenticated" }, directPaymentTotalCents, manualDiscountPending = false, selectedSelection, onSelectionChange, eligibility, eligibilityLoading, eligibilityError = null, onRequestLogin, onStateChange }) => {
|
|
5454
|
+
const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, isAuthenticated = false, creditState = { kind: "not_authenticated" }, directPaymentTotalCents, manualDiscountPending = false, selectedSelection, onSelectionChange, eligibility, admission, eligibilityLoading, eligibilityError = null, onRequestLogin, onStateChange, nowIso }) => {
|
|
5221
5455
|
const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
|
|
5222
5456
|
const selectedMethod = selectedSelection.method;
|
|
5223
|
-
const
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
totalPriceCents: totalPrice,
|
|
5230
|
-
currency: eligibility.currency,
|
|
5231
|
-
startsAt: getRegistrationStartAt(event, occurrenceContext)
|
|
5232
|
-
}).options : [];
|
|
5233
|
-
const directPaymentSelectionState = resolveEventRegistrationDirectPaymentSelection({
|
|
5234
|
-
options: directPaymentOptions,
|
|
5457
|
+
const { canShowDirectPaymentOptions, directPaymentOptions, directPaymentSelectionState, directPaymentFallbackKind, selectedDirectOption } = buildEventPaymentSelectionView({
|
|
5458
|
+
event,
|
|
5459
|
+
occurrenceContext,
|
|
5460
|
+
eligibility,
|
|
5461
|
+
totalPriceCents: directPaymentTotalCents,
|
|
5462
|
+
nowIso,
|
|
5235
5463
|
selection: selectedSelection
|
|
5236
5464
|
});
|
|
5237
|
-
const directPaymentFallbackKind = (directPaymentSelectionState.kind === "invalid" ? directPaymentSelectionState.fallbackSelection : null)?.collectionOptionKind;
|
|
5238
|
-
const selectedDirectOption = directPaymentSelectionState.kind === "valid" ? directPaymentOptions.find((option) => option.kind === directPaymentSelectionState.selection.collectionOptionKind) ?? null : null;
|
|
5239
5465
|
const siteCreditPreview = buildSelectedSiteCreditPreview({
|
|
5240
5466
|
options: directPaymentOptions,
|
|
5241
5467
|
selectionState: directPaymentSelectionState,
|
|
@@ -5254,7 +5480,8 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
|
|
|
5254
5480
|
const paymentStepStatus = resolvePaymentStepStatus({
|
|
5255
5481
|
loading: eligibilityLoading,
|
|
5256
5482
|
error: eligibilityError,
|
|
5257
|
-
eligibility
|
|
5483
|
+
eligibility,
|
|
5484
|
+
admission
|
|
5258
5485
|
});
|
|
5259
5486
|
const paymentButtonText = resolvePaymentButtonText(selectedMethod, siteCreditPreview, eligibility, selectedDirectOption);
|
|
5260
5487
|
const showLoginPrompt = shouldPromptForLogin(paymentStepStatus, isAuthenticated, eligibility);
|
|
@@ -5275,6 +5502,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
|
|
|
5275
5502
|
]);
|
|
5276
5503
|
const blockingPanel = /* @__PURE__ */ jsx(PaymentBlockingPanel, {
|
|
5277
5504
|
eligibility,
|
|
5505
|
+
admission,
|
|
5278
5506
|
eligibilityLoading,
|
|
5279
5507
|
eligibilityError,
|
|
5280
5508
|
occurrenceId,
|
|
@@ -5422,16 +5650,6 @@ function ExistingRegistrationNotice(props) {
|
|
|
5422
5650
|
})
|
|
5423
5651
|
});
|
|
5424
5652
|
}
|
|
5425
|
-
function resolveExistingRegistrationKind(wizard) {
|
|
5426
|
-
return wizard.registrationState.kind === "waitlisted" ? "waitlisted" : "booked";
|
|
5427
|
-
}
|
|
5428
|
-
function isExistingRegistrationBlocking(wizard) {
|
|
5429
|
-
return hasBlockingExistingRegistration({
|
|
5430
|
-
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
5431
|
-
registration: wizard.registrationState,
|
|
5432
|
-
hasWaitlistClaim: wizard.waitlistClaim.claim !== null
|
|
5433
|
-
});
|
|
5434
|
-
}
|
|
5435
5653
|
function AttendeeDetailsContent(props) {
|
|
5436
5654
|
const { wizard } = props;
|
|
5437
5655
|
const membership = wizard.portalAuthState === "authenticated" && wizard.ticketsCount === 1 ? wizard.eligibility?.eligibleMemberships[0] : void 0;
|
|
@@ -5462,12 +5680,29 @@ function AttendeeDetailsContent(props) {
|
|
|
5462
5680
|
})
|
|
5463
5681
|
] });
|
|
5464
5682
|
}
|
|
5683
|
+
function EventDiscountCodeDisclosure(props) {
|
|
5684
|
+
const { wizard } = props;
|
|
5685
|
+
if (wizard.discountsAvailableLoading || !wizard.shouldShowDiscountToggle) return null;
|
|
5686
|
+
return /* @__PURE__ */ jsx(DiscountCodeDisclosure, {
|
|
5687
|
+
surface: "event-registration",
|
|
5688
|
+
isOpen: wizard.discountUiOpen,
|
|
5689
|
+
code: wizard.discountCode,
|
|
5690
|
+
onOpen: () => wizard.setDiscountUiOpen(true),
|
|
5691
|
+
onChange: wizard.setDiscountCode,
|
|
5692
|
+
onRemove: () => {
|
|
5693
|
+
wizard.setDiscountCode("");
|
|
5694
|
+
wizard.setDiscountUiOpen(false);
|
|
5695
|
+
},
|
|
5696
|
+
id: "er-discount-code"
|
|
5697
|
+
});
|
|
5698
|
+
}
|
|
5465
5699
|
function PaymentSelectionContent(props) {
|
|
5466
5700
|
const { wizard } = props;
|
|
5467
5701
|
const subtotalCents = wizard.ticketSelectionSubtotalCents;
|
|
5468
5702
|
if (!wizard.api.config.siteId) return null;
|
|
5469
5703
|
if (subtotalCents === null) return /* @__PURE__ */ jsx(PaymentBlockingPanel, {
|
|
5470
5704
|
eligibility: wizard.eligibility,
|
|
5705
|
+
admission: wizard.admission,
|
|
5471
5706
|
eligibilityLoading: wizard.eligibilityLoading,
|
|
5472
5707
|
eligibilityError: wizard.eligibilityError,
|
|
5473
5708
|
occurrenceId: wizard.occurrenceContext?.id ?? "",
|
|
@@ -5492,31 +5727,62 @@ function PaymentSelectionContent(props) {
|
|
|
5492
5727
|
selectedSelection: wizard.paymentSelection,
|
|
5493
5728
|
onSelectionChange: wizard.handlePaymentSelectionChange,
|
|
5494
5729
|
eligibility: wizard.eligibility,
|
|
5730
|
+
admission: wizard.admission,
|
|
5495
5731
|
eligibilityLoading: wizard.eligibilityLoading,
|
|
5496
5732
|
eligibilityError: wizard.eligibilityError,
|
|
5497
5733
|
onRequestLogin: () => wizard.setShowMagicLinkModal(true),
|
|
5498
|
-
onStateChange: wizard.handlePaymentStepStateChange
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5734
|
+
onStateChange: wizard.handlePaymentStepStateChange,
|
|
5735
|
+
nowIso: wizard.nowIso
|
|
5736
|
+
}), /* @__PURE__ */ jsx(EventDiscountCodeDisclosure, { wizard })] });
|
|
5737
|
+
}
|
|
5738
|
+
function ClosedAdmissionNotice({ wizard }) {
|
|
5739
|
+
const admission = wizard.admission;
|
|
5740
|
+
return admission.kind === "closed" && admission.reason !== "alreadyWaitlisted" && !wizard.eligibilityLoading ? /* @__PURE__ */ jsx("p", {
|
|
5741
|
+
role: "alert",
|
|
5742
|
+
className: "er-error",
|
|
5743
|
+
children: admission.message
|
|
5744
|
+
}) : null;
|
|
5745
|
+
}
|
|
5746
|
+
function TicketSelectionContent({ wizard }) {
|
|
5747
|
+
if (!wizard.selectedEvent && !wizard.occurrenceContext) return null;
|
|
5748
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5749
|
+
wizard.admission.kind === "closed" && wizard.admission.reason === "alreadyWaitlisted" && /* @__PURE__ */ jsx(ExistingRegistrationNotice, {
|
|
5750
|
+
kind: "waitlisted",
|
|
5751
|
+
onBookForSomeoneElse: wizard.handleBookForSomeoneElse
|
|
5752
|
+
}),
|
|
5753
|
+
/* @__PURE__ */ jsx(ClosedAdmissionNotice, { wizard }),
|
|
5754
|
+
/* @__PURE__ */ jsx(TicketSelectionStep, {
|
|
5755
|
+
event: wizard.selectedEvent,
|
|
5756
|
+
occurrenceContext: wizard.occurrenceContext,
|
|
5757
|
+
selectedAttendanceMode: wizard.selectedAttendanceMode,
|
|
5758
|
+
onAttendanceModeChange: wizard.setSelectedAttendanceMode,
|
|
5759
|
+
ticketsCount: wizard.ticketsCount,
|
|
5760
|
+
maxTickets: wizard.maxTicketsNum,
|
|
5761
|
+
visibleTicketTypes: wizard.visibleTicketTypes,
|
|
5762
|
+
ticketSelections: wizard.selectedTicketLines,
|
|
5763
|
+
onTicketSelectionsChange: wizard.setSelectedTicketLines,
|
|
5764
|
+
slidingScale: wizard.selectedEventSlidingScale,
|
|
5765
|
+
selectedSlidingAmountInput: wizard.selectedSlidingAmountInput,
|
|
5766
|
+
slidingScaleSelectionMessage: wizard.slidingScaleSelectionMessage,
|
|
5767
|
+
onSlidingAmountChange: wizard.setSelectedSlidingAmountInput,
|
|
5768
|
+
onTicketsChange: wizard.setTicketsCount,
|
|
5769
|
+
bookingUnit: resolveBookingUnit(wizard.selectedEvent)
|
|
5770
|
+
})
|
|
5771
|
+
] });
|
|
5511
5772
|
}
|
|
5512
5773
|
function EventRegistrationWizardContent(props) {
|
|
5513
5774
|
const { wizard } = props;
|
|
5514
5775
|
const showSpamProtection = props.showSpamProtection ?? isSpamProtectionEnabled();
|
|
5515
5776
|
switch (wizard.step) {
|
|
5777
|
+
case "payment": return /* @__PURE__ */ jsx(EventPaymentMount, {
|
|
5778
|
+
state: wizard.paymentController.state,
|
|
5779
|
+
onComplete: wizard.paymentController.check,
|
|
5780
|
+
onRetry: wizard.paymentController.retryPaymentLoad,
|
|
5781
|
+
onBack: wizard.paymentController.backToBooking
|
|
5782
|
+
});
|
|
5516
5783
|
case "error":
|
|
5517
5784
|
case "success":
|
|
5518
5785
|
case "submitting":
|
|
5519
|
-
case "redirecting":
|
|
5520
5786
|
case "verifying-payment":
|
|
5521
5787
|
case "verifying-timeout":
|
|
5522
5788
|
case "payment-status":
|
|
@@ -5528,28 +5794,11 @@ function EventRegistrationWizardContent(props) {
|
|
|
5528
5794
|
showVenue: props.showVenue,
|
|
5529
5795
|
showCapacity: props.showCapacity
|
|
5530
5796
|
});
|
|
5531
|
-
case "select-tickets":
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
}), /* @__PURE__ */ jsx(TicketSelectionStep, {
|
|
5537
|
-
event: wizard.selectedEvent,
|
|
5538
|
-
occurrenceContext: wizard.occurrenceContext,
|
|
5539
|
-
selectedAttendanceMode: wizard.selectedAttendanceMode,
|
|
5540
|
-
onAttendanceModeChange: wizard.setSelectedAttendanceMode,
|
|
5541
|
-
ticketsCount: wizard.ticketsCount,
|
|
5542
|
-
maxTickets: wizard.maxTicketsNum,
|
|
5543
|
-
visibleTicketTypes: wizard.visibleTicketTypes,
|
|
5544
|
-
ticketSelections: wizard.selectedTicketLines,
|
|
5545
|
-
onTicketSelectionsChange: wizard.setSelectedTicketLines,
|
|
5546
|
-
slidingScale: wizard.selectedEventSlidingScale,
|
|
5547
|
-
selectedSlidingAmountInput: wizard.selectedSlidingAmountInput,
|
|
5548
|
-
slidingScaleSelectionMessage: wizard.slidingScaleSelectionMessage,
|
|
5549
|
-
onSlidingAmountChange: wizard.setSelectedSlidingAmountInput,
|
|
5550
|
-
onTicketsChange: wizard.setTicketsCount,
|
|
5551
|
-
bookingUnit: resolveBookingUnit(wizard.selectedEvent)
|
|
5552
|
-
})] });
|
|
5797
|
+
case "select-tickets": return /* @__PURE__ */ jsx(TicketSelectionContent, { wizard });
|
|
5798
|
+
case "fully-booked": return /* @__PURE__ */ jsx(FullyBookedStep, {
|
|
5799
|
+
wizard,
|
|
5800
|
+
showSpamProtection
|
|
5801
|
+
});
|
|
5553
5802
|
case "enter-details": return /* @__PURE__ */ jsx(AttendeeDetailsContent, {
|
|
5554
5803
|
wizard,
|
|
5555
5804
|
showSpamProtection
|
|
@@ -5628,7 +5877,10 @@ function presentation(state) {
|
|
|
5628
5877
|
case "assistanceRequired": return {
|
|
5629
5878
|
title: "We still can’t confirm your payment",
|
|
5630
5879
|
message: "Please don’t make another payment. Contact the organiser so they can check your booking.",
|
|
5631
|
-
action: {
|
|
5880
|
+
action: {
|
|
5881
|
+
label: "Return to booking",
|
|
5882
|
+
disabled: true
|
|
5883
|
+
}
|
|
5632
5884
|
};
|
|
5633
5885
|
}
|
|
5634
5886
|
}
|
|
@@ -5879,51 +6131,27 @@ function EventRegistrationMagicLinkModal(props) {
|
|
|
5879
6131
|
function EventRegistrationTerminalState(props) {
|
|
5880
6132
|
const { wizard } = props;
|
|
5881
6133
|
switch (wizard.step) {
|
|
5882
|
-
case "submitting":
|
|
5883
|
-
case "
|
|
5884
|
-
const label = wizard.step === "redirecting" ? "Redirecting to payment" : "Processing your registration";
|
|
5885
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
5886
|
-
className: "er-center",
|
|
5887
|
-
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
5888
|
-
size: "lg",
|
|
5889
|
-
srLabel: label
|
|
5890
|
-
}), /* @__PURE__ */ jsxs("p", {
|
|
5891
|
-
className: "er-text--muted",
|
|
5892
|
-
children: [label, "..."]
|
|
5893
|
-
})]
|
|
5894
|
-
});
|
|
5895
|
-
}
|
|
6134
|
+
case "submitting": return /* @__PURE__ */ jsx(RegistrationProcessing, {});
|
|
6135
|
+
case "payment": return null;
|
|
5896
6136
|
case "verifying-payment": return /* @__PURE__ */ jsx(VerifyingPaymentStep, {});
|
|
5897
6137
|
case "payment-failed": return /* @__PURE__ */ jsx(PaymentFailedStep, {
|
|
5898
6138
|
message: wizard.errorMessage,
|
|
5899
6139
|
onRetry: () => wizard.setStep("select-payment")
|
|
5900
6140
|
});
|
|
5901
|
-
case "verifying-timeout": return /* @__PURE__ */ jsx(
|
|
5902
|
-
|
|
5903
|
-
title: wizard.verification.status === "timeout" ? void 0 : "We’re checking your payment",
|
|
5904
|
-
message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
|
|
6141
|
+
case "verifying-timeout": return /* @__PURE__ */ jsx(RegistrationVerificationTimeout, {
|
|
6142
|
+
wizard,
|
|
5905
6143
|
supportEmail: props.supportEmail
|
|
5906
6144
|
});
|
|
5907
|
-
case "payment-status": return
|
|
5908
|
-
state: wizard.paymentStatusRecovery,
|
|
5909
|
-
onCheck: wizard.handleCheckPaymentStatus,
|
|
5910
|
-
onContinuePayment: wizard.handleContinueExistingPayment,
|
|
5911
|
-
onReturnToPayment: wizard.handleReturnToPayment,
|
|
5912
|
-
onReturnToBooking: wizard.handleReturnToBooking
|
|
5913
|
-
}) : null;
|
|
6145
|
+
case "payment-status": return /* @__PURE__ */ jsx(RegistrationPaymentStatus, { wizard });
|
|
5914
6146
|
case "success": return /* @__PURE__ */ jsx(EventRegistrationSuccess, {
|
|
5915
6147
|
wizard,
|
|
5916
6148
|
fallbackMessage: props.successMessage,
|
|
5917
6149
|
demoEmailSuppressed: props.demoEmailSuppressed
|
|
5918
6150
|
});
|
|
5919
|
-
case "error": return /* @__PURE__ */ jsx(
|
|
5920
|
-
message: wizard.errorMessage,
|
|
5921
|
-
action: wizard.errorAction,
|
|
5922
|
-
canJoinWaitlist: wizard.eligibility?.availability.kind === "waitlist" && wizard.eligibility.registration.kind !== "pending_payment",
|
|
5923
|
-
onRetry: wizard.handleRetry
|
|
5924
|
-
});
|
|
6151
|
+
case "error": return /* @__PURE__ */ jsx(RegistrationError, { wizard });
|
|
5925
6152
|
case "select-event":
|
|
5926
6153
|
case "select-tickets":
|
|
6154
|
+
case "fully-booked":
|
|
5927
6155
|
case "enter-details":
|
|
5928
6156
|
case "select-payment": return null;
|
|
5929
6157
|
}
|
|
@@ -5992,6 +6220,46 @@ function EventRegistrationSurface(props) {
|
|
|
5992
6220
|
})]
|
|
5993
6221
|
});
|
|
5994
6222
|
}
|
|
6223
|
+
function RegistrationProcessing() {
|
|
6224
|
+
const label = "Processing your registration";
|
|
6225
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6226
|
+
className: "er-center",
|
|
6227
|
+
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
6228
|
+
size: "lg",
|
|
6229
|
+
srLabel: label
|
|
6230
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
6231
|
+
className: "er-text--muted",
|
|
6232
|
+
children: [label, "..."]
|
|
6233
|
+
})]
|
|
6234
|
+
});
|
|
6235
|
+
}
|
|
6236
|
+
function RegistrationVerificationTimeout({ wizard, supportEmail }) {
|
|
6237
|
+
const timedOut = wizard.verification.status === "timeout";
|
|
6238
|
+
return /* @__PURE__ */ jsx(VerifyingTimeoutStep, {
|
|
6239
|
+
onCheckAgain: timedOut ? wizard.verification.retry : wizard.verification.retryReturn,
|
|
6240
|
+
title: timedOut ? void 0 : "We’re checking your payment",
|
|
6241
|
+
message: timedOut ? void 0 : wizard.errorMessage,
|
|
6242
|
+
supportEmail
|
|
6243
|
+
});
|
|
6244
|
+
}
|
|
6245
|
+
function RegistrationPaymentStatus({ wizard }) {
|
|
6246
|
+
return wizard.paymentStatusRecovery ? /* @__PURE__ */ jsx(PaymentStatusStep, {
|
|
6247
|
+
state: wizard.paymentStatusRecovery,
|
|
6248
|
+
onCheck: wizard.handleCheckPaymentStatus,
|
|
6249
|
+
onContinuePayment: wizard.handleContinueExistingPayment,
|
|
6250
|
+
onReturnToPayment: wizard.handleReturnToPayment,
|
|
6251
|
+
onReturnToBooking: wizard.handleReturnToBooking
|
|
6252
|
+
}) : null;
|
|
6253
|
+
}
|
|
6254
|
+
function RegistrationError({ wizard }) {
|
|
6255
|
+
const admission = wizard.admission;
|
|
6256
|
+
return /* @__PURE__ */ jsx(ErrorStep, {
|
|
6257
|
+
message: wizard.errorMessage,
|
|
6258
|
+
action: wizard.errorAction,
|
|
6259
|
+
canJoinWaitlist: admission.kind === "waitlist",
|
|
6260
|
+
onRetry: wizard.handleRetry
|
|
6261
|
+
});
|
|
6262
|
+
}
|
|
5995
6263
|
//#endregion
|
|
5996
6264
|
//#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizard.tsx
|
|
5997
6265
|
const EVENT_PORTAL_AUTH_COPY = {
|
|
@@ -6039,11 +6307,12 @@ function getWizardStepLabel(input) {
|
|
|
6039
6307
|
case "select-event": return input.eventSelectionLabel;
|
|
6040
6308
|
case "select-tickets": return input.selectedEvent?.registrationSubject.kind === "wholeSeries" ? "Places" : "Tickets";
|
|
6041
6309
|
case "enter-details": return "Details";
|
|
6042
|
-
case "select-payment": return "Payment";
|
|
6310
|
+
case "select-payment": return "Payment options";
|
|
6311
|
+
case "payment": return "Payment";
|
|
6312
|
+
case "fully-booked":
|
|
6043
6313
|
case "error":
|
|
6044
6314
|
case "success":
|
|
6045
6315
|
case "submitting":
|
|
6046
|
-
case "redirecting":
|
|
6047
6316
|
case "verifying-payment":
|
|
6048
6317
|
case "verifying-timeout":
|
|
6049
6318
|
case "payment-status":
|
|
@@ -6074,7 +6343,6 @@ function EventRegistrationWizardView(viewProps) {
|
|
|
6074
6343
|
const showSpamProtection = spamProtectionEnabled ?? isSpamProtectionEnabled();
|
|
6075
6344
|
const registrationRootClassName = `event-registration ${className || ""}`;
|
|
6076
6345
|
const registrationRootRef = React.useRef(null);
|
|
6077
|
-
useEventCheckoutHandoffRestore(wizard.step === "redirecting");
|
|
6078
6346
|
const [bookingOverlayOpen, setBookingOverlayOpen] = useState(false);
|
|
6079
6347
|
const [floatingPortalRoot, setFloatingPortalRoot] = useState(null);
|
|
6080
6348
|
useEffect(() => {
|
|
@@ -6114,19 +6382,19 @@ function EventRegistrationWizardView(viewProps) {
|
|
|
6114
6382
|
})
|
|
6115
6383
|
})
|
|
6116
6384
|
});
|
|
6117
|
-
const isWizardStep = WIZARD_STEPS.includes(wizard.step);
|
|
6118
6385
|
const activeWizardSteps = useMemo(() => {
|
|
6119
6386
|
const needsPaymentStep = requiresPaymentStep({
|
|
6120
6387
|
eventRequiresPayment: wizard.eventRequiresPayment,
|
|
6121
6388
|
paymentSelection: wizard.paymentSelection
|
|
6122
6389
|
});
|
|
6123
|
-
return getWizardStepsForContext(wizard.hasPreSelectedContext, needsPaymentStep);
|
|
6390
|
+
return getWizardStepsForContext(wizard.hasPreSelectedContext, needsPaymentStep, wizard.step === "payment");
|
|
6124
6391
|
}, [
|
|
6392
|
+
wizard.step,
|
|
6125
6393
|
wizard.hasPreSelectedContext,
|
|
6126
6394
|
wizard.eventRequiresPayment,
|
|
6127
6395
|
wizard.paymentSelection
|
|
6128
6396
|
]);
|
|
6129
|
-
const totalSteps = activeWizardSteps
|
|
6397
|
+
const { isWizardStep, totalSteps } = getRegistrationStepPresentation(wizard.step, activeWizardSteps);
|
|
6130
6398
|
const summaryEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
|
|
6131
6399
|
const eventSelectionStepLabel = getEventSelectionMode(wizard.scopedEvents) === "date" ? "Date" : "Event";
|
|
6132
6400
|
const stepLabels = activeWizardSteps.map((step) => getWizardStepLabel({
|
|
@@ -6186,7 +6454,10 @@ function EventRegistrationWizardView(viewProps) {
|
|
|
6186
6454
|
ticketCurrency: bookingCurrency,
|
|
6187
6455
|
buttonVariant,
|
|
6188
6456
|
formatTicketPrice: (ticketType) => formatTicketPriceIfKnown(ticketType, bookingCurrency),
|
|
6189
|
-
onOpen: () =>
|
|
6457
|
+
onOpen: () => {
|
|
6458
|
+
if (wizard.paymentController.state.kind === "payment") wizard.paymentController.retryPaymentLoad();
|
|
6459
|
+
setBookingOverlayOpen(true);
|
|
6460
|
+
},
|
|
6190
6461
|
onClose: () => setBookingOverlayOpen(false),
|
|
6191
6462
|
overlaySurface: renderRegistrationSurface("overlay")
|
|
6192
6463
|
})]
|