@riverbankcms/sdk 0.151.0 → 0.152.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 +37 -0
- package/dist/{EventEmbeddedCheckoutStep-BBHbM22D.mjs → EventEmbeddedCheckoutStep-DVQXWFm6.mjs} +10 -9
- package/dist/{PreviewEditorSidebar-BHplI9HE.mjs → PreviewEditorSidebar-Dr4NJi3Q.mjs} +4 -3
- package/dist/{PreviewEditorUI-DuyN8nsD.mjs → PreviewEditorUI-DSZXQbyh.mjs} +5 -4
- package/dist/{SdkPreviewModeRuntime-CR5ypwxJ.mjs → SdkPreviewModeRuntime-Dl4GyMc3.mjs} +124 -53
- package/dist/{SiteChromeCustomizeContext-D5t6joF_.mjs → SiteChromeCustomizeContext-DgBe-FlM.mjs} +20418 -32298
- package/dist/ThemedButton-B8ViBnLK.mjs +16350 -0
- 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/endpoints.d.ts +7 -0
- package/dist/_dts/api/src/index.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/siteAssets.d.ts +1 -0
- package/dist/_dts/blocks/src/definitions.d.ts +1 -1
- package/dist/_dts/blocks/src/index.d.ts +1 -0
- package/dist/_dts/blocks/src/pageRenderPreparation.d.ts +1 -0
- package/dist/_dts/blocks/src/pageRendererContracts.d.ts +1 -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/shared/schemas.d.ts +16 -0
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +5 -0
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +2 -0
- package/dist/_dts/blocks/src/system/helpers/normalizeMailingListBlockContent.d.ts +2 -0
- 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/useBookingSubmission.state.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +3 -1
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +23 -0
- 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-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/MonthLookView.d.ts +10 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +16 -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 +1 -0
- package/dist/_dts/blocks/src/system/transforms/registry/links.d.ts +3 -1
- 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/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-targeting-availability.d.ts +68 -0
- package/dist/_dts/core/src/mailing-list-targeting.d.ts +2 -0
- package/dist/_dts/core/src/ticket-quantity.d.ts +13 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +51 -32
- 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/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/fileStorage.d.ts +4 -3
- package/dist/_dts/media-core/src/index.d.ts +1 -0
- package/dist/_dts/media-core/src/storageObjectKey.d.ts +12 -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/preview/previewModeRootAttribute.d.ts +11 -0
- package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +0 -1
- package/dist/_dts/sdk/src/rendering/image.d.ts +10 -0
- package/dist/_dts/sdk/src/rendering/index.d.ts +3 -1
- package/dist/_dts/sdk/src/rendering/link.d.ts +9 -0
- 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/blocks/opaquePanels.d.ts +3 -3
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/client/BookingMailingListNote-CBuMKN0w.mjs +386 -0
- package/dist/client/{CardListItem-ZDLYh6dL.mjs → CardListItem-Dc9XTXhB.mjs} +3 -4
- package/dist/client/CheckIcon-CpyXr-Kg.mjs +35 -0
- package/dist/client/{CheckboxChoice-M-3HycLw.mjs → CheckboxChoice-CIqx_o0E.mjs} +1 -1
- package/dist/client/{DemoBookingPortalAccess-BMtvPTWE.mjs → DemoBookingPortalAccess-D3VQ_kLj.mjs} +85 -85
- package/dist/client/{EventCombined.client-DUm_DOxW.mjs → EventCombined.client-BHGEKise.mjs} +8 -9
- package/dist/client/{EventEmbeddedCheckoutStep-DsNNzgRm.mjs → EventEmbeddedCheckoutStep-Bo1Cm23R.mjs} +11 -10
- package/dist/client/{EventListing.client-DjNYGUVm.mjs → EventListing.client-D5OQgVPr.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-DuFiOHq_.mjs → LeafletStaticMap-CLL5cWrr.mjs} +1 -1
- package/dist/client/{ModalShell-CqkBvBIC.mjs → ModalShell-BXzucfR6.mjs} +83 -12
- package/dist/client/{RichText-LjPCUGGi.mjs → RichText-BoDmnopf.mjs} +6 -3
- package/dist/client/{ThemedButton-DZKjtaDD.mjs → ThemedButton-Ciltp0IK.mjs} +2 -2
- package/dist/client/{accordion-Qe--SILD.mjs → accordion-DOkRS64-.mjs} +1 -1
- package/dist/client/aspectTransforms-D-TnDdq4.mjs +93 -0
- package/dist/client/{bookingForm-3BCl4g_f.mjs → bookingForm-wlMVwo9h.mjs} +289 -149
- package/dist/client/bookings.mjs +12212 -10832
- package/dist/client/{carousel-h2YjKOS2.mjs → carousel-CGWk-Z0u.mjs} +2 -2
- package/dist/client/{carousel.client-BLrd4hmY.mjs → carousel.client-kX5mN1Eg.mjs} +46 -41
- package/dist/client/{cart-5NeiigVd.mjs → cart-OBBPlaH4.mjs} +3 -3
- package/dist/client/{checkout-G4UWjOEw.mjs → checkout-Bmw2WjQX.mjs} +3 -3
- package/dist/client/client.mjs +9541 -6039
- package/dist/client/{colorStyles-DTunOThj.mjs → colorStyles-ECDNPE_P.mjs} +23 -86
- package/dist/client/{context-GK4-AVAh.mjs → context-BI77UFAn.mjs} +275 -10
- package/dist/client/{eventCalendar-Prw3Yo_L.mjs → eventCalendar-qkej2Edn.mjs} +19 -17
- package/dist/client/{eventCombined-BUugi6__.mjs → eventCombined-DApKHvat.mjs} +4 -4
- package/dist/client/{eventDetails-CBHUda-R.mjs → eventDetails-BQyUDPH0.mjs} +3 -4
- package/dist/client/{eventListing-CQeG45Dg.mjs → eventListing-CeAnshlZ.mjs} +4 -4
- package/dist/client/{eventRegistration-Dif3p3oJ.mjs → eventRegistration-C3A3NyBO.mjs} +2209 -2144
- package/dist/client/{form-Cf0WMtfG.mjs → form-DW8rU7jO.mjs} +6 -6
- package/dist/client/{headerSection-Bqdr3JWp.mjs → headerSection-CkIhsoNm.mjs} +9 -9
- package/dist/client/hooks.mjs +1289 -380
- package/dist/client/{locationMap-BVvPou4O.mjs → locationMap-D4O8wbli.mjs} +4 -4
- package/dist/client/{media-47fcnhzD.mjs → media-C5K_0xPd.mjs} +2 -2
- package/dist/client/{newsletterForm-Cx-1dnic.mjs → newsletterForm-B7IxSPuz.mjs} +5 -5
- package/dist/client/{productDetail-DaUMaJYk.mjs → productDetail-Bqxpwy5N.mjs} +3 -3
- package/dist/client/{productList-BKQlWEKE.mjs → productList-u9Lz8V15.mjs} +3 -3
- package/dist/client/{propsDecoder-DO5iXphQ.mjs → propsDecoder-Bf1jucUp.mjs} +17333 -14489
- package/dist/client/rendering/client.mjs +58216 -55133
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +9099 -5636
- package/dist/client/{routeIslandApiConfig-BNm0Z3-g.mjs → routeIslandApiConfig-BgP-aPMl.mjs} +1 -1
- package/dist/client/{shop-D7ytcFBC.mjs → shop-B_eykR-_.mjs} +16 -14
- package/dist/client/{shop-commerce-D68-hHy2.mjs → shop-commerce-CT0APkFV.mjs} +9 -9
- package/dist/client/{shop-commerce-store-Cu7X2lyu.mjs → shop-commerce-store-DcvZxdEK.mjs} +1 -1
- package/dist/client/{shopShared-D12rxE69.mjs → shopShared-BVJOiUiJ.mjs} +5 -5
- package/dist/client/themePortalRoot-DS92SRVZ.mjs +47 -0
- package/dist/client/{TerminalPanel-DOTSUCO0.mjs → useDiscountCodeUi-DPmYDunz.mjs} +60 -77
- package/dist/client/{useEventPagination-jgKa67KV.mjs → useEventPagination-8-U55vH5.mjs} +7 -8
- package/dist/preview-next/before-render.mjs +7 -0
- 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-C5jPdSrk.mjs} +1 -1
- package/dist/server/components.mjs +3138 -1373
- package/dist/server/config-validation.mjs +1395 -486
- package/dist/server/config.mjs +1395 -486
- package/dist/server/data.mjs +1289 -380
- package/dist/server/index.mjs +8 -1
- package/dist/server/next.mjs +3362 -1538
- package/dist/server/page-converter.mjs +1357 -453
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +2335 -1044
- package/dist/server/rendering.mjs +3152 -1370
- package/dist/server/routing.mjs +1437 -490
- package/dist/server/server.mjs +1297 -381
- package/dist/server/theme-bridge.mjs +1135 -795
- package/dist/{spinner-tSdG9YvG.mjs → spinner-B-ab2rJp.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/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
|
@@ -16166,6 +16166,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
16166
16166
|
default: return assertNever$1(pricing);
|
|
16167
16167
|
}
|
|
16168
16168
|
}
|
|
16169
|
+
/**
|
|
16170
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
16171
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
16172
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
16173
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
16174
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
16175
|
+
*/
|
|
16176
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
16177
|
+
switch (display.kind) {
|
|
16178
|
+
case "free": return "Free";
|
|
16179
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
16180
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
16181
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
16182
|
+
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)}`;
|
|
16183
|
+
case "unavailable": return "Pricing unavailable";
|
|
16184
|
+
case "external": return display.label;
|
|
16185
|
+
default: return assertNever$1(display);
|
|
16186
|
+
}
|
|
16187
|
+
}
|
|
16188
|
+
/** Render an event's price directly from its pricing value. */
|
|
16189
|
+
function formatEventPricing(pricing, options = {}) {
|
|
16190
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
16191
|
+
}
|
|
16169
16192
|
//#endregion
|
|
16170
16193
|
//#region ../core/src/event-page-surface-subject.ts
|
|
16171
16194
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -16309,6 +16332,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
16309
16332
|
}
|
|
16310
16333
|
//#endregion
|
|
16311
16334
|
//#region ../core/src/booking-date-time.ts
|
|
16335
|
+
const DEFAULT_LOCALE = "en-US";
|
|
16312
16336
|
const FALLBACK_TIMEZONE = "UTC";
|
|
16313
16337
|
const START_OF_DAY = {
|
|
16314
16338
|
hour: 0,
|
|
@@ -16431,6 +16455,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
16431
16455
|
if (result.ok) return result.value;
|
|
16432
16456
|
throw new Error(formatParseError(result));
|
|
16433
16457
|
}
|
|
16458
|
+
function formatBookingInstant(isoString, options) {
|
|
16459
|
+
const date = new Date(isoString);
|
|
16460
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
16461
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
16462
|
+
}
|
|
16463
|
+
function formatBookingDate(input, format = {
|
|
16464
|
+
weekday: "long",
|
|
16465
|
+
year: "numeric",
|
|
16466
|
+
month: "long",
|
|
16467
|
+
day: "numeric"
|
|
16468
|
+
}) {
|
|
16469
|
+
return formatBookingInstant(input.startsAt, {
|
|
16470
|
+
locale: input.locale,
|
|
16471
|
+
timeZone: input.timeZone,
|
|
16472
|
+
format
|
|
16473
|
+
});
|
|
16474
|
+
}
|
|
16475
|
+
function formatBookingTime(input, format = {
|
|
16476
|
+
hour: "numeric",
|
|
16477
|
+
minute: "2-digit",
|
|
16478
|
+
hour12: true
|
|
16479
|
+
}) {
|
|
16480
|
+
return formatBookingInstant(input.startsAt, {
|
|
16481
|
+
locale: input.locale,
|
|
16482
|
+
timeZone: input.timeZone,
|
|
16483
|
+
format
|
|
16484
|
+
});
|
|
16485
|
+
}
|
|
16434
16486
|
function getBookingLocalDateKey(input) {
|
|
16435
16487
|
return formatDateKey$1(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
16436
16488
|
}
|
|
@@ -16644,6 +16696,14 @@ function formError(field) {
|
|
|
16644
16696
|
}
|
|
16645
16697
|
//#endregion
|
|
16646
16698
|
//#region ../core/src/mailing-list-targeting.ts
|
|
16699
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
16700
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
16701
|
+
switch (targeting.provider) {
|
|
16702
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
16703
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
16704
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
16705
|
+
}
|
|
16706
|
+
}
|
|
16647
16707
|
function planMailingListChoicePresentation(targeting) {
|
|
16648
16708
|
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
16649
16709
|
switch (targeting.provider) {
|
|
@@ -16683,6 +16743,103 @@ function planMailingListChoicePresentation(targeting) {
|
|
|
16683
16743
|
}
|
|
16684
16744
|
}
|
|
16685
16745
|
//#endregion
|
|
16746
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
16747
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
16748
|
+
switch (provider.provider) {
|
|
16749
|
+
case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
|
|
16750
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
16751
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
16752
|
+
}
|
|
16753
|
+
}
|
|
16754
|
+
function assessMailingListTargeting(context, targeting) {
|
|
16755
|
+
if (context?.tag !== "configured") return {
|
|
16756
|
+
tag: "unavailable",
|
|
16757
|
+
reason: "setup_missing",
|
|
16758
|
+
targeting
|
|
16759
|
+
};
|
|
16760
|
+
const catalog = context.provider;
|
|
16761
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
16762
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
16763
|
+
return destination === null ? {
|
|
16764
|
+
tag: "unavailable",
|
|
16765
|
+
reason: "default_missing",
|
|
16766
|
+
targeting
|
|
16767
|
+
} : {
|
|
16768
|
+
tag: "available",
|
|
16769
|
+
value: {
|
|
16770
|
+
mode: "default",
|
|
16771
|
+
targeting,
|
|
16772
|
+
provider: catalog.provider,
|
|
16773
|
+
destination
|
|
16774
|
+
}
|
|
16775
|
+
};
|
|
16776
|
+
}
|
|
16777
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
16778
|
+
switch (targeting.provider) {
|
|
16779
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
16780
|
+
provider: "native",
|
|
16781
|
+
catalog,
|
|
16782
|
+
targeting
|
|
16783
|
+
}, catalog.topics) : {
|
|
16784
|
+
tag: "unavailable",
|
|
16785
|
+
reason: "provider_mismatch",
|
|
16786
|
+
targeting
|
|
16787
|
+
};
|
|
16788
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
16789
|
+
provider: "brevo",
|
|
16790
|
+
catalog,
|
|
16791
|
+
targeting
|
|
16792
|
+
}, catalog.lists) : {
|
|
16793
|
+
tag: "unavailable",
|
|
16794
|
+
reason: "provider_mismatch",
|
|
16795
|
+
targeting
|
|
16796
|
+
};
|
|
16797
|
+
case "mailchimp": {
|
|
16798
|
+
if (catalog.provider !== "mailchimp") return {
|
|
16799
|
+
tag: "unavailable",
|
|
16800
|
+
reason: "provider_mismatch",
|
|
16801
|
+
targeting
|
|
16802
|
+
};
|
|
16803
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
16804
|
+
return audience === void 0 ? {
|
|
16805
|
+
tag: "unavailable",
|
|
16806
|
+
reason: "audience_missing",
|
|
16807
|
+
value: {
|
|
16808
|
+
mode: "custom",
|
|
16809
|
+
provider: "mailchimp",
|
|
16810
|
+
catalog,
|
|
16811
|
+
targeting
|
|
16812
|
+
}
|
|
16813
|
+
} : assessMatchedChoices({
|
|
16814
|
+
provider: "mailchimp",
|
|
16815
|
+
catalog,
|
|
16816
|
+
targeting,
|
|
16817
|
+
audience
|
|
16818
|
+
}, audience.interests);
|
|
16819
|
+
}
|
|
16820
|
+
}
|
|
16821
|
+
}
|
|
16822
|
+
function assessMatchedChoices(matched, choices) {
|
|
16823
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
16824
|
+
const available = new Set(choices.map((item) => item.id));
|
|
16825
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
16826
|
+
const value = {
|
|
16827
|
+
mode: "custom",
|
|
16828
|
+
...matched,
|
|
16829
|
+
choices,
|
|
16830
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
16831
|
+
};
|
|
16832
|
+
return missingIds.length > 0 ? {
|
|
16833
|
+
tag: "unavailable",
|
|
16834
|
+
reason: "choices_missing",
|
|
16835
|
+
missingIds,
|
|
16836
|
+
value
|
|
16837
|
+
} : {
|
|
16838
|
+
tag: "available",
|
|
16839
|
+
value
|
|
16840
|
+
};
|
|
16841
|
+
}
|
|
16842
|
+
//#endregion
|
|
16686
16843
|
//#region ../core/src/mailing-list-runtime.ts
|
|
16687
16844
|
function parseMailingListRuntimeContext(value) {
|
|
16688
16845
|
if (!isRecord$6(value)) return invalidRuntimeContext();
|
|
@@ -16747,57 +16904,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
16747
16904
|
function parseMailchimpRuntimeProvider(value) {
|
|
16748
16905
|
if (!Array.isArray(value.audiences)) return null;
|
|
16749
16906
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
for (const audience of value.audiences) {
|
|
16753
|
-
if (!isRecord$6(audience)) return null;
|
|
16754
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
16755
|
-
const name = parseName(audience.name);
|
|
16756
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
16757
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
16758
|
-
if (interests === null) return null;
|
|
16759
|
-
audiences.push({
|
|
16760
|
-
id,
|
|
16761
|
-
name,
|
|
16762
|
-
interests
|
|
16763
|
-
});
|
|
16764
|
-
}
|
|
16765
|
-
return {
|
|
16907
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
16908
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
16766
16909
|
provider: "mailchimp",
|
|
16767
16910
|
defaultAudienceId,
|
|
16768
16911
|
audiences
|
|
16769
|
-
};
|
|
16912
|
+
} : null;
|
|
16770
16913
|
}
|
|
16771
|
-
function
|
|
16772
|
-
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
interests
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16783
|
-
|
|
16784
|
-
|
|
16785
|
-
|
|
16914
|
+
function parseMailchimpAudience(value) {
|
|
16915
|
+
if (!isRecord$6(value) || !Array.isArray(value.interests)) return null;
|
|
16916
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
16917
|
+
const name = parseName(value.name);
|
|
16918
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
16919
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
16920
|
+
id,
|
|
16921
|
+
name,
|
|
16922
|
+
interests
|
|
16923
|
+
} : null;
|
|
16924
|
+
}
|
|
16925
|
+
function parseMailchimpInterest(value) {
|
|
16926
|
+
if (!isRecord$6(value)) return null;
|
|
16927
|
+
const id = parseMailchimpInterestId(value.id);
|
|
16928
|
+
const name = parseName(value.name);
|
|
16929
|
+
const categoryName = parseName(value.categoryName);
|
|
16930
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
16931
|
+
id,
|
|
16932
|
+
name,
|
|
16933
|
+
categoryName
|
|
16934
|
+
} : null;
|
|
16786
16935
|
}
|
|
16787
16936
|
function parseNamedItems(value, parseId) {
|
|
16788
16937
|
if (!Array.isArray(value)) return null;
|
|
16789
|
-
const items =
|
|
16790
|
-
for (const item of value) {
|
|
16938
|
+
const items = Array.from(value, (item) => {
|
|
16791
16939
|
if (!isRecord$6(item)) return null;
|
|
16792
16940
|
const id = parseId(item.id);
|
|
16793
16941
|
const name = parseName(item.name);
|
|
16794
|
-
|
|
16795
|
-
items.push({
|
|
16942
|
+
return id !== null && name !== null ? {
|
|
16796
16943
|
id,
|
|
16797
16944
|
name
|
|
16798
|
-
}
|
|
16799
|
-
}
|
|
16800
|
-
return items;
|
|
16945
|
+
} : null;
|
|
16946
|
+
});
|
|
16947
|
+
return items.every((item) => item !== null) ? items : null;
|
|
16801
16948
|
}
|
|
16802
16949
|
function parseName(value) {
|
|
16803
16950
|
if (typeof value !== "string") return null;
|
|
@@ -16813,6 +16960,7 @@ function invalidRuntimeContext() {
|
|
|
16813
16960
|
//#endregion
|
|
16814
16961
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
16815
16962
|
function parseMailingListPlacementTargeting(value) {
|
|
16963
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
16816
16964
|
if (!isRecord$5(value)) return targetingError("shape");
|
|
16817
16965
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
16818
16966
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -16911,14 +17059,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
16911
17059
|
}
|
|
16912
17060
|
function parseUniqueIds(value, parseId) {
|
|
16913
17061
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
16914
|
-
|
|
16915
|
-
|
|
17062
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
17063
|
+
if (!parsed.ok) return parsed;
|
|
16916
17064
|
const id = parseId(item);
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
parsed.push(id);
|
|
16920
|
-
}
|
|
16921
|
-
return ok(parsed);
|
|
17065
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
17066
|
+
}, ok([]));
|
|
16922
17067
|
}
|
|
16923
17068
|
function isRecord$5(value) {
|
|
16924
17069
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -16967,6 +17112,45 @@ const SURFACE_EVENT_PRESET_VALUES = [
|
|
|
16967
17112
|
"performance"
|
|
16968
17113
|
];
|
|
16969
17114
|
//#endregion
|
|
17115
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
17116
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
17117
|
+
event: {
|
|
17118
|
+
label: "Event",
|
|
17119
|
+
pluralLabel: "Events",
|
|
17120
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
17121
|
+
},
|
|
17122
|
+
class: {
|
|
17123
|
+
label: "Class",
|
|
17124
|
+
pluralLabel: "Classes",
|
|
17125
|
+
description: "Regular scheduled classes and group sessions."
|
|
17126
|
+
},
|
|
17127
|
+
course: {
|
|
17128
|
+
label: "Course",
|
|
17129
|
+
pluralLabel: "Courses",
|
|
17130
|
+
description: "A fixed set of dates that people book together."
|
|
17131
|
+
},
|
|
17132
|
+
term: {
|
|
17133
|
+
label: "Term",
|
|
17134
|
+
pluralLabel: "Terms",
|
|
17135
|
+
description: "A fixed term of sessions that people book together."
|
|
17136
|
+
},
|
|
17137
|
+
workshop: {
|
|
17138
|
+
label: "Workshop",
|
|
17139
|
+
pluralLabel: "Workshops",
|
|
17140
|
+
description: "One-off workshops, day sessions, or special events."
|
|
17141
|
+
},
|
|
17142
|
+
retreat: {
|
|
17143
|
+
label: "Retreat",
|
|
17144
|
+
pluralLabel: "Retreats",
|
|
17145
|
+
description: "Multi-day or residential immersive experiences."
|
|
17146
|
+
},
|
|
17147
|
+
performance: {
|
|
17148
|
+
label: "Performance",
|
|
17149
|
+
pluralLabel: "Performances",
|
|
17150
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
17151
|
+
}
|
|
17152
|
+
};
|
|
17153
|
+
//#endregion
|
|
16970
17154
|
//#region ../media-core/src/aspectTransforms.ts
|
|
16971
17155
|
function parseAspectRatioValue(value) {
|
|
16972
17156
|
if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -24210,6 +24394,15 @@ const formBlockDefinition = {
|
|
|
24210
24394
|
runtime: formBlockRuntime
|
|
24211
24395
|
};
|
|
24212
24396
|
//#endregion
|
|
24397
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
24398
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
24399
|
+
function normalizeMailingListBlockContent(record) {
|
|
24400
|
+
return record.targeting == null ? {
|
|
24401
|
+
...record,
|
|
24402
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
24403
|
+
} : record;
|
|
24404
|
+
}
|
|
24405
|
+
//#endregion
|
|
24213
24406
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
24214
24407
|
const contactNewsletterLayout = styledSection({
|
|
24215
24408
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -24373,6 +24566,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
24373
24566
|
],
|
|
24374
24567
|
icon: "MailPlus"
|
|
24375
24568
|
}),
|
|
24569
|
+
contentNormalizer: {
|
|
24570
|
+
fieldIds: ["targeting"],
|
|
24571
|
+
normalize: normalizeMailingListBlockContent
|
|
24572
|
+
},
|
|
24376
24573
|
dataSchemas: { form: formDataSchema.optional() },
|
|
24377
24574
|
dataLoaders: { form: {
|
|
24378
24575
|
endpoint: "getPublicFormById",
|
|
@@ -27518,6 +27715,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
27518
27715
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
27519
27716
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
27520
27717
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
27718
|
+
z.strictObject({
|
|
27719
|
+
currency: z.string().trim().length(3),
|
|
27720
|
+
totalCents: nonNegativeIntegerSchema,
|
|
27721
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
27722
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
27723
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
27724
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
27725
|
+
});
|
|
27521
27726
|
//#endregion
|
|
27522
27727
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
27523
27728
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -27758,6 +27963,10 @@ const publicEventBaseSchema = z.object({
|
|
|
27758
27963
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
27759
27964
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
27760
27965
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
27966
|
+
scheduleSummary: z.object({
|
|
27967
|
+
recurrenceDescription: z.string(),
|
|
27968
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
27969
|
+
}).nullable().optional(),
|
|
27761
27970
|
id: z.string(),
|
|
27762
27971
|
occurrenceId: z.string(),
|
|
27763
27972
|
seriesId: z.string(),
|
|
@@ -28168,67 +28377,266 @@ const occurrenceContextSchema = z.object({
|
|
|
28168
28377
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
28169
28378
|
}).nullable();
|
|
28170
28379
|
//#endregion
|
|
28171
|
-
//#region ../blocks/src/system/runtime/
|
|
28172
|
-
|
|
28173
|
-
|
|
28174
|
-
|
|
28175
|
-
|
|
28176
|
-
|
|
28177
|
-
|
|
28178
|
-
|
|
28179
|
-
|
|
28180
|
-
|
|
28181
|
-
|
|
28182
|
-
|
|
28183
|
-
|
|
28184
|
-
"invalidEventOfferingCatalogue"
|
|
28185
|
-
])
|
|
28186
|
-
});
|
|
28187
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
28188
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
28189
|
-
if (unsupported.success) return unsupported.data;
|
|
28190
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
28191
|
-
if (parsed.ok) return parsed.value;
|
|
28192
|
-
ctx.addIssue({
|
|
28193
|
-
code: z.ZodIssueCode.custom,
|
|
28194
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
28195
|
-
});
|
|
28196
|
-
return z.NEVER;
|
|
28197
|
-
});
|
|
28198
|
-
function resolveEventRegistrationScope(context) {
|
|
28199
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
28200
|
-
if (occurrenceSeriesId) return {
|
|
28201
|
-
kind: "occurrenceSeries",
|
|
28202
|
-
seriesId: occurrenceSeriesId
|
|
28380
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
28381
|
+
/**
|
|
28382
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
28383
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
28384
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
28385
|
+
*
|
|
28386
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
28387
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
28388
|
+
*/
|
|
28389
|
+
function getEventAvailability(event) {
|
|
28390
|
+
if (event.capacity == null) return {
|
|
28391
|
+
available: null,
|
|
28392
|
+
isFull: false
|
|
28203
28393
|
};
|
|
28204
|
-
|
|
28205
|
-
|
|
28206
|
-
|
|
28394
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
28395
|
+
if (available <= 0) return {
|
|
28396
|
+
available: 0,
|
|
28397
|
+
isFull: true
|
|
28207
28398
|
};
|
|
28208
|
-
|
|
28209
|
-
|
|
28210
|
-
|
|
28211
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
28399
|
+
return {
|
|
28400
|
+
available,
|
|
28401
|
+
isFull: false
|
|
28212
28402
|
};
|
|
28213
|
-
|
|
28214
|
-
|
|
28215
|
-
|
|
28403
|
+
}
|
|
28404
|
+
/**
|
|
28405
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
28406
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
28407
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
28408
|
+
*
|
|
28409
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
28410
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
28411
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
28412
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
28413
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
28414
|
+
*/
|
|
28415
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
28416
|
+
if (!attendanceMode) return event;
|
|
28417
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
28418
|
+
}
|
|
28419
|
+
/**
|
|
28420
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
28421
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
28422
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
28423
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
28424
|
+
* `capacity - registeredCount` fallback.
|
|
28425
|
+
*/
|
|
28426
|
+
function canJoinEventWaitlist(event, options) {
|
|
28427
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
28428
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
28429
|
+
}
|
|
28430
|
+
/**
|
|
28431
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
28432
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
28433
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
28434
|
+
* to be stale on a cached page.
|
|
28435
|
+
*
|
|
28436
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
28437
|
+
*
|
|
28438
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
28439
|
+
* 5% floor stops large events staying silent until three remain.
|
|
28440
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
28441
|
+
*/
|
|
28442
|
+
function lowCapacityThreshold(capacity) {
|
|
28443
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
28444
|
+
}
|
|
28445
|
+
function getRemainingPlaces(source) {
|
|
28446
|
+
const { available, isFull } = getEventAvailability(source);
|
|
28447
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
28448
|
+
if (isFull) return {
|
|
28449
|
+
kind: "full",
|
|
28450
|
+
waitlist: canJoinEventWaitlist(source)
|
|
28216
28451
|
};
|
|
28217
|
-
|
|
28452
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
28453
|
+
kind: "low",
|
|
28454
|
+
remaining: available
|
|
28455
|
+
};
|
|
28456
|
+
return { kind: "open" };
|
|
28218
28457
|
}
|
|
28219
|
-
|
|
28220
|
-
|
|
28221
|
-
|
|
28222
|
-
|
|
28223
|
-
|
|
28224
|
-
|
|
28225
|
-
|
|
28226
|
-
|
|
28227
|
-
|
|
28228
|
-
case "
|
|
28229
|
-
case "
|
|
28458
|
+
/**
|
|
28459
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
28460
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
28461
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
28462
|
+
* it in rather than re-deriving the count.
|
|
28463
|
+
*/
|
|
28464
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
28465
|
+
const remaining = getRemainingPlaces(source);
|
|
28466
|
+
switch (remaining.kind) {
|
|
28467
|
+
case "unlimited":
|
|
28468
|
+
case "open": return null;
|
|
28469
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
28470
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
28471
|
+
}
|
|
28472
|
+
}
|
|
28473
|
+
function formatPlacesLeft(count, compact) {
|
|
28474
|
+
if (compact) return `${count} left`;
|
|
28475
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
28476
|
+
}
|
|
28477
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
28478
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
28479
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
28480
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
28481
|
+
}
|
|
28482
|
+
/**
|
|
28483
|
+
* Which capacity figure wins when they disagree.
|
|
28484
|
+
*
|
|
28485
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
28486
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
28487
|
+
* The registration write path admits or refuses per mode
|
|
28488
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
28489
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
28490
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
28491
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
28492
|
+
*
|
|
28493
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
28494
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
28495
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
28496
|
+
* the aggregate, unchanged.
|
|
28497
|
+
*/
|
|
28498
|
+
function findHybridModeRows(event) {
|
|
28499
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
28500
|
+
const rows = event.attendanceModes ?? [];
|
|
28501
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
28502
|
+
const online = rows.find((row) => row.mode === "online");
|
|
28503
|
+
return inPerson && online ? {
|
|
28504
|
+
inPerson,
|
|
28505
|
+
online
|
|
28506
|
+
} : null;
|
|
28507
|
+
}
|
|
28508
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
28509
|
+
function remainingPlacesRank(remaining) {
|
|
28510
|
+
switch (remaining.kind) {
|
|
28511
|
+
case "unlimited": return 4;
|
|
28512
|
+
case "open": return 3;
|
|
28513
|
+
case "low": return 2;
|
|
28514
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
28515
|
+
}
|
|
28516
|
+
}
|
|
28517
|
+
function isMoreOpen(candidate, than) {
|
|
28518
|
+
const rank = remainingPlacesRank(candidate);
|
|
28519
|
+
const otherRank = remainingPlacesRank(than);
|
|
28520
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
28521
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
28522
|
+
}
|
|
28523
|
+
/** True when `candidate` has less room left than `than`. */
|
|
28524
|
+
function isScarcer(candidate, than) {
|
|
28525
|
+
return isMoreOpen(than, candidate);
|
|
28526
|
+
}
|
|
28527
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
28528
|
+
in_person: "In person",
|
|
28529
|
+
online: "Online"
|
|
28530
|
+
};
|
|
28531
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
28532
|
+
const PLACES_AVAILABLE = "Places available";
|
|
28533
|
+
/**
|
|
28534
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
28535
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
28536
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
28537
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
28538
|
+
* promise the registration wizard would otherwise have to break.
|
|
28539
|
+
*
|
|
28540
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
28541
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
28542
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
28543
|
+
* { compact: true } -> "Online: 3 left"
|
|
28544
|
+
*/
|
|
28545
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
28546
|
+
const rows = findHybridModeRows(event);
|
|
28547
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
28548
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
28549
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
28550
|
+
if (inPerson === online) return inPerson;
|
|
28551
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
28552
|
+
return formatBothHybridSides(rows, {
|
|
28553
|
+
inPerson,
|
|
28554
|
+
online
|
|
28555
|
+
});
|
|
28556
|
+
}
|
|
28557
|
+
/**
|
|
28558
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
28559
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
28560
|
+
*/
|
|
28561
|
+
function formatBothHybridSides(rows, labels) {
|
|
28562
|
+
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(" · ");
|
|
28563
|
+
}
|
|
28564
|
+
function namedModePlaces(mode, label) {
|
|
28565
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
28566
|
+
}
|
|
28567
|
+
/**
|
|
28568
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
28569
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
28570
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
28571
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
28572
|
+
* how the event is delivered rather than about its remaining places.
|
|
28573
|
+
*/
|
|
28574
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
28575
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
28576
|
+
const online = getRemainingPlaces(rows.online);
|
|
28577
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
28578
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
28579
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
28580
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
28581
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
28582
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
28583
|
+
}
|
|
28584
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
28585
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
28586
|
+
}
|
|
28587
|
+
function rowFor(rows, mode) {
|
|
28588
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
28589
|
+
}
|
|
28590
|
+
//#endregion
|
|
28591
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
28592
|
+
const registrationDisplaySchema = z.object({
|
|
28593
|
+
venue: z.enum(["shown", "hidden"]),
|
|
28594
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
28595
|
+
});
|
|
28596
|
+
function resolveRegistrationDisplay(source) {
|
|
28597
|
+
return {
|
|
28598
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
28599
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
28600
|
+
};
|
|
28601
|
+
}
|
|
28602
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
28603
|
+
function shownVenue(event, display) {
|
|
28604
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
28605
|
+
}
|
|
28606
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
28607
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
28608
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
28609
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
28610
|
+
return capacityPlacesLabel(source, display, wording);
|
|
28611
|
+
}
|
|
28612
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
28613
|
+
const remaining = getRemainingPlaces(source);
|
|
28614
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
28615
|
+
switch (remaining.kind) {
|
|
28616
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
28617
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
28618
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
28619
|
+
case "open": return wording.open ?? null;
|
|
28620
|
+
default: return assertNever$1(remaining);
|
|
28230
28621
|
}
|
|
28231
28622
|
}
|
|
28623
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
28624
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
28625
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
28626
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
28627
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
28628
|
+
}).join(" · ") || null;
|
|
28629
|
+
}
|
|
28630
|
+
function ticketPlacesLabel(remaining, display) {
|
|
28631
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
28632
|
+
return formatTicketTypeRemaining(remaining);
|
|
28633
|
+
}
|
|
28634
|
+
//#endregion
|
|
28635
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
28636
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
28637
|
+
kind: z.literal("preview"),
|
|
28638
|
+
token: z.string().min(1)
|
|
28639
|
+
}).strict()]);
|
|
28232
28640
|
//#endregion
|
|
28233
28641
|
//#region ../calendar/src/grid.ts
|
|
28234
28642
|
const MONTH_NAMES = [
|
|
@@ -28316,6 +28724,11 @@ function buildCalendarViewport(input) {
|
|
|
28316
28724
|
//#endregion
|
|
28317
28725
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
28318
28726
|
/**
|
|
28727
|
+
* Date and time presentation for events: the single place an event's
|
|
28728
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
28729
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
28730
|
+
*/
|
|
28731
|
+
/**
|
|
28319
28732
|
* The English locale a site's public dates are written in, read from the
|
|
28320
28733
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
28321
28734
|
*
|
|
@@ -28335,6 +28748,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
28335
28748
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
28336
28749
|
return "en-US";
|
|
28337
28750
|
}
|
|
28751
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
28752
|
+
const locale = options?.locale ?? "en-US";
|
|
28753
|
+
const dateTime = toScheduledBookingDateTime({
|
|
28754
|
+
startsAt: isoTimestamp,
|
|
28755
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
28756
|
+
locale
|
|
28757
|
+
});
|
|
28758
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
28759
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
28760
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
28761
|
+
return {
|
|
28762
|
+
weekday,
|
|
28763
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
28764
|
+
month,
|
|
28765
|
+
label: formatBookingDate(dateTime, {
|
|
28766
|
+
weekday: "long",
|
|
28767
|
+
year: "numeric",
|
|
28768
|
+
month: "long",
|
|
28769
|
+
day: "numeric"
|
|
28770
|
+
})
|
|
28771
|
+
};
|
|
28772
|
+
}
|
|
28338
28773
|
//#endregion
|
|
28339
28774
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
28340
28775
|
function isRecord$4(value) {
|
|
@@ -28354,6 +28789,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
28354
28789
|
};
|
|
28355
28790
|
}
|
|
28356
28791
|
//#endregion
|
|
28792
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
28793
|
+
/**
|
|
28794
|
+
* Format an event's price directly from its pricing value (without the full
|
|
28795
|
+
* event). Same output as {@link formatEventPrice}.
|
|
28796
|
+
*/
|
|
28797
|
+
function formatEventPriceDisplay(pricing) {
|
|
28798
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
28799
|
+
}
|
|
28800
|
+
//#endregion
|
|
28357
28801
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
28358
28802
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
28359
28803
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -28388,49 +28832,685 @@ function eventListWindowEvents(events, window) {
|
|
|
28388
28832
|
});
|
|
28389
28833
|
}
|
|
28390
28834
|
//#endregion
|
|
28391
|
-
//#region ../blocks/src/system/
|
|
28392
|
-
|
|
28393
|
-
"
|
|
28394
|
-
"calendar",
|
|
28395
|
-
"list",
|
|
28396
|
-
"timetable",
|
|
28397
|
-
"week-board"
|
|
28398
|
-
];
|
|
28399
|
-
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
28400
|
-
const eventCalendarListLayoutValues = [
|
|
28401
|
-
"stack",
|
|
28402
|
-
"grid",
|
|
28403
|
-
"compact"
|
|
28404
|
-
];
|
|
28405
|
-
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
28406
|
-
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
28407
|
-
const eventCalendarListLayoutOptions = [
|
|
28408
|
-
{
|
|
28409
|
-
id: "stack",
|
|
28410
|
-
label: "Stack"
|
|
28411
|
-
},
|
|
28412
|
-
{
|
|
28413
|
-
id: "grid",
|
|
28414
|
-
label: "Grid"
|
|
28415
|
-
},
|
|
28416
|
-
{
|
|
28417
|
-
id: "compact",
|
|
28418
|
-
label: "Compact"
|
|
28419
|
-
}
|
|
28420
|
-
];
|
|
28421
|
-
function isEventCalendarDisplayMode(value) {
|
|
28422
|
-
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
28835
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
28836
|
+
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
28837
|
+
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
28423
28838
|
}
|
|
28424
|
-
function
|
|
28425
|
-
|
|
28426
|
-
return
|
|
28839
|
+
function findPreSelectedEvent(input) {
|
|
28840
|
+
const occurrenceContext = input.occurrenceContext;
|
|
28841
|
+
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
28842
|
+
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
28843
|
+
startsAt: occurrenceContext.startsAt,
|
|
28844
|
+
timeZone: occurrenceContext.timeZone
|
|
28845
|
+
}));
|
|
28846
|
+
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
28847
|
+
startsAt: event.startsAt,
|
|
28848
|
+
timeZone: event.timeZone
|
|
28849
|
+
})) === contextDate) ?? null;
|
|
28427
28850
|
}
|
|
28428
|
-
|
|
28429
|
-
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
|
|
28433
|
-
|
|
28851
|
+
function resolveEventRequiresPayment(input) {
|
|
28852
|
+
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
28853
|
+
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
28854
|
+
if (!input.event) return false;
|
|
28855
|
+
return publicEventPricingType(input.event.pricing) === "paid";
|
|
28856
|
+
}
|
|
28857
|
+
//#endregion
|
|
28858
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
28859
|
+
/**
|
|
28860
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
28861
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
28862
|
+
* English when the site names no zone.
|
|
28863
|
+
*/
|
|
28864
|
+
function bookingDateLocale(siteTimeZone) {
|
|
28865
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
28866
|
+
}
|
|
28867
|
+
function bookingInstant(startsAt, input) {
|
|
28868
|
+
return toScheduledBookingDateTime({
|
|
28869
|
+
startsAt,
|
|
28870
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
28871
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
28872
|
+
});
|
|
28873
|
+
}
|
|
28874
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
28875
|
+
function bookingClock(startsAt, input) {
|
|
28876
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
28877
|
+
hour: "numeric",
|
|
28878
|
+
minute: "2-digit",
|
|
28879
|
+
hour12: true
|
|
28880
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
28881
|
+
}
|
|
28882
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
28883
|
+
function clockRange(input) {
|
|
28884
|
+
const start = bookingClock(input.startsAt, input);
|
|
28885
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
28886
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
28887
|
+
}
|
|
28888
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
28889
|
+
function formatBookingScheduleSummary(event) {
|
|
28890
|
+
const summary = event.scheduleSummary;
|
|
28891
|
+
if (!summary) return null;
|
|
28892
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
28893
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
28894
|
+
timeZone: "UTC",
|
|
28895
|
+
siteTimeZone: event.siteTimeZone
|
|
28896
|
+
}, "time") : null;
|
|
28897
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
28898
|
+
}
|
|
28899
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
28900
|
+
function formatBookingWhen(input, variant) {
|
|
28901
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
28902
|
+
const day = formatBookingDate(instant, {
|
|
28903
|
+
weekday: "short",
|
|
28904
|
+
day: "numeric",
|
|
28905
|
+
month: "short"
|
|
28906
|
+
});
|
|
28907
|
+
switch (variant) {
|
|
28908
|
+
case "day": return day;
|
|
28909
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
28910
|
+
weekday: "long",
|
|
28911
|
+
day: "numeric",
|
|
28912
|
+
month: "long"
|
|
28913
|
+
});
|
|
28914
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
28915
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
28916
|
+
month: "long",
|
|
28917
|
+
year: "numeric"
|
|
28918
|
+
});
|
|
28919
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
28920
|
+
case "timeRange": return clockRange(input);
|
|
28921
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
28922
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
28923
|
+
}
|
|
28924
|
+
}
|
|
28925
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
28926
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
28927
|
+
return formatBookingWhen({
|
|
28928
|
+
startsAt: isoTimestamp,
|
|
28929
|
+
timeZone: options?.timeZone,
|
|
28930
|
+
siteTimeZone: options?.siteTimeZone
|
|
28931
|
+
}, "short");
|
|
28932
|
+
}
|
|
28933
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
28934
|
+
function occurrenceTitleOverride(occurrence) {
|
|
28935
|
+
const title = occurrence?.overrides?.title;
|
|
28936
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
28937
|
+
}
|
|
28938
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
28939
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
28940
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
28941
|
+
return event && title ? {
|
|
28942
|
+
...event,
|
|
28943
|
+
title
|
|
28944
|
+
} : event;
|
|
28945
|
+
}
|
|
28946
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
28947
|
+
const first = sessions[0];
|
|
28948
|
+
if (!first) return null;
|
|
28949
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
28950
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
28951
|
+
timeZone: first.timeZone,
|
|
28952
|
+
siteTimeZone
|
|
28953
|
+
});
|
|
28954
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
28955
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
28956
|
+
timeZone: last.timeZone,
|
|
28957
|
+
siteTimeZone
|
|
28958
|
+
});
|
|
28959
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
28960
|
+
}
|
|
28961
|
+
/**
|
|
28962
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
28963
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
28964
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
28965
|
+
*/
|
|
28966
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
28967
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
28968
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
28969
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
28970
|
+
}
|
|
28971
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
28972
|
+
function scheduleInput(event, occurrence) {
|
|
28973
|
+
const times = occurrence?.startsAt ? {
|
|
28974
|
+
startsAt: occurrence.startsAt,
|
|
28975
|
+
endsAt: occurrence.endsAt ?? null
|
|
28976
|
+
} : {
|
|
28977
|
+
startsAt: event.startsAt,
|
|
28978
|
+
endsAt: event.endsAt
|
|
28979
|
+
};
|
|
28980
|
+
if (!times.startsAt) return null;
|
|
28981
|
+
return {
|
|
28982
|
+
...times,
|
|
28983
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
28984
|
+
siteTimeZone: event.siteTimeZone
|
|
28985
|
+
};
|
|
28986
|
+
}
|
|
28987
|
+
//#endregion
|
|
28988
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
28989
|
+
function registrationRoute(input) {
|
|
28990
|
+
const base = input.chooseEvent ? [
|
|
28991
|
+
"select-event",
|
|
28992
|
+
"select-tickets",
|
|
28993
|
+
"enter-details"
|
|
28994
|
+
] : ["select-tickets", "enter-details"];
|
|
28995
|
+
switch (input.payment) {
|
|
28996
|
+
case "none": return base;
|
|
28997
|
+
case "options": return [...base, "select-payment"];
|
|
28998
|
+
case "optionsAndPayment": return [
|
|
28999
|
+
...base,
|
|
29000
|
+
"select-payment",
|
|
29001
|
+
"payment"
|
|
29002
|
+
];
|
|
29003
|
+
}
|
|
29004
|
+
}
|
|
29005
|
+
const REGISTRATION_STEP_LABELS = [
|
|
29006
|
+
"Event",
|
|
29007
|
+
"Date",
|
|
29008
|
+
"Tickets",
|
|
29009
|
+
"Places",
|
|
29010
|
+
"Your details",
|
|
29011
|
+
"How you’ll pay",
|
|
29012
|
+
"Payment"
|
|
29013
|
+
];
|
|
29014
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
29015
|
+
function getEventSelectionMode(events) {
|
|
29016
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
29017
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
29018
|
+
}
|
|
29019
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
29020
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
29021
|
+
return {
|
|
29022
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
29023
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
29024
|
+
};
|
|
29025
|
+
}
|
|
29026
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
29027
|
+
function registrationStepLabel(step, context) {
|
|
29028
|
+
switch (step) {
|
|
29029
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
29030
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
29031
|
+
case "enter-details": return "Your details";
|
|
29032
|
+
case "select-payment": return "How you’ll pay";
|
|
29033
|
+
case "payment": return "Payment";
|
|
29034
|
+
}
|
|
29035
|
+
}
|
|
29036
|
+
function bookingButtonText(buttonText) {
|
|
29037
|
+
return buttonText?.trim() || "Book your place";
|
|
29038
|
+
}
|
|
29039
|
+
function placesLabel(event, input, compact) {
|
|
29040
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
29041
|
+
}
|
|
29042
|
+
function isFull(event, mode) {
|
|
29043
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
29044
|
+
full: "full",
|
|
29045
|
+
waitlist: "full"
|
|
29046
|
+
}) === "full";
|
|
29047
|
+
}
|
|
29048
|
+
function priceLabel(event) {
|
|
29049
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
29050
|
+
}
|
|
29051
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
29052
|
+
function lowestPaidAmount(display) {
|
|
29053
|
+
switch (display.kind) {
|
|
29054
|
+
case "exact":
|
|
29055
|
+
case "from": return display.amount;
|
|
29056
|
+
case "range": return display.minAmount;
|
|
29057
|
+
case "mixed": return display.paidFromAmount;
|
|
29058
|
+
case "free":
|
|
29059
|
+
case "unavailable":
|
|
29060
|
+
case "external": return null;
|
|
29061
|
+
}
|
|
29062
|
+
}
|
|
29063
|
+
/**
|
|
29064
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
29065
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
29066
|
+
*/
|
|
29067
|
+
function seriesPriceLabel(events) {
|
|
29068
|
+
const firstEvent = events[0];
|
|
29069
|
+
if (!firstEvent) return null;
|
|
29070
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
29071
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
29072
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
29073
|
+
const lowest = displays.flatMap((display) => {
|
|
29074
|
+
const amount = lowestPaidAmount(display);
|
|
29075
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
29076
|
+
amount,
|
|
29077
|
+
currency: display.currency
|
|
29078
|
+
}];
|
|
29079
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
29080
|
+
return lowest ? formatBookingPriceDisplay({
|
|
29081
|
+
kind: "from",
|
|
29082
|
+
amount: lowest.amount,
|
|
29083
|
+
currency: lowest.currency
|
|
29084
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
29085
|
+
}
|
|
29086
|
+
function dateTile(event) {
|
|
29087
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
29088
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
29089
|
+
return {
|
|
29090
|
+
month: rail.month,
|
|
29091
|
+
day: rail.day
|
|
29092
|
+
};
|
|
29093
|
+
}
|
|
29094
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
29095
|
+
function formatBookingShortDate(event) {
|
|
29096
|
+
return formatBookingWhen(event, "day");
|
|
29097
|
+
}
|
|
29098
|
+
function byStart(left, right) {
|
|
29099
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
29100
|
+
}
|
|
29101
|
+
function singleEntry(event, input) {
|
|
29102
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
29103
|
+
return {
|
|
29104
|
+
kind: "single",
|
|
29105
|
+
title: event.title,
|
|
29106
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
29107
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
29108
|
+
venue: shownVenue(event, input.display),
|
|
29109
|
+
price: priceLabel(event),
|
|
29110
|
+
places: placesLabel(event, input, false),
|
|
29111
|
+
tile: dateTile(event),
|
|
29112
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
29113
|
+
};
|
|
29114
|
+
}
|
|
29115
|
+
function chooseDateEntry(input) {
|
|
29116
|
+
const ordered = [...input.events].sort(byStart);
|
|
29117
|
+
const first = ordered[0];
|
|
29118
|
+
const shown = ordered.slice(0, 4);
|
|
29119
|
+
return {
|
|
29120
|
+
kind: "chooseDate",
|
|
29121
|
+
title: first?.title ?? "",
|
|
29122
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
29123
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
29124
|
+
price: seriesPriceLabel(ordered),
|
|
29125
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
29126
|
+
dateCount: ordered.length,
|
|
29127
|
+
dates: shown.map((event) => ({
|
|
29128
|
+
selectionId: event.selectionId,
|
|
29129
|
+
label: formatBookingShortDate(event),
|
|
29130
|
+
places: placesLabel(event, input, true),
|
|
29131
|
+
full: isFull(event, input.attendanceMode)
|
|
29132
|
+
})),
|
|
29133
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
29134
|
+
action: "Choose a date"
|
|
29135
|
+
};
|
|
29136
|
+
}
|
|
29137
|
+
/** The card before a booking starts; the server renders this too. */
|
|
29138
|
+
function idleBookingEntry(input) {
|
|
29139
|
+
if (input.event) return singleEntry(input.event, input);
|
|
29140
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
29141
|
+
if (only) return singleEntry(only, input);
|
|
29142
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
29143
|
+
return {
|
|
29144
|
+
kind: "chooseEvent",
|
|
29145
|
+
title: input.events[0]?.title ?? "",
|
|
29146
|
+
count: input.events.length,
|
|
29147
|
+
noun: input.noun.pluralLabel,
|
|
29148
|
+
action: "Choose an event"
|
|
29149
|
+
};
|
|
29150
|
+
}
|
|
29151
|
+
//#endregion
|
|
29152
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
29153
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
29154
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
29155
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
29156
|
+
{
|
|
29157
|
+
preset: "class",
|
|
29158
|
+
sourceKey: "eventPreset:class",
|
|
29159
|
+
dataKey: "classEvents",
|
|
29160
|
+
label: "Classes"
|
|
29161
|
+
},
|
|
29162
|
+
{
|
|
29163
|
+
preset: "workshop",
|
|
29164
|
+
sourceKey: "eventPreset:workshop",
|
|
29165
|
+
dataKey: "workshopEvents",
|
|
29166
|
+
label: "Workshops"
|
|
29167
|
+
},
|
|
29168
|
+
{
|
|
29169
|
+
preset: "retreat",
|
|
29170
|
+
sourceKey: "eventPreset:retreat",
|
|
29171
|
+
dataKey: "retreatEvents",
|
|
29172
|
+
label: "Retreats"
|
|
29173
|
+
},
|
|
29174
|
+
{
|
|
29175
|
+
preset: "performance",
|
|
29176
|
+
sourceKey: "eventPreset:performance",
|
|
29177
|
+
dataKey: "performanceEvents",
|
|
29178
|
+
label: "Performances"
|
|
29179
|
+
}
|
|
29180
|
+
];
|
|
29181
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
29182
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
29183
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
29184
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
29185
|
+
kind: "eventPreset",
|
|
29186
|
+
preset: definition.preset
|
|
29187
|
+
}]));
|
|
29188
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
29189
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
29190
|
+
}
|
|
29191
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
29192
|
+
if (value == null) return { kind: "legacy" };
|
|
29193
|
+
if (value.length === 0) return { kind: "default" };
|
|
29194
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
29195
|
+
return keys.length > 0 ? {
|
|
29196
|
+
kind: "custom",
|
|
29197
|
+
keys
|
|
29198
|
+
} : { kind: "default" };
|
|
29199
|
+
}
|
|
29200
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
29201
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
29202
|
+
return keys.length >= 2 ? keys : [];
|
|
29203
|
+
}
|
|
29204
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
29205
|
+
if (!isRecord$3(value)) return null;
|
|
29206
|
+
const groupOrderValue = value.groupOrder;
|
|
29207
|
+
if (Array.isArray(groupOrderValue)) {
|
|
29208
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
29209
|
+
return {
|
|
29210
|
+
...value,
|
|
29211
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
29212
|
+
};
|
|
29213
|
+
}
|
|
29214
|
+
if (groupOrderValue != null) return {
|
|
29215
|
+
...value,
|
|
29216
|
+
groupOrder: []
|
|
29217
|
+
};
|
|
29218
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$3) : []);
|
|
29219
|
+
return legacyOrder.length > 0 ? {
|
|
29220
|
+
...value,
|
|
29221
|
+
groupOrder: legacyOrder
|
|
29222
|
+
} : value;
|
|
29223
|
+
}
|
|
29224
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
29225
|
+
function sourceFromPresetSummary(preset) {
|
|
29226
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
29227
|
+
if (preset.engine !== "event_series") return null;
|
|
29228
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
29229
|
+
kind: "eventPreset",
|
|
29230
|
+
preset: preset.canonicalBehaviour
|
|
29231
|
+
};
|
|
29232
|
+
return null;
|
|
29233
|
+
}
|
|
29234
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
29235
|
+
const keys = [];
|
|
29236
|
+
for (const value of values) {
|
|
29237
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
29238
|
+
if (!keys.includes(value)) keys.push(value);
|
|
29239
|
+
}
|
|
29240
|
+
return keys;
|
|
29241
|
+
}
|
|
29242
|
+
function isRecord$3(value) {
|
|
29243
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29244
|
+
}
|
|
29245
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
29246
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
29247
|
+
}
|
|
29248
|
+
//#endregion
|
|
29249
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
29250
|
+
function offeringKindForEvent(event) {
|
|
29251
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
29252
|
+
}
|
|
29253
|
+
function presetKind(preset) {
|
|
29254
|
+
const source = sourceFromPresetSummary(preset);
|
|
29255
|
+
if (!source) return null;
|
|
29256
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
29257
|
+
}
|
|
29258
|
+
/**
|
|
29259
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
29260
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
29261
|
+
* name stands in when the site has none.
|
|
29262
|
+
*/
|
|
29263
|
+
function offeringNounForEvent(event, presets) {
|
|
29264
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
29265
|
+
const kind = offeringKindForEvent(event);
|
|
29266
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
29267
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
29268
|
+
}
|
|
29269
|
+
function lowerCased(noun) {
|
|
29270
|
+
return {
|
|
29271
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
29272
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
29273
|
+
};
|
|
29274
|
+
}
|
|
29275
|
+
//#endregion
|
|
29276
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
29277
|
+
function toRegistrationEvent(event) {
|
|
29278
|
+
return {
|
|
29279
|
+
...event,
|
|
29280
|
+
selectionId: event.id,
|
|
29281
|
+
registrationSubject: {
|
|
29282
|
+
kind: "occurrence",
|
|
29283
|
+
occurrenceId: event.occurrenceId
|
|
29284
|
+
}
|
|
29285
|
+
};
|
|
29286
|
+
}
|
|
29287
|
+
function toRegistrationEvents(events) {
|
|
29288
|
+
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
29289
|
+
}
|
|
29290
|
+
/**
|
|
29291
|
+
* Project one whole-series run onto the registration surface.
|
|
29292
|
+
*
|
|
29293
|
+
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
29294
|
+
* Event record; only the schedule is widened from the single occurrence to the
|
|
29295
|
+
* live run. A run without live sessions has no registration event.
|
|
29296
|
+
*/
|
|
29297
|
+
function toWholeSeriesRegistrationEvent(group) {
|
|
29298
|
+
const { representative, run } = group;
|
|
29299
|
+
const sessions = orderedLiveRunSessions(run.sessions);
|
|
29300
|
+
const firstSession = sessions[0];
|
|
29301
|
+
if (!firstSession) return null;
|
|
29302
|
+
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
29303
|
+
return {
|
|
29304
|
+
...representative,
|
|
29305
|
+
selectionId: run.eventSeriesId,
|
|
29306
|
+
registrationSubject: {
|
|
29307
|
+
kind: "wholeSeries",
|
|
29308
|
+
eventSeriesId: run.eventSeriesId,
|
|
29309
|
+
sessions
|
|
29310
|
+
},
|
|
29311
|
+
startsAt: firstSession.startsAt,
|
|
29312
|
+
endsAt: lastSession.endsAt,
|
|
29313
|
+
timeZone: firstSession.timeZone
|
|
29314
|
+
};
|
|
29315
|
+
}
|
|
29316
|
+
function toWholeSeriesRegistrationEvents(events) {
|
|
29317
|
+
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
29318
|
+
}
|
|
29319
|
+
//#endregion
|
|
29320
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
29321
|
+
/**
|
|
29322
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
29323
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
29324
|
+
* so the server and the client agree on one card.
|
|
29325
|
+
*/
|
|
29326
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
29327
|
+
const tileSchema = z.object({
|
|
29328
|
+
month: z.string(),
|
|
29329
|
+
day: z.string()
|
|
29330
|
+
}).nullable();
|
|
29331
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
29332
|
+
z.object({
|
|
29333
|
+
kind: z.literal("single"),
|
|
29334
|
+
title: z.string(),
|
|
29335
|
+
when: z.string().nullable(),
|
|
29336
|
+
shortWhen: z.string().nullable(),
|
|
29337
|
+
venue: z.string().nullable(),
|
|
29338
|
+
price: z.string().nullable(),
|
|
29339
|
+
places: z.string().nullable(),
|
|
29340
|
+
tile: tileSchema,
|
|
29341
|
+
action: z.string()
|
|
29342
|
+
}),
|
|
29343
|
+
z.object({
|
|
29344
|
+
kind: z.literal("chooseDate"),
|
|
29345
|
+
title: z.string(),
|
|
29346
|
+
schedule: z.string(),
|
|
29347
|
+
venue: z.string().nullable(),
|
|
29348
|
+
price: z.string().nullable(),
|
|
29349
|
+
nextDate: z.string().nullable(),
|
|
29350
|
+
dateCount: z.number(),
|
|
29351
|
+
dates: z.array(z.object({
|
|
29352
|
+
selectionId: z.string(),
|
|
29353
|
+
label: z.string(),
|
|
29354
|
+
places: z.string().nullable(),
|
|
29355
|
+
full: z.boolean()
|
|
29356
|
+
})),
|
|
29357
|
+
moreCount: z.number(),
|
|
29358
|
+
action: z.string()
|
|
29359
|
+
}),
|
|
29360
|
+
z.object({
|
|
29361
|
+
kind: z.literal("chooseEvent"),
|
|
29362
|
+
title: z.string(),
|
|
29363
|
+
count: z.number(),
|
|
29364
|
+
noun: z.string(),
|
|
29365
|
+
action: z.string()
|
|
29366
|
+
})
|
|
29367
|
+
]);
|
|
29368
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
29369
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
29370
|
+
}
|
|
29371
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
29372
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
29373
|
+
return {
|
|
29374
|
+
scopedEvents,
|
|
29375
|
+
preSelected: findPreSelectedEvent({
|
|
29376
|
+
scopedEvents,
|
|
29377
|
+
occurrenceContext: source.occurrenceContext
|
|
29378
|
+
})
|
|
29379
|
+
};
|
|
29380
|
+
}
|
|
29381
|
+
function nounFor(scoped, presets) {
|
|
29382
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
29383
|
+
}
|
|
29384
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
29385
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
29386
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
29387
|
+
}
|
|
29388
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
29389
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
29390
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
29391
|
+
return idleBookingEntry({
|
|
29392
|
+
events: scoped.scopedEvents,
|
|
29393
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
29394
|
+
display,
|
|
29395
|
+
buttonText: source.buttonText,
|
|
29396
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
29397
|
+
attendanceMode: null
|
|
29398
|
+
});
|
|
29399
|
+
}
|
|
29400
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
29401
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
29402
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
29403
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
29404
|
+
if (!entry) return null;
|
|
29405
|
+
return {
|
|
29406
|
+
kind: "event-registration",
|
|
29407
|
+
state: "booking-card",
|
|
29408
|
+
className: source.className ?? null,
|
|
29409
|
+
entry,
|
|
29410
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
29411
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
29412
|
+
};
|
|
29413
|
+
}
|
|
29414
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
29415
|
+
kind: z.literal("unsupported"),
|
|
29416
|
+
reason: z.enum([
|
|
29417
|
+
"unsupportedSubject",
|
|
29418
|
+
"invalidEventSeriesId",
|
|
29419
|
+
"invalidEventSeriesBookingScope",
|
|
29420
|
+
"invalidEventOfferingId",
|
|
29421
|
+
"invalidEventOfferingBookingScope",
|
|
29422
|
+
"invalidEventOfferingCatalogue"
|
|
29423
|
+
])
|
|
29424
|
+
});
|
|
29425
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
29426
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
29427
|
+
if (unsupported.success) return unsupported.data;
|
|
29428
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
29429
|
+
if (parsed.ok) return parsed.value;
|
|
29430
|
+
ctx.addIssue({
|
|
29431
|
+
code: z.ZodIssueCode.custom,
|
|
29432
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
29433
|
+
});
|
|
29434
|
+
return z.NEVER;
|
|
29435
|
+
});
|
|
29436
|
+
function resolveEventRegistrationScope(context) {
|
|
29437
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
29438
|
+
if (occurrenceSeriesId) return {
|
|
29439
|
+
kind: "occurrenceSeries",
|
|
29440
|
+
seriesId: occurrenceSeriesId
|
|
29441
|
+
};
|
|
29442
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
29443
|
+
kind: "pageSurfaceSeries",
|
|
29444
|
+
seriesId: context.subject.eventSeriesId
|
|
29445
|
+
};
|
|
29446
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
29447
|
+
kind: "pageSurfaceOffering",
|
|
29448
|
+
offeringId: context.subject.eventOfferingId,
|
|
29449
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
29450
|
+
};
|
|
29451
|
+
if (context.subject?.kind === "unsupported") return {
|
|
29452
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
29453
|
+
reason: context.subject.reason
|
|
29454
|
+
};
|
|
29455
|
+
return { kind: "unscoped" };
|
|
29456
|
+
}
|
|
29457
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
29458
|
+
const scope = resolveEventRegistrationScope(context);
|
|
29459
|
+
switch (scope.kind) {
|
|
29460
|
+
case "occurrenceSeries":
|
|
29461
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
29462
|
+
case "pageSurfaceOffering": {
|
|
29463
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
29464
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
29465
|
+
}
|
|
29466
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
29467
|
+
case "unscoped": return [...events];
|
|
29468
|
+
}
|
|
29469
|
+
}
|
|
29470
|
+
//#endregion
|
|
29471
|
+
//#region ../blocks/src/system/constants/events.ts
|
|
29472
|
+
const eventCalendarDisplayModeValues = [
|
|
29473
|
+
"combined",
|
|
29474
|
+
"calendar",
|
|
29475
|
+
"list",
|
|
29476
|
+
"timetable",
|
|
29477
|
+
"week-board"
|
|
29478
|
+
];
|
|
29479
|
+
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
29480
|
+
const eventCalendarListLayoutValues = [
|
|
29481
|
+
"stack",
|
|
29482
|
+
"grid",
|
|
29483
|
+
"compact"
|
|
29484
|
+
];
|
|
29485
|
+
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
29486
|
+
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
29487
|
+
const eventCalendarListLayoutOptions = [
|
|
29488
|
+
{
|
|
29489
|
+
id: "stack",
|
|
29490
|
+
label: "Stack"
|
|
29491
|
+
},
|
|
29492
|
+
{
|
|
29493
|
+
id: "grid",
|
|
29494
|
+
label: "Grid"
|
|
29495
|
+
},
|
|
29496
|
+
{
|
|
29497
|
+
id: "compact",
|
|
29498
|
+
label: "Compact"
|
|
29499
|
+
}
|
|
29500
|
+
];
|
|
29501
|
+
function isEventCalendarDisplayMode(value) {
|
|
29502
|
+
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
29503
|
+
}
|
|
29504
|
+
function normalizeEventCalendarDisplayMode$1(input) {
|
|
29505
|
+
if (isEventCalendarDisplayMode(input.variant)) return input.variant;
|
|
29506
|
+
return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : void 0;
|
|
29507
|
+
}
|
|
29508
|
+
/** One closed authority for the projections required by each rendered mode. */
|
|
29509
|
+
function resolveEventCalendarReadPlan(input) {
|
|
29510
|
+
const mode = normalizeEventCalendarDisplayMode$1(input) ?? "combined";
|
|
29511
|
+
switch (mode) {
|
|
29512
|
+
case "combined": return {
|
|
29513
|
+
mode,
|
|
28434
29514
|
jobs: "both",
|
|
28435
29515
|
readProfile: "listing-card"
|
|
28436
29516
|
};
|
|
@@ -28510,95 +29590,6 @@ const calendarTabViewsSchema = z.enum([
|
|
|
28510
29590
|
"week"
|
|
28511
29591
|
]);
|
|
28512
29592
|
//#endregion
|
|
28513
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
28514
|
-
/**
|
|
28515
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
28516
|
-
*
|
|
28517
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
28518
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
28519
|
-
* @returns Array of wizard steps to display
|
|
28520
|
-
*/
|
|
28521
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
28522
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
28523
|
-
"select-event",
|
|
28524
|
-
"select-tickets",
|
|
28525
|
-
"enter-details"
|
|
28526
|
-
];
|
|
28527
|
-
if (!needsPaymentStep) return baseSteps;
|
|
28528
|
-
return paymentActive ? [
|
|
28529
|
-
...baseSteps,
|
|
28530
|
-
"select-payment",
|
|
28531
|
-
"payment"
|
|
28532
|
-
] : [...baseSteps, "select-payment"];
|
|
28533
|
-
}
|
|
28534
|
-
//#endregion
|
|
28535
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
28536
|
-
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
28537
|
-
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
28538
|
-
}
|
|
28539
|
-
function findPreSelectedEvent(input) {
|
|
28540
|
-
const occurrenceContext = input.occurrenceContext;
|
|
28541
|
-
if (!occurrenceContext) return input.scopedEvents.length === 1 ? input.scopedEvents[0] ?? null : null;
|
|
28542
|
-
const contextDate = getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
28543
|
-
startsAt: occurrenceContext.startsAt,
|
|
28544
|
-
timeZone: occurrenceContext.timeZone
|
|
28545
|
-
}));
|
|
28546
|
-
return input.scopedEvents.find((event) => eventMatchesOccurrenceId(event, occurrenceContext.id) || getBookingLocalDateKey(toScheduledBookingDateTime({
|
|
28547
|
-
startsAt: event.startsAt,
|
|
28548
|
-
timeZone: event.timeZone
|
|
28549
|
-
})) === contextDate) ?? null;
|
|
28550
|
-
}
|
|
28551
|
-
function resolveEventRequiresPayment(input) {
|
|
28552
|
-
if (input.eligibility) return input.eligibility.requiresPayment;
|
|
28553
|
-
if (input.selectedTicketType) return input.selectedTicketType.priceAmount > 0;
|
|
28554
|
-
if (!input.event) return false;
|
|
28555
|
-
return publicEventPricingType(input.event.pricing) === "paid";
|
|
28556
|
-
}
|
|
28557
|
-
//#endregion
|
|
28558
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
28559
|
-
function toRegistrationEvent(event) {
|
|
28560
|
-
return {
|
|
28561
|
-
...event,
|
|
28562
|
-
selectionId: event.id,
|
|
28563
|
-
registrationSubject: {
|
|
28564
|
-
kind: "occurrence",
|
|
28565
|
-
occurrenceId: event.occurrenceId
|
|
28566
|
-
}
|
|
28567
|
-
};
|
|
28568
|
-
}
|
|
28569
|
-
function toRegistrationEvents(events) {
|
|
28570
|
-
return events.filter((event) => event.bookingScope === "single_occurrence").map(toRegistrationEvent);
|
|
28571
|
-
}
|
|
28572
|
-
/**
|
|
28573
|
-
* Project one whole-series run onto the registration surface.
|
|
28574
|
-
*
|
|
28575
|
-
* Capacity, pricing, payment terms and consent come straight off the canonical
|
|
28576
|
-
* Event record; only the schedule is widened from the single occurrence to the
|
|
28577
|
-
* live run. A run without live sessions has no registration event.
|
|
28578
|
-
*/
|
|
28579
|
-
function toWholeSeriesRegistrationEvent(group) {
|
|
28580
|
-
const { representative, run } = group;
|
|
28581
|
-
const sessions = orderedLiveRunSessions(run.sessions);
|
|
28582
|
-
const firstSession = sessions[0];
|
|
28583
|
-
if (!firstSession) return null;
|
|
28584
|
-
const lastSession = sessions[sessions.length - 1] ?? firstSession;
|
|
28585
|
-
return {
|
|
28586
|
-
...representative,
|
|
28587
|
-
selectionId: run.eventSeriesId,
|
|
28588
|
-
registrationSubject: {
|
|
28589
|
-
kind: "wholeSeries",
|
|
28590
|
-
eventSeriesId: run.eventSeriesId,
|
|
28591
|
-
sessions
|
|
28592
|
-
},
|
|
28593
|
-
startsAt: firstSession.startsAt,
|
|
28594
|
-
endsAt: lastSession.endsAt,
|
|
28595
|
-
timeZone: firstSession.timeZone
|
|
28596
|
-
};
|
|
28597
|
-
}
|
|
28598
|
-
function toWholeSeriesRegistrationEvents(events) {
|
|
28599
|
-
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
28600
|
-
}
|
|
28601
|
-
//#endregion
|
|
28602
29593
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
28603
29594
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
28604
29595
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -28641,27 +29632,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
28641
29632
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
28642
29633
|
"Date",
|
|
28643
29634
|
"Tickets",
|
|
28644
|
-
"
|
|
28645
|
-
];
|
|
28646
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
28647
|
-
"Event",
|
|
28648
|
-
"Date",
|
|
28649
|
-
"Tickets",
|
|
28650
|
-
"Details",
|
|
28651
|
-
"Payment options",
|
|
28652
|
-
"Payment"
|
|
29635
|
+
"Your details"
|
|
28653
29636
|
];
|
|
28654
29637
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
28655
|
-
const
|
|
29638
|
+
const eventRegistrationCommonSchemaShape = {
|
|
28656
29639
|
demoEmailSuppressed: z.boolean().optional(),
|
|
28657
29640
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
28658
29641
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
28659
29642
|
maxTickets: z.string().optional(),
|
|
28660
|
-
showVenue: z.boolean().optional(),
|
|
28661
|
-
showCapacity: z.boolean().optional(),
|
|
28662
29643
|
successMessage: z.string().optional(),
|
|
28663
29644
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
28664
|
-
|
|
29645
|
+
host: bookingHostSchema.optional(),
|
|
28665
29646
|
spamProtectionEnabled: z.boolean().optional(),
|
|
28666
29647
|
supportEmail: z.string().optional(),
|
|
28667
29648
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -28686,32 +29667,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
28686
29667
|
portalToken: z.string().nullable().optional(),
|
|
28687
29668
|
previewToken: z.string().nullable().optional(),
|
|
28688
29669
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
28689
|
-
...
|
|
29670
|
+
...eventRegistrationCommonSchemaShape,
|
|
29671
|
+
showVenue: z.boolean().optional(),
|
|
29672
|
+
showCapacity: z.boolean().optional(),
|
|
28690
29673
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
28691
29674
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
28692
29675
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
28693
29676
|
className: z.string().nullable().optional(),
|
|
28694
29677
|
buttonText: z.string().nullable().optional(),
|
|
28695
29678
|
maxTickets: z.string().nullable().optional(),
|
|
28696
|
-
stage: previewStageSchema.optional()
|
|
29679
|
+
stage: previewStageSchema.optional(),
|
|
29680
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
28697
29681
|
});
|
|
28698
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
28699
|
-
|
|
28700
|
-
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
|
|
28704
|
-
|
|
28705
|
-
|
|
28706
|
-
|
|
28707
|
-
|
|
28708
|
-
|
|
28709
|
-
|
|
28710
|
-
|
|
28711
|
-
|
|
28712
|
-
|
|
29682
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
29683
|
+
z.object({
|
|
29684
|
+
kind: z.literal("event-registration"),
|
|
29685
|
+
state: z.literal("generic-shell"),
|
|
29686
|
+
className: z.string().nullable(),
|
|
29687
|
+
titleText: z.string(),
|
|
29688
|
+
bodyText: z.string(),
|
|
29689
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
29690
|
+
summaryButtonText: z.string()
|
|
29691
|
+
}),
|
|
29692
|
+
z.object({
|
|
29693
|
+
kind: z.literal("event-registration"),
|
|
29694
|
+
state: z.literal("registration-closed"),
|
|
29695
|
+
className: z.string().nullable(),
|
|
29696
|
+
titleText: z.string(),
|
|
29697
|
+
bodyText: z.string()
|
|
29698
|
+
}),
|
|
29699
|
+
z.object({
|
|
29700
|
+
kind: z.literal("event-registration"),
|
|
29701
|
+
state: z.literal("booking-card"),
|
|
29702
|
+
className: z.string().nullable(),
|
|
29703
|
+
entry: idleBookingEntrySchema,
|
|
29704
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
29705
|
+
buttonText: z.string()
|
|
29706
|
+
})
|
|
29707
|
+
]);
|
|
28713
29708
|
const eventRegistrationHydrationSchema = z.object({
|
|
28714
|
-
...
|
|
29709
|
+
...eventRegistrationCommonSchemaShape,
|
|
29710
|
+
display: registrationDisplaySchema,
|
|
29711
|
+
offeringNoun: z.object({
|
|
29712
|
+
label: z.string(),
|
|
29713
|
+
pluralLabel: z.string()
|
|
29714
|
+
}).optional(),
|
|
28715
29715
|
eventSource: eventRegistrationEventSourceSchema
|
|
28716
29716
|
});
|
|
28717
29717
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -28726,7 +29726,7 @@ z.object({
|
|
|
28726
29726
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
28727
29727
|
stage: previewStageSchema.optional()
|
|
28728
29728
|
});
|
|
28729
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
29729
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
28730
29730
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
28731
29731
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
28732
29732
|
kind: "event-registration",
|
|
@@ -28735,6 +29735,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
28735
29735
|
titleText: "Registration closed",
|
|
28736
29736
|
bodyText: "This run is no longer open for bookings."
|
|
28737
29737
|
};
|
|
29738
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
29739
|
+
if (card) return card;
|
|
28738
29740
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
28739
29741
|
return {
|
|
28740
29742
|
kind: "event-registration",
|
|
@@ -28751,11 +29753,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
28751
29753
|
if (selectedRun) {
|
|
28752
29754
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
28753
29755
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
28754
|
-
return
|
|
28755
|
-
|
|
28756
|
-
|
|
28757
|
-
|
|
28758
|
-
|
|
29756
|
+
return shellStepLabels(registrationRoute({
|
|
29757
|
+
chooseEvent: false,
|
|
29758
|
+
payment: resolveEventRequiresPayment({
|
|
29759
|
+
eligibility: null,
|
|
29760
|
+
selectedTicketType: null,
|
|
29761
|
+
event: selectedEvent
|
|
29762
|
+
}) ? "optionsAndPayment" : "none"
|
|
29763
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
28759
29764
|
}
|
|
28760
29765
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
28761
29766
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -28764,14 +29769,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
28764
29769
|
occurrenceContext: source.occurrenceContext
|
|
28765
29770
|
});
|
|
28766
29771
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
28767
|
-
|
|
29772
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
28768
29773
|
eligibility: null,
|
|
28769
29774
|
selectedTicketType: null,
|
|
28770
29775
|
event: preSelectedEvent
|
|
28771
|
-
}) : false
|
|
28772
|
-
|
|
28773
|
-
|
|
28774
|
-
|
|
29776
|
+
}) : false;
|
|
29777
|
+
return shellStepLabels(registrationRoute({
|
|
29778
|
+
chooseEvent: !hasPreSelectedContext,
|
|
29779
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
29780
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
28775
29781
|
}
|
|
28776
29782
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
28777
29783
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -28787,29 +29793,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
28787
29793
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
28788
29794
|
return runs.length === 1 ? runs[0] : null;
|
|
28789
29795
|
}
|
|
28790
|
-
function
|
|
28791
|
-
|
|
28792
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
28793
|
-
case "select-tickets": return "Tickets";
|
|
28794
|
-
case "enter-details": return "Details";
|
|
28795
|
-
case "select-payment": return "Payment options";
|
|
28796
|
-
case "payment": return "Payment";
|
|
28797
|
-
case "error":
|
|
28798
|
-
case "success":
|
|
28799
|
-
case "submitting":
|
|
28800
|
-
case "verifying-payment":
|
|
28801
|
-
case "verifying-timeout":
|
|
28802
|
-
case "payment-status":
|
|
28803
|
-
case "payment-failed": return "Details";
|
|
28804
|
-
}
|
|
28805
|
-
}
|
|
28806
|
-
function isDateSelection(events) {
|
|
28807
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
28808
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
29796
|
+
function shellStepLabels(route, context) {
|
|
29797
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
28809
29798
|
}
|
|
28810
29799
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
28811
|
-
if (stepLabels.includes("
|
|
28812
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
29800
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
29801
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
28813
29802
|
return "Preparing dates, tickets, and booking details.";
|
|
28814
29803
|
}
|
|
28815
29804
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -28819,6 +29808,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
28819
29808
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
28820
29809
|
},
|
|
28821
29810
|
buildRender: (source) => {
|
|
29811
|
+
const display = resolveRegistrationDisplay(source);
|
|
28822
29812
|
const eventSource = resolveEventRegistrationEventSource({
|
|
28823
29813
|
events: source.events,
|
|
28824
29814
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -28826,7 +29816,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
28826
29816
|
});
|
|
28827
29817
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
28828
29818
|
return {
|
|
28829
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
29819
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
28830
29820
|
hydration: {
|
|
28831
29821
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
28832
29822
|
subject: source.subject ?? null,
|
|
@@ -28836,29 +29826,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
28836
29826
|
} : eventSource,
|
|
28837
29827
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
28838
29828
|
maxTickets: source.maxTickets ?? void 0,
|
|
28839
|
-
|
|
28840
|
-
showCapacity: source.showCapacity,
|
|
29829
|
+
display,
|
|
28841
29830
|
successMessage: source.successMessage,
|
|
28842
29831
|
buttonVariant: source.buttonVariant,
|
|
28843
|
-
|
|
29832
|
+
host: source.host ?? "overlay",
|
|
28844
29833
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
28845
29834
|
supportEmail: source.supportEmail,
|
|
28846
29835
|
sitePasses: source.sitePasses ?? null,
|
|
28847
29836
|
siteMemberships: source.siteMemberships ?? null,
|
|
28848
29837
|
mailingList: source.mailingList,
|
|
28849
|
-
siteName: source.siteName
|
|
29838
|
+
siteName: source.siteName,
|
|
29839
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
28850
29840
|
}
|
|
28851
29841
|
};
|
|
28852
29842
|
}
|
|
28853
29843
|
});
|
|
28854
29844
|
function normalizeEventRegistrationEventInput(value) {
|
|
28855
|
-
if (!isRecord$
|
|
29845
|
+
if (!isRecord$2(value)) return value;
|
|
28856
29846
|
return {
|
|
28857
29847
|
...value,
|
|
28858
29848
|
destination: resolveRuntimeEventDestination(value)
|
|
28859
29849
|
};
|
|
28860
29850
|
}
|
|
28861
|
-
function isRecord$
|
|
29851
|
+
function isRecord$2(value) {
|
|
28862
29852
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28863
29853
|
}
|
|
28864
29854
|
const eventRegistrationBlockDefinition = {
|
|
@@ -28898,7 +29888,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
28898
29888
|
description: "Main heading for the registration form",
|
|
28899
29889
|
required: false,
|
|
28900
29890
|
multiline: false,
|
|
28901
|
-
defaultValue: "
|
|
29891
|
+
defaultValue: ""
|
|
28902
29892
|
},
|
|
28903
29893
|
{
|
|
28904
29894
|
id: "description",
|
|
@@ -28970,11 +29960,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
28970
29960
|
{
|
|
28971
29961
|
id: "buttonText",
|
|
28972
29962
|
type: "text",
|
|
28973
|
-
label: "
|
|
28974
|
-
description: "Text
|
|
29963
|
+
label: "Button text",
|
|
29964
|
+
description: "Text on the booking button",
|
|
28975
29965
|
required: false,
|
|
28976
29966
|
multiline: false,
|
|
28977
|
-
defaultValue: "
|
|
29967
|
+
defaultValue: "Book your place",
|
|
28978
29968
|
maxLength: 40
|
|
28979
29969
|
},
|
|
28980
29970
|
createButtonVariantField()
|
|
@@ -29006,21 +29996,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
29006
29996
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
29007
29997
|
buttonText: { $bind: {
|
|
29008
29998
|
from: "content.buttonText",
|
|
29009
|
-
fallback: "
|
|
29999
|
+
fallback: "Book your place"
|
|
29010
30000
|
} },
|
|
29011
30001
|
buttonVariant: { $bind: {
|
|
29012
30002
|
from: "content.buttonVariant",
|
|
29013
30003
|
fallback: "primary"
|
|
29014
30004
|
} },
|
|
29015
|
-
overlayEnabled: { $bind: {
|
|
29016
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
29017
|
-
fallback: false
|
|
29018
|
-
} },
|
|
29019
30005
|
events: { $bind: { from: "data.events" } },
|
|
29020
30006
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
29021
30007
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
29022
30008
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
29023
30009
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
30010
|
+
bookingOfferingPresets: { $bind: {
|
|
30011
|
+
from: "$root.bookingOfferingPresets",
|
|
30012
|
+
fallback: []
|
|
30013
|
+
} },
|
|
29024
30014
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
29025
30015
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
29026
30016
|
stage: { $bind: {
|
|
@@ -31656,7 +32646,21 @@ const eventCalendarBlockDefinition = {
|
|
|
31656
32646
|
list: { label: "List" }
|
|
31657
32647
|
}
|
|
31658
32648
|
}, eventCalendarContentShape),
|
|
31659
|
-
|
|
32649
|
+
contentNormalizer: {
|
|
32650
|
+
fieldIds: [
|
|
32651
|
+
"variant",
|
|
32652
|
+
"displayMode",
|
|
32653
|
+
"listLayout",
|
|
32654
|
+
"defaultCalendarView",
|
|
32655
|
+
"eventSurface",
|
|
32656
|
+
"filterEventPresets",
|
|
32657
|
+
"scheduleScope",
|
|
32658
|
+
"filterCategoryIds",
|
|
32659
|
+
"filterStaffMemberId",
|
|
32660
|
+
"filterVenueId"
|
|
32661
|
+
],
|
|
32662
|
+
normalize: normalizeEventCalendarContent
|
|
32663
|
+
},
|
|
31660
32664
|
dataSchemas: {
|
|
31661
32665
|
events: publicEventsArraySchema.optional(),
|
|
31662
32666
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -31905,90 +32909,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
31905
32909
|
} }
|
|
31906
32910
|
};
|
|
31907
32911
|
//#endregion
|
|
31908
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
31909
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
31910
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
31911
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
31912
|
-
{
|
|
31913
|
-
preset: "class",
|
|
31914
|
-
sourceKey: "eventPreset:class",
|
|
31915
|
-
dataKey: "classEvents",
|
|
31916
|
-
label: "Classes"
|
|
31917
|
-
},
|
|
31918
|
-
{
|
|
31919
|
-
preset: "workshop",
|
|
31920
|
-
sourceKey: "eventPreset:workshop",
|
|
31921
|
-
dataKey: "workshopEvents",
|
|
31922
|
-
label: "Workshops"
|
|
31923
|
-
},
|
|
31924
|
-
{
|
|
31925
|
-
preset: "retreat",
|
|
31926
|
-
sourceKey: "eventPreset:retreat",
|
|
31927
|
-
dataKey: "retreatEvents",
|
|
31928
|
-
label: "Retreats"
|
|
31929
|
-
},
|
|
31930
|
-
{
|
|
31931
|
-
preset: "performance",
|
|
31932
|
-
sourceKey: "eventPreset:performance",
|
|
31933
|
-
dataKey: "performanceEvents",
|
|
31934
|
-
label: "Performances"
|
|
31935
|
-
}
|
|
31936
|
-
];
|
|
31937
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
31938
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
31939
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
31940
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
31941
|
-
kind: "eventPreset",
|
|
31942
|
-
preset: definition.preset
|
|
31943
|
-
}]));
|
|
31944
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
31945
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
31946
|
-
}
|
|
31947
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
31948
|
-
if (value == null) return { kind: "legacy" };
|
|
31949
|
-
if (value.length === 0) return { kind: "default" };
|
|
31950
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
31951
|
-
return keys.length > 0 ? {
|
|
31952
|
-
kind: "custom",
|
|
31953
|
-
keys
|
|
31954
|
-
} : { kind: "default" };
|
|
31955
|
-
}
|
|
31956
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
31957
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
31958
|
-
return keys.length >= 2 ? keys : [];
|
|
31959
|
-
}
|
|
31960
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
31961
|
-
if (!isRecord$2(value)) return null;
|
|
31962
|
-
const groupOrderValue = value.groupOrder;
|
|
31963
|
-
if (Array.isArray(groupOrderValue)) {
|
|
31964
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
31965
|
-
return {
|
|
31966
|
-
...value,
|
|
31967
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
31968
|
-
};
|
|
31969
|
-
}
|
|
31970
|
-
if (groupOrderValue != null) return {
|
|
31971
|
-
...value,
|
|
31972
|
-
groupOrder: []
|
|
31973
|
-
};
|
|
31974
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$2) : []);
|
|
31975
|
-
return legacyOrder.length > 0 ? {
|
|
31976
|
-
...value,
|
|
31977
|
-
groupOrder: legacyOrder
|
|
31978
|
-
} : value;
|
|
31979
|
-
}
|
|
31980
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
31981
|
-
const keys = [];
|
|
31982
|
-
for (const value of values) {
|
|
31983
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
31984
|
-
if (!keys.includes(value)) keys.push(value);
|
|
31985
|
-
}
|
|
31986
|
-
return keys;
|
|
31987
|
-
}
|
|
31988
|
-
function isRecord$2(value) {
|
|
31989
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31990
|
-
}
|
|
31991
|
-
//#endregion
|
|
31992
32912
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
31993
32913
|
const groupOverrideFields = [
|
|
31994
32914
|
{
|
|
@@ -32352,7 +33272,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
32352
33272
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
32353
33273
|
const offeringsPreviewBlockDefinition = {
|
|
32354
33274
|
manifest: offeringsPreviewManifest,
|
|
32355
|
-
|
|
33275
|
+
contentNormalizer: {
|
|
33276
|
+
fieldIds: [
|
|
33277
|
+
"displayMode",
|
|
33278
|
+
"heading",
|
|
33279
|
+
"description",
|
|
33280
|
+
"itemLimit",
|
|
33281
|
+
"groupOrder",
|
|
33282
|
+
"groupOverrides",
|
|
33283
|
+
"_cardStyles",
|
|
33284
|
+
"buttonVariant",
|
|
33285
|
+
"buttonText",
|
|
33286
|
+
"emptyMessage",
|
|
33287
|
+
"_sectionStyles"
|
|
33288
|
+
],
|
|
33289
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
33290
|
+
},
|
|
32356
33291
|
dataSchemas: {
|
|
32357
33292
|
...offeringsPreviewEventDataSchemas,
|
|
32358
33293
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -35950,11 +36885,11 @@ function buildNewsletterDisplay(source) {
|
|
|
35950
36885
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
35951
36886
|
privacyNote: null
|
|
35952
36887
|
};
|
|
35953
|
-
const
|
|
35954
|
-
const choices = resolveRuntimeChoices(
|
|
36888
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
36889
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
35955
36890
|
return {
|
|
35956
36891
|
kind: "newsletter-form",
|
|
35957
|
-
availability:
|
|
36892
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
35958
36893
|
className: source.className ?? null,
|
|
35959
36894
|
buttonLabel: form.buttonLabel,
|
|
35960
36895
|
successMessage: form.successMessage,
|
|
@@ -36011,60 +36946,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
36011
36946
|
default: return assertNever$1(source);
|
|
36012
36947
|
}
|
|
36013
36948
|
}
|
|
36014
|
-
function resolveRuntimeChoices(
|
|
36015
|
-
if (
|
|
36016
|
-
|
|
36017
|
-
|
|
36018
|
-
|
|
36019
|
-
|
|
36020
|
-
id: item.id,
|
|
36021
|
-
label: item.name
|
|
36022
|
-
})) : [];
|
|
36023
|
-
}
|
|
36024
|
-
case "brevo": {
|
|
36025
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
36026
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
36027
|
-
id: String(item.id),
|
|
36028
|
-
label: item.name
|
|
36029
|
-
})) : [];
|
|
36030
|
-
}
|
|
36031
|
-
case "mailchimp": {
|
|
36032
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
36033
|
-
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) => ({
|
|
36034
|
-
id: item.id,
|
|
36035
|
-
label: item.name
|
|
36036
|
-
})) ?? [];
|
|
36037
|
-
}
|
|
36038
|
-
}
|
|
36039
|
-
}
|
|
36040
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
36041
|
-
if (context?.tag !== "configured") return false;
|
|
36042
|
-
const provider = context.provider;
|
|
36043
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
36044
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
36045
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
36046
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
36047
|
-
}
|
|
36048
|
-
if (targeting.provider !== provider.provider) return false;
|
|
36049
|
-
switch (targeting.provider) {
|
|
36050
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
36051
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
36052
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
36053
|
-
}
|
|
36054
|
-
}
|
|
36055
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
36056
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
36057
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
36058
|
-
}
|
|
36059
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
36060
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
36061
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
36062
|
-
}
|
|
36063
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
36064
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
36065
|
-
if (!audience) return false;
|
|
36066
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
36067
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
36949
|
+
function resolveRuntimeChoices(assessment) {
|
|
36950
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
36951
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
36952
|
+
id: String(item.id),
|
|
36953
|
+
label: item.name
|
|
36954
|
+
}));
|
|
36068
36955
|
}
|
|
36069
36956
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
36070
36957
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -36168,6 +37055,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
36168
37055
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
36169
37056
|
const newsletterSignupBlockDefinition = {
|
|
36170
37057
|
manifest: newsletterSignupManifest,
|
|
37058
|
+
contentNormalizer: {
|
|
37059
|
+
fieldIds: ["targeting"],
|
|
37060
|
+
normalize: normalizeMailingListBlockContent
|
|
37061
|
+
},
|
|
36171
37062
|
runtime: newsletterFormBlockRuntime
|
|
36172
37063
|
};
|
|
36173
37064
|
//#endregion
|
|
@@ -36900,7 +37791,20 @@ const locationMapBlockDefinition = {
|
|
|
36900
37791
|
})], { gap: "md" })
|
|
36901
37792
|
})
|
|
36902
37793
|
}),
|
|
36903
|
-
|
|
37794
|
+
contentNormalizer: {
|
|
37795
|
+
fieldIds: [
|
|
37796
|
+
"heading",
|
|
37797
|
+
"locationSource",
|
|
37798
|
+
"venueId",
|
|
37799
|
+
"location",
|
|
37800
|
+
"showAddressText",
|
|
37801
|
+
"showDirections",
|
|
37802
|
+
"directionsLabel",
|
|
37803
|
+
"zoom",
|
|
37804
|
+
"heightPx"
|
|
37805
|
+
],
|
|
37806
|
+
normalize: normalizeLocationMapContent
|
|
37807
|
+
}
|
|
36904
37808
|
};
|
|
36905
37809
|
//#endregion
|
|
36906
37810
|
//#region ../blocks/src/system/blocks/index.ts
|