@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
package/dist/server/config.mjs
CHANGED
|
@@ -1986,6 +1986,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
1986
1986
|
default: return assertNever$2(pricing);
|
|
1987
1987
|
}
|
|
1988
1988
|
}
|
|
1989
|
+
/**
|
|
1990
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
1991
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
1992
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
1993
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
1994
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
1995
|
+
*/
|
|
1996
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
1997
|
+
switch (display.kind) {
|
|
1998
|
+
case "free": return "Free";
|
|
1999
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
2000
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
2001
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
2002
|
+
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)}`;
|
|
2003
|
+
case "unavailable": return "Pricing unavailable";
|
|
2004
|
+
case "external": return display.label;
|
|
2005
|
+
default: return assertNever$2(display);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
/** Render an event's price directly from its pricing value. */
|
|
2009
|
+
function formatEventPricing(pricing, options = {}) {
|
|
2010
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
2011
|
+
}
|
|
1989
2012
|
//#endregion
|
|
1990
2013
|
//#region ../core/src/event-page-surface-subject.ts
|
|
1991
2014
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -2129,6 +2152,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
2129
2152
|
}
|
|
2130
2153
|
//#endregion
|
|
2131
2154
|
//#region ../core/src/booking-date-time.ts
|
|
2155
|
+
const DEFAULT_LOCALE = "en-US";
|
|
2132
2156
|
const FALLBACK_TIMEZONE = "UTC";
|
|
2133
2157
|
const START_OF_DAY = {
|
|
2134
2158
|
hour: 0,
|
|
@@ -2251,6 +2275,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
2251
2275
|
if (result.ok) return result.value;
|
|
2252
2276
|
throw new Error(formatParseError(result));
|
|
2253
2277
|
}
|
|
2278
|
+
function formatBookingInstant(isoString, options) {
|
|
2279
|
+
const date = new Date(isoString);
|
|
2280
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
2281
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
2282
|
+
}
|
|
2283
|
+
function formatBookingDate(input, format = {
|
|
2284
|
+
weekday: "long",
|
|
2285
|
+
year: "numeric",
|
|
2286
|
+
month: "long",
|
|
2287
|
+
day: "numeric"
|
|
2288
|
+
}) {
|
|
2289
|
+
return formatBookingInstant(input.startsAt, {
|
|
2290
|
+
locale: input.locale,
|
|
2291
|
+
timeZone: input.timeZone,
|
|
2292
|
+
format
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
function formatBookingTime(input, format = {
|
|
2296
|
+
hour: "numeric",
|
|
2297
|
+
minute: "2-digit",
|
|
2298
|
+
hour12: true
|
|
2299
|
+
}) {
|
|
2300
|
+
return formatBookingInstant(input.startsAt, {
|
|
2301
|
+
locale: input.locale,
|
|
2302
|
+
timeZone: input.timeZone,
|
|
2303
|
+
format
|
|
2304
|
+
});
|
|
2305
|
+
}
|
|
2254
2306
|
function getBookingLocalDateKey(input) {
|
|
2255
2307
|
return formatDateKey$1(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
2256
2308
|
}
|
|
@@ -2524,6 +2576,14 @@ function formError(field) {
|
|
|
2524
2576
|
}
|
|
2525
2577
|
//#endregion
|
|
2526
2578
|
//#region ../core/src/mailing-list-targeting.ts
|
|
2579
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
2580
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
2581
|
+
switch (targeting.provider) {
|
|
2582
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
2583
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
2584
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2527
2587
|
function planMailingListChoicePresentation(targeting) {
|
|
2528
2588
|
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
2529
2589
|
switch (targeting.provider) {
|
|
@@ -2563,6 +2623,103 @@ function planMailingListChoicePresentation(targeting) {
|
|
|
2563
2623
|
}
|
|
2564
2624
|
}
|
|
2565
2625
|
//#endregion
|
|
2626
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
2627
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
2628
|
+
switch (provider.provider) {
|
|
2629
|
+
case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
|
|
2630
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
2631
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
function assessMailingListTargeting(context, targeting) {
|
|
2635
|
+
if (context?.tag !== "configured") return {
|
|
2636
|
+
tag: "unavailable",
|
|
2637
|
+
reason: "setup_missing",
|
|
2638
|
+
targeting
|
|
2639
|
+
};
|
|
2640
|
+
const catalog = context.provider;
|
|
2641
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
2642
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
2643
|
+
return destination === null ? {
|
|
2644
|
+
tag: "unavailable",
|
|
2645
|
+
reason: "default_missing",
|
|
2646
|
+
targeting
|
|
2647
|
+
} : {
|
|
2648
|
+
tag: "available",
|
|
2649
|
+
value: {
|
|
2650
|
+
mode: "default",
|
|
2651
|
+
targeting,
|
|
2652
|
+
provider: catalog.provider,
|
|
2653
|
+
destination
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
2658
|
+
switch (targeting.provider) {
|
|
2659
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
2660
|
+
provider: "native",
|
|
2661
|
+
catalog,
|
|
2662
|
+
targeting
|
|
2663
|
+
}, catalog.topics) : {
|
|
2664
|
+
tag: "unavailable",
|
|
2665
|
+
reason: "provider_mismatch",
|
|
2666
|
+
targeting
|
|
2667
|
+
};
|
|
2668
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
2669
|
+
provider: "brevo",
|
|
2670
|
+
catalog,
|
|
2671
|
+
targeting
|
|
2672
|
+
}, catalog.lists) : {
|
|
2673
|
+
tag: "unavailable",
|
|
2674
|
+
reason: "provider_mismatch",
|
|
2675
|
+
targeting
|
|
2676
|
+
};
|
|
2677
|
+
case "mailchimp": {
|
|
2678
|
+
if (catalog.provider !== "mailchimp") return {
|
|
2679
|
+
tag: "unavailable",
|
|
2680
|
+
reason: "provider_mismatch",
|
|
2681
|
+
targeting
|
|
2682
|
+
};
|
|
2683
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
2684
|
+
return audience === void 0 ? {
|
|
2685
|
+
tag: "unavailable",
|
|
2686
|
+
reason: "audience_missing",
|
|
2687
|
+
value: {
|
|
2688
|
+
mode: "custom",
|
|
2689
|
+
provider: "mailchimp",
|
|
2690
|
+
catalog,
|
|
2691
|
+
targeting
|
|
2692
|
+
}
|
|
2693
|
+
} : assessMatchedChoices({
|
|
2694
|
+
provider: "mailchimp",
|
|
2695
|
+
catalog,
|
|
2696
|
+
targeting,
|
|
2697
|
+
audience
|
|
2698
|
+
}, audience.interests);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
function assessMatchedChoices(matched, choices) {
|
|
2703
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
2704
|
+
const available = new Set(choices.map((item) => item.id));
|
|
2705
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
2706
|
+
const value = {
|
|
2707
|
+
mode: "custom",
|
|
2708
|
+
...matched,
|
|
2709
|
+
choices,
|
|
2710
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
2711
|
+
};
|
|
2712
|
+
return missingIds.length > 0 ? {
|
|
2713
|
+
tag: "unavailable",
|
|
2714
|
+
reason: "choices_missing",
|
|
2715
|
+
missingIds,
|
|
2716
|
+
value
|
|
2717
|
+
} : {
|
|
2718
|
+
tag: "available",
|
|
2719
|
+
value
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
//#endregion
|
|
2566
2723
|
//#region ../core/src/mailing-list-runtime.ts
|
|
2567
2724
|
function parseMailingListRuntimeContext(value) {
|
|
2568
2725
|
if (!isRecord$8(value)) return invalidRuntimeContext();
|
|
@@ -2627,57 +2784,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
2627
2784
|
function parseMailchimpRuntimeProvider(value) {
|
|
2628
2785
|
if (!Array.isArray(value.audiences)) return null;
|
|
2629
2786
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
for (const audience of value.audiences) {
|
|
2633
|
-
if (!isRecord$8(audience)) return null;
|
|
2634
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
2635
|
-
const name = parseName(audience.name);
|
|
2636
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
2637
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
2638
|
-
if (interests === null) return null;
|
|
2639
|
-
audiences.push({
|
|
2640
|
-
id,
|
|
2641
|
-
name,
|
|
2642
|
-
interests
|
|
2643
|
-
});
|
|
2644
|
-
}
|
|
2645
|
-
return {
|
|
2787
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
2788
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
2646
2789
|
provider: "mailchimp",
|
|
2647
2790
|
defaultAudienceId,
|
|
2648
2791
|
audiences
|
|
2649
|
-
};
|
|
2792
|
+
} : null;
|
|
2650
2793
|
}
|
|
2651
|
-
function
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
interests
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2794
|
+
function parseMailchimpAudience(value) {
|
|
2795
|
+
if (!isRecord$8(value) || !Array.isArray(value.interests)) return null;
|
|
2796
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
2797
|
+
const name = parseName(value.name);
|
|
2798
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
2799
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
2800
|
+
id,
|
|
2801
|
+
name,
|
|
2802
|
+
interests
|
|
2803
|
+
} : null;
|
|
2804
|
+
}
|
|
2805
|
+
function parseMailchimpInterest(value) {
|
|
2806
|
+
if (!isRecord$8(value)) return null;
|
|
2807
|
+
const id = parseMailchimpInterestId(value.id);
|
|
2808
|
+
const name = parseName(value.name);
|
|
2809
|
+
const categoryName = parseName(value.categoryName);
|
|
2810
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
2811
|
+
id,
|
|
2812
|
+
name,
|
|
2813
|
+
categoryName
|
|
2814
|
+
} : null;
|
|
2666
2815
|
}
|
|
2667
2816
|
function parseNamedItems(value, parseId) {
|
|
2668
2817
|
if (!Array.isArray(value)) return null;
|
|
2669
|
-
const items =
|
|
2670
|
-
for (const item of value) {
|
|
2818
|
+
const items = Array.from(value, (item) => {
|
|
2671
2819
|
if (!isRecord$8(item)) return null;
|
|
2672
2820
|
const id = parseId(item.id);
|
|
2673
2821
|
const name = parseName(item.name);
|
|
2674
|
-
|
|
2675
|
-
items.push({
|
|
2822
|
+
return id !== null && name !== null ? {
|
|
2676
2823
|
id,
|
|
2677
2824
|
name
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
return items;
|
|
2825
|
+
} : null;
|
|
2826
|
+
});
|
|
2827
|
+
return items.every((item) => item !== null) ? items : null;
|
|
2681
2828
|
}
|
|
2682
2829
|
function parseName(value) {
|
|
2683
2830
|
if (typeof value !== "string") return null;
|
|
@@ -2693,6 +2840,7 @@ function invalidRuntimeContext() {
|
|
|
2693
2840
|
//#endregion
|
|
2694
2841
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2695
2842
|
function parseMailingListPlacementTargeting(value) {
|
|
2843
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
2696
2844
|
if (!isRecord$7(value)) return targetingError("shape");
|
|
2697
2845
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
2698
2846
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -2791,14 +2939,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
2791
2939
|
}
|
|
2792
2940
|
function parseUniqueIds(value, parseId) {
|
|
2793
2941
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
2794
|
-
|
|
2795
|
-
|
|
2942
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
2943
|
+
if (!parsed.ok) return parsed;
|
|
2796
2944
|
const id = parseId(item);
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
parsed.push(id);
|
|
2800
|
-
}
|
|
2801
|
-
return ok(parsed);
|
|
2945
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
2946
|
+
}, ok([]));
|
|
2802
2947
|
}
|
|
2803
2948
|
function isRecord$7(value) {
|
|
2804
2949
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3227,6 +3372,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
3227
3372
|
};
|
|
3228
3373
|
}
|
|
3229
3374
|
//#endregion
|
|
3375
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
3376
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
3377
|
+
event: {
|
|
3378
|
+
label: "Event",
|
|
3379
|
+
pluralLabel: "Events",
|
|
3380
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
3381
|
+
},
|
|
3382
|
+
class: {
|
|
3383
|
+
label: "Class",
|
|
3384
|
+
pluralLabel: "Classes",
|
|
3385
|
+
description: "Regular scheduled classes and group sessions."
|
|
3386
|
+
},
|
|
3387
|
+
course: {
|
|
3388
|
+
label: "Course",
|
|
3389
|
+
pluralLabel: "Courses",
|
|
3390
|
+
description: "A fixed set of dates that people book together."
|
|
3391
|
+
},
|
|
3392
|
+
term: {
|
|
3393
|
+
label: "Term",
|
|
3394
|
+
pluralLabel: "Terms",
|
|
3395
|
+
description: "A fixed term of sessions that people book together."
|
|
3396
|
+
},
|
|
3397
|
+
workshop: {
|
|
3398
|
+
label: "Workshop",
|
|
3399
|
+
pluralLabel: "Workshops",
|
|
3400
|
+
description: "One-off workshops, day sessions, or special events."
|
|
3401
|
+
},
|
|
3402
|
+
retreat: {
|
|
3403
|
+
label: "Retreat",
|
|
3404
|
+
pluralLabel: "Retreats",
|
|
3405
|
+
description: "Multi-day or residential immersive experiences."
|
|
3406
|
+
},
|
|
3407
|
+
performance: {
|
|
3408
|
+
label: "Performance",
|
|
3409
|
+
pluralLabel: "Performances",
|
|
3410
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
3411
|
+
}
|
|
3412
|
+
};
|
|
3413
|
+
//#endregion
|
|
3230
3414
|
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
3231
3415
|
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3232
3416
|
checkPublicEventRegistrationNextStep: {
|
|
@@ -24262,6 +24446,14 @@ z.object({
|
|
|
24262
24446
|
icon: z.string().optional()
|
|
24263
24447
|
});
|
|
24264
24448
|
//#endregion
|
|
24449
|
+
//#region ../blocks/src/lib/typeGuards.ts
|
|
24450
|
+
/**
|
|
24451
|
+
* Strict record guard: excludes null, primitives, and arrays.
|
|
24452
|
+
*/
|
|
24453
|
+
function isRecord$5(value) {
|
|
24454
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24455
|
+
}
|
|
24456
|
+
//#endregion
|
|
24265
24457
|
//#region ../blocks/src/system/designCapabilities.ts
|
|
24266
24458
|
function declareBlockDesignCapability(capability) {
|
|
24267
24459
|
return {
|
|
@@ -31115,6 +31307,15 @@ const formBlockDefinition = {
|
|
|
31115
31307
|
runtime: formBlockRuntime
|
|
31116
31308
|
};
|
|
31117
31309
|
//#endregion
|
|
31310
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
31311
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
31312
|
+
function normalizeMailingListBlockContent(record) {
|
|
31313
|
+
return record.targeting == null ? {
|
|
31314
|
+
...record,
|
|
31315
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
31316
|
+
} : record;
|
|
31317
|
+
}
|
|
31318
|
+
//#endregion
|
|
31118
31319
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
31119
31320
|
const contactNewsletterLayout = styledSection({
|
|
31120
31321
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -31278,6 +31479,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
31278
31479
|
],
|
|
31279
31480
|
icon: "MailPlus"
|
|
31280
31481
|
}),
|
|
31482
|
+
contentNormalizer: {
|
|
31483
|
+
fieldIds: ["targeting"],
|
|
31484
|
+
normalize: normalizeMailingListBlockContent
|
|
31485
|
+
},
|
|
31281
31486
|
dataSchemas: { form: formDataSchema.optional() },
|
|
31282
31487
|
dataLoaders: { form: {
|
|
31283
31488
|
endpoint: "getPublicFormById",
|
|
@@ -32695,14 +32900,6 @@ const mediaTransforms = [{
|
|
|
32695
32900
|
}
|
|
32696
32901
|
}];
|
|
32697
32902
|
//#endregion
|
|
32698
|
-
//#region ../blocks/src/lib/typeGuards.ts
|
|
32699
|
-
/**
|
|
32700
|
-
* Strict record guard: excludes null, primitives, and arrays.
|
|
32701
|
-
*/
|
|
32702
|
-
function isRecord$5(value) {
|
|
32703
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32704
|
-
}
|
|
32705
|
-
//#endregion
|
|
32706
32903
|
//#region ../blocks/src/system/transforms/registry/content.ts
|
|
32707
32904
|
const supportedRichTextTokenSchema = z.enum(["year", "site_name"]);
|
|
32708
32905
|
const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(supportedRichTextTokenSchema).default(["year", "site_name"]) });
|
|
@@ -35678,6 +35875,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
35678
35875
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
35679
35876
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
35680
35877
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
35878
|
+
z.strictObject({
|
|
35879
|
+
currency: z.string().trim().length(3),
|
|
35880
|
+
totalCents: nonNegativeIntegerSchema,
|
|
35881
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
35882
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
35883
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
35884
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
35885
|
+
});
|
|
35681
35886
|
//#endregion
|
|
35682
35887
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
35683
35888
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -35918,6 +36123,10 @@ const publicEventBaseSchema = z.object({
|
|
|
35918
36123
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
35919
36124
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
35920
36125
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
36126
|
+
scheduleSummary: z.object({
|
|
36127
|
+
recurrenceDescription: z.string(),
|
|
36128
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
36129
|
+
}).nullable().optional(),
|
|
35921
36130
|
id: z.string(),
|
|
35922
36131
|
occurrenceId: z.string(),
|
|
35923
36132
|
seriesId: z.string(),
|
|
@@ -36328,68 +36537,267 @@ const occurrenceContextSchema = z.object({
|
|
|
36328
36537
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
36329
36538
|
}).nullable();
|
|
36330
36539
|
//#endregion
|
|
36331
|
-
//#region ../blocks/src/system/runtime/
|
|
36332
|
-
|
|
36333
|
-
|
|
36334
|
-
|
|
36335
|
-
|
|
36336
|
-
|
|
36337
|
-
|
|
36338
|
-
|
|
36339
|
-
|
|
36340
|
-
|
|
36341
|
-
|
|
36342
|
-
|
|
36343
|
-
|
|
36344
|
-
"invalidEventOfferingCatalogue"
|
|
36345
|
-
])
|
|
36346
|
-
});
|
|
36347
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
36348
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
36349
|
-
if (unsupported.success) return unsupported.data;
|
|
36350
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
36351
|
-
if (parsed.ok) return parsed.value;
|
|
36352
|
-
ctx.addIssue({
|
|
36353
|
-
code: z.ZodIssueCode.custom,
|
|
36354
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
36355
|
-
});
|
|
36356
|
-
return z.NEVER;
|
|
36357
|
-
});
|
|
36358
|
-
function resolveEventRegistrationScope(context) {
|
|
36359
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
36360
|
-
if (occurrenceSeriesId) return {
|
|
36361
|
-
kind: "occurrenceSeries",
|
|
36362
|
-
seriesId: occurrenceSeriesId
|
|
36540
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
36541
|
+
/**
|
|
36542
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
36543
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
36544
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
36545
|
+
*
|
|
36546
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
36547
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
36548
|
+
*/
|
|
36549
|
+
function getEventAvailability(event) {
|
|
36550
|
+
if (event.capacity == null) return {
|
|
36551
|
+
available: null,
|
|
36552
|
+
isFull: false
|
|
36363
36553
|
};
|
|
36364
|
-
|
|
36365
|
-
|
|
36366
|
-
|
|
36554
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
36555
|
+
if (available <= 0) return {
|
|
36556
|
+
available: 0,
|
|
36557
|
+
isFull: true
|
|
36367
36558
|
};
|
|
36368
|
-
|
|
36369
|
-
|
|
36370
|
-
|
|
36371
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
36559
|
+
return {
|
|
36560
|
+
available,
|
|
36561
|
+
isFull: false
|
|
36372
36562
|
};
|
|
36373
|
-
|
|
36374
|
-
|
|
36375
|
-
|
|
36563
|
+
}
|
|
36564
|
+
/**
|
|
36565
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
36566
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
36567
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
36568
|
+
*
|
|
36569
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
36570
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
36571
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
36572
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
36573
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
36574
|
+
*/
|
|
36575
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
36576
|
+
if (!attendanceMode) return event;
|
|
36577
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
36578
|
+
}
|
|
36579
|
+
/**
|
|
36580
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
36581
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
36582
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
36583
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
36584
|
+
* `capacity - registeredCount` fallback.
|
|
36585
|
+
*/
|
|
36586
|
+
function canJoinEventWaitlist(event, options) {
|
|
36587
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
36588
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
36589
|
+
}
|
|
36590
|
+
/**
|
|
36591
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
36592
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
36593
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
36594
|
+
* to be stale on a cached page.
|
|
36595
|
+
*
|
|
36596
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
36597
|
+
*
|
|
36598
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
36599
|
+
* 5% floor stops large events staying silent until three remain.
|
|
36600
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
36601
|
+
*/
|
|
36602
|
+
function lowCapacityThreshold(capacity) {
|
|
36603
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
36604
|
+
}
|
|
36605
|
+
function getRemainingPlaces(source) {
|
|
36606
|
+
const { available, isFull } = getEventAvailability(source);
|
|
36607
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
36608
|
+
if (isFull) return {
|
|
36609
|
+
kind: "full",
|
|
36610
|
+
waitlist: canJoinEventWaitlist(source)
|
|
36376
36611
|
};
|
|
36377
|
-
|
|
36612
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
36613
|
+
kind: "low",
|
|
36614
|
+
remaining: available
|
|
36615
|
+
};
|
|
36616
|
+
return { kind: "open" };
|
|
36378
36617
|
}
|
|
36379
|
-
|
|
36380
|
-
|
|
36381
|
-
|
|
36382
|
-
|
|
36383
|
-
|
|
36384
|
-
|
|
36385
|
-
|
|
36386
|
-
|
|
36387
|
-
|
|
36388
|
-
case "
|
|
36389
|
-
case "
|
|
36618
|
+
/**
|
|
36619
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
36620
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
36621
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
36622
|
+
* it in rather than re-deriving the count.
|
|
36623
|
+
*/
|
|
36624
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
36625
|
+
const remaining = getRemainingPlaces(source);
|
|
36626
|
+
switch (remaining.kind) {
|
|
36627
|
+
case "unlimited":
|
|
36628
|
+
case "open": return null;
|
|
36629
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
36630
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
36631
|
+
}
|
|
36632
|
+
}
|
|
36633
|
+
function formatPlacesLeft(count, compact) {
|
|
36634
|
+
if (compact) return `${count} left`;
|
|
36635
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
36636
|
+
}
|
|
36637
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
36638
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
36639
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
36640
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
36641
|
+
}
|
|
36642
|
+
/**
|
|
36643
|
+
* Which capacity figure wins when they disagree.
|
|
36644
|
+
*
|
|
36645
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
36646
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
36647
|
+
* The registration write path admits or refuses per mode
|
|
36648
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
36649
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
36650
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
36651
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
36652
|
+
*
|
|
36653
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
36654
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
36655
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
36656
|
+
* the aggregate, unchanged.
|
|
36657
|
+
*/
|
|
36658
|
+
function findHybridModeRows(event) {
|
|
36659
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
36660
|
+
const rows = event.attendanceModes ?? [];
|
|
36661
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
36662
|
+
const online = rows.find((row) => row.mode === "online");
|
|
36663
|
+
return inPerson && online ? {
|
|
36664
|
+
inPerson,
|
|
36665
|
+
online
|
|
36666
|
+
} : null;
|
|
36667
|
+
}
|
|
36668
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
36669
|
+
function remainingPlacesRank(remaining) {
|
|
36670
|
+
switch (remaining.kind) {
|
|
36671
|
+
case "unlimited": return 4;
|
|
36672
|
+
case "open": return 3;
|
|
36673
|
+
case "low": return 2;
|
|
36674
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
36675
|
+
}
|
|
36676
|
+
}
|
|
36677
|
+
function isMoreOpen(candidate, than) {
|
|
36678
|
+
const rank = remainingPlacesRank(candidate);
|
|
36679
|
+
const otherRank = remainingPlacesRank(than);
|
|
36680
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
36681
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
36682
|
+
}
|
|
36683
|
+
/** True when `candidate` has less room left than `than`. */
|
|
36684
|
+
function isScarcer(candidate, than) {
|
|
36685
|
+
return isMoreOpen(than, candidate);
|
|
36686
|
+
}
|
|
36687
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
36688
|
+
in_person: "In person",
|
|
36689
|
+
online: "Online"
|
|
36690
|
+
};
|
|
36691
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
36692
|
+
const PLACES_AVAILABLE = "Places available";
|
|
36693
|
+
/**
|
|
36694
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
36695
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
36696
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
36697
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
36698
|
+
* promise the registration wizard would otherwise have to break.
|
|
36699
|
+
*
|
|
36700
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
36701
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
36702
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
36703
|
+
* { compact: true } -> "Online: 3 left"
|
|
36704
|
+
*/
|
|
36705
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
36706
|
+
const rows = findHybridModeRows(event);
|
|
36707
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
36708
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
36709
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
36710
|
+
if (inPerson === online) return inPerson;
|
|
36711
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
36712
|
+
return formatBothHybridSides(rows, {
|
|
36713
|
+
inPerson,
|
|
36714
|
+
online
|
|
36715
|
+
});
|
|
36716
|
+
}
|
|
36717
|
+
/**
|
|
36718
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
36719
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
36720
|
+
*/
|
|
36721
|
+
function formatBothHybridSides(rows, labels) {
|
|
36722
|
+
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(" · ");
|
|
36723
|
+
}
|
|
36724
|
+
function namedModePlaces(mode, label) {
|
|
36725
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
36726
|
+
}
|
|
36727
|
+
/**
|
|
36728
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
36729
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
36730
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
36731
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
36732
|
+
* how the event is delivered rather than about its remaining places.
|
|
36733
|
+
*/
|
|
36734
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
36735
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
36736
|
+
const online = getRemainingPlaces(rows.online);
|
|
36737
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
36738
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
36739
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
36740
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
36741
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
36742
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
36390
36743
|
}
|
|
36744
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
36745
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
36746
|
+
}
|
|
36747
|
+
function rowFor(rows, mode) {
|
|
36748
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
36391
36749
|
}
|
|
36392
36750
|
//#endregion
|
|
36751
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
36752
|
+
const registrationDisplaySchema = z.object({
|
|
36753
|
+
venue: z.enum(["shown", "hidden"]),
|
|
36754
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
36755
|
+
});
|
|
36756
|
+
function resolveRegistrationDisplay(source) {
|
|
36757
|
+
return {
|
|
36758
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
36759
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
36760
|
+
};
|
|
36761
|
+
}
|
|
36762
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
36763
|
+
function shownVenue(event, display) {
|
|
36764
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
36765
|
+
}
|
|
36766
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
36767
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
36768
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
36769
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
36770
|
+
return capacityPlacesLabel(source, display, wording);
|
|
36771
|
+
}
|
|
36772
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
36773
|
+
const remaining = getRemainingPlaces(source);
|
|
36774
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
36775
|
+
switch (remaining.kind) {
|
|
36776
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
36777
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
36778
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
36779
|
+
case "open": return wording.open ?? null;
|
|
36780
|
+
default: return assertNever$2(remaining);
|
|
36781
|
+
}
|
|
36782
|
+
}
|
|
36783
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
36784
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
36785
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
36786
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
36787
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
36788
|
+
}).join(" · ") || null;
|
|
36789
|
+
}
|
|
36790
|
+
function ticketPlacesLabel(remaining, display) {
|
|
36791
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
36792
|
+
return formatTicketTypeRemaining(remaining);
|
|
36793
|
+
}
|
|
36794
|
+
//#endregion
|
|
36795
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
36796
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
36797
|
+
kind: z.literal("preview"),
|
|
36798
|
+
token: z.string().min(1)
|
|
36799
|
+
}).strict()]);
|
|
36800
|
+
//#endregion
|
|
36393
36801
|
//#region ../calendar/src/grid.ts
|
|
36394
36802
|
const MONTH_NAMES = [
|
|
36395
36803
|
"January",
|
|
@@ -36476,6 +36884,11 @@ function buildCalendarViewport(input) {
|
|
|
36476
36884
|
//#endregion
|
|
36477
36885
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
36478
36886
|
/**
|
|
36887
|
+
* Date and time presentation for events: the single place an event's
|
|
36888
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
36889
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
36890
|
+
*/
|
|
36891
|
+
/**
|
|
36479
36892
|
* The English locale a site's public dates are written in, read from the
|
|
36480
36893
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
36481
36894
|
*
|
|
@@ -36495,6 +36908,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
36495
36908
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
36496
36909
|
return "en-US";
|
|
36497
36910
|
}
|
|
36911
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
36912
|
+
const locale = options?.locale ?? "en-US";
|
|
36913
|
+
const dateTime = toScheduledBookingDateTime({
|
|
36914
|
+
startsAt: isoTimestamp,
|
|
36915
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
36916
|
+
locale
|
|
36917
|
+
});
|
|
36918
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
36919
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
36920
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
36921
|
+
return {
|
|
36922
|
+
weekday,
|
|
36923
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
36924
|
+
month,
|
|
36925
|
+
label: formatBookingDate(dateTime, {
|
|
36926
|
+
weekday: "long",
|
|
36927
|
+
year: "numeric",
|
|
36928
|
+
month: "long",
|
|
36929
|
+
day: "numeric"
|
|
36930
|
+
})
|
|
36931
|
+
};
|
|
36932
|
+
}
|
|
36498
36933
|
//#endregion
|
|
36499
36934
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
36500
36935
|
function isRecord$4(value) {
|
|
@@ -36514,6 +36949,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
36514
36949
|
};
|
|
36515
36950
|
}
|
|
36516
36951
|
//#endregion
|
|
36952
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
36953
|
+
/**
|
|
36954
|
+
* Format an event's price directly from its pricing value (without the full
|
|
36955
|
+
* event). Same output as {@link formatEventPrice}.
|
|
36956
|
+
*/
|
|
36957
|
+
function formatEventPriceDisplay(pricing) {
|
|
36958
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
36959
|
+
}
|
|
36960
|
+
//#endregion
|
|
36517
36961
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
36518
36962
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
36519
36963
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -36548,150 +36992,6 @@ function eventListWindowEvents(events, window) {
|
|
|
36548
36992
|
});
|
|
36549
36993
|
}
|
|
36550
36994
|
//#endregion
|
|
36551
|
-
//#region ../blocks/src/system/constants/events.ts
|
|
36552
|
-
const eventCalendarDisplayModeValues = [
|
|
36553
|
-
"combined",
|
|
36554
|
-
"calendar",
|
|
36555
|
-
"list",
|
|
36556
|
-
"timetable",
|
|
36557
|
-
"week-board"
|
|
36558
|
-
];
|
|
36559
|
-
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
36560
|
-
const eventCalendarListLayoutValues = [
|
|
36561
|
-
"stack",
|
|
36562
|
-
"grid",
|
|
36563
|
-
"compact"
|
|
36564
|
-
];
|
|
36565
|
-
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
36566
|
-
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
36567
|
-
const eventCalendarListLayoutOptions = [
|
|
36568
|
-
{
|
|
36569
|
-
id: "stack",
|
|
36570
|
-
label: "Stack"
|
|
36571
|
-
},
|
|
36572
|
-
{
|
|
36573
|
-
id: "grid",
|
|
36574
|
-
label: "Grid"
|
|
36575
|
-
},
|
|
36576
|
-
{
|
|
36577
|
-
id: "compact",
|
|
36578
|
-
label: "Compact"
|
|
36579
|
-
}
|
|
36580
|
-
];
|
|
36581
|
-
function isEventCalendarDisplayMode(value) {
|
|
36582
|
-
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
36583
|
-
}
|
|
36584
|
-
function normalizeEventCalendarDisplayMode$1(input) {
|
|
36585
|
-
if (isEventCalendarDisplayMode(input.variant)) return input.variant;
|
|
36586
|
-
return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : void 0;
|
|
36587
|
-
}
|
|
36588
|
-
/** One closed authority for the projections required by each rendered mode. */
|
|
36589
|
-
function resolveEventCalendarReadPlan(input) {
|
|
36590
|
-
const mode = normalizeEventCalendarDisplayMode$1(input) ?? "combined";
|
|
36591
|
-
switch (mode) {
|
|
36592
|
-
case "combined": return {
|
|
36593
|
-
mode,
|
|
36594
|
-
jobs: "both",
|
|
36595
|
-
readProfile: "listing-card"
|
|
36596
|
-
};
|
|
36597
|
-
case "list": return {
|
|
36598
|
-
mode,
|
|
36599
|
-
jobs: "list",
|
|
36600
|
-
readProfile: "listing-card"
|
|
36601
|
-
};
|
|
36602
|
-
case "calendar": return {
|
|
36603
|
-
mode,
|
|
36604
|
-
jobs: "calendar",
|
|
36605
|
-
readProfile: "listing-card"
|
|
36606
|
-
};
|
|
36607
|
-
case "timetable":
|
|
36608
|
-
case "week-board": return {
|
|
36609
|
-
mode,
|
|
36610
|
-
jobs: "calendar",
|
|
36611
|
-
readProfile: "timetable"
|
|
36612
|
-
};
|
|
36613
|
-
}
|
|
36614
|
-
}
|
|
36615
|
-
function isEventCalendarDefaultView(value) {
|
|
36616
|
-
return typeof value === "string" && eventCalendarDefaultViewValues.includes(value);
|
|
36617
|
-
}
|
|
36618
|
-
function isEventCalendarListLayout(value) {
|
|
36619
|
-
return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
|
|
36620
|
-
}
|
|
36621
|
-
/** The calendar manifest owns its secondary arrangement axis. */
|
|
36622
|
-
const eventCalendarVariantMeaning = {
|
|
36623
|
-
kind: "mode",
|
|
36624
|
-
arrangementField: "listLayout",
|
|
36625
|
-
keys: eventCalendarListLayoutValues,
|
|
36626
|
-
lookOnlyKeys: [
|
|
36627
|
-
...arrangementOnlyListLayouts,
|
|
36628
|
-
"month-grid",
|
|
36629
|
-
"month-day"
|
|
36630
|
-
],
|
|
36631
|
-
defaultKey: "stack",
|
|
36632
|
-
modeLabels: {
|
|
36633
|
-
list: "List",
|
|
36634
|
-
calendar: "Month",
|
|
36635
|
-
combined: "List and month",
|
|
36636
|
-
timetable: "Timetable",
|
|
36637
|
-
"week-board": "Week board"
|
|
36638
|
-
}
|
|
36639
|
-
};
|
|
36640
|
-
/** Weekly lists share the arrangement-Look admission used by calendar arrangements. */
|
|
36641
|
-
function eventCalendarListGroupingDecision(input) {
|
|
36642
|
-
const available = input.arrangementLooks && resolveEventCalendarReadPlan(input).mode === "list";
|
|
36643
|
-
return {
|
|
36644
|
-
available,
|
|
36645
|
-
grouping: available && input.listBy === "week" ? "week" : "upcoming"
|
|
36646
|
-
};
|
|
36647
|
-
}
|
|
36648
|
-
//#endregion
|
|
36649
|
-
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
36650
|
-
const previewStageSchema = z.enum(["preview", "published"]);
|
|
36651
|
-
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
36652
|
-
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
36653
|
-
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
36654
|
-
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
36655
|
-
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
36656
|
-
const columnOptionSchema = z.enum([
|
|
36657
|
-
"2",
|
|
36658
|
-
"3",
|
|
36659
|
-
"4"
|
|
36660
|
-
]);
|
|
36661
|
-
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
36662
|
-
const filterAutoShowSchema = z.enum([
|
|
36663
|
-
"auto",
|
|
36664
|
-
"always",
|
|
36665
|
-
"never"
|
|
36666
|
-
]);
|
|
36667
|
-
const calendarTabViewsSchema = z.enum([
|
|
36668
|
-
"both",
|
|
36669
|
-
"month",
|
|
36670
|
-
"week"
|
|
36671
|
-
]);
|
|
36672
|
-
//#endregion
|
|
36673
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
36674
|
-
/**
|
|
36675
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
36676
|
-
*
|
|
36677
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
36678
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
36679
|
-
* @returns Array of wizard steps to display
|
|
36680
|
-
*/
|
|
36681
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
36682
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
36683
|
-
"select-event",
|
|
36684
|
-
"select-tickets",
|
|
36685
|
-
"enter-details"
|
|
36686
|
-
];
|
|
36687
|
-
if (!needsPaymentStep) return baseSteps;
|
|
36688
|
-
return paymentActive ? [
|
|
36689
|
-
...baseSteps,
|
|
36690
|
-
"select-payment",
|
|
36691
|
-
"payment"
|
|
36692
|
-
] : [...baseSteps, "select-payment"];
|
|
36693
|
-
}
|
|
36694
|
-
//#endregion
|
|
36695
36995
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
36696
36996
|
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
36697
36997
|
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
@@ -36715,6 +37015,424 @@ function resolveEventRequiresPayment(input) {
|
|
|
36715
37015
|
return publicEventPricingType(input.event.pricing) === "paid";
|
|
36716
37016
|
}
|
|
36717
37017
|
//#endregion
|
|
37018
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
37019
|
+
/**
|
|
37020
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
37021
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
37022
|
+
* English when the site names no zone.
|
|
37023
|
+
*/
|
|
37024
|
+
function bookingDateLocale(siteTimeZone) {
|
|
37025
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
37026
|
+
}
|
|
37027
|
+
function bookingInstant(startsAt, input) {
|
|
37028
|
+
return toScheduledBookingDateTime({
|
|
37029
|
+
startsAt,
|
|
37030
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
37031
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
37032
|
+
});
|
|
37033
|
+
}
|
|
37034
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
37035
|
+
function bookingClock(startsAt, input) {
|
|
37036
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
37037
|
+
hour: "numeric",
|
|
37038
|
+
minute: "2-digit",
|
|
37039
|
+
hour12: true
|
|
37040
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
37041
|
+
}
|
|
37042
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
37043
|
+
function clockRange(input) {
|
|
37044
|
+
const start = bookingClock(input.startsAt, input);
|
|
37045
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
37046
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
37047
|
+
}
|
|
37048
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
37049
|
+
function formatBookingScheduleSummary(event) {
|
|
37050
|
+
const summary = event.scheduleSummary;
|
|
37051
|
+
if (!summary) return null;
|
|
37052
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
37053
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
37054
|
+
timeZone: "UTC",
|
|
37055
|
+
siteTimeZone: event.siteTimeZone
|
|
37056
|
+
}, "time") : null;
|
|
37057
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
37058
|
+
}
|
|
37059
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
37060
|
+
function formatBookingWhen(input, variant) {
|
|
37061
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
37062
|
+
const day = formatBookingDate(instant, {
|
|
37063
|
+
weekday: "short",
|
|
37064
|
+
day: "numeric",
|
|
37065
|
+
month: "short"
|
|
37066
|
+
});
|
|
37067
|
+
switch (variant) {
|
|
37068
|
+
case "day": return day;
|
|
37069
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
37070
|
+
weekday: "long",
|
|
37071
|
+
day: "numeric",
|
|
37072
|
+
month: "long"
|
|
37073
|
+
});
|
|
37074
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
37075
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
37076
|
+
month: "long",
|
|
37077
|
+
year: "numeric"
|
|
37078
|
+
});
|
|
37079
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
37080
|
+
case "timeRange": return clockRange(input);
|
|
37081
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
37082
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
37083
|
+
}
|
|
37084
|
+
}
|
|
37085
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
37086
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
37087
|
+
return formatBookingWhen({
|
|
37088
|
+
startsAt: isoTimestamp,
|
|
37089
|
+
timeZone: options?.timeZone,
|
|
37090
|
+
siteTimeZone: options?.siteTimeZone
|
|
37091
|
+
}, "short");
|
|
37092
|
+
}
|
|
37093
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
37094
|
+
function occurrenceTitleOverride(occurrence) {
|
|
37095
|
+
const title = occurrence?.overrides?.title;
|
|
37096
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
37097
|
+
}
|
|
37098
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
37099
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
37100
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
37101
|
+
return event && title ? {
|
|
37102
|
+
...event,
|
|
37103
|
+
title
|
|
37104
|
+
} : event;
|
|
37105
|
+
}
|
|
37106
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
37107
|
+
const first = sessions[0];
|
|
37108
|
+
if (!first) return null;
|
|
37109
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
37110
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
37111
|
+
timeZone: first.timeZone,
|
|
37112
|
+
siteTimeZone
|
|
37113
|
+
});
|
|
37114
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
37115
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
37116
|
+
timeZone: last.timeZone,
|
|
37117
|
+
siteTimeZone
|
|
37118
|
+
});
|
|
37119
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
37120
|
+
}
|
|
37121
|
+
/**
|
|
37122
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
37123
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
37124
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
37125
|
+
*/
|
|
37126
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
37127
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
37128
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
37129
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
37130
|
+
}
|
|
37131
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
37132
|
+
function scheduleInput(event, occurrence) {
|
|
37133
|
+
const times = occurrence?.startsAt ? {
|
|
37134
|
+
startsAt: occurrence.startsAt,
|
|
37135
|
+
endsAt: occurrence.endsAt ?? null
|
|
37136
|
+
} : {
|
|
37137
|
+
startsAt: event.startsAt,
|
|
37138
|
+
endsAt: event.endsAt
|
|
37139
|
+
};
|
|
37140
|
+
if (!times.startsAt) return null;
|
|
37141
|
+
return {
|
|
37142
|
+
...times,
|
|
37143
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
37144
|
+
siteTimeZone: event.siteTimeZone
|
|
37145
|
+
};
|
|
37146
|
+
}
|
|
37147
|
+
//#endregion
|
|
37148
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
37149
|
+
function registrationRoute(input) {
|
|
37150
|
+
const base = input.chooseEvent ? [
|
|
37151
|
+
"select-event",
|
|
37152
|
+
"select-tickets",
|
|
37153
|
+
"enter-details"
|
|
37154
|
+
] : ["select-tickets", "enter-details"];
|
|
37155
|
+
switch (input.payment) {
|
|
37156
|
+
case "none": return base;
|
|
37157
|
+
case "options": return [...base, "select-payment"];
|
|
37158
|
+
case "optionsAndPayment": return [
|
|
37159
|
+
...base,
|
|
37160
|
+
"select-payment",
|
|
37161
|
+
"payment"
|
|
37162
|
+
];
|
|
37163
|
+
}
|
|
37164
|
+
}
|
|
37165
|
+
const REGISTRATION_STEP_LABELS = [
|
|
37166
|
+
"Event",
|
|
37167
|
+
"Date",
|
|
37168
|
+
"Tickets",
|
|
37169
|
+
"Places",
|
|
37170
|
+
"Your details",
|
|
37171
|
+
"How you’ll pay",
|
|
37172
|
+
"Payment"
|
|
37173
|
+
];
|
|
37174
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
37175
|
+
function getEventSelectionMode(events) {
|
|
37176
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
37177
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
37178
|
+
}
|
|
37179
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
37180
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
37181
|
+
return {
|
|
37182
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
37183
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
37184
|
+
};
|
|
37185
|
+
}
|
|
37186
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
37187
|
+
function registrationStepLabel(step, context) {
|
|
37188
|
+
switch (step) {
|
|
37189
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
37190
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
37191
|
+
case "enter-details": return "Your details";
|
|
37192
|
+
case "select-payment": return "How you’ll pay";
|
|
37193
|
+
case "payment": return "Payment";
|
|
37194
|
+
}
|
|
37195
|
+
}
|
|
37196
|
+
function bookingButtonText(buttonText) {
|
|
37197
|
+
return buttonText?.trim() || "Book your place";
|
|
37198
|
+
}
|
|
37199
|
+
function placesLabel(event, input, compact) {
|
|
37200
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
37201
|
+
}
|
|
37202
|
+
function isFull(event, mode) {
|
|
37203
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
37204
|
+
full: "full",
|
|
37205
|
+
waitlist: "full"
|
|
37206
|
+
}) === "full";
|
|
37207
|
+
}
|
|
37208
|
+
function priceLabel(event) {
|
|
37209
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
37210
|
+
}
|
|
37211
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
37212
|
+
function lowestPaidAmount(display) {
|
|
37213
|
+
switch (display.kind) {
|
|
37214
|
+
case "exact":
|
|
37215
|
+
case "from": return display.amount;
|
|
37216
|
+
case "range": return display.minAmount;
|
|
37217
|
+
case "mixed": return display.paidFromAmount;
|
|
37218
|
+
case "free":
|
|
37219
|
+
case "unavailable":
|
|
37220
|
+
case "external": return null;
|
|
37221
|
+
}
|
|
37222
|
+
}
|
|
37223
|
+
/**
|
|
37224
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
37225
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
37226
|
+
*/
|
|
37227
|
+
function seriesPriceLabel(events) {
|
|
37228
|
+
const firstEvent = events[0];
|
|
37229
|
+
if (!firstEvent) return null;
|
|
37230
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
37231
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
37232
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
37233
|
+
const lowest = displays.flatMap((display) => {
|
|
37234
|
+
const amount = lowestPaidAmount(display);
|
|
37235
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
37236
|
+
amount,
|
|
37237
|
+
currency: display.currency
|
|
37238
|
+
}];
|
|
37239
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
37240
|
+
return lowest ? formatBookingPriceDisplay({
|
|
37241
|
+
kind: "from",
|
|
37242
|
+
amount: lowest.amount,
|
|
37243
|
+
currency: lowest.currency
|
|
37244
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
37245
|
+
}
|
|
37246
|
+
function dateTile(event) {
|
|
37247
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
37248
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
37249
|
+
return {
|
|
37250
|
+
month: rail.month,
|
|
37251
|
+
day: rail.day
|
|
37252
|
+
};
|
|
37253
|
+
}
|
|
37254
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
37255
|
+
function formatBookingShortDate(event) {
|
|
37256
|
+
return formatBookingWhen(event, "day");
|
|
37257
|
+
}
|
|
37258
|
+
function byStart(left, right) {
|
|
37259
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
37260
|
+
}
|
|
37261
|
+
function singleEntry(event, input) {
|
|
37262
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
37263
|
+
return {
|
|
37264
|
+
kind: "single",
|
|
37265
|
+
title: event.title,
|
|
37266
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
37267
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
37268
|
+
venue: shownVenue(event, input.display),
|
|
37269
|
+
price: priceLabel(event),
|
|
37270
|
+
places: placesLabel(event, input, false),
|
|
37271
|
+
tile: dateTile(event),
|
|
37272
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
37273
|
+
};
|
|
37274
|
+
}
|
|
37275
|
+
function chooseDateEntry(input) {
|
|
37276
|
+
const ordered = [...input.events].sort(byStart);
|
|
37277
|
+
const first = ordered[0];
|
|
37278
|
+
const shown = ordered.slice(0, 4);
|
|
37279
|
+
return {
|
|
37280
|
+
kind: "chooseDate",
|
|
37281
|
+
title: first?.title ?? "",
|
|
37282
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
37283
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
37284
|
+
price: seriesPriceLabel(ordered),
|
|
37285
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
37286
|
+
dateCount: ordered.length,
|
|
37287
|
+
dates: shown.map((event) => ({
|
|
37288
|
+
selectionId: event.selectionId,
|
|
37289
|
+
label: formatBookingShortDate(event),
|
|
37290
|
+
places: placesLabel(event, input, true),
|
|
37291
|
+
full: isFull(event, input.attendanceMode)
|
|
37292
|
+
})),
|
|
37293
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
37294
|
+
action: "Choose a date"
|
|
37295
|
+
};
|
|
37296
|
+
}
|
|
37297
|
+
/** The card before a booking starts; the server renders this too. */
|
|
37298
|
+
function idleBookingEntry(input) {
|
|
37299
|
+
if (input.event) return singleEntry(input.event, input);
|
|
37300
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
37301
|
+
if (only) return singleEntry(only, input);
|
|
37302
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
37303
|
+
return {
|
|
37304
|
+
kind: "chooseEvent",
|
|
37305
|
+
title: input.events[0]?.title ?? "",
|
|
37306
|
+
count: input.events.length,
|
|
37307
|
+
noun: input.noun.pluralLabel,
|
|
37308
|
+
action: "Choose an event"
|
|
37309
|
+
};
|
|
37310
|
+
}
|
|
37311
|
+
//#endregion
|
|
37312
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
37313
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
37314
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
37315
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
37316
|
+
{
|
|
37317
|
+
preset: "class",
|
|
37318
|
+
sourceKey: "eventPreset:class",
|
|
37319
|
+
dataKey: "classEvents",
|
|
37320
|
+
label: "Classes"
|
|
37321
|
+
},
|
|
37322
|
+
{
|
|
37323
|
+
preset: "workshop",
|
|
37324
|
+
sourceKey: "eventPreset:workshop",
|
|
37325
|
+
dataKey: "workshopEvents",
|
|
37326
|
+
label: "Workshops"
|
|
37327
|
+
},
|
|
37328
|
+
{
|
|
37329
|
+
preset: "retreat",
|
|
37330
|
+
sourceKey: "eventPreset:retreat",
|
|
37331
|
+
dataKey: "retreatEvents",
|
|
37332
|
+
label: "Retreats"
|
|
37333
|
+
},
|
|
37334
|
+
{
|
|
37335
|
+
preset: "performance",
|
|
37336
|
+
sourceKey: "eventPreset:performance",
|
|
37337
|
+
dataKey: "performanceEvents",
|
|
37338
|
+
label: "Performances"
|
|
37339
|
+
}
|
|
37340
|
+
];
|
|
37341
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
37342
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
37343
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
37344
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
37345
|
+
kind: "eventPreset",
|
|
37346
|
+
preset: definition.preset
|
|
37347
|
+
}]));
|
|
37348
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
37349
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
37350
|
+
}
|
|
37351
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
37352
|
+
if (value == null) return { kind: "legacy" };
|
|
37353
|
+
if (value.length === 0) return { kind: "default" };
|
|
37354
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
37355
|
+
return keys.length > 0 ? {
|
|
37356
|
+
kind: "custom",
|
|
37357
|
+
keys
|
|
37358
|
+
} : { kind: "default" };
|
|
37359
|
+
}
|
|
37360
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
37361
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
37362
|
+
return keys.length >= 2 ? keys : [];
|
|
37363
|
+
}
|
|
37364
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
37365
|
+
if (!isRecord$3(value)) return null;
|
|
37366
|
+
const groupOrderValue = value.groupOrder;
|
|
37367
|
+
if (Array.isArray(groupOrderValue)) {
|
|
37368
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
37369
|
+
return {
|
|
37370
|
+
...value,
|
|
37371
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
37372
|
+
};
|
|
37373
|
+
}
|
|
37374
|
+
if (groupOrderValue != null) return {
|
|
37375
|
+
...value,
|
|
37376
|
+
groupOrder: []
|
|
37377
|
+
};
|
|
37378
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$3) : []);
|
|
37379
|
+
return legacyOrder.length > 0 ? {
|
|
37380
|
+
...value,
|
|
37381
|
+
groupOrder: legacyOrder
|
|
37382
|
+
} : value;
|
|
37383
|
+
}
|
|
37384
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
37385
|
+
function sourceFromPresetSummary(preset) {
|
|
37386
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
37387
|
+
if (preset.engine !== "event_series") return null;
|
|
37388
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
37389
|
+
kind: "eventPreset",
|
|
37390
|
+
preset: preset.canonicalBehaviour
|
|
37391
|
+
};
|
|
37392
|
+
return null;
|
|
37393
|
+
}
|
|
37394
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
37395
|
+
const keys = [];
|
|
37396
|
+
for (const value of values) {
|
|
37397
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
37398
|
+
if (!keys.includes(value)) keys.push(value);
|
|
37399
|
+
}
|
|
37400
|
+
return keys;
|
|
37401
|
+
}
|
|
37402
|
+
function isRecord$3(value) {
|
|
37403
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37404
|
+
}
|
|
37405
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
37406
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
37407
|
+
}
|
|
37408
|
+
//#endregion
|
|
37409
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
37410
|
+
function offeringKindForEvent(event) {
|
|
37411
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
37412
|
+
}
|
|
37413
|
+
function presetKind(preset) {
|
|
37414
|
+
const source = sourceFromPresetSummary(preset);
|
|
37415
|
+
if (!source) return null;
|
|
37416
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
37417
|
+
}
|
|
37418
|
+
/**
|
|
37419
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
37420
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
37421
|
+
* name stands in when the site has none.
|
|
37422
|
+
*/
|
|
37423
|
+
function offeringNounForEvent(event, presets) {
|
|
37424
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
37425
|
+
const kind = offeringKindForEvent(event);
|
|
37426
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
37427
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
37428
|
+
}
|
|
37429
|
+
function lowerCased(noun) {
|
|
37430
|
+
return {
|
|
37431
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
37432
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
37433
|
+
};
|
|
37434
|
+
}
|
|
37435
|
+
//#endregion
|
|
36718
37436
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
36719
37437
|
function toRegistrationEvent(event) {
|
|
36720
37438
|
return {
|
|
@@ -36759,6 +37477,279 @@ function toWholeSeriesRegistrationEvents(events) {
|
|
|
36759
37477
|
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
36760
37478
|
}
|
|
36761
37479
|
//#endregion
|
|
37480
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
37481
|
+
/**
|
|
37482
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
37483
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
37484
|
+
* so the server and the client agree on one card.
|
|
37485
|
+
*/
|
|
37486
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
37487
|
+
const tileSchema = z.object({
|
|
37488
|
+
month: z.string(),
|
|
37489
|
+
day: z.string()
|
|
37490
|
+
}).nullable();
|
|
37491
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
37492
|
+
z.object({
|
|
37493
|
+
kind: z.literal("single"),
|
|
37494
|
+
title: z.string(),
|
|
37495
|
+
when: z.string().nullable(),
|
|
37496
|
+
shortWhen: z.string().nullable(),
|
|
37497
|
+
venue: z.string().nullable(),
|
|
37498
|
+
price: z.string().nullable(),
|
|
37499
|
+
places: z.string().nullable(),
|
|
37500
|
+
tile: tileSchema,
|
|
37501
|
+
action: z.string()
|
|
37502
|
+
}),
|
|
37503
|
+
z.object({
|
|
37504
|
+
kind: z.literal("chooseDate"),
|
|
37505
|
+
title: z.string(),
|
|
37506
|
+
schedule: z.string(),
|
|
37507
|
+
venue: z.string().nullable(),
|
|
37508
|
+
price: z.string().nullable(),
|
|
37509
|
+
nextDate: z.string().nullable(),
|
|
37510
|
+
dateCount: z.number(),
|
|
37511
|
+
dates: z.array(z.object({
|
|
37512
|
+
selectionId: z.string(),
|
|
37513
|
+
label: z.string(),
|
|
37514
|
+
places: z.string().nullable(),
|
|
37515
|
+
full: z.boolean()
|
|
37516
|
+
})),
|
|
37517
|
+
moreCount: z.number(),
|
|
37518
|
+
action: z.string()
|
|
37519
|
+
}),
|
|
37520
|
+
z.object({
|
|
37521
|
+
kind: z.literal("chooseEvent"),
|
|
37522
|
+
title: z.string(),
|
|
37523
|
+
count: z.number(),
|
|
37524
|
+
noun: z.string(),
|
|
37525
|
+
action: z.string()
|
|
37526
|
+
})
|
|
37527
|
+
]);
|
|
37528
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
37529
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
37530
|
+
}
|
|
37531
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
37532
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37533
|
+
return {
|
|
37534
|
+
scopedEvents,
|
|
37535
|
+
preSelected: findPreSelectedEvent({
|
|
37536
|
+
scopedEvents,
|
|
37537
|
+
occurrenceContext: source.occurrenceContext
|
|
37538
|
+
})
|
|
37539
|
+
};
|
|
37540
|
+
}
|
|
37541
|
+
function nounFor(scoped, presets) {
|
|
37542
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
37543
|
+
}
|
|
37544
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
37545
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
37546
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
37547
|
+
}
|
|
37548
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
37549
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
37550
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
37551
|
+
return idleBookingEntry({
|
|
37552
|
+
events: scoped.scopedEvents,
|
|
37553
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
37554
|
+
display,
|
|
37555
|
+
buttonText: source.buttonText,
|
|
37556
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
37557
|
+
attendanceMode: null
|
|
37558
|
+
});
|
|
37559
|
+
}
|
|
37560
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
37561
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
37562
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
37563
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
37564
|
+
if (!entry) return null;
|
|
37565
|
+
return {
|
|
37566
|
+
kind: "event-registration",
|
|
37567
|
+
state: "booking-card",
|
|
37568
|
+
className: source.className ?? null,
|
|
37569
|
+
entry,
|
|
37570
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
37571
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
37572
|
+
};
|
|
37573
|
+
}
|
|
37574
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
37575
|
+
kind: z.literal("unsupported"),
|
|
37576
|
+
reason: z.enum([
|
|
37577
|
+
"unsupportedSubject",
|
|
37578
|
+
"invalidEventSeriesId",
|
|
37579
|
+
"invalidEventSeriesBookingScope",
|
|
37580
|
+
"invalidEventOfferingId",
|
|
37581
|
+
"invalidEventOfferingBookingScope",
|
|
37582
|
+
"invalidEventOfferingCatalogue"
|
|
37583
|
+
])
|
|
37584
|
+
});
|
|
37585
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
37586
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
37587
|
+
if (unsupported.success) return unsupported.data;
|
|
37588
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
37589
|
+
if (parsed.ok) return parsed.value;
|
|
37590
|
+
ctx.addIssue({
|
|
37591
|
+
code: z.ZodIssueCode.custom,
|
|
37592
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
37593
|
+
});
|
|
37594
|
+
return z.NEVER;
|
|
37595
|
+
});
|
|
37596
|
+
function resolveEventRegistrationScope(context) {
|
|
37597
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
37598
|
+
if (occurrenceSeriesId) return {
|
|
37599
|
+
kind: "occurrenceSeries",
|
|
37600
|
+
seriesId: occurrenceSeriesId
|
|
37601
|
+
};
|
|
37602
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
37603
|
+
kind: "pageSurfaceSeries",
|
|
37604
|
+
seriesId: context.subject.eventSeriesId
|
|
37605
|
+
};
|
|
37606
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
37607
|
+
kind: "pageSurfaceOffering",
|
|
37608
|
+
offeringId: context.subject.eventOfferingId,
|
|
37609
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
37610
|
+
};
|
|
37611
|
+
if (context.subject?.kind === "unsupported") return {
|
|
37612
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
37613
|
+
reason: context.subject.reason
|
|
37614
|
+
};
|
|
37615
|
+
return { kind: "unscoped" };
|
|
37616
|
+
}
|
|
37617
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
37618
|
+
const scope = resolveEventRegistrationScope(context);
|
|
37619
|
+
switch (scope.kind) {
|
|
37620
|
+
case "occurrenceSeries":
|
|
37621
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
37622
|
+
case "pageSurfaceOffering": {
|
|
37623
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
37624
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
37625
|
+
}
|
|
37626
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
37627
|
+
case "unscoped": return [...events];
|
|
37628
|
+
}
|
|
37629
|
+
}
|
|
37630
|
+
//#endregion
|
|
37631
|
+
//#region ../blocks/src/system/constants/events.ts
|
|
37632
|
+
const eventCalendarDisplayModeValues = [
|
|
37633
|
+
"combined",
|
|
37634
|
+
"calendar",
|
|
37635
|
+
"list",
|
|
37636
|
+
"timetable",
|
|
37637
|
+
"week-board"
|
|
37638
|
+
];
|
|
37639
|
+
const eventCalendarDefaultViewValues = ["month", "week"];
|
|
37640
|
+
const eventCalendarListLayoutValues = [
|
|
37641
|
+
"stack",
|
|
37642
|
+
"grid",
|
|
37643
|
+
"compact"
|
|
37644
|
+
];
|
|
37645
|
+
const arrangementOnlyListLayouts = ["ledger", "day-groups"];
|
|
37646
|
+
const eventListArrangementValues = [...eventCalendarListLayoutValues, ...arrangementOnlyListLayouts];
|
|
37647
|
+
const eventCalendarListLayoutOptions = [
|
|
37648
|
+
{
|
|
37649
|
+
id: "stack",
|
|
37650
|
+
label: "Stack"
|
|
37651
|
+
},
|
|
37652
|
+
{
|
|
37653
|
+
id: "grid",
|
|
37654
|
+
label: "Grid"
|
|
37655
|
+
},
|
|
37656
|
+
{
|
|
37657
|
+
id: "compact",
|
|
37658
|
+
label: "Compact"
|
|
37659
|
+
}
|
|
37660
|
+
];
|
|
37661
|
+
function isEventCalendarDisplayMode(value) {
|
|
37662
|
+
return typeof value === "string" && eventCalendarDisplayModeValues.includes(value);
|
|
37663
|
+
}
|
|
37664
|
+
function normalizeEventCalendarDisplayMode$1(input) {
|
|
37665
|
+
if (isEventCalendarDisplayMode(input.variant)) return input.variant;
|
|
37666
|
+
return isEventCalendarDisplayMode(input.displayMode) ? input.displayMode : void 0;
|
|
37667
|
+
}
|
|
37668
|
+
/** One closed authority for the projections required by each rendered mode. */
|
|
37669
|
+
function resolveEventCalendarReadPlan(input) {
|
|
37670
|
+
const mode = normalizeEventCalendarDisplayMode$1(input) ?? "combined";
|
|
37671
|
+
switch (mode) {
|
|
37672
|
+
case "combined": return {
|
|
37673
|
+
mode,
|
|
37674
|
+
jobs: "both",
|
|
37675
|
+
readProfile: "listing-card"
|
|
37676
|
+
};
|
|
37677
|
+
case "list": return {
|
|
37678
|
+
mode,
|
|
37679
|
+
jobs: "list",
|
|
37680
|
+
readProfile: "listing-card"
|
|
37681
|
+
};
|
|
37682
|
+
case "calendar": return {
|
|
37683
|
+
mode,
|
|
37684
|
+
jobs: "calendar",
|
|
37685
|
+
readProfile: "listing-card"
|
|
37686
|
+
};
|
|
37687
|
+
case "timetable":
|
|
37688
|
+
case "week-board": return {
|
|
37689
|
+
mode,
|
|
37690
|
+
jobs: "calendar",
|
|
37691
|
+
readProfile: "timetable"
|
|
37692
|
+
};
|
|
37693
|
+
}
|
|
37694
|
+
}
|
|
37695
|
+
function isEventCalendarDefaultView(value) {
|
|
37696
|
+
return typeof value === "string" && eventCalendarDefaultViewValues.includes(value);
|
|
37697
|
+
}
|
|
37698
|
+
function isEventCalendarListLayout(value) {
|
|
37699
|
+
return typeof value === "string" && eventCalendarListLayoutValues.includes(value);
|
|
37700
|
+
}
|
|
37701
|
+
/** The calendar manifest owns its secondary arrangement axis. */
|
|
37702
|
+
const eventCalendarVariantMeaning = {
|
|
37703
|
+
kind: "mode",
|
|
37704
|
+
arrangementField: "listLayout",
|
|
37705
|
+
keys: eventCalendarListLayoutValues,
|
|
37706
|
+
lookOnlyKeys: [
|
|
37707
|
+
...arrangementOnlyListLayouts,
|
|
37708
|
+
"month-grid",
|
|
37709
|
+
"month-day"
|
|
37710
|
+
],
|
|
37711
|
+
defaultKey: "stack",
|
|
37712
|
+
modeLabels: {
|
|
37713
|
+
list: "List",
|
|
37714
|
+
calendar: "Month",
|
|
37715
|
+
combined: "List and month",
|
|
37716
|
+
timetable: "Timetable",
|
|
37717
|
+
"week-board": "Week board"
|
|
37718
|
+
}
|
|
37719
|
+
};
|
|
37720
|
+
/** Weekly lists share the arrangement-Look admission used by calendar arrangements. */
|
|
37721
|
+
function eventCalendarListGroupingDecision(input) {
|
|
37722
|
+
const available = input.arrangementLooks && resolveEventCalendarReadPlan(input).mode === "list";
|
|
37723
|
+
return {
|
|
37724
|
+
available,
|
|
37725
|
+
grouping: available && input.listBy === "week" ? "week" : "upcoming"
|
|
37726
|
+
};
|
|
37727
|
+
}
|
|
37728
|
+
//#endregion
|
|
37729
|
+
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
37730
|
+
const previewStageSchema = z.enum(["preview", "published"]);
|
|
37731
|
+
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
37732
|
+
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
37733
|
+
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
37734
|
+
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
37735
|
+
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
37736
|
+
const columnOptionSchema = z.enum([
|
|
37737
|
+
"2",
|
|
37738
|
+
"3",
|
|
37739
|
+
"4"
|
|
37740
|
+
]);
|
|
37741
|
+
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
37742
|
+
const filterAutoShowSchema = z.enum([
|
|
37743
|
+
"auto",
|
|
37744
|
+
"always",
|
|
37745
|
+
"never"
|
|
37746
|
+
]);
|
|
37747
|
+
const calendarTabViewsSchema = z.enum([
|
|
37748
|
+
"both",
|
|
37749
|
+
"month",
|
|
37750
|
+
"week"
|
|
37751
|
+
]);
|
|
37752
|
+
//#endregion
|
|
36762
37753
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
36763
37754
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
36764
37755
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -36801,27 +37792,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
36801
37792
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
36802
37793
|
"Date",
|
|
36803
37794
|
"Tickets",
|
|
36804
|
-
"
|
|
36805
|
-
];
|
|
36806
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
36807
|
-
"Event",
|
|
36808
|
-
"Date",
|
|
36809
|
-
"Tickets",
|
|
36810
|
-
"Details",
|
|
36811
|
-
"Payment options",
|
|
36812
|
-
"Payment"
|
|
37795
|
+
"Your details"
|
|
36813
37796
|
];
|
|
36814
37797
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
36815
|
-
const
|
|
37798
|
+
const eventRegistrationCommonSchemaShape = {
|
|
36816
37799
|
demoEmailSuppressed: z.boolean().optional(),
|
|
36817
37800
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
36818
37801
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
36819
37802
|
maxTickets: z.string().optional(),
|
|
36820
|
-
showVenue: z.boolean().optional(),
|
|
36821
|
-
showCapacity: z.boolean().optional(),
|
|
36822
37803
|
successMessage: z.string().optional(),
|
|
36823
37804
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
36824
|
-
|
|
37805
|
+
host: bookingHostSchema.optional(),
|
|
36825
37806
|
spamProtectionEnabled: z.boolean().optional(),
|
|
36826
37807
|
supportEmail: z.string().optional(),
|
|
36827
37808
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -36846,32 +37827,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
36846
37827
|
portalToken: z.string().nullable().optional(),
|
|
36847
37828
|
previewToken: z.string().nullable().optional(),
|
|
36848
37829
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36849
|
-
...
|
|
37830
|
+
...eventRegistrationCommonSchemaShape,
|
|
37831
|
+
showVenue: z.boolean().optional(),
|
|
37832
|
+
showCapacity: z.boolean().optional(),
|
|
36850
37833
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36851
37834
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36852
37835
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
36853
37836
|
className: z.string().nullable().optional(),
|
|
36854
37837
|
buttonText: z.string().nullable().optional(),
|
|
36855
37838
|
maxTickets: z.string().nullable().optional(),
|
|
36856
|
-
stage: previewStageSchema.optional()
|
|
37839
|
+
stage: previewStageSchema.optional(),
|
|
37840
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
36857
37841
|
});
|
|
36858
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
36859
|
-
|
|
36860
|
-
|
|
36861
|
-
|
|
36862
|
-
|
|
36863
|
-
|
|
36864
|
-
|
|
36865
|
-
|
|
36866
|
-
|
|
36867
|
-
|
|
36868
|
-
|
|
36869
|
-
|
|
36870
|
-
|
|
36871
|
-
|
|
36872
|
-
|
|
37842
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
37843
|
+
z.object({
|
|
37844
|
+
kind: z.literal("event-registration"),
|
|
37845
|
+
state: z.literal("generic-shell"),
|
|
37846
|
+
className: z.string().nullable(),
|
|
37847
|
+
titleText: z.string(),
|
|
37848
|
+
bodyText: z.string(),
|
|
37849
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
37850
|
+
summaryButtonText: z.string()
|
|
37851
|
+
}),
|
|
37852
|
+
z.object({
|
|
37853
|
+
kind: z.literal("event-registration"),
|
|
37854
|
+
state: z.literal("registration-closed"),
|
|
37855
|
+
className: z.string().nullable(),
|
|
37856
|
+
titleText: z.string(),
|
|
37857
|
+
bodyText: z.string()
|
|
37858
|
+
}),
|
|
37859
|
+
z.object({
|
|
37860
|
+
kind: z.literal("event-registration"),
|
|
37861
|
+
state: z.literal("booking-card"),
|
|
37862
|
+
className: z.string().nullable(),
|
|
37863
|
+
entry: idleBookingEntrySchema,
|
|
37864
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
37865
|
+
buttonText: z.string()
|
|
37866
|
+
})
|
|
37867
|
+
]);
|
|
36873
37868
|
const eventRegistrationHydrationSchema = z.object({
|
|
36874
|
-
...
|
|
37869
|
+
...eventRegistrationCommonSchemaShape,
|
|
37870
|
+
display: registrationDisplaySchema,
|
|
37871
|
+
offeringNoun: z.object({
|
|
37872
|
+
label: z.string(),
|
|
37873
|
+
pluralLabel: z.string()
|
|
37874
|
+
}).optional(),
|
|
36875
37875
|
eventSource: eventRegistrationEventSourceSchema
|
|
36876
37876
|
});
|
|
36877
37877
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -36886,7 +37886,7 @@ z.object({
|
|
|
36886
37886
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36887
37887
|
stage: previewStageSchema.optional()
|
|
36888
37888
|
});
|
|
36889
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
37889
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
36890
37890
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
36891
37891
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
36892
37892
|
kind: "event-registration",
|
|
@@ -36895,6 +37895,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
36895
37895
|
titleText: "Registration closed",
|
|
36896
37896
|
bodyText: "This run is no longer open for bookings."
|
|
36897
37897
|
};
|
|
37898
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
37899
|
+
if (card) return card;
|
|
36898
37900
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
36899
37901
|
return {
|
|
36900
37902
|
kind: "event-registration",
|
|
@@ -36911,11 +37913,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36911
37913
|
if (selectedRun) {
|
|
36912
37914
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
36913
37915
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
36914
|
-
return
|
|
36915
|
-
|
|
36916
|
-
|
|
36917
|
-
|
|
36918
|
-
|
|
37916
|
+
return shellStepLabels(registrationRoute({
|
|
37917
|
+
chooseEvent: false,
|
|
37918
|
+
payment: resolveEventRequiresPayment({
|
|
37919
|
+
eligibility: null,
|
|
37920
|
+
selectedTicketType: null,
|
|
37921
|
+
event: selectedEvent
|
|
37922
|
+
}) ? "optionsAndPayment" : "none"
|
|
37923
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
36919
37924
|
}
|
|
36920
37925
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
36921
37926
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -36924,14 +37929,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
36924
37929
|
occurrenceContext: source.occurrenceContext
|
|
36925
37930
|
});
|
|
36926
37931
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
36927
|
-
|
|
37932
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
36928
37933
|
eligibility: null,
|
|
36929
37934
|
selectedTicketType: null,
|
|
36930
37935
|
event: preSelectedEvent
|
|
36931
|
-
}) : false
|
|
36932
|
-
|
|
36933
|
-
|
|
36934
|
-
|
|
37936
|
+
}) : false;
|
|
37937
|
+
return shellStepLabels(registrationRoute({
|
|
37938
|
+
chooseEvent: !hasPreSelectedContext,
|
|
37939
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
37940
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
36935
37941
|
}
|
|
36936
37942
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
36937
37943
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -36947,29 +37953,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
36947
37953
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
36948
37954
|
return runs.length === 1 ? runs[0] : null;
|
|
36949
37955
|
}
|
|
36950
|
-
function
|
|
36951
|
-
|
|
36952
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
36953
|
-
case "select-tickets": return "Tickets";
|
|
36954
|
-
case "enter-details": return "Details";
|
|
36955
|
-
case "select-payment": return "Payment options";
|
|
36956
|
-
case "payment": return "Payment";
|
|
36957
|
-
case "error":
|
|
36958
|
-
case "success":
|
|
36959
|
-
case "submitting":
|
|
36960
|
-
case "verifying-payment":
|
|
36961
|
-
case "verifying-timeout":
|
|
36962
|
-
case "payment-status":
|
|
36963
|
-
case "payment-failed": return "Details";
|
|
36964
|
-
}
|
|
36965
|
-
}
|
|
36966
|
-
function isDateSelection(events) {
|
|
36967
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
36968
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
37956
|
+
function shellStepLabels(route, context) {
|
|
37957
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
36969
37958
|
}
|
|
36970
37959
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
36971
|
-
if (stepLabels.includes("
|
|
36972
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
37960
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
37961
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
36973
37962
|
return "Preparing dates, tickets, and booking details.";
|
|
36974
37963
|
}
|
|
36975
37964
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -36979,6 +37968,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36979
37968
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
36980
37969
|
},
|
|
36981
37970
|
buildRender: (source) => {
|
|
37971
|
+
const display = resolveRegistrationDisplay(source);
|
|
36982
37972
|
const eventSource = resolveEventRegistrationEventSource({
|
|
36983
37973
|
events: source.events,
|
|
36984
37974
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -36986,7 +37976,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36986
37976
|
});
|
|
36987
37977
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
36988
37978
|
return {
|
|
36989
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
37979
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
36990
37980
|
hydration: {
|
|
36991
37981
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
36992
37982
|
subject: source.subject ?? null,
|
|
@@ -36996,29 +37986,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
36996
37986
|
} : eventSource,
|
|
36997
37987
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
36998
37988
|
maxTickets: source.maxTickets ?? void 0,
|
|
36999
|
-
|
|
37000
|
-
showCapacity: source.showCapacity,
|
|
37989
|
+
display,
|
|
37001
37990
|
successMessage: source.successMessage,
|
|
37002
37991
|
buttonVariant: source.buttonVariant,
|
|
37003
|
-
|
|
37992
|
+
host: source.host ?? "overlay",
|
|
37004
37993
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
37005
37994
|
supportEmail: source.supportEmail,
|
|
37006
37995
|
sitePasses: source.sitePasses ?? null,
|
|
37007
37996
|
siteMemberships: source.siteMemberships ?? null,
|
|
37008
37997
|
mailingList: source.mailingList,
|
|
37009
|
-
siteName: source.siteName
|
|
37998
|
+
siteName: source.siteName,
|
|
37999
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
37010
38000
|
}
|
|
37011
38001
|
};
|
|
37012
38002
|
}
|
|
37013
38003
|
});
|
|
37014
38004
|
function normalizeEventRegistrationEventInput(value) {
|
|
37015
|
-
if (!isRecord$
|
|
38005
|
+
if (!isRecord$2(value)) return value;
|
|
37016
38006
|
return {
|
|
37017
38007
|
...value,
|
|
37018
38008
|
destination: resolveRuntimeEventDestination(value)
|
|
37019
38009
|
};
|
|
37020
38010
|
}
|
|
37021
|
-
function isRecord$
|
|
38011
|
+
function isRecord$2(value) {
|
|
37022
38012
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37023
38013
|
}
|
|
37024
38014
|
const eventRegistrationBlockDefinition = {
|
|
@@ -37058,7 +38048,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
37058
38048
|
description: "Main heading for the registration form",
|
|
37059
38049
|
required: false,
|
|
37060
38050
|
multiline: false,
|
|
37061
|
-
defaultValue: "
|
|
38051
|
+
defaultValue: ""
|
|
37062
38052
|
},
|
|
37063
38053
|
{
|
|
37064
38054
|
id: "description",
|
|
@@ -37130,11 +38120,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
37130
38120
|
{
|
|
37131
38121
|
id: "buttonText",
|
|
37132
38122
|
type: "text",
|
|
37133
|
-
label: "
|
|
37134
|
-
description: "Text
|
|
38123
|
+
label: "Button text",
|
|
38124
|
+
description: "Text on the booking button",
|
|
37135
38125
|
required: false,
|
|
37136
38126
|
multiline: false,
|
|
37137
|
-
defaultValue: "
|
|
38127
|
+
defaultValue: "Book your place",
|
|
37138
38128
|
maxLength: 40
|
|
37139
38129
|
},
|
|
37140
38130
|
createButtonVariantField()
|
|
@@ -37166,21 +38156,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
37166
38156
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
37167
38157
|
buttonText: { $bind: {
|
|
37168
38158
|
from: "content.buttonText",
|
|
37169
|
-
fallback: "
|
|
38159
|
+
fallback: "Book your place"
|
|
37170
38160
|
} },
|
|
37171
38161
|
buttonVariant: { $bind: {
|
|
37172
38162
|
from: "content.buttonVariant",
|
|
37173
38163
|
fallback: "primary"
|
|
37174
38164
|
} },
|
|
37175
|
-
overlayEnabled: { $bind: {
|
|
37176
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
37177
|
-
fallback: false
|
|
37178
|
-
} },
|
|
37179
38165
|
events: { $bind: { from: "data.events" } },
|
|
37180
38166
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
37181
38167
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
37182
38168
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
37183
38169
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
38170
|
+
bookingOfferingPresets: { $bind: {
|
|
38171
|
+
from: "$root.bookingOfferingPresets",
|
|
38172
|
+
fallback: []
|
|
38173
|
+
} },
|
|
37184
38174
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
37185
38175
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
37186
38176
|
stage: { $bind: {
|
|
@@ -39841,7 +40831,21 @@ const eventCalendarBlockDefinition = {
|
|
|
39841
40831
|
list: { label: "List" }
|
|
39842
40832
|
}
|
|
39843
40833
|
}, eventCalendarContentShape),
|
|
39844
|
-
|
|
40834
|
+
contentNormalizer: {
|
|
40835
|
+
fieldIds: [
|
|
40836
|
+
"variant",
|
|
40837
|
+
"displayMode",
|
|
40838
|
+
"listLayout",
|
|
40839
|
+
"defaultCalendarView",
|
|
40840
|
+
"eventSurface",
|
|
40841
|
+
"filterEventPresets",
|
|
40842
|
+
"scheduleScope",
|
|
40843
|
+
"filterCategoryIds",
|
|
40844
|
+
"filterStaffMemberId",
|
|
40845
|
+
"filterVenueId"
|
|
40846
|
+
],
|
|
40847
|
+
normalize: normalizeEventCalendarContent
|
|
40848
|
+
},
|
|
39845
40849
|
dataSchemas: {
|
|
39846
40850
|
events: publicEventsArraySchema.optional(),
|
|
39847
40851
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -40090,90 +41094,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
40090
41094
|
} }
|
|
40091
41095
|
};
|
|
40092
41096
|
//#endregion
|
|
40093
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
40094
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
40095
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
40096
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
40097
|
-
{
|
|
40098
|
-
preset: "class",
|
|
40099
|
-
sourceKey: "eventPreset:class",
|
|
40100
|
-
dataKey: "classEvents",
|
|
40101
|
-
label: "Classes"
|
|
40102
|
-
},
|
|
40103
|
-
{
|
|
40104
|
-
preset: "workshop",
|
|
40105
|
-
sourceKey: "eventPreset:workshop",
|
|
40106
|
-
dataKey: "workshopEvents",
|
|
40107
|
-
label: "Workshops"
|
|
40108
|
-
},
|
|
40109
|
-
{
|
|
40110
|
-
preset: "retreat",
|
|
40111
|
-
sourceKey: "eventPreset:retreat",
|
|
40112
|
-
dataKey: "retreatEvents",
|
|
40113
|
-
label: "Retreats"
|
|
40114
|
-
},
|
|
40115
|
-
{
|
|
40116
|
-
preset: "performance",
|
|
40117
|
-
sourceKey: "eventPreset:performance",
|
|
40118
|
-
dataKey: "performanceEvents",
|
|
40119
|
-
label: "Performances"
|
|
40120
|
-
}
|
|
40121
|
-
];
|
|
40122
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
40123
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
40124
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
40125
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
40126
|
-
kind: "eventPreset",
|
|
40127
|
-
preset: definition.preset
|
|
40128
|
-
}]));
|
|
40129
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
40130
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
40131
|
-
}
|
|
40132
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
40133
|
-
if (value == null) return { kind: "legacy" };
|
|
40134
|
-
if (value.length === 0) return { kind: "default" };
|
|
40135
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
40136
|
-
return keys.length > 0 ? {
|
|
40137
|
-
kind: "custom",
|
|
40138
|
-
keys
|
|
40139
|
-
} : { kind: "default" };
|
|
40140
|
-
}
|
|
40141
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
40142
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
40143
|
-
return keys.length >= 2 ? keys : [];
|
|
40144
|
-
}
|
|
40145
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
40146
|
-
if (!isRecord$2(value)) return null;
|
|
40147
|
-
const groupOrderValue = value.groupOrder;
|
|
40148
|
-
if (Array.isArray(groupOrderValue)) {
|
|
40149
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
40150
|
-
return {
|
|
40151
|
-
...value,
|
|
40152
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
40153
|
-
};
|
|
40154
|
-
}
|
|
40155
|
-
if (groupOrderValue != null) return {
|
|
40156
|
-
...value,
|
|
40157
|
-
groupOrder: []
|
|
40158
|
-
};
|
|
40159
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$2) : []);
|
|
40160
|
-
return legacyOrder.length > 0 ? {
|
|
40161
|
-
...value,
|
|
40162
|
-
groupOrder: legacyOrder
|
|
40163
|
-
} : value;
|
|
40164
|
-
}
|
|
40165
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
40166
|
-
const keys = [];
|
|
40167
|
-
for (const value of values) {
|
|
40168
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
40169
|
-
if (!keys.includes(value)) keys.push(value);
|
|
40170
|
-
}
|
|
40171
|
-
return keys;
|
|
40172
|
-
}
|
|
40173
|
-
function isRecord$2(value) {
|
|
40174
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40175
|
-
}
|
|
40176
|
-
//#endregion
|
|
40177
41097
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
40178
41098
|
const groupOverrideFields = [
|
|
40179
41099
|
{
|
|
@@ -40537,7 +41457,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
40537
41457
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
40538
41458
|
const offeringsPreviewBlockDefinition = {
|
|
40539
41459
|
manifest: offeringsPreviewManifest,
|
|
40540
|
-
|
|
41460
|
+
contentNormalizer: {
|
|
41461
|
+
fieldIds: [
|
|
41462
|
+
"displayMode",
|
|
41463
|
+
"heading",
|
|
41464
|
+
"description",
|
|
41465
|
+
"itemLimit",
|
|
41466
|
+
"groupOrder",
|
|
41467
|
+
"groupOverrides",
|
|
41468
|
+
"_cardStyles",
|
|
41469
|
+
"buttonVariant",
|
|
41470
|
+
"buttonText",
|
|
41471
|
+
"emptyMessage",
|
|
41472
|
+
"_sectionStyles"
|
|
41473
|
+
],
|
|
41474
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
41475
|
+
},
|
|
40541
41476
|
dataSchemas: {
|
|
40542
41477
|
...offeringsPreviewEventDataSchemas,
|
|
40543
41478
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -44135,11 +45070,11 @@ function buildNewsletterDisplay(source) {
|
|
|
44135
45070
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
44136
45071
|
privacyNote: null
|
|
44137
45072
|
};
|
|
44138
|
-
const
|
|
44139
|
-
const choices = resolveRuntimeChoices(
|
|
45073
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
45074
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
44140
45075
|
return {
|
|
44141
45076
|
kind: "newsletter-form",
|
|
44142
|
-
availability:
|
|
45077
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
44143
45078
|
className: source.className ?? null,
|
|
44144
45079
|
buttonLabel: form.buttonLabel,
|
|
44145
45080
|
successMessage: form.successMessage,
|
|
@@ -44196,60 +45131,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
44196
45131
|
default: return assertNever$2(source);
|
|
44197
45132
|
}
|
|
44198
45133
|
}
|
|
44199
|
-
function resolveRuntimeChoices(
|
|
44200
|
-
if (
|
|
44201
|
-
|
|
44202
|
-
|
|
44203
|
-
|
|
44204
|
-
|
|
44205
|
-
id: item.id,
|
|
44206
|
-
label: item.name
|
|
44207
|
-
})) : [];
|
|
44208
|
-
}
|
|
44209
|
-
case "brevo": {
|
|
44210
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
44211
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44212
|
-
id: String(item.id),
|
|
44213
|
-
label: item.name
|
|
44214
|
-
})) : [];
|
|
44215
|
-
}
|
|
44216
|
-
case "mailchimp": {
|
|
44217
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
44218
|
-
return (context.provider.provider === "mailchimp" ? context.provider.audiences.find((item) => item.id === targeting.audienceId) : void 0)?.interests.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44219
|
-
id: item.id,
|
|
44220
|
-
label: item.name
|
|
44221
|
-
})) ?? [];
|
|
44222
|
-
}
|
|
44223
|
-
}
|
|
44224
|
-
}
|
|
44225
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
44226
|
-
if (context?.tag !== "configured") return false;
|
|
44227
|
-
const provider = context.provider;
|
|
44228
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
44229
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
44230
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
44231
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
44232
|
-
}
|
|
44233
|
-
if (targeting.provider !== provider.provider) return false;
|
|
44234
|
-
switch (targeting.provider) {
|
|
44235
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
44236
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
44237
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
44238
|
-
}
|
|
44239
|
-
}
|
|
44240
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
44241
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
44242
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44243
|
-
}
|
|
44244
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
44245
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
44246
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44247
|
-
}
|
|
44248
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
44249
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
44250
|
-
if (!audience) return false;
|
|
44251
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
44252
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
45134
|
+
function resolveRuntimeChoices(assessment) {
|
|
45135
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
45136
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
45137
|
+
id: String(item.id),
|
|
45138
|
+
label: item.name
|
|
45139
|
+
}));
|
|
44253
45140
|
}
|
|
44254
45141
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
44255
45142
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -44353,6 +45240,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
44353
45240
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
44354
45241
|
const newsletterSignupBlockDefinition = {
|
|
44355
45242
|
manifest: newsletterSignupManifest,
|
|
45243
|
+
contentNormalizer: {
|
|
45244
|
+
fieldIds: ["targeting"],
|
|
45245
|
+
normalize: normalizeMailingListBlockContent
|
|
45246
|
+
},
|
|
44356
45247
|
runtime: newsletterFormBlockRuntime
|
|
44357
45248
|
};
|
|
44358
45249
|
//#endregion
|
|
@@ -45085,7 +45976,20 @@ const locationMapBlockDefinition = {
|
|
|
45085
45976
|
})], { gap: "md" })
|
|
45086
45977
|
})
|
|
45087
45978
|
}),
|
|
45088
|
-
|
|
45979
|
+
contentNormalizer: {
|
|
45980
|
+
fieldIds: [
|
|
45981
|
+
"heading",
|
|
45982
|
+
"locationSource",
|
|
45983
|
+
"venueId",
|
|
45984
|
+
"location",
|
|
45985
|
+
"showAddressText",
|
|
45986
|
+
"showDirections",
|
|
45987
|
+
"directionsLabel",
|
|
45988
|
+
"zoom",
|
|
45989
|
+
"heightPx"
|
|
45990
|
+
],
|
|
45991
|
+
normalize: normalizeLocationMapContent
|
|
45992
|
+
}
|
|
45089
45993
|
};
|
|
45090
45994
|
//#endregion
|
|
45091
45995
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -46290,17 +47194,7 @@ const linksTransforms = [{
|
|
|
46290
47194
|
id: "links.resolve",
|
|
46291
47195
|
kind: "formatter",
|
|
46292
47196
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
46293
|
-
run: (value, _options, context) =>
|
|
46294
|
-
if (!value || typeof value !== "object") return null;
|
|
46295
|
-
const link = value;
|
|
46296
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
46297
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
46298
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
46299
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
46300
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
46301
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
46302
|
-
return null;
|
|
46303
|
-
}
|
|
47197
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
46304
47198
|
}, {
|
|
46305
47199
|
id: "links.label",
|
|
46306
47200
|
kind: "formatter",
|
|
@@ -46327,6 +47221,21 @@ const linksTransforms = [{
|
|
|
46327
47221
|
return null;
|
|
46328
47222
|
}
|
|
46329
47223
|
}];
|
|
47224
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
47225
|
+
if (!value || typeof value !== "object") return null;
|
|
47226
|
+
const link = value;
|
|
47227
|
+
switch (link.kind) {
|
|
47228
|
+
case "internal": return resolveInternalLink(link, context);
|
|
47229
|
+
case "page": return resolvePageLink(link, context);
|
|
47230
|
+
case "entry": return resolveEntryLink(link, context);
|
|
47231
|
+
case "external":
|
|
47232
|
+
case "url": return resolveExternalLink(link);
|
|
47233
|
+
default: return resolvePreResolvedLink(link);
|
|
47234
|
+
}
|
|
47235
|
+
}
|
|
47236
|
+
function resolvePreResolvedLink(link) {
|
|
47237
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
47238
|
+
}
|
|
46330
47239
|
const eventCalendarSelectionParam = {
|
|
46331
47240
|
id: "events.calendarSelectionParam",
|
|
46332
47241
|
kind: "formatter",
|