@riverbankcms/sdk 0.136.0 → 0.138.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/CHANGELOG.md +109 -0
- package/README.md +7 -4
- package/dist/{PreviewEditorSidebar-BU5ZlhQR.mjs → PreviewEditorSidebar-BVPur_CU.mjs} +12 -18
- package/dist/{PreviewEditorUI-9XkHL-bC.mjs → PreviewEditorUI-DLhWX8oh.mjs} +3 -3
- package/dist/{PreviewQueryProvider-wbEpXryy.mjs → PreviewQueryProvider-BguJY1SW.mjs} +1 -1
- package/dist/{SdkPreviewModeRuntime-CnWmj-2B.mjs → SdkPreviewModeRuntime-Tda6qw4z.mjs} +1375 -495
- package/dist/{SiteChromeCustomizeContext-B6d5zkog.mjs → SiteChromeCustomizeContext-BHFgMjde.mjs} +35665 -33602
- package/dist/_dts/ai/src/contracts/proposals.d.ts +7226 -3057
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +1223 -811
- package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
- package/dist/_dts/api/src/accessAdmin.d.ts +16 -18
- package/dist/_dts/api/src/accountApi.d.ts +49 -2
- package/dist/_dts/api/src/appointmentServiceContracts.d.ts +83 -0
- package/dist/_dts/api/src/appointmentServiceLocation.d.ts +12 -0
- package/dist/_dts/api/src/appointmentServiceVisibility.d.ts +14 -0
- package/dist/_dts/api/src/appointmentSetup.d.ts +8 -0
- package/dist/_dts/api/src/bookingConfig.d.ts +35 -87
- package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +1 -1
- package/dist/_dts/api/src/bookingOperations.d.ts +2 -69
- package/dist/_dts/api/src/bookingRecords.d.ts +2 -2
- package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +2 -2
- package/dist/_dts/api/src/bookingServicePricing.d.ts +47 -0
- package/dist/_dts/api/src/bookings.d.ts +2 -2
- package/dist/_dts/api/src/cache-tags.d.ts +7 -2
- package/dist/_dts/api/src/common/index.d.ts +1 -0
- package/dist/_dts/api/src/common/zodFieldErrors.d.ts +34 -0
- package/dist/_dts/api/src/communications.d.ts +14 -8
- package/dist/_dts/api/src/contentRuntime.d.ts +3 -6
- package/dist/_dts/api/src/domainConnection.d.ts +41 -0
- package/dist/_dts/api/src/endpoints.d.ts +1636 -1637
- package/dist/_dts/api/src/eventAttendanceLabels.d.ts +2 -2
- package/dist/_dts/api/src/eventManagementContracts.d.ts +10 -14
- package/dist/_dts/api/src/index.d.ts +11 -9
- package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
- package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
- package/dist/_dts/api/src/media.d.ts +19 -2
- package/dist/_dts/api/src/occurrenceScheduling.d.ts +1 -1
- package/dist/_dts/api/src/participantMessaging.d.ts +3 -3
- package/dist/_dts/api/src/public/endpoints.d.ts +1 -1
- package/dist/_dts/api/src/publicBookingAvailabilityEndpointDefinitions.d.ts +62 -0
- package/dist/_dts/api/src/publicBookingService.d.ts +109 -2
- package/dist/_dts/api/src/publicEventCheckoutEndpointDefinitions.d.ts +27 -0
- package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
- package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +2 -1
- package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +30 -148
- package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +8 -26
- package/dist/_dts/api/src/publicExperience/siteEndpoints.d.ts +5 -13
- package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +2 -3
- package/dist/_dts/api/src/schemas/admin-allowed-domains.d.ts +76 -0
- package/dist/_dts/api/src/schemas/admin-observability-logs.d.ts +61 -0
- package/dist/_dts/api/src/schemas/admin-users.d.ts +80 -0
- package/dist/_dts/api/src/schemas/newsletter-memberships.d.ts +98 -0
- package/dist/_dts/api/src/schemas/sdk-entries.d.ts +128 -0
- package/dist/_dts/api/src/schemas/site-api-keys.d.ts +112 -0
- package/dist/_dts/api/src/schemas/support.d.ts +35 -0
- package/dist/_dts/api/src/sdk-event-booking-offer.d.ts +14 -0
- package/dist/_dts/api/src/sdk-event-payment-terms.d.ts +4 -16
- package/dist/_dts/api/src/sdk-event-upsert.d.ts +11 -21
- package/dist/_dts/api/src/sdkContracts.d.ts +8 -23
- package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +37 -0
- package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
- package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +66 -0
- package/dist/_dts/api/src/sdkThemeWire.d.ts +157 -146
- package/dist/_dts/api/src/siteInfrastructure.d.ts +37 -37
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +35 -54
- package/dist/_dts/api/src/siteOnboarding.d.ts +3 -3
- package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +38 -16
- package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
- package/dist/_dts/api/src/types.d.ts +2 -2
- package/dist/_dts/api/src/{wholeSeriesOfferings.d.ts → wholeSeriesRuns.d.ts} +11 -67
- package/dist/_dts/block-form/src/FormRenderer.d.ts +3 -1
- package/dist/_dts/block-form/src/backend/store-backend.d.ts +2 -1
- package/dist/_dts/block-form/src/backend/types.d.ts +2 -0
- package/dist/_dts/block-form/src/context/FormFocusContext.d.ts +7 -0
- package/dist/_dts/block-form/src/index.d.ts +2 -0
- package/dist/_dts/block-form/src/manifest/ManifestForm.d.ts +2 -1
- package/dist/_dts/block-form/src/utils/promotedFieldBackend.d.ts +8 -0
- package/dist/_dts/block-form/src/utils/promotedFieldPlan.d.ts +18 -0
- package/dist/_dts/block-form/src/utils/resolvePromotedFields.d.ts +8 -1
- package/dist/_dts/blocks/src/BlockErrorBoundary.d.ts +46 -0
- package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -141
- package/dist/_dts/blocks/src/contracts/index.d.ts +2 -0
- package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +12 -6
- package/dist/_dts/blocks/src/index.d.ts +1 -0
- package/dist/_dts/blocks/src/pageRenderAudience.d.ts +54 -0
- package/dist/_dts/blocks/src/pageRenderDiagnostics.d.ts +26 -0
- package/dist/_dts/blocks/src/pageRenderPlan.d.ts +116 -0
- package/dist/_dts/blocks/src/pageRenderPreparation.d.ts +109 -0
- package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +1 -0
- package/dist/_dts/blocks/src/pageRendererContracts.d.ts +154 -0
- package/dist/_dts/blocks/src/portal/types.d.ts +1 -1
- package/dist/_dts/blocks/src/server.d.ts +1 -0
- package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +12 -20
- package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/events/eventCalendarDataLoaders.d.ts +3 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +95 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/index.d.ts +1 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/runGrouping.d.ts +37 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +1046 -773
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +59 -46
- package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +3 -3
- package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +161 -161
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +13 -6
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/scheduleSummary.d.ts +10 -4
- package/dist/_dts/blocks/src/system/constants/buttonRoles.d.ts +2 -2
- package/dist/_dts/blocks/src/system/constants/events.d.ts +4 -0
- package/dist/_dts/blocks/src/system/customize/facets.d.ts +4 -4
- package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
- package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +5 -9
- package/dist/_dts/blocks/src/system/manifest/schema.d.ts +83 -83
- package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +12 -3
- package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -8
- package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +13 -0
- package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +12 -20
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +32 -37
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +15 -18
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +11 -8
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +38 -22
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +7 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-details/WholeSeriesPricingDisplay.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-details/logic.d.ts +16 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardActions.d.ts +4 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +5 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventScope.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +15 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.d.ts +14 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationSurface.d.ts +3 -21
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.d.ts +0 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.d.ts +14 -16
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +13 -15
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +9 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +25 -23
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +11 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +8 -13
- package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +11 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +24 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +1080 -560
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventProductEligibility.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +7 -7
- package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +11 -0
- package/dist/_dts/commerce/src/moneyReport.d.ts +1 -1
- package/dist/_dts/commerce/src/purchase/checkoutErrorCodes.d.ts +1 -1
- package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
- package/dist/_dts/commerce/src/purchase/eventOrderOptionSnapshot.d.ts +3 -0
- package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
- package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +6 -3
- package/dist/_dts/commerce/src/purchase/types.d.ts +3 -2
- package/dist/_dts/commerce/src/waitlists.d.ts +1 -1
- package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +4 -0
- package/dist/_dts/content-editor/src/controller/useBlockedPublishPlan.d.ts +11 -0
- package/dist/_dts/content-editor/src/hooks/applyBlockedPublishPlan.d.ts +1 -1
- package/dist/_dts/content-editor/src/hooks/blockedPublishPlan.d.ts +13 -5
- package/dist/_dts/content-editor/src/hooks/useEntryActions.d.ts +5 -1
- package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +34 -2
- package/dist/_dts/content-editor/src/index.d.ts +2 -1
- package/dist/_dts/content-editor/src/ui/blockValidationManifestRegistry.d.ts +2 -0
- package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +4 -2
- package/dist/_dts/content-editor/src/ui/stores/types.d.ts +27 -5
- package/dist/_dts/content-model/src/content-types/schema.d.ts +3 -3
- package/dist/_dts/content-model/src/templates/defaults.d.ts +11 -0
- package/dist/_dts/core/src/branded.d.ts +28 -9
- package/dist/_dts/core/src/event-booking-offer-parser.d.ts +82 -0
- package/dist/_dts/core/src/event-booking-offer.d.ts +89 -0
- package/dist/_dts/core/src/event-page-surface-subject.d.ts +81 -4
- package/dist/_dts/core/src/event-pricing.d.ts +81 -89
- package/dist/_dts/core/src/index.d.ts +3 -0
- package/dist/_dts/core/src/non-empty-array.d.ts +3 -0
- package/dist/_dts/core/src/whole-series-run-schedule.d.ts +92 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +495 -279
- package/dist/_dts/db/src/index.d.ts +1 -0
- package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
- package/dist/_dts/editor-blocks/src/BlockForm.d.ts +2 -6
- package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +1 -1
- package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +2 -2
- package/dist/_dts/editor-blocks/src/block-editor/BlockSettingsModal.d.ts +4 -2
- package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockValidationManifests.d.ts +1 -0
- package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +22 -7
- package/dist/_dts/editor-blocks/src/block-editor/useSettingsFieldFocus.d.ts +18 -0
- package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
- package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
- package/dist/_dts/preview-next/src/client/blocks/previewBatchLoaderParams.d.ts +2 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
- package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
- package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
- package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
- package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
- package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
- package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
- package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
- package/dist/_dts/sdk/src/client/{eventSubrouteReadOperations.d.ts → publicEventReadOperations.d.ts} +4 -3
- package/dist/_dts/sdk/src/client/types.d.ts +6 -10
- package/dist/_dts/sdk/src/config/types.d.ts +1 -1
- package/dist/_dts/sdk/src/config/validation.d.ts +3 -3
- package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +5 -0
- package/dist/_dts/sdk/src/data/prefetchBlockData.d.ts +2 -3
- package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +8 -8
- package/dist/_dts/sdk/src/next/tags.d.ts +5 -8
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -26
- package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +9 -1
- package/dist/_dts/sdk/src/rendering/index.d.ts +1 -0
- package/dist/_dts/sdk/src/rendering/islands/types.d.ts +6 -53
- package/dist/_dts/sdk/src/rendering/server.d.ts +1 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/accordions/types.d.ts +5 -5
- package/dist/_dts/theme-core/src/buttons/styles/recipes/flatInk.d.ts +25 -25
- package/dist/_dts/theme-core/src/buttons/styles/registry.d.ts +25 -25
- package/dist/_dts/theme-core/src/buttons/styles/selection.d.ts +7 -7
- package/dist/_dts/theme-core/src/buttons/types.d.ts +22 -22
- package/dist/_dts/theme-core/src/cards/types.d.ts +49 -49
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
- package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +26 -3
- package/dist/_dts/theme-core/src/inputs/types.d.ts +2 -2
- package/dist/_dts/theme-core/src/interactive/baseSchema.d.ts +1 -1
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +195 -195
- package/dist/_dts/theme-core/src/navigation/types.d.ts +3 -3
- package/dist/_dts/theme-core/src/palette/colors.d.ts +1 -1
- package/dist/_dts/theme-core/src/palette/curated/types.d.ts +2 -2
- package/dist/_dts/theme-core/src/schema.d.ts +258 -257
- package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
- package/dist/_dts/theme-core/src/site-styles/cardRoleVocabulary.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
- package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +10 -0
- package/dist/_dts/theme-core/src/site-styles/designState.d.ts +4 -4
- package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
- package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
- package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
- package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
- package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -9
- package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
- package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
- package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
- package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +10 -1
- package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +7 -0
- package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
- package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
- package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
- package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +1 -1
- package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +3 -3
- package/dist/_dts/ui/src/badge.d.ts +1 -1
- package/dist/_dts/ui/src/button.d.ts +2 -2
- package/dist/client/{BookingConsentAgreement-DCch21a6.mjs → BookingConsentAgreement-DQUik1Mx.mjs} +2 -2
- package/dist/client/{DiscountCodeDisclosure-DIj1T59K.mjs → DiscountCodeDisclosure-CU67Q4vH.mjs} +1 -1
- package/dist/client/{EventCombined.client-BWVNlXTx.mjs → EventCombined.client-a02TXUgg.mjs} +233 -348
- package/dist/client/{EventListing.client-DVFCDe3i.mjs → EventListing.client-99qx7jFl.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-BY5mIHw9.mjs → LeafletStaticMap-CWzcq73L.mjs} +1 -1
- package/dist/client/{accordion-CK29E8rG.mjs → accordion-D1nb3-Oj.mjs} +1 -1
- package/dist/client/{bookingForm-DFvnet-N.mjs → bookingForm-BGrmLhaO.mjs} +5 -5
- package/dist/client/bookings.mjs +10555 -10475
- package/dist/client/{carousel-BVU5NQlb.mjs → carousel-DSmOx3ad.mjs} +1 -1
- package/dist/client/{cart-BNItcZVa.mjs → cart-COWeOIUk.mjs} +3 -3
- package/dist/client/{checkout-Bu6iCdkP.mjs → checkout-CeysaIJK.mjs} +3 -3
- package/dist/client/client.mjs +58968 -57441
- package/dist/client/{context-BImarOAq.mjs → context-DBzX85Xc.mjs} +46 -18
- package/dist/client/dates-DCYhZBlW.mjs +264 -0
- package/dist/client/{eventCalendar-DS2h-UXD.mjs → eventCalendar-BgsN73Ul.mjs} +21 -44
- package/dist/client/{eventCombined-Drt4Oq9p.mjs → eventCombined-DcZQAMQP.mjs} +3 -3
- package/dist/client/{eventDetails-Bl2vWgTX.mjs → eventDetails-BWwGJ54l.mjs} +131 -51
- package/dist/client/{eventListing-CS7PHY7v.mjs → eventListing-DqYqV8vp.mjs} +3 -3
- package/dist/client/{eventRegistration-D-j8eNy2.mjs → eventRegistration-DQGDgu_e.mjs} +1122 -803
- package/dist/client/{form-RMpoLTyr.mjs → form-ClfpasVT.mjs} +2 -2
- package/dist/client/{headerSection-BYE3Lb3k.mjs → headerSection-BuOMe98N.mjs} +2 -2
- package/dist/client/hooks.mjs +9630 -9526
- package/dist/client/{locationMap-BxSr7Kkh.mjs → locationMap-CEqu_sfa.mjs} +2 -2
- package/dist/client/{newsletterForm-DerbXwFC.mjs → newsletterForm-IbrHjMxy.mjs} +2 -2
- package/dist/client/pricing-xj7MPZlK.mjs +314 -0
- package/dist/client/{productDetail-4SZCLhAf.mjs → productDetail-vxqTt5Xj.mjs} +3 -3
- package/dist/client/{productList-D7AP4GNq.mjs → productList-OTdZu8sb.mjs} +3 -3
- package/dist/client/{propsDecoder-pzBeCh14.mjs → propsDecoder-CY9gGEF7.mjs} +786 -1194
- package/dist/client/rendering/client.mjs +11481 -10469
- package/dist/client/rendering/islands.mjs +17 -17
- package/dist/client/rendering.mjs +26871 -25232
- package/dist/client/{scrollToBlock-CduAKf8T.mjs → scrollToBlock--BFV6kl-.mjs} +1 -1
- package/dist/client/{shop-Cp5p_kGe.mjs → shop-CP4YbDL9.mjs} +6 -6
- package/dist/client/{shop-commerce-DicXYaYX.mjs → shop-commerce-APs4XBXE.mjs} +5 -5
- package/dist/client/{shop-commerce-store-CGWnpY4K.mjs → shop-commerce-store-CAVLxLFr.mjs} +1 -1
- package/dist/client/{shopShared-BDf9ljkm.mjs → shopShared-BnSRrwXI.mjs} +3 -3
- package/dist/client/{useEventFilters-DeeyGYuk.mjs → useEventFilters-1a1by4c8.mjs} +33 -18
- package/dist/preview-next/before-render.mjs +186 -148
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/keepAlive.mjs +186 -148
- package/dist/preview-next/middleware.mjs +186 -148
- package/dist/{previewAuthStore-DbqBol0V.mjs → previewAuthStore-BkEgnYPP.mjs} +186 -148
- package/dist/{sdk-runtime-19MO27F0.mjs → sdk-runtime-DwGfsT0S.mjs} +2 -2
- package/dist/{separator-DaPLtJ1f.mjs → separator-BeqDLneQ.mjs} +1 -1
- package/dist/server/components.mjs +53243 -51879
- package/dist/server/config-validation.mjs +1015 -906
- package/dist/server/config.mjs +1019 -910
- package/dist/server/data.mjs +10304 -10200
- package/dist/server/index.mjs +217 -198
- package/dist/server/next/tags.mjs +18 -4
- package/dist/server/next.mjs +62787 -61617
- package/dist/server/page-converter.mjs +797 -917
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +52557 -51365
- package/dist/server/rendering.mjs +54373 -53054
- package/dist/server/routing.mjs +13274 -13142
- package/dist/server/server.mjs +1076 -1154
- package/dist/server/theme-bridge.mjs +69 -9
- package/dist/server/theme.mjs +27 -8
- package/dist/styles/index.css +32 -1
- package/package.json +1 -1
- package/dist/_dts/api/src/publicExperience/wholeSeriesEndpoints.d.ts +0 -65
- package/dist/_dts/api/src/publicWholeSeriesEndpointDefinitions.d.ts +0 -20
- package/dist/_dts/api/src/sdk-event-pricing.d.ts +0 -61
- package/dist/_dts/blocks/src/system/blocks/events/whole-series/index.d.ts +0 -3
- package/dist/_dts/blocks/src/system/blocks/events/whole-series/pricing.d.ts +0 -50
- package/dist/_dts/blocks/src/system/blocks/events/whole-series/schemas.d.ts +0 -135
- package/dist/_dts/blocks/src/system/blocks/events/whole-series/types.d.ts +0 -87
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
- package/dist/_dts/sdk/src/client/wholeSeriesReadOperations.d.ts +0 -11
- package/dist/_dts/sdk/src/public-api/wholeSeriesContracts.d.ts +0 -2
- /package/dist/_dts/blocks/src/system/runtime/nodes/events/{shared → domain}/destination.d.ts +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator$1, o as resolveBookingPaymentDueNowCents, r as SpinnerNode, s as formatPrice, t as BookingConsentAgreement } from "./BookingConsentAgreement-
|
|
3
|
-
import { $t as
|
|
4
|
-
import {
|
|
2
|
+
import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator$1, o as resolveBookingPaymentDueNowCents, r as SpinnerNode, s as formatPrice, t as BookingConsentAgreement } from "./BookingConsentAgreement-DQUik1Mx.mjs";
|
|
3
|
+
import { $t as toBookingTimeZone, C as WIZARD_STEPS, Gt as formatBookingDateTime, Nt as assertNever, O as resolveEventRegistrationScopedEvents, S as resolveRegistrationTarget, T as getWizardStepsForContext, Ut as formatBookingDate, _ as toWholeSeriesRegistrationEvents, an as publicEventPricingCurrency, at as groupPublicEventsByRun, b as resolveDiscountContext, cn as publicEventPricingStrategy, g as toRegistrationEvents, h as getRegistrationStartAt, ln as publicEventPricingType, qt as formatBookingTime, sn as publicEventPricingOptions, t as defineIslandPropsDecoder, tn as toScheduledBookingDateTime, un as formatCurrencyAmount, ut as themeButtonClassName, v as findEventByOccurrenceId, w as getStepNumber, x as resolveEventRequiresPayment, y as findPreSelectedEvent } from "./propsDecoder-CY9gGEF7.mjs";
|
|
4
|
+
import { a as canJoinEventWaitlistOnAnyMode, c as formatTicketTypeRemaining, f as getRemainingPlaces, h as selectMostOpenCapacitySource, i as canJoinEventWaitlist, m as selectEventCapacitySource, o as formatEventRemainingPlaces, p as isEventFull, r as formatEventPriceDisplay, s as formatRemainingPlaces, u as getEventAvailability } from "./pricing-xj7MPZlK.mjs";
|
|
5
|
+
import { n as useBlockApi, r as BlockApiError, t as BlockApiProvider } from "./context-DBzX85Xc.mjs";
|
|
5
6
|
import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
|
|
6
|
-
import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock
|
|
7
|
-
import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-
|
|
7
|
+
import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock--BFV6kl-.mjs";
|
|
8
|
+
import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-CU67Q4vH.mjs";
|
|
8
9
|
import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
|
|
9
10
|
import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
|
|
10
11
|
import { t as buildCheckoutReturnUrls } from "./checkoutUrls-BuseL0dw.mjs";
|
|
@@ -597,11 +598,11 @@ function transformRegistrationOptionsResponse(response) {
|
|
|
597
598
|
} : null,
|
|
598
599
|
eligible: response.registration.kind === "none" && registrationAvailable,
|
|
599
600
|
requiresPayment: monetaryPaymentAvailable,
|
|
600
|
-
|
|
601
|
+
pricingStrategy: response.pricing.strategy,
|
|
601
602
|
paymentTerms: response.pricing.paymentTerms,
|
|
602
|
-
|
|
603
|
+
selectedPricingOptionId: response.pricing.lines.length === 1 ? response.pricing.lines[0]?.pricingOptionId ?? null : null,
|
|
603
604
|
ticketLines: response.pricing.lines.map((line) => ({
|
|
604
|
-
|
|
605
|
+
pricingOptionId: line.pricingOptionId,
|
|
605
606
|
label: line.label,
|
|
606
607
|
description: line.description,
|
|
607
608
|
quantity: line.quantity,
|
|
@@ -609,7 +610,7 @@ function transformRegistrationOptionsResponse(response) {
|
|
|
609
610
|
subtotalCents: line.subtotalCents,
|
|
610
611
|
currency: response.pricing.currency
|
|
611
612
|
})),
|
|
612
|
-
ticketTypes:
|
|
613
|
+
ticketTypes: response.pricing.options,
|
|
613
614
|
isFull,
|
|
614
615
|
waitlistEnabled: response.availability.waitlistEnabled,
|
|
615
616
|
canJoinWaitlist,
|
|
@@ -629,39 +630,6 @@ function transformRegistrationOptionsResponse(response) {
|
|
|
629
630
|
function hasMonetaryPaymentOption(response) {
|
|
630
631
|
return response.paymentOptions.some((option) => option.kind === "payInFull" || option.kind === "deferredManual" || option.kind === "instalmentPlan" || option.kind === "flexibleBalance");
|
|
631
632
|
}
|
|
632
|
-
function projectRegistrationPricingOptions(options) {
|
|
633
|
-
return options.map((option) => ({
|
|
634
|
-
id: option.pricingOptionId,
|
|
635
|
-
name: option.label,
|
|
636
|
-
description: option.description,
|
|
637
|
-
priceAmount: option.unitPriceCents,
|
|
638
|
-
isActive: option.availability.kind === "available" || option.availability.reason !== "inactive",
|
|
639
|
-
sortOrder: option.sortOrder,
|
|
640
|
-
capacityMode: option.availability.remainingPlaces === null ? "unlimited" : "limited",
|
|
641
|
-
capacityLimit: option.capacityLimit,
|
|
642
|
-
attendanceScope: option.attendanceScope,
|
|
643
|
-
saleStartsAt: option.saleStartsAt,
|
|
644
|
-
saleEndsAt: option.saleEndsAt,
|
|
645
|
-
availability: option.availability.kind === "available" ? {
|
|
646
|
-
kind: "available",
|
|
647
|
-
remainingCapacity: option.availability.remainingPlaces
|
|
648
|
-
} : {
|
|
649
|
-
kind: "unavailable",
|
|
650
|
-
reason: toLegacyAvailabilityReason(option.availability.reason),
|
|
651
|
-
remainingCapacity: option.availability.remainingPlaces
|
|
652
|
-
}
|
|
653
|
-
}));
|
|
654
|
-
}
|
|
655
|
-
function toLegacyAvailabilityReason(reason) {
|
|
656
|
-
switch (reason) {
|
|
657
|
-
case "inactive": return "inactive";
|
|
658
|
-
case "notOnSaleYet": return "not_on_sale_yet";
|
|
659
|
-
case "saleEnded": return "sale_ended";
|
|
660
|
-
case "soldOut":
|
|
661
|
-
case "attendanceModeUnavailable": return "sold_out";
|
|
662
|
-
case "overallCapacityUnavailable": return "event_sold_out";
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
633
|
function getTicketTypeAvailabilityLabel(ticketType) {
|
|
666
634
|
const availability = ticketType.availability;
|
|
667
635
|
if (availability.kind === "available") return null;
|
|
@@ -670,24 +638,28 @@ function getTicketTypeAvailabilityLabel(ticketType) {
|
|
|
670
638
|
case "not_on_sale_yet": return "Not on sale yet";
|
|
671
639
|
case "sale_ended": return "Sales ended";
|
|
672
640
|
case "sold_out":
|
|
673
|
-
case "
|
|
641
|
+
case "attendance_mode_unavailable":
|
|
642
|
+
case "overallCapacityUnavailable": return "Sold out";
|
|
643
|
+
default: return "Unavailable";
|
|
674
644
|
}
|
|
675
645
|
}
|
|
676
646
|
function getVisibleTicketTypes(input) {
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
647
|
+
const eventTicketTypes = input.event ? publicEventPricingOptions(input.event.pricing).map(({ id, ...option }) => ({
|
|
648
|
+
...option,
|
|
649
|
+
pricingOptionId: id
|
|
650
|
+
})) : [];
|
|
651
|
+
return (input.eligibility?.ticketTypes ?? eventTicketTypes).filter((ticketType) => ticketType.isActive && (!input.selectedAttendanceMode || (ticketType.attendanceScope ?? "both") === "both" || (ticketType.attendanceScope ?? "both") === input.selectedAttendanceMode));
|
|
680
652
|
}
|
|
681
653
|
function getImplicitSingleAvailableTicketType(ticketTypes) {
|
|
682
654
|
return ticketTypes.length === 1 && ticketTypes[0]?.availability.kind === "available" ? ticketTypes[0] : null;
|
|
683
655
|
}
|
|
684
656
|
function findSelectedTicketType(input) {
|
|
685
|
-
if (!input.
|
|
657
|
+
if (!input.selectedPricingOptionId) return null;
|
|
686
658
|
return getVisibleTicketTypes({
|
|
687
659
|
event: input.event,
|
|
688
660
|
eligibility: input.eligibility,
|
|
689
661
|
selectedAttendanceMode: input.selectedAttendanceMode
|
|
690
|
-
}).find((ticketType) => ticketType.
|
|
662
|
+
}).find((ticketType) => ticketType.pricingOptionId === input.selectedPricingOptionId) ?? null;
|
|
691
663
|
}
|
|
692
664
|
//#endregion
|
|
693
665
|
//#region ../blocks/src/system/runtime/nodes/event-registration/EventSelectionStep.tsx
|
|
@@ -713,10 +685,12 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
713
685
|
className: "er-event-grid",
|
|
714
686
|
children: events.map((event) => {
|
|
715
687
|
const isSelected = selectedEvent?.selectionId === event.selectionId;
|
|
716
|
-
const
|
|
717
|
-
const
|
|
688
|
+
const remaining = getRemainingPlaces(selectMostOpenCapacitySource(event));
|
|
689
|
+
const isSoldOut = isEventFull(event);
|
|
690
|
+
const canJoinWaitlist = canJoinEventWaitlistOnAnyMode(event);
|
|
718
691
|
const isUnavailable = isSoldOut && !canJoinWaitlist;
|
|
719
|
-
const isLowCapacity =
|
|
692
|
+
const isLowCapacity = remaining.kind === "low";
|
|
693
|
+
const capacityLabel = formatEventRemainingPlaces(event, { full: "Sold out" });
|
|
720
694
|
const timeZone = event.timeZone ?? null;
|
|
721
695
|
const cardClasses = [
|
|
722
696
|
"er-event-card",
|
|
@@ -748,9 +722,9 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
748
722
|
children: " · "
|
|
749
723
|
}), event.venue.name] })]
|
|
750
724
|
})]
|
|
751
|
-
}), showCapacity &&
|
|
725
|
+
}), showCapacity && capacityLabel && /* @__PURE__ */ jsx("span", {
|
|
752
726
|
className: badgeClasses,
|
|
753
|
-
children:
|
|
727
|
+
children: capacityLabel
|
|
754
728
|
})]
|
|
755
729
|
})
|
|
756
730
|
}, event.selectionId);
|
|
@@ -759,6 +733,61 @@ const EventSelectionStep = ({ events, selectedEvent, onSelect, showVenue, showCa
|
|
|
759
733
|
});
|
|
760
734
|
};
|
|
761
735
|
//#endregion
|
|
736
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
|
|
737
|
+
function resolveRegistrationRecoveryAction(step, action) {
|
|
738
|
+
if (step === "payment-failed") return "payment-options";
|
|
739
|
+
if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
|
|
740
|
+
return action;
|
|
741
|
+
}
|
|
742
|
+
function canRecoverToWaitlist(eligibility) {
|
|
743
|
+
return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
|
|
744
|
+
}
|
|
745
|
+
function shouldRefreshAfterRegistrationError(step, action, enabled) {
|
|
746
|
+
return enabled || step === "error" && action === "places";
|
|
747
|
+
}
|
|
748
|
+
function resetRegistrationAfterExpiry(input) {
|
|
749
|
+
input.dispatchFlow({
|
|
750
|
+
type: "reset",
|
|
751
|
+
hasPreSelectedContext: input.hasPreSelectedContext
|
|
752
|
+
});
|
|
753
|
+
input.setSelectedTicketLines([]);
|
|
754
|
+
input.setSelectedSlidingAmountInput("");
|
|
755
|
+
const mode = input.preSelectedEvent?.deliveryMode;
|
|
756
|
+
input.setSelectedAttendanceMode(mode === "online" || mode === "in_person" ? mode : null);
|
|
757
|
+
input.setErrorMessage("");
|
|
758
|
+
input.setPendingRegistrationReference(null);
|
|
759
|
+
}
|
|
760
|
+
/** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
|
|
761
|
+
function recoverRegistrationError(action, handlers) {
|
|
762
|
+
switch (action) {
|
|
763
|
+
case "none": return;
|
|
764
|
+
case "portal":
|
|
765
|
+
case "payment-status":
|
|
766
|
+
window.location.assign("/portal");
|
|
767
|
+
return;
|
|
768
|
+
case "event":
|
|
769
|
+
window.location.assign(window.location.pathname);
|
|
770
|
+
return;
|
|
771
|
+
case "retry":
|
|
772
|
+
window.location.reload();
|
|
773
|
+
return;
|
|
774
|
+
case "details":
|
|
775
|
+
handlers.clearError();
|
|
776
|
+
handlers.setStep("enter-details");
|
|
777
|
+
return;
|
|
778
|
+
case "payment-options":
|
|
779
|
+
case "places":
|
|
780
|
+
handlers.refreshOptions();
|
|
781
|
+
handlers.clearError();
|
|
782
|
+
handlers.setStep(action === "places" ? handlers.canJoinWaitlist ? "enter-details" : "select-tickets" : "select-payment");
|
|
783
|
+
return;
|
|
784
|
+
case "start":
|
|
785
|
+
handlers.refreshOptions();
|
|
786
|
+
handlers.reset();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
//#endregion
|
|
762
791
|
//#region ../blocks/src/system/runtime/nodes/event-registration/validation.ts
|
|
763
792
|
function createInitialRegistrationFormData() {
|
|
764
793
|
return {
|
|
@@ -784,30 +813,36 @@ function normalizeTicketSelectionLines(lines) {
|
|
|
784
813
|
for (const line of lines) {
|
|
785
814
|
const quantity = Math.floor(line.quantity);
|
|
786
815
|
if (quantity <= 0) continue;
|
|
787
|
-
const key = line.
|
|
816
|
+
const key = line.pricingOptionId ?? null;
|
|
788
817
|
quantitiesByTicketType.set(key, (quantitiesByTicketType.get(key) ?? 0) + quantity);
|
|
789
818
|
}
|
|
790
|
-
return [...quantitiesByTicketType.entries()].map(([
|
|
791
|
-
|
|
819
|
+
return [...quantitiesByTicketType.entries()].map(([pricingOptionId, quantity]) => ({
|
|
820
|
+
pricingOptionId,
|
|
792
821
|
quantity
|
|
793
822
|
}));
|
|
794
823
|
}
|
|
795
824
|
function getTicketSelectionTotal(lines) {
|
|
796
825
|
return normalizeTicketSelectionLines(lines).reduce((total, line) => total + line.quantity, 0);
|
|
797
826
|
}
|
|
798
|
-
function getTicketLineQuantity(lines,
|
|
799
|
-
return normalizeTicketSelectionLines(lines).find((line) => line.
|
|
827
|
+
function getTicketLineQuantity(lines, pricingOptionId) {
|
|
828
|
+
return normalizeTicketSelectionLines(lines).find((line) => line.pricingOptionId === pricingOptionId)?.quantity ?? 0;
|
|
800
829
|
}
|
|
801
|
-
function
|
|
830
|
+
function getSingleSelectedPricingOptionId(lines) {
|
|
802
831
|
const normalized = normalizeTicketSelectionLines(lines);
|
|
803
|
-
return normalized.length === 1 ? normalized[0]?.
|
|
832
|
+
return normalized.length === 1 ? normalized[0]?.pricingOptionId ?? null : null;
|
|
833
|
+
}
|
|
834
|
+
function hasValidPricingOptionSelection(input) {
|
|
835
|
+
if (!input.selectionRequired) return true;
|
|
836
|
+
if (input.lines.length === 0) return false;
|
|
837
|
+
const availableOptionIds = new Set(input.visibleOptions.filter((option) => option.availability.kind === "available").map((option) => option.pricingOptionId));
|
|
838
|
+
return input.lines.every((line) => line.pricingOptionId !== null && availableOptionIds.has(line.pricingOptionId));
|
|
804
839
|
}
|
|
805
840
|
function setTicketLineQuantity(input) {
|
|
806
841
|
const nextQuantity = Math.max(0, Math.floor(input.quantity));
|
|
807
|
-
const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.
|
|
842
|
+
const normalized = normalizeTicketSelectionLines(input.lines).filter((line) => line.pricingOptionId !== input.pricingOptionId);
|
|
808
843
|
if (nextQuantity <= 0) return normalized;
|
|
809
844
|
return [...normalized, {
|
|
810
|
-
|
|
845
|
+
pricingOptionId: input.pricingOptionId,
|
|
811
846
|
quantity: nextQuantity
|
|
812
847
|
}];
|
|
813
848
|
}
|
|
@@ -818,25 +853,6 @@ function getTicketTypeLineMax(input) {
|
|
|
818
853
|
const maxByTicketType = input.ticketTypeRemainingCapacity ?? input.maxTickets;
|
|
819
854
|
return Math.max(0, Math.min(maxByBlock, maxByEvent, maxByTicketType));
|
|
820
855
|
}
|
|
821
|
-
function calculateTicketSelectionSubtotal(input) {
|
|
822
|
-
return normalizeTicketSelectionLines(input.lines).reduce((subtotal, line) => {
|
|
823
|
-
const unitPriceCents = (line.ticketTypeId ? input.ticketTypes.find((candidate) => candidate.id === line.ticketTypeId) ?? null : null)?.priceAmount ?? input.fallbackUnitPriceCents;
|
|
824
|
-
return subtotal + Math.max(0, unitPriceCents) * line.quantity;
|
|
825
|
-
}, 0);
|
|
826
|
-
}
|
|
827
|
-
function buildTicketSelectionSummaryLines(input) {
|
|
828
|
-
return normalizeTicketSelectionLines(input.lines).map((line) => {
|
|
829
|
-
const ticketType = line.ticketTypeId ? input.ticketTypes.find((candidate) => candidate.id === line.ticketTypeId) ?? null : null;
|
|
830
|
-
const unitPriceCents = ticketType?.priceAmount ?? input.fallbackUnitPriceCents;
|
|
831
|
-
return {
|
|
832
|
-
ticketTypeId: line.ticketTypeId,
|
|
833
|
-
label: ticketType?.name ?? input.fallbackLabel,
|
|
834
|
-
quantity: line.quantity,
|
|
835
|
-
unitPriceCents,
|
|
836
|
-
subtotalCents: Math.max(0, unitPriceCents) * line.quantity
|
|
837
|
-
};
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
856
|
//#endregion
|
|
841
857
|
//#region ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
|
|
842
858
|
const initialEligibilityLookupState = {
|
|
@@ -992,7 +1008,7 @@ function useEligibilityWithDeps(params, deps) {
|
|
|
992
1008
|
const result = await api.getRegistrationOptions({
|
|
993
1009
|
subject,
|
|
994
1010
|
selections: ticketSelections.map((selection) => ({
|
|
995
|
-
pricingOptionId: selection.
|
|
1011
|
+
pricingOptionId: selection.pricingOptionId,
|
|
996
1012
|
quantity: selection.quantity
|
|
997
1013
|
})),
|
|
998
1014
|
selectedSlidingAmount: params.selectedSlidingAmount ?? void 0
|
|
@@ -1002,11 +1018,11 @@ function useEligibilityWithDeps(params, deps) {
|
|
|
1002
1018
|
type: "resolved",
|
|
1003
1019
|
eligibility: transformRegistrationOptionsResponse(result)
|
|
1004
1020
|
});
|
|
1005
|
-
} catch
|
|
1021
|
+
} catch {
|
|
1006
1022
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
1007
1023
|
dispatch({
|
|
1008
1024
|
type: "failed",
|
|
1009
|
-
message:
|
|
1025
|
+
message: "We couldn’t load the booking options for this event. Please refresh this page and try again. If this keeps happening, contact the organiser for help."
|
|
1010
1026
|
});
|
|
1011
1027
|
}
|
|
1012
1028
|
}
|
|
@@ -1018,6 +1034,7 @@ function useEligibilityWithDeps(params, deps) {
|
|
|
1018
1034
|
}, [
|
|
1019
1035
|
api,
|
|
1020
1036
|
params.enabled,
|
|
1037
|
+
params.refreshKey,
|
|
1021
1038
|
params.subject?.kind,
|
|
1022
1039
|
params.subject?.kind === "occurrence" ? params.subject.occurrenceId : params.subject?.eventSeriesId,
|
|
1023
1040
|
params.attendanceMode,
|
|
@@ -1127,8 +1144,252 @@ function logoutPortal(anchorId) {
|
|
|
1127
1144
|
form.submit();
|
|
1128
1145
|
}
|
|
1129
1146
|
//#endregion
|
|
1147
|
+
//#region ../commerce/src/purchase/checkoutPaymentFlow.ts
|
|
1148
|
+
function planCheckoutPaymentFlow(options) {
|
|
1149
|
+
const amountDueCents = toNonNegativeCents(options.amountDueCents);
|
|
1150
|
+
const discountCents = toNonNegativeCents(options.discountCents);
|
|
1151
|
+
const availableCreditCents = toNonNegativeCents(options.availableCreditCents);
|
|
1152
|
+
const minimumStripeChargeCents = toNonNegativeCents(options.minimumStripeChargeCents ?? 0);
|
|
1153
|
+
if (amountDueCents <= 0) return {
|
|
1154
|
+
kind: "bypass",
|
|
1155
|
+
bypassReason: discountCents > 0 ? "discount_free" : "free",
|
|
1156
|
+
reserveCreditCents: 0
|
|
1157
|
+
};
|
|
1158
|
+
if (!options.creditCurrencyMatches || availableCreditCents <= 0) return {
|
|
1159
|
+
kind: "stripe",
|
|
1160
|
+
reserveCreditCents: toNonNegativeCents(0)
|
|
1161
|
+
};
|
|
1162
|
+
if (availableCreditCents >= amountDueCents) return {
|
|
1163
|
+
kind: "store_credit_only",
|
|
1164
|
+
reserveCreditCents: amountDueCents
|
|
1165
|
+
};
|
|
1166
|
+
return {
|
|
1167
|
+
kind: "stripe",
|
|
1168
|
+
reserveCreditCents: planMixedPaymentCreditReservation({
|
|
1169
|
+
amountDueCents,
|
|
1170
|
+
availableCreditCents,
|
|
1171
|
+
minimumStripeChargeCents
|
|
1172
|
+
})
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
function planMixedPaymentCreditReservation(input) {
|
|
1176
|
+
const chargeAfterFullCredit = input.amountDueCents - input.availableCreditCents;
|
|
1177
|
+
if (input.minimumStripeChargeCents <= 0 || chargeAfterFullCredit <= 0 || chargeAfterFullCredit >= input.minimumStripeChargeCents) return input.availableCreditCents;
|
|
1178
|
+
if (input.amountDueCents < input.minimumStripeChargeCents) return toNonNegativeCents(0);
|
|
1179
|
+
return toNonNegativeCents(input.amountDueCents - input.minimumStripeChargeCents);
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Apply site credit to a flexible-balance booking before card payment.
|
|
1183
|
+
*
|
|
1184
|
+
* Credit first reduces the configured payment due now. Once that payment is
|
|
1185
|
+
* covered, any remaining credit reduces the later balance. If a partial credit
|
|
1186
|
+
* application would leave a positive card charge below Stripe's minimum, less
|
|
1187
|
+
* credit is used so the configured payment can still be collected.
|
|
1188
|
+
*/
|
|
1189
|
+
function planFlexibleBalanceCreditFirst(input) {
|
|
1190
|
+
const totalCents = toNonNegativeCents(input.totalAfterDiscountCents);
|
|
1191
|
+
const configuredDueNowCents = toNonNegativeCents(Math.min(input.configuredPaymentDueNowCents, totalCents));
|
|
1192
|
+
const availableCreditCents = toNonNegativeCents(input.creditCurrencyMatches ? input.availableCreditCents : 0);
|
|
1193
|
+
const minimumStripeChargeCents = toNonNegativeCents(input.minimumStripeChargeCents ?? 0);
|
|
1194
|
+
if (availableCreditCents >= totalCents && totalCents > 0) return {
|
|
1195
|
+
kind: "credit_only",
|
|
1196
|
+
reserveCreditCents: totalCents,
|
|
1197
|
+
cardDueNowCents: toNonNegativeCents(0),
|
|
1198
|
+
laterBalanceCents: toNonNegativeCents(0)
|
|
1199
|
+
};
|
|
1200
|
+
let reserveCreditCents = toNonNegativeCents(Math.min(availableCreditCents, totalCents));
|
|
1201
|
+
if (reserveCreditCents >= configuredDueNowCents) return {
|
|
1202
|
+
kind: "flexible_balance",
|
|
1203
|
+
reserveCreditCents,
|
|
1204
|
+
cardDueNowCents: toNonNegativeCents(0),
|
|
1205
|
+
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents)
|
|
1206
|
+
};
|
|
1207
|
+
const plannedCardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
1208
|
+
if (plannedCardDueNowCents > 0 && plannedCardDueNowCents < minimumStripeChargeCents) {
|
|
1209
|
+
if (configuredDueNowCents < minimumStripeChargeCents) return {
|
|
1210
|
+
kind: "card_below_minimum",
|
|
1211
|
+
reserveCreditCents: toNonNegativeCents(0),
|
|
1212
|
+
cardDueNowCents: configuredDueNowCents,
|
|
1213
|
+
laterBalanceCents: toNonNegativeCents(totalCents - configuredDueNowCents)
|
|
1214
|
+
};
|
|
1215
|
+
reserveCreditCents = toNonNegativeCents(configuredDueNowCents - minimumStripeChargeCents);
|
|
1216
|
+
}
|
|
1217
|
+
const cardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
1218
|
+
return {
|
|
1219
|
+
kind: "flexible_balance",
|
|
1220
|
+
reserveCreditCents,
|
|
1221
|
+
cardDueNowCents,
|
|
1222
|
+
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents - cardDueNowCents)
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
//#endregion
|
|
1226
|
+
//#region ../commerce/src/purchase/settlement.ts
|
|
1227
|
+
function normalizeCurrencyCode(raw) {
|
|
1228
|
+
const normalized = raw.trim().toUpperCase();
|
|
1229
|
+
if (!/^[A-Z]{3}$/.test(normalized)) throw new Error(`Invalid currency code: ${raw}`);
|
|
1230
|
+
return normalized;
|
|
1231
|
+
}
|
|
1232
|
+
//#endregion
|
|
1233
|
+
//#region ../commerce/src/purchase/checkoutSessionMetadata.ts
|
|
1234
|
+
const datedOfferingSharedEngineMetadataShape = {
|
|
1235
|
+
datedOfferingEngineContractVersion: z.literal("shared_v1"),
|
|
1236
|
+
datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
|
|
1237
|
+
datedOfferingCapacityHoldId: z.string().uuid(),
|
|
1238
|
+
datedOfferingCapacityHoldAuditRef: z.string().uuid(),
|
|
1239
|
+
customerId: z.string().uuid(),
|
|
1240
|
+
eventSeriesId: z.string().uuid()
|
|
1241
|
+
};
|
|
1242
|
+
z.object(datedOfferingSharedEngineMetadataShape);
|
|
1243
|
+
const orderCheckoutSessionMetadataBaseShape = {
|
|
1244
|
+
type: z.literal("order"),
|
|
1245
|
+
site_id: z.string().uuid(),
|
|
1246
|
+
order_id: z.string().uuid().optional(),
|
|
1247
|
+
customer_email: z.string().email(),
|
|
1248
|
+
customer_name: z.string().optional(),
|
|
1249
|
+
product_id: z.string().uuid().optional(),
|
|
1250
|
+
attendee_id: z.string().uuid().optional(),
|
|
1251
|
+
occurrence_id: z.string().uuid().optional(),
|
|
1252
|
+
tickets_count: z.string().optional(),
|
|
1253
|
+
notes: z.string().optional(),
|
|
1254
|
+
discount_redemption_id: z.string().uuid().optional(),
|
|
1255
|
+
discount_code_id: z.string().uuid().optional(),
|
|
1256
|
+
discount_code: z.string().optional(),
|
|
1257
|
+
discount_public_label: z.string().optional(),
|
|
1258
|
+
credit_reservation_id: z.string().uuid().optional(),
|
|
1259
|
+
credit_reserved_cents: z.string().optional(),
|
|
1260
|
+
discount_code_amount_cents: z.string().optional(),
|
|
1261
|
+
order_payment_reason: z.enum([
|
|
1262
|
+
"instalment_payoff",
|
|
1263
|
+
"flexible_balance_initial",
|
|
1264
|
+
"flexible_balance_paydown"
|
|
1265
|
+
]).optional(),
|
|
1266
|
+
order_payment_plan_id: z.string().uuid().optional(),
|
|
1267
|
+
order_flexible_balance_contract_id: z.string().uuid().optional()
|
|
1268
|
+
};
|
|
1269
|
+
const absentDatedOfferingSharedEngineMetadataShape = {
|
|
1270
|
+
datedOfferingEngineContractVersion: z.never().optional(),
|
|
1271
|
+
datedOfferingEngineRouteKind: z.never().optional(),
|
|
1272
|
+
datedOfferingCapacityHoldId: z.never().optional(),
|
|
1273
|
+
datedOfferingCapacityHoldAuditRef: z.never().optional(),
|
|
1274
|
+
customerId: z.never().optional(),
|
|
1275
|
+
eventSeriesId: z.never().optional()
|
|
1276
|
+
};
|
|
1277
|
+
const LegacyOrderCheckoutSessionMetadataSchema = z.object({
|
|
1278
|
+
...orderCheckoutSessionMetadataBaseShape,
|
|
1279
|
+
...absentDatedOfferingSharedEngineMetadataShape
|
|
1280
|
+
});
|
|
1281
|
+
const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
|
|
1282
|
+
...orderCheckoutSessionMetadataBaseShape,
|
|
1283
|
+
...datedOfferingSharedEngineMetadataShape
|
|
1284
|
+
});
|
|
1285
|
+
z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
|
|
1286
|
+
toNonNegativeCents(0);
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region ../commerce/src/purchase/stripeMinimumCharge.ts
|
|
1289
|
+
const STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY = {
|
|
1290
|
+
GBP: 30,
|
|
1291
|
+
USD: 50,
|
|
1292
|
+
EUR: 50,
|
|
1293
|
+
AED: 200,
|
|
1294
|
+
AUD: 50,
|
|
1295
|
+
BGN: 100,
|
|
1296
|
+
BRL: 50,
|
|
1297
|
+
CAD: 50,
|
|
1298
|
+
CHF: 50,
|
|
1299
|
+
CZK: 1500,
|
|
1300
|
+
DKK: 250,
|
|
1301
|
+
HKD: 400,
|
|
1302
|
+
HUF: 17500,
|
|
1303
|
+
JPY: 50,
|
|
1304
|
+
MXN: 1e3,
|
|
1305
|
+
MYR: 200,
|
|
1306
|
+
NOK: 300,
|
|
1307
|
+
NZD: 50,
|
|
1308
|
+
PLN: 200,
|
|
1309
|
+
RON: 200,
|
|
1310
|
+
SEK: 300,
|
|
1311
|
+
SGD: 50,
|
|
1312
|
+
THB: 1e3
|
|
1313
|
+
};
|
|
1314
|
+
function isStripeMinimumChargeCurrency(currency) {
|
|
1315
|
+
return currency in STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY;
|
|
1316
|
+
}
|
|
1317
|
+
function getStripeMinimumChargeRequirement(rawCurrency) {
|
|
1318
|
+
let currency;
|
|
1319
|
+
try {
|
|
1320
|
+
currency = normalizeCurrencyCode(rawCurrency);
|
|
1321
|
+
} catch {
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
const currencyKey = currency;
|
|
1325
|
+
if (!isStripeMinimumChargeCurrency(currencyKey)) return null;
|
|
1326
|
+
return {
|
|
1327
|
+
currency,
|
|
1328
|
+
minimumAmountCents: STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY[currencyKey]
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
//#endregion
|
|
1332
|
+
//#region ../commerce/src/purchase/event-registration-errors.ts
|
|
1333
|
+
const eventRegistrationErrors = {
|
|
1334
|
+
registrationClosed: {
|
|
1335
|
+
message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
|
|
1336
|
+
action: "none"
|
|
1337
|
+
},
|
|
1338
|
+
paymentUncertain: {
|
|
1339
|
+
message: "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.",
|
|
1340
|
+
action: "payment-status"
|
|
1341
|
+
},
|
|
1342
|
+
paymentPageUnavailable: {
|
|
1343
|
+
message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
|
|
1344
|
+
action: "retry"
|
|
1345
|
+
},
|
|
1346
|
+
paymentUnavailable: {
|
|
1347
|
+
message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
|
|
1348
|
+
action: "none"
|
|
1349
|
+
},
|
|
1350
|
+
capacityChanged: {
|
|
1351
|
+
message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
|
|
1352
|
+
action: "places"
|
|
1353
|
+
},
|
|
1354
|
+
selectionChanged: {
|
|
1355
|
+
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
1356
|
+
action: "places"
|
|
1357
|
+
},
|
|
1358
|
+
registrationPreparationChanged: {
|
|
1359
|
+
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
1360
|
+
action: "places"
|
|
1361
|
+
},
|
|
1362
|
+
registrationAlreadyExists: {
|
|
1363
|
+
message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
|
|
1364
|
+
action: "portal"
|
|
1365
|
+
},
|
|
1366
|
+
holdExpired: {
|
|
1367
|
+
message: "Your reservation has timed out. Please check availability and choose your places again.",
|
|
1368
|
+
action: "start"
|
|
1369
|
+
},
|
|
1370
|
+
waitlistUnavailable: {
|
|
1371
|
+
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.",
|
|
1372
|
+
action: "event"
|
|
1373
|
+
},
|
|
1374
|
+
paymentContextMismatch: {
|
|
1375
|
+
message: "The payment options for this event have changed. Please check the latest options before continuing.",
|
|
1376
|
+
action: "payment-options"
|
|
1377
|
+
},
|
|
1378
|
+
idempotencyConflict: {
|
|
1379
|
+
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.",
|
|
1380
|
+
action: "portal"
|
|
1381
|
+
},
|
|
1382
|
+
invalidCommitInput: {
|
|
1383
|
+
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.",
|
|
1384
|
+
action: "details"
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
function parseEventRegistrationErrorReason(value) {
|
|
1388
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
|
|
1389
|
+
}
|
|
1390
|
+
//#endregion
|
|
1130
1391
|
//#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
|
|
1131
|
-
const DEFAULT_WAITLIST_CLAIM_ERROR = "
|
|
1392
|
+
const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
|
|
1132
1393
|
function createInitialWaitlistClaimState(hasToken) {
|
|
1133
1394
|
return hasToken ? { kind: "resolving" } : { kind: "idle" };
|
|
1134
1395
|
}
|
|
@@ -1144,14 +1405,13 @@ function waitlistClaimReducer(_state, action) {
|
|
|
1144
1405
|
}
|
|
1145
1406
|
}
|
|
1146
1407
|
function toWaitlistClaimResolveFailure(error) {
|
|
1147
|
-
const message = error instanceof Error ? error.message : DEFAULT_WAITLIST_CLAIM_ERROR;
|
|
1148
1408
|
if (isUnauthorizedBlockApiError(error)) return {
|
|
1149
1409
|
kind: "portal-login-required",
|
|
1150
|
-
message
|
|
1410
|
+
message: "Please log in to continue with your waiting list invitation."
|
|
1151
1411
|
};
|
|
1152
1412
|
return {
|
|
1153
1413
|
kind: "error",
|
|
1154
|
-
message
|
|
1414
|
+
message: hasStatus(error) && (error.status === 404 || error.status === 409 || error.status === 410) ? eventRegistrationErrors.waitlistUnavailable.message : DEFAULT_WAITLIST_CLAIM_ERROR
|
|
1155
1415
|
};
|
|
1156
1416
|
}
|
|
1157
1417
|
function isUnauthorizedBlockApiError(error) {
|
|
@@ -1512,11 +1772,21 @@ function cleanupStaleRegistrations() {
|
|
|
1512
1772
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
|
|
1513
1773
|
const eventRegistrationStripeReturnDeps = {
|
|
1514
1774
|
usePaymentVerification,
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1775
|
+
readReturnParams: () => {
|
|
1776
|
+
const params = new URLSearchParams(window.location.search);
|
|
1777
|
+
return {
|
|
1778
|
+
registration: params.get("registration"),
|
|
1779
|
+
registration_attempt: params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM),
|
|
1780
|
+
session_id: params.get("session_id")
|
|
1781
|
+
};
|
|
1782
|
+
},
|
|
1783
|
+
clearReturnParams: () => {
|
|
1784
|
+
consumeSearchParams([
|
|
1785
|
+
"registration",
|
|
1786
|
+
EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
|
|
1787
|
+
"session_id"
|
|
1788
|
+
]);
|
|
1789
|
+
},
|
|
1520
1790
|
scrollToBlock,
|
|
1521
1791
|
cleanupStaleRegistrations,
|
|
1522
1792
|
clearPendingRegistration,
|
|
@@ -1537,52 +1807,66 @@ function showReturnReconciliation(options, message) {
|
|
|
1537
1807
|
options.setErrorMessage(message);
|
|
1538
1808
|
options.setStep("verifying-timeout");
|
|
1539
1809
|
}
|
|
1810
|
+
function checkoutReturnCommand(params) {
|
|
1811
|
+
const checkoutAttemptId = params.registration_attempt;
|
|
1812
|
+
if (!checkoutAttemptId) return null;
|
|
1813
|
+
if (params.registration === "cancelled") return {
|
|
1814
|
+
kind: "abandon",
|
|
1815
|
+
checkoutAttemptId
|
|
1816
|
+
};
|
|
1817
|
+
if (params.registration === "success" && params.session_id) return {
|
|
1818
|
+
kind: "resolveSuccess",
|
|
1819
|
+
checkoutAttemptId,
|
|
1820
|
+
sessionId: params.session_id
|
|
1821
|
+
};
|
|
1822
|
+
return null;
|
|
1823
|
+
}
|
|
1540
1824
|
async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
|
|
1541
1825
|
deps.cleanupStaleRegistrations();
|
|
1542
|
-
const params = deps.
|
|
1543
|
-
if (params.registration !== "cancelled" && params.registration !== "success") return;
|
|
1826
|
+
const params = deps.readReturnParams();
|
|
1827
|
+
if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
|
|
1544
1828
|
deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
|
|
1545
1829
|
const siteId = options.api.config.siteId;
|
|
1546
|
-
const
|
|
1547
|
-
if (!siteId) return;
|
|
1548
|
-
if (!
|
|
1549
|
-
showReturnReconciliation(options, "We
|
|
1550
|
-
return;
|
|
1830
|
+
const command = checkoutReturnCommand(params);
|
|
1831
|
+
if (!siteId) return "settled";
|
|
1832
|
+
if (!command) {
|
|
1833
|
+
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.");
|
|
1834
|
+
return "settled";
|
|
1551
1835
|
}
|
|
1836
|
+
const { checkoutAttemptId } = command;
|
|
1552
1837
|
const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
|
|
1553
1838
|
checkoutAttemptIdRef.current = checkoutAttemptId;
|
|
1554
1839
|
if (pending) restorePendingPresentation(options, pending);
|
|
1840
|
+
options.setStep("verifying-payment");
|
|
1555
1841
|
try {
|
|
1556
|
-
const outcome =
|
|
1557
|
-
kind: "resolveSuccess",
|
|
1558
|
-
checkoutAttemptId,
|
|
1559
|
-
sessionId: params.session_id
|
|
1560
|
-
}) : { kind: "notFound" } : await options.api.resolveEventCheckoutReturn({
|
|
1561
|
-
kind: "abandon",
|
|
1562
|
-
checkoutAttemptId
|
|
1563
|
-
});
|
|
1842
|
+
const outcome = await options.api.resolveEventCheckoutReturn(command);
|
|
1564
1843
|
switch (outcome.kind) {
|
|
1565
1844
|
case "resolved":
|
|
1845
|
+
deps.clearReturnParams();
|
|
1566
1846
|
options.setPendingRegistrationReference(outcome.reference);
|
|
1567
1847
|
options.setStep("verifying-payment");
|
|
1568
|
-
return;
|
|
1848
|
+
return "settled";
|
|
1569
1849
|
case "abandoned":
|
|
1850
|
+
deps.clearReturnParams();
|
|
1570
1851
|
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
1571
1852
|
options.setStep("select-payment");
|
|
1572
|
-
return;
|
|
1853
|
+
return "settled";
|
|
1573
1854
|
case "notFound":
|
|
1574
1855
|
if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
|
|
1856
|
+
deps.clearReturnParams();
|
|
1575
1857
|
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
1576
1858
|
options.setStep("select-payment");
|
|
1577
|
-
return;
|
|
1859
|
+
return "settled";
|
|
1578
1860
|
}
|
|
1579
|
-
|
|
1861
|
+
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.");
|
|
1862
|
+
return "settled";
|
|
1580
1863
|
case "reconciliationRequired": break;
|
|
1581
1864
|
}
|
|
1582
|
-
showReturnReconciliation(options, "We’re checking your payment. Please
|
|
1865
|
+
showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
|
|
1583
1866
|
} catch {
|
|
1584
|
-
showReturnReconciliation(options, "We
|
|
1867
|
+
showReturnReconciliation(options, "We couldn’t check your payment just now. Please check again in a moment. Don’t make another booking while we’re checking.");
|
|
1585
1868
|
}
|
|
1869
|
+
return "retryable";
|
|
1586
1870
|
}
|
|
1587
1871
|
function useEventRegistrationStripeReturn(options) {
|
|
1588
1872
|
return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
|
|
@@ -1590,10 +1874,34 @@ function useEventRegistrationStripeReturn(options) {
|
|
|
1590
1874
|
function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
1591
1875
|
const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
|
|
1592
1876
|
const checkoutAttemptIdRef = useRef(null);
|
|
1877
|
+
const lookupInFlightRef = useRef(false);
|
|
1878
|
+
const [lookupState, setLookupState] = useState("settled");
|
|
1879
|
+
const resolveReturn = useCallback(async () => {
|
|
1880
|
+
if (lookupInFlightRef.current) return;
|
|
1881
|
+
lookupInFlightRef.current = true;
|
|
1882
|
+
setLookupState("loading");
|
|
1883
|
+
try {
|
|
1884
|
+
setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
|
|
1885
|
+
} finally {
|
|
1886
|
+
lookupInFlightRef.current = false;
|
|
1887
|
+
}
|
|
1888
|
+
}, [options, deps]);
|
|
1593
1889
|
const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
|
|
1594
1890
|
const verification = deps.usePaymentVerification(verificationConfig);
|
|
1891
|
+
const hasVerificationTimeout = step === "verifying-timeout" && pendingRegistrationReference !== null;
|
|
1892
|
+
const retry = useCallback(() => {
|
|
1893
|
+
if (hasVerificationTimeout) {
|
|
1894
|
+
setStep("verifying-payment");
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
verification.retry();
|
|
1898
|
+
}, [
|
|
1899
|
+
hasVerificationTimeout,
|
|
1900
|
+
setStep,
|
|
1901
|
+
verification.retry
|
|
1902
|
+
]);
|
|
1595
1903
|
useEffect(() => {
|
|
1596
|
-
|
|
1904
|
+
resolveReturn();
|
|
1597
1905
|
}, []);
|
|
1598
1906
|
useEffect(() => {
|
|
1599
1907
|
if (verification.status === "completed") {
|
|
@@ -1603,7 +1911,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
|
1603
1911
|
setRegistrationResult({ status: "confirmed" });
|
|
1604
1912
|
setStep("success");
|
|
1605
1913
|
} else if (verification.status === "failed") {
|
|
1606
|
-
setErrorMessage(
|
|
1914
|
+
setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
|
|
1607
1915
|
setStep("payment-failed");
|
|
1608
1916
|
} else if (verification.status === "timeout") setStep("verifying-timeout");
|
|
1609
1917
|
}, [
|
|
@@ -1616,11 +1924,26 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
|
1616
1924
|
setRegistrationResult,
|
|
1617
1925
|
setStep
|
|
1618
1926
|
]);
|
|
1619
|
-
return
|
|
1927
|
+
return {
|
|
1928
|
+
...verification,
|
|
1929
|
+
status: hasVerificationTimeout ? "timeout" : verification.status,
|
|
1930
|
+
retry,
|
|
1931
|
+
retryReturn: lookupState === "retryable" ? () => {
|
|
1932
|
+
resolveReturn();
|
|
1933
|
+
} : void 0
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
//#endregion
|
|
1937
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.ts
|
|
1938
|
+
function registrationErrorPresentation(error) {
|
|
1939
|
+
const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
|
|
1940
|
+
if (reason) return eventRegistrationErrors[reason];
|
|
1941
|
+
if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
|
|
1942
|
+
return eventRegistrationErrors.paymentUncertain;
|
|
1620
1943
|
}
|
|
1621
1944
|
//#endregion
|
|
1622
1945
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
|
|
1623
|
-
function
|
|
1946
|
+
function createClientCommandId(cryptoSource = {
|
|
1624
1947
|
randomUUID: globalThis.crypto.randomUUID?.bind(globalThis.crypto),
|
|
1625
1948
|
getRandomValues: (bytes) => globalThis.crypto.getRandomValues(bytes)
|
|
1626
1949
|
}) {
|
|
@@ -1633,7 +1956,7 @@ function createCheckoutAttemptId(cryptoSource = {
|
|
|
1633
1956
|
}
|
|
1634
1957
|
const eventRegistrationSubmitDeps = {
|
|
1635
1958
|
savePendingRegistration,
|
|
1636
|
-
|
|
1959
|
+
createClientCommandId
|
|
1637
1960
|
};
|
|
1638
1961
|
function useEventRegistrationSubmit(options) {
|
|
1639
1962
|
return useEventRegistrationSubmitWithDeps(options, eventRegistrationSubmitDeps);
|
|
@@ -1666,6 +1989,23 @@ function toRegistrationResult(result) {
|
|
|
1666
1989
|
};
|
|
1667
1990
|
}
|
|
1668
1991
|
function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
1992
|
+
/**
|
|
1993
|
+
* The command identity for the submission currently in progress.
|
|
1994
|
+
*
|
|
1995
|
+
* Held across attempts rather than minted per click, so a customer who
|
|
1996
|
+
* re-submits after a timeout replays their first attempt instead of asking
|
|
1997
|
+
* for a second booking. It is released only once an attempt has actually
|
|
1998
|
+
* landed — a success, or a hand-off to checkout — because until then nobody
|
|
1999
|
+
* knows whether the first one committed.
|
|
2000
|
+
*
|
|
2001
|
+
* Reusing it after a failure is safe even if the customer edits their
|
|
2002
|
+
* details. The server consults the command record before it re-checks
|
|
2003
|
+
* anything, so a submission that already booked is answered with the booking
|
|
2004
|
+
* that exists — not refused for spending a credit or a claim that this very
|
|
2005
|
+
* command already spent, and not treated as a second booking because a name
|
|
2006
|
+
* or a note changed in between.
|
|
2007
|
+
*/
|
|
2008
|
+
const commandIdRef = useRef(null);
|
|
1669
2009
|
return async (method, passId, membershipId, selection, submitOptions) => {
|
|
1670
2010
|
const target = options.registrationTarget;
|
|
1671
2011
|
if (!target) return {
|
|
@@ -1674,15 +2014,21 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
1674
2014
|
message: "Select an event to continue."
|
|
1675
2015
|
};
|
|
1676
2016
|
options.setStep("submitting");
|
|
2017
|
+
const registrationCommandId = commandIdRef.current ?? deps.createClientCommandId();
|
|
2018
|
+
commandIdRef.current = registrationCommandId;
|
|
1677
2019
|
try {
|
|
1678
|
-
const prepared = prepareSubmitContext(options, target, method, passId, membershipId, selection);
|
|
1679
|
-
if (prepared.subject.kind === "wholeSeries" && method === "stripe")
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
2020
|
+
const prepared = prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection);
|
|
2021
|
+
if (prepared.subject.kind === "wholeSeries" && method === "stripe") {
|
|
2022
|
+
commandIdRef.current = null;
|
|
2023
|
+
return await submitWholeSeriesCheckout(options, deps, {
|
|
2024
|
+
...prepared,
|
|
2025
|
+
subject: prepared.subject
|
|
2026
|
+
}, submitOptions);
|
|
2027
|
+
}
|
|
1683
2028
|
const result = await options.api.registerForEvent({
|
|
2029
|
+
registrationCommandId: prepared.registrationCommandId,
|
|
1684
2030
|
subject: prepared.subject,
|
|
1685
|
-
ticketSelections: prepared.ticketSelections,
|
|
2031
|
+
ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
|
|
1686
2032
|
selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
|
|
1687
2033
|
email: options.formData.email.trim().toLowerCase(),
|
|
1688
2034
|
name: options.formData.name.trim(),
|
|
@@ -1697,6 +2043,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
1697
2043
|
claimToken: options.claimToken ?? void 0,
|
|
1698
2044
|
guests: prepared.guestsPayload
|
|
1699
2045
|
});
|
|
2046
|
+
commandIdRef.current = null;
|
|
1700
2047
|
if (needsOccurrenceCheckout(result, method)) return await submitOccurrenceCheckout(options, deps, prepared, result, method, submitOptions);
|
|
1701
2048
|
options.setRegistrationResult(toRegistrationResult(result));
|
|
1702
2049
|
options.setStep("success");
|
|
@@ -1705,7 +2052,8 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
1705
2052
|
outcome: { kind: "completed" }
|
|
1706
2053
|
};
|
|
1707
2054
|
} catch (error) {
|
|
1708
|
-
const message
|
|
2055
|
+
const { message, action } = registrationErrorPresentation(error);
|
|
2056
|
+
options.setErrorAction?.(action);
|
|
1709
2057
|
options.setErrorMessage(message);
|
|
1710
2058
|
options.setStep("error");
|
|
1711
2059
|
return {
|
|
@@ -1716,11 +2064,22 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
1716
2064
|
}
|
|
1717
2065
|
};
|
|
1718
2066
|
}
|
|
1719
|
-
function
|
|
2067
|
+
function toTicketSelectionRequests(lines) {
|
|
2068
|
+
return lines.map((line) => ({
|
|
2069
|
+
pricingOptionId: line.pricingOptionId,
|
|
2070
|
+
quantity: line.quantity
|
|
2071
|
+
}));
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Freeze everything this submission is about to send, including the command
|
|
2075
|
+
* identity the server keys the commit on.
|
|
2076
|
+
*/
|
|
2077
|
+
function prepareSubmitContext(options, registrationCommandId, target, method, passId, membershipId, selection) {
|
|
1720
2078
|
const ticketSelections = normalizeTicketSelectionLines(options.ticketSelections);
|
|
1721
2079
|
if (ticketSelections.length === 0) throw new Error("Choose at least one ticket to continue.");
|
|
1722
2080
|
const bundleProductId = method === "pass_bundle" || method === "membership_bundle" ? passId || membershipId : void 0;
|
|
1723
2081
|
return {
|
|
2082
|
+
registrationCommandId,
|
|
1724
2083
|
ticketSelections,
|
|
1725
2084
|
bundleProductId,
|
|
1726
2085
|
selectionSnapshot: resolveSelectionSnapshot(method, passId, membershipId, bundleProductId, selection),
|
|
@@ -1764,11 +2123,11 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
|
|
|
1764
2123
|
async function submitWholeSeriesCheckout(options, deps, prepared, submitOptions) {
|
|
1765
2124
|
options.setStep("redirecting");
|
|
1766
2125
|
if (prepared.selectionSnapshot.method !== "stripe") throw new Error("Choose an available payment option.");
|
|
1767
|
-
const checkoutAttemptId = deps.
|
|
2126
|
+
const checkoutAttemptId = deps.createClientCommandId();
|
|
1768
2127
|
const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
|
|
1769
2128
|
const result = await options.api.createEventCheckout({
|
|
1770
2129
|
subject: prepared.subject,
|
|
1771
|
-
ticketSelections: prepared.ticketSelections,
|
|
2130
|
+
ticketSelections: toTicketSelectionRequests(prepared.ticketSelections),
|
|
1772
2131
|
selectedSlidingAmount: options.selectedSlidingAmount ?? void 0,
|
|
1773
2132
|
email: options.formData.email.trim().toLowerCase(),
|
|
1774
2133
|
name: options.formData.name.trim(),
|
|
@@ -1819,7 +2178,7 @@ async function submitOccurrenceCheckout(options, deps, prepared, registration, m
|
|
|
1819
2178
|
};
|
|
1820
2179
|
options.setPendingRegistrationReference(reference);
|
|
1821
2180
|
options.setStep("redirecting");
|
|
1822
|
-
const checkoutAttemptId = deps.
|
|
2181
|
+
const checkoutAttemptId = deps.createClientCommandId();
|
|
1823
2182
|
const urls = buildCheckoutReturnUrls("registration", EVENT_REGISTRATION_ANCHOR_ID, { [EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM]: checkoutAttemptId });
|
|
1824
2183
|
const result = await options.api.createEventCheckout({
|
|
1825
2184
|
subject: {
|
|
@@ -1870,6 +2229,13 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
|
|
|
1870
2229
|
}
|
|
1871
2230
|
//#endregion
|
|
1872
2231
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.ts
|
|
2232
|
+
function getEventSelectionDefaults(event) {
|
|
2233
|
+
const suggestedAmount = getSlidingScaleForEvent(event)?.suggestedAmount;
|
|
2234
|
+
return {
|
|
2235
|
+
slidingAmountInput: suggestedAmount == null ? "" : formatCentsAsCurrencyInput(suggestedAmount),
|
|
2236
|
+
attendanceMode: event.deliveryMode === "hybrid" ? null : event.deliveryMode ?? "in_person"
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
1873
2239
|
function parseCurrencyInputToCents(value) {
|
|
1874
2240
|
const trimmed = value.trim();
|
|
1875
2241
|
if (!trimmed) return null;
|
|
@@ -1881,11 +2247,11 @@ function formatCentsAsCurrencyInput(amount) {
|
|
|
1881
2247
|
return Number.isInteger(major) ? String(major) : major.toFixed(2);
|
|
1882
2248
|
}
|
|
1883
2249
|
function getSlidingScaleForEvent(event) {
|
|
1884
|
-
const pricing = event
|
|
2250
|
+
const pricing = event?.pricing ?? null;
|
|
1885
2251
|
return pricing?.kind === "sliding_scale" ? {
|
|
1886
|
-
minAmount: pricing.
|
|
1887
|
-
maxAmount: pricing.
|
|
1888
|
-
suggestedAmount: pricing.
|
|
2252
|
+
minAmount: pricing.minimum,
|
|
2253
|
+
maxAmount: pricing.maximum,
|
|
2254
|
+
suggestedAmount: pricing.suggested
|
|
1889
2255
|
} : null;
|
|
1890
2256
|
}
|
|
1891
2257
|
function getSlidingScaleSelectionMessage(input) {
|
|
@@ -1917,14 +2283,14 @@ function resolveWaitlistClaimRestoration(input) {
|
|
|
1917
2283
|
const event = findEventByOccurrenceId(input.scopedEvents, subject.occurrenceId);
|
|
1918
2284
|
if (!event && input.occurrenceContextId !== subject.occurrenceId) return {
|
|
1919
2285
|
ok: false,
|
|
1920
|
-
message: "This
|
|
2286
|
+
message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
|
|
1921
2287
|
};
|
|
1922
2288
|
return {
|
|
1923
2289
|
ok: true,
|
|
1924
2290
|
event,
|
|
1925
2291
|
attendanceMode: subject.attendanceMode,
|
|
1926
2292
|
ticketSelections: [{
|
|
1927
|
-
|
|
2293
|
+
pricingOptionId: null,
|
|
1928
2294
|
quantity: 1
|
|
1929
2295
|
}],
|
|
1930
2296
|
ticketsCount: 1,
|
|
@@ -1934,7 +2300,7 @@ function resolveWaitlistClaimRestoration(input) {
|
|
|
1934
2300
|
const event = input.scopedEvents.find((candidate) => candidate.registrationSubject.kind === "wholeSeries" && candidate.registrationSubject.eventSeriesId === subject.eventSeriesId);
|
|
1935
2301
|
if (!event) return {
|
|
1936
2302
|
ok: false,
|
|
1937
|
-
message: "This
|
|
2303
|
+
message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
|
|
1938
2304
|
};
|
|
1939
2305
|
return {
|
|
1940
2306
|
ok: true,
|
|
@@ -1948,7 +2314,7 @@ function resolveWaitlistClaimRestoration(input) {
|
|
|
1948
2314
|
function resolveClaimedTicketSelections(claim) {
|
|
1949
2315
|
if (!claim) return null;
|
|
1950
2316
|
return claim.subject.kind === "whole_series" ? claim.subject.ticketSelections : [{
|
|
1951
|
-
|
|
2317
|
+
pricingOptionId: null,
|
|
1952
2318
|
quantity: 1
|
|
1953
2319
|
}];
|
|
1954
2320
|
}
|
|
@@ -1967,6 +2333,7 @@ function useWaitlistClaimRestoration(input) {
|
|
|
1967
2333
|
occurrenceContextId: input.occurrenceContextId
|
|
1968
2334
|
});
|
|
1969
2335
|
if (!restoration.ok) {
|
|
2336
|
+
input.setters.setErrorAction?.("none");
|
|
1970
2337
|
input.setters.setErrorMessage(restoration.message);
|
|
1971
2338
|
input.setters.setStep("error");
|
|
1972
2339
|
return;
|
|
@@ -1996,7 +2363,31 @@ function useWaitlistClaimRestoration(input) {
|
|
|
1996
2363
|
]);
|
|
1997
2364
|
}
|
|
1998
2365
|
//#endregion
|
|
2366
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationCompletion.ts
|
|
2367
|
+
function resolveRegistrationAvailabilityBlocker(input) {
|
|
2368
|
+
if (input.hasWaitlistClaim) return null;
|
|
2369
|
+
if (input.eligibilityError) return input.eligibilityError;
|
|
2370
|
+
if (!input.eligibility) return "Registration is not available for this event.";
|
|
2371
|
+
if (input.eligibility.availability.kind === "unavailable" && input.eligibility.availability.reason === "paymentUnavailable") return "Payment options are not available for this event.";
|
|
2372
|
+
if (input.eligibility.availability.kind === "unavailable" || !input.eligibility.eligible) return "Registration is not available for this event.";
|
|
2373
|
+
return null;
|
|
2374
|
+
}
|
|
2375
|
+
function resolvePricingSelectionBlocker(input) {
|
|
2376
|
+
if (input.selectionRequired && !input.hasValidSelection) return "Choose at least one available ticket to continue.";
|
|
2377
|
+
return input.slidingScaleSelectionMessage;
|
|
2378
|
+
}
|
|
2379
|
+
function isSoldOutWithoutWaitlist(input) {
|
|
2380
|
+
return Boolean(!input.hasWaitlistClaim && input.eligibility?.isFull && !input.eligibility.canJoinWaitlist);
|
|
2381
|
+
}
|
|
2382
|
+
//#endregion
|
|
1999
2383
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
|
|
2384
|
+
function resolveDiscountSubtotalCents(context, subtotalCents) {
|
|
2385
|
+
if (context?.type !== "event" || subtotalCents === null) return void 0;
|
|
2386
|
+
return subtotalCents;
|
|
2387
|
+
}
|
|
2388
|
+
function usesTieredPricing(event) {
|
|
2389
|
+
return event !== null && event !== void 0 ? publicEventPricingStrategy(event.pricing) === "tiered" : false;
|
|
2390
|
+
}
|
|
2000
2391
|
const eventRegistrationWizardDeps = {
|
|
2001
2392
|
usePortalAuth,
|
|
2002
2393
|
useEligibility,
|
|
@@ -2011,7 +2402,7 @@ function useEventRegistrationWizard(options) {
|
|
|
2011
2402
|
}
|
|
2012
2403
|
function useEventRegistrationWizardWithDeps(options, deps) {
|
|
2013
2404
|
const api = useBlockApi();
|
|
2014
|
-
const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.
|
|
2405
|
+
const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.events ?? [])], [options.events]);
|
|
2015
2406
|
const scopedEvents = useMemo(() => {
|
|
2016
2407
|
return resolveEventRegistrationScopedEvents(registrationEvents, {
|
|
2017
2408
|
occurrenceContext: options.occurrenceContext,
|
|
@@ -2021,7 +2412,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2021
2412
|
registrationEvents,
|
|
2022
2413
|
options.occurrenceContext?.seriesId,
|
|
2023
2414
|
options.subject?.kind,
|
|
2024
|
-
options.subject?.kind === "eventSeries" ? options.subject.eventSeriesId : options.subject?.kind === "eventOffering" ? `${options.subject.eventOfferingId}:${options.subject.
|
|
2415
|
+
options.subject?.kind === "eventSeries" ? options.subject.eventSeriesId : options.subject?.kind === "eventOffering" ? `${options.subject.eventOfferingId}:${options.subject.catalogueEventSeriesIds.join(",")}` : options.subject?.reason
|
|
2025
2416
|
]);
|
|
2026
2417
|
const preSelectedEvent = useMemo(() => findPreSelectedEvent({
|
|
2027
2418
|
scopedEvents,
|
|
@@ -2045,6 +2436,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2045
2436
|
});
|
|
2046
2437
|
const [registrationResult, setRegistrationResult] = useState(null);
|
|
2047
2438
|
const [errorMessage, setErrorMessage] = useState("");
|
|
2439
|
+
const [errorAction, setErrorAction] = useState("retry");
|
|
2440
|
+
const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
|
|
2048
2441
|
const [altchaSolution, setAltchaSolution] = useState(null);
|
|
2049
2442
|
const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
|
|
2050
2443
|
const waitlistClaim = deps.useWaitlistClaim();
|
|
@@ -2072,12 +2465,9 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2072
2465
|
}), [options.occurrenceContext, selectedEvent]);
|
|
2073
2466
|
const registrationOccurrenceId = getRegistrationOccurrenceId(registrationTarget);
|
|
2074
2467
|
const currentEvent = selectedEvent ?? preSelectedEvent;
|
|
2075
|
-
const
|
|
2076
|
-
const
|
|
2077
|
-
const
|
|
2078
|
-
const currentAvailableSpots = selectedModeAvailability?.availableSpots ?? currentEvent?.availableSpots;
|
|
2079
|
-
const currentWaitlistEnabled = selectedModeAvailability?.waitlistEnabled ?? currentEvent?.waitlistEnabled ?? false;
|
|
2080
|
-
const usesTicketTypeSelections = currentEventUsesTicketTypes && !(currentAvailableSpots === 0 && currentWaitlistEnabled === true);
|
|
2468
|
+
const currentEventUsesTicketTypes = usesTieredPricing(currentEvent);
|
|
2469
|
+
const currentCanJoinWaitlist = currentEvent ? canJoinEventWaitlist(currentEvent, { attendanceMode: selectedAttendanceMode }) : false;
|
|
2470
|
+
const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
|
|
2081
2471
|
const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
|
|
2082
2472
|
event: currentEvent,
|
|
2083
2473
|
eligibility: null,
|
|
@@ -2091,7 +2481,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2091
2481
|
if (claimedTicketSelections) return [...claimedTicketSelections];
|
|
2092
2482
|
if (usesTicketTypeSelections) return normalizedSelectedTicketLines;
|
|
2093
2483
|
return [{
|
|
2094
|
-
|
|
2484
|
+
pricingOptionId: null,
|
|
2095
2485
|
quantity: ticketsCount
|
|
2096
2486
|
}];
|
|
2097
2487
|
}, [
|
|
@@ -2108,7 +2498,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2108
2498
|
});
|
|
2109
2499
|
}, [flowState.ticketsCount, ticketsCount]);
|
|
2110
2500
|
const eligibilityResult = deps.useEligibility({
|
|
2111
|
-
|
|
2501
|
+
refreshKey: optionsRefreshKey,
|
|
2502
|
+
enabled: shouldRefreshAfterRegistrationError(step, errorAction, shouldLoadRegistrationOptions(portalAuthState, step)),
|
|
2112
2503
|
subject: registrationTarget?.subject ?? null,
|
|
2113
2504
|
attendanceMode: selectedAttendanceMode,
|
|
2114
2505
|
ticketSelections,
|
|
@@ -2137,6 +2528,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2137
2528
|
});
|
|
2138
2529
|
}, [waitlistClaim.claim]);
|
|
2139
2530
|
const waitlistRestorationSetters = useMemo(() => ({
|
|
2531
|
+
setErrorAction,
|
|
2140
2532
|
setErrorMessage,
|
|
2141
2533
|
setStep,
|
|
2142
2534
|
setSelectedEvent,
|
|
@@ -2160,6 +2552,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2160
2552
|
if (waitlistClaim.requiresPortalLogin) return;
|
|
2161
2553
|
if (!waitlistClaim.error) return;
|
|
2162
2554
|
setErrorMessage(waitlistClaim.error);
|
|
2555
|
+
setErrorAction("event");
|
|
2163
2556
|
setStep("error");
|
|
2164
2557
|
}, [
|
|
2165
2558
|
waitlistClaim.error,
|
|
@@ -2240,17 +2633,17 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2240
2633
|
selectedAttendanceMode,
|
|
2241
2634
|
eligibility
|
|
2242
2635
|
]);
|
|
2243
|
-
const
|
|
2636
|
+
const singleSelectedPricingOptionId = getSingleSelectedPricingOptionId(normalizedSelectedTicketLines);
|
|
2244
2637
|
const selectedTicketType = useMemo(() => findSelectedTicketType({
|
|
2245
2638
|
event: currentEvent,
|
|
2246
2639
|
eligibility,
|
|
2247
|
-
|
|
2640
|
+
selectedPricingOptionId: singleSelectedPricingOptionId,
|
|
2248
2641
|
selectedAttendanceMode
|
|
2249
2642
|
}), [
|
|
2250
2643
|
currentEvent,
|
|
2251
2644
|
eligibility,
|
|
2252
2645
|
selectedAttendanceMode,
|
|
2253
|
-
|
|
2646
|
+
singleSelectedPricingOptionId
|
|
2254
2647
|
]);
|
|
2255
2648
|
const selectedSlidingAmount = useMemo(() => parseCurrencyInputToCents(selectedSlidingAmountInput), [selectedSlidingAmountInput]);
|
|
2256
2649
|
const selectedEventSlidingScale = useMemo(() => getSlidingScaleForEvent(selectedEvent ?? preSelectedEvent), [selectedEvent, preSelectedEvent]);
|
|
@@ -2260,14 +2653,14 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2260
2653
|
});
|
|
2261
2654
|
const ticketTypeSelectionRequired = useMemo(() => {
|
|
2262
2655
|
const event = currentEvent;
|
|
2263
|
-
if (!
|
|
2656
|
+
if (!usesTieredPricing(event)) return false;
|
|
2264
2657
|
if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
|
|
2265
|
-
|
|
2266
|
-
return !((selectedModeAvailability?.availableSpots ?? event.availableSpots) === 0 && (selectedModeAvailability?.waitlistEnabled ?? event.waitlistEnabled) === true);
|
|
2658
|
+
return !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
|
|
2267
2659
|
}, [currentEvent, selectedAttendanceMode]);
|
|
2268
|
-
const hasValidTicketSelection =
|
|
2269
|
-
|
|
2270
|
-
|
|
2660
|
+
const hasValidTicketSelection = hasValidPricingOptionSelection({
|
|
2661
|
+
selectionRequired: ticketTypeSelectionRequired,
|
|
2662
|
+
lines: normalizedSelectedTicketLines,
|
|
2663
|
+
visibleOptions: visibleTicketTypes
|
|
2271
2664
|
});
|
|
2272
2665
|
useEffect(() => {
|
|
2273
2666
|
if (!usesTicketTypeSelections) {
|
|
@@ -2278,12 +2671,12 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2278
2671
|
const implicitTicketType = getImplicitSingleAvailableTicketType(eventTicketTypesForSelection);
|
|
2279
2672
|
if (implicitTicketType && normalizedSelectedTicketLines.length === 0) {
|
|
2280
2673
|
setSelectedTicketLines([{
|
|
2281
|
-
|
|
2674
|
+
pricingOptionId: implicitTicketType.pricingOptionId,
|
|
2282
2675
|
quantity: 1
|
|
2283
2676
|
}]);
|
|
2284
2677
|
return;
|
|
2285
2678
|
}
|
|
2286
|
-
const filteredLines = normalizedSelectedTicketLines.filter((line) => line.
|
|
2679
|
+
const filteredLines = normalizedSelectedTicketLines.filter((line) => line.pricingOptionId && availableTicketTypes.some((ticketType) => ticketType.pricingOptionId === line.pricingOptionId));
|
|
2287
2680
|
if (filteredLines.length !== normalizedSelectedTicketLines.length) setSelectedTicketLines(filteredLines);
|
|
2288
2681
|
}, [
|
|
2289
2682
|
eventTicketTypesForSelection,
|
|
@@ -2343,8 +2736,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2343
2736
|
selectedSlidingAmount
|
|
2344
2737
|
]);
|
|
2345
2738
|
const handleDetailsComplete = async () => {
|
|
2346
|
-
|
|
2347
|
-
|
|
2739
|
+
const blockDetailsCompletion = (message) => {
|
|
2740
|
+
setErrorAction("places");
|
|
2348
2741
|
setErrorMessage(message);
|
|
2349
2742
|
setStep("error");
|
|
2350
2743
|
return {
|
|
@@ -2352,16 +2745,19 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2352
2745
|
reason: "blocked",
|
|
2353
2746
|
message
|
|
2354
2747
|
};
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2748
|
+
};
|
|
2749
|
+
const availabilityBlocker = resolveRegistrationAvailabilityBlocker({
|
|
2750
|
+
hasWaitlistClaim: waitlistClaim.claim !== null,
|
|
2751
|
+
eligibility,
|
|
2752
|
+
eligibilityError
|
|
2753
|
+
});
|
|
2754
|
+
if (availabilityBlocker) return blockDetailsCompletion(availabilityBlocker);
|
|
2755
|
+
const pricingSelectionBlocker = resolvePricingSelectionBlocker({
|
|
2756
|
+
selectionRequired: ticketTypeSelectionRequired,
|
|
2757
|
+
hasValidSelection: hasValidTicketSelection,
|
|
2758
|
+
slidingScaleSelectionMessage
|
|
2759
|
+
});
|
|
2760
|
+
if (pricingSelectionBlocker) return blockDetailsCompletion(pricingSelectionBlocker);
|
|
2365
2761
|
if (!validateForm()) {
|
|
2366
2762
|
setGuestSectionShake(true);
|
|
2367
2763
|
return {
|
|
@@ -2370,16 +2766,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2370
2766
|
message: "Check the highlighted fields and try again."
|
|
2371
2767
|
};
|
|
2372
2768
|
}
|
|
2373
|
-
if (
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
return {
|
|
2378
|
-
ok: false,
|
|
2379
|
-
reason: "blocked",
|
|
2380
|
-
message
|
|
2381
|
-
};
|
|
2382
|
-
}
|
|
2769
|
+
if (isSoldOutWithoutWaitlist({
|
|
2770
|
+
hasWaitlistClaim: waitlistClaim.claim !== null,
|
|
2771
|
+
eligibility
|
|
2772
|
+
})) return blockDetailsCompletion("Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.");
|
|
2383
2773
|
if (!eligibility?.canJoinWaitlist && requiresPaymentStep({
|
|
2384
2774
|
eventRequiresPayment,
|
|
2385
2775
|
paymentSelection
|
|
@@ -2395,15 +2785,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2395
2785
|
eventRequiresPayment,
|
|
2396
2786
|
canJoinWaitlist: eligibility?.canJoinWaitlist
|
|
2397
2787
|
});
|
|
2398
|
-
if (!submitPlan.ok)
|
|
2399
|
-
setErrorMessage(submitPlan.message);
|
|
2400
|
-
setStep("error");
|
|
2401
|
-
return {
|
|
2402
|
-
ok: false,
|
|
2403
|
-
reason: "blocked",
|
|
2404
|
-
message: submitPlan.message
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2788
|
+
if (!submitPlan.ok) return blockDetailsCompletion(submitPlan.message);
|
|
2407
2789
|
const submitResult = await handleSubmit(submitPlan.args.method, submitPlan.args.passId, submitPlan.args.membershipId, submitPlan.args.selection);
|
|
2408
2790
|
if (!submitResult.ok) return {
|
|
2409
2791
|
ok: false,
|
|
@@ -2449,36 +2831,15 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2449
2831
|
paymentSelection,
|
|
2450
2832
|
ticketsCount
|
|
2451
2833
|
]);
|
|
2452
|
-
const
|
|
2453
|
-
const
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
eligibility,
|
|
2462
|
-
fallbackUnitPriceCents,
|
|
2463
|
-
normalizedSelectedTicketLines,
|
|
2464
|
-
ticketsCount,
|
|
2465
|
-
usesTicketTypeSelections,
|
|
2466
|
-
visibleTicketTypes
|
|
2467
|
-
]);
|
|
2468
|
-
const ticketSelectionSummaryLines = useMemo(() => buildTicketSelectionSummaryLines({
|
|
2469
|
-
lines: ticketSelections,
|
|
2470
|
-
ticketTypes: visibleTicketTypes,
|
|
2471
|
-
fallbackLabel: "Ticket",
|
|
2472
|
-
fallbackUnitPriceCents
|
|
2473
|
-
}), [
|
|
2474
|
-
fallbackUnitPriceCents,
|
|
2475
|
-
ticketSelections,
|
|
2476
|
-
visibleTicketTypes
|
|
2477
|
-
]);
|
|
2478
|
-
const discountSubtotalCents = useMemo(() => {
|
|
2479
|
-
if (discountContext?.type !== "event") return void 0;
|
|
2480
|
-
return ticketSelectionSubtotalCents;
|
|
2481
|
-
}, [discountContext, ticketSelectionSubtotalCents]);
|
|
2834
|
+
const ticketSelectionSubtotalCents = eligibility?.price ?? null;
|
|
2835
|
+
const ticketSelectionSummaryLines = useMemo(() => eligibility?.ticketLines.map((line) => ({
|
|
2836
|
+
pricingOptionId: line.pricingOptionId,
|
|
2837
|
+
label: line.label,
|
|
2838
|
+
quantity: line.quantity,
|
|
2839
|
+
unitPriceCents: line.unitPriceCents,
|
|
2840
|
+
subtotalCents: line.subtotalCents
|
|
2841
|
+
})) ?? [], [eligibility]);
|
|
2842
|
+
const discountSubtotalCents = resolveDiscountSubtotalCents(discountContext, ticketSelectionSubtotalCents);
|
|
2482
2843
|
const discountUi = deps.useDiscountCodeUi({
|
|
2483
2844
|
api,
|
|
2484
2845
|
discountContext,
|
|
@@ -2487,6 +2848,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2487
2848
|
const selectionMethod = paymentSelection.method;
|
|
2488
2849
|
const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
|
|
2489
2850
|
const handleSubmit = deps.useEventRegistrationSubmit({
|
|
2851
|
+
setErrorAction,
|
|
2490
2852
|
api,
|
|
2491
2853
|
registrationTarget,
|
|
2492
2854
|
selectedAttendanceMode,
|
|
@@ -2509,26 +2871,31 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2509
2871
|
...current,
|
|
2510
2872
|
consentAccepted: false
|
|
2511
2873
|
}));
|
|
2512
|
-
const
|
|
2513
|
-
setSelectedSlidingAmountInput(
|
|
2514
|
-
setSelectedAttendanceMode(
|
|
2874
|
+
const defaults = getEventSelectionDefaults(event);
|
|
2875
|
+
setSelectedSlidingAmountInput(defaults.slidingAmountInput);
|
|
2876
|
+
setSelectedAttendanceMode(defaults.attendanceMode);
|
|
2515
2877
|
setSelectedTicketLines([]);
|
|
2516
2878
|
dispatchFlow({
|
|
2517
2879
|
type: "event-changed",
|
|
2518
2880
|
hasPreSelectedContext: true
|
|
2519
2881
|
});
|
|
2520
2882
|
};
|
|
2521
|
-
const handleRetry = () => {
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2883
|
+
const handleRetry = () => recoverRegistrationError(resolveRegistrationRecoveryAction(step, errorAction), {
|
|
2884
|
+
canJoinWaitlist: canRecoverToWaitlist(eligibility),
|
|
2885
|
+
refreshOptions: () => setOptionsRefreshKey((value) => value + 1),
|
|
2886
|
+
clearError: () => setErrorMessage(""),
|
|
2887
|
+
setStep,
|
|
2888
|
+
reset: () => resetRegistrationAfterExpiry({
|
|
2889
|
+
hasPreSelectedContext,
|
|
2890
|
+
preSelectedEvent,
|
|
2891
|
+
dispatchFlow,
|
|
2892
|
+
setSelectedTicketLines,
|
|
2893
|
+
setSelectedSlidingAmountInput,
|
|
2894
|
+
setSelectedAttendanceMode,
|
|
2895
|
+
setErrorMessage,
|
|
2896
|
+
setPendingRegistrationReference
|
|
2897
|
+
})
|
|
2898
|
+
});
|
|
2532
2899
|
const handlePaymentStepStateChange = useCallback((state) => {
|
|
2533
2900
|
setPaymentStepState(state);
|
|
2534
2901
|
}, []);
|
|
@@ -2591,6 +2958,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
2591
2958
|
handleGuestShakeEnd,
|
|
2592
2959
|
registrationResult,
|
|
2593
2960
|
errorMessage,
|
|
2961
|
+
errorAction,
|
|
2594
2962
|
altchaSolution,
|
|
2595
2963
|
setAltchaSolution,
|
|
2596
2964
|
portalAuthState,
|
|
@@ -2832,7 +3200,7 @@ function getSelectedDirectPaymentOption(input) {
|
|
|
2832
3200
|
paymentTerms: eligibility.paymentTerms,
|
|
2833
3201
|
totalPriceCents: input.totalCents,
|
|
2834
3202
|
currency: input.currency,
|
|
2835
|
-
startsAt: input.wizard.occurrenceContext
|
|
3203
|
+
startsAt: getRegistrationStartAt(summaryEvent, input.wizard.occurrenceContext)
|
|
2836
3204
|
}).options;
|
|
2837
3205
|
const requestedKind = input.wizard.paymentSelection.collectionOptionKind;
|
|
2838
3206
|
return options.find((option) => option.kind === requestedKind) ?? options.find((option) => option.kind === "upfront") ?? options[0] ?? null;
|
|
@@ -2867,7 +3235,7 @@ function EntitlementSummaryRow(props) {
|
|
|
2867
3235
|
children: props.copy.productPrice ? /* @__PURE__ */ jsx("span", {
|
|
2868
3236
|
className: "er-summary-bar-included",
|
|
2869
3237
|
children: props.copy.productPrice
|
|
2870
|
-
}) : productPrice ? formatPrice(productPrice, productCurrency
|
|
3238
|
+
}) : productPrice && productCurrency ? formatPrice(productPrice, productCurrency) : null
|
|
2871
3239
|
})]
|
|
2872
3240
|
});
|
|
2873
3241
|
}
|
|
@@ -2875,10 +3243,10 @@ function EventRegistrationSummaryBar(props) {
|
|
|
2875
3243
|
const { wizard } = props;
|
|
2876
3244
|
const summaryEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
|
|
2877
3245
|
const summaryTitle = wizard.occurrenceContext?.overrides?.title ?? summaryEvent?.title ?? "";
|
|
2878
|
-
const summaryCurrency =
|
|
3246
|
+
const summaryCurrency = summaryEvent ? publicEventPricingCurrency(summaryEvent.pricing) : null;
|
|
2879
3247
|
const teamMemberNames = (summaryEvent?.teamMembers ?? []).map((teamMember) => teamMember.name).filter(Boolean);
|
|
2880
|
-
const
|
|
2881
|
-
|
|
3248
|
+
const subtotalCents = wizard.ticketSelectionSubtotalCents;
|
|
3249
|
+
if (!summaryTitle || !summaryCurrency || subtotalCents === null) return null;
|
|
2882
3250
|
const autoAppliedDiscount = wizard.discountCode.trim().length > 0 ? null : wizard.autoAppliedDiscount;
|
|
2883
3251
|
const autoAppliedDiscountCents = Math.max(0, autoAppliedDiscount?.computedAmountCents ?? 0);
|
|
2884
3252
|
const discountedTotalCents = Math.max(0, subtotalCents - autoAppliedDiscountCents);
|
|
@@ -2894,7 +3262,6 @@ function EventRegistrationSummaryBar(props) {
|
|
|
2894
3262
|
balanceDueBy: getSummaryRow(selectedDirectPaymentOption, "Balance due by"),
|
|
2895
3263
|
depositPolicy: getSummaryRow(selectedDirectPaymentOption, "Deposit policy")
|
|
2896
3264
|
} : null;
|
|
2897
|
-
if (!summaryTitle) return null;
|
|
2898
3265
|
const scheduleSummary = summaryEvent ? getScheduleSummary(wizard, summaryEvent) : null;
|
|
2899
3266
|
const bookingUnit = summaryEvent?.registrationSubject.kind === "wholeSeries" ? "place" : "ticket";
|
|
2900
3267
|
const productMethod = isProductMethod(wizard.paymentSelection.method);
|
|
@@ -2917,7 +3284,8 @@ function EventRegistrationSummaryBar(props) {
|
|
|
2917
3284
|
/* @__PURE__ */ jsxs("span", {
|
|
2918
3285
|
className: "er-summary-bar-meta",
|
|
2919
3286
|
children: [scheduleSummary, wizard.step !== "select-event" && wizard.step !== "select-tickets" && wizard.ticketsCount > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2920
|
-
"
|
|
3287
|
+
" ",
|
|
3288
|
+
"· ",
|
|
2921
3289
|
wizard.ticketsCount,
|
|
2922
3290
|
" ",
|
|
2923
3291
|
bookingUnit,
|
|
@@ -2997,11 +3365,11 @@ function EventRegistrationSummaryBar(props) {
|
|
|
2997
3365
|
*/
|
|
2998
3366
|
function resolveDetailsButtonText(input) {
|
|
2999
3367
|
const { wizard } = input;
|
|
3000
|
-
if (wizard.eligibility?.canJoinWaitlist) return "Join
|
|
3368
|
+
if (wizard.eligibility?.canJoinWaitlist) return "Join waitlist";
|
|
3001
3369
|
if (!input.hasWaitlistClaim && wizard.eligibility?.isFull) return "Sold out";
|
|
3002
3370
|
if (wizard.paymentSelection.method === "pass") return "Book using class pass";
|
|
3003
3371
|
if (wizard.paymentSelection.method === "membership") return input.fallbackText;
|
|
3004
|
-
return wizard.eventRequiresPayment ? "Continue to
|
|
3372
|
+
return wizard.eventRequiresPayment ? "Continue to payment" : input.fallbackText;
|
|
3005
3373
|
}
|
|
3006
3374
|
function resolveExistingRegistrationLabel(wizard) {
|
|
3007
3375
|
return wizard.registrationState.kind === "waitlisted" ? "Already on waitlist" : "Already registered";
|
|
@@ -3013,18 +3381,114 @@ function isExistingRegistrationBlocking$1(wizard) {
|
|
|
3013
3381
|
hasWaitlistClaim: wizard.waitlistClaim.claim !== null
|
|
3014
3382
|
});
|
|
3015
3383
|
}
|
|
3016
|
-
|
|
3384
|
+
/**
|
|
3385
|
+
* Full for the visitor's selected attendance mode (or the whole event when no
|
|
3386
|
+
* mode is chosen) with no waitlist to fall back on. Reads the same capacity
|
|
3387
|
+
* source as the steps above the action bar so the button never disagrees
|
|
3388
|
+
* with them on a hybrid event.
|
|
3389
|
+
*/
|
|
3390
|
+
function isFullWithNoWaitlist(event, attendanceMode) {
|
|
3391
|
+
if (!event) return false;
|
|
3392
|
+
const source = selectEventCapacitySource(event, attendanceMode);
|
|
3393
|
+
return getEventAvailability(source).isFull && !source.waitlistEnabled;
|
|
3394
|
+
}
|
|
3395
|
+
function resolveTicketSelectionContinueLabel(input) {
|
|
3396
|
+
if (input.isCheckingExistingRegistration) return "Checking registration...";
|
|
3397
|
+
if (input.hasExistingRegistration) return resolveExistingRegistrationLabel(input.wizard);
|
|
3398
|
+
if (input.isSoldOutWithoutWaitlist) return "Sold out";
|
|
3399
|
+
if (input.ticketTypeSelectionBlocked) return "Choose a ticket";
|
|
3400
|
+
return "Continue";
|
|
3401
|
+
}
|
|
3402
|
+
function SelectTicketsActions(props) {
|
|
3017
3403
|
const { wizard } = props;
|
|
3018
|
-
const nextStepAfterTickets = "enter-details";
|
|
3019
|
-
const prevStepForDetails = "select-tickets";
|
|
3020
3404
|
const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
|
|
3021
3405
|
const currentEvent = wizard.selectedEvent ?? wizard.preSelectedEvent;
|
|
3022
|
-
const isSoldOutWithoutWaitlist = !hasWaitlistClaim && currentEvent
|
|
3023
|
-
const
|
|
3406
|
+
const isSoldOutWithoutWaitlist = !hasWaitlistClaim && isFullWithNoWaitlist(currentEvent, wizard.selectedAttendanceMode);
|
|
3407
|
+
const isWaitingForEligibility = wizard.portalAuthState === "authenticated" && wizard.eligibilityLoading;
|
|
3408
|
+
const isCheckingExistingRegistration = wizard.portalAuthState === "authenticated" && wizard.existingRegistrationLoading;
|
|
3409
|
+
const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
|
|
3410
|
+
const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
|
|
3411
|
+
const isContinueDisabled = isWaitingForEligibility || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
|
|
3412
|
+
const continueLabel = resolveTicketSelectionContinueLabel({
|
|
3413
|
+
wizard,
|
|
3414
|
+
isCheckingExistingRegistration,
|
|
3415
|
+
hasExistingRegistration,
|
|
3416
|
+
isSoldOutWithoutWaitlist,
|
|
3417
|
+
ticketTypeSelectionBlocked
|
|
3418
|
+
});
|
|
3419
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3420
|
+
className: "rb-wizard-actions er-actions",
|
|
3421
|
+
children: [!wizard.hasPreSelectedContext && /* @__PURE__ */ jsx("button", {
|
|
3422
|
+
type: "button",
|
|
3423
|
+
onClick: () => wizard.setStep("select-event"),
|
|
3424
|
+
className: "er-back-btn",
|
|
3425
|
+
children: "← Back"
|
|
3426
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
3427
|
+
type: "button",
|
|
3428
|
+
onClick: () => wizard.setStep("enter-details"),
|
|
3429
|
+
disabled: isContinueDisabled,
|
|
3430
|
+
className: props.buttonClass,
|
|
3431
|
+
children: isWaitingForEligibility ? /* @__PURE__ */ jsxs("span", {
|
|
3432
|
+
className: "er-button-with-spinner",
|
|
3433
|
+
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
3434
|
+
size: "xs",
|
|
3435
|
+
color: "inherit",
|
|
3436
|
+
className: "er-button-spinner",
|
|
3437
|
+
"aria-hidden": true
|
|
3438
|
+
}), continueLabel]
|
|
3439
|
+
}) : continueLabel
|
|
3440
|
+
})]
|
|
3441
|
+
});
|
|
3442
|
+
}
|
|
3443
|
+
function EnterDetailsActions(props) {
|
|
3444
|
+
const { wizard } = props;
|
|
3445
|
+
const hasWaitlistClaim = wizard.waitlistClaim.claim !== null;
|
|
3446
|
+
const isCheckingEligibility = wizard.eligibilityLoading;
|
|
3447
|
+
const eligibilityUnavailable = !hasWaitlistClaim && (Boolean(wizard.eligibilityError) || !wizard.eligibility || wizard.eligibility.availability.kind === "unavailable" || !wizard.eligibility.eligible);
|
|
3448
|
+
const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
|
|
3449
|
+
const isContinueDisabled = isCheckingEligibility || eligibilityUnavailable || isSoldOut;
|
|
3450
|
+
const continueLabel = isCheckingEligibility ? "Checking availability..." : wizard.eligibilityError ? "Availability unavailable" : eligibilityUnavailable ? "Registration unavailable" : resolveDetailsButtonText({
|
|
3024
3451
|
wizard,
|
|
3025
3452
|
hasWaitlistClaim,
|
|
3026
3453
|
fallbackText: props.buttonText
|
|
3027
3454
|
});
|
|
3455
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3456
|
+
className: "rb-wizard-actions er-actions",
|
|
3457
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
3458
|
+
type: "button",
|
|
3459
|
+
onClick: () => wizard.setStep("select-tickets"),
|
|
3460
|
+
className: "er-back-btn",
|
|
3461
|
+
children: "← Back"
|
|
3462
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
3463
|
+
type: "button",
|
|
3464
|
+
onClick: wizard.handleDetailsComplete,
|
|
3465
|
+
disabled: isContinueDisabled,
|
|
3466
|
+
className: props.buttonClass,
|
|
3467
|
+
children: continueLabel
|
|
3468
|
+
})]
|
|
3469
|
+
});
|
|
3470
|
+
}
|
|
3471
|
+
function SelectPaymentActions(props) {
|
|
3472
|
+
const { wizard } = props;
|
|
3473
|
+
const { status, canContinue, buttonText } = wizard.paymentStepState;
|
|
3474
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3475
|
+
className: "rb-wizard-actions er-actions",
|
|
3476
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
3477
|
+
type: "button",
|
|
3478
|
+
onClick: () => wizard.setStep("enter-details"),
|
|
3479
|
+
className: "er-back-btn",
|
|
3480
|
+
children: "← Back"
|
|
3481
|
+
}), status === "ready" && /* @__PURE__ */ jsx("button", {
|
|
3482
|
+
type: "button",
|
|
3483
|
+
onClick: () => void wizard.handlePaymentSelect(),
|
|
3484
|
+
disabled: !canContinue,
|
|
3485
|
+
className: props.buttonClass,
|
|
3486
|
+
children: buttonText
|
|
3487
|
+
})]
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
function EventRegistrationWizardActions(props) {
|
|
3491
|
+
const { wizard } = props;
|
|
3028
3492
|
switch (wizard.step) {
|
|
3029
3493
|
case "error":
|
|
3030
3494
|
case "success":
|
|
@@ -3034,268 +3498,13 @@ function EventRegistrationWizardActions(props) {
|
|
|
3034
3498
|
case "verifying-timeout":
|
|
3035
3499
|
case "payment-failed": return null;
|
|
3036
3500
|
case "select-event": return null;
|
|
3037
|
-
case "select-tickets": {
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
const hasExistingRegistration = isExistingRegistrationBlocking$1(wizard);
|
|
3041
|
-
const ticketTypeSelectionBlocked = wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection;
|
|
3042
|
-
const isContinueDisabled = isWaitingForEligibility || isCheckingExistingRegistration || hasExistingRegistration || isSoldOutWithoutWaitlist || ticketTypeSelectionBlocked;
|
|
3043
|
-
const continueLabel = isCheckingExistingRegistration ? "Checking registration..." : hasExistingRegistration ? resolveExistingRegistrationLabel(wizard) : isSoldOutWithoutWaitlist ? "Sold out" : ticketTypeSelectionBlocked ? "Choose a ticket" : "Continue";
|
|
3044
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
3045
|
-
className: "rb-wizard-actions er-actions",
|
|
3046
|
-
children: [!wizard.hasPreSelectedContext && /* @__PURE__ */ jsx("button", {
|
|
3047
|
-
type: "button",
|
|
3048
|
-
onClick: () => wizard.setStep("select-event"),
|
|
3049
|
-
className: "er-back-btn",
|
|
3050
|
-
children: "← Back"
|
|
3051
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
3052
|
-
type: "button",
|
|
3053
|
-
onClick: () => wizard.setStep(nextStepAfterTickets),
|
|
3054
|
-
disabled: isContinueDisabled,
|
|
3055
|
-
className: props.buttonClass,
|
|
3056
|
-
children: isWaitingForEligibility ? /* @__PURE__ */ jsxs("span", {
|
|
3057
|
-
className: "er-button-with-spinner",
|
|
3058
|
-
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
3059
|
-
size: "xs",
|
|
3060
|
-
color: "inherit",
|
|
3061
|
-
className: "er-button-spinner",
|
|
3062
|
-
"aria-hidden": true
|
|
3063
|
-
}), continueLabel]
|
|
3064
|
-
}) : continueLabel
|
|
3065
|
-
})]
|
|
3066
|
-
});
|
|
3067
|
-
}
|
|
3068
|
-
case "enter-details": {
|
|
3069
|
-
const isCheckingEligibility = wizard.eligibilityLoading;
|
|
3070
|
-
const isSoldOut = !hasWaitlistClaim && wizard.eligibility?.isFull === true && wizard.eligibility.canJoinWaitlist !== true;
|
|
3071
|
-
const isContinueDisabled = isCheckingEligibility || isSoldOut;
|
|
3072
|
-
const continueLabel = isCheckingEligibility ? "Checking availability..." : getDetailsButtonText();
|
|
3073
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
3074
|
-
className: "rb-wizard-actions er-actions",
|
|
3075
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
3076
|
-
type: "button",
|
|
3077
|
-
onClick: () => wizard.setStep(prevStepForDetails),
|
|
3078
|
-
className: "er-back-btn",
|
|
3079
|
-
children: "← Back"
|
|
3080
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
3081
|
-
type: "button",
|
|
3082
|
-
onClick: wizard.handleDetailsComplete,
|
|
3083
|
-
disabled: isContinueDisabled,
|
|
3084
|
-
className: props.buttonClass,
|
|
3085
|
-
children: continueLabel
|
|
3086
|
-
})]
|
|
3087
|
-
});
|
|
3088
|
-
}
|
|
3089
|
-
case "select-payment": {
|
|
3090
|
-
const { status, canContinue, buttonText } = wizard.paymentStepState;
|
|
3091
|
-
const handlePaymentContinue = () => {
|
|
3092
|
-
wizard.handlePaymentSelect();
|
|
3093
|
-
};
|
|
3094
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
3095
|
-
className: "rb-wizard-actions er-actions",
|
|
3096
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
3097
|
-
type: "button",
|
|
3098
|
-
onClick: () => wizard.setStep("enter-details"),
|
|
3099
|
-
className: "er-back-btn",
|
|
3100
|
-
children: "← Back"
|
|
3101
|
-
}), status === "ready" && /* @__PURE__ */ jsx("button", {
|
|
3102
|
-
type: "button",
|
|
3103
|
-
onClick: handlePaymentContinue,
|
|
3104
|
-
disabled: !canContinue,
|
|
3105
|
-
className: props.buttonClass,
|
|
3106
|
-
children: buttonText
|
|
3107
|
-
})]
|
|
3108
|
-
});
|
|
3109
|
-
}
|
|
3501
|
+
case "select-tickets": return /* @__PURE__ */ jsx(SelectTicketsActions, { ...props });
|
|
3502
|
+
case "enter-details": return /* @__PURE__ */ jsx(EnterDetailsActions, { ...props });
|
|
3503
|
+
case "select-payment": return /* @__PURE__ */ jsx(SelectPaymentActions, { ...props });
|
|
3110
3504
|
default: return null;
|
|
3111
3505
|
}
|
|
3112
3506
|
}
|
|
3113
3507
|
//#endregion
|
|
3114
|
-
//#region ../commerce/src/purchase/checkoutPaymentFlow.ts
|
|
3115
|
-
function planCheckoutPaymentFlow(options) {
|
|
3116
|
-
const amountDueCents = toNonNegativeCents(options.amountDueCents);
|
|
3117
|
-
const discountCents = toNonNegativeCents(options.discountCents);
|
|
3118
|
-
const availableCreditCents = toNonNegativeCents(options.availableCreditCents);
|
|
3119
|
-
const minimumStripeChargeCents = toNonNegativeCents(options.minimumStripeChargeCents ?? 0);
|
|
3120
|
-
if (amountDueCents <= 0) return {
|
|
3121
|
-
kind: "bypass",
|
|
3122
|
-
bypassReason: discountCents > 0 ? "discount_free" : "free",
|
|
3123
|
-
reserveCreditCents: 0
|
|
3124
|
-
};
|
|
3125
|
-
if (!options.creditCurrencyMatches || availableCreditCents <= 0) return {
|
|
3126
|
-
kind: "stripe",
|
|
3127
|
-
reserveCreditCents: toNonNegativeCents(0)
|
|
3128
|
-
};
|
|
3129
|
-
if (availableCreditCents >= amountDueCents) return {
|
|
3130
|
-
kind: "store_credit_only",
|
|
3131
|
-
reserveCreditCents: amountDueCents
|
|
3132
|
-
};
|
|
3133
|
-
return {
|
|
3134
|
-
kind: "stripe",
|
|
3135
|
-
reserveCreditCents: planMixedPaymentCreditReservation({
|
|
3136
|
-
amountDueCents,
|
|
3137
|
-
availableCreditCents,
|
|
3138
|
-
minimumStripeChargeCents
|
|
3139
|
-
})
|
|
3140
|
-
};
|
|
3141
|
-
}
|
|
3142
|
-
function planMixedPaymentCreditReservation(input) {
|
|
3143
|
-
const chargeAfterFullCredit = input.amountDueCents - input.availableCreditCents;
|
|
3144
|
-
if (input.minimumStripeChargeCents <= 0 || chargeAfterFullCredit <= 0 || chargeAfterFullCredit >= input.minimumStripeChargeCents) return input.availableCreditCents;
|
|
3145
|
-
if (input.amountDueCents < input.minimumStripeChargeCents) return toNonNegativeCents(0);
|
|
3146
|
-
return toNonNegativeCents(input.amountDueCents - input.minimumStripeChargeCents);
|
|
3147
|
-
}
|
|
3148
|
-
/**
|
|
3149
|
-
* Apply site credit to a flexible-balance booking before card payment.
|
|
3150
|
-
*
|
|
3151
|
-
* Credit first reduces the configured payment due now. Once that payment is
|
|
3152
|
-
* covered, any remaining credit reduces the later balance. If a partial credit
|
|
3153
|
-
* application would leave a positive card charge below Stripe's minimum, less
|
|
3154
|
-
* credit is used so the configured payment can still be collected.
|
|
3155
|
-
*/
|
|
3156
|
-
function planFlexibleBalanceCreditFirst(input) {
|
|
3157
|
-
const totalCents = toNonNegativeCents(input.totalAfterDiscountCents);
|
|
3158
|
-
const configuredDueNowCents = toNonNegativeCents(Math.min(input.configuredPaymentDueNowCents, totalCents));
|
|
3159
|
-
const availableCreditCents = toNonNegativeCents(input.creditCurrencyMatches ? input.availableCreditCents : 0);
|
|
3160
|
-
const minimumStripeChargeCents = toNonNegativeCents(input.minimumStripeChargeCents ?? 0);
|
|
3161
|
-
if (availableCreditCents >= totalCents && totalCents > 0) return {
|
|
3162
|
-
kind: "credit_only",
|
|
3163
|
-
reserveCreditCents: totalCents,
|
|
3164
|
-
cardDueNowCents: toNonNegativeCents(0),
|
|
3165
|
-
laterBalanceCents: toNonNegativeCents(0)
|
|
3166
|
-
};
|
|
3167
|
-
let reserveCreditCents = toNonNegativeCents(Math.min(availableCreditCents, totalCents));
|
|
3168
|
-
if (reserveCreditCents >= configuredDueNowCents) return {
|
|
3169
|
-
kind: "flexible_balance",
|
|
3170
|
-
reserveCreditCents,
|
|
3171
|
-
cardDueNowCents: toNonNegativeCents(0),
|
|
3172
|
-
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents)
|
|
3173
|
-
};
|
|
3174
|
-
const plannedCardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
3175
|
-
if (plannedCardDueNowCents > 0 && plannedCardDueNowCents < minimumStripeChargeCents) {
|
|
3176
|
-
if (configuredDueNowCents < minimumStripeChargeCents) return {
|
|
3177
|
-
kind: "card_below_minimum",
|
|
3178
|
-
reserveCreditCents: toNonNegativeCents(0),
|
|
3179
|
-
cardDueNowCents: configuredDueNowCents,
|
|
3180
|
-
laterBalanceCents: toNonNegativeCents(totalCents - configuredDueNowCents)
|
|
3181
|
-
};
|
|
3182
|
-
reserveCreditCents = toNonNegativeCents(configuredDueNowCents - minimumStripeChargeCents);
|
|
3183
|
-
}
|
|
3184
|
-
const cardDueNowCents = toNonNegativeCents(configuredDueNowCents - reserveCreditCents);
|
|
3185
|
-
return {
|
|
3186
|
-
kind: "flexible_balance",
|
|
3187
|
-
reserveCreditCents,
|
|
3188
|
-
cardDueNowCents,
|
|
3189
|
-
laterBalanceCents: toNonNegativeCents(totalCents - reserveCreditCents - cardDueNowCents)
|
|
3190
|
-
};
|
|
3191
|
-
}
|
|
3192
|
-
//#endregion
|
|
3193
|
-
//#region ../commerce/src/purchase/settlement.ts
|
|
3194
|
-
function normalizeCurrencyCode(raw) {
|
|
3195
|
-
const normalized = raw.trim().toUpperCase();
|
|
3196
|
-
if (!/^[A-Z]{3}$/.test(normalized)) throw new Error(`Invalid currency code: ${raw}`);
|
|
3197
|
-
return normalized;
|
|
3198
|
-
}
|
|
3199
|
-
//#endregion
|
|
3200
|
-
//#region ../commerce/src/purchase/checkoutSessionMetadata.ts
|
|
3201
|
-
const datedOfferingSharedEngineMetadataShape = {
|
|
3202
|
-
datedOfferingEngineContractVersion: z.literal("shared_v1"),
|
|
3203
|
-
datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
|
|
3204
|
-
datedOfferingCapacityHoldId: z.string().uuid(),
|
|
3205
|
-
datedOfferingCapacityHoldAuditRef: z.string().uuid(),
|
|
3206
|
-
customerId: z.string().uuid(),
|
|
3207
|
-
eventSeriesId: z.string().uuid()
|
|
3208
|
-
};
|
|
3209
|
-
z.object(datedOfferingSharedEngineMetadataShape);
|
|
3210
|
-
const orderCheckoutSessionMetadataBaseShape = {
|
|
3211
|
-
type: z.literal("order"),
|
|
3212
|
-
site_id: z.string().uuid(),
|
|
3213
|
-
order_id: z.string().uuid().optional(),
|
|
3214
|
-
customer_email: z.string().email(),
|
|
3215
|
-
customer_name: z.string().optional(),
|
|
3216
|
-
product_id: z.string().uuid().optional(),
|
|
3217
|
-
attendee_id: z.string().uuid().optional(),
|
|
3218
|
-
occurrence_id: z.string().uuid().optional(),
|
|
3219
|
-
tickets_count: z.string().optional(),
|
|
3220
|
-
notes: z.string().optional(),
|
|
3221
|
-
discount_redemption_id: z.string().uuid().optional(),
|
|
3222
|
-
discount_code_id: z.string().uuid().optional(),
|
|
3223
|
-
discount_code: z.string().optional(),
|
|
3224
|
-
discount_public_label: z.string().optional(),
|
|
3225
|
-
credit_reservation_id: z.string().uuid().optional(),
|
|
3226
|
-
credit_reserved_cents: z.string().optional(),
|
|
3227
|
-
discount_code_amount_cents: z.string().optional(),
|
|
3228
|
-
order_payment_reason: z.enum([
|
|
3229
|
-
"instalment_payoff",
|
|
3230
|
-
"flexible_balance_initial",
|
|
3231
|
-
"flexible_balance_paydown"
|
|
3232
|
-
]).optional(),
|
|
3233
|
-
order_payment_plan_id: z.string().uuid().optional(),
|
|
3234
|
-
order_flexible_balance_contract_id: z.string().uuid().optional()
|
|
3235
|
-
};
|
|
3236
|
-
const absentDatedOfferingSharedEngineMetadataShape = {
|
|
3237
|
-
datedOfferingEngineContractVersion: z.never().optional(),
|
|
3238
|
-
datedOfferingEngineRouteKind: z.never().optional(),
|
|
3239
|
-
datedOfferingCapacityHoldId: z.never().optional(),
|
|
3240
|
-
datedOfferingCapacityHoldAuditRef: z.never().optional(),
|
|
3241
|
-
customerId: z.never().optional(),
|
|
3242
|
-
eventSeriesId: z.never().optional()
|
|
3243
|
-
};
|
|
3244
|
-
const LegacyOrderCheckoutSessionMetadataSchema = z.object({
|
|
3245
|
-
...orderCheckoutSessionMetadataBaseShape,
|
|
3246
|
-
...absentDatedOfferingSharedEngineMetadataShape
|
|
3247
|
-
});
|
|
3248
|
-
const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
|
|
3249
|
-
...orderCheckoutSessionMetadataBaseShape,
|
|
3250
|
-
...datedOfferingSharedEngineMetadataShape
|
|
3251
|
-
});
|
|
3252
|
-
z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
|
|
3253
|
-
toNonNegativeCents(0);
|
|
3254
|
-
//#endregion
|
|
3255
|
-
//#region ../commerce/src/purchase/stripeMinimumCharge.ts
|
|
3256
|
-
const STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY = {
|
|
3257
|
-
GBP: 30,
|
|
3258
|
-
USD: 50,
|
|
3259
|
-
EUR: 50,
|
|
3260
|
-
AED: 200,
|
|
3261
|
-
AUD: 50,
|
|
3262
|
-
BGN: 100,
|
|
3263
|
-
BRL: 50,
|
|
3264
|
-
CAD: 50,
|
|
3265
|
-
CHF: 50,
|
|
3266
|
-
CZK: 1500,
|
|
3267
|
-
DKK: 250,
|
|
3268
|
-
HKD: 400,
|
|
3269
|
-
HUF: 17500,
|
|
3270
|
-
JPY: 50,
|
|
3271
|
-
MXN: 1e3,
|
|
3272
|
-
MYR: 200,
|
|
3273
|
-
NOK: 300,
|
|
3274
|
-
NZD: 50,
|
|
3275
|
-
PLN: 200,
|
|
3276
|
-
RON: 200,
|
|
3277
|
-
SEK: 300,
|
|
3278
|
-
SGD: 50,
|
|
3279
|
-
THB: 1e3
|
|
3280
|
-
};
|
|
3281
|
-
function isStripeMinimumChargeCurrency(currency) {
|
|
3282
|
-
return currency in STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY;
|
|
3283
|
-
}
|
|
3284
|
-
function getStripeMinimumChargeRequirement(rawCurrency) {
|
|
3285
|
-
let currency;
|
|
3286
|
-
try {
|
|
3287
|
-
currency = normalizeCurrencyCode(rawCurrency);
|
|
3288
|
-
} catch {
|
|
3289
|
-
return null;
|
|
3290
|
-
}
|
|
3291
|
-
const currencyKey = currency;
|
|
3292
|
-
if (!isStripeMinimumChargeCurrency(currencyKey)) return null;
|
|
3293
|
-
return {
|
|
3294
|
-
currency,
|
|
3295
|
-
minimumAmountCents: STRIPE_MINIMUM_CHARGE_CENTS_BY_CURRENCY[currencyKey]
|
|
3296
|
-
};
|
|
3297
|
-
}
|
|
3298
|
-
//#endregion
|
|
3299
3508
|
//#region ../blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.ts
|
|
3300
3509
|
function calculateEventRegistrationPreviewTotal(input) {
|
|
3301
3510
|
const discountCents = input.manualDiscountCode.trim() ? 0 : input.automaticDiscount?.computedAmountCents ?? 0;
|
|
@@ -3325,49 +3534,203 @@ function buildEventRegistrationSiteCreditPreview(input) {
|
|
|
3325
3534
|
creditCurrencyMatches: true,
|
|
3326
3535
|
minimumStripeChargeCents: minimumChargeCents
|
|
3327
3536
|
});
|
|
3328
|
-
const appliedCreditCents = plan.reserveCreditCents;
|
|
3329
|
-
return {
|
|
3330
|
-
kind: "applied",
|
|
3331
|
-
outcome: plan.kind === "store_credit_only" ? "credit_only" : "mixed",
|
|
3332
|
-
availableCreditCents: summary.availableCents,
|
|
3333
|
-
appliedCreditCents,
|
|
3334
|
-
cardDueNowCents: Math.max(0, input.option.totalCents - appliedCreditCents),
|
|
3335
|
-
laterBalanceCents: 0,
|
|
3336
|
-
remainingCreditCents: Math.max(0, summary.availableCents - appliedCreditCents),
|
|
3337
|
-
manualDiscountPending: input.manualDiscountPending
|
|
3338
|
-
};
|
|
3537
|
+
const appliedCreditCents = plan.reserveCreditCents;
|
|
3538
|
+
return {
|
|
3539
|
+
kind: "applied",
|
|
3540
|
+
outcome: plan.kind === "store_credit_only" ? "credit_only" : "mixed",
|
|
3541
|
+
availableCreditCents: summary.availableCents,
|
|
3542
|
+
appliedCreditCents,
|
|
3543
|
+
cardDueNowCents: Math.max(0, input.option.totalCents - appliedCreditCents),
|
|
3544
|
+
laterBalanceCents: 0,
|
|
3545
|
+
remainingCreditCents: Math.max(0, summary.availableCents - appliedCreditCents),
|
|
3546
|
+
manualDiscountPending: input.manualDiscountPending
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
const plan = planFlexibleBalanceCreditFirst({
|
|
3550
|
+
totalAfterDiscountCents: input.option.totalCents,
|
|
3551
|
+
configuredPaymentDueNowCents: input.option.configuredPaymentDueNowCents,
|
|
3552
|
+
availableCreditCents: summary.availableCents,
|
|
3553
|
+
creditCurrencyMatches: true,
|
|
3554
|
+
minimumStripeChargeCents: minimumChargeCents
|
|
3555
|
+
});
|
|
3556
|
+
if (plan.kind === "card_below_minimum") return { kind: "not_applicable" };
|
|
3557
|
+
return {
|
|
3558
|
+
kind: "applied",
|
|
3559
|
+
outcome: plan.kind === "credit_only" ? "credit_only" : "mixed",
|
|
3560
|
+
availableCreditCents: summary.availableCents,
|
|
3561
|
+
appliedCreditCents: plan.reserveCreditCents,
|
|
3562
|
+
cardDueNowCents: plan.cardDueNowCents,
|
|
3563
|
+
laterBalanceCents: plan.laterBalanceCents,
|
|
3564
|
+
remainingCreditCents: Math.max(0, summary.availableCents - plan.reserveCreditCents),
|
|
3565
|
+
manualDiscountPending: input.manualDiscountPending
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
function buildSelectedSiteCreditPreview(input) {
|
|
3569
|
+
if (!input.eligibility) return { kind: "unavailable" };
|
|
3570
|
+
const selectedKind = input.selectionState.kind === "valid" ? input.selectionState.selection.collectionOptionKind : null;
|
|
3571
|
+
const option = input.options.find((candidate) => candidate.kind === selectedKind) ?? null;
|
|
3572
|
+
return buildEventRegistrationSiteCreditPreview({
|
|
3573
|
+
...input,
|
|
3574
|
+
currency: input.eligibility.currency,
|
|
3575
|
+
option
|
|
3576
|
+
});
|
|
3577
|
+
}
|
|
3578
|
+
//#endregion
|
|
3579
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/PaymentBlockingPanel.tsx
|
|
3580
|
+
function resolvePaymentStepStatus(input) {
|
|
3581
|
+
if (input.loading) return "loading";
|
|
3582
|
+
if (input.error || !input.eligibility) return "error";
|
|
3583
|
+
if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
|
|
3584
|
+
return "ready";
|
|
3585
|
+
}
|
|
3586
|
+
function shouldPromptForLogin(status, isAuthenticated, eligibility) {
|
|
3587
|
+
return Boolean(status === "not-eligible" && !isAuthenticated && eligibility && (eligibility.requiresAuthForPasses || eligibility.requiresAuthForMemberships));
|
|
3588
|
+
}
|
|
3589
|
+
function MissingEligibilityPanel() {
|
|
3590
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3591
|
+
className: "rb-reg-stack er-stack",
|
|
3592
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
3593
|
+
className: "er-center",
|
|
3594
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
3595
|
+
className: "er-text er-text--error",
|
|
3596
|
+
children: "We couldn’t load the booking options for this event. Please refresh this page and try again. If this keeps happening, contact the organiser for help."
|
|
3597
|
+
})
|
|
3598
|
+
})
|
|
3599
|
+
});
|
|
3600
|
+
}
|
|
3601
|
+
function UnavailableEntitlementMessage(props) {
|
|
3602
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3603
|
+
/* @__PURE__ */ jsx("p", {
|
|
3604
|
+
className: "er-text er-text--error",
|
|
3605
|
+
children: "This event requires a valid pass or membership to register."
|
|
3606
|
+
}),
|
|
3607
|
+
props.eligibility.eventAcceptsPasses && !props.eligibility.eventAcceptsMemberships && /* @__PURE__ */ jsx("p", {
|
|
3608
|
+
className: "er-text er-text--muted",
|
|
3609
|
+
children: "You need a pass with credits for this event category."
|
|
3610
|
+
}),
|
|
3611
|
+
props.eligibility.eventAcceptsMemberships && !props.eligibility.eventAcceptsPasses && /* @__PURE__ */ jsx("p", {
|
|
3612
|
+
className: "er-text er-text--muted",
|
|
3613
|
+
children: "You need an active membership for this event category."
|
|
3614
|
+
})
|
|
3615
|
+
] });
|
|
3616
|
+
}
|
|
3617
|
+
function IneligiblePaymentPanel(props) {
|
|
3618
|
+
if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
|
|
3619
|
+
className: "rb-reg-stack er-stack",
|
|
3620
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3621
|
+
className: "er-title",
|
|
3622
|
+
children: "Sold Out"
|
|
3623
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3624
|
+
className: "er-center",
|
|
3625
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
3626
|
+
className: "er-text er-text--muted",
|
|
3627
|
+
children: "This event is fully booked and there is no waitlist available for this booking."
|
|
3628
|
+
})
|
|
3629
|
+
})]
|
|
3630
|
+
});
|
|
3631
|
+
const promptLogin = shouldPromptForLogin("not-eligible", props.isAuthenticated, props.eligibility);
|
|
3632
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3633
|
+
className: "rb-reg-stack er-stack",
|
|
3634
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3635
|
+
className: "er-title",
|
|
3636
|
+
children: promptLogin ? "Log In Required" : "Payment Required"
|
|
3637
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3638
|
+
className: "er-center",
|
|
3639
|
+
children: promptLogin ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3640
|
+
/* @__PURE__ */ jsx("p", {
|
|
3641
|
+
className: "er-text er-text--muted",
|
|
3642
|
+
children: "Have a pass or membership? Log in to use it."
|
|
3643
|
+
}),
|
|
3644
|
+
/* @__PURE__ */ jsx("button", {
|
|
3645
|
+
type: "button",
|
|
3646
|
+
className: themeButtonClassName({
|
|
3647
|
+
variant: "primary",
|
|
3648
|
+
size: "md"
|
|
3649
|
+
}),
|
|
3650
|
+
disabled: !props.email.trim(),
|
|
3651
|
+
onClick: props.onRequestLogin,
|
|
3652
|
+
children: "Email me a login link"
|
|
3653
|
+
}),
|
|
3654
|
+
!props.email.trim() && /* @__PURE__ */ jsx("p", {
|
|
3655
|
+
className: "er-text er-text--muted",
|
|
3656
|
+
children: "Enter your email to request a login link."
|
|
3657
|
+
})
|
|
3658
|
+
] }) : /* @__PURE__ */ jsx(UnavailableEntitlementMessage, { eligibility: props.eligibility })
|
|
3659
|
+
})]
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
function PaymentBlockingPanel(props) {
|
|
3663
|
+
if (props.eligibilityLoading) return /* @__PURE__ */ jsx("div", {
|
|
3664
|
+
className: "rb-reg-stack er-stack",
|
|
3665
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3666
|
+
className: "er-center",
|
|
3667
|
+
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
3668
|
+
size: "lg",
|
|
3669
|
+
srLabel: "Checking payment options"
|
|
3670
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3671
|
+
className: "er-text--muted",
|
|
3672
|
+
children: "Checking payment options..."
|
|
3673
|
+
})]
|
|
3674
|
+
})
|
|
3675
|
+
});
|
|
3676
|
+
if (props.eligibilityError) return /* @__PURE__ */ jsx("div", {
|
|
3677
|
+
className: "rb-reg-stack er-stack",
|
|
3678
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
3679
|
+
className: "er-center",
|
|
3680
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
3681
|
+
className: "er-text er-text--error",
|
|
3682
|
+
children: props.eligibilityError
|
|
3683
|
+
})
|
|
3684
|
+
})
|
|
3685
|
+
});
|
|
3686
|
+
if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {});
|
|
3687
|
+
if (props.eligibility.registration.kind !== "none") {
|
|
3688
|
+
const isBooked = props.eligibility.registration.kind === "booked";
|
|
3689
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3690
|
+
className: "rb-reg-stack er-stack",
|
|
3691
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3692
|
+
className: "er-title",
|
|
3693
|
+
children: isBooked ? "Already booked" : "Already on the waitlist"
|
|
3694
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3695
|
+
className: "er-center",
|
|
3696
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
3697
|
+
className: "er-text er-text--muted",
|
|
3698
|
+
children: isBooked ? "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser." : "You're already on the waitlist for this event."
|
|
3699
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
3700
|
+
href: "/portal",
|
|
3701
|
+
className: "er-retry-btn",
|
|
3702
|
+
children: "View my bookings"
|
|
3703
|
+
})]
|
|
3704
|
+
})]
|
|
3705
|
+
});
|
|
3339
3706
|
}
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3707
|
+
if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
|
|
3708
|
+
className: "rb-reg-stack er-stack",
|
|
3709
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
3710
|
+
className: "er-title",
|
|
3711
|
+
children: "Payment"
|
|
3712
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3713
|
+
className: "er-payment-summary",
|
|
3714
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
3715
|
+
className: "er-text er-text--success",
|
|
3716
|
+
children: "This event is free!"
|
|
3717
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
3718
|
+
className: "er-text er-text--muted",
|
|
3719
|
+
children: [
|
|
3720
|
+
props.ticketsCount,
|
|
3721
|
+
" ticket",
|
|
3722
|
+
props.ticketsCount > 1 ? "s" : ""
|
|
3723
|
+
]
|
|
3724
|
+
})]
|
|
3725
|
+
})]
|
|
3346
3726
|
});
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
appliedCreditCents: plan.reserveCreditCents,
|
|
3353
|
-
cardDueNowCents: plan.cardDueNowCents,
|
|
3354
|
-
laterBalanceCents: plan.laterBalanceCents,
|
|
3355
|
-
remainingCreditCents: Math.max(0, summary.availableCents - plan.reserveCreditCents),
|
|
3356
|
-
manualDiscountPending: input.manualDiscountPending
|
|
3357
|
-
};
|
|
3358
|
-
}
|
|
3359
|
-
function buildSelectedSiteCreditPreview(input) {
|
|
3360
|
-
const selectedKind = input.selectionState.kind === "valid" ? input.selectionState.selection.collectionOptionKind : null;
|
|
3361
|
-
const option = input.options.find((candidate) => candidate.kind === selectedKind) ?? null;
|
|
3362
|
-
return buildEventRegistrationSiteCreditPreview({
|
|
3363
|
-
...input,
|
|
3364
|
-
currency: input.eligibility?.currency ?? "GBP",
|
|
3365
|
-
option
|
|
3727
|
+
return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
|
|
3728
|
+
eligibility: props.eligibility,
|
|
3729
|
+
email: props.email,
|
|
3730
|
+
isAuthenticated: props.isAuthenticated,
|
|
3731
|
+
onRequestLogin: props.onRequestLogin
|
|
3366
3732
|
});
|
|
3367
3733
|
}
|
|
3368
|
-
function resolveDirectPaymentTotalCents(explicitTotalCents, eligibility) {
|
|
3369
|
-
return explicitTotalCents ?? eligibility?.price ?? 0;
|
|
3370
|
-
}
|
|
3371
3734
|
//#endregion
|
|
3372
3735
|
//#region ../blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.tsx
|
|
3373
3736
|
function pluralizeBookingUnit(kind, quantity) {
|
|
@@ -3409,9 +3772,16 @@ function TicketCounter(props) {
|
|
|
3409
3772
|
});
|
|
3410
3773
|
}
|
|
3411
3774
|
function TicketCounterLimit(props) {
|
|
3775
|
+
const showBookingLimit = !props.availabilityLabel || props.maxAllowed < (props.availableSpots ?? Infinity);
|
|
3412
3776
|
return /* @__PURE__ */ jsxs("p", {
|
|
3413
3777
|
className: "er-ticket-counter-limit",
|
|
3414
|
-
children: [/* @__PURE__ */ jsx("span", { children: props.
|
|
3778
|
+
children: [props.availabilityLabel ? /* @__PURE__ */ jsx("span", { children: props.availabilityLabel }) : null, showBookingLimit ? /* @__PURE__ */ jsxs(Fragment, { children: [props.availabilityLabel ? /* @__PURE__ */ jsx("br", {}) : null, /* @__PURE__ */ jsxs("span", { children: [
|
|
3779
|
+
"Up to ",
|
|
3780
|
+
props.maxAllowed,
|
|
3781
|
+
" ",
|
|
3782
|
+
props.quantityLabel,
|
|
3783
|
+
" per booking."
|
|
3784
|
+
] })] }) : null]
|
|
3415
3785
|
});
|
|
3416
3786
|
}
|
|
3417
3787
|
function BookingUnitSessionHint(props) {
|
|
@@ -3427,7 +3797,7 @@ function BookingUnitSessionHint(props) {
|
|
|
3427
3797
|
}
|
|
3428
3798
|
function bookingQuantityLabel(unit, waitlist) {
|
|
3429
3799
|
if (!waitlist) return pluralizeBookingUnit(unit, 2);
|
|
3430
|
-
return
|
|
3800
|
+
return "waitlist places";
|
|
3431
3801
|
}
|
|
3432
3802
|
function BookingQuantityPrompt(props) {
|
|
3433
3803
|
return /* @__PURE__ */ jsxs("h3", {
|
|
@@ -3486,6 +3856,7 @@ function SlidingScaleAmountField(props) {
|
|
|
3486
3856
|
}
|
|
3487
3857
|
function TicketTypeQuantityRows(props) {
|
|
3488
3858
|
const totalSelectedQuantity = getTicketSelectionTotal(props.ticketSelections);
|
|
3859
|
+
const effectiveMaxTickets = props.availableSpots == null ? props.maxTickets : Math.min(props.maxTickets, props.availableSpots);
|
|
3489
3860
|
return /* @__PURE__ */ jsxs("div", {
|
|
3490
3861
|
className: "er-ticket-lines",
|
|
3491
3862
|
children: [
|
|
@@ -3494,16 +3865,17 @@ function TicketTypeQuantityRows(props) {
|
|
|
3494
3865
|
role: "list",
|
|
3495
3866
|
"aria-label": props.bookingUnit === "place" ? "Places" : "Tickets",
|
|
3496
3867
|
children: props.ticketTypes.map((ticketType) => {
|
|
3497
|
-
const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.
|
|
3868
|
+
const quantity = getTicketLineQuantity(props.ticketSelections, ticketType.pricingOptionId);
|
|
3498
3869
|
const disabled = ticketType.availability.kind === "unavailable";
|
|
3499
3870
|
const availabilityLabel = getTicketTypeAvailabilityLabel(ticketType);
|
|
3871
|
+
const ticketTypeRemainingLabel = formatTicketTypeRemaining(ticketType.availability.remainingPlaces);
|
|
3500
3872
|
const priceLabel = ticketType.priceAmount > 0 ? formatPrice(ticketType.priceAmount, props.currency) : "Free";
|
|
3501
3873
|
const maxAllowed = disabled ? 0 : getTicketTypeLineMax({
|
|
3502
3874
|
currentQuantity: quantity,
|
|
3503
3875
|
totalSelectedQuantity,
|
|
3504
3876
|
maxTickets: props.maxTickets,
|
|
3505
3877
|
availableSpots: props.availableSpots,
|
|
3506
|
-
ticketTypeRemainingCapacity: ticketType.availability.
|
|
3878
|
+
ticketTypeRemainingCapacity: ticketType.availability.remainingPlaces
|
|
3507
3879
|
});
|
|
3508
3880
|
return /* @__PURE__ */ jsxs("div", {
|
|
3509
3881
|
className: `er-ticket-line${disabled ? " er-ticket-line--disabled" : ""}`,
|
|
@@ -3528,9 +3900,9 @@ function TicketTypeQuantityRows(props) {
|
|
|
3528
3900
|
availabilityLabel ? /* @__PURE__ */ jsx("p", {
|
|
3529
3901
|
className: "er-ticket-line-detail",
|
|
3530
3902
|
children: availabilityLabel
|
|
3531
|
-
}) :
|
|
3903
|
+
}) : ticketTypeRemainingLabel ? /* @__PURE__ */ jsx("p", {
|
|
3532
3904
|
className: "er-ticket-line-detail",
|
|
3533
|
-
children:
|
|
3905
|
+
children: ticketTypeRemainingLabel
|
|
3534
3906
|
}) : null
|
|
3535
3907
|
]
|
|
3536
3908
|
}), /* @__PURE__ */ jsx(TicketCounter, {
|
|
@@ -3541,17 +3913,19 @@ function TicketTypeQuantityRows(props) {
|
|
|
3541
3913
|
onTicketsChange: (nextQuantity) => {
|
|
3542
3914
|
props.onTicketSelectionsChange?.(setTicketLineQuantity({
|
|
3543
3915
|
lines: props.ticketSelections,
|
|
3544
|
-
|
|
3916
|
+
pricingOptionId: ticketType.pricingOptionId,
|
|
3545
3917
|
quantity: nextQuantity
|
|
3546
3918
|
}));
|
|
3547
3919
|
}
|
|
3548
3920
|
})]
|
|
3549
|
-
}, ticketType.
|
|
3921
|
+
}, ticketType.pricingOptionId);
|
|
3550
3922
|
})
|
|
3551
3923
|
}),
|
|
3552
3924
|
/* @__PURE__ */ jsx(TicketCounterLimit, {
|
|
3553
|
-
|
|
3554
|
-
|
|
3925
|
+
maxAllowed: effectiveMaxTickets,
|
|
3926
|
+
quantityLabel: pluralizeBookingUnit(props.bookingUnit, effectiveMaxTickets),
|
|
3927
|
+
availableSpots: props.availableSpots,
|
|
3928
|
+
availabilityLabel: props.availabilityLabel
|
|
3555
3929
|
}),
|
|
3556
3930
|
totalSelectedQuantity === 0 && props.hasAvailableTicketTypes ? /* @__PURE__ */ jsxs("p", {
|
|
3557
3931
|
className: "er-text er-text--muted",
|
|
@@ -3572,9 +3946,13 @@ function TicketTypeQuantityRows(props) {
|
|
|
3572
3946
|
});
|
|
3573
3947
|
}
|
|
3574
3948
|
function getAttendanceModeDetail(attendanceMode) {
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3949
|
+
const remaining = getRemainingPlaces(attendanceMode);
|
|
3950
|
+
switch (remaining.kind) {
|
|
3951
|
+
case "unlimited": return "Unlimited places";
|
|
3952
|
+
case "open": return "Places available";
|
|
3953
|
+
case "low": return formatRemainingPlaces(attendanceMode);
|
|
3954
|
+
case "full": return remaining.waitlist ? "Currently full, waitlist available" : "Currently full";
|
|
3955
|
+
}
|
|
3578
3956
|
}
|
|
3579
3957
|
function AttendanceModeTiles(props) {
|
|
3580
3958
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -3608,6 +3986,12 @@ function getMaxAllowedTicketCount(input) {
|
|
|
3608
3986
|
if (!input.hasSelectedTicketType) return 1;
|
|
3609
3987
|
return Math.max(1, Math.min(input.maxTickets, input.selectedTicketTypeRemainingCapacity ?? input.maxTickets, input.availableSpots ?? input.maxTickets));
|
|
3610
3988
|
}
|
|
3989
|
+
function resolveTicketSelectionPricing(event) {
|
|
3990
|
+
return {
|
|
3991
|
+
mode: event ? publicEventPricingStrategy(event.pricing) : void 0,
|
|
3992
|
+
currency: event ? publicEventPricingCurrency(event.pricing) : null
|
|
3993
|
+
};
|
|
3994
|
+
}
|
|
3611
3995
|
/**
|
|
3612
3996
|
* Ticket Selection Step
|
|
3613
3997
|
*
|
|
@@ -3620,15 +4004,13 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3620
4004
|
const unit = bookingUnit.kind;
|
|
3621
4005
|
const deliveryMode = event?.deliveryMode ?? "in_person";
|
|
3622
4006
|
const attendanceModes = event?.attendanceModes ?? [];
|
|
3623
|
-
const
|
|
3624
|
-
const
|
|
3625
|
-
const
|
|
3626
|
-
const isSoldOut =
|
|
3627
|
-
const canJoinWaitlist =
|
|
3628
|
-
const
|
|
3629
|
-
const
|
|
3630
|
-
const eventPricingCurrency = eventPricing ? publicEventPricingCurrency(eventPricing) : null;
|
|
3631
|
-
const usesTicketTypes = eventPricingMode === "ticket_types" && !canJoinWaitlist;
|
|
4007
|
+
const capacitySource = event ? selectEventCapacitySource(event, selectedAttendanceMode) : null;
|
|
4008
|
+
const availability = capacitySource ? getEventAvailability(capacitySource) : null;
|
|
4009
|
+
const availableSpots = availability?.available;
|
|
4010
|
+
const isSoldOut = availability?.isFull ?? false;
|
|
4011
|
+
const canJoinWaitlist = capacitySource ? canJoinEventWaitlist(capacitySource) : false;
|
|
4012
|
+
const { mode: eventPricingMode, currency: eventPricingCurrency } = resolveTicketSelectionPricing(event);
|
|
4013
|
+
const usesTicketTypes = eventPricingMode === "tiered" && !canJoinWaitlist;
|
|
3632
4014
|
const visibleTicketTypes = usesTicketTypes ? visibleTicketTypesOverride ?? getVisibleTicketTypes({
|
|
3633
4015
|
event,
|
|
3634
4016
|
eligibility: null,
|
|
@@ -3642,10 +4024,10 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3642
4024
|
usesTicketTypes,
|
|
3643
4025
|
maxTickets,
|
|
3644
4026
|
availableSpots,
|
|
3645
|
-
selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.
|
|
4027
|
+
selectedTicketTypeRemainingCapacity: implicitTicketType?.availability.remainingPlaces ?? null,
|
|
3646
4028
|
hasSelectedTicketType: implicitTicketType !== null
|
|
3647
4029
|
});
|
|
3648
|
-
const eventAvailabilityLabel = !canJoinWaitlist &&
|
|
4030
|
+
const eventAvailabilityLabel = !canJoinWaitlist && capacitySource ? formatRemainingPlaces(capacitySource) : null;
|
|
3649
4031
|
if (deliveryMode === "hybrid" && !selectedAttendanceMode) return /* @__PURE__ */ jsxs("div", {
|
|
3650
4032
|
className: "rb-reg-stack er-stack",
|
|
3651
4033
|
children: [
|
|
@@ -3668,12 +4050,19 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3668
4050
|
className: "rb-reg-stack er-stack",
|
|
3669
4051
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
3670
4052
|
className: "er-title",
|
|
3671
|
-
children: "Sold
|
|
4053
|
+
children: "Sold out"
|
|
3672
4054
|
}), /* @__PURE__ */ jsx("p", {
|
|
3673
4055
|
className: "er-text er-text--muted",
|
|
3674
4056
|
children: "Sorry you missed out! This event is fully booked."
|
|
3675
4057
|
})]
|
|
3676
4058
|
});
|
|
4059
|
+
if (!eventPricingCurrency) return /* @__PURE__ */ jsx("div", {
|
|
4060
|
+
className: "rb-reg-stack er-stack",
|
|
4061
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
4062
|
+
className: "er-text er-text--muted",
|
|
4063
|
+
children: "Pricing is unavailable for this event right now."
|
|
4064
|
+
})
|
|
4065
|
+
});
|
|
3677
4066
|
return /* @__PURE__ */ jsxs("div", {
|
|
3678
4067
|
className: "rb-reg-stack er-stack",
|
|
3679
4068
|
children: [
|
|
@@ -3699,7 +4088,8 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3699
4088
|
ticketSelections,
|
|
3700
4089
|
maxTickets,
|
|
3701
4090
|
availableSpots,
|
|
3702
|
-
|
|
4091
|
+
availabilityLabel: eventAvailabilityLabel,
|
|
4092
|
+
currency: eventPricingCurrency,
|
|
3703
4093
|
hasAvailableTicketTypes,
|
|
3704
4094
|
onTicketSelectionsChange,
|
|
3705
4095
|
bookingUnit: unit
|
|
@@ -3707,7 +4097,7 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3707
4097
|
] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3708
4098
|
slidingScale ? /* @__PURE__ */ jsx(SlidingScaleAmountField, {
|
|
3709
4099
|
slidingScale,
|
|
3710
|
-
currency: eventPricingCurrency
|
|
4100
|
+
currency: eventPricingCurrency,
|
|
3711
4101
|
value: selectedSlidingAmountInput,
|
|
3712
4102
|
message: slidingScaleSelectionMessage,
|
|
3713
4103
|
onChange: onSlidingAmountChange
|
|
@@ -3725,14 +4115,16 @@ const TicketSelectionStep = ({ event, occurrenceContext: _occurrenceContext, sel
|
|
|
3725
4115
|
label: bookingQuantityLabel(unit, canJoinWaitlist),
|
|
3726
4116
|
onTicketsChange
|
|
3727
4117
|
}), /* @__PURE__ */ jsx(TicketCounterLimit, {
|
|
3728
|
-
|
|
4118
|
+
maxAllowed,
|
|
4119
|
+
quantityLabel: canJoinWaitlist ? bookingQuantityLabel(unit, true) : pluralizeBookingUnit(unit, maxAllowed),
|
|
4120
|
+
availableSpots: canJoinWaitlist ? null : availableSpots,
|
|
3729
4121
|
availabilityLabel: eventAvailabilityLabel
|
|
3730
4122
|
})]
|
|
3731
4123
|
})
|
|
3732
4124
|
] }),
|
|
3733
4125
|
canJoinWaitlist && /* @__PURE__ */ jsx("p", {
|
|
3734
4126
|
className: "er-text er-text--muted",
|
|
3735
|
-
children: "This event is currently full. Continue to join the waitlist if a
|
|
4127
|
+
children: "This event is currently full. Continue to join the waitlist if a place opens up."
|
|
3736
4128
|
})
|
|
3737
4129
|
]
|
|
3738
4130
|
});
|
|
@@ -4204,162 +4596,6 @@ function SiteCreditPreviewPanel(props) {
|
|
|
4204
4596
|
});
|
|
4205
4597
|
}
|
|
4206
4598
|
//#endregion
|
|
4207
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/PaymentBlockingPanel.tsx
|
|
4208
|
-
function resolvePaymentStepStatus(input) {
|
|
4209
|
-
if (input.loading) return "loading";
|
|
4210
|
-
if (input.error || !input.eligibility) return "error";
|
|
4211
|
-
if (input.eligibility.registration.kind !== "none" || !input.eligibility.eligible && !input.eligibility.isFree) return "not-eligible";
|
|
4212
|
-
return "ready";
|
|
4213
|
-
}
|
|
4214
|
-
function shouldPromptForLogin(status, isAuthenticated, eligibility) {
|
|
4215
|
-
return Boolean(status === "not-eligible" && !isAuthenticated && eligibility && (eligibility.requiresAuthForPasses || eligibility.requiresAuthForMemberships));
|
|
4216
|
-
}
|
|
4217
|
-
function MissingEligibilityPanel(props) {
|
|
4218
|
-
const missing = [!props.occurrenceId && "occurrenceId", !props.email && "email"].filter((part) => Boolean(part));
|
|
4219
|
-
return /* @__PURE__ */ jsx("div", {
|
|
4220
|
-
className: "rb-reg-stack er-stack",
|
|
4221
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
4222
|
-
className: "er-center",
|
|
4223
|
-
children: /* @__PURE__ */ jsxs("p", {
|
|
4224
|
-
className: "er-text er-text--error",
|
|
4225
|
-
children: ["Unable to determine payment options", missing.length > 0 && ` (missing: ${missing.join(", ")})`]
|
|
4226
|
-
})
|
|
4227
|
-
})
|
|
4228
|
-
});
|
|
4229
|
-
}
|
|
4230
|
-
function UnavailableEntitlementMessage(props) {
|
|
4231
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4232
|
-
/* @__PURE__ */ jsx("p", {
|
|
4233
|
-
className: "er-text er-text--error",
|
|
4234
|
-
children: "This event requires a valid pass or membership to register."
|
|
4235
|
-
}),
|
|
4236
|
-
props.eligibility.eventAcceptsPasses && !props.eligibility.eventAcceptsMemberships && /* @__PURE__ */ jsx("p", {
|
|
4237
|
-
className: "er-text er-text--muted",
|
|
4238
|
-
children: "You need a pass with credits for this event category."
|
|
4239
|
-
}),
|
|
4240
|
-
props.eligibility.eventAcceptsMemberships && !props.eligibility.eventAcceptsPasses && /* @__PURE__ */ jsx("p", {
|
|
4241
|
-
className: "er-text er-text--muted",
|
|
4242
|
-
children: "You need an active membership for this event category."
|
|
4243
|
-
})
|
|
4244
|
-
] });
|
|
4245
|
-
}
|
|
4246
|
-
function IneligiblePaymentPanel(props) {
|
|
4247
|
-
if (props.eligibility.isFull && !props.eligibility.canJoinWaitlist) return /* @__PURE__ */ jsxs("div", {
|
|
4248
|
-
className: "rb-reg-stack er-stack",
|
|
4249
|
-
children: [/* @__PURE__ */ jsx("h3", {
|
|
4250
|
-
className: "er-title",
|
|
4251
|
-
children: "Sold Out"
|
|
4252
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
4253
|
-
className: "er-center",
|
|
4254
|
-
children: /* @__PURE__ */ jsx("p", {
|
|
4255
|
-
className: "er-text er-text--muted",
|
|
4256
|
-
children: "This event is fully booked and there is no waitlist available for this booking."
|
|
4257
|
-
})
|
|
4258
|
-
})]
|
|
4259
|
-
});
|
|
4260
|
-
const promptLogin = shouldPromptForLogin("not-eligible", props.isAuthenticated, props.eligibility);
|
|
4261
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
4262
|
-
className: "rb-reg-stack er-stack",
|
|
4263
|
-
children: [/* @__PURE__ */ jsx("h3", {
|
|
4264
|
-
className: "er-title",
|
|
4265
|
-
children: promptLogin ? "Log In Required" : "Payment Required"
|
|
4266
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
4267
|
-
className: "er-center",
|
|
4268
|
-
children: promptLogin ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4269
|
-
/* @__PURE__ */ jsx("p", {
|
|
4270
|
-
className: "er-text er-text--muted",
|
|
4271
|
-
children: "Have a pass or membership? Log in to use it."
|
|
4272
|
-
}),
|
|
4273
|
-
/* @__PURE__ */ jsx("button", {
|
|
4274
|
-
type: "button",
|
|
4275
|
-
className: themeButtonClassName({
|
|
4276
|
-
variant: "primary",
|
|
4277
|
-
size: "md"
|
|
4278
|
-
}),
|
|
4279
|
-
disabled: !props.email.trim(),
|
|
4280
|
-
onClick: props.onRequestLogin,
|
|
4281
|
-
children: "Email me a login link"
|
|
4282
|
-
}),
|
|
4283
|
-
!props.email.trim() && /* @__PURE__ */ jsx("p", {
|
|
4284
|
-
className: "er-text er-text--muted",
|
|
4285
|
-
children: "Enter your email to request a login link."
|
|
4286
|
-
})
|
|
4287
|
-
] }) : /* @__PURE__ */ jsx(UnavailableEntitlementMessage, { eligibility: props.eligibility })
|
|
4288
|
-
})]
|
|
4289
|
-
});
|
|
4290
|
-
}
|
|
4291
|
-
function PaymentBlockingPanel(props) {
|
|
4292
|
-
if (props.eligibilityLoading) return /* @__PURE__ */ jsx("div", {
|
|
4293
|
-
className: "rb-reg-stack er-stack",
|
|
4294
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
4295
|
-
className: "er-center",
|
|
4296
|
-
children: [/* @__PURE__ */ jsx(SpinnerNode, {
|
|
4297
|
-
size: "lg",
|
|
4298
|
-
srLabel: "Checking payment options"
|
|
4299
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
4300
|
-
className: "er-text--muted",
|
|
4301
|
-
children: "Checking payment options..."
|
|
4302
|
-
})]
|
|
4303
|
-
})
|
|
4304
|
-
});
|
|
4305
|
-
if (props.eligibilityError) return /* @__PURE__ */ jsx("div", {
|
|
4306
|
-
className: "rb-reg-stack er-stack",
|
|
4307
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
4308
|
-
className: "er-center",
|
|
4309
|
-
children: /* @__PURE__ */ jsx("p", {
|
|
4310
|
-
className: "er-text er-text--error",
|
|
4311
|
-
children: props.eligibilityError
|
|
4312
|
-
})
|
|
4313
|
-
})
|
|
4314
|
-
});
|
|
4315
|
-
if (!props.eligibility) return /* @__PURE__ */ jsx(MissingEligibilityPanel, {
|
|
4316
|
-
occurrenceId: props.occurrenceId,
|
|
4317
|
-
email: props.email
|
|
4318
|
-
});
|
|
4319
|
-
if (props.eligibility.registration.kind !== "none") {
|
|
4320
|
-
const isBooked = props.eligibility.registration.kind === "booked";
|
|
4321
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
4322
|
-
className: "rb-reg-stack er-stack",
|
|
4323
|
-
children: [/* @__PURE__ */ jsx("h3", {
|
|
4324
|
-
className: "er-title",
|
|
4325
|
-
children: isBooked ? "Already booked" : "Already on the waitlist"
|
|
4326
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
4327
|
-
className: "er-center",
|
|
4328
|
-
children: /* @__PURE__ */ jsx("p", {
|
|
4329
|
-
className: "er-text er-text--muted",
|
|
4330
|
-
children: isBooked ? "You're already booked on this event." : "You're already on the waitlist for this event."
|
|
4331
|
-
})
|
|
4332
|
-
})]
|
|
4333
|
-
});
|
|
4334
|
-
}
|
|
4335
|
-
if (props.eligibility.isFree) return /* @__PURE__ */ jsxs("div", {
|
|
4336
|
-
className: "rb-reg-stack er-stack",
|
|
4337
|
-
children: [/* @__PURE__ */ jsx("h3", {
|
|
4338
|
-
className: "er-title",
|
|
4339
|
-
children: "Payment"
|
|
4340
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
4341
|
-
className: "er-payment-summary",
|
|
4342
|
-
children: [/* @__PURE__ */ jsx("p", {
|
|
4343
|
-
className: "er-text er-text--success",
|
|
4344
|
-
children: "This event is free!"
|
|
4345
|
-
}), /* @__PURE__ */ jsxs("p", {
|
|
4346
|
-
className: "er-text er-text--muted",
|
|
4347
|
-
children: [
|
|
4348
|
-
props.ticketsCount,
|
|
4349
|
-
" ticket",
|
|
4350
|
-
props.ticketsCount > 1 ? "s" : ""
|
|
4351
|
-
]
|
|
4352
|
-
})]
|
|
4353
|
-
})]
|
|
4354
|
-
});
|
|
4355
|
-
return props.eligibility.eligible ? null : /* @__PURE__ */ jsx(IneligiblePaymentPanel, {
|
|
4356
|
-
eligibility: props.eligibility,
|
|
4357
|
-
email: props.email,
|
|
4358
|
-
isAuthenticated: props.isAuthenticated,
|
|
4359
|
-
onRequestLogin: props.onRequestLogin
|
|
4360
|
-
});
|
|
4361
|
-
}
|
|
4362
|
-
//#endregion
|
|
4363
4599
|
//#region ../blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.tsx
|
|
4364
4600
|
/**
|
|
4365
4601
|
* Payment Selection Step Component
|
|
@@ -4448,12 +4684,12 @@ function DirectPaymentTiles(props) {
|
|
|
4448
4684
|
* names the pass instead of describing the step.
|
|
4449
4685
|
*/
|
|
4450
4686
|
function resolvePaymentButtonText(method, siteCreditPreview, eligibility, selectedDirectOption) {
|
|
4451
|
-
const currency = eligibility?.currency ?? "GBP";
|
|
4452
4687
|
switch (method) {
|
|
4453
4688
|
case "stripe":
|
|
4454
|
-
if (siteCreditPreview.kind !== "applied") return selectedDirectOption?.ctaLabel ?? "Continue to
|
|
4455
|
-
if (
|
|
4456
|
-
return `
|
|
4689
|
+
if (siteCreditPreview.kind !== "applied") return selectedDirectOption?.ctaLabel ?? "Continue to payment";
|
|
4690
|
+
if (!eligibility) return "Continue to Payment";
|
|
4691
|
+
if (siteCreditPreview.cardDueNowCents > 0) return `Pay ${formatPrice(siteCreditPreview.cardDueNowCents, eligibility.currency)} by card`;
|
|
4692
|
+
return `Book with ${formatPrice(siteCreditPreview.appliedCreditCents, eligibility.currency)} site credit`;
|
|
4457
4693
|
case "pass": return "Book using class pass";
|
|
4458
4694
|
case "pass_bundle":
|
|
4459
4695
|
case "membership_bundle": return "Purchase & Register";
|
|
@@ -4483,7 +4719,7 @@ function canContinueWithPaymentSelection(selection, directPaymentSelection) {
|
|
|
4483
4719
|
const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, isAuthenticated = false, creditState = { kind: "not_authenticated" }, directPaymentTotalCents, manualDiscountPending = false, selectedSelection, onSelectionChange, eligibility, eligibilityLoading, eligibilityError = null, onRequestLogin, onStateChange }) => {
|
|
4484
4720
|
const occurrenceId = occurrenceContext?.id ?? (event?.registrationSubject.kind === "occurrence" ? event.registrationSubject.occurrenceId : "");
|
|
4485
4721
|
const selectedMethod = selectedSelection.method;
|
|
4486
|
-
const totalPrice =
|
|
4722
|
+
const totalPrice = directPaymentTotalCents;
|
|
4487
4723
|
const canShowDirectPaymentOptions = Boolean(eligibility?.eligible && eligibility.canPayDirectly && eligibility.price);
|
|
4488
4724
|
const directPaymentOptions = eligibility && canShowDirectPaymentOptions ? buildEventRegistrationPaymentOptionsViewModel({
|
|
4489
4725
|
eventTitle: event?.title ?? "Event",
|
|
@@ -4491,7 +4727,7 @@ const PaymentSelectionStep = ({ event, occurrenceContext, ticketsCount, email, i
|
|
|
4491
4727
|
paymentTerms: eligibility.paymentTerms,
|
|
4492
4728
|
totalPriceCents: totalPrice,
|
|
4493
4729
|
currency: eligibility.currency,
|
|
4494
|
-
startsAt: occurrenceContext
|
|
4730
|
+
startsAt: getRegistrationStartAt(event, occurrenceContext)
|
|
4495
4731
|
}).options : [];
|
|
4496
4732
|
const directPaymentSelectionState = resolveEventRegistrationDirectPaymentSelection({
|
|
4497
4733
|
options: directPaymentOptions,
|
|
@@ -4724,6 +4960,53 @@ function AttendeeDetailsContent(props) {
|
|
|
4724
4960
|
})
|
|
4725
4961
|
] });
|
|
4726
4962
|
}
|
|
4963
|
+
function PaymentSelectionContent(props) {
|
|
4964
|
+
const { wizard } = props;
|
|
4965
|
+
const subtotalCents = wizard.ticketSelectionSubtotalCents;
|
|
4966
|
+
if (!wizard.api.config.siteId) return null;
|
|
4967
|
+
if (subtotalCents === null) return /* @__PURE__ */ jsx(PaymentBlockingPanel, {
|
|
4968
|
+
eligibility: wizard.eligibility,
|
|
4969
|
+
eligibilityLoading: wizard.eligibilityLoading,
|
|
4970
|
+
eligibilityError: wizard.eligibilityError,
|
|
4971
|
+
occurrenceId: wizard.occurrenceContext?.id ?? "",
|
|
4972
|
+
email: wizard.formData.email,
|
|
4973
|
+
ticketsCount: wizard.ticketsCount,
|
|
4974
|
+
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
4975
|
+
onRequestLogin: () => wizard.setShowMagicLinkModal(true)
|
|
4976
|
+
});
|
|
4977
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PaymentSelectionStep, {
|
|
4978
|
+
event: wizard.selectedEvent,
|
|
4979
|
+
occurrenceContext: wizard.occurrenceContext,
|
|
4980
|
+
ticketsCount: wizard.ticketsCount,
|
|
4981
|
+
email: wizard.formData.email,
|
|
4982
|
+
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
4983
|
+
creditState: wizard.portalCreditState,
|
|
4984
|
+
directPaymentTotalCents: calculateEventRegistrationPreviewTotal({
|
|
4985
|
+
subtotalCents,
|
|
4986
|
+
manualDiscountCode: wizard.discountCode,
|
|
4987
|
+
automaticDiscount: wizard.autoAppliedDiscount
|
|
4988
|
+
}),
|
|
4989
|
+
manualDiscountPending: wizard.discountCode.trim().length > 0,
|
|
4990
|
+
selectedSelection: wizard.paymentSelection,
|
|
4991
|
+
onSelectionChange: wizard.handlePaymentSelectionChange,
|
|
4992
|
+
eligibility: wizard.eligibility,
|
|
4993
|
+
eligibilityLoading: wizard.eligibilityLoading,
|
|
4994
|
+
eligibilityError: wizard.eligibilityError,
|
|
4995
|
+
onRequestLogin: () => wizard.setShowMagicLinkModal(true),
|
|
4996
|
+
onStateChange: wizard.handlePaymentStepStateChange
|
|
4997
|
+
}), wizard.discountsAvailableLoading ? null : wizard.shouldShowDiscountToggle ? /* @__PURE__ */ jsx(DiscountCodeDisclosure, {
|
|
4998
|
+
surface: "event-registration",
|
|
4999
|
+
isOpen: wizard.discountUiOpen,
|
|
5000
|
+
code: wizard.discountCode,
|
|
5001
|
+
onOpen: () => wizard.setDiscountUiOpen(true),
|
|
5002
|
+
onChange: wizard.setDiscountCode,
|
|
5003
|
+
onRemove: () => {
|
|
5004
|
+
wizard.setDiscountCode("");
|
|
5005
|
+
wizard.setDiscountUiOpen(false);
|
|
5006
|
+
},
|
|
5007
|
+
id: "er-discount-code"
|
|
5008
|
+
}) : null] });
|
|
5009
|
+
}
|
|
4727
5010
|
function EventRegistrationWizardContent(props) {
|
|
4728
5011
|
const { wizard } = props;
|
|
4729
5012
|
const showSpamProtection = props.showSpamProtection ?? isSpamProtectionEnabled();
|
|
@@ -4768,40 +5051,7 @@ function EventRegistrationWizardContent(props) {
|
|
|
4768
5051
|
wizard,
|
|
4769
5052
|
showSpamProtection
|
|
4770
5053
|
});
|
|
4771
|
-
case "select-payment":
|
|
4772
|
-
if (!wizard.api.config.siteId) return null;
|
|
4773
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PaymentSelectionStep, {
|
|
4774
|
-
event: wizard.selectedEvent,
|
|
4775
|
-
occurrenceContext: wizard.occurrenceContext,
|
|
4776
|
-
ticketsCount: wizard.ticketsCount,
|
|
4777
|
-
email: wizard.formData.email,
|
|
4778
|
-
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
4779
|
-
creditState: wizard.portalCreditState,
|
|
4780
|
-
directPaymentTotalCents: calculateEventRegistrationPreviewTotal({
|
|
4781
|
-
subtotalCents: wizard.ticketSelectionSubtotalCents,
|
|
4782
|
-
manualDiscountCode: wizard.discountCode,
|
|
4783
|
-
automaticDiscount: wizard.autoAppliedDiscount
|
|
4784
|
-
}),
|
|
4785
|
-
manualDiscountPending: wizard.discountCode.trim().length > 0,
|
|
4786
|
-
selectedSelection: wizard.paymentSelection,
|
|
4787
|
-
onSelectionChange: wizard.handlePaymentSelectionChange,
|
|
4788
|
-
eligibility: wizard.eligibility,
|
|
4789
|
-
eligibilityLoading: wizard.eligibilityLoading,
|
|
4790
|
-
eligibilityError: wizard.eligibilityError,
|
|
4791
|
-
onRequestLogin: () => wizard.setShowMagicLinkModal(true),
|
|
4792
|
-
onStateChange: wizard.handlePaymentStepStateChange
|
|
4793
|
-
}), wizard.discountsAvailableLoading ? null : wizard.shouldShowDiscountToggle ? /* @__PURE__ */ jsx(DiscountCodeDisclosure, {
|
|
4794
|
-
surface: "event-registration",
|
|
4795
|
-
isOpen: wizard.discountUiOpen,
|
|
4796
|
-
code: wizard.discountCode,
|
|
4797
|
-
onOpen: () => wizard.setDiscountUiOpen(true),
|
|
4798
|
-
onChange: wizard.setDiscountCode,
|
|
4799
|
-
onRemove: () => {
|
|
4800
|
-
wizard.setDiscountCode("");
|
|
4801
|
-
wizard.setDiscountUiOpen(false);
|
|
4802
|
-
},
|
|
4803
|
-
id: "er-discount-code"
|
|
4804
|
-
}) : null] });
|
|
5054
|
+
case "select-payment": return /* @__PURE__ */ jsx(PaymentSelectionContent, { wizard });
|
|
4805
5055
|
default: return null;
|
|
4806
5056
|
}
|
|
4807
5057
|
}
|
|
@@ -4827,7 +5077,19 @@ function StepIndicator(props) {
|
|
|
4827
5077
|
*
|
|
4828
5078
|
* Displays an error message with a retry button when registration fails.
|
|
4829
5079
|
*/
|
|
4830
|
-
const
|
|
5080
|
+
const labels = {
|
|
5081
|
+
none: "",
|
|
5082
|
+
retry: "Try again",
|
|
5083
|
+
places: "Choose places",
|
|
5084
|
+
start: "Start again",
|
|
5085
|
+
details: "Check my details",
|
|
5086
|
+
"payment-options": "View payment options",
|
|
5087
|
+
"payment-status": "Check payment status",
|
|
5088
|
+
portal: "View my bookings",
|
|
5089
|
+
event: "View event"
|
|
5090
|
+
};
|
|
5091
|
+
const ErrorStep = ({ message, onRetry, action = "retry", canJoinWaitlist = false }) => {
|
|
5092
|
+
const offerWaitlist = action === "places" && canJoinWaitlist;
|
|
4831
5093
|
return /* @__PURE__ */ jsx(TerminalPanel, {
|
|
4832
5094
|
tone: "error",
|
|
4833
5095
|
className: "er-center",
|
|
@@ -4836,16 +5098,20 @@ const ErrorStep = ({ message, onRetry }) => {
|
|
|
4836
5098
|
variant: "error",
|
|
4837
5099
|
children: /* @__PURE__ */ jsx(CrossIcon, {})
|
|
4838
5100
|
}),
|
|
4839
|
-
title: "
|
|
5101
|
+
title: "We couldn’t complete your booking",
|
|
4840
5102
|
body: /* @__PURE__ */ jsx("p", {
|
|
4841
5103
|
className: "er-text--muted er-message",
|
|
4842
|
-
children: message
|
|
5104
|
+
children: offerWaitlist ? "Sorry, this event is now full. You can join the waiting list, and we’ll email you if a place becomes available." : message
|
|
4843
5105
|
}),
|
|
4844
|
-
actions: /* @__PURE__ */ jsx("
|
|
5106
|
+
actions: action === "none" ? void 0 : action === "portal" || action === "payment-status" ? /* @__PURE__ */ jsx("a", {
|
|
5107
|
+
href: "/portal",
|
|
5108
|
+
className: "er-retry-btn",
|
|
5109
|
+
children: labels[action]
|
|
5110
|
+
}) : /* @__PURE__ */ jsx("button", {
|
|
4845
5111
|
type: "button",
|
|
4846
5112
|
onClick: onRetry,
|
|
4847
5113
|
className: "er-retry-btn",
|
|
4848
|
-
children: "
|
|
5114
|
+
children: offerWaitlist ? "Join the waiting list" : labels[action]
|
|
4849
5115
|
})
|
|
4850
5116
|
});
|
|
4851
5117
|
};
|
|
@@ -4857,7 +5123,7 @@ const ErrorStep = ({ message, onRetry }) => {
|
|
|
4857
5123
|
* Displays when the payment was definitively declined/failed.
|
|
4858
5124
|
* Provides a retry option that returns to payment selection with form state preserved.
|
|
4859
5125
|
*/
|
|
4860
|
-
const PaymentFailedStep = ({
|
|
5126
|
+
const PaymentFailedStep = ({ onRetry }) => {
|
|
4861
5127
|
return /* @__PURE__ */ jsx(TerminalPanel, {
|
|
4862
5128
|
tone: "error",
|
|
4863
5129
|
className: "er-center",
|
|
@@ -4866,16 +5132,16 @@ const PaymentFailedStep = ({ message, onRetry }) => {
|
|
|
4866
5132
|
variant: "error",
|
|
4867
5133
|
children: /* @__PURE__ */ jsx(CrossIcon, {})
|
|
4868
5134
|
}),
|
|
4869
|
-
title: "
|
|
5135
|
+
title: "Your payment didn’t go through",
|
|
4870
5136
|
body: /* @__PURE__ */ jsx("p", {
|
|
4871
5137
|
className: "er-text--muted er-message",
|
|
4872
|
-
children:
|
|
5138
|
+
children: "Please try again or choose another payment option. If this keeps happening, contact the organiser for help."
|
|
4873
5139
|
}),
|
|
4874
5140
|
actions: /* @__PURE__ */ jsx("button", {
|
|
4875
5141
|
type: "button",
|
|
4876
5142
|
onClick: onRetry,
|
|
4877
5143
|
className: "er-retry-btn",
|
|
4878
|
-
children: "
|
|
5144
|
+
children: "View payment options"
|
|
4879
5145
|
})
|
|
4880
5146
|
});
|
|
4881
5147
|
};
|
|
@@ -4970,7 +5236,7 @@ const VerifyingPaymentStep = () => {
|
|
|
4970
5236
|
* - "Check Again" button to restart polling
|
|
4971
5237
|
* - Contact support option for user reassurance
|
|
4972
5238
|
*/
|
|
4973
|
-
const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "
|
|
5239
|
+
const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "We’re checking your payment", message = "Your booking is not confirmed yet. Please don’t make another booking while we check. You can check your payment status again in a moment." }) => {
|
|
4974
5240
|
return /* @__PURE__ */ jsx(TerminalPanel, {
|
|
4975
5241
|
tone: "warning",
|
|
4976
5242
|
className: "er-center",
|
|
@@ -4989,8 +5255,12 @@ const VerifyingTimeoutStep = ({ onCheckAgain, supportEmail, title = "Your regist
|
|
|
4989
5255
|
type: "button",
|
|
4990
5256
|
onClick: onCheckAgain,
|
|
4991
5257
|
className: "er-btn er-btn--primary",
|
|
4992
|
-
children: "Check
|
|
4993
|
-
}) :
|
|
5258
|
+
children: "Check payment status"
|
|
5259
|
+
}) : /* @__PURE__ */ jsx("a", {
|
|
5260
|
+
href: "/portal",
|
|
5261
|
+
className: "er-btn er-btn--primary",
|
|
5262
|
+
children: "Check payment status"
|
|
5263
|
+
}),
|
|
4994
5264
|
secondaryBody: supportEmail ? /* @__PURE__ */ jsxs("p", {
|
|
4995
5265
|
className: "er-text--sm er-text--muted er-message",
|
|
4996
5266
|
children: [
|
|
@@ -5086,7 +5356,7 @@ function EventRegistrationTerminalState(props) {
|
|
|
5086
5356
|
onRetry: () => wizard.setStep("select-payment")
|
|
5087
5357
|
});
|
|
5088
5358
|
case "verifying-timeout": return /* @__PURE__ */ jsx(VerifyingTimeoutStep, {
|
|
5089
|
-
onCheckAgain: wizard.verification.status === "timeout" ? wizard.verification.retry :
|
|
5359
|
+
onCheckAgain: wizard.verification.status === "timeout" ? wizard.verification.retry : wizard.verification.retryReturn,
|
|
5090
5360
|
title: wizard.verification.status === "timeout" ? void 0 : "We’re checking your payment",
|
|
5091
5361
|
message: wizard.verification.status === "timeout" ? void 0 : wizard.errorMessage,
|
|
5092
5362
|
supportEmail: props.supportEmail
|
|
@@ -5098,6 +5368,8 @@ function EventRegistrationTerminalState(props) {
|
|
|
5098
5368
|
}) : null;
|
|
5099
5369
|
case "error": return /* @__PURE__ */ jsx(ErrorStep, {
|
|
5100
5370
|
message: wizard.errorMessage,
|
|
5371
|
+
action: wizard.errorAction,
|
|
5372
|
+
canJoinWaitlist: wizard.eligibility?.isFull && wizard.eligibility.canJoinWaitlist,
|
|
5101
5373
|
onRetry: wizard.handleRetry
|
|
5102
5374
|
});
|
|
5103
5375
|
case "select-event":
|
|
@@ -5173,7 +5445,7 @@ function BookingEntry(props) {
|
|
|
5173
5445
|
className: "er-booking-teaser__ticket-name",
|
|
5174
5446
|
children: ticketType.name
|
|
5175
5447
|
}), /* @__PURE__ */ jsx("strong", { children: props.formatTicketPrice(ticketType) })]
|
|
5176
|
-
}, ticketType.
|
|
5448
|
+
}, ticketType.pricingOptionId))
|
|
5177
5449
|
}) : null
|
|
5178
5450
|
]
|
|
5179
5451
|
}), /* @__PURE__ */ jsx("button", {
|
|
@@ -5255,21 +5527,28 @@ const EVENT_PORTAL_AUTH_COPY = {
|
|
|
5255
5527
|
buttonText: "Email me a login link →"
|
|
5256
5528
|
},
|
|
5257
5529
|
"waitlist-claim": {
|
|
5258
|
-
title: "Log in to claim your waitlist
|
|
5530
|
+
title: "Log in to claim your waitlist place",
|
|
5259
5531
|
buttonText: "Email me a login link to continue →"
|
|
5260
5532
|
}
|
|
5261
5533
|
};
|
|
5262
5534
|
function getActiveTicketTypes(event) {
|
|
5263
|
-
return event?.pricing.kind === "
|
|
5535
|
+
return event?.pricing.kind === "tiered" ? event.pricing.options.filter((ticketType) => ticketType.isActive).sort((left, right) => left.sortOrder - right.sortOrder).map(({ id, ...ticketType }) => ({
|
|
5536
|
+
...ticketType,
|
|
5537
|
+
pricingOptionId: id
|
|
5538
|
+
})) : [];
|
|
5264
5539
|
}
|
|
5265
5540
|
function formatTicketTypePrice(ticketType, currency) {
|
|
5266
5541
|
return formatCurrencyAmount(ticketType.priceAmount, currency, { decimals: "auto" });
|
|
5267
5542
|
}
|
|
5268
|
-
function
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5543
|
+
function formatTicketPriceIfKnown(ticketType, currency) {
|
|
5544
|
+
return currency ? formatTicketTypePrice(ticketType, currency) : "";
|
|
5545
|
+
}
|
|
5546
|
+
function getAvailabilityLabel(event, attendanceMode) {
|
|
5547
|
+
if (!event) return null;
|
|
5548
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, attendanceMode), {
|
|
5549
|
+
full: "Fully booked",
|
|
5550
|
+
waitlist: "Waitlist available"
|
|
5551
|
+
});
|
|
5273
5552
|
}
|
|
5274
5553
|
function getWizardStepLabel(input) {
|
|
5275
5554
|
switch (input.step) {
|
|
@@ -5287,7 +5566,7 @@ function getWizardStepLabel(input) {
|
|
|
5287
5566
|
}
|
|
5288
5567
|
}
|
|
5289
5568
|
function EventRegistrationWizard(props) {
|
|
5290
|
-
const { occurrenceContext, subject, events,
|
|
5569
|
+
const { occurrenceContext, subject, events, maxTickets = "5", showVenue = true, showCapacity = true, successMessage = "Thank you for registering! Check your email for confirmation details.", buttonText = "Complete Registration", buttonVariant = "primary", className, spamProtectionEnabled, supportEmail } = props;
|
|
5291
5570
|
const maxTicketsNum = normalizeEventRegistrationMaxTickets(maxTickets);
|
|
5292
5571
|
const showSpamProtection = spamProtectionEnabled ?? isSpamProtectionEnabled();
|
|
5293
5572
|
const buttonClass = themeButtonClassName({
|
|
@@ -5301,7 +5580,6 @@ function EventRegistrationWizard(props) {
|
|
|
5301
5580
|
occurrenceContext: occurrenceContext ?? null,
|
|
5302
5581
|
subject: subject ?? null,
|
|
5303
5582
|
events: events ?? [],
|
|
5304
|
-
wholeSeriesOfferings: wholeSeriesOfferings ?? [],
|
|
5305
5583
|
maxTicketsNum
|
|
5306
5584
|
});
|
|
5307
5585
|
const [bookingOverlayOpen, setBookingOverlayOpen] = useState(false);
|
|
@@ -5366,7 +5644,7 @@ function EventRegistrationWizard(props) {
|
|
|
5366
5644
|
const currentStepNumber = getStepNumber(wizard.step, activeWizardSteps);
|
|
5367
5645
|
const summaryEventPricingType = summaryEvent ? publicEventPricingType(summaryEvent.pricing) : "free";
|
|
5368
5646
|
const summaryPriceLabel = summaryEvent ? formatEventPriceDisplay(summaryEvent.pricing) : null;
|
|
5369
|
-
const summaryAvailabilityLabel = getAvailabilityLabel(summaryEvent);
|
|
5647
|
+
const summaryAvailabilityLabel = getAvailabilityLabel(summaryEvent, wizard.selectedAttendanceMode);
|
|
5370
5648
|
const waitlistClaimRequiresPortalLogin = wizard.waitlistClaim.requiresPortalLogin && wizard.portalAuthState !== "authenticated" && wizard.portalAuthState !== "checking";
|
|
5371
5649
|
const portalAuthCopy = waitlistClaimRequiresPortalLogin ? {
|
|
5372
5650
|
...EVENT_PORTAL_AUTH_COPY["waitlist-claim"],
|
|
@@ -5400,7 +5678,7 @@ function EventRegistrationWizard(props) {
|
|
|
5400
5678
|
children: renderRegistrationSurface("inline")
|
|
5401
5679
|
});
|
|
5402
5680
|
const bookingTicketTypes = getActiveTicketTypes(summaryEvent);
|
|
5403
|
-
const
|
|
5681
|
+
const bookingCurrency = summaryEvent?.pricing.kind === "tiered" ? summaryEvent.pricing.currency : null;
|
|
5404
5682
|
return /* @__PURE__ */ jsxs("div", {
|
|
5405
5683
|
ref: registrationRootRef,
|
|
5406
5684
|
id: EVENT_REGISTRATION_ANCHOR_ID,
|
|
@@ -5414,9 +5692,9 @@ function EventRegistrationWizard(props) {
|
|
|
5414
5692
|
priceLabel: summaryPriceLabel,
|
|
5415
5693
|
availabilityLabel: summaryAvailabilityLabel,
|
|
5416
5694
|
ticketTypes: bookingTicketTypes,
|
|
5417
|
-
ticketCurrency:
|
|
5695
|
+
ticketCurrency: bookingCurrency,
|
|
5418
5696
|
buttonClass,
|
|
5419
|
-
formatTicketPrice: (ticketType) =>
|
|
5697
|
+
formatTicketPrice: (ticketType) => formatTicketPriceIfKnown(ticketType, bookingCurrency),
|
|
5420
5698
|
onOpen: () => setBookingOverlayOpen(true),
|
|
5421
5699
|
onClose: () => setBookingOverlayOpen(false),
|
|
5422
5700
|
overlaySurface: renderRegistrationSurface("overlay")
|
|
@@ -5424,6 +5702,52 @@ function EventRegistrationWizard(props) {
|
|
|
5424
5702
|
});
|
|
5425
5703
|
}
|
|
5426
5704
|
//#endregion
|
|
5705
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationSurface.ts
|
|
5706
|
+
/**
|
|
5707
|
+
* Whether a run agrees with the offering whose page it arrived on.
|
|
5708
|
+
*
|
|
5709
|
+
* Scoping has already restricted the events to the subject's series, so the
|
|
5710
|
+
* series set needs no second check here. What is still worth checking is the
|
|
5711
|
+
* run's own idea of its parent: a run that claims a different offering means
|
|
5712
|
+
* the page and the data disagree about who owns it, and the surface fails
|
|
5713
|
+
* closed rather than taking a booking against an offering it cannot vouch for.
|
|
5714
|
+
*/
|
|
5715
|
+
function agreesWithSubjectOffering(run, subject) {
|
|
5716
|
+
if (subject?.kind !== "eventOffering") return true;
|
|
5717
|
+
return run.run.eventOfferingId === subject.eventOfferingId;
|
|
5718
|
+
}
|
|
5719
|
+
/**
|
|
5720
|
+
* Subjects whose page only ever registers for a whole run.
|
|
5721
|
+
*
|
|
5722
|
+
* The subject's own booking scope decides, for an offering exactly as for a
|
|
5723
|
+
* series: an ordinary offering with no dates is a normal empty state, not a
|
|
5724
|
+
* whole-series page with nothing bookable.
|
|
5725
|
+
*/
|
|
5726
|
+
function isWholeSeriesSubject(subject) {
|
|
5727
|
+
return (subject?.kind === "eventOffering" || subject?.kind === "eventSeries") && subject.bookingScope === "whole_series";
|
|
5728
|
+
}
|
|
5729
|
+
function planEventRegistrationSurface(input) {
|
|
5730
|
+
const scopedEvents = resolveEventRegistrationScopedEvents(input.events, {
|
|
5731
|
+
occurrenceContext: input.occurrenceContext,
|
|
5732
|
+
subject: input.subject
|
|
5733
|
+
});
|
|
5734
|
+
const bookingScopes = new Set(scopedEvents.map((event) => event.bookingScope));
|
|
5735
|
+
if (scopedEvents.length === 0 && isWholeSeriesSubject(input.subject)) return { kind: "unavailableWholeSeries" };
|
|
5736
|
+
if (!input.occurrenceContext && !input.subject && bookingScopes.has("single_occurrence")) return {
|
|
5737
|
+
kind: "occurrence",
|
|
5738
|
+
events: scopedEvents.filter((event) => event.bookingScope === "single_occurrence")
|
|
5739
|
+
};
|
|
5740
|
+
if (bookingScopes.size === 0 || bookingScopes.has("single_occurrence")) return bookingScopes.has("whole_series") ? { kind: "mixedBookingScopes" } : {
|
|
5741
|
+
kind: "occurrence",
|
|
5742
|
+
events: scopedEvents
|
|
5743
|
+
};
|
|
5744
|
+
const runs = groupPublicEventsByRun(scopedEvents);
|
|
5745
|
+
return runs.every((run) => agreesWithSubjectOffering(run, input.subject)) && runs.length > 0 ? {
|
|
5746
|
+
kind: "wholeSeries",
|
|
5747
|
+
runs
|
|
5748
|
+
} : { kind: "unavailableWholeSeries" };
|
|
5749
|
+
}
|
|
5750
|
+
//#endregion
|
|
5427
5751
|
//#region ../blocks/src/system/runtime/nodes/event-registration/PastOccurrenceNotice.tsx
|
|
5428
5752
|
function isPastOccurrence(startsAt) {
|
|
5429
5753
|
if (!startsAt) return false;
|
|
@@ -5503,15 +5827,10 @@ function toEventRegistrationClientProps(props, display) {
|
|
|
5503
5827
|
const EventRegistrationClient = (clientProps) => {
|
|
5504
5828
|
const surface = planEventRegistrationSurface({
|
|
5505
5829
|
events: clientProps.events ?? [],
|
|
5506
|
-
wholeSeriesOfferings: clientProps.wholeSeriesOfferings ?? [],
|
|
5507
|
-
wholeSeriesOffering: clientProps.wholeSeriesOffering,
|
|
5508
5830
|
occurrenceContext: clientProps.occurrenceContext,
|
|
5509
5831
|
subject: clientProps.subject
|
|
5510
5832
|
});
|
|
5511
|
-
if (surface.kind === "wholeSeries") return /* @__PURE__ */ jsx(EventRegistrationWizard, {
|
|
5512
|
-
...clientProps,
|
|
5513
|
-
wholeSeriesOfferings: [...surface.offerings]
|
|
5514
|
-
});
|
|
5833
|
+
if (surface.kind === "wholeSeries") return /* @__PURE__ */ jsx(EventRegistrationWizard, { ...clientProps });
|
|
5515
5834
|
if (surface.kind === "unavailableWholeSeries" || surface.kind === "mixedBookingScopes") return /* @__PURE__ */ jsx("div", {
|
|
5516
5835
|
className: clientProps.className,
|
|
5517
5836
|
role: "status",
|