@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
package/dist/server/config.mjs
CHANGED
|
@@ -1776,12 +1776,14 @@ const unsafeAsSiteId = (id) => id;
|
|
|
1776
1776
|
const unsafeAsApiKeyId = (id) => id;
|
|
1777
1777
|
const unsafeAsEventOfferingId = (id) => id;
|
|
1778
1778
|
const unsafeAsEventSeriesId = (id) => id;
|
|
1779
|
+
const unsafeAsMediaAssetId = (id) => id;
|
|
1779
1780
|
const unsafeAsUserId = (id) => id;
|
|
1780
1781
|
const unsafeAsContentVersionId = (id) => id;
|
|
1781
1782
|
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1782
1783
|
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1783
1784
|
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1784
1785
|
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1786
|
+
const parseMediaAssetId = (value) => parseUuidBrand(value, unsafeAsMediaAssetId);
|
|
1785
1787
|
const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
|
|
1786
1788
|
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1787
1789
|
//#endregion
|
|
@@ -1986,6 +1988,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
1986
1988
|
default: return assertNever$2(pricing);
|
|
1987
1989
|
}
|
|
1988
1990
|
}
|
|
1991
|
+
/**
|
|
1992
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
1993
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
1994
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
1995
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
1996
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
1997
|
+
*/
|
|
1998
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
1999
|
+
switch (display.kind) {
|
|
2000
|
+
case "free": return "Free";
|
|
2001
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
2002
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
2003
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
2004
|
+
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)}`;
|
|
2005
|
+
case "unavailable": return "Pricing unavailable";
|
|
2006
|
+
case "external": return display.label;
|
|
2007
|
+
default: return assertNever$2(display);
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
/** Render an event's price directly from its pricing value. */
|
|
2011
|
+
function formatEventPricing(pricing, options = {}) {
|
|
2012
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
2013
|
+
}
|
|
1989
2014
|
//#endregion
|
|
1990
2015
|
//#region ../core/src/event-page-surface-subject.ts
|
|
1991
2016
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -2129,6 +2154,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
2129
2154
|
}
|
|
2130
2155
|
//#endregion
|
|
2131
2156
|
//#region ../core/src/booking-date-time.ts
|
|
2157
|
+
const DEFAULT_LOCALE = "en-US";
|
|
2132
2158
|
const FALLBACK_TIMEZONE = "UTC";
|
|
2133
2159
|
const START_OF_DAY = {
|
|
2134
2160
|
hour: 0,
|
|
@@ -2251,6 +2277,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
2251
2277
|
if (result.ok) return result.value;
|
|
2252
2278
|
throw new Error(formatParseError(result));
|
|
2253
2279
|
}
|
|
2280
|
+
function formatBookingInstant(isoString, options) {
|
|
2281
|
+
const date = new Date(isoString);
|
|
2282
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
2283
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
2284
|
+
}
|
|
2285
|
+
function formatBookingDate(input, format = {
|
|
2286
|
+
weekday: "long",
|
|
2287
|
+
year: "numeric",
|
|
2288
|
+
month: "long",
|
|
2289
|
+
day: "numeric"
|
|
2290
|
+
}) {
|
|
2291
|
+
return formatBookingInstant(input.startsAt, {
|
|
2292
|
+
locale: input.locale,
|
|
2293
|
+
timeZone: input.timeZone,
|
|
2294
|
+
format
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2297
|
+
function formatBookingTime(input, format = {
|
|
2298
|
+
hour: "numeric",
|
|
2299
|
+
minute: "2-digit",
|
|
2300
|
+
hour12: true
|
|
2301
|
+
}) {
|
|
2302
|
+
return formatBookingInstant(input.startsAt, {
|
|
2303
|
+
locale: input.locale,
|
|
2304
|
+
timeZone: input.timeZone,
|
|
2305
|
+
format
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2254
2308
|
function getBookingLocalDateKey(input) {
|
|
2255
2309
|
return formatDateKey$1(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
2256
2310
|
}
|
|
@@ -2412,7 +2466,7 @@ function parsePositiveInteger(value) {
|
|
|
2412
2466
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
2413
2467
|
}
|
|
2414
2468
|
function parseNewsletterListId(value) {
|
|
2415
|
-
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
2469
|
+
return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
|
|
2416
2470
|
}
|
|
2417
2471
|
function parseMailchimpAccountId(value) {
|
|
2418
2472
|
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
@@ -2454,8 +2508,15 @@ function parseMailingListProviderScope(value) {
|
|
|
2454
2508
|
}
|
|
2455
2509
|
return err("invalid_mailing_list_provider_scope");
|
|
2456
2510
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2511
|
+
z.unknown().transform((value, ctx) => {
|
|
2512
|
+
const parsed = parseNewsletterAudience(value);
|
|
2513
|
+
if (parsed.ok) return parsed.value;
|
|
2514
|
+
ctx.addIssue({
|
|
2515
|
+
code: "custom",
|
|
2516
|
+
message: "Choose a valid newsletter audience."
|
|
2517
|
+
});
|
|
2518
|
+
return z.NEVER;
|
|
2519
|
+
});
|
|
2459
2520
|
function parseMailingListGlobalForm(value) {
|
|
2460
2521
|
if (!isRecord$9(value)) return formError("shape");
|
|
2461
2522
|
const fields = parseGlobalFields(value.fields);
|
|
@@ -2475,6 +2536,16 @@ function parseMailingListGlobalForm(value) {
|
|
|
2475
2536
|
privacyNote
|
|
2476
2537
|
});
|
|
2477
2538
|
}
|
|
2539
|
+
function parseNewsletterAudience(value) {
|
|
2540
|
+
if (!isRecord$9(value)) return err("invalid_newsletter_audience");
|
|
2541
|
+
if (value.kind === "general" && Object.keys(value).length === 1) return ok({ kind: "general" });
|
|
2542
|
+
if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) return err("invalid_newsletter_audience");
|
|
2543
|
+
const topicId = parseNewsletterListId(value.topicId);
|
|
2544
|
+
return topicId === null ? err("invalid_newsletter_audience") : ok({
|
|
2545
|
+
kind: "topic",
|
|
2546
|
+
topicId
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2478
2549
|
function parseGlobalFields(value) {
|
|
2479
2550
|
if (!isRecord$9(value) || typeof value.preset !== "string") return null;
|
|
2480
2551
|
switch (value.preset) {
|
|
@@ -2524,44 +2595,144 @@ function formError(field) {
|
|
|
2524
2595
|
}
|
|
2525
2596
|
//#endregion
|
|
2526
2597
|
//#region ../core/src/mailing-list-targeting.ts
|
|
2598
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
2599
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
2600
|
+
switch (targeting.provider) {
|
|
2601
|
+
case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
2602
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
2603
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2527
2606
|
function planMailingListChoicePresentation(targeting) {
|
|
2528
|
-
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
2607
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") return { tag: "hidden" };
|
|
2529
2608
|
switch (targeting.provider) {
|
|
2530
|
-
case "native": return
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2609
|
+
case "native": return presentVisitorSelection({
|
|
2610
|
+
provider: "native",
|
|
2611
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
2612
|
+
}, targeting.selection.offeredTopicIds.length);
|
|
2613
|
+
case "brevo": return presentVisitorSelection({
|
|
2614
|
+
provider: "brevo",
|
|
2615
|
+
listIds: targeting.selection.offeredListIds
|
|
2616
|
+
}, targeting.selection.offeredListIds.length);
|
|
2617
|
+
case "mailchimp": return presentVisitorSelection({
|
|
2618
|
+
provider: "mailchimp",
|
|
2619
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
2620
|
+
}, targeting.selection.offeredInterestIds.length);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
function presentVisitorSelection(selection, optionCount) {
|
|
2624
|
+
return optionCount === 1 ? {
|
|
2625
|
+
tag: "automatic",
|
|
2626
|
+
selection
|
|
2627
|
+
} : {
|
|
2628
|
+
tag: "visitor_choice",
|
|
2629
|
+
provider: selection.provider,
|
|
2630
|
+
optionCount
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
//#endregion
|
|
2634
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
2635
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
2636
|
+
switch (provider.provider) {
|
|
2637
|
+
case "native": {
|
|
2638
|
+
const audience = provider.defaultAudience;
|
|
2639
|
+
return audience.kind === "general" ? {
|
|
2640
|
+
id: "general",
|
|
2641
|
+
name: "General mailing list"
|
|
2642
|
+
} : provider.topics.find((item) => item.id === audience.topicId) ?? null;
|
|
2643
|
+
}
|
|
2644
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
2645
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
function assessMailingListTargeting(context, targeting) {
|
|
2649
|
+
if (context?.tag !== "configured") return {
|
|
2650
|
+
tag: "unavailable",
|
|
2651
|
+
reason: "setup_missing",
|
|
2652
|
+
targeting
|
|
2653
|
+
};
|
|
2654
|
+
const catalog = context.provider;
|
|
2655
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
2656
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
2657
|
+
return destination === null ? {
|
|
2658
|
+
tag: "unavailable",
|
|
2659
|
+
reason: "default_missing",
|
|
2660
|
+
targeting
|
|
2661
|
+
} : {
|
|
2662
|
+
tag: "available",
|
|
2663
|
+
value: {
|
|
2664
|
+
mode: "default",
|
|
2665
|
+
targeting,
|
|
2666
|
+
provider: catalog.provider,
|
|
2667
|
+
destination
|
|
2668
|
+
}
|
|
2669
|
+
};
|
|
2670
|
+
}
|
|
2671
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
2672
|
+
switch (targeting.provider) {
|
|
2673
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
2538
2674
|
provider: "native",
|
|
2539
|
-
|
|
2675
|
+
catalog,
|
|
2676
|
+
targeting
|
|
2677
|
+
}, catalog.topics) : {
|
|
2678
|
+
tag: "unavailable",
|
|
2679
|
+
reason: "provider_mismatch",
|
|
2680
|
+
targeting
|
|
2540
2681
|
};
|
|
2541
|
-
case "brevo": return
|
|
2542
|
-
tag: "automatic",
|
|
2543
|
-
selection: {
|
|
2544
|
-
provider: "brevo",
|
|
2545
|
-
listIds: targeting.selection.offeredListIds
|
|
2546
|
-
}
|
|
2547
|
-
} : {
|
|
2548
|
-
tag: "visitor_choice",
|
|
2682
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
2549
2683
|
provider: "brevo",
|
|
2550
|
-
|
|
2684
|
+
catalog,
|
|
2685
|
+
targeting
|
|
2686
|
+
}, catalog.lists) : {
|
|
2687
|
+
tag: "unavailable",
|
|
2688
|
+
reason: "provider_mismatch",
|
|
2689
|
+
targeting
|
|
2551
2690
|
};
|
|
2552
|
-
case "mailchimp":
|
|
2553
|
-
|
|
2554
|
-
|
|
2691
|
+
case "mailchimp": {
|
|
2692
|
+
if (catalog.provider !== "mailchimp") return {
|
|
2693
|
+
tag: "unavailable",
|
|
2694
|
+
reason: "provider_mismatch",
|
|
2695
|
+
targeting
|
|
2696
|
+
};
|
|
2697
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
2698
|
+
return audience === void 0 ? {
|
|
2699
|
+
tag: "unavailable",
|
|
2700
|
+
reason: "audience_missing",
|
|
2701
|
+
value: {
|
|
2702
|
+
mode: "custom",
|
|
2703
|
+
provider: "mailchimp",
|
|
2704
|
+
catalog,
|
|
2705
|
+
targeting
|
|
2706
|
+
}
|
|
2707
|
+
} : assessMatchedChoices({
|
|
2555
2708
|
provider: "mailchimp",
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
optionCount: targeting.selection.offeredInterestIds.length
|
|
2562
|
-
};
|
|
2709
|
+
catalog,
|
|
2710
|
+
targeting,
|
|
2711
|
+
audience
|
|
2712
|
+
}, audience.interests);
|
|
2713
|
+
}
|
|
2563
2714
|
}
|
|
2564
2715
|
}
|
|
2716
|
+
function assessMatchedChoices(matched, choices) {
|
|
2717
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
2718
|
+
const available = new Set(choices.map((item) => item.id));
|
|
2719
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
2720
|
+
const value = {
|
|
2721
|
+
mode: "custom",
|
|
2722
|
+
...matched,
|
|
2723
|
+
choices,
|
|
2724
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
2725
|
+
};
|
|
2726
|
+
return missingIds.length > 0 ? {
|
|
2727
|
+
tag: "unavailable",
|
|
2728
|
+
reason: "choices_missing",
|
|
2729
|
+
missingIds,
|
|
2730
|
+
value
|
|
2731
|
+
} : {
|
|
2732
|
+
tag: "available",
|
|
2733
|
+
value
|
|
2734
|
+
};
|
|
2735
|
+
}
|
|
2565
2736
|
//#endregion
|
|
2566
2737
|
//#region ../core/src/mailing-list-runtime.ts
|
|
2567
2738
|
function parseMailingListRuntimeContext(value) {
|
|
@@ -2607,11 +2778,12 @@ function parseRuntimeProvider(value) {
|
|
|
2607
2778
|
}
|
|
2608
2779
|
}
|
|
2609
2780
|
function parseNativeRuntimeProvider(value) {
|
|
2610
|
-
|
|
2781
|
+
if ("defaultTopicId" in value) return null;
|
|
2782
|
+
const defaultAudience = parseNewsletterAudience(value.defaultAudience);
|
|
2611
2783
|
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
2612
|
-
return
|
|
2784
|
+
return defaultAudience.ok && topics !== null ? {
|
|
2613
2785
|
provider: "native",
|
|
2614
|
-
|
|
2786
|
+
defaultAudience: defaultAudience.value,
|
|
2615
2787
|
topics
|
|
2616
2788
|
} : null;
|
|
2617
2789
|
}
|
|
@@ -2627,57 +2799,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
2627
2799
|
function parseMailchimpRuntimeProvider(value) {
|
|
2628
2800
|
if (!Array.isArray(value.audiences)) return null;
|
|
2629
2801
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
for (const audience of value.audiences) {
|
|
2633
|
-
if (!isRecord$8(audience)) return null;
|
|
2634
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
2635
|
-
const name = parseName(audience.name);
|
|
2636
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
2637
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
2638
|
-
if (interests === null) return null;
|
|
2639
|
-
audiences.push({
|
|
2640
|
-
id,
|
|
2641
|
-
name,
|
|
2642
|
-
interests
|
|
2643
|
-
});
|
|
2644
|
-
}
|
|
2645
|
-
return {
|
|
2802
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
2803
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
2646
2804
|
provider: "mailchimp",
|
|
2647
2805
|
defaultAudienceId,
|
|
2648
2806
|
audiences
|
|
2649
|
-
};
|
|
2807
|
+
} : null;
|
|
2650
2808
|
}
|
|
2651
|
-
function
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
interests
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2809
|
+
function parseMailchimpAudience(value) {
|
|
2810
|
+
if (!isRecord$8(value) || !Array.isArray(value.interests)) return null;
|
|
2811
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
2812
|
+
const name = parseName(value.name);
|
|
2813
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
2814
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
2815
|
+
id,
|
|
2816
|
+
name,
|
|
2817
|
+
interests
|
|
2818
|
+
} : null;
|
|
2819
|
+
}
|
|
2820
|
+
function parseMailchimpInterest(value) {
|
|
2821
|
+
if (!isRecord$8(value)) return null;
|
|
2822
|
+
const id = parseMailchimpInterestId(value.id);
|
|
2823
|
+
const name = parseName(value.name);
|
|
2824
|
+
const categoryName = parseName(value.categoryName);
|
|
2825
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
2826
|
+
id,
|
|
2827
|
+
name,
|
|
2828
|
+
categoryName
|
|
2829
|
+
} : null;
|
|
2666
2830
|
}
|
|
2667
2831
|
function parseNamedItems(value, parseId) {
|
|
2668
2832
|
if (!Array.isArray(value)) return null;
|
|
2669
|
-
const items =
|
|
2670
|
-
for (const item of value) {
|
|
2833
|
+
const items = Array.from(value, (item) => {
|
|
2671
2834
|
if (!isRecord$8(item)) return null;
|
|
2672
2835
|
const id = parseId(item.id);
|
|
2673
2836
|
const name = parseName(item.name);
|
|
2674
|
-
|
|
2675
|
-
items.push({
|
|
2837
|
+
return id !== null && name !== null ? {
|
|
2676
2838
|
id,
|
|
2677
2839
|
name
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
return items;
|
|
2840
|
+
} : null;
|
|
2841
|
+
});
|
|
2842
|
+
return items.every((item) => item !== null) ? items : null;
|
|
2681
2843
|
}
|
|
2682
2844
|
function parseName(value) {
|
|
2683
2845
|
if (typeof value !== "string") return null;
|
|
@@ -2693,6 +2855,7 @@ function invalidRuntimeContext() {
|
|
|
2693
2855
|
//#endregion
|
|
2694
2856
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2695
2857
|
function parseMailingListPlacementTargeting(value) {
|
|
2858
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
2696
2859
|
if (!isRecord$7(value)) return targetingError("shape");
|
|
2697
2860
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
2698
2861
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -2705,6 +2868,11 @@ function parseMailingListPlacementTargeting(value) {
|
|
|
2705
2868
|
}
|
|
2706
2869
|
}
|
|
2707
2870
|
function parseNativeTargeting(selection) {
|
|
2871
|
+
if (selection.tag === "general") return Object.keys(selection).length === 1 ? ok({
|
|
2872
|
+
mode: "custom",
|
|
2873
|
+
provider: "native",
|
|
2874
|
+
selection: { tag: "general" }
|
|
2875
|
+
}) : targetingError("selection");
|
|
2708
2876
|
if (selection.tag === "fixed") {
|
|
2709
2877
|
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
2710
2878
|
return topicIds.ok ? ok({
|
|
@@ -2791,14 +2959,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
2791
2959
|
}
|
|
2792
2960
|
function parseUniqueIds(value, parseId) {
|
|
2793
2961
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
2794
|
-
|
|
2795
|
-
|
|
2962
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
2963
|
+
if (!parsed.ok) return parsed;
|
|
2796
2964
|
const id = parseId(item);
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
parsed.push(id);
|
|
2800
|
-
}
|
|
2801
|
-
return ok(parsed);
|
|
2965
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
2966
|
+
}, ok([]));
|
|
2802
2967
|
}
|
|
2803
2968
|
function isRecord$7(value) {
|
|
2804
2969
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3227,6 +3392,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
3227
3392
|
};
|
|
3228
3393
|
}
|
|
3229
3394
|
//#endregion
|
|
3395
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
3396
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
3397
|
+
event: {
|
|
3398
|
+
label: "Event",
|
|
3399
|
+
pluralLabel: "Events",
|
|
3400
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
3401
|
+
},
|
|
3402
|
+
class: {
|
|
3403
|
+
label: "Class",
|
|
3404
|
+
pluralLabel: "Classes",
|
|
3405
|
+
description: "Regular scheduled classes and group sessions."
|
|
3406
|
+
},
|
|
3407
|
+
course: {
|
|
3408
|
+
label: "Course",
|
|
3409
|
+
pluralLabel: "Courses",
|
|
3410
|
+
description: "A fixed set of dates that people book together."
|
|
3411
|
+
},
|
|
3412
|
+
term: {
|
|
3413
|
+
label: "Term",
|
|
3414
|
+
pluralLabel: "Terms",
|
|
3415
|
+
description: "A fixed term of sessions that people book together."
|
|
3416
|
+
},
|
|
3417
|
+
workshop: {
|
|
3418
|
+
label: "Workshop",
|
|
3419
|
+
pluralLabel: "Workshops",
|
|
3420
|
+
description: "One-off workshops, day sessions, or special events."
|
|
3421
|
+
},
|
|
3422
|
+
retreat: {
|
|
3423
|
+
label: "Retreat",
|
|
3424
|
+
pluralLabel: "Retreats",
|
|
3425
|
+
description: "Multi-day or residential immersive experiences."
|
|
3426
|
+
},
|
|
3427
|
+
performance: {
|
|
3428
|
+
label: "Performance",
|
|
3429
|
+
pluralLabel: "Performances",
|
|
3430
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
//#endregion
|
|
3230
3434
|
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
3231
3435
|
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3232
3436
|
checkPublicEventRegistrationNextStep: {
|
|
@@ -7753,7 +7957,96 @@ const themeLookMetadataSchema = z.object({
|
|
|
7753
7957
|
skinMarks: skinMarksSchema.optional()
|
|
7754
7958
|
});
|
|
7755
7959
|
//#endregion
|
|
7756
|
-
//#region ../
|
|
7960
|
+
//#region ../media-core/src/identifiers.ts
|
|
7961
|
+
function slugifyMediaIdentifier(value) {
|
|
7962
|
+
return value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
7963
|
+
}
|
|
7964
|
+
function parseMediaIdentifier(value) {
|
|
7965
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
7966
|
+
const trimmed = value.trim();
|
|
7967
|
+
if (trimmed.length === 0) return err({ kind: "empty_identifier" });
|
|
7968
|
+
const normalized = slugifyMediaIdentifier(trimmed);
|
|
7969
|
+
if (normalized.length === 0) return err({
|
|
7970
|
+
kind: "empty_after_normalization",
|
|
7971
|
+
value
|
|
7972
|
+
});
|
|
7973
|
+
return ok(normalized);
|
|
7974
|
+
}
|
|
7975
|
+
/**
|
|
7976
|
+
* Admits identifiers read from trusted persistence without repairing dirty data in memory.
|
|
7977
|
+
* User input should use parseMediaIdentifier, which intentionally canonicalizes it.
|
|
7978
|
+
*/
|
|
7979
|
+
function parseCanonicalMediaIdentifier(value) {
|
|
7980
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
7981
|
+
const parsed = parseMediaIdentifier(value);
|
|
7982
|
+
if (!parsed.ok) return parsed;
|
|
7983
|
+
if (value !== parsed.value) return err({
|
|
7984
|
+
kind: "non_canonical_identifier",
|
|
7985
|
+
value,
|
|
7986
|
+
canonical: parsed.value
|
|
7987
|
+
});
|
|
7988
|
+
return parsed;
|
|
7989
|
+
}
|
|
7990
|
+
//#endregion
|
|
7991
|
+
//#region ../media-core/src/mediaIdentifierSchema.ts
|
|
7992
|
+
/** Strict stored-reference admission delegates the canonical identifier decision. */
|
|
7993
|
+
const mediaIdentifierSchema = z.string().transform((value, context) => {
|
|
7994
|
+
const parsed = parseCanonicalMediaIdentifier(value);
|
|
7995
|
+
if (parsed.ok) return parsed.value;
|
|
7996
|
+
context.addIssue({
|
|
7997
|
+
code: "custom",
|
|
7998
|
+
message: "Expected a canonical media identifier"
|
|
7999
|
+
});
|
|
8000
|
+
return z.NEVER;
|
|
8001
|
+
});
|
|
8002
|
+
//#endregion
|
|
8003
|
+
//#region ../media-core/src/mediaKinds.ts
|
|
8004
|
+
const mediaTypeDiscriminants = [
|
|
8005
|
+
"image",
|
|
8006
|
+
"video",
|
|
8007
|
+
"audio",
|
|
8008
|
+
"document",
|
|
8009
|
+
"spreadsheet",
|
|
8010
|
+
"archive"
|
|
8011
|
+
];
|
|
8012
|
+
//#endregion
|
|
8013
|
+
//#region ../media-core/src/renderableMediaAsset.ts
|
|
8014
|
+
/** A portable reference never uses an incidental UUID, URL or storage snapshot for identity. */
|
|
8015
|
+
function resolveManagedMediaReference(reference, index) {
|
|
8016
|
+
const asset = index?.byIdentifier.get(reference.identifier);
|
|
8017
|
+
return asset ? {
|
|
8018
|
+
kind: "resolved",
|
|
8019
|
+
reference,
|
|
8020
|
+
asset
|
|
8021
|
+
} : {
|
|
8022
|
+
kind: "missing",
|
|
8023
|
+
reference
|
|
8024
|
+
};
|
|
8025
|
+
}
|
|
8026
|
+
//#endregion
|
|
8027
|
+
//#region ../media-core/src/renderableMediaAssetAdmission.ts
|
|
8028
|
+
const mediaAssetIdSchema = z.string().transform((value, context) => {
|
|
8029
|
+
const parsed = parseMediaAssetId(value);
|
|
8030
|
+
if (parsed.ok) return parsed.value;
|
|
8031
|
+
context.addIssue({
|
|
8032
|
+
code: "custom",
|
|
8033
|
+
message: "Expected a media asset ID"
|
|
8034
|
+
});
|
|
8035
|
+
return z.NEVER;
|
|
8036
|
+
});
|
|
8037
|
+
const nonemptyStorageValue = z.string().refine((value) => value.trim().length > 0);
|
|
8038
|
+
const renderableMediaAssetSchema = z.object({
|
|
8039
|
+
id: mediaAssetIdSchema,
|
|
8040
|
+
identifier: mediaIdentifierSchema,
|
|
8041
|
+
storageBucket: nonemptyStorageValue,
|
|
8042
|
+
storagePath: nonemptyStorageValue,
|
|
8043
|
+
mimeType: nonemptyStorageValue,
|
|
8044
|
+
filename: z.string().optional(),
|
|
8045
|
+
width: z.number().positive().nullable(),
|
|
8046
|
+
height: z.number().positive().nullable()
|
|
8047
|
+
});
|
|
8048
|
+
//#endregion
|
|
8049
|
+
//#region ../media-core/src/media.ts
|
|
7757
8050
|
const hotspotSchema = z.object({
|
|
7758
8051
|
x: z.number().min(0).max(1),
|
|
7759
8052
|
y: z.number().min(0).max(1),
|
|
@@ -7787,56 +8080,149 @@ const transformSchema = z.object({
|
|
|
7787
8080
|
rotation: rotationSchema.optional()
|
|
7788
8081
|
});
|
|
7789
8082
|
const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
|
|
7790
|
-
tag: z.literal("
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
storagePath: z.string().min(1)
|
|
7794
|
-
}), z.object({
|
|
8083
|
+
tag: z.literal("media"),
|
|
8084
|
+
identifier: mediaIdentifierSchema
|
|
8085
|
+
}).strict(), z.object({
|
|
7795
8086
|
tag: z.literal("external-src"),
|
|
7796
|
-
assetId: z.string().optional(),
|
|
7797
8087
|
src: z.string().url()
|
|
7798
|
-
})]);
|
|
7799
|
-
const
|
|
8088
|
+
}).strict()]);
|
|
8089
|
+
const mediaUsageShape = {
|
|
7800
8090
|
purpose: z.string().optional(),
|
|
7801
8091
|
placeholder: z.boolean().default(true).optional(),
|
|
7802
|
-
assetId: z.string().optional(),
|
|
7803
|
-
identifier: z.string().optional(),
|
|
7804
|
-
src: z.string().optional(),
|
|
7805
8092
|
alt: z.string().optional(),
|
|
7806
8093
|
filename: z.string().optional(),
|
|
7807
|
-
mimeType: z.string().optional(),
|
|
7808
8094
|
width: z.number().optional(),
|
|
7809
8095
|
height: z.number().optional(),
|
|
7810
|
-
storageBucket: z.string().optional(),
|
|
7811
|
-
storagePath: z.string().optional(),
|
|
7812
8096
|
poster: mediaPosterSchema.optional(),
|
|
7813
8097
|
transform: transformSchema.optional()
|
|
7814
|
-
}
|
|
7815
|
-
const
|
|
8098
|
+
};
|
|
8099
|
+
const environmentExclusions = {
|
|
8100
|
+
assetId: z.never().optional(),
|
|
8101
|
+
id: z.never().optional(),
|
|
8102
|
+
src: z.never().optional(),
|
|
8103
|
+
storageBucket: z.never().optional(),
|
|
8104
|
+
storagePath: z.never().optional(),
|
|
8105
|
+
mimeType: z.never().optional()
|
|
8106
|
+
};
|
|
8107
|
+
const mediaBaseSchema = z.object({
|
|
8108
|
+
...mediaUsageShape,
|
|
8109
|
+
...environmentExclusions,
|
|
8110
|
+
identifier: mediaIdentifierSchema
|
|
8111
|
+
}).strict();
|
|
7816
8112
|
const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
|
|
7817
8113
|
const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
|
|
7818
|
-
const
|
|
7819
|
-
const
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
z.
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
persistableMediaBaseSchema.extend({ type: z.literal("archive") })
|
|
8114
|
+
const mediaSchema = mediaBaseSchema.extend({ type: z.enum(mediaTypeDiscriminants) });
|
|
8115
|
+
const externalMediaSchema = z.object({
|
|
8116
|
+
...mediaUsageShape,
|
|
8117
|
+
...environmentExclusions,
|
|
8118
|
+
type: z.enum(mediaTypeDiscriminants),
|
|
8119
|
+
src: z.string().min(1),
|
|
8120
|
+
identifier: z.never().optional()
|
|
8121
|
+
}).strict();
|
|
8122
|
+
const assetMediaSchema = z.object({
|
|
8123
|
+
...mediaUsageShape,
|
|
8124
|
+
...environmentExclusions,
|
|
8125
|
+
type: z.enum(mediaTypeDiscriminants),
|
|
8126
|
+
asset: renderableMediaAssetSchema,
|
|
8127
|
+
identifier: z.never().optional()
|
|
8128
|
+
}).strict();
|
|
8129
|
+
const runtimeMediaSchema = z.union([
|
|
8130
|
+
mediaSchema,
|
|
8131
|
+
externalMediaSchema,
|
|
8132
|
+
assetMediaSchema
|
|
7838
8133
|
]);
|
|
7839
8134
|
//#endregion
|
|
8135
|
+
//#region ../media-core/src/transformRect.ts
|
|
8136
|
+
function isValidTransformRectStructure(rect) {
|
|
8137
|
+
if (!Array.isArray(rect) || rect.length !== 4) return false;
|
|
8138
|
+
const [left, top, width, height] = rect;
|
|
8139
|
+
return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
|
|
8140
|
+
}
|
|
8141
|
+
//#endregion
|
|
8142
|
+
//#region ../media-core/src/aspectTransforms.ts
|
|
8143
|
+
const DEFAULT_RECT_EPSILON = .5;
|
|
8144
|
+
function parseAspectRatioValue(value) {
|
|
8145
|
+
if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
8146
|
+
if (typeof value !== "string") return void 0;
|
|
8147
|
+
const normalized = value.trim();
|
|
8148
|
+
if (!normalized) return void 0;
|
|
8149
|
+
if (normalized === "auto") return void 0;
|
|
8150
|
+
if (normalized.includes(":") || normalized.includes("/")) {
|
|
8151
|
+
const delimiter = normalized.includes(":") ? ":" : "/";
|
|
8152
|
+
const [wRaw, hRaw] = normalized.split(delimiter);
|
|
8153
|
+
const width = Number(wRaw?.trim());
|
|
8154
|
+
const height = Number(hRaw?.trim());
|
|
8155
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
|
|
8156
|
+
return width / height;
|
|
8157
|
+
}
|
|
8158
|
+
const numeric = Number(normalized);
|
|
8159
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
|
|
8160
|
+
return numeric;
|
|
8161
|
+
}
|
|
8162
|
+
const MAX_ASPECT_DISTANCE = .25;
|
|
8163
|
+
function resolveMediaTransformForAspect(transform, targetAspect) {
|
|
8164
|
+
if (!transform) return {};
|
|
8165
|
+
const base = {
|
|
8166
|
+
rect: transform.rect,
|
|
8167
|
+
hotspot: transform.hotspot,
|
|
8168
|
+
rotation: transform.rotation
|
|
8169
|
+
};
|
|
8170
|
+
const target = parseAspectRatioValue(targetAspect);
|
|
8171
|
+
const crops = transform.aspectCrops;
|
|
8172
|
+
if (!target || !crops || Object.keys(crops).length === 0) return base;
|
|
8173
|
+
let best = null;
|
|
8174
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
8175
|
+
for (const [key, candidate] of Object.entries(crops)) {
|
|
8176
|
+
const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
|
|
8177
|
+
if (!candidateAspect) continue;
|
|
8178
|
+
const distance = Math.abs(Math.log(candidateAspect / target));
|
|
8179
|
+
if (distance < bestDistance) {
|
|
8180
|
+
best = candidate;
|
|
8181
|
+
bestDistance = distance;
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
if (!best) return base;
|
|
8185
|
+
if (bestDistance > MAX_ASPECT_DISTANCE) return base;
|
|
8186
|
+
return {
|
|
8187
|
+
rect: best.rect ?? base.rect,
|
|
8188
|
+
hotspot: best.hotspot ?? base.hotspot,
|
|
8189
|
+
rotation: best.rotation ?? base.rotation
|
|
8190
|
+
};
|
|
8191
|
+
}
|
|
8192
|
+
function isValidTransformRect(rect) {
|
|
8193
|
+
return isValidTransformRectStructure(rect);
|
|
8194
|
+
}
|
|
8195
|
+
function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
|
|
8196
|
+
if (!isValidTransformRect(rect)) return false;
|
|
8197
|
+
if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
|
|
8198
|
+
const [x, y, width, height] = rect;
|
|
8199
|
+
return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
|
|
8200
|
+
}
|
|
8201
|
+
//#endregion
|
|
8202
|
+
//#region ../media-core/src/rotation.ts
|
|
8203
|
+
function rotateNormalizedPoint(point, rotation) {
|
|
8204
|
+
const x = point.x;
|
|
8205
|
+
const y = point.y;
|
|
8206
|
+
switch (rotation) {
|
|
8207
|
+
case 0: return {
|
|
8208
|
+
x,
|
|
8209
|
+
y
|
|
8210
|
+
};
|
|
8211
|
+
case 90: return {
|
|
8212
|
+
x: 1 - y,
|
|
8213
|
+
y: x
|
|
8214
|
+
};
|
|
8215
|
+
case 180: return {
|
|
8216
|
+
x: 1 - x,
|
|
8217
|
+
y: 1 - y
|
|
8218
|
+
};
|
|
8219
|
+
case 270: return {
|
|
8220
|
+
x: y,
|
|
8221
|
+
y: 1 - x
|
|
8222
|
+
};
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8225
|
+
//#endregion
|
|
7840
8226
|
//#region ../theme-core/src/palette/schema.ts
|
|
7841
8227
|
const colourHexString = z.string().regex(/^#([0-9A-Fa-f]{3}){1,2}$/);
|
|
7842
8228
|
const paletteColorSchema = z.object({
|
|
@@ -16385,6 +16771,21 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
|
|
|
16385
16771
|
showVideoOnMobile: z.boolean().nullable().optional()
|
|
16386
16772
|
})
|
|
16387
16773
|
]);
|
|
16774
|
+
/** Application rendering sources are admitted separately from saved references. */
|
|
16775
|
+
const runtimeBoxBackgroundSchema = z.discriminatedUnion("type", [
|
|
16776
|
+
boxBackgroundSchema.options[0],
|
|
16777
|
+
boxBackgroundSchema.options[1],
|
|
16778
|
+
boxBackgroundSchema.options[2].extend({ image: z.union([
|
|
16779
|
+
imageMediaSchema,
|
|
16780
|
+
externalMediaSchema.extend({ type: z.literal("image") }),
|
|
16781
|
+
assetMediaSchema.extend({ type: z.literal("image") })
|
|
16782
|
+
]).nullable().optional() }),
|
|
16783
|
+
boxBackgroundSchema.options[3].extend({ image: z.union([
|
|
16784
|
+
videoMediaSchema,
|
|
16785
|
+
externalMediaSchema.extend({ type: z.literal("video") }),
|
|
16786
|
+
assetMediaSchema.extend({ type: z.literal("video") })
|
|
16787
|
+
]).nullable().optional() })
|
|
16788
|
+
]);
|
|
16388
16789
|
function normalizeAuthoringOpacity(value) {
|
|
16389
16790
|
if (!isRecord$6(value)) return value;
|
|
16390
16791
|
return {
|
|
@@ -23234,97 +23635,6 @@ function registerManifest(manifest) {
|
|
|
23234
23635
|
return manifest;
|
|
23235
23636
|
}
|
|
23236
23637
|
//#endregion
|
|
23237
|
-
//#region ../media-core/src/transformRect.ts
|
|
23238
|
-
function isValidTransformRectStructure(rect) {
|
|
23239
|
-
if (!Array.isArray(rect) || rect.length !== 4) return false;
|
|
23240
|
-
const [left, top, width, height] = rect;
|
|
23241
|
-
return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
|
|
23242
|
-
}
|
|
23243
|
-
//#endregion
|
|
23244
|
-
//#region ../media-core/src/aspectTransforms.ts
|
|
23245
|
-
const DEFAULT_RECT_EPSILON = .5;
|
|
23246
|
-
function parseAspectRatioValue(value) {
|
|
23247
|
-
if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
23248
|
-
if (typeof value !== "string") return void 0;
|
|
23249
|
-
const normalized = value.trim();
|
|
23250
|
-
if (!normalized) return void 0;
|
|
23251
|
-
if (normalized === "auto") return void 0;
|
|
23252
|
-
if (normalized.includes(":") || normalized.includes("/")) {
|
|
23253
|
-
const delimiter = normalized.includes(":") ? ":" : "/";
|
|
23254
|
-
const [wRaw, hRaw] = normalized.split(delimiter);
|
|
23255
|
-
const width = Number(wRaw?.trim());
|
|
23256
|
-
const height = Number(hRaw?.trim());
|
|
23257
|
-
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
|
|
23258
|
-
return width / height;
|
|
23259
|
-
}
|
|
23260
|
-
const numeric = Number(normalized);
|
|
23261
|
-
if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
|
|
23262
|
-
return numeric;
|
|
23263
|
-
}
|
|
23264
|
-
const MAX_ASPECT_DISTANCE = .25;
|
|
23265
|
-
function resolveMediaTransformForAspect(transform, targetAspect) {
|
|
23266
|
-
if (!transform) return {};
|
|
23267
|
-
const base = {
|
|
23268
|
-
rect: transform.rect,
|
|
23269
|
-
hotspot: transform.hotspot,
|
|
23270
|
-
rotation: transform.rotation
|
|
23271
|
-
};
|
|
23272
|
-
const target = parseAspectRatioValue(targetAspect);
|
|
23273
|
-
const crops = transform.aspectCrops;
|
|
23274
|
-
if (!target || !crops || Object.keys(crops).length === 0) return base;
|
|
23275
|
-
let best = null;
|
|
23276
|
-
let bestDistance = Number.POSITIVE_INFINITY;
|
|
23277
|
-
for (const [key, candidate] of Object.entries(crops)) {
|
|
23278
|
-
const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
|
|
23279
|
-
if (!candidateAspect) continue;
|
|
23280
|
-
const distance = Math.abs(Math.log(candidateAspect / target));
|
|
23281
|
-
if (distance < bestDistance) {
|
|
23282
|
-
best = candidate;
|
|
23283
|
-
bestDistance = distance;
|
|
23284
|
-
}
|
|
23285
|
-
}
|
|
23286
|
-
if (!best) return base;
|
|
23287
|
-
if (bestDistance > MAX_ASPECT_DISTANCE) return base;
|
|
23288
|
-
return {
|
|
23289
|
-
rect: best.rect ?? base.rect,
|
|
23290
|
-
hotspot: best.hotspot ?? base.hotspot,
|
|
23291
|
-
rotation: best.rotation ?? base.rotation
|
|
23292
|
-
};
|
|
23293
|
-
}
|
|
23294
|
-
function isValidTransformRect(rect) {
|
|
23295
|
-
return isValidTransformRectStructure(rect);
|
|
23296
|
-
}
|
|
23297
|
-
function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
|
|
23298
|
-
if (!isValidTransformRect(rect)) return false;
|
|
23299
|
-
if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
|
|
23300
|
-
const [x, y, width, height] = rect;
|
|
23301
|
-
return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
|
|
23302
|
-
}
|
|
23303
|
-
//#endregion
|
|
23304
|
-
//#region ../media-core/src/rotation.ts
|
|
23305
|
-
function rotateNormalizedPoint(point, rotation) {
|
|
23306
|
-
const x = point.x;
|
|
23307
|
-
const y = point.y;
|
|
23308
|
-
switch (rotation) {
|
|
23309
|
-
case 0: return {
|
|
23310
|
-
x,
|
|
23311
|
-
y
|
|
23312
|
-
};
|
|
23313
|
-
case 90: return {
|
|
23314
|
-
x: 1 - y,
|
|
23315
|
-
y: x
|
|
23316
|
-
};
|
|
23317
|
-
case 180: return {
|
|
23318
|
-
x: 1 - x,
|
|
23319
|
-
y: 1 - y
|
|
23320
|
-
};
|
|
23321
|
-
case 270: return {
|
|
23322
|
-
x: y,
|
|
23323
|
-
y: 1 - x
|
|
23324
|
-
};
|
|
23325
|
-
}
|
|
23326
|
-
}
|
|
23327
|
-
//#endregion
|
|
23328
23638
|
//#region ../blocks/src/system/node/schema.ts
|
|
23329
23639
|
const transformStepSchema = z.object({
|
|
23330
23640
|
id: z.string().min(1, "Transform requires an identifier"),
|
|
@@ -24262,6 +24572,14 @@ z.object({
|
|
|
24262
24572
|
icon: z.string().optional()
|
|
24263
24573
|
});
|
|
24264
24574
|
//#endregion
|
|
24575
|
+
//#region ../blocks/src/lib/typeGuards.ts
|
|
24576
|
+
/**
|
|
24577
|
+
* Strict record guard: excludes null, primitives, and arrays.
|
|
24578
|
+
*/
|
|
24579
|
+
function isRecord$5(value) {
|
|
24580
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24581
|
+
}
|
|
24582
|
+
//#endregion
|
|
24265
24583
|
//#region ../blocks/src/system/designCapabilities.ts
|
|
24266
24584
|
function declareBlockDesignCapability(capability) {
|
|
24267
24585
|
return {
|
|
@@ -26242,6 +26560,12 @@ function parseBackgroundOverlay(value) {
|
|
|
26242
26560
|
const result = boxBackgroundOverlaySchema.safeParse(value);
|
|
26243
26561
|
return result.success ? result.data : void 0;
|
|
26244
26562
|
}
|
|
26563
|
+
/** Rendering accepts explicit application sources separately from stored references. */
|
|
26564
|
+
const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
|
|
26565
|
+
function parseRuntimeBackgroundContent(value) {
|
|
26566
|
+
const result = runtimeBackgroundContentSchema.safeParse(value);
|
|
26567
|
+
return result.success ? result.data : null;
|
|
26568
|
+
}
|
|
26245
26569
|
//#endregion
|
|
26246
26570
|
//#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
|
|
26247
26571
|
function resolveBackgroundColorValue(value, context) {
|
|
@@ -31115,6 +31439,15 @@ const formBlockDefinition = {
|
|
|
31115
31439
|
runtime: formBlockRuntime
|
|
31116
31440
|
};
|
|
31117
31441
|
//#endregion
|
|
31442
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
31443
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
31444
|
+
function normalizeMailingListBlockContent(record) {
|
|
31445
|
+
return record.targeting == null ? {
|
|
31446
|
+
...record,
|
|
31447
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
31448
|
+
} : record;
|
|
31449
|
+
}
|
|
31450
|
+
//#endregion
|
|
31118
31451
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
31119
31452
|
const contactNewsletterLayout = styledSection({
|
|
31120
31453
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -31278,6 +31611,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
31278
31611
|
],
|
|
31279
31612
|
icon: "MailPlus"
|
|
31280
31613
|
}),
|
|
31614
|
+
contentNormalizer: {
|
|
31615
|
+
fieldIds: ["targeting"],
|
|
31616
|
+
normalize: normalizeMailingListBlockContent
|
|
31617
|
+
},
|
|
31281
31618
|
dataSchemas: { form: formDataSchema.optional() },
|
|
31282
31619
|
dataLoaders: { form: {
|
|
31283
31620
|
endpoint: "getPublicFormById",
|
|
@@ -32695,14 +33032,6 @@ const mediaTransforms = [{
|
|
|
32695
33032
|
}
|
|
32696
33033
|
}];
|
|
32697
33034
|
//#endregion
|
|
32698
|
-
//#region ../blocks/src/lib/typeGuards.ts
|
|
32699
|
-
/**
|
|
32700
|
-
* Strict record guard: excludes null, primitives, and arrays.
|
|
32701
|
-
*/
|
|
32702
|
-
function isRecord$5(value) {
|
|
32703
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32704
|
-
}
|
|
32705
|
-
//#endregion
|
|
32706
33035
|
//#region ../blocks/src/system/transforms/registry/content.ts
|
|
32707
33036
|
const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
|
|
32708
33037
|
const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(supportedRichTextTokenSchema).default(["year", "site_name"]) });
|
|
@@ -35495,14 +35824,6 @@ const weeklySlotAvailabilityBlockDefinition = {
|
|
|
35495
35824
|
} }
|
|
35496
35825
|
};
|
|
35497
35826
|
//#endregion
|
|
35498
|
-
//#region ../blocks/src/lib/media.ts
|
|
35499
|
-
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
35500
|
-
"document",
|
|
35501
|
-
"spreadsheet",
|
|
35502
|
-
"archive",
|
|
35503
|
-
"audio"
|
|
35504
|
-
];
|
|
35505
|
-
//#endregion
|
|
35506
35827
|
//#region ../blocks/src/system/manifest/richTextSchema.ts
|
|
35507
35828
|
/**
|
|
35508
35829
|
* Shared Rich Text Schema
|
|
@@ -35678,6 +35999,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
35678
35999
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
35679
36000
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
35680
36001
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
36002
|
+
z.strictObject({
|
|
36003
|
+
currency: z.string().trim().length(3),
|
|
36004
|
+
totalCents: nonNegativeIntegerSchema,
|
|
36005
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
36006
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
36007
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
36008
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
36009
|
+
});
|
|
35681
36010
|
//#endregion
|
|
35682
36011
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
35683
36012
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -35918,6 +36247,10 @@ const publicEventBaseSchema = z.object({
|
|
|
35918
36247
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
35919
36248
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
35920
36249
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
36250
|
+
scheduleSummary: z.object({
|
|
36251
|
+
recurrenceDescription: z.string(),
|
|
36252
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
36253
|
+
}).nullable().optional(),
|
|
35921
36254
|
id: z.string(),
|
|
35922
36255
|
occurrenceId: z.string(),
|
|
35923
36256
|
seriesId: z.string(),
|
|
@@ -35926,7 +36259,7 @@ const publicEventBaseSchema = z.object({
|
|
|
35926
36259
|
content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
|
|
35927
36260
|
presentation: z.object({
|
|
35928
36261
|
summary: z.string().nullable().optional(),
|
|
35929
|
-
image:
|
|
36262
|
+
image: runtimeMediaSchema.nullable().optional()
|
|
35930
36263
|
}).optional(),
|
|
35931
36264
|
slug: z.string(),
|
|
35932
36265
|
path: z.string().nullable(),
|
|
@@ -36328,67 +36661,266 @@ const occurrenceContextSchema = z.object({
|
|
|
36328
36661
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
36329
36662
|
}).nullable();
|
|
36330
36663
|
//#endregion
|
|
36331
|
-
//#region ../blocks/src/system/runtime/
|
|
36332
|
-
|
|
36333
|
-
|
|
36334
|
-
|
|
36335
|
-
|
|
36336
|
-
|
|
36337
|
-
|
|
36338
|
-
|
|
36339
|
-
|
|
36340
|
-
|
|
36341
|
-
|
|
36342
|
-
|
|
36343
|
-
|
|
36344
|
-
"invalidEventOfferingCatalogue"
|
|
36345
|
-
])
|
|
36346
|
-
});
|
|
36347
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
36348
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
36349
|
-
if (unsupported.success) return unsupported.data;
|
|
36350
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
36351
|
-
if (parsed.ok) return parsed.value;
|
|
36352
|
-
ctx.addIssue({
|
|
36353
|
-
code: z.ZodIssueCode.custom,
|
|
36354
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
36355
|
-
});
|
|
36356
|
-
return z.NEVER;
|
|
36357
|
-
});
|
|
36358
|
-
function resolveEventRegistrationScope(context) {
|
|
36359
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
36360
|
-
if (occurrenceSeriesId) return {
|
|
36361
|
-
kind: "occurrenceSeries",
|
|
36362
|
-
seriesId: occurrenceSeriesId
|
|
36664
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
36665
|
+
/**
|
|
36666
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
36667
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
36668
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
36669
|
+
*
|
|
36670
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
36671
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
36672
|
+
*/
|
|
36673
|
+
function getEventAvailability(event) {
|
|
36674
|
+
if (event.capacity == null) return {
|
|
36675
|
+
available: null,
|
|
36676
|
+
isFull: false
|
|
36363
36677
|
};
|
|
36364
|
-
|
|
36365
|
-
|
|
36366
|
-
|
|
36678
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
36679
|
+
if (available <= 0) return {
|
|
36680
|
+
available: 0,
|
|
36681
|
+
isFull: true
|
|
36367
36682
|
};
|
|
36368
|
-
|
|
36369
|
-
|
|
36370
|
-
|
|
36371
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
36683
|
+
return {
|
|
36684
|
+
available,
|
|
36685
|
+
isFull: false
|
|
36372
36686
|
};
|
|
36373
|
-
|
|
36374
|
-
|
|
36375
|
-
|
|
36687
|
+
}
|
|
36688
|
+
/**
|
|
36689
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
36690
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
36691
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
36692
|
+
*
|
|
36693
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
36694
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
36695
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
36696
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
36697
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
36698
|
+
*/
|
|
36699
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
36700
|
+
if (!attendanceMode) return event;
|
|
36701
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
36702
|
+
}
|
|
36703
|
+
/**
|
|
36704
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
36705
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
36706
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
36707
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
36708
|
+
* `capacity - registeredCount` fallback.
|
|
36709
|
+
*/
|
|
36710
|
+
function canJoinEventWaitlist(event, options) {
|
|
36711
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
36712
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
36713
|
+
}
|
|
36714
|
+
/**
|
|
36715
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
36716
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
36717
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
36718
|
+
* to be stale on a cached page.
|
|
36719
|
+
*
|
|
36720
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
36721
|
+
*
|
|
36722
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
36723
|
+
* 5% floor stops large events staying silent until three remain.
|
|
36724
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
36725
|
+
*/
|
|
36726
|
+
function lowCapacityThreshold(capacity) {
|
|
36727
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
36728
|
+
}
|
|
36729
|
+
function getRemainingPlaces(source) {
|
|
36730
|
+
const { available, isFull } = getEventAvailability(source);
|
|
36731
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
36732
|
+
if (isFull) return {
|
|
36733
|
+
kind: "full",
|
|
36734
|
+
waitlist: canJoinEventWaitlist(source)
|
|
36376
36735
|
};
|
|
36377
|
-
|
|
36736
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
36737
|
+
kind: "low",
|
|
36738
|
+
remaining: available
|
|
36739
|
+
};
|
|
36740
|
+
return { kind: "open" };
|
|
36378
36741
|
}
|
|
36379
|
-
|
|
36380
|
-
|
|
36381
|
-
|
|
36382
|
-
|
|
36383
|
-
|
|
36384
|
-
|
|
36385
|
-
|
|
36386
|
-
|
|
36387
|
-
|
|
36388
|
-
case "
|
|
36389
|
-
case "
|
|
36742
|
+
/**
|
|
36743
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
36744
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
36745
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
36746
|
+
* it in rather than re-deriving the count.
|
|
36747
|
+
*/
|
|
36748
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
36749
|
+
const remaining = getRemainingPlaces(source);
|
|
36750
|
+
switch (remaining.kind) {
|
|
36751
|
+
case "unlimited":
|
|
36752
|
+
case "open": return null;
|
|
36753
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
36754
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
36755
|
+
}
|
|
36756
|
+
}
|
|
36757
|
+
function formatPlacesLeft(count, compact) {
|
|
36758
|
+
if (compact) return `${count} left`;
|
|
36759
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
36760
|
+
}
|
|
36761
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
36762
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
36763
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
36764
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
36765
|
+
}
|
|
36766
|
+
/**
|
|
36767
|
+
* Which capacity figure wins when they disagree.
|
|
36768
|
+
*
|
|
36769
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
36770
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
36771
|
+
* The registration write path admits or refuses per mode
|
|
36772
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
36773
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
36774
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
36775
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
36776
|
+
*
|
|
36777
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
36778
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
36779
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
36780
|
+
* the aggregate, unchanged.
|
|
36781
|
+
*/
|
|
36782
|
+
function findHybridModeRows(event) {
|
|
36783
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
36784
|
+
const rows = event.attendanceModes ?? [];
|
|
36785
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
36786
|
+
const online = rows.find((row) => row.mode === "online");
|
|
36787
|
+
return inPerson && online ? {
|
|
36788
|
+
inPerson,
|
|
36789
|
+
online
|
|
36790
|
+
} : null;
|
|
36791
|
+
}
|
|
36792
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
36793
|
+
function remainingPlacesRank(remaining) {
|
|
36794
|
+
switch (remaining.kind) {
|
|
36795
|
+
case "unlimited": return 4;
|
|
36796
|
+
case "open": return 3;
|
|
36797
|
+
case "low": return 2;
|
|
36798
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
36799
|
+
}
|
|
36800
|
+
}
|
|
36801
|
+
function isMoreOpen(candidate, than) {
|
|
36802
|
+
const rank = remainingPlacesRank(candidate);
|
|
36803
|
+
const otherRank = remainingPlacesRank(than);
|
|
36804
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
36805
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
36806
|
+
}
|
|
36807
|
+
/** True when `candidate` has less room left than `than`. */
|
|
36808
|
+
function isScarcer(candidate, than) {
|
|
36809
|
+
return isMoreOpen(than, candidate);
|
|
36810
|
+
}
|
|
36811
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
36812
|
+
in_person: "In person",
|
|
36813
|
+
online: "Online"
|
|
36814
|
+
};
|
|
36815
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
36816
|
+
const PLACES_AVAILABLE = "Places available";
|
|
36817
|
+
/**
|
|
36818
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
36819
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
36820
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
36821
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
36822
|
+
* promise the registration wizard would otherwise have to break.
|
|
36823
|
+
*
|
|
36824
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
36825
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
36826
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
36827
|
+
* { compact: true } -> "Online: 3 left"
|
|
36828
|
+
*/
|
|
36829
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
36830
|
+
const rows = findHybridModeRows(event);
|
|
36831
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
36832
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
36833
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
36834
|
+
if (inPerson === online) return inPerson;
|
|
36835
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
36836
|
+
return formatBothHybridSides(rows, {
|
|
36837
|
+
inPerson,
|
|
36838
|
+
online
|
|
36839
|
+
});
|
|
36840
|
+
}
|
|
36841
|
+
/**
|
|
36842
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
36843
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
36844
|
+
*/
|
|
36845
|
+
function formatBothHybridSides(rows, labels) {
|
|
36846
|
+
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(" · ");
|
|
36847
|
+
}
|
|
36848
|
+
function namedModePlaces(mode, label) {
|
|
36849
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
36850
|
+
}
|
|
36851
|
+
/**
|
|
36852
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
36853
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
36854
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
36855
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
36856
|
+
* how the event is delivered rather than about its remaining places.
|
|
36857
|
+
*/
|
|
36858
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
36859
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
36860
|
+
const online = getRemainingPlaces(rows.online);
|
|
36861
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
36862
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
36863
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
36864
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
36865
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
36866
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
36867
|
+
}
|
|
36868
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
36869
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
36870
|
+
}
|
|
36871
|
+
function rowFor(rows, mode) {
|
|
36872
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
36873
|
+
}
|
|
36874
|
+
//#endregion
|
|
36875
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
36876
|
+
const registrationDisplaySchema = z.object({
|
|
36877
|
+
venue: z.enum(["shown", "hidden"]),
|
|
36878
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
36879
|
+
});
|
|
36880
|
+
function resolveRegistrationDisplay(source) {
|
|
36881
|
+
return {
|
|
36882
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
36883
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
36884
|
+
};
|
|
36885
|
+
}
|
|
36886
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
36887
|
+
function shownVenue(event, display) {
|
|
36888
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
36889
|
+
}
|
|
36890
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
36891
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
36892
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
36893
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
36894
|
+
return capacityPlacesLabel(source, display, wording);
|
|
36895
|
+
}
|
|
36896
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
36897
|
+
const remaining = getRemainingPlaces(source);
|
|
36898
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
36899
|
+
switch (remaining.kind) {
|
|
36900
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
36901
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
36902
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
36903
|
+
case "open": return wording.open ?? null;
|
|
36904
|
+
default: return assertNever$2(remaining);
|
|
36390
36905
|
}
|
|
36391
36906
|
}
|
|
36907
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
36908
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
36909
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
36910
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
36911
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
36912
|
+
}).join(" · ") || null;
|
|
36913
|
+
}
|
|
36914
|
+
function ticketPlacesLabel(remaining, display) {
|
|
36915
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
36916
|
+
return formatTicketTypeRemaining(remaining);
|
|
36917
|
+
}
|
|
36918
|
+
//#endregion
|
|
36919
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
36920
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
36921
|
+
kind: z.literal("preview"),
|
|
36922
|
+
token: z.string().min(1)
|
|
36923
|
+
}).strict()]);
|
|
36392
36924
|
//#endregion
|
|
36393
36925
|
//#region ../calendar/src/grid.ts
|
|
36394
36926
|
const MONTH_NAMES = [
|
|
@@ -36476,6 +37008,11 @@ function buildCalendarViewport(input) {
|
|
|
36476
37008
|
//#endregion
|
|
36477
37009
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
36478
37010
|
/**
|
|
37011
|
+
* Date and time presentation for events: the single place an event's
|
|
37012
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
37013
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
37014
|
+
*/
|
|
37015
|
+
/**
|
|
36479
37016
|
* The English locale a site's public dates are written in, read from the
|
|
36480
37017
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
36481
37018
|
*
|
|
@@ -36495,6 +37032,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
36495
37032
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
36496
37033
|
return "en-US";
|
|
36497
37034
|
}
|
|
37035
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
37036
|
+
const locale = options?.locale ?? "en-US";
|
|
37037
|
+
const dateTime = toScheduledBookingDateTime({
|
|
37038
|
+
startsAt: isoTimestamp,
|
|
37039
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
37040
|
+
locale
|
|
37041
|
+
});
|
|
37042
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
37043
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
37044
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
37045
|
+
return {
|
|
37046
|
+
weekday,
|
|
37047
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
37048
|
+
month,
|
|
37049
|
+
label: formatBookingDate(dateTime, {
|
|
37050
|
+
weekday: "long",
|
|
37051
|
+
year: "numeric",
|
|
37052
|
+
month: "long",
|
|
37053
|
+
day: "numeric"
|
|
37054
|
+
})
|
|
37055
|
+
};
|
|
37056
|
+
}
|
|
36498
37057
|
//#endregion
|
|
36499
37058
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
36500
37059
|
function isRecord$4(value) {
|
|
@@ -36514,6 +37073,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
36514
37073
|
};
|
|
36515
37074
|
}
|
|
36516
37075
|
//#endregion
|
|
37076
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
37077
|
+
/**
|
|
37078
|
+
* Format an event's price directly from its pricing value (without the full
|
|
37079
|
+
* event). Same output as {@link formatEventPrice}.
|
|
37080
|
+
*/
|
|
37081
|
+
function formatEventPriceDisplay(pricing) {
|
|
37082
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
37083
|
+
}
|
|
37084
|
+
//#endregion
|
|
36517
37085
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
36518
37086
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
36519
37087
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -36548,6 +37116,642 @@ function eventListWindowEvents(events, window) {
|
|
|
36548
37116
|
});
|
|
36549
37117
|
}
|
|
36550
37118
|
//#endregion
|
|
37119
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
37120
|
+
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
37121
|
+
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
37122
|
+
}
|
|
37123
|
+
function findPreSelectedEvent(input) {
|
|
37124
|
+
const occurrenceContext = input.occurrenceContext;
|
|
37125
|
+
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
37126
|
+
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
37127
|
+
startsAt: occurrenceContext.startsAt,
|
|
37128
|
+
timeZone: occurrenceContext.timeZone
|
|
37129
|
+
}));
|
|
37130
|
+
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
37131
|
+
startsAt: event.startsAt,
|
|
37132
|
+
timeZone: event.timeZone
|
|
37133
|
+
})) === contextDate) ?? null;
|
|
37134
|
+
}
|
|
37135
|
+
function resolveEventRequiresPayment(input) {
|
|
37136
|
+
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
37137
|
+
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
37138
|
+
if (!input.event) return false;
|
|
37139
|
+
return publicEventPricingType(input.event.pricing) === "paid";
|
|
37140
|
+
}
|
|
37141
|
+
//#endregion
|
|
37142
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
37143
|
+
/**
|
|
37144
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
37145
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
37146
|
+
* English when the site names no zone.
|
|
37147
|
+
*/
|
|
37148
|
+
function bookingDateLocale(siteTimeZone) {
|
|
37149
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
37150
|
+
}
|
|
37151
|
+
function bookingInstant(startsAt, input) {
|
|
37152
|
+
return toScheduledBookingDateTime({
|
|
37153
|
+
startsAt,
|
|
37154
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
37155
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
37156
|
+
});
|
|
37157
|
+
}
|
|
37158
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
37159
|
+
function bookingClock(startsAt, input) {
|
|
37160
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
37161
|
+
hour: "numeric",
|
|
37162
|
+
minute: "2-digit",
|
|
37163
|
+
hour12: true
|
|
37164
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
37165
|
+
}
|
|
37166
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
37167
|
+
function clockRange(input) {
|
|
37168
|
+
const start = bookingClock(input.startsAt, input);
|
|
37169
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
37170
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
37171
|
+
}
|
|
37172
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
37173
|
+
function formatBookingScheduleSummary(event) {
|
|
37174
|
+
const summary = event.scheduleSummary;
|
|
37175
|
+
if (!summary) return null;
|
|
37176
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
37177
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
37178
|
+
timeZone: "UTC",
|
|
37179
|
+
siteTimeZone: event.siteTimeZone
|
|
37180
|
+
}, "time") : null;
|
|
37181
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
37182
|
+
}
|
|
37183
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
37184
|
+
function formatBookingWhen(input, variant) {
|
|
37185
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
37186
|
+
const day = formatBookingDate(instant, {
|
|
37187
|
+
weekday: "short",
|
|
37188
|
+
day: "numeric",
|
|
37189
|
+
month: "short"
|
|
37190
|
+
});
|
|
37191
|
+
switch (variant) {
|
|
37192
|
+
case "day": return day;
|
|
37193
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
37194
|
+
weekday: "long",
|
|
37195
|
+
day: "numeric",
|
|
37196
|
+
month: "long"
|
|
37197
|
+
});
|
|
37198
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
37199
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
37200
|
+
month: "long",
|
|
37201
|
+
year: "numeric"
|
|
37202
|
+
});
|
|
37203
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
37204
|
+
case "timeRange": return clockRange(input);
|
|
37205
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
37206
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
37207
|
+
}
|
|
37208
|
+
}
|
|
37209
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
37210
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
37211
|
+
return formatBookingWhen({
|
|
37212
|
+
startsAt: isoTimestamp,
|
|
37213
|
+
timeZone: options?.timeZone,
|
|
37214
|
+
siteTimeZone: options?.siteTimeZone
|
|
37215
|
+
}, "short");
|
|
37216
|
+
}
|
|
37217
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
37218
|
+
function occurrenceTitleOverride(occurrence) {
|
|
37219
|
+
const title = occurrence?.overrides?.title;
|
|
37220
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
37221
|
+
}
|
|
37222
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
37223
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
37224
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
37225
|
+
return event && title ? {
|
|
37226
|
+
...event,
|
|
37227
|
+
title
|
|
37228
|
+
} : event;
|
|
37229
|
+
}
|
|
37230
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
37231
|
+
const first = sessions[0];
|
|
37232
|
+
if (!first) return null;
|
|
37233
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
37234
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
37235
|
+
timeZone: first.timeZone,
|
|
37236
|
+
siteTimeZone
|
|
37237
|
+
});
|
|
37238
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
37239
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
37240
|
+
timeZone: last.timeZone,
|
|
37241
|
+
siteTimeZone
|
|
37242
|
+
});
|
|
37243
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
37244
|
+
}
|
|
37245
|
+
/**
|
|
37246
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
37247
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
37248
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
37249
|
+
*/
|
|
37250
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
37251
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
37252
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
37253
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
37254
|
+
}
|
|
37255
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
37256
|
+
function scheduleInput(event, occurrence) {
|
|
37257
|
+
const times = occurrence?.startsAt ? {
|
|
37258
|
+
startsAt: occurrence.startsAt,
|
|
37259
|
+
endsAt: occurrence.endsAt ?? null
|
|
37260
|
+
} : {
|
|
37261
|
+
startsAt: event.startsAt,
|
|
37262
|
+
endsAt: event.endsAt
|
|
37263
|
+
};
|
|
37264
|
+
if (!times.startsAt) return null;
|
|
37265
|
+
return {
|
|
37266
|
+
...times,
|
|
37267
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
37268
|
+
siteTimeZone: event.siteTimeZone
|
|
37269
|
+
};
|
|
37270
|
+
}
|
|
37271
|
+
//#endregion
|
|
37272
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
37273
|
+
function registrationRoute(input) {
|
|
37274
|
+
const base = input.chooseEvent ? [
|
|
37275
|
+
"select-event",
|
|
37276
|
+
"select-tickets",
|
|
37277
|
+
"enter-details"
|
|
37278
|
+
] : ["select-tickets", "enter-details"];
|
|
37279
|
+
switch (input.payment) {
|
|
37280
|
+
case "none": return base;
|
|
37281
|
+
case "options": return [...base, "select-payment"];
|
|
37282
|
+
case "optionsAndPayment": return [
|
|
37283
|
+
...base,
|
|
37284
|
+
"select-payment",
|
|
37285
|
+
"payment"
|
|
37286
|
+
];
|
|
37287
|
+
}
|
|
37288
|
+
}
|
|
37289
|
+
const REGISTRATION_STEP_LABELS = [
|
|
37290
|
+
"Event",
|
|
37291
|
+
"Date",
|
|
37292
|
+
"Tickets",
|
|
37293
|
+
"Places",
|
|
37294
|
+
"Your details",
|
|
37295
|
+
"How you’ll pay",
|
|
37296
|
+
"Payment"
|
|
37297
|
+
];
|
|
37298
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
37299
|
+
function getEventSelectionMode(events) {
|
|
37300
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
37301
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
37302
|
+
}
|
|
37303
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
37304
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
37305
|
+
return {
|
|
37306
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
37307
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
37308
|
+
};
|
|
37309
|
+
}
|
|
37310
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
37311
|
+
function registrationStepLabel(step, context) {
|
|
37312
|
+
switch (step) {
|
|
37313
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
37314
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
37315
|
+
case "enter-details": return "Your details";
|
|
37316
|
+
case "select-payment": return "How you’ll pay";
|
|
37317
|
+
case "payment": return "Payment";
|
|
37318
|
+
}
|
|
37319
|
+
}
|
|
37320
|
+
function bookingButtonText(buttonText) {
|
|
37321
|
+
return buttonText?.trim() || "Book your place";
|
|
37322
|
+
}
|
|
37323
|
+
function placesLabel(event, input, compact) {
|
|
37324
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
37325
|
+
}
|
|
37326
|
+
function isFull(event, mode) {
|
|
37327
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
37328
|
+
full: "full",
|
|
37329
|
+
waitlist: "full"
|
|
37330
|
+
}) === "full";
|
|
37331
|
+
}
|
|
37332
|
+
function priceLabel(event) {
|
|
37333
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
37334
|
+
}
|
|
37335
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
37336
|
+
function lowestPaidAmount(display) {
|
|
37337
|
+
switch (display.kind) {
|
|
37338
|
+
case "exact":
|
|
37339
|
+
case "from": return display.amount;
|
|
37340
|
+
case "range": return display.minAmount;
|
|
37341
|
+
case "mixed": return display.paidFromAmount;
|
|
37342
|
+
case "free":
|
|
37343
|
+
case "unavailable":
|
|
37344
|
+
case "external": return null;
|
|
37345
|
+
}
|
|
37346
|
+
}
|
|
37347
|
+
/**
|
|
37348
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
37349
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
37350
|
+
*/
|
|
37351
|
+
function seriesPriceLabel(events) {
|
|
37352
|
+
const firstEvent = events[0];
|
|
37353
|
+
if (!firstEvent) return null;
|
|
37354
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
37355
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
37356
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
37357
|
+
const lowest = displays.flatMap((display) => {
|
|
37358
|
+
const amount = lowestPaidAmount(display);
|
|
37359
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
37360
|
+
amount,
|
|
37361
|
+
currency: display.currency
|
|
37362
|
+
}];
|
|
37363
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
37364
|
+
return lowest ? formatBookingPriceDisplay({
|
|
37365
|
+
kind: "from",
|
|
37366
|
+
amount: lowest.amount,
|
|
37367
|
+
currency: lowest.currency
|
|
37368
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
37369
|
+
}
|
|
37370
|
+
function dateTile(event) {
|
|
37371
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
37372
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
37373
|
+
return {
|
|
37374
|
+
month: rail.month,
|
|
37375
|
+
day: rail.day
|
|
37376
|
+
};
|
|
37377
|
+
}
|
|
37378
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
37379
|
+
function formatBookingShortDate(event) {
|
|
37380
|
+
return formatBookingWhen(event, "day");
|
|
37381
|
+
}
|
|
37382
|
+
function byStart(left, right) {
|
|
37383
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
37384
|
+
}
|
|
37385
|
+
function singleEntry(event, input) {
|
|
37386
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
37387
|
+
return {
|
|
37388
|
+
kind: "single",
|
|
37389
|
+
title: event.title,
|
|
37390
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
37391
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
37392
|
+
venue: shownVenue(event, input.display),
|
|
37393
|
+
price: priceLabel(event),
|
|
37394
|
+
places: placesLabel(event, input, false),
|
|
37395
|
+
tile: dateTile(event),
|
|
37396
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
37397
|
+
};
|
|
37398
|
+
}
|
|
37399
|
+
function chooseDateEntry(input) {
|
|
37400
|
+
const ordered = [...input.events].sort(byStart);
|
|
37401
|
+
const first = ordered[0];
|
|
37402
|
+
const shown = ordered.slice(0, 4);
|
|
37403
|
+
return {
|
|
37404
|
+
kind: "chooseDate",
|
|
37405
|
+
title: first?.title ?? "",
|
|
37406
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
37407
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
37408
|
+
price: seriesPriceLabel(ordered),
|
|
37409
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
37410
|
+
dateCount: ordered.length,
|
|
37411
|
+
dates: shown.map((event) => ({
|
|
37412
|
+
selectionId: event.selectionId,
|
|
37413
|
+
label: formatBookingShortDate(event),
|
|
37414
|
+
places: placesLabel(event, input, true),
|
|
37415
|
+
full: isFull(event, input.attendanceMode)
|
|
37416
|
+
})),
|
|
37417
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
37418
|
+
action: "Choose a date"
|
|
37419
|
+
};
|
|
37420
|
+
}
|
|
37421
|
+
/** The card before a booking starts; the server renders this too. */
|
|
37422
|
+
function idleBookingEntry(input) {
|
|
37423
|
+
if (input.event) return singleEntry(input.event, input);
|
|
37424
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
37425
|
+
if (only) return singleEntry(only, input);
|
|
37426
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
37427
|
+
return {
|
|
37428
|
+
kind: "chooseEvent",
|
|
37429
|
+
title: input.events[0]?.title ?? "",
|
|
37430
|
+
count: input.events.length,
|
|
37431
|
+
noun: input.noun.pluralLabel,
|
|
37432
|
+
action: "Choose an event"
|
|
37433
|
+
};
|
|
37434
|
+
}
|
|
37435
|
+
//#endregion
|
|
37436
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
37437
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
37438
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
37439
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
37440
|
+
{
|
|
37441
|
+
preset: "class",
|
|
37442
|
+
sourceKey: "eventPreset:class",
|
|
37443
|
+
dataKey: "classEvents",
|
|
37444
|
+
label: "Classes"
|
|
37445
|
+
},
|
|
37446
|
+
{
|
|
37447
|
+
preset: "workshop",
|
|
37448
|
+
sourceKey: "eventPreset:workshop",
|
|
37449
|
+
dataKey: "workshopEvents",
|
|
37450
|
+
label: "Workshops"
|
|
37451
|
+
},
|
|
37452
|
+
{
|
|
37453
|
+
preset: "retreat",
|
|
37454
|
+
sourceKey: "eventPreset:retreat",
|
|
37455
|
+
dataKey: "retreatEvents",
|
|
37456
|
+
label: "Retreats"
|
|
37457
|
+
},
|
|
37458
|
+
{
|
|
37459
|
+
preset: "performance",
|
|
37460
|
+
sourceKey: "eventPreset:performance",
|
|
37461
|
+
dataKey: "performanceEvents",
|
|
37462
|
+
label: "Performances"
|
|
37463
|
+
}
|
|
37464
|
+
];
|
|
37465
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
37466
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
37467
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
37468
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
37469
|
+
kind: "eventPreset",
|
|
37470
|
+
preset: definition.preset
|
|
37471
|
+
}]));
|
|
37472
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
37473
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
37474
|
+
}
|
|
37475
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
37476
|
+
if (value == null) return { kind: "legacy" };
|
|
37477
|
+
if (value.length === 0) return { kind: "default" };
|
|
37478
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
37479
|
+
return keys.length > 0 ? {
|
|
37480
|
+
kind: "custom",
|
|
37481
|
+
keys
|
|
37482
|
+
} : { kind: "default" };
|
|
37483
|
+
}
|
|
37484
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
37485
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
37486
|
+
return keys.length >= 2 ? keys : [];
|
|
37487
|
+
}
|
|
37488
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
37489
|
+
if (!isRecord$3(value)) return null;
|
|
37490
|
+
const groupOrderValue = value.groupOrder;
|
|
37491
|
+
if (Array.isArray(groupOrderValue)) {
|
|
37492
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
37493
|
+
return {
|
|
37494
|
+
...value,
|
|
37495
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
37496
|
+
};
|
|
37497
|
+
}
|
|
37498
|
+
if (groupOrderValue != null) return {
|
|
37499
|
+
...value,
|
|
37500
|
+
groupOrder: []
|
|
37501
|
+
};
|
|
37502
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$3) : []);
|
|
37503
|
+
return legacyOrder.length > 0 ? {
|
|
37504
|
+
...value,
|
|
37505
|
+
groupOrder: legacyOrder
|
|
37506
|
+
} : value;
|
|
37507
|
+
}
|
|
37508
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
37509
|
+
function sourceFromPresetSummary(preset) {
|
|
37510
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
37511
|
+
if (preset.engine !== "event_series") return null;
|
|
37512
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
37513
|
+
kind: "eventPreset",
|
|
37514
|
+
preset: preset.canonicalBehaviour
|
|
37515
|
+
};
|
|
37516
|
+
return null;
|
|
37517
|
+
}
|
|
37518
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
37519
|
+
const keys = [];
|
|
37520
|
+
for (const value of values) {
|
|
37521
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
37522
|
+
if (!keys.includes(value)) keys.push(value);
|
|
37523
|
+
}
|
|
37524
|
+
return keys;
|
|
37525
|
+
}
|
|
37526
|
+
function isRecord$3(value) {
|
|
37527
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37528
|
+
}
|
|
37529
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
37530
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
37531
|
+
}
|
|
37532
|
+
//#endregion
|
|
37533
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
37534
|
+
function offeringKindForEvent(event) {
|
|
37535
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
37536
|
+
}
|
|
37537
|
+
function presetKind(preset) {
|
|
37538
|
+
const source = sourceFromPresetSummary(preset);
|
|
37539
|
+
if (!source) return null;
|
|
37540
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
37541
|
+
}
|
|
37542
|
+
/**
|
|
37543
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
37544
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
37545
|
+
* name stands in when the site has none.
|
|
37546
|
+
*/
|
|
37547
|
+
function offeringNounForEvent(event, presets) {
|
|
37548
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
37549
|
+
const kind = offeringKindForEvent(event);
|
|
37550
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
37551
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
37552
|
+
}
|
|
37553
|
+
function lowerCased(noun) {
|
|
37554
|
+
return {
|
|
37555
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
37556
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
37557
|
+
};
|
|
37558
|
+
}
|
|
37559
|
+
//#endregion
|
|
37560
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
37561
|
+
function toRegistrationEvent(event) {
|
|
37562
|
+
return {
|
|
37563
|
+
...event,
|
|
37564
|
+
selectionId: event.id,
|
|
37565
|
+
registrationSubject: {
|
|
37566
|
+
kind: "occurrence",
|
|
37567
|
+
occurrenceId: event.occurrenceId
|
|
37568
|
+
}
|
|
37569
|
+
};
|
|
37570
|
+
}
|
|
37571
|
+
function toRegistrationEvents(events) {
|
|
37572
|
+
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
37573
|
+
}
|
|
37574
|
+
/**
|
|
37575
|
+
* Project one whole-series run onto the registration surface.
|
|
37576
|
+
*
|
|
37577
|
+
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
37578
|
+
* Event record; only the schedule is widened from the single occurrence to the
|
|
37579
|
+
* live run. A run without live sessions has no registration event.
|
|
37580
|
+
*/
|
|
37581
|
+
function toWholeSeriesRegistrationEvent(group) {
|
|
37582
|
+
const { representative, run } = group;
|
|
37583
|
+
const sessions = orderedLiveRunSessions(run.sessions);
|
|
37584
|
+
const firstSession = sessions[0];
|
|
37585
|
+
if (!firstSession) return null;
|
|
37586
|
+
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
37587
|
+
return {
|
|
37588
|
+
...representative,
|
|
37589
|
+
selectionId: run.eventSeriesId,
|
|
37590
|
+
registrationSubject: {
|
|
37591
|
+
kind: "wholeSeries",
|
|
37592
|
+
eventSeriesId: run.eventSeriesId,
|
|
37593
|
+
sessions
|
|
37594
|
+
},
|
|
37595
|
+
startsAt: firstSession.startsAt,
|
|
37596
|
+
endsAt: lastSession.endsAt,
|
|
37597
|
+
timeZone: firstSession.timeZone
|
|
37598
|
+
};
|
|
37599
|
+
}
|
|
37600
|
+
function toWholeSeriesRegistrationEvents(events) {
|
|
37601
|
+
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
37602
|
+
}
|
|
37603
|
+
//#endregion
|
|
37604
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
37605
|
+
/**
|
|
37606
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
37607
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
37608
|
+
* so the server and the client agree on one card.
|
|
37609
|
+
*/
|
|
37610
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
37611
|
+
const tileSchema = z.object({
|
|
37612
|
+
month: z.string(),
|
|
37613
|
+
day: z.string()
|
|
37614
|
+
}).nullable();
|
|
37615
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
37616
|
+
z.object({
|
|
37617
|
+
kind: z.literal("single"),
|
|
37618
|
+
title: z.string(),
|
|
37619
|
+
when: z.string().nullable(),
|
|
37620
|
+
shortWhen: z.string().nullable(),
|
|
37621
|
+
venue: z.string().nullable(),
|
|
37622
|
+
price: z.string().nullable(),
|
|
37623
|
+
places: z.string().nullable(),
|
|
37624
|
+
tile: tileSchema,
|
|
37625
|
+
action: z.string()
|
|
37626
|
+
}),
|
|
37627
|
+
z.object({
|
|
37628
|
+
kind: z.literal("chooseDate"),
|
|
37629
|
+
title: z.string(),
|
|
37630
|
+
schedule: z.string(),
|
|
37631
|
+
venue: z.string().nullable(),
|
|
37632
|
+
price: z.string().nullable(),
|
|
37633
|
+
nextDate: z.string().nullable(),
|
|
37634
|
+
dateCount: z.number(),
|
|
37635
|
+
dates: z.array(z.object({
|
|
37636
|
+
selectionId: z.string(),
|
|
37637
|
+
label: z.string(),
|
|
37638
|
+
places: z.string().nullable(),
|
|
37639
|
+
full: z.boolean()
|
|
37640
|
+
})),
|
|
37641
|
+
moreCount: z.number(),
|
|
37642
|
+
action: z.string()
|
|
37643
|
+
}),
|
|
37644
|
+
z.object({
|
|
37645
|
+
kind: z.literal("chooseEvent"),
|
|
37646
|
+
title: z.string(),
|
|
37647
|
+
count: z.number(),
|
|
37648
|
+
noun: z.string(),
|
|
37649
|
+
action: z.string()
|
|
37650
|
+
})
|
|
37651
|
+
]);
|
|
37652
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
37653
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
37654
|
+
}
|
|
37655
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
37656
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37657
|
+
return {
|
|
37658
|
+
scopedEvents,
|
|
37659
|
+
preSelected: findPreSelectedEvent({
|
|
37660
|
+
scopedEvents,
|
|
37661
|
+
occurrenceContext: source.occurrenceContext
|
|
37662
|
+
})
|
|
37663
|
+
};
|
|
37664
|
+
}
|
|
37665
|
+
function nounFor(scoped, presets) {
|
|
37666
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
37667
|
+
}
|
|
37668
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
37669
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
37670
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
37671
|
+
}
|
|
37672
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
37673
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
37674
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
37675
|
+
return idleBookingEntry({
|
|
37676
|
+
events: scoped.scopedEvents,
|
|
37677
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
37678
|
+
display,
|
|
37679
|
+
buttonText: source.buttonText,
|
|
37680
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
37681
|
+
attendanceMode: null
|
|
37682
|
+
});
|
|
37683
|
+
}
|
|
37684
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
37685
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
37686
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
37687
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
37688
|
+
if (!entry) return null;
|
|
37689
|
+
return {
|
|
37690
|
+
kind: "event-registration",
|
|
37691
|
+
state: "booking-card",
|
|
37692
|
+
className: source.className ?? null,
|
|
37693
|
+
entry,
|
|
37694
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
37695
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
37696
|
+
};
|
|
37697
|
+
}
|
|
37698
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
37699
|
+
kind: z.literal("unsupported"),
|
|
37700
|
+
reason: z.enum([
|
|
37701
|
+
"unsupportedSubject",
|
|
37702
|
+
"invalidEventSeriesId",
|
|
37703
|
+
"invalidEventSeriesBookingScope",
|
|
37704
|
+
"invalidEventOfferingId",
|
|
37705
|
+
"invalidEventOfferingBookingScope",
|
|
37706
|
+
"invalidEventOfferingCatalogue"
|
|
37707
|
+
])
|
|
37708
|
+
});
|
|
37709
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
37710
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
37711
|
+
if (unsupported.success) return unsupported.data;
|
|
37712
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
37713
|
+
if (parsed.ok) return parsed.value;
|
|
37714
|
+
ctx.addIssue({
|
|
37715
|
+
code: z.ZodIssueCode.custom,
|
|
37716
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
37717
|
+
});
|
|
37718
|
+
return z.NEVER;
|
|
37719
|
+
});
|
|
37720
|
+
function resolveEventRegistrationScope(context) {
|
|
37721
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
37722
|
+
if (occurrenceSeriesId) return {
|
|
37723
|
+
kind: "occurrenceSeries",
|
|
37724
|
+
seriesId: occurrenceSeriesId
|
|
37725
|
+
};
|
|
37726
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
37727
|
+
kind: "pageSurfaceSeries",
|
|
37728
|
+
seriesId: context.subject.eventSeriesId
|
|
37729
|
+
};
|
|
37730
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
37731
|
+
kind: "pageSurfaceOffering",
|
|
37732
|
+
offeringId: context.subject.eventOfferingId,
|
|
37733
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
37734
|
+
};
|
|
37735
|
+
if (context.subject?.kind === "unsupported") return {
|
|
37736
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
37737
|
+
reason: context.subject.reason
|
|
37738
|
+
};
|
|
37739
|
+
return { kind: "unscoped" };
|
|
37740
|
+
}
|
|
37741
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
37742
|
+
const scope = resolveEventRegistrationScope(context);
|
|
37743
|
+
switch (scope.kind) {
|
|
37744
|
+
case "occurrenceSeries":
|
|
37745
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
37746
|
+
case "pageSurfaceOffering": {
|
|
37747
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
37748
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
37749
|
+
}
|
|
37750
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
37751
|
+
case "unscoped": return [...events];
|
|
37752
|
+
}
|
|
37753
|
+
}
|
|
37754
|
+
//#endregion
|
|
36551
37755
|
//#region ../blocks/src/system/constants/events.ts
|
|
36552
37756
|
const eventCalendarDisplayModeValues = [
|
|
36553
37757
|
"combined",
|
|
@@ -36670,95 +37874,6 @@ const calendarTabViewsSchema = z.enum([
|
|
|
36670
37874
|
"week"
|
|
36671
37875
|
]);
|
|
36672
37876
|
//#endregion
|
|
36673
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
36674
|
-
/**
|
|
36675
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
36676
|
-
*
|
|
36677
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
36678
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
36679
|
-
* @returns Array of wizard steps to display
|
|
36680
|
-
*/
|
|
36681
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
36682
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
36683
|
-
"select-event",
|
|
36684
|
-
"select-tickets",
|
|
36685
|
-
"enter-details"
|
|
36686
|
-
];
|
|
36687
|
-
if (!needsPaymentStep) return baseSteps;
|
|
36688
|
-
return paymentActive ? [
|
|
36689
|
-
...baseSteps,
|
|
36690
|
-
"select-payment",
|
|
36691
|
-
"payment"
|
|
36692
|
-
] : [...baseSteps, "select-payment"];
|
|
36693
|
-
}
|
|
36694
|
-
//#endregion
|
|
36695
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
36696
|
-
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
36697
|
-
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
36698
|
-
}
|
|
36699
|
-
function findPreSelectedEvent(input) {
|
|
36700
|
-
const occurrenceContext = input.occurrenceContext;
|
|
36701
|
-
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
36702
|
-
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
36703
|
-
startsAt: occurrenceContext.startsAt,
|
|
36704
|
-
timeZone: occurrenceContext.timeZone
|
|
36705
|
-
}));
|
|
36706
|
-
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
36707
|
-
startsAt: event.startsAt,
|
|
36708
|
-
timeZone: event.timeZone
|
|
36709
|
-
})) === contextDate) ?? null;
|
|
36710
|
-
}
|
|
36711
|
-
function resolveEventRequiresPayment(input) {
|
|
36712
|
-
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
36713
|
-
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
36714
|
-
if (!input.event) return false;
|
|
36715
|
-
return publicEventPricingType(input.event.pricing) === "paid";
|
|
36716
|
-
}
|
|
36717
|
-
//#endregion
|
|
36718
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
36719
|
-
function toRegistrationEvent(event) {
|
|
36720
|
-
return {
|
|
36721
|
-
...event,
|
|
36722
|
-
selectionId: event.id,
|
|
36723
|
-
registrationSubject: {
|
|
36724
|
-
kind: "occurrence",
|
|
36725
|
-
occurrenceId: event.occurrenceId
|
|
36726
|
-
}
|
|
36727
|
-
};
|
|
36728
|
-
}
|
|
36729
|
-
function toRegistrationEvents(events) {
|
|
36730
|
-
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
36731
|
-
}
|
|
36732
|
-
/**
|
|
36733
|
-
* Project one whole-series run onto the registration surface.
|
|
36734
|
-
*
|
|
36735
|
-
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
36736
|
-
* Event record; only the schedule is widened from the single occurrence to the
|
|
36737
|
-
* live run. A run without live sessions has no registration event.
|
|
36738
|
-
*/
|
|
36739
|
-
function toWholeSeriesRegistrationEvent(group) {
|
|
36740
|
-
const { representative, run } = group;
|
|
36741
|
-
const sessions = orderedLiveRunSessions(run.sessions);
|
|
36742
|
-
const firstSession = sessions[0];
|
|
36743
|
-
if (!firstSession) return null;
|
|
36744
|
-
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
36745
|
-
return {
|
|
36746
|
-
...representative,
|
|
36747
|
-
selectionId: run.eventSeriesId,
|
|
36748
|
-
registrationSubject: {
|
|
36749
|
-
kind: "wholeSeries",
|
|
36750
|
-
eventSeriesId: run.eventSeriesId,
|
|
36751
|
-
sessions
|
|
36752
|
-
},
|
|
36753
|
-
startsAt: firstSession.startsAt,
|
|
36754
|
-
endsAt: lastSession.endsAt,
|
|
36755
|
-
timeZone: firstSession.timeZone
|
|
36756
|
-
};
|
|
36757
|
-
}
|
|
36758
|
-
function toWholeSeriesRegistrationEvents(events) {
|
|
36759
|
-
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
36760
|
-
}
|
|
36761
|
-
//#endregion
|
|
36762
37877
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
36763
37878
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
36764
37879
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -36801,27 +37916,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
36801
37916
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
36802
37917
|
"Date",
|
|
36803
37918
|
"Tickets",
|
|
36804
|
-
"
|
|
36805
|
-
];
|
|
36806
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
36807
|
-
"Event",
|
|
36808
|
-
"Date",
|
|
36809
|
-
"Tickets",
|
|
36810
|
-
"Details",
|
|
36811
|
-
"Payment options",
|
|
36812
|
-
"Payment"
|
|
37919
|
+
"Your details"
|
|
36813
37920
|
];
|
|
36814
37921
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
36815
|
-
const
|
|
37922
|
+
const eventRegistrationCommonSchemaShape = {
|
|
36816
37923
|
demoEmailSuppressed: z.boolean().optional(),
|
|
36817
37924
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
36818
37925
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
36819
37926
|
maxTickets: z.string().optional(),
|
|
36820
|
-
showVenue: z.boolean().optional(),
|
|
36821
|
-
showCapacity: z.boolean().optional(),
|
|
36822
37927
|
successMessage: z.string().optional(),
|
|
36823
37928
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
36824
|
-
|
|
37929
|
+
host: bookingHostSchema.optional(),
|
|
36825
37930
|
spamProtectionEnabled: z.boolean().optional(),
|
|
36826
37931
|
supportEmail: z.string().optional(),
|
|
36827
37932
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -36846,32 +37951,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
36846
37951
|
portalToken: z.string().nullable().optional(),
|
|
36847
37952
|
previewToken: z.string().nullable().optional(),
|
|
36848
37953
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36849
|
-
...
|
|
37954
|
+
...eventRegistrationCommonSchemaShape,
|
|
37955
|
+
showVenue: z.boolean().optional(),
|
|
37956
|
+
showCapacity: z.boolean().optional(),
|
|
36850
37957
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36851
37958
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36852
37959
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
36853
37960
|
className: z.string().nullable().optional(),
|
|
36854
37961
|
buttonText: z.string().nullable().optional(),
|
|
36855
37962
|
maxTickets: z.string().nullable().optional(),
|
|
36856
|
-
stage: previewStageSchema.optional()
|
|
37963
|
+
stage: previewStageSchema.optional(),
|
|
37964
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
36857
37965
|
});
|
|
36858
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
36859
|
-
|
|
36860
|
-
|
|
36861
|
-
|
|
36862
|
-
|
|
36863
|
-
|
|
36864
|
-
|
|
36865
|
-
|
|
36866
|
-
|
|
36867
|
-
|
|
36868
|
-
|
|
36869
|
-
|
|
36870
|
-
|
|
36871
|
-
|
|
36872
|
-
|
|
37966
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
37967
|
+
z.object({
|
|
37968
|
+
kind: z.literal("event-registration"),
|
|
37969
|
+
state: z.literal("generic-shell"),
|
|
37970
|
+
className: z.string().nullable(),
|
|
37971
|
+
titleText: z.string(),
|
|
37972
|
+
bodyText: z.string(),
|
|
37973
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
37974
|
+
summaryButtonText: z.string()
|
|
37975
|
+
}),
|
|
37976
|
+
z.object({
|
|
37977
|
+
kind: z.literal("event-registration"),
|
|
37978
|
+
state: z.literal("registration-closed"),
|
|
37979
|
+
className: z.string().nullable(),
|
|
37980
|
+
titleText: z.string(),
|
|
37981
|
+
bodyText: z.string()
|
|
37982
|
+
}),
|
|
37983
|
+
z.object({
|
|
37984
|
+
kind: z.literal("event-registration"),
|
|
37985
|
+
state: z.literal("booking-card"),
|
|
37986
|
+
className: z.string().nullable(),
|
|
37987
|
+
entry: idleBookingEntrySchema,
|
|
37988
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
37989
|
+
buttonText: z.string()
|
|
37990
|
+
})
|
|
37991
|
+
]);
|
|
36873
37992
|
const eventRegistrationHydrationSchema = z.object({
|
|
36874
|
-
...
|
|
37993
|
+
...eventRegistrationCommonSchemaShape,
|
|
37994
|
+
display: registrationDisplaySchema,
|
|
37995
|
+
offeringNoun: z.object({
|
|
37996
|
+
label: z.string(),
|
|
37997
|
+
pluralLabel: z.string()
|
|
37998
|
+
}).optional(),
|
|
36875
37999
|
eventSource: eventRegistrationEventSourceSchema
|
|
36876
38000
|
});
|
|
36877
38001
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -36886,7 +38010,7 @@ z.object({
|
|
|
36886
38010
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36887
38011
|
stage: previewStageSchema.optional()
|
|
36888
38012
|
});
|
|
36889
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
38013
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
36890
38014
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
36891
38015
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
36892
38016
|
kind: "event-registration",
|
|
@@ -36895,6 +38019,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
36895
38019
|
titleText: "Registration closed",
|
|
36896
38020
|
bodyText: "This run is no longer open for bookings."
|
|
36897
38021
|
};
|
|
38022
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
38023
|
+
if (card) return card;
|
|
36898
38024
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
36899
38025
|
return {
|
|
36900
38026
|
kind: "event-registration",
|
|
@@ -36911,11 +38037,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36911
38037
|
if (selectedRun) {
|
|
36912
38038
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
36913
38039
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
36914
|
-
return
|
|
36915
|
-
|
|
36916
|
-
|
|
36917
|
-
|
|
36918
|
-
|
|
38040
|
+
return shellStepLabels(registrationRoute({
|
|
38041
|
+
chooseEvent: false,
|
|
38042
|
+
payment: resolveEventRequiresPayment({
|
|
38043
|
+
eligibility: null,
|
|
38044
|
+
selectedTicketType: null,
|
|
38045
|
+
event: selectedEvent
|
|
38046
|
+
}) ? "optionsAndPayment" : "none"
|
|
38047
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
36919
38048
|
}
|
|
36920
38049
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
36921
38050
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -36924,14 +38053,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36924
38053
|
occurrenceContext: source.occurrenceContext
|
|
36925
38054
|
});
|
|
36926
38055
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
36927
|
-
|
|
38056
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
36928
38057
|
eligibility: null,
|
|
36929
38058
|
selectedTicketType: null,
|
|
36930
38059
|
event: preSelectedEvent
|
|
36931
|
-
}) : false
|
|
36932
|
-
|
|
36933
|
-
|
|
36934
|
-
|
|
38060
|
+
}) : false;
|
|
38061
|
+
return shellStepLabels(registrationRoute({
|
|
38062
|
+
chooseEvent: !hasPreSelectedContext,
|
|
38063
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
38064
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
36935
38065
|
}
|
|
36936
38066
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
36937
38067
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -36947,29 +38077,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
36947
38077
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
36948
38078
|
return runs.length === 1 ? runs[0] : null;
|
|
36949
38079
|
}
|
|
36950
|
-
function
|
|
36951
|
-
|
|
36952
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
36953
|
-
case "select-tickets": return "Tickets";
|
|
36954
|
-
case "enter-details": return "Details";
|
|
36955
|
-
case "select-payment": return "Payment options";
|
|
36956
|
-
case "payment": return "Payment";
|
|
36957
|
-
case "error":
|
|
36958
|
-
case "success":
|
|
36959
|
-
case "submitting":
|
|
36960
|
-
case "verifying-payment":
|
|
36961
|
-
case "verifying-timeout":
|
|
36962
|
-
case "payment-status":
|
|
36963
|
-
case "payment-failed": return "Details";
|
|
36964
|
-
}
|
|
36965
|
-
}
|
|
36966
|
-
function isDateSelection(events) {
|
|
36967
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
36968
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
38080
|
+
function shellStepLabels(route, context) {
|
|
38081
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
36969
38082
|
}
|
|
36970
38083
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
36971
|
-
if (stepLabels.includes("
|
|
36972
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
38084
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
38085
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
36973
38086
|
return "Preparing dates, tickets, and booking details.";
|
|
36974
38087
|
}
|
|
36975
38088
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -36979,6 +38092,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36979
38092
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
36980
38093
|
},
|
|
36981
38094
|
buildRender: (source) => {
|
|
38095
|
+
const display = resolveRegistrationDisplay(source);
|
|
36982
38096
|
const eventSource = resolveEventRegistrationEventSource({
|
|
36983
38097
|
events: source.events,
|
|
36984
38098
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -36986,7 +38100,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36986
38100
|
});
|
|
36987
38101
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
36988
38102
|
return {
|
|
36989
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
38103
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
36990
38104
|
hydration: {
|
|
36991
38105
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
36992
38106
|
subject: source.subject ?? null,
|
|
@@ -36996,29 +38110,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36996
38110
|
} : eventSource,
|
|
36997
38111
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
36998
38112
|
maxTickets: source.maxTickets ?? void 0,
|
|
36999
|
-
|
|
37000
|
-
showCapacity: source.showCapacity,
|
|
38113
|
+
display,
|
|
37001
38114
|
successMessage: source.successMessage,
|
|
37002
38115
|
buttonVariant: source.buttonVariant,
|
|
37003
|
-
|
|
38116
|
+
host: source.host ?? "overlay",
|
|
37004
38117
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
37005
38118
|
supportEmail: source.supportEmail,
|
|
37006
38119
|
sitePasses: source.sitePasses ?? null,
|
|
37007
38120
|
siteMemberships: source.siteMemberships ?? null,
|
|
37008
38121
|
mailingList: source.mailingList,
|
|
37009
|
-
siteName: source.siteName
|
|
38122
|
+
siteName: source.siteName,
|
|
38123
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
37010
38124
|
}
|
|
37011
38125
|
};
|
|
37012
38126
|
}
|
|
37013
38127
|
});
|
|
37014
38128
|
function normalizeEventRegistrationEventInput(value) {
|
|
37015
|
-
if (!isRecord$
|
|
38129
|
+
if (!isRecord$2(value)) return value;
|
|
37016
38130
|
return {
|
|
37017
38131
|
...value,
|
|
37018
38132
|
destination: resolveRuntimeEventDestination(value)
|
|
37019
38133
|
};
|
|
37020
38134
|
}
|
|
37021
|
-
function isRecord$
|
|
38135
|
+
function isRecord$2(value) {
|
|
37022
38136
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37023
38137
|
}
|
|
37024
38138
|
const eventRegistrationBlockDefinition = {
|
|
@@ -37058,7 +38172,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
37058
38172
|
description: "Main heading for the registration form",
|
|
37059
38173
|
required: false,
|
|
37060
38174
|
multiline: false,
|
|
37061
|
-
defaultValue: "
|
|
38175
|
+
defaultValue: ""
|
|
37062
38176
|
},
|
|
37063
38177
|
{
|
|
37064
38178
|
id: "description",
|
|
@@ -37130,11 +38244,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
37130
38244
|
{
|
|
37131
38245
|
id: "buttonText",
|
|
37132
38246
|
type: "text",
|
|
37133
|
-
label: "
|
|
37134
|
-
description: "Text
|
|
38247
|
+
label: "Button text",
|
|
38248
|
+
description: "Text on the booking button",
|
|
37135
38249
|
required: false,
|
|
37136
38250
|
multiline: false,
|
|
37137
|
-
defaultValue: "
|
|
38251
|
+
defaultValue: "Book your place",
|
|
37138
38252
|
maxLength: 40
|
|
37139
38253
|
},
|
|
37140
38254
|
createButtonVariantField()
|
|
@@ -37166,21 +38280,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
37166
38280
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
37167
38281
|
buttonText: { $bind: {
|
|
37168
38282
|
from: "content.buttonText",
|
|
37169
|
-
fallback: "
|
|
38283
|
+
fallback: "Book your place"
|
|
37170
38284
|
} },
|
|
37171
38285
|
buttonVariant: { $bind: {
|
|
37172
38286
|
from: "content.buttonVariant",
|
|
37173
38287
|
fallback: "primary"
|
|
37174
38288
|
} },
|
|
37175
|
-
overlayEnabled: { $bind: {
|
|
37176
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
37177
|
-
fallback: false
|
|
37178
|
-
} },
|
|
37179
38289
|
events: { $bind: { from: "data.events" } },
|
|
37180
38290
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
37181
38291
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
37182
38292
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
37183
38293
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
38294
|
+
bookingOfferingPresets: { $bind: {
|
|
38295
|
+
from: "$root.bookingOfferingPresets",
|
|
38296
|
+
fallback: []
|
|
38297
|
+
} },
|
|
37184
38298
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
37185
38299
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
37186
38300
|
stage: { $bind: {
|
|
@@ -39841,7 +40955,21 @@ const eventCalendarBlockDefinition = {
|
|
|
39841
40955
|
list: { label: "List" }
|
|
39842
40956
|
}
|
|
39843
40957
|
}, eventCalendarContentShape),
|
|
39844
|
-
|
|
40958
|
+
contentNormalizer: {
|
|
40959
|
+
fieldIds: [
|
|
40960
|
+
"variant",
|
|
40961
|
+
"displayMode",
|
|
40962
|
+
"listLayout",
|
|
40963
|
+
"defaultCalendarView",
|
|
40964
|
+
"eventSurface",
|
|
40965
|
+
"filterEventPresets",
|
|
40966
|
+
"scheduleScope",
|
|
40967
|
+
"filterCategoryIds",
|
|
40968
|
+
"filterStaffMemberId",
|
|
40969
|
+
"filterVenueId"
|
|
40970
|
+
],
|
|
40971
|
+
normalize: normalizeEventCalendarContent
|
|
40972
|
+
},
|
|
39845
40973
|
dataSchemas: {
|
|
39846
40974
|
events: publicEventsArraySchema.optional(),
|
|
39847
40975
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -40090,90 +41218,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
40090
41218
|
} }
|
|
40091
41219
|
};
|
|
40092
41220
|
//#endregion
|
|
40093
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
40094
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
40095
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
40096
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
40097
|
-
{
|
|
40098
|
-
preset: "class",
|
|
40099
|
-
sourceKey: "eventPreset:class",
|
|
40100
|
-
dataKey: "classEvents",
|
|
40101
|
-
label: "Classes"
|
|
40102
|
-
},
|
|
40103
|
-
{
|
|
40104
|
-
preset: "workshop",
|
|
40105
|
-
sourceKey: "eventPreset:workshop",
|
|
40106
|
-
dataKey: "workshopEvents",
|
|
40107
|
-
label: "Workshops"
|
|
40108
|
-
},
|
|
40109
|
-
{
|
|
40110
|
-
preset: "retreat",
|
|
40111
|
-
sourceKey: "eventPreset:retreat",
|
|
40112
|
-
dataKey: "retreatEvents",
|
|
40113
|
-
label: "Retreats"
|
|
40114
|
-
},
|
|
40115
|
-
{
|
|
40116
|
-
preset: "performance",
|
|
40117
|
-
sourceKey: "eventPreset:performance",
|
|
40118
|
-
dataKey: "performanceEvents",
|
|
40119
|
-
label: "Performances"
|
|
40120
|
-
}
|
|
40121
|
-
];
|
|
40122
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
40123
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
40124
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
40125
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
40126
|
-
kind: "eventPreset",
|
|
40127
|
-
preset: definition.preset
|
|
40128
|
-
}]));
|
|
40129
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
40130
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
40131
|
-
}
|
|
40132
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
40133
|
-
if (value == null) return { kind: "legacy" };
|
|
40134
|
-
if (value.length === 0) return { kind: "default" };
|
|
40135
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
40136
|
-
return keys.length > 0 ? {
|
|
40137
|
-
kind: "custom",
|
|
40138
|
-
keys
|
|
40139
|
-
} : { kind: "default" };
|
|
40140
|
-
}
|
|
40141
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
40142
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
40143
|
-
return keys.length >= 2 ? keys : [];
|
|
40144
|
-
}
|
|
40145
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
40146
|
-
if (!isRecord$2(value)) return null;
|
|
40147
|
-
const groupOrderValue = value.groupOrder;
|
|
40148
|
-
if (Array.isArray(groupOrderValue)) {
|
|
40149
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
40150
|
-
return {
|
|
40151
|
-
...value,
|
|
40152
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
40153
|
-
};
|
|
40154
|
-
}
|
|
40155
|
-
if (groupOrderValue != null) return {
|
|
40156
|
-
...value,
|
|
40157
|
-
groupOrder: []
|
|
40158
|
-
};
|
|
40159
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$2) : []);
|
|
40160
|
-
return legacyOrder.length > 0 ? {
|
|
40161
|
-
...value,
|
|
40162
|
-
groupOrder: legacyOrder
|
|
40163
|
-
} : value;
|
|
40164
|
-
}
|
|
40165
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
40166
|
-
const keys = [];
|
|
40167
|
-
for (const value of values) {
|
|
40168
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
40169
|
-
if (!keys.includes(value)) keys.push(value);
|
|
40170
|
-
}
|
|
40171
|
-
return keys;
|
|
40172
|
-
}
|
|
40173
|
-
function isRecord$2(value) {
|
|
40174
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40175
|
-
}
|
|
40176
|
-
//#endregion
|
|
40177
41221
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
40178
41222
|
const groupOverrideFields = [
|
|
40179
41223
|
{
|
|
@@ -40537,7 +41581,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
40537
41581
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
40538
41582
|
const offeringsPreviewBlockDefinition = {
|
|
40539
41583
|
manifest: offeringsPreviewManifest,
|
|
40540
|
-
|
|
41584
|
+
contentNormalizer: {
|
|
41585
|
+
fieldIds: [
|
|
41586
|
+
"displayMode",
|
|
41587
|
+
"heading",
|
|
41588
|
+
"description",
|
|
41589
|
+
"itemLimit",
|
|
41590
|
+
"groupOrder",
|
|
41591
|
+
"groupOverrides",
|
|
41592
|
+
"_cardStyles",
|
|
41593
|
+
"buttonVariant",
|
|
41594
|
+
"buttonText",
|
|
41595
|
+
"emptyMessage",
|
|
41596
|
+
"_sectionStyles"
|
|
41597
|
+
],
|
|
41598
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
41599
|
+
},
|
|
40541
41600
|
dataSchemas: {
|
|
40542
41601
|
...offeringsPreviewEventDataSchemas,
|
|
40543
41602
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -42091,6 +43150,14 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
|
|
|
42091
43150
|
}
|
|
42092
43151
|
}) };
|
|
42093
43152
|
//#endregion
|
|
43153
|
+
//#region ../blocks/src/lib/media.ts
|
|
43154
|
+
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
43155
|
+
"document",
|
|
43156
|
+
"spreadsheet",
|
|
43157
|
+
"archive",
|
|
43158
|
+
"audio"
|
|
43159
|
+
];
|
|
43160
|
+
//#endregion
|
|
42094
43161
|
//#region ../blocks/src/system/blocks/file-download.ts
|
|
42095
43162
|
const bound = (from) => ({ $bind: { from } });
|
|
42096
43163
|
const fileDownloadLayout = styledSection({
|
|
@@ -44135,11 +45202,11 @@ function buildNewsletterDisplay(source) {
|
|
|
44135
45202
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
44136
45203
|
privacyNote: null
|
|
44137
45204
|
};
|
|
44138
|
-
const
|
|
44139
|
-
const choices = resolveRuntimeChoices(
|
|
45205
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
45206
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
44140
45207
|
return {
|
|
44141
45208
|
kind: "newsletter-form",
|
|
44142
|
-
availability:
|
|
45209
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
44143
45210
|
className: source.className ?? null,
|
|
44144
45211
|
buttonLabel: form.buttonLabel,
|
|
44145
45212
|
successMessage: form.successMessage,
|
|
@@ -44196,60 +45263,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
44196
45263
|
default: return assertNever$2(source);
|
|
44197
45264
|
}
|
|
44198
45265
|
}
|
|
44199
|
-
function resolveRuntimeChoices(
|
|
44200
|
-
if (
|
|
44201
|
-
|
|
44202
|
-
|
|
44203
|
-
|
|
44204
|
-
|
|
44205
|
-
id: item.id,
|
|
44206
|
-
label: item.name
|
|
44207
|
-
})) : [];
|
|
44208
|
-
}
|
|
44209
|
-
case "brevo": {
|
|
44210
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
44211
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44212
|
-
id: String(item.id),
|
|
44213
|
-
label: item.name
|
|
44214
|
-
})) : [];
|
|
44215
|
-
}
|
|
44216
|
-
case "mailchimp": {
|
|
44217
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
44218
|
-
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) => ({
|
|
44219
|
-
id: item.id,
|
|
44220
|
-
label: item.name
|
|
44221
|
-
})) ?? [];
|
|
44222
|
-
}
|
|
44223
|
-
}
|
|
44224
|
-
}
|
|
44225
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
44226
|
-
if (context?.tag !== "configured") return false;
|
|
44227
|
-
const provider = context.provider;
|
|
44228
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
44229
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
44230
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
44231
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
44232
|
-
}
|
|
44233
|
-
if (targeting.provider !== provider.provider) return false;
|
|
44234
|
-
switch (targeting.provider) {
|
|
44235
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
44236
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
44237
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
44238
|
-
}
|
|
44239
|
-
}
|
|
44240
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
44241
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
44242
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44243
|
-
}
|
|
44244
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
44245
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
44246
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44247
|
-
}
|
|
44248
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
44249
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
44250
|
-
if (!audience) return false;
|
|
44251
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
44252
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
45266
|
+
function resolveRuntimeChoices(assessment) {
|
|
45267
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
45268
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
45269
|
+
id: String(item.id),
|
|
45270
|
+
label: item.name
|
|
45271
|
+
}));
|
|
44253
45272
|
}
|
|
44254
45273
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
44255
45274
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -44353,6 +45372,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
44353
45372
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
44354
45373
|
const newsletterSignupBlockDefinition = {
|
|
44355
45374
|
manifest: newsletterSignupManifest,
|
|
45375
|
+
contentNormalizer: {
|
|
45376
|
+
fieldIds: ["targeting"],
|
|
45377
|
+
normalize: normalizeMailingListBlockContent
|
|
45378
|
+
},
|
|
44356
45379
|
runtime: newsletterFormBlockRuntime
|
|
44357
45380
|
};
|
|
44358
45381
|
//#endregion
|
|
@@ -44380,7 +45403,7 @@ const memberPhotoClassName = (baseClass) => cardRoleChildClass({
|
|
|
44380
45403
|
baseClass,
|
|
44381
45404
|
stylesFrom: "content._cardStyles"
|
|
44382
45405
|
});
|
|
44383
|
-
const teamMemberPhotoSchema =
|
|
45406
|
+
const teamMemberPhotoSchema = runtimeMediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
|
|
44384
45407
|
const teamMemberDataSchema = z.object({
|
|
44385
45408
|
_type: z.literal("teamMember"),
|
|
44386
45409
|
id: z.string(),
|
|
@@ -45085,7 +46108,20 @@ const locationMapBlockDefinition = {
|
|
|
45085
46108
|
})], { gap: "md" })
|
|
45086
46109
|
})
|
|
45087
46110
|
}),
|
|
45088
|
-
|
|
46111
|
+
contentNormalizer: {
|
|
46112
|
+
fieldIds: [
|
|
46113
|
+
"heading",
|
|
46114
|
+
"locationSource",
|
|
46115
|
+
"venueId",
|
|
46116
|
+
"location",
|
|
46117
|
+
"showAddressText",
|
|
46118
|
+
"showDirections",
|
|
46119
|
+
"directionsLabel",
|
|
46120
|
+
"zoom",
|
|
46121
|
+
"heightPx"
|
|
46122
|
+
],
|
|
46123
|
+
normalize: normalizeLocationMapContent
|
|
46124
|
+
}
|
|
45089
46125
|
};
|
|
45090
46126
|
//#endregion
|
|
45091
46127
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -45909,11 +46945,14 @@ const offeringsPreviewDatesReadEnabled = {
|
|
|
45909
46945
|
//#endregion
|
|
45910
46946
|
//#region ../blocks/src/system/helpers/backgroundMedia.ts
|
|
45911
46947
|
function resolveBackgroundMedia(input) {
|
|
45912
|
-
const parsedMedia =
|
|
46948
|
+
const parsedMedia = runtimeMediaSchema.safeParse(input.image);
|
|
45913
46949
|
if (!parsedMedia.success) return null;
|
|
45914
46950
|
switch (parsedMedia.data.type) {
|
|
45915
46951
|
case "image":
|
|
45916
|
-
case "video": return
|
|
46952
|
+
case "video": return {
|
|
46953
|
+
...parsedMedia.data,
|
|
46954
|
+
type: parsedMedia.data.type
|
|
46955
|
+
};
|
|
45917
46956
|
case "audio":
|
|
45918
46957
|
case "document":
|
|
45919
46958
|
case "spreadsheet":
|
|
@@ -45925,6 +46964,75 @@ function backgroundVideoMobileClassNames(input) {
|
|
|
45925
46964
|
return input.showVideoOnMobile === true ? "" : "rb-hidden rb-md-block";
|
|
45926
46965
|
}
|
|
45927
46966
|
//#endregion
|
|
46967
|
+
//#region ../blocks/src/system/runtime/nodes/mediaContext.ts
|
|
46968
|
+
/**
|
|
46969
|
+
* Server-side: AsyncLocalStorage for request isolation.
|
|
46970
|
+
* Prevents race conditions when multiple requests are processed concurrently.
|
|
46971
|
+
*
|
|
46972
|
+
* Lazy initialization to avoid issues in environments that don't support async_hooks.
|
|
46973
|
+
*/
|
|
46974
|
+
const serverStorageState = {
|
|
46975
|
+
storage: null,
|
|
46976
|
+
checked: false
|
|
46977
|
+
};
|
|
46978
|
+
function getServerStorage() {
|
|
46979
|
+
if (typeof window !== "undefined") return null;
|
|
46980
|
+
if (serverStorageState.checked) return serverStorageState.storage;
|
|
46981
|
+
serverStorageState.checked = true;
|
|
46982
|
+
try {
|
|
46983
|
+
const globalWithNonWebpackRequire = globalThis;
|
|
46984
|
+
const AsyncLocalStorage = (typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)"))("async_hooks").AsyncLocalStorage;
|
|
46985
|
+
if (AsyncLocalStorage) {
|
|
46986
|
+
serverStorageState.storage = new AsyncLocalStorage();
|
|
46987
|
+
return serverStorageState.storage;
|
|
46988
|
+
}
|
|
46989
|
+
return null;
|
|
46990
|
+
} catch {
|
|
46991
|
+
if (process.env.NODE_ENV !== "production") console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
|
|
46992
|
+
return null;
|
|
46993
|
+
}
|
|
46994
|
+
}
|
|
46995
|
+
/**
|
|
46996
|
+
* Client-side context storage.
|
|
46997
|
+
* Safe because browsers are single-threaded per tab.
|
|
46998
|
+
*
|
|
46999
|
+
* IMPORTANT: This must be shared across bundles.
|
|
47000
|
+
* SDK preview mode can load multiple independently-bundled entrypoints
|
|
47001
|
+
* (e.g. `@riverbankcms/sdk/rendering` + `@riverbankcms/sdk/preview-next/client`),
|
|
47002
|
+
* which can otherwise each get their own module-scoped singleton.
|
|
47003
|
+
*/
|
|
47004
|
+
const RB_MEDIA_CONTEXT_KEY = Symbol.for("riverbankcms.blocks.mediaContext");
|
|
47005
|
+
function getClientContextStore() {
|
|
47006
|
+
const g = globalThis;
|
|
47007
|
+
const existing = g[RB_MEDIA_CONTEXT_KEY];
|
|
47008
|
+
if (existing && typeof existing === "object") return existing;
|
|
47009
|
+
const next = {};
|
|
47010
|
+
g[RB_MEDIA_CONTEXT_KEY] = next;
|
|
47011
|
+
return next;
|
|
47012
|
+
}
|
|
47013
|
+
/**
|
|
47014
|
+
* Get the current media context.
|
|
47015
|
+
* Server-side: Uses AsyncLocalStorage for request isolation.
|
|
47016
|
+
* Client-side: Uses module-level state (safe in single-threaded browser).
|
|
47017
|
+
*/
|
|
47018
|
+
function getMediaContext() {
|
|
47019
|
+
const storage = getServerStorage();
|
|
47020
|
+
if (storage) return storage.getStore() ?? {};
|
|
47021
|
+
return getClientContextStore();
|
|
47022
|
+
}
|
|
47023
|
+
function getCurrentResolveImageUrlContext() {
|
|
47024
|
+
const context = getMediaContext();
|
|
47025
|
+
if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) return;
|
|
47026
|
+
return {
|
|
47027
|
+
supabaseUrl: context.supabaseUrl,
|
|
47028
|
+
siteId: context.siteId,
|
|
47029
|
+
mediaAssetIndex: context.mediaAssetIndex
|
|
47030
|
+
};
|
|
47031
|
+
}
|
|
47032
|
+
function getMediaAssetIndex(context) {
|
|
47033
|
+
return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
|
|
47034
|
+
}
|
|
47035
|
+
//#endregion
|
|
45928
47036
|
//#region ../blocks/src/system/runtime/nodes/media.tsx
|
|
45929
47037
|
function getValidSourceDimension(value) {
|
|
45930
47038
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -45960,41 +47068,72 @@ function applyRectTransform(existingStyle, patch) {
|
|
|
45960
47068
|
if (patch.transform) next.transform = appendTransform(existingStyle?.transform, patch.transform);
|
|
45961
47069
|
return next;
|
|
45962
47070
|
}
|
|
45963
|
-
|
|
47071
|
+
/** Resolve portable content without exposing runtime metadata as saved values. */
|
|
47072
|
+
function resolveMediaWithContext(reference, context) {
|
|
47073
|
+
return resolveManagedMediaReference(reference, getMediaAssetIndex(context ?? void 0));
|
|
47074
|
+
}
|
|
47075
|
+
function sourceFromAsset(value, asset) {
|
|
47076
|
+
return {
|
|
47077
|
+
type: value.type,
|
|
47078
|
+
alt: value.alt,
|
|
47079
|
+
filename: value.filename,
|
|
47080
|
+
purpose: value.purpose,
|
|
47081
|
+
placeholder: value.placeholder,
|
|
47082
|
+
transform: value.transform,
|
|
47083
|
+
poster: value.poster,
|
|
47084
|
+
identifier: asset.identifier,
|
|
47085
|
+
assetId: asset.id,
|
|
47086
|
+
storageBucket: asset.storageBucket,
|
|
47087
|
+
storagePath: asset.storagePath,
|
|
47088
|
+
mimeType: asset.mimeType,
|
|
47089
|
+
width: asset.width,
|
|
47090
|
+
height: asset.height
|
|
47091
|
+
};
|
|
47092
|
+
}
|
|
47093
|
+
function resolveRuntimeMedia(value, context) {
|
|
47094
|
+
if ("asset" in value && value.asset) return sourceFromAsset(value, value.asset);
|
|
47095
|
+
if ("src" in value && value.src) return value;
|
|
47096
|
+
if (!value.identifier) return void 0;
|
|
47097
|
+
const resolved = resolveMediaWithContext(value, context);
|
|
47098
|
+
return resolved.kind === "resolved" ? sourceFromAsset(resolved.reference, resolved.asset) : void 0;
|
|
47099
|
+
}
|
|
47100
|
+
function usesProxyFraming(source, transform) {
|
|
47101
|
+
if (!source?.assetId || !isExplicitCropProxyEnabled()) return false;
|
|
47102
|
+
return Boolean(transform.rotation) || isExplicitRectCrop(transform.rect, getValidSourceDimension(source.width), getValidSourceDimension(source.height));
|
|
47103
|
+
}
|
|
47104
|
+
function rectFramingPatch(source, rect, proxy, style) {
|
|
47105
|
+
if (!source || !rect || proxy) return {};
|
|
47106
|
+
const patch = buildCssRectStylePatch(source, rect);
|
|
47107
|
+
return patch ? applyRectTransform(style, patch) : {};
|
|
47108
|
+
}
|
|
47109
|
+
function hotspotFramingPatch(transform, proxy, rectPatch, style) {
|
|
47110
|
+
if (!transform.hotspot || rectPatch.objectPosition !== void 0) return {};
|
|
47111
|
+
const fit = style?.objectFit;
|
|
47112
|
+
if (fit && fit !== "cover" && fit !== "contain") return {};
|
|
47113
|
+
const point = proxy && transform.rotation ? rotateNormalizedPoint(transform.hotspot, transform.rotation) : transform.hotspot;
|
|
47114
|
+
return { objectPosition: `${point.x * 100}% ${point.y * 100}%` };
|
|
47115
|
+
}
|
|
47116
|
+
function rotationFramingPatch(rotation, proxy, rectPatch, style) {
|
|
47117
|
+
if (!rotation || proxy) return {};
|
|
47118
|
+
return {
|
|
47119
|
+
transform: appendTransform(rectPatch.transform ?? style?.transform, `rotate(${rotation}deg)`),
|
|
47120
|
+
transformOrigin: rectPatch.transformOrigin ?? "center"
|
|
47121
|
+
};
|
|
47122
|
+
}
|
|
47123
|
+
/** CSS framing is a pure projection of the resolved source and per-use transform. */
|
|
47124
|
+
function deriveMediaFramingStyle(source, transform, proxy, style) {
|
|
47125
|
+
if (!transform.rect && !transform.hotspot && !transform.rotation) return style;
|
|
47126
|
+
const rectPatch = rectFramingPatch(source, transform.rect, proxy, style);
|
|
47127
|
+
return mergeStyles(style, {
|
|
47128
|
+
...rectPatch,
|
|
47129
|
+
...hotspotFramingPatch(transform, proxy, rectPatch, style),
|
|
47130
|
+
...rotationFramingPatch(transform.rotation, proxy, rectPatch, style)
|
|
47131
|
+
});
|
|
47132
|
+
}
|
|
47133
|
+
function computeMediaTransformStyle(value, style, targetAspectRatio, options, context) {
|
|
47134
|
+
const source = resolveRuntimeMedia(value, context ?? getCurrentResolveImageUrlContext());
|
|
45964
47135
|
const transform = options?.resolvedTransform ?? resolveMediaTransformForAspect(value.transform, targetAspectRatio);
|
|
45965
|
-
|
|
45966
|
-
const hotspot = transform.hotspot;
|
|
45967
|
-
const rotation = transform.rotation;
|
|
45968
|
-
if (!rect && !hotspot && !rotation) return style;
|
|
45969
|
-
const stylePatch = {};
|
|
45970
|
-
const heuristicSuppressCss = Boolean(isExplicitCropProxyEnabled() && value.assetId && (typeof rotation === "number" && rotation !== 0 || isExplicitRectCrop(rect, getValidSourceDimension(value.width), getValidSourceDimension(value.height))));
|
|
45971
|
-
const shouldSuppressCss = options?.isProxy ?? heuristicSuppressCss;
|
|
45972
|
-
if (rect && !shouldSuppressCss) {
|
|
45973
|
-
const rectPatch = buildCssRectStylePatch(value, rect);
|
|
45974
|
-
if (rectPatch) {
|
|
45975
|
-
const mergedRect = applyRectTransform(style, rectPatch);
|
|
45976
|
-
Object.assign(stylePatch, mergedRect);
|
|
45977
|
-
}
|
|
45978
|
-
}
|
|
45979
|
-
if (hotspot) {
|
|
45980
|
-
const effectiveObjectFit = stylePatch.objectFit ?? style?.objectFit;
|
|
45981
|
-
if ((!effectiveObjectFit || effectiveObjectFit === "cover" || effectiveObjectFit === "contain") && stylePatch.objectPosition === void 0) {
|
|
45982
|
-
const resolved = shouldSuppressCss && rotation ? rotateNormalizedPoint({
|
|
45983
|
-
x: hotspot.x,
|
|
45984
|
-
y: hotspot.y
|
|
45985
|
-
}, rotation) : {
|
|
45986
|
-
x: hotspot.x,
|
|
45987
|
-
y: hotspot.y
|
|
45988
|
-
};
|
|
45989
|
-
stylePatch.objectPosition = `${resolved.x * 100}% ${resolved.y * 100}%`;
|
|
45990
|
-
}
|
|
45991
|
-
}
|
|
45992
|
-
if (rotation && !shouldSuppressCss) {
|
|
45993
|
-
const existingTransform = stylePatch.transform ?? style?.transform;
|
|
45994
|
-
stylePatch.transform = existingTransform ? `${existingTransform} rotate(${rotation}deg)` : `rotate(${rotation}deg)`;
|
|
45995
|
-
if (!stylePatch.transformOrigin) stylePatch.transformOrigin = "center";
|
|
45996
|
-
}
|
|
45997
|
-
return mergeStyles(style, stylePatch);
|
|
47136
|
+
return deriveMediaFramingStyle(source, transform, options?.isProxy ?? usesProxyFraming(source, transform), style);
|
|
45998
47137
|
}
|
|
45999
47138
|
//#endregion
|
|
46000
47139
|
//#region ../blocks/src/system/transforms/registry/background.ts
|
|
@@ -46143,11 +47282,11 @@ const backgroundTransforms = [
|
|
|
46143
47282
|
}
|
|
46144
47283
|
];
|
|
46145
47284
|
function parseMediaBackground(value) {
|
|
46146
|
-
const background =
|
|
47285
|
+
const background = parseRuntimeBackgroundContent(value);
|
|
46147
47286
|
return background?.type === "image" || background?.type === "video" ? background : null;
|
|
46148
47287
|
}
|
|
46149
47288
|
function resolveBackgroundLayerStyle(value, fallbackToken, context) {
|
|
46150
|
-
const background =
|
|
47289
|
+
const background = parseRuntimeBackgroundContent(value);
|
|
46151
47290
|
const style = {};
|
|
46152
47291
|
const gradient = background?.type === "gradient" ? isString(background.gradient) ? background.gradient.trim() : gradientPresetCss(background.gradientPresetId) : null;
|
|
46153
47292
|
const color = background?.type === "color" && isString(background.color) ? background.color.trim() : null;
|
|
@@ -46290,17 +47429,7 @@ const linksTransforms = [{
|
|
|
46290
47429
|
id: "links.resolve",
|
|
46291
47430
|
kind: "formatter",
|
|
46292
47431
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
46293
|
-
run: (value, _options, context) =>
|
|
46294
|
-
if (!value || typeof value !== "object") return null;
|
|
46295
|
-
const link = value;
|
|
46296
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
46297
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
46298
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
46299
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
46300
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
46301
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
46302
|
-
return null;
|
|
46303
|
-
}
|
|
47432
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
46304
47433
|
}, {
|
|
46305
47434
|
id: "links.label",
|
|
46306
47435
|
kind: "formatter",
|
|
@@ -46327,6 +47456,21 @@ const linksTransforms = [{
|
|
|
46327
47456
|
return null;
|
|
46328
47457
|
}
|
|
46329
47458
|
}];
|
|
47459
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
47460
|
+
if (!value || typeof value !== "object") return null;
|
|
47461
|
+
const link = value;
|
|
47462
|
+
switch (link.kind) {
|
|
47463
|
+
case "internal": return resolveInternalLink(link, context);
|
|
47464
|
+
case "page": return resolvePageLink(link, context);
|
|
47465
|
+
case "entry": return resolveEntryLink(link, context);
|
|
47466
|
+
case "external":
|
|
47467
|
+
case "url": return resolveExternalLink(link);
|
|
47468
|
+
default: return resolvePreResolvedLink(link);
|
|
47469
|
+
}
|
|
47470
|
+
}
|
|
47471
|
+
function resolvePreResolvedLink(link) {
|
|
47472
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
47473
|
+
}
|
|
46330
47474
|
const eventCalendarSelectionParam = {
|
|
46331
47475
|
id: "events.calendarSelectionParam",
|
|
46332
47476
|
kind: "formatter",
|