@riverbankcms/sdk 0.151.0 → 0.153.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 +52 -0
- package/dist/{EventEmbeddedCheckoutStep-BBHbM22D.mjs → EventEmbeddedCheckoutStep-veN-QiAE.mjs} +10 -9
- package/dist/{PreviewEditorSidebar-BHplI9HE.mjs → PreviewEditorSidebar-jI_4DTZY.mjs} +4 -3
- package/dist/{PreviewEditorUI-DuyN8nsD.mjs → PreviewEditorUI-ORkVZhfu.mjs} +5 -4
- package/dist/{SdkPreviewModeRuntime-CR5ypwxJ.mjs → SdkPreviewModeRuntime-DaNqevI1.mjs} +341 -164
- package/dist/{SiteChromeCustomizeContext-D5t6joF_.mjs → SiteChromeCustomizeContext-CgNuBHC0.mjs} +27124 -39230
- package/dist/ThemedButton-X2UxhW6F.mjs +16525 -0
- package/dist/_dts/ai/src/contracts/proposals.d.ts +52 -52
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +2357 -7859
- package/dist/_dts/api/src/bookingOperations.d.ts +5 -3
- package/dist/_dts/api/src/commercePortalEndpoints.d.ts +4 -0
- package/dist/_dts/api/src/communications.d.ts +19 -5
- package/dist/_dts/api/src/endpoints.d.ts +7 -0
- package/dist/_dts/api/src/index.d.ts +1 -1
- package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
- package/dist/_dts/api/src/navigation/types.d.ts +7 -0
- package/dist/_dts/api/src/navigation.d.ts +1 -1
- package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +10 -1
- package/dist/_dts/api/src/sdkThemeWire.d.ts +186 -1434
- package/dist/_dts/api/src/shared-contracts.d.ts +10 -0
- package/dist/_dts/api/src/siteAssets.d.ts +1 -0
- package/dist/_dts/api/src/siteInfrastructure.d.ts +2 -1
- package/dist/_dts/api/src/teamMembers.d.ts +2 -27
- package/dist/_dts/block-form/src/widgets/RepeaterField/components/layoutGridDomain.d.ts +3 -13
- package/dist/_dts/blocks/src/contracts/index.d.ts +1 -0
- package/dist/_dts/blocks/src/definitions.d.ts +1 -1
- package/dist/_dts/blocks/src/index.d.ts +2 -0
- package/dist/_dts/blocks/src/lib/media.d.ts +1 -0
- package/dist/_dts/blocks/src/lib/picsum.d.ts +2 -2
- package/dist/_dts/blocks/src/pageRenderPreparation.d.ts +1 -0
- package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -1
- package/dist/_dts/blocks/src/primitives/content/utils/sanitizeHref.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +4 -4
- package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +212 -804
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +7 -2
- package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +45 -45
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +2 -0
- package/dist/_dts/blocks/src/system/blocks/shared/teamMembers.d.ts +4 -7
- package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +2 -2
- package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +6 -6
- package/dist/_dts/blocks/src/system/fields/backgroundContent.d.ts +377 -1
- package/dist/_dts/blocks/src/system/helpers/backgroundMedia.d.ts +6 -2
- package/dist/_dts/blocks/src/system/helpers/normalizeMailingListBlockContent.d.ts +2 -0
- package/dist/_dts/blocks/src/system/helpers/resolveBackground.d.ts +3 -3
- package/dist/_dts/blocks/src/system/layout/repeaterGrid.d.ts +12 -5
- package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +3 -3
- package/dist/_dts/blocks/src/system/manifest/schema.d.ts +24 -24
- package/dist/_dts/blocks/src/system/manifest/validation.d.ts +2 -0
- package/dist/_dts/blocks/src/system/node/fragments/lookSlot.d.ts +1 -1
- package/dist/_dts/blocks/src/system/registry.d.ts +14 -2
- package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +0 -5
- package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/api/schemas/events.d.ts +971 -0
- package/dist/_dts/blocks/src/system/runtime/api/schemas/waitlist-claims.d.ts +42 -0
- package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +10 -2
- package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +10 -136
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +48 -6
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -3
- package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFlowController.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/hooks/useBookingSubmission.state.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +5 -1
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/lookSurfaces.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/ImageResolveContext.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +50 -202
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +51 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +6 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/carousel.client.hooks.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/carousel.client.state.d.ts +7 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-details/lookPresentation.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/BookingEntryViews.d.ts +42 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventEmbeddedCheckoutStep.d.ts +4 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationBookingLayer.d.ts +19 -9
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationPayment.d.ts +4 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +24 -9
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizardContent.d.ts +4 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventSelectionStep.d.ts +5 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/GuestDetailsSection.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentStatusStep.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SingleTicketEntitlementNote.d.ts +11 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SuccessStep.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.d.ts +31 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/bookingEntry.d.ts +154 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/bookingFocus.d.ts +12 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +9 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/finishedBooking.d.ts +77 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/index.d.ts +0 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/offeringNoun.d.ts +12 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/paymentResponse.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationCompletion.d.ts +33 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDerivations.d.ts +11 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDisplay.d.ts +31 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationDraft.state.d.ts +60 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationStateMachine.d.ts +58 -10
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationSurface.d.ts +17 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +23 -7
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useBookingBarFacts.d.ts +12 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationRecoveryRequest.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +4 -11
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +1563 -31
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventSourceRecovery.d.ts +2 -12
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/usePaymentStatusRecovery.d.ts +147 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/utils.d.ts +50 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/waitlistClaimRestoration.d.ts +6 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/wizardSteps.d.ts +85 -15
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +53 -8
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CardListItem.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/MonthLookView.d.ts +10 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +290 -882
- package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +3 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +22 -90
- package/dist/_dts/blocks/src/system/runtime/nodes/mediaContext.d.ts +69 -0
- package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptionCopy.d.ts +5 -1
- package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptions.d.ts +37 -1
- package/dist/_dts/blocks/src/system/runtime/shared/components/ModalShell.d.ts +9 -2
- package/dist/_dts/blocks/src/system/runtime/shared/components/PaymentChoiceRows.d.ts +28 -0
- package/dist/_dts/blocks/src/system/runtime/shared/components/StepIndicator.d.ts +6 -8
- package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.d.ts +9 -12
- package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.state.d.ts +15 -0
- package/dist/_dts/blocks/src/system/runtime/shared/utils/themePortalRoot.d.ts +10 -15
- package/dist/_dts/blocks/src/system/transforms/registry/index.d.ts +2 -0
- package/dist/_dts/blocks/src/system/transforms/registry/links.d.ts +2 -0
- package/dist/_dts/commerce/src/purchase/bookingInstalmentSchedule.d.ts +2 -0
- package/dist/_dts/commerce/src/purchase/bookingPaymentSelection.d.ts +6 -0
- package/dist/_dts/commerce/src/purchase/confirmationEmailPayment.d.ts +14 -14
- package/dist/_dts/commerce/src/purchase/confirmationPayment.d.ts +65 -0
- package/dist/_dts/commerce/src/purchase/confirmationPaymentSchema.d.ts +66 -0
- package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
- package/dist/_dts/commerce/src/purchase/orderPaymentState.d.ts +8 -0
- package/dist/_dts/content-model/src/content-types/schema.d.ts +3 -3
- package/dist/_dts/content-model/src/templates/defaults.d.ts +2 -2
- package/dist/_dts/core/src/appointment-booking-terms.d.ts +20 -0
- package/dist/_dts/core/src/booking-payment-schemas.d.ts +70 -0
- package/dist/_dts/core/src/branded.d.ts +0 -2
- package/dist/_dts/core/src/demo-claim-access.d.ts +1 -1
- package/dist/_dts/core/src/demo-claim-readiness.d.ts +18 -0
- package/dist/_dts/core/src/demo-lifecycle-status.d.ts +1 -1
- package/dist/_dts/core/src/demo-warm-pool-target.d.ts +1 -1
- package/dist/_dts/core/src/index.d.ts +4 -0
- package/dist/_dts/core/src/mailing-list-runtime.d.ts +2 -2
- package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +9 -1
- package/dist/_dts/core/src/mailing-list-setup.d.ts +9 -1
- package/dist/_dts/core/src/mailing-list-submission.d.ts +1 -1
- package/dist/_dts/core/src/mailing-list-targeting-availability.d.ts +68 -0
- package/dist/_dts/core/src/mailing-list-targeting.d.ts +11 -1
- package/dist/_dts/core/src/ticket-quantity.d.ts +13 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +106 -36
- package/dist/_dts/editor/src/chrome/chromeLayers.d.ts +7 -0
- package/dist/_dts/editor/src/index.d.ts +1 -0
- package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
- package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +2 -2
- package/dist/_dts/editor-blocks/src/media/admitEditorMediaField.d.ts +4 -0
- package/dist/_dts/editor-blocks/src/widgets/link/LinkAddressInput.d.ts +8 -0
- package/dist/_dts/editor-blocks/src/widgets/link/LinkContentList.d.ts +12 -0
- package/dist/_dts/editor-blocks/src/widgets/link/LinkPicker.d.ts +5 -1
- package/dist/_dts/editor-blocks/src/widgets/link/LinkPickerDialog.d.ts +3 -3
- package/dist/_dts/editor-blocks/src/widgets/link/LinkSummary.d.ts +8 -2
- package/dist/_dts/editor-blocks/src/widgets/link/LinkWidget.d.ts +4 -3
- package/dist/_dts/editor-blocks/src/widgets/link/LinkWidgetContext.d.ts +2 -1
- package/dist/_dts/editor-blocks/src/widgets/link/draft.d.ts +44 -0
- package/dist/_dts/editor-blocks/src/widgets/link/presentation.d.ts +13 -0
- package/dist/_dts/editor-blocks/src/widgets/link/types.d.ts +14 -0
- package/dist/_dts/editor-blocks/src/widgets/link/useRoutableContent.d.ts +2 -0
- package/dist/_dts/editor-blocks/src/widgets/link/utils.d.ts +5 -4
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListTargetingField.d.ts +1 -1
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +13 -8
- package/dist/_dts/media-core/src/assetsInUseSummary.d.ts +6 -0
- package/dist/_dts/media-core/src/contentMediaAudit.d.ts +3 -2
- package/dist/_dts/media-core/src/fileStorage.d.ts +4 -3
- package/dist/_dts/media-core/src/index.d.ts +5 -0
- package/dist/_dts/media-core/src/media.d.ts +406 -0
- package/dist/_dts/media-core/src/mediaIdentifierSchema.d.ts +3 -0
- package/dist/_dts/media-core/src/mediaKinds.d.ts +2 -0
- package/dist/_dts/media-core/src/mediaUsageProjection.d.ts +13 -1
- package/dist/_dts/media-core/src/mediaWriteNormalizer.d.ts +2 -6
- package/dist/_dts/media-core/src/portableMediaReferences.d.ts +8 -21
- package/dist/_dts/media-core/src/renderableMediaAsset.d.ts +28 -14
- package/dist/_dts/media-core/src/renderableMediaAssetAdmission.d.ts +15 -0
- package/dist/_dts/media-core/src/storageObjectKey.d.ts +12 -0
- package/dist/_dts/media-editor/src/CropDialog.d.ts +6 -3
- package/dist/_dts/media-editor/src/MediaEditor.d.ts +2 -1
- package/dist/_dts/media-editor/src/MediaPreview.d.ts +3 -3
- package/dist/_dts/media-editor/src/cropEditorSource.d.ts +5 -7
- package/dist/_dts/media-editor/src/editorMediaState.d.ts +29 -0
- package/dist/_dts/media-editor/src/mediaSelection.d.ts +1 -2
- package/dist/_dts/media-editor/src/runtimeMediaAssetState.d.ts +4 -5
- package/dist/_dts/media-editor/src/types.d.ts +1 -1
- package/dist/_dts/media-editor/src/utils.d.ts +0 -1
- package/dist/_dts/media-react/src/components/cropChangePolicy.d.ts +4 -1
- package/dist/_dts/media-react/src/components/cropGeometry.d.ts +1 -0
- package/dist/_dts/media-react/src/components/useImageCropperController.d.ts +1 -0
- package/dist/_dts/media-react/src/hooks/useSupabaseMediaUploader.d.ts +1 -1
- package/dist/_dts/media-react/src/internal/supabaseResumableUpload.d.ts +13 -0
- package/dist/_dts/preview-next/src/client/blocks/BlockBackgroundChooser.d.ts +2 -1
- package/dist/_dts/preview-next/src/client/blocks/previewCustomizeSelectedMedia.d.ts +11 -12
- package/dist/_dts/preview-next/src/client/preview/previewModeRootAttribute.d.ts +11 -0
- package/dist/_dts/sdk/src/contracts/content.d.ts +2 -45
- package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
- package/dist/_dts/sdk/src/contracts/rendering.d.ts +3 -3
- package/dist/_dts/sdk/src/index.d.ts +1 -0
- package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +0 -1
- package/dist/_dts/sdk/src/rendering/image.d.ts +14 -4
- package/dist/_dts/sdk/src/rendering/index.d.ts +5 -2
- package/dist/_dts/sdk/src/rendering/link.d.ts +5 -0
- package/dist/_dts/sdk/src/rendering/mediaAssets.d.ts +2 -4
- package/dist/_dts/sdk/src/rendering/overrides.d.ts +1 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
- package/dist/_dts/theme-core/src/blocks/opaquePanels.d.ts +3 -3
- package/dist/_dts/theme-core/src/boxBackgroundSchema.d.ts +397 -26
- package/dist/_dts/theme-core/src/buttons/types.d.ts +21 -21
- package/dist/_dts/theme-core/src/cards/types.d.ts +34 -34
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/inputs/types.d.ts +3 -3
- package/dist/_dts/theme-core/src/lib/media.d.ts +2 -616
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +261 -2619
- package/dist/_dts/theme-core/src/palette/curated/types.d.ts +1 -1
- package/dist/_dts/theme-core/src/schema.d.ts +548 -3187
- package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
- package/dist/_dts/theme-core/src/site-styles/runtimeBackgroundResolution.d.ts +9 -9
- package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +1 -1
- package/dist/_dts/theme-core/src/styles/skinTokens.d.ts +2 -2
- package/dist/_dts/theme-core/src/typography/schema.d.ts +2 -2
- package/dist/client/BookingMailingListNote-DrchYW1m.mjs +386 -0
- package/dist/client/{CardListItem-ZDLYh6dL.mjs → CardListItem-CC_GVmF6.mjs} +5 -5
- package/dist/client/CheckIcon-CpyXr-Kg.mjs +35 -0
- package/dist/client/{CheckboxChoice-M-3HycLw.mjs → CheckboxChoice-Dq30m3DO.mjs} +1 -1
- package/dist/client/{DemoBookingPortalAccess-BMtvPTWE.mjs → DemoBookingPortalAccess-ojwbVUmx.mjs} +85 -85
- package/dist/client/{EventCombined.client-DUm_DOxW.mjs → EventCombined.client-DyN0v0Xk.mjs} +7 -9
- package/dist/client/{EventEmbeddedCheckoutStep-DsNNzgRm.mjs → EventEmbeddedCheckoutStep-CgfpKc3n.mjs} +11 -10
- package/dist/client/{EventListing.client-DjNYGUVm.mjs → EventListing.client-CuOuvYMz.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-DuFiOHq_.mjs → LeafletStaticMap-B0WhRr3j.mjs} +1 -1
- package/dist/client/{ModalShell-CqkBvBIC.mjs → ModalShell-BXzucfR6.mjs} +83 -12
- package/dist/client/{RichText-LjPCUGGi.mjs → RichText-C1fIXBzA.mjs} +50 -34
- package/dist/client/{ThemedButton-DZKjtaDD.mjs → ThemedButton-B7HFqFBg.mjs} +1 -2
- package/dist/client/{accordion-Qe--SILD.mjs → accordion-DCDVWSye.mjs} +1 -1
- package/dist/client/{bookingForm-3BCl4g_f.mjs → bookingForm-BJ3C4GlM.mjs} +321 -154
- package/dist/client/bookings.mjs +118607 -22429
- package/dist/client/{carousel-h2YjKOS2.mjs → carousel-BSCBhfHY.mjs} +2 -2
- package/dist/client/{carousel.client-BLrd4hmY.mjs → carousel.client-GEtOGsxo.mjs} +46 -41
- package/dist/client/{cart-5NeiigVd.mjs → cart-Yv-aAtck.mjs} +3 -3
- package/dist/client/{checkout-G4UWjOEw.mjs → checkout-B9xDkl30.mjs} +3 -3
- package/dist/client/client.mjs +37511 -33793
- package/dist/client/{context-GK4-AVAh.mjs → context-BOGe3rIA.mjs} +275 -10
- package/dist/client/{eventCalendar-Prw3Yo_L.mjs → eventCalendar-D6M0T9hs.mjs} +18 -17
- package/dist/client/{eventCombined-BUugi6__.mjs → eventCombined-NM4UFBq8.mjs} +4 -4
- package/dist/client/{eventDetails-CBHUda-R.mjs → eventDetails-f_FhV4O8.mjs} +3 -4
- package/dist/client/{eventListing-CQeG45Dg.mjs → eventListing-WLkfAROh.mjs} +4 -4
- package/dist/client/{eventRegistration-Dif3p3oJ.mjs → eventRegistration-D3ejfLvW.mjs} +2209 -2144
- package/dist/client/{form-Cf0WMtfG.mjs → form-D5Or2Jyu.mjs} +5 -6
- package/dist/client/{headerSection-Bqdr3JWp.mjs → headerSection-hWgnv27V.mjs} +9 -9
- package/dist/client/hooks.mjs +17278 -16106
- package/dist/client/{locationMap-BVvPou4O.mjs → locationMap-Di1K0O2S.mjs} +3 -4
- package/dist/client/{media-47fcnhzD.mjs → media-D29-F1u_.mjs} +183 -362
- package/dist/client/mediaContext-CwbbimYB.mjs +135 -0
- package/dist/client/{newsletterForm-Cx-1dnic.mjs → newsletterForm-CwxcwTNO.mjs} +5 -5
- package/dist/client/{productDetail-DaUMaJYk.mjs → productDetail-BLSnhPdA.mjs} +3 -3
- package/dist/client/{productList-BKQlWEKE.mjs → productList-oGytONOX.mjs} +3 -3
- package/dist/client/{propsDecoder-DO5iXphQ.mjs → propsDecoder-lf_dTeZS.mjs} +18659 -14473
- package/dist/client/renderableMediaAssetAdmission-CHkXYDC_.mjs +143 -0
- package/dist/client/rendering/client.mjs +58971 -55722
- package/dist/client/rendering/islands.mjs +20 -23
- package/dist/client/rendering.mjs +41610 -37917
- package/dist/client/{routeIslandApiConfig-BNm0Z3-g.mjs → routeIslandApiConfig-Bc_WVPS8.mjs} +1 -1
- package/dist/client/{shop-D7ytcFBC.mjs → shop-BQ3bR7fA.mjs} +16 -14
- package/dist/client/{shop-commerce-D68-hHy2.mjs → shop-commerce-DDPll6ZC.mjs} +9 -9
- package/dist/client/{shop-commerce-store-Cu7X2lyu.mjs → shop-commerce-store-DO-e1pTe.mjs} +1 -1
- package/dist/client/{shopShared-D12rxE69.mjs → shopShared-BylM9jh1.mjs} +5 -5
- package/dist/client/themePortalRoot-DS92SRVZ.mjs +47 -0
- package/dist/client/{TerminalPanel-DOTSUCO0.mjs → useDiscountCodeUi-B1Puub2v.mjs} +60 -77
- package/dist/client/{useEventPagination-jgKa67KV.mjs → useEventPagination-BBhkmQaT.mjs} +6 -8
- package/dist/preview-next/before-render.mjs +96 -4
- package/dist/preview-next/client/runtime.mjs +3 -3
- package/dist/preview-next/keepAlive.mjs +7 -0
- package/dist/preview-next/middleware.mjs +7 -0
- package/dist/{sdk-runtime-4cCWO_3i.mjs → sdk-runtime-DWCvhJGu.mjs} +1 -1
- package/dist/server/components.mjs +21820 -19902
- package/dist/server/config-validation.mjs +1786 -642
- package/dist/server/config.mjs +1786 -642
- package/dist/server/data.mjs +17220 -16076
- package/dist/server/index.mjs +234 -2
- package/dist/server/next.mjs +22505 -20528
- package/dist/server/page-converter.mjs +7587 -6572
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +20487 -19044
- package/dist/server/rendering.mjs +21844 -19901
- package/dist/server/routing.mjs +19186 -17961
- package/dist/server/server.mjs +1874 -695
- package/dist/server/theme-bridge.mjs +1371 -914
- package/dist/server/theme.mjs +154 -37
- package/dist/{spinner-tSdG9YvG.mjs → spinner-BYM-Y81w.mjs} +1 -1
- package/dist/styles/index.css +1088 -721
- package/package.json +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/OrderSummary.d.ts +0 -15
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +0 -22
- package/dist/_dts/blocks/src/system/runtime/shared/components/SelectableOptionCard.d.ts +0 -30
- package/dist/client/BookingMailingListNote-DlDSs5Vm.mjs +0 -567
- package/dist/client/colorStyles-DTunOThj.mjs +0 -1316
- package/dist/client/pricing-CMD0kADd.mjs +0 -314
- package/dist/client/result-DRW7JWXz.mjs +0 -30
- package/dist/client/scrollToBlock-C86BYkyV.mjs +0 -17
- package/dist/client/themePortalRoot-AGs4cE7t.mjs +0 -30
- package/dist/spinner-BL3kW9Uh.mjs +0 -803
|
@@ -1731,12 +1731,14 @@ const unsafeAsSiteId = (id) => id;
|
|
|
1731
1731
|
const unsafeAsApiKeyId = (id) => id;
|
|
1732
1732
|
const unsafeAsEventOfferingId = (id) => id;
|
|
1733
1733
|
const unsafeAsEventSeriesId = (id) => id;
|
|
1734
|
+
const unsafeAsMediaAssetId = (id) => id;
|
|
1734
1735
|
const unsafeAsUserId = (id) => id;
|
|
1735
1736
|
const unsafeAsContentVersionId = (id) => id;
|
|
1736
1737
|
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1737
1738
|
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1738
1739
|
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1739
1740
|
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1741
|
+
const parseMediaAssetId = (value) => parseUuidBrand(value, unsafeAsMediaAssetId);
|
|
1740
1742
|
const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
|
|
1741
1743
|
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1742
1744
|
//#endregion
|
|
@@ -1941,6 +1943,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
1941
1943
|
default: return assertNever$2(pricing);
|
|
1942
1944
|
}
|
|
1943
1945
|
}
|
|
1946
|
+
/**
|
|
1947
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
1948
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
1949
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
1950
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
1951
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
1952
|
+
*/
|
|
1953
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
1954
|
+
switch (display.kind) {
|
|
1955
|
+
case "free": return "Free";
|
|
1956
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
1957
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
1958
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
1959
|
+
case "mixed": return display.paidToAmount > display.paidFromAmount ? `Free / ${formatCurrencyAmount(display.paidFromAmount, display.currency, options)} - ${formatCurrencyAmount(display.paidToAmount, display.currency, options)}` : `Free / ${formatCurrencyAmount(display.paidFromAmount, display.currency, options)}`;
|
|
1960
|
+
case "unavailable": return "Pricing unavailable";
|
|
1961
|
+
case "external": return display.label;
|
|
1962
|
+
default: return assertNever$2(display);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
/** Render an event's price directly from its pricing value. */
|
|
1966
|
+
function formatEventPricing(pricing, options = {}) {
|
|
1967
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
1968
|
+
}
|
|
1944
1969
|
//#endregion
|
|
1945
1970
|
//#region ../core/src/event-page-surface-subject.ts
|
|
1946
1971
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -2084,6 +2109,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
2084
2109
|
}
|
|
2085
2110
|
//#endregion
|
|
2086
2111
|
//#region ../core/src/booking-date-time.ts
|
|
2112
|
+
const DEFAULT_LOCALE = "en-US";
|
|
2087
2113
|
const FALLBACK_TIMEZONE = "UTC";
|
|
2088
2114
|
const START_OF_DAY = {
|
|
2089
2115
|
hour: 0,
|
|
@@ -2206,6 +2232,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
2206
2232
|
if (result.ok) return result.value;
|
|
2207
2233
|
throw new Error(formatParseError(result));
|
|
2208
2234
|
}
|
|
2235
|
+
function formatBookingInstant(isoString, options) {
|
|
2236
|
+
const date = new Date(isoString);
|
|
2237
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
2238
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
2239
|
+
}
|
|
2240
|
+
function formatBookingDate(input, format = {
|
|
2241
|
+
weekday: "long",
|
|
2242
|
+
year: "numeric",
|
|
2243
|
+
month: "long",
|
|
2244
|
+
day: "numeric"
|
|
2245
|
+
}) {
|
|
2246
|
+
return formatBookingInstant(input.startsAt, {
|
|
2247
|
+
locale: input.locale,
|
|
2248
|
+
timeZone: input.timeZone,
|
|
2249
|
+
format
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
function formatBookingTime(input, format = {
|
|
2253
|
+
hour: "numeric",
|
|
2254
|
+
minute: "2-digit",
|
|
2255
|
+
hour12: true
|
|
2256
|
+
}) {
|
|
2257
|
+
return formatBookingInstant(input.startsAt, {
|
|
2258
|
+
locale: input.locale,
|
|
2259
|
+
timeZone: input.timeZone,
|
|
2260
|
+
format
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2209
2263
|
function getBookingLocalDateKey(input) {
|
|
2210
2264
|
return formatDateKey$1(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
2211
2265
|
}
|
|
@@ -2335,7 +2389,7 @@ function parsePositiveInteger(value) {
|
|
|
2335
2389
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
2336
2390
|
}
|
|
2337
2391
|
function parseNewsletterListId(value) {
|
|
2338
|
-
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
2392
|
+
return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
|
|
2339
2393
|
}
|
|
2340
2394
|
function parseMailchimpAccountId(value) {
|
|
2341
2395
|
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
@@ -2377,8 +2431,15 @@ function parseMailingListProviderScope(value) {
|
|
|
2377
2431
|
}
|
|
2378
2432
|
return err("invalid_mailing_list_provider_scope");
|
|
2379
2433
|
}
|
|
2380
|
-
|
|
2381
|
-
|
|
2434
|
+
z.unknown().transform((value, ctx) => {
|
|
2435
|
+
const parsed = parseNewsletterAudience(value);
|
|
2436
|
+
if (parsed.ok) return parsed.value;
|
|
2437
|
+
ctx.addIssue({
|
|
2438
|
+
code: "custom",
|
|
2439
|
+
message: "Choose a valid newsletter audience."
|
|
2440
|
+
});
|
|
2441
|
+
return z.NEVER;
|
|
2442
|
+
});
|
|
2382
2443
|
function parseMailingListGlobalForm(value) {
|
|
2383
2444
|
if (!isRecord$9(value)) return formError("shape");
|
|
2384
2445
|
const fields = parseGlobalFields(value.fields);
|
|
@@ -2398,6 +2459,16 @@ function parseMailingListGlobalForm(value) {
|
|
|
2398
2459
|
privacyNote
|
|
2399
2460
|
});
|
|
2400
2461
|
}
|
|
2462
|
+
function parseNewsletterAudience(value) {
|
|
2463
|
+
if (!isRecord$9(value)) return err("invalid_newsletter_audience");
|
|
2464
|
+
if (value.kind === "general" && Object.keys(value).length === 1) return ok({ kind: "general" });
|
|
2465
|
+
if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) return err("invalid_newsletter_audience");
|
|
2466
|
+
const topicId = parseNewsletterListId(value.topicId);
|
|
2467
|
+
return topicId === null ? err("invalid_newsletter_audience") : ok({
|
|
2468
|
+
kind: "topic",
|
|
2469
|
+
topicId
|
|
2470
|
+
});
|
|
2471
|
+
}
|
|
2401
2472
|
function parseGlobalFields(value) {
|
|
2402
2473
|
if (!isRecord$9(value) || typeof value.preset !== "string") return null;
|
|
2403
2474
|
switch (value.preset) {
|
|
@@ -2447,44 +2518,144 @@ function formError(field) {
|
|
|
2447
2518
|
}
|
|
2448
2519
|
//#endregion
|
|
2449
2520
|
//#region ../core/src/mailing-list-targeting.ts
|
|
2521
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
2522
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
2523
|
+
switch (targeting.provider) {
|
|
2524
|
+
case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
2525
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
2526
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2450
2529
|
function planMailingListChoicePresentation(targeting) {
|
|
2451
|
-
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
2530
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") return { tag: "hidden" };
|
|
2452
2531
|
switch (targeting.provider) {
|
|
2453
|
-
case "native": return
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2532
|
+
case "native": return presentVisitorSelection({
|
|
2533
|
+
provider: "native",
|
|
2534
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
2535
|
+
}, targeting.selection.offeredTopicIds.length);
|
|
2536
|
+
case "brevo": return presentVisitorSelection({
|
|
2537
|
+
provider: "brevo",
|
|
2538
|
+
listIds: targeting.selection.offeredListIds
|
|
2539
|
+
}, targeting.selection.offeredListIds.length);
|
|
2540
|
+
case "mailchimp": return presentVisitorSelection({
|
|
2541
|
+
provider: "mailchimp",
|
|
2542
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
2543
|
+
}, targeting.selection.offeredInterestIds.length);
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
function presentVisitorSelection(selection, optionCount) {
|
|
2547
|
+
return optionCount === 1 ? {
|
|
2548
|
+
tag: "automatic",
|
|
2549
|
+
selection
|
|
2550
|
+
} : {
|
|
2551
|
+
tag: "visitor_choice",
|
|
2552
|
+
provider: selection.provider,
|
|
2553
|
+
optionCount
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
//#endregion
|
|
2557
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
2558
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
2559
|
+
switch (provider.provider) {
|
|
2560
|
+
case "native": {
|
|
2561
|
+
const audience = provider.defaultAudience;
|
|
2562
|
+
return audience.kind === "general" ? {
|
|
2563
|
+
id: "general",
|
|
2564
|
+
name: "General mailing list"
|
|
2565
|
+
} : provider.topics.find((item) => item.id === audience.topicId) ?? null;
|
|
2566
|
+
}
|
|
2567
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
2568
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
function assessMailingListTargeting(context, targeting) {
|
|
2572
|
+
if (context?.tag !== "configured") return {
|
|
2573
|
+
tag: "unavailable",
|
|
2574
|
+
reason: "setup_missing",
|
|
2575
|
+
targeting
|
|
2576
|
+
};
|
|
2577
|
+
const catalog = context.provider;
|
|
2578
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
2579
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
2580
|
+
return destination === null ? {
|
|
2581
|
+
tag: "unavailable",
|
|
2582
|
+
reason: "default_missing",
|
|
2583
|
+
targeting
|
|
2584
|
+
} : {
|
|
2585
|
+
tag: "available",
|
|
2586
|
+
value: {
|
|
2587
|
+
mode: "default",
|
|
2588
|
+
targeting,
|
|
2589
|
+
provider: catalog.provider,
|
|
2590
|
+
destination
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
2595
|
+
switch (targeting.provider) {
|
|
2596
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
2461
2597
|
provider: "native",
|
|
2462
|
-
|
|
2598
|
+
catalog,
|
|
2599
|
+
targeting
|
|
2600
|
+
}, catalog.topics) : {
|
|
2601
|
+
tag: "unavailable",
|
|
2602
|
+
reason: "provider_mismatch",
|
|
2603
|
+
targeting
|
|
2463
2604
|
};
|
|
2464
|
-
case "brevo": return
|
|
2465
|
-
tag: "automatic",
|
|
2466
|
-
selection: {
|
|
2467
|
-
provider: "brevo",
|
|
2468
|
-
listIds: targeting.selection.offeredListIds
|
|
2469
|
-
}
|
|
2470
|
-
} : {
|
|
2471
|
-
tag: "visitor_choice",
|
|
2605
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
2472
2606
|
provider: "brevo",
|
|
2473
|
-
|
|
2607
|
+
catalog,
|
|
2608
|
+
targeting
|
|
2609
|
+
}, catalog.lists) : {
|
|
2610
|
+
tag: "unavailable",
|
|
2611
|
+
reason: "provider_mismatch",
|
|
2612
|
+
targeting
|
|
2474
2613
|
};
|
|
2475
|
-
case "mailchimp":
|
|
2476
|
-
|
|
2477
|
-
|
|
2614
|
+
case "mailchimp": {
|
|
2615
|
+
if (catalog.provider !== "mailchimp") return {
|
|
2616
|
+
tag: "unavailable",
|
|
2617
|
+
reason: "provider_mismatch",
|
|
2618
|
+
targeting
|
|
2619
|
+
};
|
|
2620
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
2621
|
+
return audience === void 0 ? {
|
|
2622
|
+
tag: "unavailable",
|
|
2623
|
+
reason: "audience_missing",
|
|
2624
|
+
value: {
|
|
2625
|
+
mode: "custom",
|
|
2626
|
+
provider: "mailchimp",
|
|
2627
|
+
catalog,
|
|
2628
|
+
targeting
|
|
2629
|
+
}
|
|
2630
|
+
} : assessMatchedChoices({
|
|
2478
2631
|
provider: "mailchimp",
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
optionCount: targeting.selection.offeredInterestIds.length
|
|
2485
|
-
};
|
|
2632
|
+
catalog,
|
|
2633
|
+
targeting,
|
|
2634
|
+
audience
|
|
2635
|
+
}, audience.interests);
|
|
2636
|
+
}
|
|
2486
2637
|
}
|
|
2487
2638
|
}
|
|
2639
|
+
function assessMatchedChoices(matched, choices) {
|
|
2640
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
2641
|
+
const available = new Set(choices.map((item) => item.id));
|
|
2642
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
2643
|
+
const value = {
|
|
2644
|
+
mode: "custom",
|
|
2645
|
+
...matched,
|
|
2646
|
+
choices,
|
|
2647
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
2648
|
+
};
|
|
2649
|
+
return missingIds.length > 0 ? {
|
|
2650
|
+
tag: "unavailable",
|
|
2651
|
+
reason: "choices_missing",
|
|
2652
|
+
missingIds,
|
|
2653
|
+
value
|
|
2654
|
+
} : {
|
|
2655
|
+
tag: "available",
|
|
2656
|
+
value
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2488
2659
|
//#endregion
|
|
2489
2660
|
//#region ../core/src/mailing-list-runtime.ts
|
|
2490
2661
|
function parseMailingListRuntimeContext(value) {
|
|
@@ -2530,11 +2701,12 @@ function parseRuntimeProvider(value) {
|
|
|
2530
2701
|
}
|
|
2531
2702
|
}
|
|
2532
2703
|
function parseNativeRuntimeProvider(value) {
|
|
2533
|
-
|
|
2704
|
+
if ("defaultTopicId" in value) return null;
|
|
2705
|
+
const defaultAudience = parseNewsletterAudience(value.defaultAudience);
|
|
2534
2706
|
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
2535
|
-
return
|
|
2707
|
+
return defaultAudience.ok && topics !== null ? {
|
|
2536
2708
|
provider: "native",
|
|
2537
|
-
|
|
2709
|
+
defaultAudience: defaultAudience.value,
|
|
2538
2710
|
topics
|
|
2539
2711
|
} : null;
|
|
2540
2712
|
}
|
|
@@ -2550,57 +2722,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
2550
2722
|
function parseMailchimpRuntimeProvider(value) {
|
|
2551
2723
|
if (!Array.isArray(value.audiences)) return null;
|
|
2552
2724
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
for (const audience of value.audiences) {
|
|
2556
|
-
if (!isRecord$8(audience)) return null;
|
|
2557
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
2558
|
-
const name = parseName(audience.name);
|
|
2559
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
2560
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
2561
|
-
if (interests === null) return null;
|
|
2562
|
-
audiences.push({
|
|
2563
|
-
id,
|
|
2564
|
-
name,
|
|
2565
|
-
interests
|
|
2566
|
-
});
|
|
2567
|
-
}
|
|
2568
|
-
return {
|
|
2725
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
2726
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
2569
2727
|
provider: "mailchimp",
|
|
2570
2728
|
defaultAudienceId,
|
|
2571
2729
|
audiences
|
|
2572
|
-
};
|
|
2730
|
+
} : null;
|
|
2573
2731
|
}
|
|
2574
|
-
function
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
interests
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2732
|
+
function parseMailchimpAudience(value) {
|
|
2733
|
+
if (!isRecord$8(value) || !Array.isArray(value.interests)) return null;
|
|
2734
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
2735
|
+
const name = parseName(value.name);
|
|
2736
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
2737
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
2738
|
+
id,
|
|
2739
|
+
name,
|
|
2740
|
+
interests
|
|
2741
|
+
} : null;
|
|
2742
|
+
}
|
|
2743
|
+
function parseMailchimpInterest(value) {
|
|
2744
|
+
if (!isRecord$8(value)) return null;
|
|
2745
|
+
const id = parseMailchimpInterestId(value.id);
|
|
2746
|
+
const name = parseName(value.name);
|
|
2747
|
+
const categoryName = parseName(value.categoryName);
|
|
2748
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
2749
|
+
id,
|
|
2750
|
+
name,
|
|
2751
|
+
categoryName
|
|
2752
|
+
} : null;
|
|
2589
2753
|
}
|
|
2590
2754
|
function parseNamedItems(value, parseId) {
|
|
2591
2755
|
if (!Array.isArray(value)) return null;
|
|
2592
|
-
const items =
|
|
2593
|
-
for (const item of value) {
|
|
2756
|
+
const items = Array.from(value, (item) => {
|
|
2594
2757
|
if (!isRecord$8(item)) return null;
|
|
2595
2758
|
const id = parseId(item.id);
|
|
2596
2759
|
const name = parseName(item.name);
|
|
2597
|
-
|
|
2598
|
-
items.push({
|
|
2760
|
+
return id !== null && name !== null ? {
|
|
2599
2761
|
id,
|
|
2600
2762
|
name
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
return items;
|
|
2763
|
+
} : null;
|
|
2764
|
+
});
|
|
2765
|
+
return items.every((item) => item !== null) ? items : null;
|
|
2604
2766
|
}
|
|
2605
2767
|
function parseName(value) {
|
|
2606
2768
|
if (typeof value !== "string") return null;
|
|
@@ -2616,6 +2778,7 @@ function invalidRuntimeContext() {
|
|
|
2616
2778
|
//#endregion
|
|
2617
2779
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2618
2780
|
function parseMailingListPlacementTargeting(value) {
|
|
2781
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
2619
2782
|
if (!isRecord$7(value)) return targetingError("shape");
|
|
2620
2783
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
2621
2784
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -2628,6 +2791,11 @@ function parseMailingListPlacementTargeting(value) {
|
|
|
2628
2791
|
}
|
|
2629
2792
|
}
|
|
2630
2793
|
function parseNativeTargeting(selection) {
|
|
2794
|
+
if (selection.tag === "general") return Object.keys(selection).length === 1 ? ok({
|
|
2795
|
+
mode: "custom",
|
|
2796
|
+
provider: "native",
|
|
2797
|
+
selection: { tag: "general" }
|
|
2798
|
+
}) : targetingError("selection");
|
|
2631
2799
|
if (selection.tag === "fixed") {
|
|
2632
2800
|
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
2633
2801
|
return topicIds.ok ? ok({
|
|
@@ -2714,14 +2882,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
2714
2882
|
}
|
|
2715
2883
|
function parseUniqueIds(value, parseId) {
|
|
2716
2884
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
2717
|
-
|
|
2718
|
-
|
|
2885
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
2886
|
+
if (!parsed.ok) return parsed;
|
|
2719
2887
|
const id = parseId(item);
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
parsed.push(id);
|
|
2723
|
-
}
|
|
2724
|
-
return ok(parsed);
|
|
2888
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
2889
|
+
}, ok([]));
|
|
2725
2890
|
}
|
|
2726
2891
|
function isRecord$7(value) {
|
|
2727
2892
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3150,6 +3315,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
3150
3315
|
};
|
|
3151
3316
|
}
|
|
3152
3317
|
//#endregion
|
|
3318
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
3319
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
3320
|
+
event: {
|
|
3321
|
+
label: "Event",
|
|
3322
|
+
pluralLabel: "Events",
|
|
3323
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
3324
|
+
},
|
|
3325
|
+
class: {
|
|
3326
|
+
label: "Class",
|
|
3327
|
+
pluralLabel: "Classes",
|
|
3328
|
+
description: "Regular scheduled classes and group sessions."
|
|
3329
|
+
},
|
|
3330
|
+
course: {
|
|
3331
|
+
label: "Course",
|
|
3332
|
+
pluralLabel: "Courses",
|
|
3333
|
+
description: "A fixed set of dates that people book together."
|
|
3334
|
+
},
|
|
3335
|
+
term: {
|
|
3336
|
+
label: "Term",
|
|
3337
|
+
pluralLabel: "Terms",
|
|
3338
|
+
description: "A fixed term of sessions that people book together."
|
|
3339
|
+
},
|
|
3340
|
+
workshop: {
|
|
3341
|
+
label: "Workshop",
|
|
3342
|
+
pluralLabel: "Workshops",
|
|
3343
|
+
description: "One-off workshops, day sessions, or special events."
|
|
3344
|
+
},
|
|
3345
|
+
retreat: {
|
|
3346
|
+
label: "Retreat",
|
|
3347
|
+
pluralLabel: "Retreats",
|
|
3348
|
+
description: "Multi-day or residential immersive experiences."
|
|
3349
|
+
},
|
|
3350
|
+
performance: {
|
|
3351
|
+
label: "Performance",
|
|
3352
|
+
pluralLabel: "Performances",
|
|
3353
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
3354
|
+
}
|
|
3355
|
+
};
|
|
3356
|
+
//#endregion
|
|
3153
3357
|
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
3154
3358
|
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3155
3359
|
checkPublicEventRegistrationNextStep: {
|
|
@@ -7676,7 +7880,96 @@ const themeLookMetadataSchema = z.object({
|
|
|
7676
7880
|
skinMarks: skinMarksSchema.optional()
|
|
7677
7881
|
});
|
|
7678
7882
|
//#endregion
|
|
7679
|
-
//#region ../
|
|
7883
|
+
//#region ../media-core/src/identifiers.ts
|
|
7884
|
+
function slugifyMediaIdentifier(value) {
|
|
7885
|
+
return value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
7886
|
+
}
|
|
7887
|
+
function parseMediaIdentifier(value) {
|
|
7888
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
7889
|
+
const trimmed = value.trim();
|
|
7890
|
+
if (trimmed.length === 0) return err({ kind: "empty_identifier" });
|
|
7891
|
+
const normalized = slugifyMediaIdentifier(trimmed);
|
|
7892
|
+
if (normalized.length === 0) return err({
|
|
7893
|
+
kind: "empty_after_normalization",
|
|
7894
|
+
value
|
|
7895
|
+
});
|
|
7896
|
+
return ok(normalized);
|
|
7897
|
+
}
|
|
7898
|
+
/**
|
|
7899
|
+
* Admits identifiers read from trusted persistence without repairing dirty data in memory.
|
|
7900
|
+
* User input should use parseMediaIdentifier, which intentionally canonicalizes it.
|
|
7901
|
+
*/
|
|
7902
|
+
function parseCanonicalMediaIdentifier(value) {
|
|
7903
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
7904
|
+
const parsed = parseMediaIdentifier(value);
|
|
7905
|
+
if (!parsed.ok) return parsed;
|
|
7906
|
+
if (value !== parsed.value) return err({
|
|
7907
|
+
kind: "non_canonical_identifier",
|
|
7908
|
+
value,
|
|
7909
|
+
canonical: parsed.value
|
|
7910
|
+
});
|
|
7911
|
+
return parsed;
|
|
7912
|
+
}
|
|
7913
|
+
//#endregion
|
|
7914
|
+
//#region ../media-core/src/mediaIdentifierSchema.ts
|
|
7915
|
+
/** Strict stored-reference admission delegates the canonical identifier decision. */
|
|
7916
|
+
const mediaIdentifierSchema = z.string().transform((value, context) => {
|
|
7917
|
+
const parsed = parseCanonicalMediaIdentifier(value);
|
|
7918
|
+
if (parsed.ok) return parsed.value;
|
|
7919
|
+
context.addIssue({
|
|
7920
|
+
code: "custom",
|
|
7921
|
+
message: "Expected a canonical media identifier"
|
|
7922
|
+
});
|
|
7923
|
+
return z.NEVER;
|
|
7924
|
+
});
|
|
7925
|
+
//#endregion
|
|
7926
|
+
//#region ../media-core/src/mediaKinds.ts
|
|
7927
|
+
const mediaTypeDiscriminants = [
|
|
7928
|
+
"image",
|
|
7929
|
+
"video",
|
|
7930
|
+
"audio",
|
|
7931
|
+
"document",
|
|
7932
|
+
"spreadsheet",
|
|
7933
|
+
"archive"
|
|
7934
|
+
];
|
|
7935
|
+
//#endregion
|
|
7936
|
+
//#region ../media-core/src/renderableMediaAsset.ts
|
|
7937
|
+
/** A portable reference never uses an incidental UUID, URL or storage snapshot for identity. */
|
|
7938
|
+
function resolveManagedMediaReference(reference, index) {
|
|
7939
|
+
const asset = index?.byIdentifier.get(reference.identifier);
|
|
7940
|
+
return asset ? {
|
|
7941
|
+
kind: "resolved",
|
|
7942
|
+
reference,
|
|
7943
|
+
asset
|
|
7944
|
+
} : {
|
|
7945
|
+
kind: "missing",
|
|
7946
|
+
reference
|
|
7947
|
+
};
|
|
7948
|
+
}
|
|
7949
|
+
//#endregion
|
|
7950
|
+
//#region ../media-core/src/renderableMediaAssetAdmission.ts
|
|
7951
|
+
const mediaAssetIdSchema = z.string().transform((value, context) => {
|
|
7952
|
+
const parsed = parseMediaAssetId(value);
|
|
7953
|
+
if (parsed.ok) return parsed.value;
|
|
7954
|
+
context.addIssue({
|
|
7955
|
+
code: "custom",
|
|
7956
|
+
message: "Expected a media asset ID"
|
|
7957
|
+
});
|
|
7958
|
+
return z.NEVER;
|
|
7959
|
+
});
|
|
7960
|
+
const nonemptyStorageValue = z.string().refine((value) => value.trim().length > 0);
|
|
7961
|
+
const renderableMediaAssetSchema = z.object({
|
|
7962
|
+
id: mediaAssetIdSchema,
|
|
7963
|
+
identifier: mediaIdentifierSchema,
|
|
7964
|
+
storageBucket: nonemptyStorageValue,
|
|
7965
|
+
storagePath: nonemptyStorageValue,
|
|
7966
|
+
mimeType: nonemptyStorageValue,
|
|
7967
|
+
filename: z.string().optional(),
|
|
7968
|
+
width: z.number().positive().nullable(),
|
|
7969
|
+
height: z.number().positive().nullable()
|
|
7970
|
+
});
|
|
7971
|
+
//#endregion
|
|
7972
|
+
//#region ../media-core/src/media.ts
|
|
7680
7973
|
const hotspotSchema = z.object({
|
|
7681
7974
|
x: z.number().min(0).max(1),
|
|
7682
7975
|
y: z.number().min(0).max(1),
|
|
@@ -7710,56 +8003,149 @@ const transformSchema = z.object({
|
|
|
7710
8003
|
rotation: rotationSchema.optional()
|
|
7711
8004
|
});
|
|
7712
8005
|
const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
|
|
7713
|
-
tag: z.literal("
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
storagePath: z.string().min(1)
|
|
7717
|
-
}), z.object({
|
|
8006
|
+
tag: z.literal("media"),
|
|
8007
|
+
identifier: mediaIdentifierSchema
|
|
8008
|
+
}).strict(), z.object({
|
|
7718
8009
|
tag: z.literal("external-src"),
|
|
7719
|
-
assetId: z.string().optional(),
|
|
7720
8010
|
src: z.string().url()
|
|
7721
|
-
})]);
|
|
7722
|
-
const
|
|
8011
|
+
}).strict()]);
|
|
8012
|
+
const mediaUsageShape = {
|
|
7723
8013
|
purpose: z.string().optional(),
|
|
7724
8014
|
placeholder: z.boolean().default(true).optional(),
|
|
7725
|
-
assetId: z.string().optional(),
|
|
7726
|
-
identifier: z.string().optional(),
|
|
7727
|
-
src: z.string().optional(),
|
|
7728
8015
|
alt: z.string().optional(),
|
|
7729
8016
|
filename: z.string().optional(),
|
|
7730
|
-
mimeType: z.string().optional(),
|
|
7731
8017
|
width: z.number().optional(),
|
|
7732
8018
|
height: z.number().optional(),
|
|
7733
|
-
storageBucket: z.string().optional(),
|
|
7734
|
-
storagePath: z.string().optional(),
|
|
7735
8019
|
poster: mediaPosterSchema.optional(),
|
|
7736
8020
|
transform: transformSchema.optional()
|
|
7737
|
-
}
|
|
7738
|
-
const
|
|
8021
|
+
};
|
|
8022
|
+
const environmentExclusions = {
|
|
8023
|
+
assetId: z.never().optional(),
|
|
8024
|
+
id: z.never().optional(),
|
|
8025
|
+
src: z.never().optional(),
|
|
8026
|
+
storageBucket: z.never().optional(),
|
|
8027
|
+
storagePath: z.never().optional(),
|
|
8028
|
+
mimeType: z.never().optional()
|
|
8029
|
+
};
|
|
8030
|
+
const mediaBaseSchema = z.object({
|
|
8031
|
+
...mediaUsageShape,
|
|
8032
|
+
...environmentExclusions,
|
|
8033
|
+
identifier: mediaIdentifierSchema
|
|
8034
|
+
}).strict();
|
|
7739
8035
|
const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
|
|
7740
8036
|
const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
|
|
7741
|
-
const
|
|
7742
|
-
const
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
z.
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
persistableMediaBaseSchema.extend({ type: z.literal("archive") })
|
|
8037
|
+
const mediaSchema = mediaBaseSchema.extend({ type: z.enum(mediaTypeDiscriminants) });
|
|
8038
|
+
const externalMediaSchema = z.object({
|
|
8039
|
+
...mediaUsageShape,
|
|
8040
|
+
...environmentExclusions,
|
|
8041
|
+
type: z.enum(mediaTypeDiscriminants),
|
|
8042
|
+
src: z.string().min(1),
|
|
8043
|
+
identifier: z.never().optional()
|
|
8044
|
+
}).strict();
|
|
8045
|
+
const assetMediaSchema = z.object({
|
|
8046
|
+
...mediaUsageShape,
|
|
8047
|
+
...environmentExclusions,
|
|
8048
|
+
type: z.enum(mediaTypeDiscriminants),
|
|
8049
|
+
asset: renderableMediaAssetSchema,
|
|
8050
|
+
identifier: z.never().optional()
|
|
8051
|
+
}).strict();
|
|
8052
|
+
const runtimeMediaSchema = z.union([
|
|
8053
|
+
mediaSchema,
|
|
8054
|
+
externalMediaSchema,
|
|
8055
|
+
assetMediaSchema
|
|
7761
8056
|
]);
|
|
7762
8057
|
//#endregion
|
|
8058
|
+
//#region ../media-core/src/transformRect.ts
|
|
8059
|
+
function isValidTransformRectStructure(rect) {
|
|
8060
|
+
if (!Array.isArray(rect) || rect.length !== 4) return false;
|
|
8061
|
+
const [left, top, width, height] = rect;
|
|
8062
|
+
return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
|
|
8063
|
+
}
|
|
8064
|
+
//#endregion
|
|
8065
|
+
//#region ../media-core/src/aspectTransforms.ts
|
|
8066
|
+
const DEFAULT_RECT_EPSILON = .5;
|
|
8067
|
+
function parseAspectRatioValue(value) {
|
|
8068
|
+
if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
8069
|
+
if (typeof value !== "string") return void 0;
|
|
8070
|
+
const normalized = value.trim();
|
|
8071
|
+
if (!normalized) return void 0;
|
|
8072
|
+
if (normalized === "auto") return void 0;
|
|
8073
|
+
if (normalized.includes(":") || normalized.includes("/")) {
|
|
8074
|
+
const delimiter = normalized.includes(":") ? ":" : "/";
|
|
8075
|
+
const [wRaw, hRaw] = normalized.split(delimiter);
|
|
8076
|
+
const width = Number(wRaw?.trim());
|
|
8077
|
+
const height = Number(hRaw?.trim());
|
|
8078
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
|
|
8079
|
+
return width / height;
|
|
8080
|
+
}
|
|
8081
|
+
const numeric = Number(normalized);
|
|
8082
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
|
|
8083
|
+
return numeric;
|
|
8084
|
+
}
|
|
8085
|
+
const MAX_ASPECT_DISTANCE = .25;
|
|
8086
|
+
function resolveMediaTransformForAspect(transform, targetAspect) {
|
|
8087
|
+
if (!transform) return {};
|
|
8088
|
+
const base = {
|
|
8089
|
+
rect: transform.rect,
|
|
8090
|
+
hotspot: transform.hotspot,
|
|
8091
|
+
rotation: transform.rotation
|
|
8092
|
+
};
|
|
8093
|
+
const target = parseAspectRatioValue(targetAspect);
|
|
8094
|
+
const crops = transform.aspectCrops;
|
|
8095
|
+
if (!target || !crops || Object.keys(crops).length === 0) return base;
|
|
8096
|
+
let best = null;
|
|
8097
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
8098
|
+
for (const [key, candidate] of Object.entries(crops)) {
|
|
8099
|
+
const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
|
|
8100
|
+
if (!candidateAspect) continue;
|
|
8101
|
+
const distance = Math.abs(Math.log(candidateAspect / target));
|
|
8102
|
+
if (distance < bestDistance) {
|
|
8103
|
+
best = candidate;
|
|
8104
|
+
bestDistance = distance;
|
|
8105
|
+
}
|
|
8106
|
+
}
|
|
8107
|
+
if (!best) return base;
|
|
8108
|
+
if (bestDistance > MAX_ASPECT_DISTANCE) return base;
|
|
8109
|
+
return {
|
|
8110
|
+
rect: best.rect ?? base.rect,
|
|
8111
|
+
hotspot: best.hotspot ?? base.hotspot,
|
|
8112
|
+
rotation: best.rotation ?? base.rotation
|
|
8113
|
+
};
|
|
8114
|
+
}
|
|
8115
|
+
function isValidTransformRect(rect) {
|
|
8116
|
+
return isValidTransformRectStructure(rect);
|
|
8117
|
+
}
|
|
8118
|
+
function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
|
|
8119
|
+
if (!isValidTransformRect(rect)) return false;
|
|
8120
|
+
if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
|
|
8121
|
+
const [x, y, width, height] = rect;
|
|
8122
|
+
return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
|
|
8123
|
+
}
|
|
8124
|
+
//#endregion
|
|
8125
|
+
//#region ../media-core/src/rotation.ts
|
|
8126
|
+
function rotateNormalizedPoint(point, rotation) {
|
|
8127
|
+
const x = point.x;
|
|
8128
|
+
const y = point.y;
|
|
8129
|
+
switch (rotation) {
|
|
8130
|
+
case 0: return {
|
|
8131
|
+
x,
|
|
8132
|
+
y
|
|
8133
|
+
};
|
|
8134
|
+
case 90: return {
|
|
8135
|
+
x: 1 - y,
|
|
8136
|
+
y: x
|
|
8137
|
+
};
|
|
8138
|
+
case 180: return {
|
|
8139
|
+
x: 1 - x,
|
|
8140
|
+
y: 1 - y
|
|
8141
|
+
};
|
|
8142
|
+
case 270: return {
|
|
8143
|
+
x: y,
|
|
8144
|
+
y: 1 - x
|
|
8145
|
+
};
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
//#endregion
|
|
7763
8149
|
//#region ../theme-core/src/palette/schema.ts
|
|
7764
8150
|
const colourHexString = z.string().regex(/^#([0-9A-Fa-f]{3}){1,2}$/);
|
|
7765
8151
|
const paletteColorSchema = z.object({
|
|
@@ -16308,6 +16694,21 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
|
|
|
16308
16694
|
showVideoOnMobile: z.boolean().nullable().optional()
|
|
16309
16695
|
})
|
|
16310
16696
|
]);
|
|
16697
|
+
/** Application rendering sources are admitted separately from saved references. */
|
|
16698
|
+
const runtimeBoxBackgroundSchema = z.discriminatedUnion("type", [
|
|
16699
|
+
boxBackgroundSchema.options[0],
|
|
16700
|
+
boxBackgroundSchema.options[1],
|
|
16701
|
+
boxBackgroundSchema.options[2].extend({ image: z.union([
|
|
16702
|
+
imageMediaSchema,
|
|
16703
|
+
externalMediaSchema.extend({ type: z.literal("image") }),
|
|
16704
|
+
assetMediaSchema.extend({ type: z.literal("image") })
|
|
16705
|
+
]).nullable().optional() }),
|
|
16706
|
+
boxBackgroundSchema.options[3].extend({ image: z.union([
|
|
16707
|
+
videoMediaSchema,
|
|
16708
|
+
externalMediaSchema.extend({ type: z.literal("video") }),
|
|
16709
|
+
assetMediaSchema.extend({ type: z.literal("video") })
|
|
16710
|
+
]).nullable().optional() })
|
|
16711
|
+
]);
|
|
16311
16712
|
function normalizeAuthoringOpacity(value) {
|
|
16312
16713
|
if (!isRecord$6(value)) return value;
|
|
16313
16714
|
return {
|
|
@@ -23157,97 +23558,6 @@ function registerManifest(manifest) {
|
|
|
23157
23558
|
return manifest;
|
|
23158
23559
|
}
|
|
23159
23560
|
//#endregion
|
|
23160
|
-
//#region ../media-core/src/transformRect.ts
|
|
23161
|
-
function isValidTransformRectStructure(rect) {
|
|
23162
|
-
if (!Array.isArray(rect) || rect.length !== 4) return false;
|
|
23163
|
-
const [left, top, width, height] = rect;
|
|
23164
|
-
return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
|
|
23165
|
-
}
|
|
23166
|
-
//#endregion
|
|
23167
|
-
//#region ../media-core/src/aspectTransforms.ts
|
|
23168
|
-
const DEFAULT_RECT_EPSILON = .5;
|
|
23169
|
-
function parseAspectRatioValue(value) {
|
|
23170
|
-
if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
23171
|
-
if (typeof value !== "string") return void 0;
|
|
23172
|
-
const normalized = value.trim();
|
|
23173
|
-
if (!normalized) return void 0;
|
|
23174
|
-
if (normalized === "auto") return void 0;
|
|
23175
|
-
if (normalized.includes(":") || normalized.includes("/")) {
|
|
23176
|
-
const delimiter = normalized.includes(":") ? ":" : "/";
|
|
23177
|
-
const [wRaw, hRaw] = normalized.split(delimiter);
|
|
23178
|
-
const width = Number(wRaw?.trim());
|
|
23179
|
-
const height = Number(hRaw?.trim());
|
|
23180
|
-
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
|
|
23181
|
-
return width / height;
|
|
23182
|
-
}
|
|
23183
|
-
const numeric = Number(normalized);
|
|
23184
|
-
if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
|
|
23185
|
-
return numeric;
|
|
23186
|
-
}
|
|
23187
|
-
const MAX_ASPECT_DISTANCE = .25;
|
|
23188
|
-
function resolveMediaTransformForAspect(transform, targetAspect) {
|
|
23189
|
-
if (!transform) return {};
|
|
23190
|
-
const base = {
|
|
23191
|
-
rect: transform.rect,
|
|
23192
|
-
hotspot: transform.hotspot,
|
|
23193
|
-
rotation: transform.rotation
|
|
23194
|
-
};
|
|
23195
|
-
const target = parseAspectRatioValue(targetAspect);
|
|
23196
|
-
const crops = transform.aspectCrops;
|
|
23197
|
-
if (!target || !crops || Object.keys(crops).length === 0) return base;
|
|
23198
|
-
let best = null;
|
|
23199
|
-
let bestDistance = Number.POSITIVE_INFINITY;
|
|
23200
|
-
for (const [key, candidate] of Object.entries(crops)) {
|
|
23201
|
-
const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
|
|
23202
|
-
if (!candidateAspect) continue;
|
|
23203
|
-
const distance = Math.abs(Math.log(candidateAspect / target));
|
|
23204
|
-
if (distance < bestDistance) {
|
|
23205
|
-
best = candidate;
|
|
23206
|
-
bestDistance = distance;
|
|
23207
|
-
}
|
|
23208
|
-
}
|
|
23209
|
-
if (!best) return base;
|
|
23210
|
-
if (bestDistance > MAX_ASPECT_DISTANCE) return base;
|
|
23211
|
-
return {
|
|
23212
|
-
rect: best.rect ?? base.rect,
|
|
23213
|
-
hotspot: best.hotspot ?? base.hotspot,
|
|
23214
|
-
rotation: best.rotation ?? base.rotation
|
|
23215
|
-
};
|
|
23216
|
-
}
|
|
23217
|
-
function isValidTransformRect(rect) {
|
|
23218
|
-
return isValidTransformRectStructure(rect);
|
|
23219
|
-
}
|
|
23220
|
-
function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
|
|
23221
|
-
if (!isValidTransformRect(rect)) return false;
|
|
23222
|
-
if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
|
|
23223
|
-
const [x, y, width, height] = rect;
|
|
23224
|
-
return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
|
|
23225
|
-
}
|
|
23226
|
-
//#endregion
|
|
23227
|
-
//#region ../media-core/src/rotation.ts
|
|
23228
|
-
function rotateNormalizedPoint(point, rotation) {
|
|
23229
|
-
const x = point.x;
|
|
23230
|
-
const y = point.y;
|
|
23231
|
-
switch (rotation) {
|
|
23232
|
-
case 0: return {
|
|
23233
|
-
x,
|
|
23234
|
-
y
|
|
23235
|
-
};
|
|
23236
|
-
case 90: return {
|
|
23237
|
-
x: 1 - y,
|
|
23238
|
-
y: x
|
|
23239
|
-
};
|
|
23240
|
-
case 180: return {
|
|
23241
|
-
x: 1 - x,
|
|
23242
|
-
y: 1 - y
|
|
23243
|
-
};
|
|
23244
|
-
case 270: return {
|
|
23245
|
-
x: y,
|
|
23246
|
-
y: 1 - x
|
|
23247
|
-
};
|
|
23248
|
-
}
|
|
23249
|
-
}
|
|
23250
|
-
//#endregion
|
|
23251
23561
|
//#region ../blocks/src/system/node/schema.ts
|
|
23252
23562
|
const transformStepSchema = z.object({
|
|
23253
23563
|
id: z.string().min(1, "Transform requires an identifier"),
|
|
@@ -24185,6 +24495,14 @@ z.object({
|
|
|
24185
24495
|
icon: z.string().optional()
|
|
24186
24496
|
});
|
|
24187
24497
|
//#endregion
|
|
24498
|
+
//#region ../blocks/src/lib/typeGuards.ts
|
|
24499
|
+
/**
|
|
24500
|
+
* Strict record guard: excludes null, primitives, and arrays.
|
|
24501
|
+
*/
|
|
24502
|
+
function isRecord$5(value) {
|
|
24503
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24504
|
+
}
|
|
24505
|
+
//#endregion
|
|
24188
24506
|
//#region ../blocks/src/system/designCapabilities.ts
|
|
24189
24507
|
function declareBlockDesignCapability(capability) {
|
|
24190
24508
|
return {
|
|
@@ -26165,6 +26483,12 @@ function parseBackgroundOverlay(value) {
|
|
|
26165
26483
|
const result = boxBackgroundOverlaySchema.safeParse(value);
|
|
26166
26484
|
return result.success ? result.data : void 0;
|
|
26167
26485
|
}
|
|
26486
|
+
/** Rendering accepts explicit application sources separately from stored references. */
|
|
26487
|
+
const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
|
|
26488
|
+
function parseRuntimeBackgroundContent(value) {
|
|
26489
|
+
const result = runtimeBackgroundContentSchema.safeParse(value);
|
|
26490
|
+
return result.success ? result.data : null;
|
|
26491
|
+
}
|
|
26168
26492
|
//#endregion
|
|
26169
26493
|
//#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
|
|
26170
26494
|
function resolveBackgroundColorValue(value, context) {
|
|
@@ -31038,6 +31362,15 @@ const formBlockDefinition = {
|
|
|
31038
31362
|
runtime: formBlockRuntime
|
|
31039
31363
|
};
|
|
31040
31364
|
//#endregion
|
|
31365
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
31366
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
31367
|
+
function normalizeMailingListBlockContent(record) {
|
|
31368
|
+
return record.targeting == null ? {
|
|
31369
|
+
...record,
|
|
31370
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
31371
|
+
} : record;
|
|
31372
|
+
}
|
|
31373
|
+
//#endregion
|
|
31041
31374
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
31042
31375
|
const contactNewsletterLayout = styledSection({
|
|
31043
31376
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -31201,6 +31534,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
31201
31534
|
],
|
|
31202
31535
|
icon: "MailPlus"
|
|
31203
31536
|
}),
|
|
31537
|
+
contentNormalizer: {
|
|
31538
|
+
fieldIds: ["targeting"],
|
|
31539
|
+
normalize: normalizeMailingListBlockContent
|
|
31540
|
+
},
|
|
31204
31541
|
dataSchemas: { form: formDataSchema.optional() },
|
|
31205
31542
|
dataLoaders: { form: {
|
|
31206
31543
|
endpoint: "getPublicFormById",
|
|
@@ -32618,14 +32955,6 @@ const mediaTransforms = [{
|
|
|
32618
32955
|
}
|
|
32619
32956
|
}];
|
|
32620
32957
|
//#endregion
|
|
32621
|
-
//#region ../blocks/src/lib/typeGuards.ts
|
|
32622
|
-
/**
|
|
32623
|
-
* Strict record guard: excludes null, primitives, and arrays.
|
|
32624
|
-
*/
|
|
32625
|
-
function isRecord$5(value) {
|
|
32626
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32627
|
-
}
|
|
32628
|
-
//#endregion
|
|
32629
32958
|
//#region ../blocks/src/system/transforms/registry/content.ts
|
|
32630
32959
|
const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
|
|
32631
32960
|
const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(supportedRichTextTokenSchema).default(["year", "site_name"]) });
|
|
@@ -35418,14 +35747,6 @@ const weeklySlotAvailabilityBlockDefinition = {
|
|
|
35418
35747
|
} }
|
|
35419
35748
|
};
|
|
35420
35749
|
//#endregion
|
|
35421
|
-
//#region ../blocks/src/lib/media.ts
|
|
35422
|
-
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
35423
|
-
"document",
|
|
35424
|
-
"spreadsheet",
|
|
35425
|
-
"archive",
|
|
35426
|
-
"audio"
|
|
35427
|
-
];
|
|
35428
|
-
//#endregion
|
|
35429
35750
|
//#region ../blocks/src/system/manifest/richTextSchema.ts
|
|
35430
35751
|
/**
|
|
35431
35752
|
* Shared Rich Text Schema
|
|
@@ -35601,6 +35922,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
35601
35922
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
35602
35923
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
35603
35924
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
35925
|
+
z.strictObject({
|
|
35926
|
+
currency: z.string().trim().length(3),
|
|
35927
|
+
totalCents: nonNegativeIntegerSchema,
|
|
35928
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
35929
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
35930
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
35931
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
35932
|
+
});
|
|
35604
35933
|
//#endregion
|
|
35605
35934
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
35606
35935
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -35841,6 +36170,10 @@ const publicEventBaseSchema = z.object({
|
|
|
35841
36170
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
35842
36171
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
35843
36172
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
36173
|
+
scheduleSummary: z.object({
|
|
36174
|
+
recurrenceDescription: z.string(),
|
|
36175
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
36176
|
+
}).nullable().optional(),
|
|
35844
36177
|
id: z.string(),
|
|
35845
36178
|
occurrenceId: z.string(),
|
|
35846
36179
|
seriesId: z.string(),
|
|
@@ -35849,7 +36182,7 @@ const publicEventBaseSchema = z.object({
|
|
|
35849
36182
|
content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
|
|
35850
36183
|
presentation: z.object({
|
|
35851
36184
|
summary: z.string().nullable().optional(),
|
|
35852
|
-
image:
|
|
36185
|
+
image: runtimeMediaSchema.nullable().optional()
|
|
35853
36186
|
}).optional(),
|
|
35854
36187
|
slug: z.string(),
|
|
35855
36188
|
path: z.string().nullable(),
|
|
@@ -36251,67 +36584,266 @@ const occurrenceContextSchema = z.object({
|
|
|
36251
36584
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
36252
36585
|
}).nullable();
|
|
36253
36586
|
//#endregion
|
|
36254
|
-
//#region ../blocks/src/system/runtime/
|
|
36255
|
-
|
|
36256
|
-
|
|
36257
|
-
|
|
36258
|
-
|
|
36259
|
-
|
|
36260
|
-
|
|
36261
|
-
|
|
36262
|
-
|
|
36263
|
-
|
|
36264
|
-
|
|
36265
|
-
|
|
36266
|
-
|
|
36267
|
-
"invalidEventOfferingCatalogue"
|
|
36268
|
-
])
|
|
36269
|
-
});
|
|
36270
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
36271
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
36272
|
-
if (unsupported.success) return unsupported.data;
|
|
36273
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
36274
|
-
if (parsed.ok) return parsed.value;
|
|
36275
|
-
ctx.addIssue({
|
|
36276
|
-
code: z.ZodIssueCode.custom,
|
|
36277
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
36278
|
-
});
|
|
36279
|
-
return z.NEVER;
|
|
36280
|
-
});
|
|
36281
|
-
function resolveEventRegistrationScope(context) {
|
|
36282
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
36283
|
-
if (occurrenceSeriesId) return {
|
|
36284
|
-
kind: "occurrenceSeries",
|
|
36285
|
-
seriesId: occurrenceSeriesId
|
|
36587
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
36588
|
+
/**
|
|
36589
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
36590
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
36591
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
36592
|
+
*
|
|
36593
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
36594
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
36595
|
+
*/
|
|
36596
|
+
function getEventAvailability(event) {
|
|
36597
|
+
if (event.capacity == null) return {
|
|
36598
|
+
available: null,
|
|
36599
|
+
isFull: false
|
|
36286
36600
|
};
|
|
36287
|
-
|
|
36288
|
-
|
|
36289
|
-
|
|
36601
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
36602
|
+
if (available <= 0) return {
|
|
36603
|
+
available: 0,
|
|
36604
|
+
isFull: true
|
|
36290
36605
|
};
|
|
36291
|
-
|
|
36292
|
-
|
|
36293
|
-
|
|
36294
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
36606
|
+
return {
|
|
36607
|
+
available,
|
|
36608
|
+
isFull: false
|
|
36295
36609
|
};
|
|
36296
|
-
|
|
36297
|
-
|
|
36298
|
-
|
|
36610
|
+
}
|
|
36611
|
+
/**
|
|
36612
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
36613
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
36614
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
36615
|
+
*
|
|
36616
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
36617
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
36618
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
36619
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
36620
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
36621
|
+
*/
|
|
36622
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
36623
|
+
if (!attendanceMode) return event;
|
|
36624
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
36625
|
+
}
|
|
36626
|
+
/**
|
|
36627
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
36628
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
36629
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
36630
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
36631
|
+
* `capacity - registeredCount` fallback.
|
|
36632
|
+
*/
|
|
36633
|
+
function canJoinEventWaitlist(event, options) {
|
|
36634
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
36635
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
36636
|
+
}
|
|
36637
|
+
/**
|
|
36638
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
36639
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
36640
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
36641
|
+
* to be stale on a cached page.
|
|
36642
|
+
*
|
|
36643
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
36644
|
+
*
|
|
36645
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
36646
|
+
* 5% floor stops large events staying silent until three remain.
|
|
36647
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
36648
|
+
*/
|
|
36649
|
+
function lowCapacityThreshold(capacity) {
|
|
36650
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
36651
|
+
}
|
|
36652
|
+
function getRemainingPlaces(source) {
|
|
36653
|
+
const { available, isFull } = getEventAvailability(source);
|
|
36654
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
36655
|
+
if (isFull) return {
|
|
36656
|
+
kind: "full",
|
|
36657
|
+
waitlist: canJoinEventWaitlist(source)
|
|
36299
36658
|
};
|
|
36300
|
-
|
|
36659
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
36660
|
+
kind: "low",
|
|
36661
|
+
remaining: available
|
|
36662
|
+
};
|
|
36663
|
+
return { kind: "open" };
|
|
36301
36664
|
}
|
|
36302
|
-
|
|
36303
|
-
|
|
36304
|
-
|
|
36305
|
-
|
|
36306
|
-
|
|
36307
|
-
|
|
36308
|
-
|
|
36309
|
-
|
|
36310
|
-
|
|
36311
|
-
case "
|
|
36312
|
-
case "
|
|
36665
|
+
/**
|
|
36666
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
36667
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
36668
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
36669
|
+
* it in rather than re-deriving the count.
|
|
36670
|
+
*/
|
|
36671
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
36672
|
+
const remaining = getRemainingPlaces(source);
|
|
36673
|
+
switch (remaining.kind) {
|
|
36674
|
+
case "unlimited":
|
|
36675
|
+
case "open": return null;
|
|
36676
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
36677
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
36678
|
+
}
|
|
36679
|
+
}
|
|
36680
|
+
function formatPlacesLeft(count, compact) {
|
|
36681
|
+
if (compact) return `${count} left`;
|
|
36682
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
36683
|
+
}
|
|
36684
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
36685
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
36686
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
36687
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
36688
|
+
}
|
|
36689
|
+
/**
|
|
36690
|
+
* Which capacity figure wins when they disagree.
|
|
36691
|
+
*
|
|
36692
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
36693
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
36694
|
+
* The registration write path admits or refuses per mode
|
|
36695
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
36696
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
36697
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
36698
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
36699
|
+
*
|
|
36700
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
36701
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
36702
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
36703
|
+
* the aggregate, unchanged.
|
|
36704
|
+
*/
|
|
36705
|
+
function findHybridModeRows(event) {
|
|
36706
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
36707
|
+
const rows = event.attendanceModes ?? [];
|
|
36708
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
36709
|
+
const online = rows.find((row) => row.mode === "online");
|
|
36710
|
+
return inPerson && online ? {
|
|
36711
|
+
inPerson,
|
|
36712
|
+
online
|
|
36713
|
+
} : null;
|
|
36714
|
+
}
|
|
36715
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
36716
|
+
function remainingPlacesRank(remaining) {
|
|
36717
|
+
switch (remaining.kind) {
|
|
36718
|
+
case "unlimited": return 4;
|
|
36719
|
+
case "open": return 3;
|
|
36720
|
+
case "low": return 2;
|
|
36721
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
36722
|
+
}
|
|
36723
|
+
}
|
|
36724
|
+
function isMoreOpen(candidate, than) {
|
|
36725
|
+
const rank = remainingPlacesRank(candidate);
|
|
36726
|
+
const otherRank = remainingPlacesRank(than);
|
|
36727
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
36728
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
36729
|
+
}
|
|
36730
|
+
/** True when `candidate` has less room left than `than`. */
|
|
36731
|
+
function isScarcer(candidate, than) {
|
|
36732
|
+
return isMoreOpen(than, candidate);
|
|
36733
|
+
}
|
|
36734
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
36735
|
+
in_person: "In person",
|
|
36736
|
+
online: "Online"
|
|
36737
|
+
};
|
|
36738
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
36739
|
+
const PLACES_AVAILABLE = "Places available";
|
|
36740
|
+
/**
|
|
36741
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
36742
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
36743
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
36744
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
36745
|
+
* promise the registration wizard would otherwise have to break.
|
|
36746
|
+
*
|
|
36747
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
36748
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
36749
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
36750
|
+
* { compact: true } -> "Online: 3 left"
|
|
36751
|
+
*/
|
|
36752
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
36753
|
+
const rows = findHybridModeRows(event);
|
|
36754
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
36755
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
36756
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
36757
|
+
if (inPerson === online) return inPerson;
|
|
36758
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
36759
|
+
return formatBothHybridSides(rows, {
|
|
36760
|
+
inPerson,
|
|
36761
|
+
online
|
|
36762
|
+
});
|
|
36763
|
+
}
|
|
36764
|
+
/**
|
|
36765
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
36766
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
36767
|
+
*/
|
|
36768
|
+
function formatBothHybridSides(rows, labels) {
|
|
36769
|
+
return (isMoreOpen(getRemainingPlaces(rows.online), getRemainingPlaces(rows.inPerson)) ? [["online", labels.online], ["in_person", labels.inPerson]] : [["in_person", labels.inPerson], ["online", labels.online]]).map(([mode, label]) => namedModePlaces(mode, label)).join(" · ");
|
|
36770
|
+
}
|
|
36771
|
+
function namedModePlaces(mode, label) {
|
|
36772
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
36773
|
+
}
|
|
36774
|
+
/**
|
|
36775
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
36776
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
36777
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
36778
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
36779
|
+
* how the event is delivered rather than about its remaining places.
|
|
36780
|
+
*/
|
|
36781
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
36782
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
36783
|
+
const online = getRemainingPlaces(rows.online);
|
|
36784
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
36785
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
36786
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
36787
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
36788
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
36789
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
36790
|
+
}
|
|
36791
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
36792
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
36793
|
+
}
|
|
36794
|
+
function rowFor(rows, mode) {
|
|
36795
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
36796
|
+
}
|
|
36797
|
+
//#endregion
|
|
36798
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
36799
|
+
const registrationDisplaySchema = z.object({
|
|
36800
|
+
venue: z.enum(["shown", "hidden"]),
|
|
36801
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
36802
|
+
});
|
|
36803
|
+
function resolveRegistrationDisplay(source) {
|
|
36804
|
+
return {
|
|
36805
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
36806
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
36807
|
+
};
|
|
36808
|
+
}
|
|
36809
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
36810
|
+
function shownVenue(event, display) {
|
|
36811
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
36812
|
+
}
|
|
36813
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
36814
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
36815
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
36816
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
36817
|
+
return capacityPlacesLabel(source, display, wording);
|
|
36818
|
+
}
|
|
36819
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
36820
|
+
const remaining = getRemainingPlaces(source);
|
|
36821
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
36822
|
+
switch (remaining.kind) {
|
|
36823
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
36824
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
36825
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
36826
|
+
case "open": return wording.open ?? null;
|
|
36827
|
+
default: return assertNever$2(remaining);
|
|
36313
36828
|
}
|
|
36314
36829
|
}
|
|
36830
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
36831
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
36832
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
36833
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
36834
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
36835
|
+
}).join(" · ") || null;
|
|
36836
|
+
}
|
|
36837
|
+
function ticketPlacesLabel(remaining, display) {
|
|
36838
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
36839
|
+
return formatTicketTypeRemaining(remaining);
|
|
36840
|
+
}
|
|
36841
|
+
//#endregion
|
|
36842
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
36843
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
36844
|
+
kind: z.literal("preview"),
|
|
36845
|
+
token: z.string().min(1)
|
|
36846
|
+
}).strict()]);
|
|
36315
36847
|
//#endregion
|
|
36316
36848
|
//#region ../calendar/src/grid.ts
|
|
36317
36849
|
const MONTH_NAMES = [
|
|
@@ -36399,6 +36931,11 @@ function buildCalendarViewport(input) {
|
|
|
36399
36931
|
//#endregion
|
|
36400
36932
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
36401
36933
|
/**
|
|
36934
|
+
* Date and time presentation for events: the single place an event's
|
|
36935
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
36936
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
36937
|
+
*/
|
|
36938
|
+
/**
|
|
36402
36939
|
* The English locale a site's public dates are written in, read from the
|
|
36403
36940
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
36404
36941
|
*
|
|
@@ -36418,6 +36955,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
36418
36955
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
36419
36956
|
return "en-US";
|
|
36420
36957
|
}
|
|
36958
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
36959
|
+
const locale = options?.locale ?? "en-US";
|
|
36960
|
+
const dateTime = toScheduledBookingDateTime({
|
|
36961
|
+
startsAt: isoTimestamp,
|
|
36962
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
36963
|
+
locale
|
|
36964
|
+
});
|
|
36965
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
36966
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
36967
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
36968
|
+
return {
|
|
36969
|
+
weekday,
|
|
36970
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
36971
|
+
month,
|
|
36972
|
+
label: formatBookingDate(dateTime, {
|
|
36973
|
+
weekday: "long",
|
|
36974
|
+
year: "numeric",
|
|
36975
|
+
month: "long",
|
|
36976
|
+
day: "numeric"
|
|
36977
|
+
})
|
|
36978
|
+
};
|
|
36979
|
+
}
|
|
36421
36980
|
//#endregion
|
|
36422
36981
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
36423
36982
|
function isRecord$4(value) {
|
|
@@ -36437,6 +36996,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
36437
36996
|
};
|
|
36438
36997
|
}
|
|
36439
36998
|
//#endregion
|
|
36999
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
37000
|
+
/**
|
|
37001
|
+
* Format an event's price directly from its pricing value (without the full
|
|
37002
|
+
* event). Same output as {@link formatEventPrice}.
|
|
37003
|
+
*/
|
|
37004
|
+
function formatEventPriceDisplay(pricing) {
|
|
37005
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
37006
|
+
}
|
|
37007
|
+
//#endregion
|
|
36440
37008
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
36441
37009
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
36442
37010
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -36471,6 +37039,642 @@ function eventListWindowEvents(events, window) {
|
|
|
36471
37039
|
});
|
|
36472
37040
|
}
|
|
36473
37041
|
//#endregion
|
|
37042
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
37043
|
+
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
37044
|
+
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
37045
|
+
}
|
|
37046
|
+
function findPreSelectedEvent(input) {
|
|
37047
|
+
const occurrenceContext = input.occurrenceContext;
|
|
37048
|
+
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
37049
|
+
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
37050
|
+
startsAt: occurrenceContext.startsAt,
|
|
37051
|
+
timeZone: occurrenceContext.timeZone
|
|
37052
|
+
}));
|
|
37053
|
+
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
37054
|
+
startsAt: event.startsAt,
|
|
37055
|
+
timeZone: event.timeZone
|
|
37056
|
+
})) === contextDate) ?? null;
|
|
37057
|
+
}
|
|
37058
|
+
function resolveEventRequiresPayment(input) {
|
|
37059
|
+
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
37060
|
+
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
37061
|
+
if (!input.event) return false;
|
|
37062
|
+
return publicEventPricingType(input.event.pricing) === "paid";
|
|
37063
|
+
}
|
|
37064
|
+
//#endregion
|
|
37065
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
37066
|
+
/**
|
|
37067
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
37068
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
37069
|
+
* English when the site names no zone.
|
|
37070
|
+
*/
|
|
37071
|
+
function bookingDateLocale(siteTimeZone) {
|
|
37072
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
37073
|
+
}
|
|
37074
|
+
function bookingInstant(startsAt, input) {
|
|
37075
|
+
return toScheduledBookingDateTime({
|
|
37076
|
+
startsAt,
|
|
37077
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
37078
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
37079
|
+
});
|
|
37080
|
+
}
|
|
37081
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
37082
|
+
function bookingClock(startsAt, input) {
|
|
37083
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
37084
|
+
hour: "numeric",
|
|
37085
|
+
minute: "2-digit",
|
|
37086
|
+
hour12: true
|
|
37087
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
37088
|
+
}
|
|
37089
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
37090
|
+
function clockRange(input) {
|
|
37091
|
+
const start = bookingClock(input.startsAt, input);
|
|
37092
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
37093
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
37094
|
+
}
|
|
37095
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
37096
|
+
function formatBookingScheduleSummary(event) {
|
|
37097
|
+
const summary = event.scheduleSummary;
|
|
37098
|
+
if (!summary) return null;
|
|
37099
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
37100
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
37101
|
+
timeZone: "UTC",
|
|
37102
|
+
siteTimeZone: event.siteTimeZone
|
|
37103
|
+
}, "time") : null;
|
|
37104
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
37105
|
+
}
|
|
37106
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
37107
|
+
function formatBookingWhen(input, variant) {
|
|
37108
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
37109
|
+
const day = formatBookingDate(instant, {
|
|
37110
|
+
weekday: "short",
|
|
37111
|
+
day: "numeric",
|
|
37112
|
+
month: "short"
|
|
37113
|
+
});
|
|
37114
|
+
switch (variant) {
|
|
37115
|
+
case "day": return day;
|
|
37116
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
37117
|
+
weekday: "long",
|
|
37118
|
+
day: "numeric",
|
|
37119
|
+
month: "long"
|
|
37120
|
+
});
|
|
37121
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
37122
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
37123
|
+
month: "long",
|
|
37124
|
+
year: "numeric"
|
|
37125
|
+
});
|
|
37126
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
37127
|
+
case "timeRange": return clockRange(input);
|
|
37128
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
37129
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
37130
|
+
}
|
|
37131
|
+
}
|
|
37132
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
37133
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
37134
|
+
return formatBookingWhen({
|
|
37135
|
+
startsAt: isoTimestamp,
|
|
37136
|
+
timeZone: options?.timeZone,
|
|
37137
|
+
siteTimeZone: options?.siteTimeZone
|
|
37138
|
+
}, "short");
|
|
37139
|
+
}
|
|
37140
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
37141
|
+
function occurrenceTitleOverride(occurrence) {
|
|
37142
|
+
const title = occurrence?.overrides?.title;
|
|
37143
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
37144
|
+
}
|
|
37145
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
37146
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
37147
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
37148
|
+
return event && title ? {
|
|
37149
|
+
...event,
|
|
37150
|
+
title
|
|
37151
|
+
} : event;
|
|
37152
|
+
}
|
|
37153
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
37154
|
+
const first = sessions[0];
|
|
37155
|
+
if (!first) return null;
|
|
37156
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
37157
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
37158
|
+
timeZone: first.timeZone,
|
|
37159
|
+
siteTimeZone
|
|
37160
|
+
});
|
|
37161
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
37162
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
37163
|
+
timeZone: last.timeZone,
|
|
37164
|
+
siteTimeZone
|
|
37165
|
+
});
|
|
37166
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
37167
|
+
}
|
|
37168
|
+
/**
|
|
37169
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
37170
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
37171
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
37172
|
+
*/
|
|
37173
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
37174
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
37175
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
37176
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
37177
|
+
}
|
|
37178
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
37179
|
+
function scheduleInput(event, occurrence) {
|
|
37180
|
+
const times = occurrence?.startsAt ? {
|
|
37181
|
+
startsAt: occurrence.startsAt,
|
|
37182
|
+
endsAt: occurrence.endsAt ?? null
|
|
37183
|
+
} : {
|
|
37184
|
+
startsAt: event.startsAt,
|
|
37185
|
+
endsAt: event.endsAt
|
|
37186
|
+
};
|
|
37187
|
+
if (!times.startsAt) return null;
|
|
37188
|
+
return {
|
|
37189
|
+
...times,
|
|
37190
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
37191
|
+
siteTimeZone: event.siteTimeZone
|
|
37192
|
+
};
|
|
37193
|
+
}
|
|
37194
|
+
//#endregion
|
|
37195
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
37196
|
+
function registrationRoute(input) {
|
|
37197
|
+
const base = input.chooseEvent ? [
|
|
37198
|
+
"select-event",
|
|
37199
|
+
"select-tickets",
|
|
37200
|
+
"enter-details"
|
|
37201
|
+
] : ["select-tickets", "enter-details"];
|
|
37202
|
+
switch (input.payment) {
|
|
37203
|
+
case "none": return base;
|
|
37204
|
+
case "options": return [...base, "select-payment"];
|
|
37205
|
+
case "optionsAndPayment": return [
|
|
37206
|
+
...base,
|
|
37207
|
+
"select-payment",
|
|
37208
|
+
"payment"
|
|
37209
|
+
];
|
|
37210
|
+
}
|
|
37211
|
+
}
|
|
37212
|
+
const REGISTRATION_STEP_LABELS = [
|
|
37213
|
+
"Event",
|
|
37214
|
+
"Date",
|
|
37215
|
+
"Tickets",
|
|
37216
|
+
"Places",
|
|
37217
|
+
"Your details",
|
|
37218
|
+
"How you’ll pay",
|
|
37219
|
+
"Payment"
|
|
37220
|
+
];
|
|
37221
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
37222
|
+
function getEventSelectionMode(events) {
|
|
37223
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
37224
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
37225
|
+
}
|
|
37226
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
37227
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
37228
|
+
return {
|
|
37229
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
37230
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
37231
|
+
};
|
|
37232
|
+
}
|
|
37233
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
37234
|
+
function registrationStepLabel(step, context) {
|
|
37235
|
+
switch (step) {
|
|
37236
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
37237
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
37238
|
+
case "enter-details": return "Your details";
|
|
37239
|
+
case "select-payment": return "How you’ll pay";
|
|
37240
|
+
case "payment": return "Payment";
|
|
37241
|
+
}
|
|
37242
|
+
}
|
|
37243
|
+
function bookingButtonText(buttonText) {
|
|
37244
|
+
return buttonText?.trim() || "Book your place";
|
|
37245
|
+
}
|
|
37246
|
+
function placesLabel(event, input, compact) {
|
|
37247
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
37248
|
+
}
|
|
37249
|
+
function isFull(event, mode) {
|
|
37250
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
37251
|
+
full: "full",
|
|
37252
|
+
waitlist: "full"
|
|
37253
|
+
}) === "full";
|
|
37254
|
+
}
|
|
37255
|
+
function priceLabel(event) {
|
|
37256
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
37257
|
+
}
|
|
37258
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
37259
|
+
function lowestPaidAmount(display) {
|
|
37260
|
+
switch (display.kind) {
|
|
37261
|
+
case "exact":
|
|
37262
|
+
case "from": return display.amount;
|
|
37263
|
+
case "range": return display.minAmount;
|
|
37264
|
+
case "mixed": return display.paidFromAmount;
|
|
37265
|
+
case "free":
|
|
37266
|
+
case "unavailable":
|
|
37267
|
+
case "external": return null;
|
|
37268
|
+
}
|
|
37269
|
+
}
|
|
37270
|
+
/**
|
|
37271
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
37272
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
37273
|
+
*/
|
|
37274
|
+
function seriesPriceLabel(events) {
|
|
37275
|
+
const firstEvent = events[0];
|
|
37276
|
+
if (!firstEvent) return null;
|
|
37277
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
37278
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
37279
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
37280
|
+
const lowest = displays.flatMap((display) => {
|
|
37281
|
+
const amount = lowestPaidAmount(display);
|
|
37282
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
37283
|
+
amount,
|
|
37284
|
+
currency: display.currency
|
|
37285
|
+
}];
|
|
37286
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
37287
|
+
return lowest ? formatBookingPriceDisplay({
|
|
37288
|
+
kind: "from",
|
|
37289
|
+
amount: lowest.amount,
|
|
37290
|
+
currency: lowest.currency
|
|
37291
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
37292
|
+
}
|
|
37293
|
+
function dateTile(event) {
|
|
37294
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
37295
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
37296
|
+
return {
|
|
37297
|
+
month: rail.month,
|
|
37298
|
+
day: rail.day
|
|
37299
|
+
};
|
|
37300
|
+
}
|
|
37301
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
37302
|
+
function formatBookingShortDate(event) {
|
|
37303
|
+
return formatBookingWhen(event, "day");
|
|
37304
|
+
}
|
|
37305
|
+
function byStart(left, right) {
|
|
37306
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
37307
|
+
}
|
|
37308
|
+
function singleEntry(event, input) {
|
|
37309
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
37310
|
+
return {
|
|
37311
|
+
kind: "single",
|
|
37312
|
+
title: event.title,
|
|
37313
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
37314
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
37315
|
+
venue: shownVenue(event, input.display),
|
|
37316
|
+
price: priceLabel(event),
|
|
37317
|
+
places: placesLabel(event, input, false),
|
|
37318
|
+
tile: dateTile(event),
|
|
37319
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
37320
|
+
};
|
|
37321
|
+
}
|
|
37322
|
+
function chooseDateEntry(input) {
|
|
37323
|
+
const ordered = [...input.events].sort(byStart);
|
|
37324
|
+
const first = ordered[0];
|
|
37325
|
+
const shown = ordered.slice(0, 4);
|
|
37326
|
+
return {
|
|
37327
|
+
kind: "chooseDate",
|
|
37328
|
+
title: first?.title ?? "",
|
|
37329
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
37330
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
37331
|
+
price: seriesPriceLabel(ordered),
|
|
37332
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
37333
|
+
dateCount: ordered.length,
|
|
37334
|
+
dates: shown.map((event) => ({
|
|
37335
|
+
selectionId: event.selectionId,
|
|
37336
|
+
label: formatBookingShortDate(event),
|
|
37337
|
+
places: placesLabel(event, input, true),
|
|
37338
|
+
full: isFull(event, input.attendanceMode)
|
|
37339
|
+
})),
|
|
37340
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
37341
|
+
action: "Choose a date"
|
|
37342
|
+
};
|
|
37343
|
+
}
|
|
37344
|
+
/** The card before a booking starts; the server renders this too. */
|
|
37345
|
+
function idleBookingEntry(input) {
|
|
37346
|
+
if (input.event) return singleEntry(input.event, input);
|
|
37347
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
37348
|
+
if (only) return singleEntry(only, input);
|
|
37349
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
37350
|
+
return {
|
|
37351
|
+
kind: "chooseEvent",
|
|
37352
|
+
title: input.events[0]?.title ?? "",
|
|
37353
|
+
count: input.events.length,
|
|
37354
|
+
noun: input.noun.pluralLabel,
|
|
37355
|
+
action: "Choose an event"
|
|
37356
|
+
};
|
|
37357
|
+
}
|
|
37358
|
+
//#endregion
|
|
37359
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
37360
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
37361
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
37362
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
37363
|
+
{
|
|
37364
|
+
preset: "class",
|
|
37365
|
+
sourceKey: "eventPreset:class",
|
|
37366
|
+
dataKey: "classEvents",
|
|
37367
|
+
label: "Classes"
|
|
37368
|
+
},
|
|
37369
|
+
{
|
|
37370
|
+
preset: "workshop",
|
|
37371
|
+
sourceKey: "eventPreset:workshop",
|
|
37372
|
+
dataKey: "workshopEvents",
|
|
37373
|
+
label: "Workshops"
|
|
37374
|
+
},
|
|
37375
|
+
{
|
|
37376
|
+
preset: "retreat",
|
|
37377
|
+
sourceKey: "eventPreset:retreat",
|
|
37378
|
+
dataKey: "retreatEvents",
|
|
37379
|
+
label: "Retreats"
|
|
37380
|
+
},
|
|
37381
|
+
{
|
|
37382
|
+
preset: "performance",
|
|
37383
|
+
sourceKey: "eventPreset:performance",
|
|
37384
|
+
dataKey: "performanceEvents",
|
|
37385
|
+
label: "Performances"
|
|
37386
|
+
}
|
|
37387
|
+
];
|
|
37388
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
37389
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
37390
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
37391
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
37392
|
+
kind: "eventPreset",
|
|
37393
|
+
preset: definition.preset
|
|
37394
|
+
}]));
|
|
37395
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
37396
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
37397
|
+
}
|
|
37398
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
37399
|
+
if (value == null) return { kind: "legacy" };
|
|
37400
|
+
if (value.length === 0) return { kind: "default" };
|
|
37401
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
37402
|
+
return keys.length > 0 ? {
|
|
37403
|
+
kind: "custom",
|
|
37404
|
+
keys
|
|
37405
|
+
} : { kind: "default" };
|
|
37406
|
+
}
|
|
37407
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
37408
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
37409
|
+
return keys.length >= 2 ? keys : [];
|
|
37410
|
+
}
|
|
37411
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
37412
|
+
if (!isRecord$3(value)) return null;
|
|
37413
|
+
const groupOrderValue = value.groupOrder;
|
|
37414
|
+
if (Array.isArray(groupOrderValue)) {
|
|
37415
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
37416
|
+
return {
|
|
37417
|
+
...value,
|
|
37418
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
37419
|
+
};
|
|
37420
|
+
}
|
|
37421
|
+
if (groupOrderValue != null) return {
|
|
37422
|
+
...value,
|
|
37423
|
+
groupOrder: []
|
|
37424
|
+
};
|
|
37425
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$3) : []);
|
|
37426
|
+
return legacyOrder.length > 0 ? {
|
|
37427
|
+
...value,
|
|
37428
|
+
groupOrder: legacyOrder
|
|
37429
|
+
} : value;
|
|
37430
|
+
}
|
|
37431
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
37432
|
+
function sourceFromPresetSummary(preset) {
|
|
37433
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
37434
|
+
if (preset.engine !== "event_series") return null;
|
|
37435
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
37436
|
+
kind: "eventPreset",
|
|
37437
|
+
preset: preset.canonicalBehaviour
|
|
37438
|
+
};
|
|
37439
|
+
return null;
|
|
37440
|
+
}
|
|
37441
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
37442
|
+
const keys = [];
|
|
37443
|
+
for (const value of values) {
|
|
37444
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
37445
|
+
if (!keys.includes(value)) keys.push(value);
|
|
37446
|
+
}
|
|
37447
|
+
return keys;
|
|
37448
|
+
}
|
|
37449
|
+
function isRecord$3(value) {
|
|
37450
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37451
|
+
}
|
|
37452
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
37453
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
37454
|
+
}
|
|
37455
|
+
//#endregion
|
|
37456
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
37457
|
+
function offeringKindForEvent(event) {
|
|
37458
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
37459
|
+
}
|
|
37460
|
+
function presetKind(preset) {
|
|
37461
|
+
const source = sourceFromPresetSummary(preset);
|
|
37462
|
+
if (!source) return null;
|
|
37463
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
37464
|
+
}
|
|
37465
|
+
/**
|
|
37466
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
37467
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
37468
|
+
* name stands in when the site has none.
|
|
37469
|
+
*/
|
|
37470
|
+
function offeringNounForEvent(event, presets) {
|
|
37471
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
37472
|
+
const kind = offeringKindForEvent(event);
|
|
37473
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
37474
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
37475
|
+
}
|
|
37476
|
+
function lowerCased(noun) {
|
|
37477
|
+
return {
|
|
37478
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
37479
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
37480
|
+
};
|
|
37481
|
+
}
|
|
37482
|
+
//#endregion
|
|
37483
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
37484
|
+
function toRegistrationEvent(event) {
|
|
37485
|
+
return {
|
|
37486
|
+
...event,
|
|
37487
|
+
selectionId: event.id,
|
|
37488
|
+
registrationSubject: {
|
|
37489
|
+
kind: "occurrence",
|
|
37490
|
+
occurrenceId: event.occurrenceId
|
|
37491
|
+
}
|
|
37492
|
+
};
|
|
37493
|
+
}
|
|
37494
|
+
function toRegistrationEvents(events) {
|
|
37495
|
+
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
37496
|
+
}
|
|
37497
|
+
/**
|
|
37498
|
+
* Project one whole-series run onto the registration surface.
|
|
37499
|
+
*
|
|
37500
|
+
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
37501
|
+
* Event record; only the schedule is widened from the single occurrence to the
|
|
37502
|
+
* live run. A run without live sessions has no registration event.
|
|
37503
|
+
*/
|
|
37504
|
+
function toWholeSeriesRegistrationEvent(group) {
|
|
37505
|
+
const { representative, run } = group;
|
|
37506
|
+
const sessions = orderedLiveRunSessions(run.sessions);
|
|
37507
|
+
const firstSession = sessions[0];
|
|
37508
|
+
if (!firstSession) return null;
|
|
37509
|
+
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
37510
|
+
return {
|
|
37511
|
+
...representative,
|
|
37512
|
+
selectionId: run.eventSeriesId,
|
|
37513
|
+
registrationSubject: {
|
|
37514
|
+
kind: "wholeSeries",
|
|
37515
|
+
eventSeriesId: run.eventSeriesId,
|
|
37516
|
+
sessions
|
|
37517
|
+
},
|
|
37518
|
+
startsAt: firstSession.startsAt,
|
|
37519
|
+
endsAt: lastSession.endsAt,
|
|
37520
|
+
timeZone: firstSession.timeZone
|
|
37521
|
+
};
|
|
37522
|
+
}
|
|
37523
|
+
function toWholeSeriesRegistrationEvents(events) {
|
|
37524
|
+
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
37525
|
+
}
|
|
37526
|
+
//#endregion
|
|
37527
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
37528
|
+
/**
|
|
37529
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
37530
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
37531
|
+
* so the server and the client agree on one card.
|
|
37532
|
+
*/
|
|
37533
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
37534
|
+
const tileSchema = z.object({
|
|
37535
|
+
month: z.string(),
|
|
37536
|
+
day: z.string()
|
|
37537
|
+
}).nullable();
|
|
37538
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
37539
|
+
z.object({
|
|
37540
|
+
kind: z.literal("single"),
|
|
37541
|
+
title: z.string(),
|
|
37542
|
+
when: z.string().nullable(),
|
|
37543
|
+
shortWhen: z.string().nullable(),
|
|
37544
|
+
venue: z.string().nullable(),
|
|
37545
|
+
price: z.string().nullable(),
|
|
37546
|
+
places: z.string().nullable(),
|
|
37547
|
+
tile: tileSchema,
|
|
37548
|
+
action: z.string()
|
|
37549
|
+
}),
|
|
37550
|
+
z.object({
|
|
37551
|
+
kind: z.literal("chooseDate"),
|
|
37552
|
+
title: z.string(),
|
|
37553
|
+
schedule: z.string(),
|
|
37554
|
+
venue: z.string().nullable(),
|
|
37555
|
+
price: z.string().nullable(),
|
|
37556
|
+
nextDate: z.string().nullable(),
|
|
37557
|
+
dateCount: z.number(),
|
|
37558
|
+
dates: z.array(z.object({
|
|
37559
|
+
selectionId: z.string(),
|
|
37560
|
+
label: z.string(),
|
|
37561
|
+
places: z.string().nullable(),
|
|
37562
|
+
full: z.boolean()
|
|
37563
|
+
})),
|
|
37564
|
+
moreCount: z.number(),
|
|
37565
|
+
action: z.string()
|
|
37566
|
+
}),
|
|
37567
|
+
z.object({
|
|
37568
|
+
kind: z.literal("chooseEvent"),
|
|
37569
|
+
title: z.string(),
|
|
37570
|
+
count: z.number(),
|
|
37571
|
+
noun: z.string(),
|
|
37572
|
+
action: z.string()
|
|
37573
|
+
})
|
|
37574
|
+
]);
|
|
37575
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
37576
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
37577
|
+
}
|
|
37578
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
37579
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37580
|
+
return {
|
|
37581
|
+
scopedEvents,
|
|
37582
|
+
preSelected: findPreSelectedEvent({
|
|
37583
|
+
scopedEvents,
|
|
37584
|
+
occurrenceContext: source.occurrenceContext
|
|
37585
|
+
})
|
|
37586
|
+
};
|
|
37587
|
+
}
|
|
37588
|
+
function nounFor(scoped, presets) {
|
|
37589
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
37590
|
+
}
|
|
37591
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
37592
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
37593
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
37594
|
+
}
|
|
37595
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
37596
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
37597
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
37598
|
+
return idleBookingEntry({
|
|
37599
|
+
events: scoped.scopedEvents,
|
|
37600
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
37601
|
+
display,
|
|
37602
|
+
buttonText: source.buttonText,
|
|
37603
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
37604
|
+
attendanceMode: null
|
|
37605
|
+
});
|
|
37606
|
+
}
|
|
37607
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
37608
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
37609
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
37610
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
37611
|
+
if (!entry) return null;
|
|
37612
|
+
return {
|
|
37613
|
+
kind: "event-registration",
|
|
37614
|
+
state: "booking-card",
|
|
37615
|
+
className: source.className ?? null,
|
|
37616
|
+
entry,
|
|
37617
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
37618
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
37619
|
+
};
|
|
37620
|
+
}
|
|
37621
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
37622
|
+
kind: z.literal("unsupported"),
|
|
37623
|
+
reason: z.enum([
|
|
37624
|
+
"unsupportedSubject",
|
|
37625
|
+
"invalidEventSeriesId",
|
|
37626
|
+
"invalidEventSeriesBookingScope",
|
|
37627
|
+
"invalidEventOfferingId",
|
|
37628
|
+
"invalidEventOfferingBookingScope",
|
|
37629
|
+
"invalidEventOfferingCatalogue"
|
|
37630
|
+
])
|
|
37631
|
+
});
|
|
37632
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
37633
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
37634
|
+
if (unsupported.success) return unsupported.data;
|
|
37635
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
37636
|
+
if (parsed.ok) return parsed.value;
|
|
37637
|
+
ctx.addIssue({
|
|
37638
|
+
code: z.ZodIssueCode.custom,
|
|
37639
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
37640
|
+
});
|
|
37641
|
+
return z.NEVER;
|
|
37642
|
+
});
|
|
37643
|
+
function resolveEventRegistrationScope(context) {
|
|
37644
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
37645
|
+
if (occurrenceSeriesId) return {
|
|
37646
|
+
kind: "occurrenceSeries",
|
|
37647
|
+
seriesId: occurrenceSeriesId
|
|
37648
|
+
};
|
|
37649
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
37650
|
+
kind: "pageSurfaceSeries",
|
|
37651
|
+
seriesId: context.subject.eventSeriesId
|
|
37652
|
+
};
|
|
37653
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
37654
|
+
kind: "pageSurfaceOffering",
|
|
37655
|
+
offeringId: context.subject.eventOfferingId,
|
|
37656
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
37657
|
+
};
|
|
37658
|
+
if (context.subject?.kind === "unsupported") return {
|
|
37659
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
37660
|
+
reason: context.subject.reason
|
|
37661
|
+
};
|
|
37662
|
+
return { kind: "unscoped" };
|
|
37663
|
+
}
|
|
37664
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
37665
|
+
const scope = resolveEventRegistrationScope(context);
|
|
37666
|
+
switch (scope.kind) {
|
|
37667
|
+
case "occurrenceSeries":
|
|
37668
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
37669
|
+
case "pageSurfaceOffering": {
|
|
37670
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
37671
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
37672
|
+
}
|
|
37673
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
37674
|
+
case "unscoped": return [...events];
|
|
37675
|
+
}
|
|
37676
|
+
}
|
|
37677
|
+
//#endregion
|
|
36474
37678
|
//#region ../blocks/src/system/constants/events.ts
|
|
36475
37679
|
const eventCalendarDisplayModeValues = [
|
|
36476
37680
|
"combined",
|
|
@@ -36593,95 +37797,6 @@ const calendarTabViewsSchema = z.enum([
|
|
|
36593
37797
|
"week"
|
|
36594
37798
|
]);
|
|
36595
37799
|
//#endregion
|
|
36596
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
36597
|
-
/**
|
|
36598
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
36599
|
-
*
|
|
36600
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
36601
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
36602
|
-
* @returns Array of wizard steps to display
|
|
36603
|
-
*/
|
|
36604
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
36605
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
36606
|
-
"select-event",
|
|
36607
|
-
"select-tickets",
|
|
36608
|
-
"enter-details"
|
|
36609
|
-
];
|
|
36610
|
-
if (!needsPaymentStep) return baseSteps;
|
|
36611
|
-
return paymentActive ? [
|
|
36612
|
-
...baseSteps,
|
|
36613
|
-
"select-payment",
|
|
36614
|
-
"payment"
|
|
36615
|
-
] : [...baseSteps, "select-payment"];
|
|
36616
|
-
}
|
|
36617
|
-
//#endregion
|
|
36618
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
36619
|
-
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
36620
|
-
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
36621
|
-
}
|
|
36622
|
-
function findPreSelectedEvent(input) {
|
|
36623
|
-
const occurrenceContext = input.occurrenceContext;
|
|
36624
|
-
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
36625
|
-
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
36626
|
-
startsAt: occurrenceContext.startsAt,
|
|
36627
|
-
timeZone: occurrenceContext.timeZone
|
|
36628
|
-
}));
|
|
36629
|
-
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
36630
|
-
startsAt: event.startsAt,
|
|
36631
|
-
timeZone: event.timeZone
|
|
36632
|
-
})) === contextDate) ?? null;
|
|
36633
|
-
}
|
|
36634
|
-
function resolveEventRequiresPayment(input) {
|
|
36635
|
-
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
36636
|
-
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
36637
|
-
if (!input.event) return false;
|
|
36638
|
-
return publicEventPricingType(input.event.pricing) === "paid";
|
|
36639
|
-
}
|
|
36640
|
-
//#endregion
|
|
36641
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
36642
|
-
function toRegistrationEvent(event) {
|
|
36643
|
-
return {
|
|
36644
|
-
...event,
|
|
36645
|
-
selectionId: event.id,
|
|
36646
|
-
registrationSubject: {
|
|
36647
|
-
kind: "occurrence",
|
|
36648
|
-
occurrenceId: event.occurrenceId
|
|
36649
|
-
}
|
|
36650
|
-
};
|
|
36651
|
-
}
|
|
36652
|
-
function toRegistrationEvents(events) {
|
|
36653
|
-
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
36654
|
-
}
|
|
36655
|
-
/**
|
|
36656
|
-
* Project one whole-series run onto the registration surface.
|
|
36657
|
-
*
|
|
36658
|
-
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
36659
|
-
* Event record; only the schedule is widened from the single occurrence to the
|
|
36660
|
-
* live run. A run without live sessions has no registration event.
|
|
36661
|
-
*/
|
|
36662
|
-
function toWholeSeriesRegistrationEvent(group) {
|
|
36663
|
-
const { representative, run } = group;
|
|
36664
|
-
const sessions = orderedLiveRunSessions(run.sessions);
|
|
36665
|
-
const firstSession = sessions[0];
|
|
36666
|
-
if (!firstSession) return null;
|
|
36667
|
-
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
36668
|
-
return {
|
|
36669
|
-
...representative,
|
|
36670
|
-
selectionId: run.eventSeriesId,
|
|
36671
|
-
registrationSubject: {
|
|
36672
|
-
kind: "wholeSeries",
|
|
36673
|
-
eventSeriesId: run.eventSeriesId,
|
|
36674
|
-
sessions
|
|
36675
|
-
},
|
|
36676
|
-
startsAt: firstSession.startsAt,
|
|
36677
|
-
endsAt: lastSession.endsAt,
|
|
36678
|
-
timeZone: firstSession.timeZone
|
|
36679
|
-
};
|
|
36680
|
-
}
|
|
36681
|
-
function toWholeSeriesRegistrationEvents(events) {
|
|
36682
|
-
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
36683
|
-
}
|
|
36684
|
-
//#endregion
|
|
36685
37800
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
36686
37801
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
36687
37802
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -36724,27 +37839,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
36724
37839
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
36725
37840
|
"Date",
|
|
36726
37841
|
"Tickets",
|
|
36727
|
-
"
|
|
36728
|
-
];
|
|
36729
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
36730
|
-
"Event",
|
|
36731
|
-
"Date",
|
|
36732
|
-
"Tickets",
|
|
36733
|
-
"Details",
|
|
36734
|
-
"Payment options",
|
|
36735
|
-
"Payment"
|
|
37842
|
+
"Your details"
|
|
36736
37843
|
];
|
|
36737
37844
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
36738
|
-
const
|
|
37845
|
+
const eventRegistrationCommonSchemaShape = {
|
|
36739
37846
|
demoEmailSuppressed: z.boolean().optional(),
|
|
36740
37847
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
36741
37848
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
36742
37849
|
maxTickets: z.string().optional(),
|
|
36743
|
-
showVenue: z.boolean().optional(),
|
|
36744
|
-
showCapacity: z.boolean().optional(),
|
|
36745
37850
|
successMessage: z.string().optional(),
|
|
36746
37851
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
36747
|
-
|
|
37852
|
+
host: bookingHostSchema.optional(),
|
|
36748
37853
|
spamProtectionEnabled: z.boolean().optional(),
|
|
36749
37854
|
supportEmail: z.string().optional(),
|
|
36750
37855
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -36769,32 +37874,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
36769
37874
|
portalToken: z.string().nullable().optional(),
|
|
36770
37875
|
previewToken: z.string().nullable().optional(),
|
|
36771
37876
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36772
|
-
...
|
|
37877
|
+
...eventRegistrationCommonSchemaShape,
|
|
37878
|
+
showVenue: z.boolean().optional(),
|
|
37879
|
+
showCapacity: z.boolean().optional(),
|
|
36773
37880
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36774
37881
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36775
37882
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
36776
37883
|
className: z.string().nullable().optional(),
|
|
36777
37884
|
buttonText: z.string().nullable().optional(),
|
|
36778
37885
|
maxTickets: z.string().nullable().optional(),
|
|
36779
|
-
stage: previewStageSchema.optional()
|
|
37886
|
+
stage: previewStageSchema.optional(),
|
|
37887
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
36780
37888
|
});
|
|
36781
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
36793
|
-
|
|
36794
|
-
|
|
36795
|
-
|
|
37889
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
37890
|
+
z.object({
|
|
37891
|
+
kind: z.literal("event-registration"),
|
|
37892
|
+
state: z.literal("generic-shell"),
|
|
37893
|
+
className: z.string().nullable(),
|
|
37894
|
+
titleText: z.string(),
|
|
37895
|
+
bodyText: z.string(),
|
|
37896
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
37897
|
+
summaryButtonText: z.string()
|
|
37898
|
+
}),
|
|
37899
|
+
z.object({
|
|
37900
|
+
kind: z.literal("event-registration"),
|
|
37901
|
+
state: z.literal("registration-closed"),
|
|
37902
|
+
className: z.string().nullable(),
|
|
37903
|
+
titleText: z.string(),
|
|
37904
|
+
bodyText: z.string()
|
|
37905
|
+
}),
|
|
37906
|
+
z.object({
|
|
37907
|
+
kind: z.literal("event-registration"),
|
|
37908
|
+
state: z.literal("booking-card"),
|
|
37909
|
+
className: z.string().nullable(),
|
|
37910
|
+
entry: idleBookingEntrySchema,
|
|
37911
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
37912
|
+
buttonText: z.string()
|
|
37913
|
+
})
|
|
37914
|
+
]);
|
|
36796
37915
|
const eventRegistrationHydrationSchema = z.object({
|
|
36797
|
-
...
|
|
37916
|
+
...eventRegistrationCommonSchemaShape,
|
|
37917
|
+
display: registrationDisplaySchema,
|
|
37918
|
+
offeringNoun: z.object({
|
|
37919
|
+
label: z.string(),
|
|
37920
|
+
pluralLabel: z.string()
|
|
37921
|
+
}).optional(),
|
|
36798
37922
|
eventSource: eventRegistrationEventSourceSchema
|
|
36799
37923
|
});
|
|
36800
37924
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -36809,7 +37933,7 @@ z.object({
|
|
|
36809
37933
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36810
37934
|
stage: previewStageSchema.optional()
|
|
36811
37935
|
});
|
|
36812
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
37936
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
36813
37937
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
36814
37938
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
36815
37939
|
kind: "event-registration",
|
|
@@ -36818,6 +37942,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
36818
37942
|
titleText: "Registration closed",
|
|
36819
37943
|
bodyText: "This run is no longer open for bookings."
|
|
36820
37944
|
};
|
|
37945
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
37946
|
+
if (card) return card;
|
|
36821
37947
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
36822
37948
|
return {
|
|
36823
37949
|
kind: "event-registration",
|
|
@@ -36834,11 +37960,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36834
37960
|
if (selectedRun) {
|
|
36835
37961
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
36836
37962
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
36837
|
-
return
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
|
|
36841
|
-
|
|
37963
|
+
return shellStepLabels(registrationRoute({
|
|
37964
|
+
chooseEvent: false,
|
|
37965
|
+
payment: resolveEventRequiresPayment({
|
|
37966
|
+
eligibility: null,
|
|
37967
|
+
selectedTicketType: null,
|
|
37968
|
+
event: selectedEvent
|
|
37969
|
+
}) ? "optionsAndPayment" : "none"
|
|
37970
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
36842
37971
|
}
|
|
36843
37972
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
36844
37973
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -36847,14 +37976,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36847
37976
|
occurrenceContext: source.occurrenceContext
|
|
36848
37977
|
});
|
|
36849
37978
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
36850
|
-
|
|
37979
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
36851
37980
|
eligibility: null,
|
|
36852
37981
|
selectedTicketType: null,
|
|
36853
37982
|
event: preSelectedEvent
|
|
36854
|
-
}) : false
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
37983
|
+
}) : false;
|
|
37984
|
+
return shellStepLabels(registrationRoute({
|
|
37985
|
+
chooseEvent: !hasPreSelectedContext,
|
|
37986
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
37987
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
36858
37988
|
}
|
|
36859
37989
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
36860
37990
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -36870,29 +38000,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
36870
38000
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
36871
38001
|
return runs.length === 1 ? runs[0] : null;
|
|
36872
38002
|
}
|
|
36873
|
-
function
|
|
36874
|
-
|
|
36875
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
36876
|
-
case "select-tickets": return "Tickets";
|
|
36877
|
-
case "enter-details": return "Details";
|
|
36878
|
-
case "select-payment": return "Payment options";
|
|
36879
|
-
case "payment": return "Payment";
|
|
36880
|
-
case "error":
|
|
36881
|
-
case "success":
|
|
36882
|
-
case "submitting":
|
|
36883
|
-
case "verifying-payment":
|
|
36884
|
-
case "verifying-timeout":
|
|
36885
|
-
case "payment-status":
|
|
36886
|
-
case "payment-failed": return "Details";
|
|
36887
|
-
}
|
|
36888
|
-
}
|
|
36889
|
-
function isDateSelection(events) {
|
|
36890
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
36891
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
38003
|
+
function shellStepLabels(route, context) {
|
|
38004
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
36892
38005
|
}
|
|
36893
38006
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
36894
|
-
if (stepLabels.includes("
|
|
36895
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
38007
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
38008
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
36896
38009
|
return "Preparing dates, tickets, and booking details.";
|
|
36897
38010
|
}
|
|
36898
38011
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -36902,6 +38015,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36902
38015
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
36903
38016
|
},
|
|
36904
38017
|
buildRender: (source) => {
|
|
38018
|
+
const display = resolveRegistrationDisplay(source);
|
|
36905
38019
|
const eventSource = resolveEventRegistrationEventSource({
|
|
36906
38020
|
events: source.events,
|
|
36907
38021
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -36909,7 +38023,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36909
38023
|
});
|
|
36910
38024
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
36911
38025
|
return {
|
|
36912
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
38026
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
36913
38027
|
hydration: {
|
|
36914
38028
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
36915
38029
|
subject: source.subject ?? null,
|
|
@@ -36919,29 +38033,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36919
38033
|
} : eventSource,
|
|
36920
38034
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
36921
38035
|
maxTickets: source.maxTickets ?? void 0,
|
|
36922
|
-
|
|
36923
|
-
showCapacity: source.showCapacity,
|
|
38036
|
+
display,
|
|
36924
38037
|
successMessage: source.successMessage,
|
|
36925
38038
|
buttonVariant: source.buttonVariant,
|
|
36926
|
-
|
|
38039
|
+
host: source.host ?? "overlay",
|
|
36927
38040
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
36928
38041
|
supportEmail: source.supportEmail,
|
|
36929
38042
|
sitePasses: source.sitePasses ?? null,
|
|
36930
38043
|
siteMemberships: source.siteMemberships ?? null,
|
|
36931
38044
|
mailingList: source.mailingList,
|
|
36932
|
-
siteName: source.siteName
|
|
38045
|
+
siteName: source.siteName,
|
|
38046
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
36933
38047
|
}
|
|
36934
38048
|
};
|
|
36935
38049
|
}
|
|
36936
38050
|
});
|
|
36937
38051
|
function normalizeEventRegistrationEventInput(value) {
|
|
36938
|
-
if (!isRecord$
|
|
38052
|
+
if (!isRecord$2(value)) return value;
|
|
36939
38053
|
return {
|
|
36940
38054
|
...value,
|
|
36941
38055
|
destination: resolveRuntimeEventDestination(value)
|
|
36942
38056
|
};
|
|
36943
38057
|
}
|
|
36944
|
-
function isRecord$
|
|
38058
|
+
function isRecord$2(value) {
|
|
36945
38059
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36946
38060
|
}
|
|
36947
38061
|
const eventRegistrationBlockDefinition = {
|
|
@@ -36981,7 +38095,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
36981
38095
|
description: "Main heading for the registration form",
|
|
36982
38096
|
required: false,
|
|
36983
38097
|
multiline: false,
|
|
36984
|
-
defaultValue: "
|
|
38098
|
+
defaultValue: ""
|
|
36985
38099
|
},
|
|
36986
38100
|
{
|
|
36987
38101
|
id: "description",
|
|
@@ -37053,11 +38167,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
37053
38167
|
{
|
|
37054
38168
|
id: "buttonText",
|
|
37055
38169
|
type: "text",
|
|
37056
|
-
label: "
|
|
37057
|
-
description: "Text
|
|
38170
|
+
label: "Button text",
|
|
38171
|
+
description: "Text on the booking button",
|
|
37058
38172
|
required: false,
|
|
37059
38173
|
multiline: false,
|
|
37060
|
-
defaultValue: "
|
|
38174
|
+
defaultValue: "Book your place",
|
|
37061
38175
|
maxLength: 40
|
|
37062
38176
|
},
|
|
37063
38177
|
createButtonVariantField()
|
|
@@ -37089,21 +38203,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
37089
38203
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
37090
38204
|
buttonText: { $bind: {
|
|
37091
38205
|
from: "content.buttonText",
|
|
37092
|
-
fallback: "
|
|
38206
|
+
fallback: "Book your place"
|
|
37093
38207
|
} },
|
|
37094
38208
|
buttonVariant: { $bind: {
|
|
37095
38209
|
from: "content.buttonVariant",
|
|
37096
38210
|
fallback: "primary"
|
|
37097
38211
|
} },
|
|
37098
|
-
overlayEnabled: { $bind: {
|
|
37099
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
37100
|
-
fallback: false
|
|
37101
|
-
} },
|
|
37102
38212
|
events: { $bind: { from: "data.events" } },
|
|
37103
38213
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
37104
38214
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
37105
38215
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
37106
38216
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
38217
|
+
bookingOfferingPresets: { $bind: {
|
|
38218
|
+
from: "$root.bookingOfferingPresets",
|
|
38219
|
+
fallback: []
|
|
38220
|
+
} },
|
|
37107
38221
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
37108
38222
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
37109
38223
|
stage: { $bind: {
|
|
@@ -39764,7 +40878,21 @@ const eventCalendarBlockDefinition = {
|
|
|
39764
40878
|
list: { label: "List" }
|
|
39765
40879
|
}
|
|
39766
40880
|
}, eventCalendarContentShape),
|
|
39767
|
-
|
|
40881
|
+
contentNormalizer: {
|
|
40882
|
+
fieldIds: [
|
|
40883
|
+
"variant",
|
|
40884
|
+
"displayMode",
|
|
40885
|
+
"listLayout",
|
|
40886
|
+
"defaultCalendarView",
|
|
40887
|
+
"eventSurface",
|
|
40888
|
+
"filterEventPresets",
|
|
40889
|
+
"scheduleScope",
|
|
40890
|
+
"filterCategoryIds",
|
|
40891
|
+
"filterStaffMemberId",
|
|
40892
|
+
"filterVenueId"
|
|
40893
|
+
],
|
|
40894
|
+
normalize: normalizeEventCalendarContent
|
|
40895
|
+
},
|
|
39768
40896
|
dataSchemas: {
|
|
39769
40897
|
events: publicEventsArraySchema.optional(),
|
|
39770
40898
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -40013,90 +41141,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
40013
41141
|
} }
|
|
40014
41142
|
};
|
|
40015
41143
|
//#endregion
|
|
40016
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
40017
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
40018
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
40019
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
40020
|
-
{
|
|
40021
|
-
preset: "class",
|
|
40022
|
-
sourceKey: "eventPreset:class",
|
|
40023
|
-
dataKey: "classEvents",
|
|
40024
|
-
label: "Classes"
|
|
40025
|
-
},
|
|
40026
|
-
{
|
|
40027
|
-
preset: "workshop",
|
|
40028
|
-
sourceKey: "eventPreset:workshop",
|
|
40029
|
-
dataKey: "workshopEvents",
|
|
40030
|
-
label: "Workshops"
|
|
40031
|
-
},
|
|
40032
|
-
{
|
|
40033
|
-
preset: "retreat",
|
|
40034
|
-
sourceKey: "eventPreset:retreat",
|
|
40035
|
-
dataKey: "retreatEvents",
|
|
40036
|
-
label: "Retreats"
|
|
40037
|
-
},
|
|
40038
|
-
{
|
|
40039
|
-
preset: "performance",
|
|
40040
|
-
sourceKey: "eventPreset:performance",
|
|
40041
|
-
dataKey: "performanceEvents",
|
|
40042
|
-
label: "Performances"
|
|
40043
|
-
}
|
|
40044
|
-
];
|
|
40045
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
40046
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
40047
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
40048
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
40049
|
-
kind: "eventPreset",
|
|
40050
|
-
preset: definition.preset
|
|
40051
|
-
}]));
|
|
40052
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
40053
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
40054
|
-
}
|
|
40055
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
40056
|
-
if (value == null) return { kind: "legacy" };
|
|
40057
|
-
if (value.length === 0) return { kind: "default" };
|
|
40058
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
40059
|
-
return keys.length > 0 ? {
|
|
40060
|
-
kind: "custom",
|
|
40061
|
-
keys
|
|
40062
|
-
} : { kind: "default" };
|
|
40063
|
-
}
|
|
40064
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
40065
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
40066
|
-
return keys.length >= 2 ? keys : [];
|
|
40067
|
-
}
|
|
40068
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
40069
|
-
if (!isRecord$2(value)) return null;
|
|
40070
|
-
const groupOrderValue = value.groupOrder;
|
|
40071
|
-
if (Array.isArray(groupOrderValue)) {
|
|
40072
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
40073
|
-
return {
|
|
40074
|
-
...value,
|
|
40075
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
40076
|
-
};
|
|
40077
|
-
}
|
|
40078
|
-
if (groupOrderValue != null) return {
|
|
40079
|
-
...value,
|
|
40080
|
-
groupOrder: []
|
|
40081
|
-
};
|
|
40082
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$2) : []);
|
|
40083
|
-
return legacyOrder.length > 0 ? {
|
|
40084
|
-
...value,
|
|
40085
|
-
groupOrder: legacyOrder
|
|
40086
|
-
} : value;
|
|
40087
|
-
}
|
|
40088
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
40089
|
-
const keys = [];
|
|
40090
|
-
for (const value of values) {
|
|
40091
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
40092
|
-
if (!keys.includes(value)) keys.push(value);
|
|
40093
|
-
}
|
|
40094
|
-
return keys;
|
|
40095
|
-
}
|
|
40096
|
-
function isRecord$2(value) {
|
|
40097
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40098
|
-
}
|
|
40099
|
-
//#endregion
|
|
40100
41144
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
40101
41145
|
const groupOverrideFields = [
|
|
40102
41146
|
{
|
|
@@ -40460,7 +41504,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
40460
41504
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
40461
41505
|
const offeringsPreviewBlockDefinition = {
|
|
40462
41506
|
manifest: offeringsPreviewManifest,
|
|
40463
|
-
|
|
41507
|
+
contentNormalizer: {
|
|
41508
|
+
fieldIds: [
|
|
41509
|
+
"displayMode",
|
|
41510
|
+
"heading",
|
|
41511
|
+
"description",
|
|
41512
|
+
"itemLimit",
|
|
41513
|
+
"groupOrder",
|
|
41514
|
+
"groupOverrides",
|
|
41515
|
+
"_cardStyles",
|
|
41516
|
+
"buttonVariant",
|
|
41517
|
+
"buttonText",
|
|
41518
|
+
"emptyMessage",
|
|
41519
|
+
"_sectionStyles"
|
|
41520
|
+
],
|
|
41521
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
41522
|
+
},
|
|
40464
41523
|
dataSchemas: {
|
|
40465
41524
|
...offeringsPreviewEventDataSchemas,
|
|
40466
41525
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -42014,6 +43073,14 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
|
|
|
42014
43073
|
}
|
|
42015
43074
|
}) };
|
|
42016
43075
|
//#endregion
|
|
43076
|
+
//#region ../blocks/src/lib/media.ts
|
|
43077
|
+
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
43078
|
+
"document",
|
|
43079
|
+
"spreadsheet",
|
|
43080
|
+
"archive",
|
|
43081
|
+
"audio"
|
|
43082
|
+
];
|
|
43083
|
+
//#endregion
|
|
42017
43084
|
//#region ../blocks/src/system/blocks/file-download.ts
|
|
42018
43085
|
const bound = (from) => ({ $bind: { from } });
|
|
42019
43086
|
const fileDownloadLayout = styledSection({
|
|
@@ -44058,11 +45125,11 @@ function buildNewsletterDisplay(source) {
|
|
|
44058
45125
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
44059
45126
|
privacyNote: null
|
|
44060
45127
|
};
|
|
44061
|
-
const
|
|
44062
|
-
const choices = resolveRuntimeChoices(
|
|
45128
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
45129
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
44063
45130
|
return {
|
|
44064
45131
|
kind: "newsletter-form",
|
|
44065
|
-
availability:
|
|
45132
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
44066
45133
|
className: source.className ?? null,
|
|
44067
45134
|
buttonLabel: form.buttonLabel,
|
|
44068
45135
|
successMessage: form.successMessage,
|
|
@@ -44119,60 +45186,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
44119
45186
|
default: return assertNever$2(source);
|
|
44120
45187
|
}
|
|
44121
45188
|
}
|
|
44122
|
-
function resolveRuntimeChoices(
|
|
44123
|
-
if (
|
|
44124
|
-
|
|
44125
|
-
|
|
44126
|
-
|
|
44127
|
-
|
|
44128
|
-
id: item.id,
|
|
44129
|
-
label: item.name
|
|
44130
|
-
})) : [];
|
|
44131
|
-
}
|
|
44132
|
-
case "brevo": {
|
|
44133
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
44134
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44135
|
-
id: String(item.id),
|
|
44136
|
-
label: item.name
|
|
44137
|
-
})) : [];
|
|
44138
|
-
}
|
|
44139
|
-
case "mailchimp": {
|
|
44140
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
44141
|
-
return (context.provider.provider === "mailchimp" ? context.provider.audiences.find((item) => item.id === targeting.audienceId) : void 0)?.interests.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44142
|
-
id: item.id,
|
|
44143
|
-
label: item.name
|
|
44144
|
-
})) ?? [];
|
|
44145
|
-
}
|
|
44146
|
-
}
|
|
44147
|
-
}
|
|
44148
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
44149
|
-
if (context?.tag !== "configured") return false;
|
|
44150
|
-
const provider = context.provider;
|
|
44151
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
44152
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
44153
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
44154
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
44155
|
-
}
|
|
44156
|
-
if (targeting.provider !== provider.provider) return false;
|
|
44157
|
-
switch (targeting.provider) {
|
|
44158
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
44159
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
44160
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
44161
|
-
}
|
|
44162
|
-
}
|
|
44163
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
44164
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
44165
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44166
|
-
}
|
|
44167
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
44168
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
44169
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44170
|
-
}
|
|
44171
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
44172
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
44173
|
-
if (!audience) return false;
|
|
44174
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
44175
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
45189
|
+
function resolveRuntimeChoices(assessment) {
|
|
45190
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
45191
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
45192
|
+
id: String(item.id),
|
|
45193
|
+
label: item.name
|
|
45194
|
+
}));
|
|
44176
45195
|
}
|
|
44177
45196
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
44178
45197
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -44276,6 +45295,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
44276
45295
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
44277
45296
|
const newsletterSignupBlockDefinition = {
|
|
44278
45297
|
manifest: newsletterSignupManifest,
|
|
45298
|
+
contentNormalizer: {
|
|
45299
|
+
fieldIds: ["targeting"],
|
|
45300
|
+
normalize: normalizeMailingListBlockContent
|
|
45301
|
+
},
|
|
44279
45302
|
runtime: newsletterFormBlockRuntime
|
|
44280
45303
|
};
|
|
44281
45304
|
//#endregion
|
|
@@ -44303,7 +45326,7 @@ const memberPhotoClassName = (baseClass) => cardRoleChildClass({
|
|
|
44303
45326
|
baseClass,
|
|
44304
45327
|
stylesFrom: "content._cardStyles"
|
|
44305
45328
|
});
|
|
44306
|
-
const teamMemberPhotoSchema =
|
|
45329
|
+
const teamMemberPhotoSchema = runtimeMediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
|
|
44307
45330
|
const teamMemberDataSchema = z.object({
|
|
44308
45331
|
_type: z.literal("teamMember"),
|
|
44309
45332
|
id: z.string(),
|
|
@@ -45008,7 +46031,20 @@ const locationMapBlockDefinition = {
|
|
|
45008
46031
|
})], { gap: "md" })
|
|
45009
46032
|
})
|
|
45010
46033
|
}),
|
|
45011
|
-
|
|
46034
|
+
contentNormalizer: {
|
|
46035
|
+
fieldIds: [
|
|
46036
|
+
"heading",
|
|
46037
|
+
"locationSource",
|
|
46038
|
+
"venueId",
|
|
46039
|
+
"location",
|
|
46040
|
+
"showAddressText",
|
|
46041
|
+
"showDirections",
|
|
46042
|
+
"directionsLabel",
|
|
46043
|
+
"zoom",
|
|
46044
|
+
"heightPx"
|
|
46045
|
+
],
|
|
46046
|
+
normalize: normalizeLocationMapContent
|
|
46047
|
+
}
|
|
45012
46048
|
};
|
|
45013
46049
|
//#endregion
|
|
45014
46050
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -45832,11 +46868,14 @@ const offeringsPreviewDatesReadEnabled = {
|
|
|
45832
46868
|
//#endregion
|
|
45833
46869
|
//#region ../blocks/src/system/helpers/backgroundMedia.ts
|
|
45834
46870
|
function resolveBackgroundMedia(input) {
|
|
45835
|
-
const parsedMedia =
|
|
46871
|
+
const parsedMedia = runtimeMediaSchema.safeParse(input.image);
|
|
45836
46872
|
if (!parsedMedia.success) return null;
|
|
45837
46873
|
switch (parsedMedia.data.type) {
|
|
45838
46874
|
case "image":
|
|
45839
|
-
case "video": return
|
|
46875
|
+
case "video": return {
|
|
46876
|
+
...parsedMedia.data,
|
|
46877
|
+
type: parsedMedia.data.type
|
|
46878
|
+
};
|
|
45840
46879
|
case "audio":
|
|
45841
46880
|
case "document":
|
|
45842
46881
|
case "spreadsheet":
|
|
@@ -45848,6 +46887,75 @@ function backgroundVideoMobileClassNames(input) {
|
|
|
45848
46887
|
return input.showVideoOnMobile === true ? "" : "rb-hidden rb-md-block";
|
|
45849
46888
|
}
|
|
45850
46889
|
//#endregion
|
|
46890
|
+
//#region ../blocks/src/system/runtime/nodes/mediaContext.ts
|
|
46891
|
+
/**
|
|
46892
|
+
* Server-side: AsyncLocalStorage for request isolation.
|
|
46893
|
+
* Prevents race conditions when multiple requests are processed concurrently.
|
|
46894
|
+
*
|
|
46895
|
+
* Lazy initialization to avoid issues in environments that don't support async_hooks.
|
|
46896
|
+
*/
|
|
46897
|
+
const serverStorageState = {
|
|
46898
|
+
storage: null,
|
|
46899
|
+
checked: false
|
|
46900
|
+
};
|
|
46901
|
+
function getServerStorage() {
|
|
46902
|
+
if (typeof window !== "undefined") return null;
|
|
46903
|
+
if (serverStorageState.checked) return serverStorageState.storage;
|
|
46904
|
+
serverStorageState.checked = true;
|
|
46905
|
+
try {
|
|
46906
|
+
const globalWithNonWebpackRequire = globalThis;
|
|
46907
|
+
const AsyncLocalStorage = (typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)"))("async_hooks").AsyncLocalStorage;
|
|
46908
|
+
if (AsyncLocalStorage) {
|
|
46909
|
+
serverStorageState.storage = new AsyncLocalStorage();
|
|
46910
|
+
return serverStorageState.storage;
|
|
46911
|
+
}
|
|
46912
|
+
return null;
|
|
46913
|
+
} catch {
|
|
46914
|
+
if (process.env.NODE_ENV !== "production") console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
|
|
46915
|
+
return null;
|
|
46916
|
+
}
|
|
46917
|
+
}
|
|
46918
|
+
/**
|
|
46919
|
+
* Client-side context storage.
|
|
46920
|
+
* Safe because browsers are single-threaded per tab.
|
|
46921
|
+
*
|
|
46922
|
+
* IMPORTANT: This must be shared across bundles.
|
|
46923
|
+
* SDK preview mode can load multiple independently-bundled entrypoints
|
|
46924
|
+
* (e.g. `@riverbankcms/sdk/rendering` + `@riverbankcms/sdk/preview-next/client`),
|
|
46925
|
+
* which can otherwise each get their own module-scoped singleton.
|
|
46926
|
+
*/
|
|
46927
|
+
const RB_MEDIA_CONTEXT_KEY = Symbol.for("riverbankcms.blocks.mediaContext");
|
|
46928
|
+
function getClientContextStore() {
|
|
46929
|
+
const g = globalThis;
|
|
46930
|
+
const existing = g[RB_MEDIA_CONTEXT_KEY];
|
|
46931
|
+
if (existing && typeof existing === "object") return existing;
|
|
46932
|
+
const next = {};
|
|
46933
|
+
g[RB_MEDIA_CONTEXT_KEY] = next;
|
|
46934
|
+
return next;
|
|
46935
|
+
}
|
|
46936
|
+
/**
|
|
46937
|
+
* Get the current media context.
|
|
46938
|
+
* Server-side: Uses AsyncLocalStorage for request isolation.
|
|
46939
|
+
* Client-side: Uses module-level state (safe in single-threaded browser).
|
|
46940
|
+
*/
|
|
46941
|
+
function getMediaContext() {
|
|
46942
|
+
const storage = getServerStorage();
|
|
46943
|
+
if (storage) return storage.getStore() ?? {};
|
|
46944
|
+
return getClientContextStore();
|
|
46945
|
+
}
|
|
46946
|
+
function getCurrentResolveImageUrlContext() {
|
|
46947
|
+
const context = getMediaContext();
|
|
46948
|
+
if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) return;
|
|
46949
|
+
return {
|
|
46950
|
+
supabaseUrl: context.supabaseUrl,
|
|
46951
|
+
siteId: context.siteId,
|
|
46952
|
+
mediaAssetIndex: context.mediaAssetIndex
|
|
46953
|
+
};
|
|
46954
|
+
}
|
|
46955
|
+
function getMediaAssetIndex(context) {
|
|
46956
|
+
return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
|
|
46957
|
+
}
|
|
46958
|
+
//#endregion
|
|
45851
46959
|
//#region ../blocks/src/system/runtime/nodes/media.tsx
|
|
45852
46960
|
function getValidSourceDimension(value) {
|
|
45853
46961
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -45883,41 +46991,72 @@ function applyRectTransform(existingStyle, patch) {
|
|
|
45883
46991
|
if (patch.transform) next.transform = appendTransform(existingStyle?.transform, patch.transform);
|
|
45884
46992
|
return next;
|
|
45885
46993
|
}
|
|
45886
|
-
|
|
46994
|
+
/** Resolve portable content without exposing runtime metadata as saved values. */
|
|
46995
|
+
function resolveMediaWithContext(reference, context) {
|
|
46996
|
+
return resolveManagedMediaReference(reference, getMediaAssetIndex(context ?? void 0));
|
|
46997
|
+
}
|
|
46998
|
+
function sourceFromAsset(value, asset) {
|
|
46999
|
+
return {
|
|
47000
|
+
type: value.type,
|
|
47001
|
+
alt: value.alt,
|
|
47002
|
+
filename: value.filename,
|
|
47003
|
+
purpose: value.purpose,
|
|
47004
|
+
placeholder: value.placeholder,
|
|
47005
|
+
transform: value.transform,
|
|
47006
|
+
poster: value.poster,
|
|
47007
|
+
identifier: asset.identifier,
|
|
47008
|
+
assetId: asset.id,
|
|
47009
|
+
storageBucket: asset.storageBucket,
|
|
47010
|
+
storagePath: asset.storagePath,
|
|
47011
|
+
mimeType: asset.mimeType,
|
|
47012
|
+
width: asset.width,
|
|
47013
|
+
height: asset.height
|
|
47014
|
+
};
|
|
47015
|
+
}
|
|
47016
|
+
function resolveRuntimeMedia(value, context) {
|
|
47017
|
+
if ("asset" in value && value.asset) return sourceFromAsset(value, value.asset);
|
|
47018
|
+
if ("src" in value && value.src) return value;
|
|
47019
|
+
if (!value.identifier) return void 0;
|
|
47020
|
+
const resolved = resolveMediaWithContext(value, context);
|
|
47021
|
+
return resolved.kind === "resolved" ? sourceFromAsset(resolved.reference, resolved.asset) : void 0;
|
|
47022
|
+
}
|
|
47023
|
+
function usesProxyFraming(source, transform) {
|
|
47024
|
+
if (!source?.assetId || !isExplicitCropProxyEnabled()) return false;
|
|
47025
|
+
return Boolean(transform.rotation) || isExplicitRectCrop(transform.rect, getValidSourceDimension(source.width), getValidSourceDimension(source.height));
|
|
47026
|
+
}
|
|
47027
|
+
function rectFramingPatch(source, rect, proxy, style) {
|
|
47028
|
+
if (!source || !rect || proxy) return {};
|
|
47029
|
+
const patch = buildCssRectStylePatch(source, rect);
|
|
47030
|
+
return patch ? applyRectTransform(style, patch) : {};
|
|
47031
|
+
}
|
|
47032
|
+
function hotspotFramingPatch(transform, proxy, rectPatch, style) {
|
|
47033
|
+
if (!transform.hotspot || rectPatch.objectPosition !== void 0) return {};
|
|
47034
|
+
const fit = style?.objectFit;
|
|
47035
|
+
if (fit && fit !== "cover" && fit !== "contain") return {};
|
|
47036
|
+
const point = proxy && transform.rotation ? rotateNormalizedPoint(transform.hotspot, transform.rotation) : transform.hotspot;
|
|
47037
|
+
return { objectPosition: `${point.x * 100}% ${point.y * 100}%` };
|
|
47038
|
+
}
|
|
47039
|
+
function rotationFramingPatch(rotation, proxy, rectPatch, style) {
|
|
47040
|
+
if (!rotation || proxy) return {};
|
|
47041
|
+
return {
|
|
47042
|
+
transform: appendTransform(rectPatch.transform ?? style?.transform, `rotate(${rotation}deg)`),
|
|
47043
|
+
transformOrigin: rectPatch.transformOrigin ?? "center"
|
|
47044
|
+
};
|
|
47045
|
+
}
|
|
47046
|
+
/** CSS framing is a pure projection of the resolved source and per-use transform. */
|
|
47047
|
+
function deriveMediaFramingStyle(source, transform, proxy, style) {
|
|
47048
|
+
if (!transform.rect && !transform.hotspot && !transform.rotation) return style;
|
|
47049
|
+
const rectPatch = rectFramingPatch(source, transform.rect, proxy, style);
|
|
47050
|
+
return mergeStyles(style, {
|
|
47051
|
+
...rectPatch,
|
|
47052
|
+
...hotspotFramingPatch(transform, proxy, rectPatch, style),
|
|
47053
|
+
...rotationFramingPatch(transform.rotation, proxy, rectPatch, style)
|
|
47054
|
+
});
|
|
47055
|
+
}
|
|
47056
|
+
function computeMediaTransformStyle(value, style, targetAspectRatio, options, context) {
|
|
47057
|
+
const source = resolveRuntimeMedia(value, context ?? getCurrentResolveImageUrlContext());
|
|
45887
47058
|
const transform = options?.resolvedTransform ?? resolveMediaTransformForAspect(value.transform, targetAspectRatio);
|
|
45888
|
-
|
|
45889
|
-
const hotspot = transform.hotspot;
|
|
45890
|
-
const rotation = transform.rotation;
|
|
45891
|
-
if (!rect && !hotspot && !rotation) return style;
|
|
45892
|
-
const stylePatch = {};
|
|
45893
|
-
const heuristicSuppressCss = Boolean(isExplicitCropProxyEnabled() && value.assetId && (typeof rotation === "number" && rotation !== 0 || isExplicitRectCrop(rect, getValidSourceDimension(value.width), getValidSourceDimension(value.height))));
|
|
45894
|
-
const shouldSuppressCss = options?.isProxy ?? heuristicSuppressCss;
|
|
45895
|
-
if (rect && !shouldSuppressCss) {
|
|
45896
|
-
const rectPatch = buildCssRectStylePatch(value, rect);
|
|
45897
|
-
if (rectPatch) {
|
|
45898
|
-
const mergedRect = applyRectTransform(style, rectPatch);
|
|
45899
|
-
Object.assign(stylePatch, mergedRect);
|
|
45900
|
-
}
|
|
45901
|
-
}
|
|
45902
|
-
if (hotspot) {
|
|
45903
|
-
const effectiveObjectFit = stylePatch.objectFit ?? style?.objectFit;
|
|
45904
|
-
if ((!effectiveObjectFit || effectiveObjectFit === "cover" || effectiveObjectFit === "contain") && stylePatch.objectPosition === void 0) {
|
|
45905
|
-
const resolved = shouldSuppressCss && rotation ? rotateNormalizedPoint({
|
|
45906
|
-
x: hotspot.x,
|
|
45907
|
-
y: hotspot.y
|
|
45908
|
-
}, rotation) : {
|
|
45909
|
-
x: hotspot.x,
|
|
45910
|
-
y: hotspot.y
|
|
45911
|
-
};
|
|
45912
|
-
stylePatch.objectPosition = `${resolved.x * 100}% ${resolved.y * 100}%`;
|
|
45913
|
-
}
|
|
45914
|
-
}
|
|
45915
|
-
if (rotation && !shouldSuppressCss) {
|
|
45916
|
-
const existingTransform = stylePatch.transform ?? style?.transform;
|
|
45917
|
-
stylePatch.transform = existingTransform ? `${existingTransform} rotate(${rotation}deg)` : `rotate(${rotation}deg)`;
|
|
45918
|
-
if (!stylePatch.transformOrigin) stylePatch.transformOrigin = "center";
|
|
45919
|
-
}
|
|
45920
|
-
return mergeStyles(style, stylePatch);
|
|
47059
|
+
return deriveMediaFramingStyle(source, transform, options?.isProxy ?? usesProxyFraming(source, transform), style);
|
|
45921
47060
|
}
|
|
45922
47061
|
//#endregion
|
|
45923
47062
|
//#region ../blocks/src/system/transforms/registry/background.ts
|
|
@@ -46066,11 +47205,11 @@ const backgroundTransforms = [
|
|
|
46066
47205
|
}
|
|
46067
47206
|
];
|
|
46068
47207
|
function parseMediaBackground(value) {
|
|
46069
|
-
const background =
|
|
47208
|
+
const background = parseRuntimeBackgroundContent(value);
|
|
46070
47209
|
return background?.type === "image" || background?.type === "video" ? background : null;
|
|
46071
47210
|
}
|
|
46072
47211
|
function resolveBackgroundLayerStyle(value, fallbackToken, context) {
|
|
46073
|
-
const background =
|
|
47212
|
+
const background = parseRuntimeBackgroundContent(value);
|
|
46074
47213
|
const style = {};
|
|
46075
47214
|
const gradient = background?.type === "gradient" ? isString(background.gradient) ? background.gradient.trim() : gradientPresetCss(background.gradientPresetId) : null;
|
|
46076
47215
|
const color = background?.type === "color" && isString(background.color) ? background.color.trim() : null;
|
|
@@ -46213,17 +47352,7 @@ const linksTransforms = [{
|
|
|
46213
47352
|
id: "links.resolve",
|
|
46214
47353
|
kind: "formatter",
|
|
46215
47354
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
46216
|
-
run: (value, _options, context) =>
|
|
46217
|
-
if (!value || typeof value !== "object") return null;
|
|
46218
|
-
const link = value;
|
|
46219
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
46220
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
46221
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
46222
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
46223
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
46224
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
46225
|
-
return null;
|
|
46226
|
-
}
|
|
47355
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
46227
47356
|
}, {
|
|
46228
47357
|
id: "links.label",
|
|
46229
47358
|
kind: "formatter",
|
|
@@ -46250,6 +47379,21 @@ const linksTransforms = [{
|
|
|
46250
47379
|
return null;
|
|
46251
47380
|
}
|
|
46252
47381
|
}];
|
|
47382
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
47383
|
+
if (!value || typeof value !== "object") return null;
|
|
47384
|
+
const link = value;
|
|
47385
|
+
switch (link.kind) {
|
|
47386
|
+
case "internal": return resolveInternalLink(link, context);
|
|
47387
|
+
case "page": return resolvePageLink(link, context);
|
|
47388
|
+
case "entry": return resolveEntryLink(link, context);
|
|
47389
|
+
case "external":
|
|
47390
|
+
case "url": return resolveExternalLink(link);
|
|
47391
|
+
default: return resolvePreResolvedLink(link);
|
|
47392
|
+
}
|
|
47393
|
+
}
|
|
47394
|
+
function resolvePreResolvedLink(link) {
|
|
47395
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
47396
|
+
}
|
|
46253
47397
|
const eventCalendarSelectionParam = {
|
|
46254
47398
|
id: "events.calendarSelectionParam",
|
|
46255
47399
|
kind: "formatter",
|