@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
|
@@ -1941,6 +1941,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
1941
1941
|
default: return assertNever$2(pricing);
|
|
1942
1942
|
}
|
|
1943
1943
|
}
|
|
1944
|
+
/**
|
|
1945
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
1946
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
1947
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
1948
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
1949
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
1950
|
+
*/
|
|
1951
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
1952
|
+
switch (display.kind) {
|
|
1953
|
+
case "free": return "Free";
|
|
1954
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
1955
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
1956
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
1957
|
+
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)}`;
|
|
1958
|
+
case "unavailable": return "Pricing unavailable";
|
|
1959
|
+
case "external": return display.label;
|
|
1960
|
+
default: return assertNever$2(display);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
/** Render an event's price directly from its pricing value. */
|
|
1964
|
+
function formatEventPricing(pricing, options = {}) {
|
|
1965
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
1966
|
+
}
|
|
1944
1967
|
//#endregion
|
|
1945
1968
|
//#region ../core/src/event-page-surface-subject.ts
|
|
1946
1969
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -2084,6 +2107,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
2084
2107
|
}
|
|
2085
2108
|
//#endregion
|
|
2086
2109
|
//#region ../core/src/booking-date-time.ts
|
|
2110
|
+
const DEFAULT_LOCALE = "en-US";
|
|
2087
2111
|
const FALLBACK_TIMEZONE = "UTC";
|
|
2088
2112
|
const START_OF_DAY = {
|
|
2089
2113
|
hour: 0,
|
|
@@ -2206,6 +2230,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
2206
2230
|
if (result.ok) return result.value;
|
|
2207
2231
|
throw new Error(formatParseError(result));
|
|
2208
2232
|
}
|
|
2233
|
+
function formatBookingInstant(isoString, options) {
|
|
2234
|
+
const date = new Date(isoString);
|
|
2235
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
2236
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
2237
|
+
}
|
|
2238
|
+
function formatBookingDate(input, format = {
|
|
2239
|
+
weekday: "long",
|
|
2240
|
+
year: "numeric",
|
|
2241
|
+
month: "long",
|
|
2242
|
+
day: "numeric"
|
|
2243
|
+
}) {
|
|
2244
|
+
return formatBookingInstant(input.startsAt, {
|
|
2245
|
+
locale: input.locale,
|
|
2246
|
+
timeZone: input.timeZone,
|
|
2247
|
+
format
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
function formatBookingTime(input, format = {
|
|
2251
|
+
hour: "numeric",
|
|
2252
|
+
minute: "2-digit",
|
|
2253
|
+
hour12: true
|
|
2254
|
+
}) {
|
|
2255
|
+
return formatBookingInstant(input.startsAt, {
|
|
2256
|
+
locale: input.locale,
|
|
2257
|
+
timeZone: input.timeZone,
|
|
2258
|
+
format
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2209
2261
|
function getBookingLocalDateKey(input) {
|
|
2210
2262
|
return formatDateKey$1(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
2211
2263
|
}
|
|
@@ -2447,6 +2499,14 @@ function formError(field) {
|
|
|
2447
2499
|
}
|
|
2448
2500
|
//#endregion
|
|
2449
2501
|
//#region ../core/src/mailing-list-targeting.ts
|
|
2502
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
2503
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
2504
|
+
switch (targeting.provider) {
|
|
2505
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
2506
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
2507
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2450
2510
|
function planMailingListChoicePresentation(targeting) {
|
|
2451
2511
|
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
2452
2512
|
switch (targeting.provider) {
|
|
@@ -2486,6 +2546,103 @@ function planMailingListChoicePresentation(targeting) {
|
|
|
2486
2546
|
}
|
|
2487
2547
|
}
|
|
2488
2548
|
//#endregion
|
|
2549
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
2550
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
2551
|
+
switch (provider.provider) {
|
|
2552
|
+
case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
|
|
2553
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
2554
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
function assessMailingListTargeting(context, targeting) {
|
|
2558
|
+
if (context?.tag !== "configured") return {
|
|
2559
|
+
tag: "unavailable",
|
|
2560
|
+
reason: "setup_missing",
|
|
2561
|
+
targeting
|
|
2562
|
+
};
|
|
2563
|
+
const catalog = context.provider;
|
|
2564
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
2565
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
2566
|
+
return destination === null ? {
|
|
2567
|
+
tag: "unavailable",
|
|
2568
|
+
reason: "default_missing",
|
|
2569
|
+
targeting
|
|
2570
|
+
} : {
|
|
2571
|
+
tag: "available",
|
|
2572
|
+
value: {
|
|
2573
|
+
mode: "default",
|
|
2574
|
+
targeting,
|
|
2575
|
+
provider: catalog.provider,
|
|
2576
|
+
destination
|
|
2577
|
+
}
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
2581
|
+
switch (targeting.provider) {
|
|
2582
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
2583
|
+
provider: "native",
|
|
2584
|
+
catalog,
|
|
2585
|
+
targeting
|
|
2586
|
+
}, catalog.topics) : {
|
|
2587
|
+
tag: "unavailable",
|
|
2588
|
+
reason: "provider_mismatch",
|
|
2589
|
+
targeting
|
|
2590
|
+
};
|
|
2591
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
2592
|
+
provider: "brevo",
|
|
2593
|
+
catalog,
|
|
2594
|
+
targeting
|
|
2595
|
+
}, catalog.lists) : {
|
|
2596
|
+
tag: "unavailable",
|
|
2597
|
+
reason: "provider_mismatch",
|
|
2598
|
+
targeting
|
|
2599
|
+
};
|
|
2600
|
+
case "mailchimp": {
|
|
2601
|
+
if (catalog.provider !== "mailchimp") return {
|
|
2602
|
+
tag: "unavailable",
|
|
2603
|
+
reason: "provider_mismatch",
|
|
2604
|
+
targeting
|
|
2605
|
+
};
|
|
2606
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
2607
|
+
return audience === void 0 ? {
|
|
2608
|
+
tag: "unavailable",
|
|
2609
|
+
reason: "audience_missing",
|
|
2610
|
+
value: {
|
|
2611
|
+
mode: "custom",
|
|
2612
|
+
provider: "mailchimp",
|
|
2613
|
+
catalog,
|
|
2614
|
+
targeting
|
|
2615
|
+
}
|
|
2616
|
+
} : assessMatchedChoices({
|
|
2617
|
+
provider: "mailchimp",
|
|
2618
|
+
catalog,
|
|
2619
|
+
targeting,
|
|
2620
|
+
audience
|
|
2621
|
+
}, audience.interests);
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
function assessMatchedChoices(matched, choices) {
|
|
2626
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
2627
|
+
const available = new Set(choices.map((item) => item.id));
|
|
2628
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
2629
|
+
const value = {
|
|
2630
|
+
mode: "custom",
|
|
2631
|
+
...matched,
|
|
2632
|
+
choices,
|
|
2633
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
2634
|
+
};
|
|
2635
|
+
return missingIds.length > 0 ? {
|
|
2636
|
+
tag: "unavailable",
|
|
2637
|
+
reason: "choices_missing",
|
|
2638
|
+
missingIds,
|
|
2639
|
+
value
|
|
2640
|
+
} : {
|
|
2641
|
+
tag: "available",
|
|
2642
|
+
value
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
//#endregion
|
|
2489
2646
|
//#region ../core/src/mailing-list-runtime.ts
|
|
2490
2647
|
function parseMailingListRuntimeContext(value) {
|
|
2491
2648
|
if (!isRecord$8(value)) return invalidRuntimeContext();
|
|
@@ -2550,57 +2707,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
2550
2707
|
function parseMailchimpRuntimeProvider(value) {
|
|
2551
2708
|
if (!Array.isArray(value.audiences)) return null;
|
|
2552
2709
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
for (const audience of value.audiences) {
|
|
2556
|
-
if (!isRecord$8(audience)) return null;
|
|
2557
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
2558
|
-
const name = parseName(audience.name);
|
|
2559
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
2560
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
2561
|
-
if (interests === null) return null;
|
|
2562
|
-
audiences.push({
|
|
2563
|
-
id,
|
|
2564
|
-
name,
|
|
2565
|
-
interests
|
|
2566
|
-
});
|
|
2567
|
-
}
|
|
2568
|
-
return {
|
|
2710
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
2711
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
2569
2712
|
provider: "mailchimp",
|
|
2570
2713
|
defaultAudienceId,
|
|
2571
2714
|
audiences
|
|
2572
|
-
};
|
|
2715
|
+
} : null;
|
|
2573
2716
|
}
|
|
2574
|
-
function
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
interests
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2717
|
+
function parseMailchimpAudience(value) {
|
|
2718
|
+
if (!isRecord$8(value) || !Array.isArray(value.interests)) return null;
|
|
2719
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
2720
|
+
const name = parseName(value.name);
|
|
2721
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
2722
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
2723
|
+
id,
|
|
2724
|
+
name,
|
|
2725
|
+
interests
|
|
2726
|
+
} : null;
|
|
2727
|
+
}
|
|
2728
|
+
function parseMailchimpInterest(value) {
|
|
2729
|
+
if (!isRecord$8(value)) return null;
|
|
2730
|
+
const id = parseMailchimpInterestId(value.id);
|
|
2731
|
+
const name = parseName(value.name);
|
|
2732
|
+
const categoryName = parseName(value.categoryName);
|
|
2733
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
2734
|
+
id,
|
|
2735
|
+
name,
|
|
2736
|
+
categoryName
|
|
2737
|
+
} : null;
|
|
2589
2738
|
}
|
|
2590
2739
|
function parseNamedItems(value, parseId) {
|
|
2591
2740
|
if (!Array.isArray(value)) return null;
|
|
2592
|
-
const items =
|
|
2593
|
-
for (const item of value) {
|
|
2741
|
+
const items = Array.from(value, (item) => {
|
|
2594
2742
|
if (!isRecord$8(item)) return null;
|
|
2595
2743
|
const id = parseId(item.id);
|
|
2596
2744
|
const name = parseName(item.name);
|
|
2597
|
-
|
|
2598
|
-
items.push({
|
|
2745
|
+
return id !== null && name !== null ? {
|
|
2599
2746
|
id,
|
|
2600
2747
|
name
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
return items;
|
|
2748
|
+
} : null;
|
|
2749
|
+
});
|
|
2750
|
+
return items.every((item) => item !== null) ? items : null;
|
|
2604
2751
|
}
|
|
2605
2752
|
function parseName(value) {
|
|
2606
2753
|
if (typeof value !== "string") return null;
|
|
@@ -2616,6 +2763,7 @@ function invalidRuntimeContext() {
|
|
|
2616
2763
|
//#endregion
|
|
2617
2764
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2618
2765
|
function parseMailingListPlacementTargeting(value) {
|
|
2766
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
2619
2767
|
if (!isRecord$7(value)) return targetingError("shape");
|
|
2620
2768
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
2621
2769
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -2714,14 +2862,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
2714
2862
|
}
|
|
2715
2863
|
function parseUniqueIds(value, parseId) {
|
|
2716
2864
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
2717
|
-
|
|
2718
|
-
|
|
2865
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
2866
|
+
if (!parsed.ok) return parsed;
|
|
2719
2867
|
const id = parseId(item);
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
parsed.push(id);
|
|
2723
|
-
}
|
|
2724
|
-
return ok(parsed);
|
|
2868
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
2869
|
+
}, ok([]));
|
|
2725
2870
|
}
|
|
2726
2871
|
function isRecord$7(value) {
|
|
2727
2872
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3150,6 +3295,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
3150
3295
|
};
|
|
3151
3296
|
}
|
|
3152
3297
|
//#endregion
|
|
3298
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
3299
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
3300
|
+
event: {
|
|
3301
|
+
label: "Event",
|
|
3302
|
+
pluralLabel: "Events",
|
|
3303
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
3304
|
+
},
|
|
3305
|
+
class: {
|
|
3306
|
+
label: "Class",
|
|
3307
|
+
pluralLabel: "Classes",
|
|
3308
|
+
description: "Regular scheduled classes and group sessions."
|
|
3309
|
+
},
|
|
3310
|
+
course: {
|
|
3311
|
+
label: "Course",
|
|
3312
|
+
pluralLabel: "Courses",
|
|
3313
|
+
description: "A fixed set of dates that people book together."
|
|
3314
|
+
},
|
|
3315
|
+
term: {
|
|
3316
|
+
label: "Term",
|
|
3317
|
+
pluralLabel: "Terms",
|
|
3318
|
+
description: "A fixed term of sessions that people book together."
|
|
3319
|
+
},
|
|
3320
|
+
workshop: {
|
|
3321
|
+
label: "Workshop",
|
|
3322
|
+
pluralLabel: "Workshops",
|
|
3323
|
+
description: "One-off workshops, day sessions, or special events."
|
|
3324
|
+
},
|
|
3325
|
+
retreat: {
|
|
3326
|
+
label: "Retreat",
|
|
3327
|
+
pluralLabel: "Retreats",
|
|
3328
|
+
description: "Multi-day or residential immersive experiences."
|
|
3329
|
+
},
|
|
3330
|
+
performance: {
|
|
3331
|
+
label: "Performance",
|
|
3332
|
+
pluralLabel: "Performances",
|
|
3333
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
3334
|
+
}
|
|
3335
|
+
};
|
|
3336
|
+
//#endregion
|
|
3153
3337
|
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
3154
3338
|
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3155
3339
|
checkPublicEventRegistrationNextStep: {
|
|
@@ -24185,6 +24369,14 @@ z.object({
|
|
|
24185
24369
|
icon: z.string().optional()
|
|
24186
24370
|
});
|
|
24187
24371
|
//#endregion
|
|
24372
|
+
//#region ../blocks/src/lib/typeGuards.ts
|
|
24373
|
+
/**
|
|
24374
|
+
* Strict record guard: excludes null, primitives, and arrays.
|
|
24375
|
+
*/
|
|
24376
|
+
function isRecord$5(value) {
|
|
24377
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24378
|
+
}
|
|
24379
|
+
//#endregion
|
|
24188
24380
|
//#region ../blocks/src/system/designCapabilities.ts
|
|
24189
24381
|
function declareBlockDesignCapability(capability) {
|
|
24190
24382
|
return {
|
|
@@ -31038,6 +31230,15 @@ const formBlockDefinition = {
|
|
|
31038
31230
|
runtime: formBlockRuntime
|
|
31039
31231
|
};
|
|
31040
31232
|
//#endregion
|
|
31233
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
31234
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
31235
|
+
function normalizeMailingListBlockContent(record) {
|
|
31236
|
+
return record.targeting == null ? {
|
|
31237
|
+
...record,
|
|
31238
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
31239
|
+
} : record;
|
|
31240
|
+
}
|
|
31241
|
+
//#endregion
|
|
31041
31242
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
31042
31243
|
const contactNewsletterLayout = styledSection({
|
|
31043
31244
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -31201,6 +31402,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
31201
31402
|
],
|
|
31202
31403
|
icon: "MailPlus"
|
|
31203
31404
|
}),
|
|
31405
|
+
contentNormalizer: {
|
|
31406
|
+
fieldIds: ["targeting"],
|
|
31407
|
+
normalize: normalizeMailingListBlockContent
|
|
31408
|
+
},
|
|
31204
31409
|
dataSchemas: { form: formDataSchema.optional() },
|
|
31205
31410
|
dataLoaders: { form: {
|
|
31206
31411
|
endpoint: "getPublicFormById",
|
|
@@ -32618,14 +32823,6 @@ const mediaTransforms = [{
|
|
|
32618
32823
|
}
|
|
32619
32824
|
}];
|
|
32620
32825
|
//#endregion
|
|
32621
|
-
//#region ../blocks/src/lib/typeGuards.ts
|
|
32622
|
-
/**
|
|
32623
|
-
* Strict record guard: excludes null, primitives, and arrays.
|
|
32624
|
-
*/
|
|
32625
|
-
function isRecord$5(value) {
|
|
32626
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32627
|
-
}
|
|
32628
|
-
//#endregion
|
|
32629
32826
|
//#region ../blocks/src/system/transforms/registry/content.ts
|
|
32630
32827
|
const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
|
|
32631
32828
|
const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(supportedRichTextTokenSchema).default(["year", "site_name"]) });
|
|
@@ -35601,6 +35798,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
35601
35798
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
35602
35799
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
35603
35800
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
35801
|
+
z.strictObject({
|
|
35802
|
+
currency: z.string().trim().length(3),
|
|
35803
|
+
totalCents: nonNegativeIntegerSchema,
|
|
35804
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
35805
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
35806
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
35807
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
35808
|
+
});
|
|
35604
35809
|
//#endregion
|
|
35605
35810
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
35606
35811
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -35841,6 +36046,10 @@ const publicEventBaseSchema = z.object({
|
|
|
35841
36046
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
35842
36047
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
35843
36048
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
36049
|
+
scheduleSummary: z.object({
|
|
36050
|
+
recurrenceDescription: z.string(),
|
|
36051
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
36052
|
+
}).nullable().optional(),
|
|
35844
36053
|
id: z.string(),
|
|
35845
36054
|
occurrenceId: z.string(),
|
|
35846
36055
|
seriesId: z.string(),
|
|
@@ -36251,68 +36460,267 @@ const occurrenceContextSchema = z.object({
|
|
|
36251
36460
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
36252
36461
|
}).nullable();
|
|
36253
36462
|
//#endregion
|
|
36254
|
-
//#region ../blocks/src/system/runtime/
|
|
36255
|
-
|
|
36256
|
-
|
|
36257
|
-
|
|
36258
|
-
|
|
36259
|
-
|
|
36260
|
-
|
|
36261
|
-
|
|
36262
|
-
|
|
36263
|
-
|
|
36264
|
-
|
|
36265
|
-
|
|
36266
|
-
|
|
36267
|
-
"invalidEventOfferingCatalogue"
|
|
36268
|
-
])
|
|
36269
|
-
});
|
|
36270
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
36271
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
36272
|
-
if (unsupported.success) return unsupported.data;
|
|
36273
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
36274
|
-
if (parsed.ok) return parsed.value;
|
|
36275
|
-
ctx.addIssue({
|
|
36276
|
-
code: z.ZodIssueCode.custom,
|
|
36277
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
36278
|
-
});
|
|
36279
|
-
return z.NEVER;
|
|
36280
|
-
});
|
|
36281
|
-
function resolveEventRegistrationScope(context) {
|
|
36282
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
36283
|
-
if (occurrenceSeriesId) return {
|
|
36284
|
-
kind: "occurrenceSeries",
|
|
36285
|
-
seriesId: occurrenceSeriesId
|
|
36463
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
36464
|
+
/**
|
|
36465
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
36466
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
36467
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
36468
|
+
*
|
|
36469
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
36470
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
36471
|
+
*/
|
|
36472
|
+
function getEventAvailability(event) {
|
|
36473
|
+
if (event.capacity == null) return {
|
|
36474
|
+
available: null,
|
|
36475
|
+
isFull: false
|
|
36286
36476
|
};
|
|
36287
|
-
|
|
36288
|
-
|
|
36289
|
-
|
|
36477
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
36478
|
+
if (available <= 0) return {
|
|
36479
|
+
available: 0,
|
|
36480
|
+
isFull: true
|
|
36290
36481
|
};
|
|
36291
|
-
|
|
36292
|
-
|
|
36293
|
-
|
|
36294
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
36482
|
+
return {
|
|
36483
|
+
available,
|
|
36484
|
+
isFull: false
|
|
36295
36485
|
};
|
|
36296
|
-
|
|
36297
|
-
|
|
36298
|
-
|
|
36486
|
+
}
|
|
36487
|
+
/**
|
|
36488
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
36489
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
36490
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
36491
|
+
*
|
|
36492
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
36493
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
36494
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
36495
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
36496
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
36497
|
+
*/
|
|
36498
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
36499
|
+
if (!attendanceMode) return event;
|
|
36500
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
36501
|
+
}
|
|
36502
|
+
/**
|
|
36503
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
36504
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
36505
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
36506
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
36507
|
+
* `capacity - registeredCount` fallback.
|
|
36508
|
+
*/
|
|
36509
|
+
function canJoinEventWaitlist(event, options) {
|
|
36510
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
36511
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
36512
|
+
}
|
|
36513
|
+
/**
|
|
36514
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
36515
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
36516
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
36517
|
+
* to be stale on a cached page.
|
|
36518
|
+
*
|
|
36519
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
36520
|
+
*
|
|
36521
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
36522
|
+
* 5% floor stops large events staying silent until three remain.
|
|
36523
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
36524
|
+
*/
|
|
36525
|
+
function lowCapacityThreshold(capacity) {
|
|
36526
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
36527
|
+
}
|
|
36528
|
+
function getRemainingPlaces(source) {
|
|
36529
|
+
const { available, isFull } = getEventAvailability(source);
|
|
36530
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
36531
|
+
if (isFull) return {
|
|
36532
|
+
kind: "full",
|
|
36533
|
+
waitlist: canJoinEventWaitlist(source)
|
|
36299
36534
|
};
|
|
36300
|
-
|
|
36535
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
36536
|
+
kind: "low",
|
|
36537
|
+
remaining: available
|
|
36538
|
+
};
|
|
36539
|
+
return { kind: "open" };
|
|
36301
36540
|
}
|
|
36302
|
-
|
|
36303
|
-
|
|
36304
|
-
|
|
36305
|
-
|
|
36306
|
-
|
|
36307
|
-
|
|
36308
|
-
|
|
36309
|
-
|
|
36310
|
-
|
|
36311
|
-
case "
|
|
36312
|
-
case "
|
|
36541
|
+
/**
|
|
36542
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
36543
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
36544
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
36545
|
+
* it in rather than re-deriving the count.
|
|
36546
|
+
*/
|
|
36547
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
36548
|
+
const remaining = getRemainingPlaces(source);
|
|
36549
|
+
switch (remaining.kind) {
|
|
36550
|
+
case "unlimited":
|
|
36551
|
+
case "open": return null;
|
|
36552
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
36553
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
36554
|
+
}
|
|
36555
|
+
}
|
|
36556
|
+
function formatPlacesLeft(count, compact) {
|
|
36557
|
+
if (compact) return `${count} left`;
|
|
36558
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
36559
|
+
}
|
|
36560
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
36561
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
36562
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
36563
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
36564
|
+
}
|
|
36565
|
+
/**
|
|
36566
|
+
* Which capacity figure wins when they disagree.
|
|
36567
|
+
*
|
|
36568
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
36569
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
36570
|
+
* The registration write path admits or refuses per mode
|
|
36571
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
36572
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
36573
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
36574
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
36575
|
+
*
|
|
36576
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
36577
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
36578
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
36579
|
+
* the aggregate, unchanged.
|
|
36580
|
+
*/
|
|
36581
|
+
function findHybridModeRows(event) {
|
|
36582
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
36583
|
+
const rows = event.attendanceModes ?? [];
|
|
36584
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
36585
|
+
const online = rows.find((row) => row.mode === "online");
|
|
36586
|
+
return inPerson && online ? {
|
|
36587
|
+
inPerson,
|
|
36588
|
+
online
|
|
36589
|
+
} : null;
|
|
36590
|
+
}
|
|
36591
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
36592
|
+
function remainingPlacesRank(remaining) {
|
|
36593
|
+
switch (remaining.kind) {
|
|
36594
|
+
case "unlimited": return 4;
|
|
36595
|
+
case "open": return 3;
|
|
36596
|
+
case "low": return 2;
|
|
36597
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
36598
|
+
}
|
|
36599
|
+
}
|
|
36600
|
+
function isMoreOpen(candidate, than) {
|
|
36601
|
+
const rank = remainingPlacesRank(candidate);
|
|
36602
|
+
const otherRank = remainingPlacesRank(than);
|
|
36603
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
36604
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
36605
|
+
}
|
|
36606
|
+
/** True when `candidate` has less room left than `than`. */
|
|
36607
|
+
function isScarcer(candidate, than) {
|
|
36608
|
+
return isMoreOpen(than, candidate);
|
|
36609
|
+
}
|
|
36610
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
36611
|
+
in_person: "In person",
|
|
36612
|
+
online: "Online"
|
|
36613
|
+
};
|
|
36614
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
36615
|
+
const PLACES_AVAILABLE = "Places available";
|
|
36616
|
+
/**
|
|
36617
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
36618
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
36619
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
36620
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
36621
|
+
* promise the registration wizard would otherwise have to break.
|
|
36622
|
+
*
|
|
36623
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
36624
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
36625
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
36626
|
+
* { compact: true } -> "Online: 3 left"
|
|
36627
|
+
*/
|
|
36628
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
36629
|
+
const rows = findHybridModeRows(event);
|
|
36630
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
36631
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
36632
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
36633
|
+
if (inPerson === online) return inPerson;
|
|
36634
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
36635
|
+
return formatBothHybridSides(rows, {
|
|
36636
|
+
inPerson,
|
|
36637
|
+
online
|
|
36638
|
+
});
|
|
36639
|
+
}
|
|
36640
|
+
/**
|
|
36641
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
36642
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
36643
|
+
*/
|
|
36644
|
+
function formatBothHybridSides(rows, labels) {
|
|
36645
|
+
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(" · ");
|
|
36646
|
+
}
|
|
36647
|
+
function namedModePlaces(mode, label) {
|
|
36648
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
36649
|
+
}
|
|
36650
|
+
/**
|
|
36651
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
36652
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
36653
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
36654
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
36655
|
+
* how the event is delivered rather than about its remaining places.
|
|
36656
|
+
*/
|
|
36657
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
36658
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
36659
|
+
const online = getRemainingPlaces(rows.online);
|
|
36660
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
36661
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
36662
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
36663
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
36664
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
36665
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
36313
36666
|
}
|
|
36667
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
36668
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
36669
|
+
}
|
|
36670
|
+
function rowFor(rows, mode) {
|
|
36671
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
36314
36672
|
}
|
|
36315
36673
|
//#endregion
|
|
36674
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
36675
|
+
const registrationDisplaySchema = z.object({
|
|
36676
|
+
venue: z.enum(["shown", "hidden"]),
|
|
36677
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
36678
|
+
});
|
|
36679
|
+
function resolveRegistrationDisplay(source) {
|
|
36680
|
+
return {
|
|
36681
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
36682
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
36683
|
+
};
|
|
36684
|
+
}
|
|
36685
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
36686
|
+
function shownVenue(event, display) {
|
|
36687
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
36688
|
+
}
|
|
36689
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
36690
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
36691
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
36692
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
36693
|
+
return capacityPlacesLabel(source, display, wording);
|
|
36694
|
+
}
|
|
36695
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
36696
|
+
const remaining = getRemainingPlaces(source);
|
|
36697
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
36698
|
+
switch (remaining.kind) {
|
|
36699
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
36700
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
36701
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
36702
|
+
case "open": return wording.open ?? null;
|
|
36703
|
+
default: return assertNever$2(remaining);
|
|
36704
|
+
}
|
|
36705
|
+
}
|
|
36706
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
36707
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
36708
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
36709
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
36710
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
36711
|
+
}).join(" · ") || null;
|
|
36712
|
+
}
|
|
36713
|
+
function ticketPlacesLabel(remaining, display) {
|
|
36714
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
36715
|
+
return formatTicketTypeRemaining(remaining);
|
|
36716
|
+
}
|
|
36717
|
+
//#endregion
|
|
36718
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
36719
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
36720
|
+
kind: z.literal("preview"),
|
|
36721
|
+
token: z.string().min(1)
|
|
36722
|
+
}).strict()]);
|
|
36723
|
+
//#endregion
|
|
36316
36724
|
//#region ../calendar/src/grid.ts
|
|
36317
36725
|
const MONTH_NAMES = [
|
|
36318
36726
|
"January",
|
|
@@ -36399,6 +36807,11 @@ function buildCalendarViewport(input) {
|
|
|
36399
36807
|
//#endregion
|
|
36400
36808
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
36401
36809
|
/**
|
|
36810
|
+
* Date and time presentation for events: the single place an event's
|
|
36811
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
36812
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
36813
|
+
*/
|
|
36814
|
+
/**
|
|
36402
36815
|
* The English locale a site's public dates are written in, read from the
|
|
36403
36816
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
36404
36817
|
*
|
|
@@ -36418,6 +36831,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
36418
36831
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
36419
36832
|
return "en-US";
|
|
36420
36833
|
}
|
|
36834
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
36835
|
+
const locale = options?.locale ?? "en-US";
|
|
36836
|
+
const dateTime = toScheduledBookingDateTime({
|
|
36837
|
+
startsAt: isoTimestamp,
|
|
36838
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
36839
|
+
locale
|
|
36840
|
+
});
|
|
36841
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
36842
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
36843
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
36844
|
+
return {
|
|
36845
|
+
weekday,
|
|
36846
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
36847
|
+
month,
|
|
36848
|
+
label: formatBookingDate(dateTime, {
|
|
36849
|
+
weekday: "long",
|
|
36850
|
+
year: "numeric",
|
|
36851
|
+
month: "long",
|
|
36852
|
+
day: "numeric"
|
|
36853
|
+
})
|
|
36854
|
+
};
|
|
36855
|
+
}
|
|
36421
36856
|
//#endregion
|
|
36422
36857
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
36423
36858
|
function isRecord$4(value) {
|
|
@@ -36437,6 +36872,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
36437
36872
|
};
|
|
36438
36873
|
}
|
|
36439
36874
|
//#endregion
|
|
36875
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
36876
|
+
/**
|
|
36877
|
+
* Format an event's price directly from its pricing value (without the full
|
|
36878
|
+
* event). Same output as {@link formatEventPrice}.
|
|
36879
|
+
*/
|
|
36880
|
+
function formatEventPriceDisplay(pricing) {
|
|
36881
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
36882
|
+
}
|
|
36883
|
+
//#endregion
|
|
36440
36884
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
36441
36885
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
36442
36886
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -36471,150 +36915,6 @@ function eventListWindowEvents(events, window) {
|
|
|
36471
36915
|
});
|
|
36472
36916
|
}
|
|
36473
36917
|
//#endregion
|
|
36474
|
-
//#region ../blocks/src/system/constants/events.ts
|
|
36475
|
-
const eventCalendarDisplayModeValues = [
|
|
36476
|
-
"combined",
|
|
36477
|
-
"calendar",
|
|
36478
|
-
"list",
|
|
36479
|
-
"timetable",
|
|
36480
|
-
"week-board"
|
|
36481
|
-
];
|
|
36482
|
-
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
36483
|
-
const eventCalendarListLayoutValues = [
|
|
36484
|
-
"stack",
|
|
36485
|
-
"grid",
|
|
36486
|
-
"compact"
|
|
36487
|
-
];
|
|
36488
|
-
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
36489
|
-
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
36490
|
-
const eventCalendarListLayoutOptions = [
|
|
36491
|
-
{
|
|
36492
|
-
id: "stack",
|
|
36493
|
-
label: "Stack"
|
|
36494
|
-
},
|
|
36495
|
-
{
|
|
36496
|
-
id: "grid",
|
|
36497
|
-
label: "Grid"
|
|
36498
|
-
},
|
|
36499
|
-
{
|
|
36500
|
-
id: "compact",
|
|
36501
|
-
label: "Compact"
|
|
36502
|
-
}
|
|
36503
|
-
];
|
|
36504
|
-
function isEventCalendarDisplayMode(value) {
|
|
36505
|
-
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
36506
|
-
}
|
|
36507
|
-
function normalizeEventCalendarDisplayMode$1(input) {
|
|
36508
|
-
if (isEventCalendarDisplayMode(input.variant)) return input.variant;
|
|
36509
|
-
return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : void 0;
|
|
36510
|
-
}
|
|
36511
|
-
/** One closed authority for the projections required by each rendered mode. */
|
|
36512
|
-
function resolveEventCalendarReadPlan(input) {
|
|
36513
|
-
const mode = normalizeEventCalendarDisplayMode$1(input) ?? "combined";
|
|
36514
|
-
switch (mode) {
|
|
36515
|
-
case "combined": return {
|
|
36516
|
-
mode,
|
|
36517
|
-
jobs: "both",
|
|
36518
|
-
readProfile: "listing-card"
|
|
36519
|
-
};
|
|
36520
|
-
case "list": return {
|
|
36521
|
-
mode,
|
|
36522
|
-
jobs: "list",
|
|
36523
|
-
readProfile: "listing-card"
|
|
36524
|
-
};
|
|
36525
|
-
case "calendar": return {
|
|
36526
|
-
mode,
|
|
36527
|
-
jobs: "calendar",
|
|
36528
|
-
readProfile: "listing-card"
|
|
36529
|
-
};
|
|
36530
|
-
case "timetable":
|
|
36531
|
-
case "week-board": return {
|
|
36532
|
-
mode,
|
|
36533
|
-
jobs: "calendar",
|
|
36534
|
-
readProfile: "timetable"
|
|
36535
|
-
};
|
|
36536
|
-
}
|
|
36537
|
-
}
|
|
36538
|
-
function isEventCalendarDefaultView(value) {
|
|
36539
|
-
return typeof value === "string" && eventCalendarDefaultViewValues.includes(value);
|
|
36540
|
-
}
|
|
36541
|
-
function isEventCalendarListLayout(value) {
|
|
36542
|
-
return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
|
|
36543
|
-
}
|
|
36544
|
-
/** The calendar manifest owns its secondary arrangement axis. */
|
|
36545
|
-
const eventCalendarVariantMeaning = {
|
|
36546
|
-
kind: "mode",
|
|
36547
|
-
arrangementField: "listLayout",
|
|
36548
|
-
keys: eventCalendarListLayoutValues,
|
|
36549
|
-
lookOnlyKeys: [
|
|
36550
|
-
...arrangementOnlyListLayouts,
|
|
36551
|
-
"month-grid",
|
|
36552
|
-
"month-day"
|
|
36553
|
-
],
|
|
36554
|
-
defaultKey: "stack",
|
|
36555
|
-
modeLabels: {
|
|
36556
|
-
list: "List",
|
|
36557
|
-
calendar: "Month",
|
|
36558
|
-
combined: "List and month",
|
|
36559
|
-
timetable: "Timetable",
|
|
36560
|
-
"week-board": "Week board"
|
|
36561
|
-
}
|
|
36562
|
-
};
|
|
36563
|
-
/** Weekly lists share the arrangement-Look admission used by calendar arrangements. */
|
|
36564
|
-
function eventCalendarListGroupingDecision(input) {
|
|
36565
|
-
const available = input.arrangementLooks && resolveEventCalendarReadPlan(input).mode === "list";
|
|
36566
|
-
return {
|
|
36567
|
-
available,
|
|
36568
|
-
grouping: available && input.listBy === "week" ? "week" : "upcoming"
|
|
36569
|
-
};
|
|
36570
|
-
}
|
|
36571
|
-
//#endregion
|
|
36572
|
-
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
36573
|
-
const previewStageSchema = z.enum(["preview", "published"]);
|
|
36574
|
-
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
36575
|
-
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
36576
|
-
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
36577
|
-
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
36578
|
-
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
36579
|
-
const columnOptionSchema = z.enum([
|
|
36580
|
-
"2",
|
|
36581
|
-
"3",
|
|
36582
|
-
"4"
|
|
36583
|
-
]);
|
|
36584
|
-
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
36585
|
-
const filterAutoShowSchema = z.enum([
|
|
36586
|
-
"auto",
|
|
36587
|
-
"always",
|
|
36588
|
-
"never"
|
|
36589
|
-
]);
|
|
36590
|
-
const calendarTabViewsSchema = z.enum([
|
|
36591
|
-
"both",
|
|
36592
|
-
"month",
|
|
36593
|
-
"week"
|
|
36594
|
-
]);
|
|
36595
|
-
//#endregion
|
|
36596
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
36597
|
-
/**
|
|
36598
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
36599
|
-
*
|
|
36600
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
36601
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
36602
|
-
* @returns Array of wizard steps to display
|
|
36603
|
-
*/
|
|
36604
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
36605
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
36606
|
-
"select-event",
|
|
36607
|
-
"select-tickets",
|
|
36608
|
-
"enter-details"
|
|
36609
|
-
];
|
|
36610
|
-
if (!needsPaymentStep) return baseSteps;
|
|
36611
|
-
return paymentActive ? [
|
|
36612
|
-
...baseSteps,
|
|
36613
|
-
"select-payment",
|
|
36614
|
-
"payment"
|
|
36615
|
-
] : [...baseSteps, "select-payment"];
|
|
36616
|
-
}
|
|
36617
|
-
//#endregion
|
|
36618
36918
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
36619
36919
|
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
36620
36920
|
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
@@ -36638,6 +36938,424 @@ function resolveEventRequiresPayment(input) {
|
|
|
36638
36938
|
return publicEventPricingType(input.event.pricing) === "paid";
|
|
36639
36939
|
}
|
|
36640
36940
|
//#endregion
|
|
36941
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
36942
|
+
/**
|
|
36943
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
36944
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
36945
|
+
* English when the site names no zone.
|
|
36946
|
+
*/
|
|
36947
|
+
function bookingDateLocale(siteTimeZone) {
|
|
36948
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
36949
|
+
}
|
|
36950
|
+
function bookingInstant(startsAt, input) {
|
|
36951
|
+
return toScheduledBookingDateTime({
|
|
36952
|
+
startsAt,
|
|
36953
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
36954
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
36955
|
+
});
|
|
36956
|
+
}
|
|
36957
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
36958
|
+
function bookingClock(startsAt, input) {
|
|
36959
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
36960
|
+
hour: "numeric",
|
|
36961
|
+
minute: "2-digit",
|
|
36962
|
+
hour12: true
|
|
36963
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
36964
|
+
}
|
|
36965
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
36966
|
+
function clockRange(input) {
|
|
36967
|
+
const start = bookingClock(input.startsAt, input);
|
|
36968
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
36969
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
36970
|
+
}
|
|
36971
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
36972
|
+
function formatBookingScheduleSummary(event) {
|
|
36973
|
+
const summary = event.scheduleSummary;
|
|
36974
|
+
if (!summary) return null;
|
|
36975
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
36976
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
36977
|
+
timeZone: "UTC",
|
|
36978
|
+
siteTimeZone: event.siteTimeZone
|
|
36979
|
+
}, "time") : null;
|
|
36980
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
36981
|
+
}
|
|
36982
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
36983
|
+
function formatBookingWhen(input, variant) {
|
|
36984
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
36985
|
+
const day = formatBookingDate(instant, {
|
|
36986
|
+
weekday: "short",
|
|
36987
|
+
day: "numeric",
|
|
36988
|
+
month: "short"
|
|
36989
|
+
});
|
|
36990
|
+
switch (variant) {
|
|
36991
|
+
case "day": return day;
|
|
36992
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
36993
|
+
weekday: "long",
|
|
36994
|
+
day: "numeric",
|
|
36995
|
+
month: "long"
|
|
36996
|
+
});
|
|
36997
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
36998
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
36999
|
+
month: "long",
|
|
37000
|
+
year: "numeric"
|
|
37001
|
+
});
|
|
37002
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
37003
|
+
case "timeRange": return clockRange(input);
|
|
37004
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
37005
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
37006
|
+
}
|
|
37007
|
+
}
|
|
37008
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
37009
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
37010
|
+
return formatBookingWhen({
|
|
37011
|
+
startsAt: isoTimestamp,
|
|
37012
|
+
timeZone: options?.timeZone,
|
|
37013
|
+
siteTimeZone: options?.siteTimeZone
|
|
37014
|
+
}, "short");
|
|
37015
|
+
}
|
|
37016
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
37017
|
+
function occurrenceTitleOverride(occurrence) {
|
|
37018
|
+
const title = occurrence?.overrides?.title;
|
|
37019
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
37020
|
+
}
|
|
37021
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
37022
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
37023
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
37024
|
+
return event && title ? {
|
|
37025
|
+
...event,
|
|
37026
|
+
title
|
|
37027
|
+
} : event;
|
|
37028
|
+
}
|
|
37029
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
37030
|
+
const first = sessions[0];
|
|
37031
|
+
if (!first) return null;
|
|
37032
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
37033
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
37034
|
+
timeZone: first.timeZone,
|
|
37035
|
+
siteTimeZone
|
|
37036
|
+
});
|
|
37037
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
37038
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
37039
|
+
timeZone: last.timeZone,
|
|
37040
|
+
siteTimeZone
|
|
37041
|
+
});
|
|
37042
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
37043
|
+
}
|
|
37044
|
+
/**
|
|
37045
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
37046
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
37047
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
37048
|
+
*/
|
|
37049
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
37050
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
37051
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
37052
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
37053
|
+
}
|
|
37054
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
37055
|
+
function scheduleInput(event, occurrence) {
|
|
37056
|
+
const times = occurrence?.startsAt ? {
|
|
37057
|
+
startsAt: occurrence.startsAt,
|
|
37058
|
+
endsAt: occurrence.endsAt ?? null
|
|
37059
|
+
} : {
|
|
37060
|
+
startsAt: event.startsAt,
|
|
37061
|
+
endsAt: event.endsAt
|
|
37062
|
+
};
|
|
37063
|
+
if (!times.startsAt) return null;
|
|
37064
|
+
return {
|
|
37065
|
+
...times,
|
|
37066
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
37067
|
+
siteTimeZone: event.siteTimeZone
|
|
37068
|
+
};
|
|
37069
|
+
}
|
|
37070
|
+
//#endregion
|
|
37071
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
37072
|
+
function registrationRoute(input) {
|
|
37073
|
+
const base = input.chooseEvent ? [
|
|
37074
|
+
"select-event",
|
|
37075
|
+
"select-tickets",
|
|
37076
|
+
"enter-details"
|
|
37077
|
+
] : ["select-tickets", "enter-details"];
|
|
37078
|
+
switch (input.payment) {
|
|
37079
|
+
case "none": return base;
|
|
37080
|
+
case "options": return [...base, "select-payment"];
|
|
37081
|
+
case "optionsAndPayment": return [
|
|
37082
|
+
...base,
|
|
37083
|
+
"select-payment",
|
|
37084
|
+
"payment"
|
|
37085
|
+
];
|
|
37086
|
+
}
|
|
37087
|
+
}
|
|
37088
|
+
const REGISTRATION_STEP_LABELS = [
|
|
37089
|
+
"Event",
|
|
37090
|
+
"Date",
|
|
37091
|
+
"Tickets",
|
|
37092
|
+
"Places",
|
|
37093
|
+
"Your details",
|
|
37094
|
+
"How you’ll pay",
|
|
37095
|
+
"Payment"
|
|
37096
|
+
];
|
|
37097
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
37098
|
+
function getEventSelectionMode(events) {
|
|
37099
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
37100
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
37101
|
+
}
|
|
37102
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
37103
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
37104
|
+
return {
|
|
37105
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
37106
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
37107
|
+
};
|
|
37108
|
+
}
|
|
37109
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
37110
|
+
function registrationStepLabel(step, context) {
|
|
37111
|
+
switch (step) {
|
|
37112
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
37113
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
37114
|
+
case "enter-details": return "Your details";
|
|
37115
|
+
case "select-payment": return "How you’ll pay";
|
|
37116
|
+
case "payment": return "Payment";
|
|
37117
|
+
}
|
|
37118
|
+
}
|
|
37119
|
+
function bookingButtonText(buttonText) {
|
|
37120
|
+
return buttonText?.trim() || "Book your place";
|
|
37121
|
+
}
|
|
37122
|
+
function placesLabel(event, input, compact) {
|
|
37123
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
37124
|
+
}
|
|
37125
|
+
function isFull(event, mode) {
|
|
37126
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
37127
|
+
full: "full",
|
|
37128
|
+
waitlist: "full"
|
|
37129
|
+
}) === "full";
|
|
37130
|
+
}
|
|
37131
|
+
function priceLabel(event) {
|
|
37132
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
37133
|
+
}
|
|
37134
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
37135
|
+
function lowestPaidAmount(display) {
|
|
37136
|
+
switch (display.kind) {
|
|
37137
|
+
case "exact":
|
|
37138
|
+
case "from": return display.amount;
|
|
37139
|
+
case "range": return display.minAmount;
|
|
37140
|
+
case "mixed": return display.paidFromAmount;
|
|
37141
|
+
case "free":
|
|
37142
|
+
case "unavailable":
|
|
37143
|
+
case "external": return null;
|
|
37144
|
+
}
|
|
37145
|
+
}
|
|
37146
|
+
/**
|
|
37147
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
37148
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
37149
|
+
*/
|
|
37150
|
+
function seriesPriceLabel(events) {
|
|
37151
|
+
const firstEvent = events[0];
|
|
37152
|
+
if (!firstEvent) return null;
|
|
37153
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
37154
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
37155
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
37156
|
+
const lowest = displays.flatMap((display) => {
|
|
37157
|
+
const amount = lowestPaidAmount(display);
|
|
37158
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
37159
|
+
amount,
|
|
37160
|
+
currency: display.currency
|
|
37161
|
+
}];
|
|
37162
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
37163
|
+
return lowest ? formatBookingPriceDisplay({
|
|
37164
|
+
kind: "from",
|
|
37165
|
+
amount: lowest.amount,
|
|
37166
|
+
currency: lowest.currency
|
|
37167
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
37168
|
+
}
|
|
37169
|
+
function dateTile(event) {
|
|
37170
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
37171
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
37172
|
+
return {
|
|
37173
|
+
month: rail.month,
|
|
37174
|
+
day: rail.day
|
|
37175
|
+
};
|
|
37176
|
+
}
|
|
37177
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
37178
|
+
function formatBookingShortDate(event) {
|
|
37179
|
+
return formatBookingWhen(event, "day");
|
|
37180
|
+
}
|
|
37181
|
+
function byStart(left, right) {
|
|
37182
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
37183
|
+
}
|
|
37184
|
+
function singleEntry(event, input) {
|
|
37185
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
37186
|
+
return {
|
|
37187
|
+
kind: "single",
|
|
37188
|
+
title: event.title,
|
|
37189
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
37190
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
37191
|
+
venue: shownVenue(event, input.display),
|
|
37192
|
+
price: priceLabel(event),
|
|
37193
|
+
places: placesLabel(event, input, false),
|
|
37194
|
+
tile: dateTile(event),
|
|
37195
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
37196
|
+
};
|
|
37197
|
+
}
|
|
37198
|
+
function chooseDateEntry(input) {
|
|
37199
|
+
const ordered = [...input.events].sort(byStart);
|
|
37200
|
+
const first = ordered[0];
|
|
37201
|
+
const shown = ordered.slice(0, 4);
|
|
37202
|
+
return {
|
|
37203
|
+
kind: "chooseDate",
|
|
37204
|
+
title: first?.title ?? "",
|
|
37205
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
37206
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
37207
|
+
price: seriesPriceLabel(ordered),
|
|
37208
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
37209
|
+
dateCount: ordered.length,
|
|
37210
|
+
dates: shown.map((event) => ({
|
|
37211
|
+
selectionId: event.selectionId,
|
|
37212
|
+
label: formatBookingShortDate(event),
|
|
37213
|
+
places: placesLabel(event, input, true),
|
|
37214
|
+
full: isFull(event, input.attendanceMode)
|
|
37215
|
+
})),
|
|
37216
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
37217
|
+
action: "Choose a date"
|
|
37218
|
+
};
|
|
37219
|
+
}
|
|
37220
|
+
/** The card before a booking starts; the server renders this too. */
|
|
37221
|
+
function idleBookingEntry(input) {
|
|
37222
|
+
if (input.event) return singleEntry(input.event, input);
|
|
37223
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
37224
|
+
if (only) return singleEntry(only, input);
|
|
37225
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
37226
|
+
return {
|
|
37227
|
+
kind: "chooseEvent",
|
|
37228
|
+
title: input.events[0]?.title ?? "",
|
|
37229
|
+
count: input.events.length,
|
|
37230
|
+
noun: input.noun.pluralLabel,
|
|
37231
|
+
action: "Choose an event"
|
|
37232
|
+
};
|
|
37233
|
+
}
|
|
37234
|
+
//#endregion
|
|
37235
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
37236
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
37237
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
37238
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
37239
|
+
{
|
|
37240
|
+
preset: "class",
|
|
37241
|
+
sourceKey: "eventPreset:class",
|
|
37242
|
+
dataKey: "classEvents",
|
|
37243
|
+
label: "Classes"
|
|
37244
|
+
},
|
|
37245
|
+
{
|
|
37246
|
+
preset: "workshop",
|
|
37247
|
+
sourceKey: "eventPreset:workshop",
|
|
37248
|
+
dataKey: "workshopEvents",
|
|
37249
|
+
label: "Workshops"
|
|
37250
|
+
},
|
|
37251
|
+
{
|
|
37252
|
+
preset: "retreat",
|
|
37253
|
+
sourceKey: "eventPreset:retreat",
|
|
37254
|
+
dataKey: "retreatEvents",
|
|
37255
|
+
label: "Retreats"
|
|
37256
|
+
},
|
|
37257
|
+
{
|
|
37258
|
+
preset: "performance",
|
|
37259
|
+
sourceKey: "eventPreset:performance",
|
|
37260
|
+
dataKey: "performanceEvents",
|
|
37261
|
+
label: "Performances"
|
|
37262
|
+
}
|
|
37263
|
+
];
|
|
37264
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
37265
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
37266
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
37267
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
37268
|
+
kind: "eventPreset",
|
|
37269
|
+
preset: definition.preset
|
|
37270
|
+
}]));
|
|
37271
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
37272
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
37273
|
+
}
|
|
37274
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
37275
|
+
if (value == null) return { kind: "legacy" };
|
|
37276
|
+
if (value.length === 0) return { kind: "default" };
|
|
37277
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
37278
|
+
return keys.length > 0 ? {
|
|
37279
|
+
kind: "custom",
|
|
37280
|
+
keys
|
|
37281
|
+
} : { kind: "default" };
|
|
37282
|
+
}
|
|
37283
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
37284
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
37285
|
+
return keys.length >= 2 ? keys : [];
|
|
37286
|
+
}
|
|
37287
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
37288
|
+
if (!isRecord$3(value)) return null;
|
|
37289
|
+
const groupOrderValue = value.groupOrder;
|
|
37290
|
+
if (Array.isArray(groupOrderValue)) {
|
|
37291
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
37292
|
+
return {
|
|
37293
|
+
...value,
|
|
37294
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
37295
|
+
};
|
|
37296
|
+
}
|
|
37297
|
+
if (groupOrderValue != null) return {
|
|
37298
|
+
...value,
|
|
37299
|
+
groupOrder: []
|
|
37300
|
+
};
|
|
37301
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$3) : []);
|
|
37302
|
+
return legacyOrder.length > 0 ? {
|
|
37303
|
+
...value,
|
|
37304
|
+
groupOrder: legacyOrder
|
|
37305
|
+
} : value;
|
|
37306
|
+
}
|
|
37307
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
37308
|
+
function sourceFromPresetSummary(preset) {
|
|
37309
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
37310
|
+
if (preset.engine !== "event_series") return null;
|
|
37311
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
37312
|
+
kind: "eventPreset",
|
|
37313
|
+
preset: preset.canonicalBehaviour
|
|
37314
|
+
};
|
|
37315
|
+
return null;
|
|
37316
|
+
}
|
|
37317
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
37318
|
+
const keys = [];
|
|
37319
|
+
for (const value of values) {
|
|
37320
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
37321
|
+
if (!keys.includes(value)) keys.push(value);
|
|
37322
|
+
}
|
|
37323
|
+
return keys;
|
|
37324
|
+
}
|
|
37325
|
+
function isRecord$3(value) {
|
|
37326
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37327
|
+
}
|
|
37328
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
37329
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
37330
|
+
}
|
|
37331
|
+
//#endregion
|
|
37332
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
37333
|
+
function offeringKindForEvent(event) {
|
|
37334
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
37335
|
+
}
|
|
37336
|
+
function presetKind(preset) {
|
|
37337
|
+
const source = sourceFromPresetSummary(preset);
|
|
37338
|
+
if (!source) return null;
|
|
37339
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
37340
|
+
}
|
|
37341
|
+
/**
|
|
37342
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
37343
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
37344
|
+
* name stands in when the site has none.
|
|
37345
|
+
*/
|
|
37346
|
+
function offeringNounForEvent(event, presets) {
|
|
37347
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
37348
|
+
const kind = offeringKindForEvent(event);
|
|
37349
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
37350
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
37351
|
+
}
|
|
37352
|
+
function lowerCased(noun) {
|
|
37353
|
+
return {
|
|
37354
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
37355
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
37356
|
+
};
|
|
37357
|
+
}
|
|
37358
|
+
//#endregion
|
|
36641
37359
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
36642
37360
|
function toRegistrationEvent(event) {
|
|
36643
37361
|
return {
|
|
@@ -36682,6 +37400,279 @@ function toWholeSeriesRegistrationEvents(events) {
|
|
|
36682
37400
|
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
36683
37401
|
}
|
|
36684
37402
|
//#endregion
|
|
37403
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
37404
|
+
/**
|
|
37405
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
37406
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
37407
|
+
* so the server and the client agree on one card.
|
|
37408
|
+
*/
|
|
37409
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
37410
|
+
const tileSchema = z.object({
|
|
37411
|
+
month: z.string(),
|
|
37412
|
+
day: z.string()
|
|
37413
|
+
}).nullable();
|
|
37414
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
37415
|
+
z.object({
|
|
37416
|
+
kind: z.literal("single"),
|
|
37417
|
+
title: z.string(),
|
|
37418
|
+
when: z.string().nullable(),
|
|
37419
|
+
shortWhen: z.string().nullable(),
|
|
37420
|
+
venue: z.string().nullable(),
|
|
37421
|
+
price: z.string().nullable(),
|
|
37422
|
+
places: z.string().nullable(),
|
|
37423
|
+
tile: tileSchema,
|
|
37424
|
+
action: z.string()
|
|
37425
|
+
}),
|
|
37426
|
+
z.object({
|
|
37427
|
+
kind: z.literal("chooseDate"),
|
|
37428
|
+
title: z.string(),
|
|
37429
|
+
schedule: z.string(),
|
|
37430
|
+
venue: z.string().nullable(),
|
|
37431
|
+
price: z.string().nullable(),
|
|
37432
|
+
nextDate: z.string().nullable(),
|
|
37433
|
+
dateCount: z.number(),
|
|
37434
|
+
dates: z.array(z.object({
|
|
37435
|
+
selectionId: z.string(),
|
|
37436
|
+
label: z.string(),
|
|
37437
|
+
places: z.string().nullable(),
|
|
37438
|
+
full: z.boolean()
|
|
37439
|
+
})),
|
|
37440
|
+
moreCount: z.number(),
|
|
37441
|
+
action: z.string()
|
|
37442
|
+
}),
|
|
37443
|
+
z.object({
|
|
37444
|
+
kind: z.literal("chooseEvent"),
|
|
37445
|
+
title: z.string(),
|
|
37446
|
+
count: z.number(),
|
|
37447
|
+
noun: z.string(),
|
|
37448
|
+
action: z.string()
|
|
37449
|
+
})
|
|
37450
|
+
]);
|
|
37451
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
37452
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
37453
|
+
}
|
|
37454
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
37455
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37456
|
+
return {
|
|
37457
|
+
scopedEvents,
|
|
37458
|
+
preSelected: findPreSelectedEvent({
|
|
37459
|
+
scopedEvents,
|
|
37460
|
+
occurrenceContext: source.occurrenceContext
|
|
37461
|
+
})
|
|
37462
|
+
};
|
|
37463
|
+
}
|
|
37464
|
+
function nounFor(scoped, presets) {
|
|
37465
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
37466
|
+
}
|
|
37467
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
37468
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
37469
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
37470
|
+
}
|
|
37471
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
37472
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
37473
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
37474
|
+
return idleBookingEntry({
|
|
37475
|
+
events: scoped.scopedEvents,
|
|
37476
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
37477
|
+
display,
|
|
37478
|
+
buttonText: source.buttonText,
|
|
37479
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
37480
|
+
attendanceMode: null
|
|
37481
|
+
});
|
|
37482
|
+
}
|
|
37483
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
37484
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
37485
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
37486
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
37487
|
+
if (!entry) return null;
|
|
37488
|
+
return {
|
|
37489
|
+
kind: "event-registration",
|
|
37490
|
+
state: "booking-card",
|
|
37491
|
+
className: source.className ?? null,
|
|
37492
|
+
entry,
|
|
37493
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
37494
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
37495
|
+
};
|
|
37496
|
+
}
|
|
37497
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
37498
|
+
kind: z.literal("unsupported"),
|
|
37499
|
+
reason: z.enum([
|
|
37500
|
+
"unsupportedSubject",
|
|
37501
|
+
"invalidEventSeriesId",
|
|
37502
|
+
"invalidEventSeriesBookingScope",
|
|
37503
|
+
"invalidEventOfferingId",
|
|
37504
|
+
"invalidEventOfferingBookingScope",
|
|
37505
|
+
"invalidEventOfferingCatalogue"
|
|
37506
|
+
])
|
|
37507
|
+
});
|
|
37508
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
37509
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
37510
|
+
if (unsupported.success) return unsupported.data;
|
|
37511
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
37512
|
+
if (parsed.ok) return parsed.value;
|
|
37513
|
+
ctx.addIssue({
|
|
37514
|
+
code: z.ZodIssueCode.custom,
|
|
37515
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
37516
|
+
});
|
|
37517
|
+
return z.NEVER;
|
|
37518
|
+
});
|
|
37519
|
+
function resolveEventRegistrationScope(context) {
|
|
37520
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
37521
|
+
if (occurrenceSeriesId) return {
|
|
37522
|
+
kind: "occurrenceSeries",
|
|
37523
|
+
seriesId: occurrenceSeriesId
|
|
37524
|
+
};
|
|
37525
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
37526
|
+
kind: "pageSurfaceSeries",
|
|
37527
|
+
seriesId: context.subject.eventSeriesId
|
|
37528
|
+
};
|
|
37529
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
37530
|
+
kind: "pageSurfaceOffering",
|
|
37531
|
+
offeringId: context.subject.eventOfferingId,
|
|
37532
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
37533
|
+
};
|
|
37534
|
+
if (context.subject?.kind === "unsupported") return {
|
|
37535
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
37536
|
+
reason: context.subject.reason
|
|
37537
|
+
};
|
|
37538
|
+
return { kind: "unscoped" };
|
|
37539
|
+
}
|
|
37540
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
37541
|
+
const scope = resolveEventRegistrationScope(context);
|
|
37542
|
+
switch (scope.kind) {
|
|
37543
|
+
case "occurrenceSeries":
|
|
37544
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
37545
|
+
case "pageSurfaceOffering": {
|
|
37546
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
37547
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
37548
|
+
}
|
|
37549
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
37550
|
+
case "unscoped": return [...events];
|
|
37551
|
+
}
|
|
37552
|
+
}
|
|
37553
|
+
//#endregion
|
|
37554
|
+
//#region ../blocks/src/system/constants/events.ts
|
|
37555
|
+
const eventCalendarDisplayModeValues = [
|
|
37556
|
+
"combined",
|
|
37557
|
+
"calendar",
|
|
37558
|
+
"list",
|
|
37559
|
+
"timetable",
|
|
37560
|
+
"week-board"
|
|
37561
|
+
];
|
|
37562
|
+
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
37563
|
+
const eventCalendarListLayoutValues = [
|
|
37564
|
+
"stack",
|
|
37565
|
+
"grid",
|
|
37566
|
+
"compact"
|
|
37567
|
+
];
|
|
37568
|
+
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
37569
|
+
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
37570
|
+
const eventCalendarListLayoutOptions = [
|
|
37571
|
+
{
|
|
37572
|
+
id: "stack",
|
|
37573
|
+
label: "Stack"
|
|
37574
|
+
},
|
|
37575
|
+
{
|
|
37576
|
+
id: "grid",
|
|
37577
|
+
label: "Grid"
|
|
37578
|
+
},
|
|
37579
|
+
{
|
|
37580
|
+
id: "compact",
|
|
37581
|
+
label: "Compact"
|
|
37582
|
+
}
|
|
37583
|
+
];
|
|
37584
|
+
function isEventCalendarDisplayMode(value) {
|
|
37585
|
+
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
37586
|
+
}
|
|
37587
|
+
function normalizeEventCalendarDisplayMode$1(input) {
|
|
37588
|
+
if (isEventCalendarDisplayMode(input.variant)) return input.variant;
|
|
37589
|
+
return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : void 0;
|
|
37590
|
+
}
|
|
37591
|
+
/** One closed authority for the projections required by each rendered mode. */
|
|
37592
|
+
function resolveEventCalendarReadPlan(input) {
|
|
37593
|
+
const mode = normalizeEventCalendarDisplayMode$1(input) ?? "combined";
|
|
37594
|
+
switch (mode) {
|
|
37595
|
+
case "combined": return {
|
|
37596
|
+
mode,
|
|
37597
|
+
jobs: "both",
|
|
37598
|
+
readProfile: "listing-card"
|
|
37599
|
+
};
|
|
37600
|
+
case "list": return {
|
|
37601
|
+
mode,
|
|
37602
|
+
jobs: "list",
|
|
37603
|
+
readProfile: "listing-card"
|
|
37604
|
+
};
|
|
37605
|
+
case "calendar": return {
|
|
37606
|
+
mode,
|
|
37607
|
+
jobs: "calendar",
|
|
37608
|
+
readProfile: "listing-card"
|
|
37609
|
+
};
|
|
37610
|
+
case "timetable":
|
|
37611
|
+
case "week-board": return {
|
|
37612
|
+
mode,
|
|
37613
|
+
jobs: "calendar",
|
|
37614
|
+
readProfile: "timetable"
|
|
37615
|
+
};
|
|
37616
|
+
}
|
|
37617
|
+
}
|
|
37618
|
+
function isEventCalendarDefaultView(value) {
|
|
37619
|
+
return typeof value === "string" && eventCalendarDefaultViewValues.includes(value);
|
|
37620
|
+
}
|
|
37621
|
+
function isEventCalendarListLayout(value) {
|
|
37622
|
+
return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
|
|
37623
|
+
}
|
|
37624
|
+
/** The calendar manifest owns its secondary arrangement axis. */
|
|
37625
|
+
const eventCalendarVariantMeaning = {
|
|
37626
|
+
kind: "mode",
|
|
37627
|
+
arrangementField: "listLayout",
|
|
37628
|
+
keys: eventCalendarListLayoutValues,
|
|
37629
|
+
lookOnlyKeys: [
|
|
37630
|
+
...arrangementOnlyListLayouts,
|
|
37631
|
+
"month-grid",
|
|
37632
|
+
"month-day"
|
|
37633
|
+
],
|
|
37634
|
+
defaultKey: "stack",
|
|
37635
|
+
modeLabels: {
|
|
37636
|
+
list: "List",
|
|
37637
|
+
calendar: "Month",
|
|
37638
|
+
combined: "List and month",
|
|
37639
|
+
timetable: "Timetable",
|
|
37640
|
+
"week-board": "Week board"
|
|
37641
|
+
}
|
|
37642
|
+
};
|
|
37643
|
+
/** Weekly lists share the arrangement-Look admission used by calendar arrangements. */
|
|
37644
|
+
function eventCalendarListGroupingDecision(input) {
|
|
37645
|
+
const available = input.arrangementLooks && resolveEventCalendarReadPlan(input).mode === "list";
|
|
37646
|
+
return {
|
|
37647
|
+
available,
|
|
37648
|
+
grouping: available && input.listBy === "week" ? "week" : "upcoming"
|
|
37649
|
+
};
|
|
37650
|
+
}
|
|
37651
|
+
//#endregion
|
|
37652
|
+
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
37653
|
+
const previewStageSchema = z.enum(["preview", "published"]);
|
|
37654
|
+
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
37655
|
+
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
37656
|
+
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
37657
|
+
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
37658
|
+
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
37659
|
+
const columnOptionSchema = z.enum([
|
|
37660
|
+
"2",
|
|
37661
|
+
"3",
|
|
37662
|
+
"4"
|
|
37663
|
+
]);
|
|
37664
|
+
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
37665
|
+
const filterAutoShowSchema = z.enum([
|
|
37666
|
+
"auto",
|
|
37667
|
+
"always",
|
|
37668
|
+
"never"
|
|
37669
|
+
]);
|
|
37670
|
+
const calendarTabViewsSchema = z.enum([
|
|
37671
|
+
"both",
|
|
37672
|
+
"month",
|
|
37673
|
+
"week"
|
|
37674
|
+
]);
|
|
37675
|
+
//#endregion
|
|
36685
37676
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
36686
37677
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
36687
37678
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -36724,27 +37715,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
36724
37715
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
36725
37716
|
"Date",
|
|
36726
37717
|
"Tickets",
|
|
36727
|
-
"
|
|
36728
|
-
];
|
|
36729
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
36730
|
-
"Event",
|
|
36731
|
-
"Date",
|
|
36732
|
-
"Tickets",
|
|
36733
|
-
"Details",
|
|
36734
|
-
"Payment options",
|
|
36735
|
-
"Payment"
|
|
37718
|
+
"Your details"
|
|
36736
37719
|
];
|
|
36737
37720
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
36738
|
-
const
|
|
37721
|
+
const eventRegistrationCommonSchemaShape = {
|
|
36739
37722
|
demoEmailSuppressed: z.boolean().optional(),
|
|
36740
37723
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
36741
37724
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
36742
37725
|
maxTickets: z.string().optional(),
|
|
36743
|
-
showVenue: z.boolean().optional(),
|
|
36744
|
-
showCapacity: z.boolean().optional(),
|
|
36745
37726
|
successMessage: z.string().optional(),
|
|
36746
37727
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
36747
|
-
|
|
37728
|
+
host: bookingHostSchema.optional(),
|
|
36748
37729
|
spamProtectionEnabled: z.boolean().optional(),
|
|
36749
37730
|
supportEmail: z.string().optional(),
|
|
36750
37731
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -36769,32 +37750,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
36769
37750
|
portalToken: z.string().nullable().optional(),
|
|
36770
37751
|
previewToken: z.string().nullable().optional(),
|
|
36771
37752
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36772
|
-
...
|
|
37753
|
+
...eventRegistrationCommonSchemaShape,
|
|
37754
|
+
showVenue: z.boolean().optional(),
|
|
37755
|
+
showCapacity: z.boolean().optional(),
|
|
36773
37756
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36774
37757
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36775
37758
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
36776
37759
|
className: z.string().nullable().optional(),
|
|
36777
37760
|
buttonText: z.string().nullable().optional(),
|
|
36778
37761
|
maxTickets: z.string().nullable().optional(),
|
|
36779
|
-
stage: previewStageSchema.optional()
|
|
37762
|
+
stage: previewStageSchema.optional(),
|
|
37763
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
36780
37764
|
});
|
|
36781
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
36793
|
-
|
|
36794
|
-
|
|
36795
|
-
|
|
37765
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
37766
|
+
z.object({
|
|
37767
|
+
kind: z.literal("event-registration"),
|
|
37768
|
+
state: z.literal("generic-shell"),
|
|
37769
|
+
className: z.string().nullable(),
|
|
37770
|
+
titleText: z.string(),
|
|
37771
|
+
bodyText: z.string(),
|
|
37772
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
37773
|
+
summaryButtonText: z.string()
|
|
37774
|
+
}),
|
|
37775
|
+
z.object({
|
|
37776
|
+
kind: z.literal("event-registration"),
|
|
37777
|
+
state: z.literal("registration-closed"),
|
|
37778
|
+
className: z.string().nullable(),
|
|
37779
|
+
titleText: z.string(),
|
|
37780
|
+
bodyText: z.string()
|
|
37781
|
+
}),
|
|
37782
|
+
z.object({
|
|
37783
|
+
kind: z.literal("event-registration"),
|
|
37784
|
+
state: z.literal("booking-card"),
|
|
37785
|
+
className: z.string().nullable(),
|
|
37786
|
+
entry: idleBookingEntrySchema,
|
|
37787
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
37788
|
+
buttonText: z.string()
|
|
37789
|
+
})
|
|
37790
|
+
]);
|
|
36796
37791
|
const eventRegistrationHydrationSchema = z.object({
|
|
36797
|
-
...
|
|
37792
|
+
...eventRegistrationCommonSchemaShape,
|
|
37793
|
+
display: registrationDisplaySchema,
|
|
37794
|
+
offeringNoun: z.object({
|
|
37795
|
+
label: z.string(),
|
|
37796
|
+
pluralLabel: z.string()
|
|
37797
|
+
}).optional(),
|
|
36798
37798
|
eventSource: eventRegistrationEventSourceSchema
|
|
36799
37799
|
});
|
|
36800
37800
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -36809,7 +37809,7 @@ z.object({
|
|
|
36809
37809
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36810
37810
|
stage: previewStageSchema.optional()
|
|
36811
37811
|
});
|
|
36812
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
37812
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
36813
37813
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
36814
37814
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
36815
37815
|
kind: "event-registration",
|
|
@@ -36818,6 +37818,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
36818
37818
|
titleText: "Registration closed",
|
|
36819
37819
|
bodyText: "This run is no longer open for bookings."
|
|
36820
37820
|
};
|
|
37821
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
37822
|
+
if (card) return card;
|
|
36821
37823
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
36822
37824
|
return {
|
|
36823
37825
|
kind: "event-registration",
|
|
@@ -36834,11 +37836,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36834
37836
|
if (selectedRun) {
|
|
36835
37837
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
36836
37838
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
36837
|
-
return
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
|
|
36841
|
-
|
|
37839
|
+
return shellStepLabels(registrationRoute({
|
|
37840
|
+
chooseEvent: false,
|
|
37841
|
+
payment: resolveEventRequiresPayment({
|
|
37842
|
+
eligibility: null,
|
|
37843
|
+
selectedTicketType: null,
|
|
37844
|
+
event: selectedEvent
|
|
37845
|
+
}) ? "optionsAndPayment" : "none"
|
|
37846
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
36842
37847
|
}
|
|
36843
37848
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
36844
37849
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -36847,14 +37852,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36847
37852
|
occurrenceContext: source.occurrenceContext
|
|
36848
37853
|
});
|
|
36849
37854
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
36850
|
-
|
|
37855
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
36851
37856
|
eligibility: null,
|
|
36852
37857
|
selectedTicketType: null,
|
|
36853
37858
|
event: preSelectedEvent
|
|
36854
|
-
}) : false
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
37859
|
+
}) : false;
|
|
37860
|
+
return shellStepLabels(registrationRoute({
|
|
37861
|
+
chooseEvent: !hasPreSelectedContext,
|
|
37862
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
37863
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
36858
37864
|
}
|
|
36859
37865
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
36860
37866
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -36870,29 +37876,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
36870
37876
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
36871
37877
|
return runs.length === 1 ? runs[0] : null;
|
|
36872
37878
|
}
|
|
36873
|
-
function
|
|
36874
|
-
|
|
36875
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
36876
|
-
case "select-tickets": return "Tickets";
|
|
36877
|
-
case "enter-details": return "Details";
|
|
36878
|
-
case "select-payment": return "Payment options";
|
|
36879
|
-
case "payment": return "Payment";
|
|
36880
|
-
case "error":
|
|
36881
|
-
case "success":
|
|
36882
|
-
case "submitting":
|
|
36883
|
-
case "verifying-payment":
|
|
36884
|
-
case "verifying-timeout":
|
|
36885
|
-
case "payment-status":
|
|
36886
|
-
case "payment-failed": return "Details";
|
|
36887
|
-
}
|
|
36888
|
-
}
|
|
36889
|
-
function isDateSelection(events) {
|
|
36890
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
36891
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
37879
|
+
function shellStepLabels(route, context) {
|
|
37880
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
36892
37881
|
}
|
|
36893
37882
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
36894
|
-
if (stepLabels.includes("
|
|
36895
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
37883
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
37884
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
36896
37885
|
return "Preparing dates, tickets, and booking details.";
|
|
36897
37886
|
}
|
|
36898
37887
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -36902,6 +37891,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36902
37891
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
36903
37892
|
},
|
|
36904
37893
|
buildRender: (source) => {
|
|
37894
|
+
const display = resolveRegistrationDisplay(source);
|
|
36905
37895
|
const eventSource = resolveEventRegistrationEventSource({
|
|
36906
37896
|
events: source.events,
|
|
36907
37897
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -36909,7 +37899,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36909
37899
|
});
|
|
36910
37900
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
36911
37901
|
return {
|
|
36912
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
37902
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
36913
37903
|
hydration: {
|
|
36914
37904
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
36915
37905
|
subject: source.subject ?? null,
|
|
@@ -36919,29 +37909,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36919
37909
|
} : eventSource,
|
|
36920
37910
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
36921
37911
|
maxTickets: source.maxTickets ?? void 0,
|
|
36922
|
-
|
|
36923
|
-
showCapacity: source.showCapacity,
|
|
37912
|
+
display,
|
|
36924
37913
|
successMessage: source.successMessage,
|
|
36925
37914
|
buttonVariant: source.buttonVariant,
|
|
36926
|
-
|
|
37915
|
+
host: source.host ?? "overlay",
|
|
36927
37916
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
36928
37917
|
supportEmail: source.supportEmail,
|
|
36929
37918
|
sitePasses: source.sitePasses ?? null,
|
|
36930
37919
|
siteMemberships: source.siteMemberships ?? null,
|
|
36931
37920
|
mailingList: source.mailingList,
|
|
36932
|
-
siteName: source.siteName
|
|
37921
|
+
siteName: source.siteName,
|
|
37922
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
36933
37923
|
}
|
|
36934
37924
|
};
|
|
36935
37925
|
}
|
|
36936
37926
|
});
|
|
36937
37927
|
function normalizeEventRegistrationEventInput(value) {
|
|
36938
|
-
if (!isRecord$
|
|
37928
|
+
if (!isRecord$2(value)) return value;
|
|
36939
37929
|
return {
|
|
36940
37930
|
...value,
|
|
36941
37931
|
destination: resolveRuntimeEventDestination(value)
|
|
36942
37932
|
};
|
|
36943
37933
|
}
|
|
36944
|
-
function isRecord$
|
|
37934
|
+
function isRecord$2(value) {
|
|
36945
37935
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36946
37936
|
}
|
|
36947
37937
|
const eventRegistrationBlockDefinition = {
|
|
@@ -36981,7 +37971,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
36981
37971
|
description: "Main heading for the registration form",
|
|
36982
37972
|
required: false,
|
|
36983
37973
|
multiline: false,
|
|
36984
|
-
defaultValue: "
|
|
37974
|
+
defaultValue: ""
|
|
36985
37975
|
},
|
|
36986
37976
|
{
|
|
36987
37977
|
id: "description",
|
|
@@ -37053,11 +38043,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
37053
38043
|
{
|
|
37054
38044
|
id: "buttonText",
|
|
37055
38045
|
type: "text",
|
|
37056
|
-
label: "
|
|
37057
|
-
description: "Text
|
|
38046
|
+
label: "Button text",
|
|
38047
|
+
description: "Text on the booking button",
|
|
37058
38048
|
required: false,
|
|
37059
38049
|
multiline: false,
|
|
37060
|
-
defaultValue: "
|
|
38050
|
+
defaultValue: "Book your place",
|
|
37061
38051
|
maxLength: 40
|
|
37062
38052
|
},
|
|
37063
38053
|
createButtonVariantField()
|
|
@@ -37089,21 +38079,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
37089
38079
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
37090
38080
|
buttonText: { $bind: {
|
|
37091
38081
|
from: "content.buttonText",
|
|
37092
|
-
fallback: "
|
|
38082
|
+
fallback: "Book your place"
|
|
37093
38083
|
} },
|
|
37094
38084
|
buttonVariant: { $bind: {
|
|
37095
38085
|
from: "content.buttonVariant",
|
|
37096
38086
|
fallback: "primary"
|
|
37097
38087
|
} },
|
|
37098
|
-
overlayEnabled: { $bind: {
|
|
37099
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
37100
|
-
fallback: false
|
|
37101
|
-
} },
|
|
37102
38088
|
events: { $bind: { from: "data.events" } },
|
|
37103
38089
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
37104
38090
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
37105
38091
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
37106
38092
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
38093
|
+
bookingOfferingPresets: { $bind: {
|
|
38094
|
+
from: "$root.bookingOfferingPresets",
|
|
38095
|
+
fallback: []
|
|
38096
|
+
} },
|
|
37107
38097
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
37108
38098
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
37109
38099
|
stage: { $bind: {
|
|
@@ -39764,7 +40754,21 @@ const eventCalendarBlockDefinition = {
|
|
|
39764
40754
|
list: { label: "List" }
|
|
39765
40755
|
}
|
|
39766
40756
|
}, eventCalendarContentShape),
|
|
39767
|
-
|
|
40757
|
+
contentNormalizer: {
|
|
40758
|
+
fieldIds: [
|
|
40759
|
+
"variant",
|
|
40760
|
+
"displayMode",
|
|
40761
|
+
"listLayout",
|
|
40762
|
+
"defaultCalendarView",
|
|
40763
|
+
"eventSurface",
|
|
40764
|
+
"filterEventPresets",
|
|
40765
|
+
"scheduleScope",
|
|
40766
|
+
"filterCategoryIds",
|
|
40767
|
+
"filterStaffMemberId",
|
|
40768
|
+
"filterVenueId"
|
|
40769
|
+
],
|
|
40770
|
+
normalize: normalizeEventCalendarContent
|
|
40771
|
+
},
|
|
39768
40772
|
dataSchemas: {
|
|
39769
40773
|
events: publicEventsArraySchema.optional(),
|
|
39770
40774
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -40013,90 +41017,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
40013
41017
|
} }
|
|
40014
41018
|
};
|
|
40015
41019
|
//#endregion
|
|
40016
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
40017
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
40018
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
40019
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
40020
|
-
{
|
|
40021
|
-
preset: "class",
|
|
40022
|
-
sourceKey: "eventPreset:class",
|
|
40023
|
-
dataKey: "classEvents",
|
|
40024
|
-
label: "Classes"
|
|
40025
|
-
},
|
|
40026
|
-
{
|
|
40027
|
-
preset: "workshop",
|
|
40028
|
-
sourceKey: "eventPreset:workshop",
|
|
40029
|
-
dataKey: "workshopEvents",
|
|
40030
|
-
label: "Workshops"
|
|
40031
|
-
},
|
|
40032
|
-
{
|
|
40033
|
-
preset: "retreat",
|
|
40034
|
-
sourceKey: "eventPreset:retreat",
|
|
40035
|
-
dataKey: "retreatEvents",
|
|
40036
|
-
label: "Retreats"
|
|
40037
|
-
},
|
|
40038
|
-
{
|
|
40039
|
-
preset: "performance",
|
|
40040
|
-
sourceKey: "eventPreset:performance",
|
|
40041
|
-
dataKey: "performanceEvents",
|
|
40042
|
-
label: "Performances"
|
|
40043
|
-
}
|
|
40044
|
-
];
|
|
40045
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
40046
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
40047
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
40048
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
40049
|
-
kind: "eventPreset",
|
|
40050
|
-
preset: definition.preset
|
|
40051
|
-
}]));
|
|
40052
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
40053
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
40054
|
-
}
|
|
40055
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
40056
|
-
if (value == null) return { kind: "legacy" };
|
|
40057
|
-
if (value.length === 0) return { kind: "default" };
|
|
40058
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
40059
|
-
return keys.length > 0 ? {
|
|
40060
|
-
kind: "custom",
|
|
40061
|
-
keys
|
|
40062
|
-
} : { kind: "default" };
|
|
40063
|
-
}
|
|
40064
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
40065
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
40066
|
-
return keys.length >= 2 ? keys : [];
|
|
40067
|
-
}
|
|
40068
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
40069
|
-
if (!isRecord$2(value)) return null;
|
|
40070
|
-
const groupOrderValue = value.groupOrder;
|
|
40071
|
-
if (Array.isArray(groupOrderValue)) {
|
|
40072
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
40073
|
-
return {
|
|
40074
|
-
...value,
|
|
40075
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
40076
|
-
};
|
|
40077
|
-
}
|
|
40078
|
-
if (groupOrderValue != null) return {
|
|
40079
|
-
...value,
|
|
40080
|
-
groupOrder: []
|
|
40081
|
-
};
|
|
40082
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$2) : []);
|
|
40083
|
-
return legacyOrder.length > 0 ? {
|
|
40084
|
-
...value,
|
|
40085
|
-
groupOrder: legacyOrder
|
|
40086
|
-
} : value;
|
|
40087
|
-
}
|
|
40088
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
40089
|
-
const keys = [];
|
|
40090
|
-
for (const value of values) {
|
|
40091
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
40092
|
-
if (!keys.includes(value)) keys.push(value);
|
|
40093
|
-
}
|
|
40094
|
-
return keys;
|
|
40095
|
-
}
|
|
40096
|
-
function isRecord$2(value) {
|
|
40097
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40098
|
-
}
|
|
40099
|
-
//#endregion
|
|
40100
41020
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
40101
41021
|
const groupOverrideFields = [
|
|
40102
41022
|
{
|
|
@@ -40460,7 +41380,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
40460
41380
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
40461
41381
|
const offeringsPreviewBlockDefinition = {
|
|
40462
41382
|
manifest: offeringsPreviewManifest,
|
|
40463
|
-
|
|
41383
|
+
contentNormalizer: {
|
|
41384
|
+
fieldIds: [
|
|
41385
|
+
"displayMode",
|
|
41386
|
+
"heading",
|
|
41387
|
+
"description",
|
|
41388
|
+
"itemLimit",
|
|
41389
|
+
"groupOrder",
|
|
41390
|
+
"groupOverrides",
|
|
41391
|
+
"_cardStyles",
|
|
41392
|
+
"buttonVariant",
|
|
41393
|
+
"buttonText",
|
|
41394
|
+
"emptyMessage",
|
|
41395
|
+
"_sectionStyles"
|
|
41396
|
+
],
|
|
41397
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
41398
|
+
},
|
|
40464
41399
|
dataSchemas: {
|
|
40465
41400
|
...offeringsPreviewEventDataSchemas,
|
|
40466
41401
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -44058,11 +44993,11 @@ function buildNewsletterDisplay(source) {
|
|
|
44058
44993
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
44059
44994
|
privacyNote: null
|
|
44060
44995
|
};
|
|
44061
|
-
const
|
|
44062
|
-
const choices = resolveRuntimeChoices(
|
|
44996
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
44997
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
44063
44998
|
return {
|
|
44064
44999
|
kind: "newsletter-form",
|
|
44065
|
-
availability:
|
|
45000
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
44066
45001
|
className: source.className ?? null,
|
|
44067
45002
|
buttonLabel: form.buttonLabel,
|
|
44068
45003
|
successMessage: form.successMessage,
|
|
@@ -44119,60 +45054,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
44119
45054
|
default: return assertNever$2(source);
|
|
44120
45055
|
}
|
|
44121
45056
|
}
|
|
44122
|
-
function resolveRuntimeChoices(
|
|
44123
|
-
if (
|
|
44124
|
-
|
|
44125
|
-
|
|
44126
|
-
|
|
44127
|
-
|
|
44128
|
-
id: item.id,
|
|
44129
|
-
label: item.name
|
|
44130
|
-
})) : [];
|
|
44131
|
-
}
|
|
44132
|
-
case "brevo": {
|
|
44133
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
44134
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44135
|
-
id: String(item.id),
|
|
44136
|
-
label: item.name
|
|
44137
|
-
})) : [];
|
|
44138
|
-
}
|
|
44139
|
-
case "mailchimp": {
|
|
44140
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
44141
|
-
return (context.provider.provider === "mailchimp" ? context.provider.audiences.find((item) => item.id === targeting.audienceId) : void 0)?.interests.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44142
|
-
id: item.id,
|
|
44143
|
-
label: item.name
|
|
44144
|
-
})) ?? [];
|
|
44145
|
-
}
|
|
44146
|
-
}
|
|
44147
|
-
}
|
|
44148
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
44149
|
-
if (context?.tag !== "configured") return false;
|
|
44150
|
-
const provider = context.provider;
|
|
44151
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
44152
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
44153
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
44154
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
44155
|
-
}
|
|
44156
|
-
if (targeting.provider !== provider.provider) return false;
|
|
44157
|
-
switch (targeting.provider) {
|
|
44158
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
44159
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
44160
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
44161
|
-
}
|
|
44162
|
-
}
|
|
44163
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
44164
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
44165
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44166
|
-
}
|
|
44167
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
44168
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
44169
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44170
|
-
}
|
|
44171
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
44172
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
44173
|
-
if (!audience) return false;
|
|
44174
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
44175
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
45057
|
+
function resolveRuntimeChoices(assessment) {
|
|
45058
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
45059
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
45060
|
+
id: String(item.id),
|
|
45061
|
+
label: item.name
|
|
45062
|
+
}));
|
|
44176
45063
|
}
|
|
44177
45064
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
44178
45065
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -44276,6 +45163,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
44276
45163
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
44277
45164
|
const newsletterSignupBlockDefinition = {
|
|
44278
45165
|
manifest: newsletterSignupManifest,
|
|
45166
|
+
contentNormalizer: {
|
|
45167
|
+
fieldIds: ["targeting"],
|
|
45168
|
+
normalize: normalizeMailingListBlockContent
|
|
45169
|
+
},
|
|
44279
45170
|
runtime: newsletterFormBlockRuntime
|
|
44280
45171
|
};
|
|
44281
45172
|
//#endregion
|
|
@@ -45008,7 +45899,20 @@ const locationMapBlockDefinition = {
|
|
|
45008
45899
|
})], { gap: "md" })
|
|
45009
45900
|
})
|
|
45010
45901
|
}),
|
|
45011
|
-
|
|
45902
|
+
contentNormalizer: {
|
|
45903
|
+
fieldIds: [
|
|
45904
|
+
"heading",
|
|
45905
|
+
"locationSource",
|
|
45906
|
+
"venueId",
|
|
45907
|
+
"location",
|
|
45908
|
+
"showAddressText",
|
|
45909
|
+
"showDirections",
|
|
45910
|
+
"directionsLabel",
|
|
45911
|
+
"zoom",
|
|
45912
|
+
"heightPx"
|
|
45913
|
+
],
|
|
45914
|
+
normalize: normalizeLocationMapContent
|
|
45915
|
+
}
|
|
45012
45916
|
};
|
|
45013
45917
|
//#endregion
|
|
45014
45918
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -46213,17 +47117,7 @@ const linksTransforms = [{
|
|
|
46213
47117
|
id: "links.resolve",
|
|
46214
47118
|
kind: "formatter",
|
|
46215
47119
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
46216
|
-
run: (value, _options, context) =>
|
|
46217
|
-
if (!value || typeof value !== "object") return null;
|
|
46218
|
-
const link = value;
|
|
46219
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
46220
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
46221
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
46222
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
46223
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
46224
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
46225
|
-
return null;
|
|
46226
|
-
}
|
|
47120
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
46227
47121
|
}, {
|
|
46228
47122
|
id: "links.label",
|
|
46229
47123
|
kind: "formatter",
|
|
@@ -46250,6 +47144,21 @@ const linksTransforms = [{
|
|
|
46250
47144
|
return null;
|
|
46251
47145
|
}
|
|
46252
47146
|
}];
|
|
47147
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
47148
|
+
if (!value || typeof value !== "object") return null;
|
|
47149
|
+
const link = value;
|
|
47150
|
+
switch (link.kind) {
|
|
47151
|
+
case "internal": return resolveInternalLink(link, context);
|
|
47152
|
+
case "page": return resolvePageLink(link, context);
|
|
47153
|
+
case "entry": return resolveEntryLink(link, context);
|
|
47154
|
+
case "external":
|
|
47155
|
+
case "url": return resolveExternalLink(link);
|
|
47156
|
+
default: return resolvePreResolvedLink(link);
|
|
47157
|
+
}
|
|
47158
|
+
}
|
|
47159
|
+
function resolvePreResolvedLink(link) {
|
|
47160
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
47161
|
+
}
|
|
46253
47162
|
const eventCalendarSelectionParam = {
|
|
46254
47163
|
id: "events.calendarSelectionParam",
|
|
46255
47164
|
kind: "formatter",
|