@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/data.mjs
CHANGED
|
@@ -322,6 +322,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
322
322
|
default: return assertNever$3(pricing);
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
327
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
328
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
329
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
330
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
331
|
+
*/
|
|
332
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
333
|
+
switch (display.kind) {
|
|
334
|
+
case "free": return "Free";
|
|
335
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
336
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
337
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
338
|
+
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)}`;
|
|
339
|
+
case "unavailable": return "Pricing unavailable";
|
|
340
|
+
case "external": return display.label;
|
|
341
|
+
default: return assertNever$3(display);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/** Render an event's price directly from its pricing value. */
|
|
345
|
+
function formatEventPricing(pricing, options = {}) {
|
|
346
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
347
|
+
}
|
|
325
348
|
//#endregion
|
|
326
349
|
//#region ../core/src/event-page-surface-subject.ts
|
|
327
350
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -465,6 +488,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
465
488
|
}
|
|
466
489
|
//#endregion
|
|
467
490
|
//#region ../core/src/booking-date-time.ts
|
|
491
|
+
const DEFAULT_LOCALE = "en-US";
|
|
468
492
|
const FALLBACK_TIMEZONE = "UTC";
|
|
469
493
|
const START_OF_DAY = {
|
|
470
494
|
hour: 0,
|
|
@@ -587,6 +611,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
587
611
|
if (result.ok) return result.value;
|
|
588
612
|
throw new Error(formatParseError(result));
|
|
589
613
|
}
|
|
614
|
+
function formatBookingInstant(isoString, options) {
|
|
615
|
+
const date = new Date(isoString);
|
|
616
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
617
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
618
|
+
}
|
|
619
|
+
function formatBookingDate(input, format = {
|
|
620
|
+
weekday: "long",
|
|
621
|
+
year: "numeric",
|
|
622
|
+
month: "long",
|
|
623
|
+
day: "numeric"
|
|
624
|
+
}) {
|
|
625
|
+
return formatBookingInstant(input.startsAt, {
|
|
626
|
+
locale: input.locale,
|
|
627
|
+
timeZone: input.timeZone,
|
|
628
|
+
format
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
function formatBookingTime(input, format = {
|
|
632
|
+
hour: "numeric",
|
|
633
|
+
minute: "2-digit",
|
|
634
|
+
hour12: true
|
|
635
|
+
}) {
|
|
636
|
+
return formatBookingInstant(input.startsAt, {
|
|
637
|
+
locale: input.locale,
|
|
638
|
+
timeZone: input.timeZone,
|
|
639
|
+
format
|
|
640
|
+
});
|
|
641
|
+
}
|
|
590
642
|
function getBookingLocalDateKey(input) {
|
|
591
643
|
return formatDateKey(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
592
644
|
}
|
|
@@ -828,6 +880,14 @@ function formError(field) {
|
|
|
828
880
|
}
|
|
829
881
|
//#endregion
|
|
830
882
|
//#region ../core/src/mailing-list-targeting.ts
|
|
883
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
884
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
885
|
+
switch (targeting.provider) {
|
|
886
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
887
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
888
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
831
891
|
function planMailingListChoicePresentation(targeting) {
|
|
832
892
|
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
833
893
|
switch (targeting.provider) {
|
|
@@ -867,6 +927,103 @@ function planMailingListChoicePresentation(targeting) {
|
|
|
867
927
|
}
|
|
868
928
|
}
|
|
869
929
|
//#endregion
|
|
930
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
931
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
932
|
+
switch (provider.provider) {
|
|
933
|
+
case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
|
|
934
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
935
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function assessMailingListTargeting(context, targeting) {
|
|
939
|
+
if (context?.tag !== "configured") return {
|
|
940
|
+
tag: "unavailable",
|
|
941
|
+
reason: "setup_missing",
|
|
942
|
+
targeting
|
|
943
|
+
};
|
|
944
|
+
const catalog = context.provider;
|
|
945
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
946
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
947
|
+
return destination === null ? {
|
|
948
|
+
tag: "unavailable",
|
|
949
|
+
reason: "default_missing",
|
|
950
|
+
targeting
|
|
951
|
+
} : {
|
|
952
|
+
tag: "available",
|
|
953
|
+
value: {
|
|
954
|
+
mode: "default",
|
|
955
|
+
targeting,
|
|
956
|
+
provider: catalog.provider,
|
|
957
|
+
destination
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
962
|
+
switch (targeting.provider) {
|
|
963
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
964
|
+
provider: "native",
|
|
965
|
+
catalog,
|
|
966
|
+
targeting
|
|
967
|
+
}, catalog.topics) : {
|
|
968
|
+
tag: "unavailable",
|
|
969
|
+
reason: "provider_mismatch",
|
|
970
|
+
targeting
|
|
971
|
+
};
|
|
972
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
973
|
+
provider: "brevo",
|
|
974
|
+
catalog,
|
|
975
|
+
targeting
|
|
976
|
+
}, catalog.lists) : {
|
|
977
|
+
tag: "unavailable",
|
|
978
|
+
reason: "provider_mismatch",
|
|
979
|
+
targeting
|
|
980
|
+
};
|
|
981
|
+
case "mailchimp": {
|
|
982
|
+
if (catalog.provider !== "mailchimp") return {
|
|
983
|
+
tag: "unavailable",
|
|
984
|
+
reason: "provider_mismatch",
|
|
985
|
+
targeting
|
|
986
|
+
};
|
|
987
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
988
|
+
return audience === void 0 ? {
|
|
989
|
+
tag: "unavailable",
|
|
990
|
+
reason: "audience_missing",
|
|
991
|
+
value: {
|
|
992
|
+
mode: "custom",
|
|
993
|
+
provider: "mailchimp",
|
|
994
|
+
catalog,
|
|
995
|
+
targeting
|
|
996
|
+
}
|
|
997
|
+
} : assessMatchedChoices({
|
|
998
|
+
provider: "mailchimp",
|
|
999
|
+
catalog,
|
|
1000
|
+
targeting,
|
|
1001
|
+
audience
|
|
1002
|
+
}, audience.interests);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
function assessMatchedChoices(matched, choices) {
|
|
1007
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
1008
|
+
const available = new Set(choices.map((item) => item.id));
|
|
1009
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
1010
|
+
const value = {
|
|
1011
|
+
mode: "custom",
|
|
1012
|
+
...matched,
|
|
1013
|
+
choices,
|
|
1014
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
1015
|
+
};
|
|
1016
|
+
return missingIds.length > 0 ? {
|
|
1017
|
+
tag: "unavailable",
|
|
1018
|
+
reason: "choices_missing",
|
|
1019
|
+
missingIds,
|
|
1020
|
+
value
|
|
1021
|
+
} : {
|
|
1022
|
+
tag: "available",
|
|
1023
|
+
value
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
//#endregion
|
|
870
1027
|
//#region ../core/src/mailing-list-runtime.ts
|
|
871
1028
|
function parseMailingListRuntimeContext(value) {
|
|
872
1029
|
if (!isRecord$10(value)) return invalidRuntimeContext();
|
|
@@ -931,57 +1088,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
931
1088
|
function parseMailchimpRuntimeProvider(value) {
|
|
932
1089
|
if (!Array.isArray(value.audiences)) return null;
|
|
933
1090
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
for (const audience of value.audiences) {
|
|
937
|
-
if (!isRecord$10(audience)) return null;
|
|
938
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
939
|
-
const name = parseName(audience.name);
|
|
940
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
941
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
942
|
-
if (interests === null) return null;
|
|
943
|
-
audiences.push({
|
|
944
|
-
id,
|
|
945
|
-
name,
|
|
946
|
-
interests
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
return {
|
|
1091
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
1092
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
950
1093
|
provider: "mailchimp",
|
|
951
1094
|
defaultAudienceId,
|
|
952
1095
|
audiences
|
|
953
|
-
};
|
|
1096
|
+
} : null;
|
|
954
1097
|
}
|
|
955
|
-
function
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
interests
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1098
|
+
function parseMailchimpAudience(value) {
|
|
1099
|
+
if (!isRecord$10(value) || !Array.isArray(value.interests)) return null;
|
|
1100
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
1101
|
+
const name = parseName(value.name);
|
|
1102
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
1103
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
1104
|
+
id,
|
|
1105
|
+
name,
|
|
1106
|
+
interests
|
|
1107
|
+
} : null;
|
|
1108
|
+
}
|
|
1109
|
+
function parseMailchimpInterest(value) {
|
|
1110
|
+
if (!isRecord$10(value)) return null;
|
|
1111
|
+
const id = parseMailchimpInterestId(value.id);
|
|
1112
|
+
const name = parseName(value.name);
|
|
1113
|
+
const categoryName = parseName(value.categoryName);
|
|
1114
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
1115
|
+
id,
|
|
1116
|
+
name,
|
|
1117
|
+
categoryName
|
|
1118
|
+
} : null;
|
|
970
1119
|
}
|
|
971
1120
|
function parseNamedItems(value, parseId) {
|
|
972
1121
|
if (!Array.isArray(value)) return null;
|
|
973
|
-
const items =
|
|
974
|
-
for (const item of value) {
|
|
1122
|
+
const items = Array.from(value, (item) => {
|
|
975
1123
|
if (!isRecord$10(item)) return null;
|
|
976
1124
|
const id = parseId(item.id);
|
|
977
1125
|
const name = parseName(item.name);
|
|
978
|
-
|
|
979
|
-
items.push({
|
|
1126
|
+
return id !== null && name !== null ? {
|
|
980
1127
|
id,
|
|
981
1128
|
name
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
return items;
|
|
1129
|
+
} : null;
|
|
1130
|
+
});
|
|
1131
|
+
return items.every((item) => item !== null) ? items : null;
|
|
985
1132
|
}
|
|
986
1133
|
function parseName(value) {
|
|
987
1134
|
if (typeof value !== "string") return null;
|
|
@@ -997,6 +1144,7 @@ function invalidRuntimeContext() {
|
|
|
997
1144
|
//#endregion
|
|
998
1145
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
999
1146
|
function parseMailingListPlacementTargeting(value) {
|
|
1147
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
1000
1148
|
if (!isRecord$9(value)) return targetingError("shape");
|
|
1001
1149
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
1002
1150
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -1095,14 +1243,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
1095
1243
|
}
|
|
1096
1244
|
function parseUniqueIds(value, parseId) {
|
|
1097
1245
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
1098
|
-
|
|
1099
|
-
|
|
1246
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
1247
|
+
if (!parsed.ok) return parsed;
|
|
1100
1248
|
const id = parseId(item);
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
parsed.push(id);
|
|
1104
|
-
}
|
|
1105
|
-
return ok(parsed);
|
|
1249
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
1250
|
+
}, ok([]));
|
|
1106
1251
|
}
|
|
1107
1252
|
function isRecord$9(value) {
|
|
1108
1253
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1531,6 +1676,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
1531
1676
|
};
|
|
1532
1677
|
}
|
|
1533
1678
|
//#endregion
|
|
1679
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
1680
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
1681
|
+
event: {
|
|
1682
|
+
label: "Event",
|
|
1683
|
+
pluralLabel: "Events",
|
|
1684
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
1685
|
+
},
|
|
1686
|
+
class: {
|
|
1687
|
+
label: "Class",
|
|
1688
|
+
pluralLabel: "Classes",
|
|
1689
|
+
description: "Regular scheduled classes and group sessions."
|
|
1690
|
+
},
|
|
1691
|
+
course: {
|
|
1692
|
+
label: "Course",
|
|
1693
|
+
pluralLabel: "Courses",
|
|
1694
|
+
description: "A fixed set of dates that people book together."
|
|
1695
|
+
},
|
|
1696
|
+
term: {
|
|
1697
|
+
label: "Term",
|
|
1698
|
+
pluralLabel: "Terms",
|
|
1699
|
+
description: "A fixed term of sessions that people book together."
|
|
1700
|
+
},
|
|
1701
|
+
workshop: {
|
|
1702
|
+
label: "Workshop",
|
|
1703
|
+
pluralLabel: "Workshops",
|
|
1704
|
+
description: "One-off workshops, day sessions, or special events."
|
|
1705
|
+
},
|
|
1706
|
+
retreat: {
|
|
1707
|
+
label: "Retreat",
|
|
1708
|
+
pluralLabel: "Retreats",
|
|
1709
|
+
description: "Multi-day or residential immersive experiences."
|
|
1710
|
+
},
|
|
1711
|
+
performance: {
|
|
1712
|
+
label: "Performance",
|
|
1713
|
+
pluralLabel: "Performances",
|
|
1714
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
//#endregion
|
|
1534
1718
|
//#region ../media-core/src/transformRect.ts
|
|
1535
1719
|
function isValidTransformRectStructure(rect) {
|
|
1536
1720
|
if (!Array.isArray(rect) || rect.length !== 4) return false;
|
|
@@ -12157,6 +12341,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
12157
12341
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
12158
12342
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
12159
12343
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
12344
|
+
z.strictObject({
|
|
12345
|
+
currency: z.string().trim().length(3),
|
|
12346
|
+
totalCents: nonNegativeIntegerSchema,
|
|
12347
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
12348
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
12349
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
12350
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
12351
|
+
});
|
|
12160
12352
|
//#endregion
|
|
12161
12353
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
12162
12354
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -12397,6 +12589,10 @@ const publicEventBaseSchema = z.object({
|
|
|
12397
12589
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
12398
12590
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
12399
12591
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
12592
|
+
scheduleSummary: z.object({
|
|
12593
|
+
recurrenceDescription: z.string(),
|
|
12594
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
12595
|
+
}).nullable().optional(),
|
|
12400
12596
|
id: z.string(),
|
|
12401
12597
|
occurrenceId: z.string(),
|
|
12402
12598
|
seriesId: z.string(),
|
|
@@ -31978,6 +32174,15 @@ const formBlockDefinition = {
|
|
|
31978
32174
|
runtime: formBlockRuntime
|
|
31979
32175
|
};
|
|
31980
32176
|
//#endregion
|
|
32177
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
32178
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
32179
|
+
function normalizeMailingListBlockContent(record) {
|
|
32180
|
+
return record.targeting == null ? {
|
|
32181
|
+
...record,
|
|
32182
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
32183
|
+
} : record;
|
|
32184
|
+
}
|
|
32185
|
+
//#endregion
|
|
31981
32186
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
31982
32187
|
const contactNewsletterLayout = styledSection({
|
|
31983
32188
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -32141,6 +32346,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
32141
32346
|
],
|
|
32142
32347
|
icon: "MailPlus"
|
|
32143
32348
|
}),
|
|
32349
|
+
contentNormalizer: {
|
|
32350
|
+
fieldIds: ["targeting"],
|
|
32351
|
+
normalize: normalizeMailingListBlockContent
|
|
32352
|
+
},
|
|
32144
32353
|
dataSchemas: { form: formDataSchema.optional() },
|
|
32145
32354
|
dataLoaders: { form: {
|
|
32146
32355
|
endpoint: "getPublicFormById",
|
|
@@ -36619,70 +36828,274 @@ const occurrenceContextSchema = z.object({
|
|
|
36619
36828
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
36620
36829
|
}).nullable();
|
|
36621
36830
|
//#endregion
|
|
36622
|
-
//#region ../blocks/src/system/runtime/
|
|
36623
|
-
|
|
36624
|
-
|
|
36625
|
-
|
|
36626
|
-
|
|
36627
|
-
|
|
36628
|
-
|
|
36629
|
-
|
|
36630
|
-
|
|
36631
|
-
|
|
36632
|
-
|
|
36633
|
-
|
|
36634
|
-
|
|
36635
|
-
"invalidEventOfferingCatalogue"
|
|
36636
|
-
])
|
|
36637
|
-
});
|
|
36638
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
36639
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
36640
|
-
if (unsupported.success) return unsupported.data;
|
|
36641
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
36642
|
-
if (parsed.ok) return parsed.value;
|
|
36643
|
-
ctx.addIssue({
|
|
36644
|
-
code: z.ZodIssueCode.custom,
|
|
36645
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
36646
|
-
});
|
|
36647
|
-
return z.NEVER;
|
|
36648
|
-
});
|
|
36649
|
-
function resolveEventRegistrationScope(context) {
|
|
36650
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
36651
|
-
if (occurrenceSeriesId) return {
|
|
36652
|
-
kind: "occurrenceSeries",
|
|
36653
|
-
seriesId: occurrenceSeriesId
|
|
36831
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
36832
|
+
/**
|
|
36833
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
36834
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
36835
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
36836
|
+
*
|
|
36837
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
36838
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
36839
|
+
*/
|
|
36840
|
+
function getEventAvailability(event) {
|
|
36841
|
+
if (event.capacity == null) return {
|
|
36842
|
+
available: null,
|
|
36843
|
+
isFull: false
|
|
36654
36844
|
};
|
|
36655
|
-
|
|
36656
|
-
|
|
36657
|
-
|
|
36845
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
36846
|
+
if (available <= 0) return {
|
|
36847
|
+
available: 0,
|
|
36848
|
+
isFull: true
|
|
36658
36849
|
};
|
|
36659
|
-
|
|
36660
|
-
|
|
36661
|
-
|
|
36662
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
36850
|
+
return {
|
|
36851
|
+
available,
|
|
36852
|
+
isFull: false
|
|
36663
36853
|
};
|
|
36664
|
-
|
|
36665
|
-
|
|
36666
|
-
|
|
36854
|
+
}
|
|
36855
|
+
/**
|
|
36856
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
36857
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
36858
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
36859
|
+
*
|
|
36860
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
36861
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
36862
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
36863
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
36864
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
36865
|
+
*/
|
|
36866
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
36867
|
+
if (!attendanceMode) return event;
|
|
36868
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
36869
|
+
}
|
|
36870
|
+
/**
|
|
36871
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
36872
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
36873
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
36874
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
36875
|
+
* `capacity - registeredCount` fallback.
|
|
36876
|
+
*/
|
|
36877
|
+
function canJoinEventWaitlist(event, options) {
|
|
36878
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
36879
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
36880
|
+
}
|
|
36881
|
+
/**
|
|
36882
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
36883
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
36884
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
36885
|
+
* to be stale on a cached page.
|
|
36886
|
+
*
|
|
36887
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
36888
|
+
*
|
|
36889
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
36890
|
+
* 5% floor stops large events staying silent until three remain.
|
|
36891
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
36892
|
+
*/
|
|
36893
|
+
function lowCapacityThreshold(capacity) {
|
|
36894
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
36895
|
+
}
|
|
36896
|
+
function getRemainingPlaces(source) {
|
|
36897
|
+
const { available, isFull } = getEventAvailability(source);
|
|
36898
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
36899
|
+
if (isFull) return {
|
|
36900
|
+
kind: "full",
|
|
36901
|
+
waitlist: canJoinEventWaitlist(source)
|
|
36667
36902
|
};
|
|
36668
|
-
|
|
36903
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
36904
|
+
kind: "low",
|
|
36905
|
+
remaining: available
|
|
36906
|
+
};
|
|
36907
|
+
return { kind: "open" };
|
|
36669
36908
|
}
|
|
36670
|
-
|
|
36671
|
-
|
|
36672
|
-
|
|
36673
|
-
|
|
36674
|
-
|
|
36675
|
-
|
|
36676
|
-
|
|
36677
|
-
|
|
36678
|
-
|
|
36679
|
-
case "
|
|
36680
|
-
case "
|
|
36909
|
+
/**
|
|
36910
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
36911
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
36912
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
36913
|
+
* it in rather than re-deriving the count.
|
|
36914
|
+
*/
|
|
36915
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
36916
|
+
const remaining = getRemainingPlaces(source);
|
|
36917
|
+
switch (remaining.kind) {
|
|
36918
|
+
case "unlimited":
|
|
36919
|
+
case "open": return null;
|
|
36920
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
36921
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
36922
|
+
}
|
|
36923
|
+
}
|
|
36924
|
+
function formatPlacesLeft(count, compact) {
|
|
36925
|
+
if (compact) return `${count} left`;
|
|
36926
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
36927
|
+
}
|
|
36928
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
36929
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
36930
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
36931
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
36932
|
+
}
|
|
36933
|
+
/**
|
|
36934
|
+
* Which capacity figure wins when they disagree.
|
|
36935
|
+
*
|
|
36936
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
36937
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
36938
|
+
* The registration write path admits or refuses per mode
|
|
36939
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
36940
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
36941
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
36942
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
36943
|
+
*
|
|
36944
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
36945
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
36946
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
36947
|
+
* the aggregate, unchanged.
|
|
36948
|
+
*/
|
|
36949
|
+
function findHybridModeRows(event) {
|
|
36950
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
36951
|
+
const rows = event.attendanceModes ?? [];
|
|
36952
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
36953
|
+
const online = rows.find((row) => row.mode === "online");
|
|
36954
|
+
return inPerson && online ? {
|
|
36955
|
+
inPerson,
|
|
36956
|
+
online
|
|
36957
|
+
} : null;
|
|
36958
|
+
}
|
|
36959
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
36960
|
+
function remainingPlacesRank(remaining) {
|
|
36961
|
+
switch (remaining.kind) {
|
|
36962
|
+
case "unlimited": return 4;
|
|
36963
|
+
case "open": return 3;
|
|
36964
|
+
case "low": return 2;
|
|
36965
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
36966
|
+
}
|
|
36967
|
+
}
|
|
36968
|
+
function isMoreOpen(candidate, than) {
|
|
36969
|
+
const rank = remainingPlacesRank(candidate);
|
|
36970
|
+
const otherRank = remainingPlacesRank(than);
|
|
36971
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
36972
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
36973
|
+
}
|
|
36974
|
+
/** True when `candidate` has less room left than `than`. */
|
|
36975
|
+
function isScarcer(candidate, than) {
|
|
36976
|
+
return isMoreOpen(than, candidate);
|
|
36977
|
+
}
|
|
36978
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
36979
|
+
in_person: "In person",
|
|
36980
|
+
online: "Online"
|
|
36981
|
+
};
|
|
36982
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
36983
|
+
const PLACES_AVAILABLE = "Places available";
|
|
36984
|
+
/**
|
|
36985
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
36986
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
36987
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
36988
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
36989
|
+
* promise the registration wizard would otherwise have to break.
|
|
36990
|
+
*
|
|
36991
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
36992
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
36993
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
36994
|
+
* { compact: true } -> "Online: 3 left"
|
|
36995
|
+
*/
|
|
36996
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
36997
|
+
const rows = findHybridModeRows(event);
|
|
36998
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
36999
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
37000
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
37001
|
+
if (inPerson === online) return inPerson;
|
|
37002
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
37003
|
+
return formatBothHybridSides(rows, {
|
|
37004
|
+
inPerson,
|
|
37005
|
+
online
|
|
37006
|
+
});
|
|
37007
|
+
}
|
|
37008
|
+
/**
|
|
37009
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
37010
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
37011
|
+
*/
|
|
37012
|
+
function formatBothHybridSides(rows, labels) {
|
|
37013
|
+
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(" · ");
|
|
37014
|
+
}
|
|
37015
|
+
function namedModePlaces(mode, label) {
|
|
37016
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
37017
|
+
}
|
|
37018
|
+
/**
|
|
37019
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
37020
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
37021
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
37022
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
37023
|
+
* how the event is delivered rather than about its remaining places.
|
|
37024
|
+
*/
|
|
37025
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
37026
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
37027
|
+
const online = getRemainingPlaces(rows.online);
|
|
37028
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
37029
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
37030
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
37031
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
37032
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
37033
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
36681
37034
|
}
|
|
37035
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
37036
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
37037
|
+
}
|
|
37038
|
+
function rowFor(rows, mode) {
|
|
37039
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
36682
37040
|
}
|
|
36683
37041
|
//#endregion
|
|
37042
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
37043
|
+
const registrationDisplaySchema = z.object({
|
|
37044
|
+
venue: z.enum(["shown", "hidden"]),
|
|
37045
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
37046
|
+
});
|
|
37047
|
+
function resolveRegistrationDisplay(source) {
|
|
37048
|
+
return {
|
|
37049
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
37050
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
37051
|
+
};
|
|
37052
|
+
}
|
|
37053
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
37054
|
+
function shownVenue(event, display) {
|
|
37055
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
37056
|
+
}
|
|
37057
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
37058
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
37059
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
37060
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
37061
|
+
return capacityPlacesLabel(source, display, wording);
|
|
37062
|
+
}
|
|
37063
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
37064
|
+
const remaining = getRemainingPlaces(source);
|
|
37065
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
37066
|
+
switch (remaining.kind) {
|
|
37067
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
37068
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
37069
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
37070
|
+
case "open": return wording.open ?? null;
|
|
37071
|
+
default: return assertNever$3(remaining);
|
|
37072
|
+
}
|
|
37073
|
+
}
|
|
37074
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
37075
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
37076
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
37077
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
37078
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
37079
|
+
}).join(" · ") || null;
|
|
37080
|
+
}
|
|
37081
|
+
function ticketPlacesLabel(remaining, display) {
|
|
37082
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
37083
|
+
return formatTicketTypeRemaining(remaining);
|
|
37084
|
+
}
|
|
37085
|
+
//#endregion
|
|
37086
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
37087
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
37088
|
+
kind: z.literal("preview"),
|
|
37089
|
+
token: z.string().min(1)
|
|
37090
|
+
}).strict()]);
|
|
37091
|
+
//#endregion
|
|
36684
37092
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
36685
37093
|
/**
|
|
37094
|
+
* Date and time presentation for events: the single place an event's
|
|
37095
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
37096
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
37097
|
+
*/
|
|
37098
|
+
/**
|
|
36686
37099
|
* The English locale a site's public dates are written in, read from the
|
|
36687
37100
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
36688
37101
|
*
|
|
@@ -36702,6 +37115,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
36702
37115
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
36703
37116
|
return "en-US";
|
|
36704
37117
|
}
|
|
37118
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
37119
|
+
const locale = options?.locale ?? "en-US";
|
|
37120
|
+
const dateTime = toScheduledBookingDateTime({
|
|
37121
|
+
startsAt: isoTimestamp,
|
|
37122
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
37123
|
+
locale
|
|
37124
|
+
});
|
|
37125
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
37126
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
37127
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
37128
|
+
return {
|
|
37129
|
+
weekday,
|
|
37130
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
37131
|
+
month,
|
|
37132
|
+
label: formatBookingDate(dateTime, {
|
|
37133
|
+
weekday: "long",
|
|
37134
|
+
year: "numeric",
|
|
37135
|
+
month: "long",
|
|
37136
|
+
day: "numeric"
|
|
37137
|
+
})
|
|
37138
|
+
};
|
|
37139
|
+
}
|
|
36705
37140
|
//#endregion
|
|
36706
37141
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
36707
37142
|
function isRecord$6(value) {
|
|
@@ -36721,6 +37156,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
36721
37156
|
};
|
|
36722
37157
|
}
|
|
36723
37158
|
//#endregion
|
|
37159
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
37160
|
+
/**
|
|
37161
|
+
* Format an event's price directly from its pricing value (without the full
|
|
37162
|
+
* event). Same output as {@link formatEventPrice}.
|
|
37163
|
+
*/
|
|
37164
|
+
function formatEventPriceDisplay(pricing) {
|
|
37165
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
37166
|
+
}
|
|
37167
|
+
//#endregion
|
|
36724
37168
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
36725
37169
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
36726
37170
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -36755,52 +37199,6 @@ function eventListWindowEvents(events, window) {
|
|
|
36755
37199
|
});
|
|
36756
37200
|
}
|
|
36757
37201
|
//#endregion
|
|
36758
|
-
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
36759
|
-
const previewStageSchema = z.enum(["preview", "published"]);
|
|
36760
|
-
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
36761
|
-
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
36762
|
-
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
36763
|
-
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
36764
|
-
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
36765
|
-
const columnOptionSchema = z.enum([
|
|
36766
|
-
"2",
|
|
36767
|
-
"3",
|
|
36768
|
-
"4"
|
|
36769
|
-
]);
|
|
36770
|
-
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
36771
|
-
const filterAutoShowSchema = z.enum([
|
|
36772
|
-
"auto",
|
|
36773
|
-
"always",
|
|
36774
|
-
"never"
|
|
36775
|
-
]);
|
|
36776
|
-
const calendarTabViewsSchema = z.enum([
|
|
36777
|
-
"both",
|
|
36778
|
-
"month",
|
|
36779
|
-
"week"
|
|
36780
|
-
]);
|
|
36781
|
-
//#endregion
|
|
36782
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
36783
|
-
/**
|
|
36784
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
36785
|
-
*
|
|
36786
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
36787
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
36788
|
-
* @returns Array of wizard steps to display
|
|
36789
|
-
*/
|
|
36790
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
36791
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
36792
|
-
"select-event",
|
|
36793
|
-
"select-tickets",
|
|
36794
|
-
"enter-details"
|
|
36795
|
-
];
|
|
36796
|
-
if (!needsPaymentStep) return baseSteps;
|
|
36797
|
-
return paymentActive ? [
|
|
36798
|
-
...baseSteps,
|
|
36799
|
-
"select-payment",
|
|
36800
|
-
"payment"
|
|
36801
|
-
] : [...baseSteps, "select-payment"];
|
|
36802
|
-
}
|
|
36803
|
-
//#endregion
|
|
36804
37202
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
36805
37203
|
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
36806
37204
|
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
@@ -36824,6 +37222,424 @@ function resolveEventRequiresPayment(input) {
|
|
|
36824
37222
|
return publicEventPricingType(input.event.pricing) === "paid";
|
|
36825
37223
|
}
|
|
36826
37224
|
//#endregion
|
|
37225
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
37226
|
+
/**
|
|
37227
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
37228
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
37229
|
+
* English when the site names no zone.
|
|
37230
|
+
*/
|
|
37231
|
+
function bookingDateLocale(siteTimeZone) {
|
|
37232
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
37233
|
+
}
|
|
37234
|
+
function bookingInstant(startsAt, input) {
|
|
37235
|
+
return toScheduledBookingDateTime({
|
|
37236
|
+
startsAt,
|
|
37237
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
37238
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
37239
|
+
});
|
|
37240
|
+
}
|
|
37241
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
37242
|
+
function bookingClock(startsAt, input) {
|
|
37243
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
37244
|
+
hour: "numeric",
|
|
37245
|
+
minute: "2-digit",
|
|
37246
|
+
hour12: true
|
|
37247
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
37248
|
+
}
|
|
37249
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
37250
|
+
function clockRange(input) {
|
|
37251
|
+
const start = bookingClock(input.startsAt, input);
|
|
37252
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
37253
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
37254
|
+
}
|
|
37255
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
37256
|
+
function formatBookingScheduleSummary(event) {
|
|
37257
|
+
const summary = event.scheduleSummary;
|
|
37258
|
+
if (!summary) return null;
|
|
37259
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
37260
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
37261
|
+
timeZone: "UTC",
|
|
37262
|
+
siteTimeZone: event.siteTimeZone
|
|
37263
|
+
}, "time") : null;
|
|
37264
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
37265
|
+
}
|
|
37266
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
37267
|
+
function formatBookingWhen(input, variant) {
|
|
37268
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
37269
|
+
const day = formatBookingDate(instant, {
|
|
37270
|
+
weekday: "short",
|
|
37271
|
+
day: "numeric",
|
|
37272
|
+
month: "short"
|
|
37273
|
+
});
|
|
37274
|
+
switch (variant) {
|
|
37275
|
+
case "day": return day;
|
|
37276
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
37277
|
+
weekday: "long",
|
|
37278
|
+
day: "numeric",
|
|
37279
|
+
month: "long"
|
|
37280
|
+
});
|
|
37281
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
37282
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
37283
|
+
month: "long",
|
|
37284
|
+
year: "numeric"
|
|
37285
|
+
});
|
|
37286
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
37287
|
+
case "timeRange": return clockRange(input);
|
|
37288
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
37289
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
37290
|
+
}
|
|
37291
|
+
}
|
|
37292
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
37293
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
37294
|
+
return formatBookingWhen({
|
|
37295
|
+
startsAt: isoTimestamp,
|
|
37296
|
+
timeZone: options?.timeZone,
|
|
37297
|
+
siteTimeZone: options?.siteTimeZone
|
|
37298
|
+
}, "short");
|
|
37299
|
+
}
|
|
37300
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
37301
|
+
function occurrenceTitleOverride(occurrence) {
|
|
37302
|
+
const title = occurrence?.overrides?.title;
|
|
37303
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
37304
|
+
}
|
|
37305
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
37306
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
37307
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
37308
|
+
return event && title ? {
|
|
37309
|
+
...event,
|
|
37310
|
+
title
|
|
37311
|
+
} : event;
|
|
37312
|
+
}
|
|
37313
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
37314
|
+
const first = sessions[0];
|
|
37315
|
+
if (!first) return null;
|
|
37316
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
37317
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
37318
|
+
timeZone: first.timeZone,
|
|
37319
|
+
siteTimeZone
|
|
37320
|
+
});
|
|
37321
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
37322
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
37323
|
+
timeZone: last.timeZone,
|
|
37324
|
+
siteTimeZone
|
|
37325
|
+
});
|
|
37326
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
37327
|
+
}
|
|
37328
|
+
/**
|
|
37329
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
37330
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
37331
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
37332
|
+
*/
|
|
37333
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
37334
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
37335
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
37336
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
37337
|
+
}
|
|
37338
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
37339
|
+
function scheduleInput(event, occurrence) {
|
|
37340
|
+
const times = occurrence?.startsAt ? {
|
|
37341
|
+
startsAt: occurrence.startsAt,
|
|
37342
|
+
endsAt: occurrence.endsAt ?? null
|
|
37343
|
+
} : {
|
|
37344
|
+
startsAt: event.startsAt,
|
|
37345
|
+
endsAt: event.endsAt
|
|
37346
|
+
};
|
|
37347
|
+
if (!times.startsAt) return null;
|
|
37348
|
+
return {
|
|
37349
|
+
...times,
|
|
37350
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
37351
|
+
siteTimeZone: event.siteTimeZone
|
|
37352
|
+
};
|
|
37353
|
+
}
|
|
37354
|
+
//#endregion
|
|
37355
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
37356
|
+
function registrationRoute(input) {
|
|
37357
|
+
const base = input.chooseEvent ? [
|
|
37358
|
+
"select-event",
|
|
37359
|
+
"select-tickets",
|
|
37360
|
+
"enter-details"
|
|
37361
|
+
] : ["select-tickets", "enter-details"];
|
|
37362
|
+
switch (input.payment) {
|
|
37363
|
+
case "none": return base;
|
|
37364
|
+
case "options": return [...base, "select-payment"];
|
|
37365
|
+
case "optionsAndPayment": return [
|
|
37366
|
+
...base,
|
|
37367
|
+
"select-payment",
|
|
37368
|
+
"payment"
|
|
37369
|
+
];
|
|
37370
|
+
}
|
|
37371
|
+
}
|
|
37372
|
+
const REGISTRATION_STEP_LABELS = [
|
|
37373
|
+
"Event",
|
|
37374
|
+
"Date",
|
|
37375
|
+
"Tickets",
|
|
37376
|
+
"Places",
|
|
37377
|
+
"Your details",
|
|
37378
|
+
"How you’ll pay",
|
|
37379
|
+
"Payment"
|
|
37380
|
+
];
|
|
37381
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
37382
|
+
function getEventSelectionMode(events) {
|
|
37383
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
37384
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
37385
|
+
}
|
|
37386
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
37387
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
37388
|
+
return {
|
|
37389
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
37390
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
37391
|
+
};
|
|
37392
|
+
}
|
|
37393
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
37394
|
+
function registrationStepLabel(step, context) {
|
|
37395
|
+
switch (step) {
|
|
37396
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
37397
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
37398
|
+
case "enter-details": return "Your details";
|
|
37399
|
+
case "select-payment": return "How you’ll pay";
|
|
37400
|
+
case "payment": return "Payment";
|
|
37401
|
+
}
|
|
37402
|
+
}
|
|
37403
|
+
function bookingButtonText(buttonText) {
|
|
37404
|
+
return buttonText?.trim() || "Book your place";
|
|
37405
|
+
}
|
|
37406
|
+
function placesLabel(event, input, compact) {
|
|
37407
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
37408
|
+
}
|
|
37409
|
+
function isFull(event, mode) {
|
|
37410
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
37411
|
+
full: "full",
|
|
37412
|
+
waitlist: "full"
|
|
37413
|
+
}) === "full";
|
|
37414
|
+
}
|
|
37415
|
+
function priceLabel(event) {
|
|
37416
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
37417
|
+
}
|
|
37418
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
37419
|
+
function lowestPaidAmount(display) {
|
|
37420
|
+
switch (display.kind) {
|
|
37421
|
+
case "exact":
|
|
37422
|
+
case "from": return display.amount;
|
|
37423
|
+
case "range": return display.minAmount;
|
|
37424
|
+
case "mixed": return display.paidFromAmount;
|
|
37425
|
+
case "free":
|
|
37426
|
+
case "unavailable":
|
|
37427
|
+
case "external": return null;
|
|
37428
|
+
}
|
|
37429
|
+
}
|
|
37430
|
+
/**
|
|
37431
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
37432
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
37433
|
+
*/
|
|
37434
|
+
function seriesPriceLabel(events) {
|
|
37435
|
+
const firstEvent = events[0];
|
|
37436
|
+
if (!firstEvent) return null;
|
|
37437
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
37438
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
37439
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
37440
|
+
const lowest = displays.flatMap((display) => {
|
|
37441
|
+
const amount = lowestPaidAmount(display);
|
|
37442
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
37443
|
+
amount,
|
|
37444
|
+
currency: display.currency
|
|
37445
|
+
}];
|
|
37446
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
37447
|
+
return lowest ? formatBookingPriceDisplay({
|
|
37448
|
+
kind: "from",
|
|
37449
|
+
amount: lowest.amount,
|
|
37450
|
+
currency: lowest.currency
|
|
37451
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
37452
|
+
}
|
|
37453
|
+
function dateTile(event) {
|
|
37454
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
37455
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
37456
|
+
return {
|
|
37457
|
+
month: rail.month,
|
|
37458
|
+
day: rail.day
|
|
37459
|
+
};
|
|
37460
|
+
}
|
|
37461
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
37462
|
+
function formatBookingShortDate(event) {
|
|
37463
|
+
return formatBookingWhen(event, "day");
|
|
37464
|
+
}
|
|
37465
|
+
function byStart(left, right) {
|
|
37466
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
37467
|
+
}
|
|
37468
|
+
function singleEntry(event, input) {
|
|
37469
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
37470
|
+
return {
|
|
37471
|
+
kind: "single",
|
|
37472
|
+
title: event.title,
|
|
37473
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
37474
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
37475
|
+
venue: shownVenue(event, input.display),
|
|
37476
|
+
price: priceLabel(event),
|
|
37477
|
+
places: placesLabel(event, input, false),
|
|
37478
|
+
tile: dateTile(event),
|
|
37479
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
37480
|
+
};
|
|
37481
|
+
}
|
|
37482
|
+
function chooseDateEntry(input) {
|
|
37483
|
+
const ordered = [...input.events].sort(byStart);
|
|
37484
|
+
const first = ordered[0];
|
|
37485
|
+
const shown = ordered.slice(0, 4);
|
|
37486
|
+
return {
|
|
37487
|
+
kind: "chooseDate",
|
|
37488
|
+
title: first?.title ?? "",
|
|
37489
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
37490
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
37491
|
+
price: seriesPriceLabel(ordered),
|
|
37492
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
37493
|
+
dateCount: ordered.length,
|
|
37494
|
+
dates: shown.map((event) => ({
|
|
37495
|
+
selectionId: event.selectionId,
|
|
37496
|
+
label: formatBookingShortDate(event),
|
|
37497
|
+
places: placesLabel(event, input, true),
|
|
37498
|
+
full: isFull(event, input.attendanceMode)
|
|
37499
|
+
})),
|
|
37500
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
37501
|
+
action: "Choose a date"
|
|
37502
|
+
};
|
|
37503
|
+
}
|
|
37504
|
+
/** The card before a booking starts; the server renders this too. */
|
|
37505
|
+
function idleBookingEntry(input) {
|
|
37506
|
+
if (input.event) return singleEntry(input.event, input);
|
|
37507
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
37508
|
+
if (only) return singleEntry(only, input);
|
|
37509
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
37510
|
+
return {
|
|
37511
|
+
kind: "chooseEvent",
|
|
37512
|
+
title: input.events[0]?.title ?? "",
|
|
37513
|
+
count: input.events.length,
|
|
37514
|
+
noun: input.noun.pluralLabel,
|
|
37515
|
+
action: "Choose an event"
|
|
37516
|
+
};
|
|
37517
|
+
}
|
|
37518
|
+
//#endregion
|
|
37519
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
37520
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
37521
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
37522
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
37523
|
+
{
|
|
37524
|
+
preset: "class",
|
|
37525
|
+
sourceKey: "eventPreset:class",
|
|
37526
|
+
dataKey: "classEvents",
|
|
37527
|
+
label: "Classes"
|
|
37528
|
+
},
|
|
37529
|
+
{
|
|
37530
|
+
preset: "workshop",
|
|
37531
|
+
sourceKey: "eventPreset:workshop",
|
|
37532
|
+
dataKey: "workshopEvents",
|
|
37533
|
+
label: "Workshops"
|
|
37534
|
+
},
|
|
37535
|
+
{
|
|
37536
|
+
preset: "retreat",
|
|
37537
|
+
sourceKey: "eventPreset:retreat",
|
|
37538
|
+
dataKey: "retreatEvents",
|
|
37539
|
+
label: "Retreats"
|
|
37540
|
+
},
|
|
37541
|
+
{
|
|
37542
|
+
preset: "performance",
|
|
37543
|
+
sourceKey: "eventPreset:performance",
|
|
37544
|
+
dataKey: "performanceEvents",
|
|
37545
|
+
label: "Performances"
|
|
37546
|
+
}
|
|
37547
|
+
];
|
|
37548
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
37549
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
37550
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
37551
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
37552
|
+
kind: "eventPreset",
|
|
37553
|
+
preset: definition.preset
|
|
37554
|
+
}]));
|
|
37555
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
37556
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
37557
|
+
}
|
|
37558
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
37559
|
+
if (value == null) return { kind: "legacy" };
|
|
37560
|
+
if (value.length === 0) return { kind: "default" };
|
|
37561
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
37562
|
+
return keys.length > 0 ? {
|
|
37563
|
+
kind: "custom",
|
|
37564
|
+
keys
|
|
37565
|
+
} : { kind: "default" };
|
|
37566
|
+
}
|
|
37567
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
37568
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
37569
|
+
return keys.length >= 2 ? keys : [];
|
|
37570
|
+
}
|
|
37571
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
37572
|
+
if (!isRecord$5(value)) return null;
|
|
37573
|
+
const groupOrderValue = value.groupOrder;
|
|
37574
|
+
if (Array.isArray(groupOrderValue)) {
|
|
37575
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
37576
|
+
return {
|
|
37577
|
+
...value,
|
|
37578
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
37579
|
+
};
|
|
37580
|
+
}
|
|
37581
|
+
if (groupOrderValue != null) return {
|
|
37582
|
+
...value,
|
|
37583
|
+
groupOrder: []
|
|
37584
|
+
};
|
|
37585
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$5) : []);
|
|
37586
|
+
return legacyOrder.length > 0 ? {
|
|
37587
|
+
...value,
|
|
37588
|
+
groupOrder: legacyOrder
|
|
37589
|
+
} : value;
|
|
37590
|
+
}
|
|
37591
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
37592
|
+
function sourceFromPresetSummary(preset) {
|
|
37593
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
37594
|
+
if (preset.engine !== "event_series") return null;
|
|
37595
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
37596
|
+
kind: "eventPreset",
|
|
37597
|
+
preset: preset.canonicalBehaviour
|
|
37598
|
+
};
|
|
37599
|
+
return null;
|
|
37600
|
+
}
|
|
37601
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
37602
|
+
const keys = [];
|
|
37603
|
+
for (const value of values) {
|
|
37604
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
37605
|
+
if (!keys.includes(value)) keys.push(value);
|
|
37606
|
+
}
|
|
37607
|
+
return keys;
|
|
37608
|
+
}
|
|
37609
|
+
function isRecord$5(value) {
|
|
37610
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37611
|
+
}
|
|
37612
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
37613
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
37614
|
+
}
|
|
37615
|
+
//#endregion
|
|
37616
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
37617
|
+
function offeringKindForEvent(event) {
|
|
37618
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
37619
|
+
}
|
|
37620
|
+
function presetKind(preset) {
|
|
37621
|
+
const source = sourceFromPresetSummary(preset);
|
|
37622
|
+
if (!source) return null;
|
|
37623
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
37624
|
+
}
|
|
37625
|
+
/**
|
|
37626
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
37627
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
37628
|
+
* name stands in when the site has none.
|
|
37629
|
+
*/
|
|
37630
|
+
function offeringNounForEvent(event, presets) {
|
|
37631
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
37632
|
+
const kind = offeringKindForEvent(event);
|
|
37633
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
37634
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
37635
|
+
}
|
|
37636
|
+
function lowerCased(noun) {
|
|
37637
|
+
return {
|
|
37638
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
37639
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
37640
|
+
};
|
|
37641
|
+
}
|
|
37642
|
+
//#endregion
|
|
36827
37643
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
36828
37644
|
function toRegistrationEvent(event) {
|
|
36829
37645
|
return {
|
|
@@ -36868,6 +37684,181 @@ function toWholeSeriesRegistrationEvents(events) {
|
|
|
36868
37684
|
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
36869
37685
|
}
|
|
36870
37686
|
//#endregion
|
|
37687
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
37688
|
+
/**
|
|
37689
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
37690
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
37691
|
+
* so the server and the client agree on one card.
|
|
37692
|
+
*/
|
|
37693
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
37694
|
+
const tileSchema = z.object({
|
|
37695
|
+
month: z.string(),
|
|
37696
|
+
day: z.string()
|
|
37697
|
+
}).nullable();
|
|
37698
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
37699
|
+
z.object({
|
|
37700
|
+
kind: z.literal("single"),
|
|
37701
|
+
title: z.string(),
|
|
37702
|
+
when: z.string().nullable(),
|
|
37703
|
+
shortWhen: z.string().nullable(),
|
|
37704
|
+
venue: z.string().nullable(),
|
|
37705
|
+
price: z.string().nullable(),
|
|
37706
|
+
places: z.string().nullable(),
|
|
37707
|
+
tile: tileSchema,
|
|
37708
|
+
action: z.string()
|
|
37709
|
+
}),
|
|
37710
|
+
z.object({
|
|
37711
|
+
kind: z.literal("chooseDate"),
|
|
37712
|
+
title: z.string(),
|
|
37713
|
+
schedule: z.string(),
|
|
37714
|
+
venue: z.string().nullable(),
|
|
37715
|
+
price: z.string().nullable(),
|
|
37716
|
+
nextDate: z.string().nullable(),
|
|
37717
|
+
dateCount: z.number(),
|
|
37718
|
+
dates: z.array(z.object({
|
|
37719
|
+
selectionId: z.string(),
|
|
37720
|
+
label: z.string(),
|
|
37721
|
+
places: z.string().nullable(),
|
|
37722
|
+
full: z.boolean()
|
|
37723
|
+
})),
|
|
37724
|
+
moreCount: z.number(),
|
|
37725
|
+
action: z.string()
|
|
37726
|
+
}),
|
|
37727
|
+
z.object({
|
|
37728
|
+
kind: z.literal("chooseEvent"),
|
|
37729
|
+
title: z.string(),
|
|
37730
|
+
count: z.number(),
|
|
37731
|
+
noun: z.string(),
|
|
37732
|
+
action: z.string()
|
|
37733
|
+
})
|
|
37734
|
+
]);
|
|
37735
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
37736
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
37737
|
+
}
|
|
37738
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
37739
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37740
|
+
return {
|
|
37741
|
+
scopedEvents,
|
|
37742
|
+
preSelected: findPreSelectedEvent({
|
|
37743
|
+
scopedEvents,
|
|
37744
|
+
occurrenceContext: source.occurrenceContext
|
|
37745
|
+
})
|
|
37746
|
+
};
|
|
37747
|
+
}
|
|
37748
|
+
function nounFor(scoped, presets) {
|
|
37749
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
37750
|
+
}
|
|
37751
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
37752
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
37753
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
37754
|
+
}
|
|
37755
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
37756
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
37757
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
37758
|
+
return idleBookingEntry({
|
|
37759
|
+
events: scoped.scopedEvents,
|
|
37760
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
37761
|
+
display,
|
|
37762
|
+
buttonText: source.buttonText,
|
|
37763
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
37764
|
+
attendanceMode: null
|
|
37765
|
+
});
|
|
37766
|
+
}
|
|
37767
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
37768
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
37769
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
37770
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
37771
|
+
if (!entry) return null;
|
|
37772
|
+
return {
|
|
37773
|
+
kind: "event-registration",
|
|
37774
|
+
state: "booking-card",
|
|
37775
|
+
className: source.className ?? null,
|
|
37776
|
+
entry,
|
|
37777
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
37778
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
37779
|
+
};
|
|
37780
|
+
}
|
|
37781
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
37782
|
+
kind: z.literal("unsupported"),
|
|
37783
|
+
reason: z.enum([
|
|
37784
|
+
"unsupportedSubject",
|
|
37785
|
+
"invalidEventSeriesId",
|
|
37786
|
+
"invalidEventSeriesBookingScope",
|
|
37787
|
+
"invalidEventOfferingId",
|
|
37788
|
+
"invalidEventOfferingBookingScope",
|
|
37789
|
+
"invalidEventOfferingCatalogue"
|
|
37790
|
+
])
|
|
37791
|
+
});
|
|
37792
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
37793
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
37794
|
+
if (unsupported.success) return unsupported.data;
|
|
37795
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
37796
|
+
if (parsed.ok) return parsed.value;
|
|
37797
|
+
ctx.addIssue({
|
|
37798
|
+
code: z.ZodIssueCode.custom,
|
|
37799
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
37800
|
+
});
|
|
37801
|
+
return z.NEVER;
|
|
37802
|
+
});
|
|
37803
|
+
function resolveEventRegistrationScope(context) {
|
|
37804
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
37805
|
+
if (occurrenceSeriesId) return {
|
|
37806
|
+
kind: "occurrenceSeries",
|
|
37807
|
+
seriesId: occurrenceSeriesId
|
|
37808
|
+
};
|
|
37809
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
37810
|
+
kind: "pageSurfaceSeries",
|
|
37811
|
+
seriesId: context.subject.eventSeriesId
|
|
37812
|
+
};
|
|
37813
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
37814
|
+
kind: "pageSurfaceOffering",
|
|
37815
|
+
offeringId: context.subject.eventOfferingId,
|
|
37816
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
37817
|
+
};
|
|
37818
|
+
if (context.subject?.kind === "unsupported") return {
|
|
37819
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
37820
|
+
reason: context.subject.reason
|
|
37821
|
+
};
|
|
37822
|
+
return { kind: "unscoped" };
|
|
37823
|
+
}
|
|
37824
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
37825
|
+
const scope = resolveEventRegistrationScope(context);
|
|
37826
|
+
switch (scope.kind) {
|
|
37827
|
+
case "occurrenceSeries":
|
|
37828
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
37829
|
+
case "pageSurfaceOffering": {
|
|
37830
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
37831
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
37832
|
+
}
|
|
37833
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
37834
|
+
case "unscoped": return [...events];
|
|
37835
|
+
}
|
|
37836
|
+
}
|
|
37837
|
+
//#endregion
|
|
37838
|
+
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
37839
|
+
const previewStageSchema = z.enum(["preview", "published"]);
|
|
37840
|
+
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
37841
|
+
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
37842
|
+
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
37843
|
+
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
37844
|
+
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
37845
|
+
const columnOptionSchema = z.enum([
|
|
37846
|
+
"2",
|
|
37847
|
+
"3",
|
|
37848
|
+
"4"
|
|
37849
|
+
]);
|
|
37850
|
+
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
37851
|
+
const filterAutoShowSchema = z.enum([
|
|
37852
|
+
"auto",
|
|
37853
|
+
"always",
|
|
37854
|
+
"never"
|
|
37855
|
+
]);
|
|
37856
|
+
const calendarTabViewsSchema = z.enum([
|
|
37857
|
+
"both",
|
|
37858
|
+
"month",
|
|
37859
|
+
"week"
|
|
37860
|
+
]);
|
|
37861
|
+
//#endregion
|
|
36871
37862
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
36872
37863
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
36873
37864
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -36910,27 +37901,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
36910
37901
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
36911
37902
|
"Date",
|
|
36912
37903
|
"Tickets",
|
|
36913
|
-
"
|
|
36914
|
-
];
|
|
36915
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
36916
|
-
"Event",
|
|
36917
|
-
"Date",
|
|
36918
|
-
"Tickets",
|
|
36919
|
-
"Details",
|
|
36920
|
-
"Payment options",
|
|
36921
|
-
"Payment"
|
|
37904
|
+
"Your details"
|
|
36922
37905
|
];
|
|
36923
37906
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
36924
|
-
const
|
|
37907
|
+
const eventRegistrationCommonSchemaShape = {
|
|
36925
37908
|
demoEmailSuppressed: z.boolean().optional(),
|
|
36926
37909
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
36927
37910
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
36928
37911
|
maxTickets: z.string().optional(),
|
|
36929
|
-
showVenue: z.boolean().optional(),
|
|
36930
|
-
showCapacity: z.boolean().optional(),
|
|
36931
37912
|
successMessage: z.string().optional(),
|
|
36932
37913
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
36933
|
-
|
|
37914
|
+
host: bookingHostSchema.optional(),
|
|
36934
37915
|
spamProtectionEnabled: z.boolean().optional(),
|
|
36935
37916
|
supportEmail: z.string().optional(),
|
|
36936
37917
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -36955,32 +37936,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
36955
37936
|
portalToken: z.string().nullable().optional(),
|
|
36956
37937
|
previewToken: z.string().nullable().optional(),
|
|
36957
37938
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36958
|
-
...
|
|
37939
|
+
...eventRegistrationCommonSchemaShape,
|
|
37940
|
+
showVenue: z.boolean().optional(),
|
|
37941
|
+
showCapacity: z.boolean().optional(),
|
|
36959
37942
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36960
37943
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
36961
37944
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
36962
37945
|
className: z.string().nullable().optional(),
|
|
36963
37946
|
buttonText: z.string().nullable().optional(),
|
|
36964
37947
|
maxTickets: z.string().nullable().optional(),
|
|
36965
|
-
stage: previewStageSchema.optional()
|
|
37948
|
+
stage: previewStageSchema.optional(),
|
|
37949
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
36966
37950
|
});
|
|
36967
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
36968
|
-
|
|
36969
|
-
|
|
36970
|
-
|
|
36971
|
-
|
|
36972
|
-
|
|
36973
|
-
|
|
36974
|
-
|
|
36975
|
-
|
|
36976
|
-
|
|
36977
|
-
|
|
36978
|
-
|
|
36979
|
-
|
|
36980
|
-
|
|
36981
|
-
|
|
37951
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
37952
|
+
z.object({
|
|
37953
|
+
kind: z.literal("event-registration"),
|
|
37954
|
+
state: z.literal("generic-shell"),
|
|
37955
|
+
className: z.string().nullable(),
|
|
37956
|
+
titleText: z.string(),
|
|
37957
|
+
bodyText: z.string(),
|
|
37958
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
37959
|
+
summaryButtonText: z.string()
|
|
37960
|
+
}),
|
|
37961
|
+
z.object({
|
|
37962
|
+
kind: z.literal("event-registration"),
|
|
37963
|
+
state: z.literal("registration-closed"),
|
|
37964
|
+
className: z.string().nullable(),
|
|
37965
|
+
titleText: z.string(),
|
|
37966
|
+
bodyText: z.string()
|
|
37967
|
+
}),
|
|
37968
|
+
z.object({
|
|
37969
|
+
kind: z.literal("event-registration"),
|
|
37970
|
+
state: z.literal("booking-card"),
|
|
37971
|
+
className: z.string().nullable(),
|
|
37972
|
+
entry: idleBookingEntrySchema,
|
|
37973
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
37974
|
+
buttonText: z.string()
|
|
37975
|
+
})
|
|
37976
|
+
]);
|
|
36982
37977
|
const eventRegistrationHydrationSchema = z.object({
|
|
36983
|
-
...
|
|
37978
|
+
...eventRegistrationCommonSchemaShape,
|
|
37979
|
+
display: registrationDisplaySchema,
|
|
37980
|
+
offeringNoun: z.object({
|
|
37981
|
+
label: z.string(),
|
|
37982
|
+
pluralLabel: z.string()
|
|
37983
|
+
}).optional(),
|
|
36984
37984
|
eventSource: eventRegistrationEventSourceSchema
|
|
36985
37985
|
});
|
|
36986
37986
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -36995,7 +37995,7 @@ z.object({
|
|
|
36995
37995
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
36996
37996
|
stage: previewStageSchema.optional()
|
|
36997
37997
|
});
|
|
36998
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
37998
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
36999
37999
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
37000
38000
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
37001
38001
|
kind: "event-registration",
|
|
@@ -37004,6 +38004,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
37004
38004
|
titleText: "Registration closed",
|
|
37005
38005
|
bodyText: "This run is no longer open for bookings."
|
|
37006
38006
|
};
|
|
38007
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
38008
|
+
if (card) return card;
|
|
37007
38009
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
37008
38010
|
return {
|
|
37009
38011
|
kind: "event-registration",
|
|
@@ -37020,11 +38022,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
37020
38022
|
if (selectedRun) {
|
|
37021
38023
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
37022
38024
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
37023
|
-
return
|
|
37024
|
-
|
|
37025
|
-
|
|
37026
|
-
|
|
37027
|
-
|
|
38025
|
+
return shellStepLabels(registrationRoute({
|
|
38026
|
+
chooseEvent: false,
|
|
38027
|
+
payment: resolveEventRequiresPayment({
|
|
38028
|
+
eligibility: null,
|
|
38029
|
+
selectedTicketType: null,
|
|
38030
|
+
event: selectedEvent
|
|
38031
|
+
}) ? "optionsAndPayment" : "none"
|
|
38032
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
37028
38033
|
}
|
|
37029
38034
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
37030
38035
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -37033,14 +38038,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
37033
38038
|
occurrenceContext: source.occurrenceContext
|
|
37034
38039
|
});
|
|
37035
38040
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
37036
|
-
|
|
38041
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
37037
38042
|
eligibility: null,
|
|
37038
38043
|
selectedTicketType: null,
|
|
37039
38044
|
event: preSelectedEvent
|
|
37040
|
-
}) : false
|
|
37041
|
-
|
|
37042
|
-
|
|
37043
|
-
|
|
38045
|
+
}) : false;
|
|
38046
|
+
return shellStepLabels(registrationRoute({
|
|
38047
|
+
chooseEvent: !hasPreSelectedContext,
|
|
38048
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
38049
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
37044
38050
|
}
|
|
37045
38051
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
37046
38052
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -37056,29 +38062,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
37056
38062
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
37057
38063
|
return runs.length === 1 ? runs[0] : null;
|
|
37058
38064
|
}
|
|
37059
|
-
function
|
|
37060
|
-
|
|
37061
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
37062
|
-
case "select-tickets": return "Tickets";
|
|
37063
|
-
case "enter-details": return "Details";
|
|
37064
|
-
case "select-payment": return "Payment options";
|
|
37065
|
-
case "payment": return "Payment";
|
|
37066
|
-
case "error":
|
|
37067
|
-
case "success":
|
|
37068
|
-
case "submitting":
|
|
37069
|
-
case "verifying-payment":
|
|
37070
|
-
case "verifying-timeout":
|
|
37071
|
-
case "payment-status":
|
|
37072
|
-
case "payment-failed": return "Details";
|
|
37073
|
-
}
|
|
37074
|
-
}
|
|
37075
|
-
function isDateSelection(events) {
|
|
37076
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
37077
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
38065
|
+
function shellStepLabels(route, context) {
|
|
38066
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
37078
38067
|
}
|
|
37079
38068
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
37080
|
-
if (stepLabels.includes("
|
|
37081
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
38069
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
38070
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
37082
38071
|
return "Preparing dates, tickets, and booking details.";
|
|
37083
38072
|
}
|
|
37084
38073
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -37088,6 +38077,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
37088
38077
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
37089
38078
|
},
|
|
37090
38079
|
buildRender: (source) => {
|
|
38080
|
+
const display = resolveRegistrationDisplay(source);
|
|
37091
38081
|
const eventSource = resolveEventRegistrationEventSource({
|
|
37092
38082
|
events: source.events,
|
|
37093
38083
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -37095,7 +38085,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
37095
38085
|
});
|
|
37096
38086
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
37097
38087
|
return {
|
|
37098
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
38088
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
37099
38089
|
hydration: {
|
|
37100
38090
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
37101
38091
|
subject: source.subject ?? null,
|
|
@@ -37105,29 +38095,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
37105
38095
|
} : eventSource,
|
|
37106
38096
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
37107
38097
|
maxTickets: source.maxTickets ?? void 0,
|
|
37108
|
-
|
|
37109
|
-
showCapacity: source.showCapacity,
|
|
38098
|
+
display,
|
|
37110
38099
|
successMessage: source.successMessage,
|
|
37111
38100
|
buttonVariant: source.buttonVariant,
|
|
37112
|
-
|
|
38101
|
+
host: source.host ?? "overlay",
|
|
37113
38102
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
37114
38103
|
supportEmail: source.supportEmail,
|
|
37115
38104
|
sitePasses: source.sitePasses ?? null,
|
|
37116
38105
|
siteMemberships: source.siteMemberships ?? null,
|
|
37117
38106
|
mailingList: source.mailingList,
|
|
37118
|
-
siteName: source.siteName
|
|
38107
|
+
siteName: source.siteName,
|
|
38108
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
37119
38109
|
}
|
|
37120
38110
|
};
|
|
37121
38111
|
}
|
|
37122
38112
|
});
|
|
37123
38113
|
function normalizeEventRegistrationEventInput(value) {
|
|
37124
|
-
if (!isRecord$
|
|
38114
|
+
if (!isRecord$4(value)) return value;
|
|
37125
38115
|
return {
|
|
37126
38116
|
...value,
|
|
37127
38117
|
destination: resolveRuntimeEventDestination(value)
|
|
37128
38118
|
};
|
|
37129
38119
|
}
|
|
37130
|
-
function isRecord$
|
|
38120
|
+
function isRecord$4(value) {
|
|
37131
38121
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37132
38122
|
}
|
|
37133
38123
|
const eventRegistrationBlockDefinition = {
|
|
@@ -37167,7 +38157,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
37167
38157
|
description: "Main heading for the registration form",
|
|
37168
38158
|
required: false,
|
|
37169
38159
|
multiline: false,
|
|
37170
|
-
defaultValue: "
|
|
38160
|
+
defaultValue: ""
|
|
37171
38161
|
},
|
|
37172
38162
|
{
|
|
37173
38163
|
id: "description",
|
|
@@ -37239,11 +38229,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
37239
38229
|
{
|
|
37240
38230
|
id: "buttonText",
|
|
37241
38231
|
type: "text",
|
|
37242
|
-
label: "
|
|
37243
|
-
description: "Text
|
|
38232
|
+
label: "Button text",
|
|
38233
|
+
description: "Text on the booking button",
|
|
37244
38234
|
required: false,
|
|
37245
38235
|
multiline: false,
|
|
37246
|
-
defaultValue: "
|
|
38236
|
+
defaultValue: "Book your place",
|
|
37247
38237
|
maxLength: 40
|
|
37248
38238
|
},
|
|
37249
38239
|
createButtonVariantField()
|
|
@@ -37275,21 +38265,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
37275
38265
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
37276
38266
|
buttonText: { $bind: {
|
|
37277
38267
|
from: "content.buttonText",
|
|
37278
|
-
fallback: "
|
|
38268
|
+
fallback: "Book your place"
|
|
37279
38269
|
} },
|
|
37280
38270
|
buttonVariant: { $bind: {
|
|
37281
38271
|
from: "content.buttonVariant",
|
|
37282
38272
|
fallback: "primary"
|
|
37283
38273
|
} },
|
|
37284
|
-
overlayEnabled: { $bind: {
|
|
37285
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
37286
|
-
fallback: false
|
|
37287
|
-
} },
|
|
37288
38274
|
events: { $bind: { from: "data.events" } },
|
|
37289
38275
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
37290
38276
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
37291
38277
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
37292
38278
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
38279
|
+
bookingOfferingPresets: { $bind: {
|
|
38280
|
+
from: "$root.bookingOfferingPresets",
|
|
38281
|
+
fallback: []
|
|
38282
|
+
} },
|
|
37293
38283
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
37294
38284
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
37295
38285
|
stage: { $bind: {
|
|
@@ -39859,7 +40849,21 @@ const eventCalendarBlockDefinition = {
|
|
|
39859
40849
|
list: { label: "List" }
|
|
39860
40850
|
}
|
|
39861
40851
|
}, eventCalendarContentShape),
|
|
39862
|
-
|
|
40852
|
+
contentNormalizer: {
|
|
40853
|
+
fieldIds: [
|
|
40854
|
+
"variant",
|
|
40855
|
+
"displayMode",
|
|
40856
|
+
"listLayout",
|
|
40857
|
+
"defaultCalendarView",
|
|
40858
|
+
"eventSurface",
|
|
40859
|
+
"filterEventPresets",
|
|
40860
|
+
"scheduleScope",
|
|
40861
|
+
"filterCategoryIds",
|
|
40862
|
+
"filterStaffMemberId",
|
|
40863
|
+
"filterVenueId"
|
|
40864
|
+
],
|
|
40865
|
+
normalize: normalizeEventCalendarContent
|
|
40866
|
+
},
|
|
39863
40867
|
dataSchemas: {
|
|
39864
40868
|
events: publicEventsArraySchema.optional(),
|
|
39865
40869
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -40332,90 +41336,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
40332
41336
|
} }
|
|
40333
41337
|
};
|
|
40334
41338
|
//#endregion
|
|
40335
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
40336
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
40337
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
40338
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
40339
|
-
{
|
|
40340
|
-
preset: "class",
|
|
40341
|
-
sourceKey: "eventPreset:class",
|
|
40342
|
-
dataKey: "classEvents",
|
|
40343
|
-
label: "Classes"
|
|
40344
|
-
},
|
|
40345
|
-
{
|
|
40346
|
-
preset: "workshop",
|
|
40347
|
-
sourceKey: "eventPreset:workshop",
|
|
40348
|
-
dataKey: "workshopEvents",
|
|
40349
|
-
label: "Workshops"
|
|
40350
|
-
},
|
|
40351
|
-
{
|
|
40352
|
-
preset: "retreat",
|
|
40353
|
-
sourceKey: "eventPreset:retreat",
|
|
40354
|
-
dataKey: "retreatEvents",
|
|
40355
|
-
label: "Retreats"
|
|
40356
|
-
},
|
|
40357
|
-
{
|
|
40358
|
-
preset: "performance",
|
|
40359
|
-
sourceKey: "eventPreset:performance",
|
|
40360
|
-
dataKey: "performanceEvents",
|
|
40361
|
-
label: "Performances"
|
|
40362
|
-
}
|
|
40363
|
-
];
|
|
40364
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
40365
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
40366
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
40367
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
40368
|
-
kind: "eventPreset",
|
|
40369
|
-
preset: definition.preset
|
|
40370
|
-
}]));
|
|
40371
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
40372
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
40373
|
-
}
|
|
40374
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
40375
|
-
if (value == null) return { kind: "legacy" };
|
|
40376
|
-
if (value.length === 0) return { kind: "default" };
|
|
40377
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
40378
|
-
return keys.length > 0 ? {
|
|
40379
|
-
kind: "custom",
|
|
40380
|
-
keys
|
|
40381
|
-
} : { kind: "default" };
|
|
40382
|
-
}
|
|
40383
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
40384
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
40385
|
-
return keys.length >= 2 ? keys : [];
|
|
40386
|
-
}
|
|
40387
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
40388
|
-
if (!isRecord$4(value)) return null;
|
|
40389
|
-
const groupOrderValue = value.groupOrder;
|
|
40390
|
-
if (Array.isArray(groupOrderValue)) {
|
|
40391
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
40392
|
-
return {
|
|
40393
|
-
...value,
|
|
40394
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
40395
|
-
};
|
|
40396
|
-
}
|
|
40397
|
-
if (groupOrderValue != null) return {
|
|
40398
|
-
...value,
|
|
40399
|
-
groupOrder: []
|
|
40400
|
-
};
|
|
40401
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$4) : []);
|
|
40402
|
-
return legacyOrder.length > 0 ? {
|
|
40403
|
-
...value,
|
|
40404
|
-
groupOrder: legacyOrder
|
|
40405
|
-
} : value;
|
|
40406
|
-
}
|
|
40407
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
40408
|
-
const keys = [];
|
|
40409
|
-
for (const value of values) {
|
|
40410
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
40411
|
-
if (!keys.includes(value)) keys.push(value);
|
|
40412
|
-
}
|
|
40413
|
-
return keys;
|
|
40414
|
-
}
|
|
40415
|
-
function isRecord$4(value) {
|
|
40416
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40417
|
-
}
|
|
40418
|
-
//#endregion
|
|
40419
41339
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
40420
41340
|
const groupOverrideFields = [
|
|
40421
41341
|
{
|
|
@@ -40779,7 +41699,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
40779
41699
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
40780
41700
|
const offeringsPreviewBlockDefinition = {
|
|
40781
41701
|
manifest: offeringsPreviewManifest,
|
|
40782
|
-
|
|
41702
|
+
contentNormalizer: {
|
|
41703
|
+
fieldIds: [
|
|
41704
|
+
"displayMode",
|
|
41705
|
+
"heading",
|
|
41706
|
+
"description",
|
|
41707
|
+
"itemLimit",
|
|
41708
|
+
"groupOrder",
|
|
41709
|
+
"groupOverrides",
|
|
41710
|
+
"_cardStyles",
|
|
41711
|
+
"buttonVariant",
|
|
41712
|
+
"buttonText",
|
|
41713
|
+
"emptyMessage",
|
|
41714
|
+
"_sectionStyles"
|
|
41715
|
+
],
|
|
41716
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
41717
|
+
},
|
|
40783
41718
|
dataSchemas: {
|
|
40784
41719
|
...offeringsPreviewEventDataSchemas,
|
|
40785
41720
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -44377,11 +45312,11 @@ function buildNewsletterDisplay(source) {
|
|
|
44377
45312
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
44378
45313
|
privacyNote: null
|
|
44379
45314
|
};
|
|
44380
|
-
const
|
|
44381
|
-
const choices = resolveRuntimeChoices(
|
|
45315
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
45316
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
44382
45317
|
return {
|
|
44383
45318
|
kind: "newsletter-form",
|
|
44384
|
-
availability:
|
|
45319
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
44385
45320
|
className: source.className ?? null,
|
|
44386
45321
|
buttonLabel: form.buttonLabel,
|
|
44387
45322
|
successMessage: form.successMessage,
|
|
@@ -44438,60 +45373,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
44438
45373
|
default: return assertNever$3(source);
|
|
44439
45374
|
}
|
|
44440
45375
|
}
|
|
44441
|
-
function resolveRuntimeChoices(
|
|
44442
|
-
if (
|
|
44443
|
-
|
|
44444
|
-
|
|
44445
|
-
|
|
44446
|
-
|
|
44447
|
-
id: item.id,
|
|
44448
|
-
label: item.name
|
|
44449
|
-
})) : [];
|
|
44450
|
-
}
|
|
44451
|
-
case "brevo": {
|
|
44452
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
44453
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
44454
|
-
id: String(item.id),
|
|
44455
|
-
label: item.name
|
|
44456
|
-
})) : [];
|
|
44457
|
-
}
|
|
44458
|
-
case "mailchimp": {
|
|
44459
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
44460
|
-
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) => ({
|
|
44461
|
-
id: item.id,
|
|
44462
|
-
label: item.name
|
|
44463
|
-
})) ?? [];
|
|
44464
|
-
}
|
|
44465
|
-
}
|
|
44466
|
-
}
|
|
44467
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
44468
|
-
if (context?.tag !== "configured") return false;
|
|
44469
|
-
const provider = context.provider;
|
|
44470
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
44471
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
44472
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
44473
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
44474
|
-
}
|
|
44475
|
-
if (targeting.provider !== provider.provider) return false;
|
|
44476
|
-
switch (targeting.provider) {
|
|
44477
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
44478
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
44479
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
44480
|
-
}
|
|
44481
|
-
}
|
|
44482
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
44483
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
44484
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44485
|
-
}
|
|
44486
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
44487
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
44488
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
44489
|
-
}
|
|
44490
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
44491
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
44492
|
-
if (!audience) return false;
|
|
44493
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
44494
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
45376
|
+
function resolveRuntimeChoices(assessment) {
|
|
45377
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
45378
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
45379
|
+
id: String(item.id),
|
|
45380
|
+
label: item.name
|
|
45381
|
+
}));
|
|
44495
45382
|
}
|
|
44496
45383
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
44497
45384
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -44595,6 +45482,10 @@ const newsletterSignupManifest = createBlockManifest({
|
|
|
44595
45482
|
[...(newsletterSignupManifest.fields ?? []).map((field) => field.id)];
|
|
44596
45483
|
const newsletterSignupBlockDefinition = {
|
|
44597
45484
|
manifest: newsletterSignupManifest,
|
|
45485
|
+
contentNormalizer: {
|
|
45486
|
+
fieldIds: ["targeting"],
|
|
45487
|
+
normalize: normalizeMailingListBlockContent
|
|
45488
|
+
},
|
|
44598
45489
|
runtime: newsletterFormBlockRuntime
|
|
44599
45490
|
};
|
|
44600
45491
|
//#endregion
|
|
@@ -45327,7 +46218,20 @@ const locationMapBlockDefinition = {
|
|
|
45327
46218
|
})], { gap: "md" })
|
|
45328
46219
|
})
|
|
45329
46220
|
}),
|
|
45330
|
-
|
|
46221
|
+
contentNormalizer: {
|
|
46222
|
+
fieldIds: [
|
|
46223
|
+
"heading",
|
|
46224
|
+
"locationSource",
|
|
46225
|
+
"venueId",
|
|
46226
|
+
"location",
|
|
46227
|
+
"showAddressText",
|
|
46228
|
+
"showDirections",
|
|
46229
|
+
"directionsLabel",
|
|
46230
|
+
"zoom",
|
|
46231
|
+
"heightPx"
|
|
46232
|
+
],
|
|
46233
|
+
normalize: normalizeLocationMapContent
|
|
46234
|
+
}
|
|
45331
46235
|
};
|
|
45332
46236
|
//#endregion
|
|
45333
46237
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -46532,17 +47436,7 @@ const linksTransforms = [{
|
|
|
46532
47436
|
id: "links.resolve",
|
|
46533
47437
|
kind: "formatter",
|
|
46534
47438
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
46535
|
-
run: (value, _options, context) =>
|
|
46536
|
-
if (!value || typeof value !== "object") return null;
|
|
46537
|
-
const link = value;
|
|
46538
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
46539
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
46540
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
46541
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
46542
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
46543
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
46544
|
-
return null;
|
|
46545
|
-
}
|
|
47439
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
46546
47440
|
}, {
|
|
46547
47441
|
id: "links.label",
|
|
46548
47442
|
kind: "formatter",
|
|
@@ -46569,6 +47463,21 @@ const linksTransforms = [{
|
|
|
46569
47463
|
return null;
|
|
46570
47464
|
}
|
|
46571
47465
|
}];
|
|
47466
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
47467
|
+
if (!value || typeof value !== "object") return null;
|
|
47468
|
+
const link = value;
|
|
47469
|
+
switch (link.kind) {
|
|
47470
|
+
case "internal": return resolveInternalLink(link, context);
|
|
47471
|
+
case "page": return resolvePageLink(link, context);
|
|
47472
|
+
case "entry": return resolveEntryLink(link, context);
|
|
47473
|
+
case "external":
|
|
47474
|
+
case "url": return resolveExternalLink(link);
|
|
47475
|
+
default: return resolvePreResolvedLink(link);
|
|
47476
|
+
}
|
|
47477
|
+
}
|
|
47478
|
+
function resolvePreResolvedLink(link) {
|
|
47479
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
47480
|
+
}
|
|
46572
47481
|
const eventCalendarSelectionParam = {
|
|
46573
47482
|
id: "events.calendarSelectionParam",
|
|
46574
47483
|
kind: "formatter",
|