@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/client/hooks.mjs
CHANGED
|
@@ -323,6 +323,29 @@ function canonicalEventPricingDisplay(pricing) {
|
|
|
323
323
|
default: return assertNever$3(pricing);
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* The single renderer for a precomputed booking price `display` ADT. This is
|
|
328
|
+
* the one place booking price variants map to user-facing strings — every call
|
|
329
|
+
* site (booking entry, events calendar, event/course details, listings, portal)
|
|
330
|
+
* should route through here so labels never drift. Adding a variant to the ADT
|
|
331
|
+
* breaks compilation here (via `assertNever`) until it is handled.
|
|
332
|
+
*/
|
|
333
|
+
function formatBookingPriceDisplay(display, options = {}) {
|
|
334
|
+
switch (display.kind) {
|
|
335
|
+
case "free": return "Free";
|
|
336
|
+
case "exact": return formatCurrencyAmount(display.amount, display.currency, options);
|
|
337
|
+
case "from": return `From ${formatCurrencyAmount(display.amount, display.currency, options)}`;
|
|
338
|
+
case "range": return `${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)}`;
|
|
339
|
+
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)}`;
|
|
340
|
+
case "unavailable": return "Pricing unavailable";
|
|
341
|
+
case "external": return display.label;
|
|
342
|
+
default: return assertNever$3(display);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/** Render an event's price directly from its pricing value. */
|
|
346
|
+
function formatEventPricing(pricing, options = {}) {
|
|
347
|
+
return formatBookingPriceDisplay(publicEventPricingDisplay(pricing), options);
|
|
348
|
+
}
|
|
326
349
|
//#endregion
|
|
327
350
|
//#region ../core/src/event-page-surface-subject.ts
|
|
328
351
|
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
@@ -466,6 +489,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
466
489
|
}
|
|
467
490
|
//#endregion
|
|
468
491
|
//#region ../core/src/booking-date-time.ts
|
|
492
|
+
const DEFAULT_LOCALE = "en-US";
|
|
469
493
|
const FALLBACK_TIMEZONE = "UTC";
|
|
470
494
|
const START_OF_DAY = {
|
|
471
495
|
hour: 0,
|
|
@@ -588,6 +612,34 @@ function toScheduledBookingDateTime(input) {
|
|
|
588
612
|
if (result.ok) return result.value;
|
|
589
613
|
throw new Error(formatParseError(result));
|
|
590
614
|
}
|
|
615
|
+
function formatBookingInstant(isoString, options) {
|
|
616
|
+
const date = new Date(isoString);
|
|
617
|
+
if (Number.isNaN(date.getTime())) return isoString;
|
|
618
|
+
return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
619
|
+
}
|
|
620
|
+
function formatBookingDate(input, format = {
|
|
621
|
+
weekday: "long",
|
|
622
|
+
year: "numeric",
|
|
623
|
+
month: "long",
|
|
624
|
+
day: "numeric"
|
|
625
|
+
}) {
|
|
626
|
+
return formatBookingInstant(input.startsAt, {
|
|
627
|
+
locale: input.locale,
|
|
628
|
+
timeZone: input.timeZone,
|
|
629
|
+
format
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
function formatBookingTime(input, format = {
|
|
633
|
+
hour: "numeric",
|
|
634
|
+
minute: "2-digit",
|
|
635
|
+
hour12: true
|
|
636
|
+
}) {
|
|
637
|
+
return formatBookingInstant(input.startsAt, {
|
|
638
|
+
locale: input.locale,
|
|
639
|
+
timeZone: input.timeZone,
|
|
640
|
+
format
|
|
641
|
+
});
|
|
642
|
+
}
|
|
591
643
|
function getBookingLocalDateKey(input) {
|
|
592
644
|
return formatDateKey(getLocalScheduleDate(new Date(input.startsAt), input.timeZone));
|
|
593
645
|
}
|
|
@@ -849,6 +901,14 @@ function formError(field) {
|
|
|
849
901
|
}
|
|
850
902
|
//#endregion
|
|
851
903
|
//#region ../core/src/mailing-list-targeting.ts
|
|
904
|
+
const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
|
|
905
|
+
function mailingListTargetingChoiceIds(targeting) {
|
|
906
|
+
switch (targeting.provider) {
|
|
907
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
908
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
909
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
852
912
|
function planMailingListChoicePresentation(targeting) {
|
|
853
913
|
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
854
914
|
switch (targeting.provider) {
|
|
@@ -888,6 +948,103 @@ function planMailingListChoicePresentation(targeting) {
|
|
|
888
948
|
}
|
|
889
949
|
}
|
|
890
950
|
//#endregion
|
|
951
|
+
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
952
|
+
function resolveMailingListDefaultDestination(provider) {
|
|
953
|
+
switch (provider.provider) {
|
|
954
|
+
case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
|
|
955
|
+
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
956
|
+
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
function assessMailingListTargeting(context, targeting) {
|
|
960
|
+
if (context?.tag !== "configured") return {
|
|
961
|
+
tag: "unavailable",
|
|
962
|
+
reason: "setup_missing",
|
|
963
|
+
targeting
|
|
964
|
+
};
|
|
965
|
+
const catalog = context.provider;
|
|
966
|
+
if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
|
|
967
|
+
const destination = resolveMailingListDefaultDestination(catalog);
|
|
968
|
+
return destination === null ? {
|
|
969
|
+
tag: "unavailable",
|
|
970
|
+
reason: "default_missing",
|
|
971
|
+
targeting
|
|
972
|
+
} : {
|
|
973
|
+
tag: "available",
|
|
974
|
+
value: {
|
|
975
|
+
mode: "default",
|
|
976
|
+
targeting,
|
|
977
|
+
provider: catalog.provider,
|
|
978
|
+
destination
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
function assessCustomTargeting(catalog, targeting) {
|
|
983
|
+
switch (targeting.provider) {
|
|
984
|
+
case "native": return catalog.provider === "native" ? assessMatchedChoices({
|
|
985
|
+
provider: "native",
|
|
986
|
+
catalog,
|
|
987
|
+
targeting
|
|
988
|
+
}, catalog.topics) : {
|
|
989
|
+
tag: "unavailable",
|
|
990
|
+
reason: "provider_mismatch",
|
|
991
|
+
targeting
|
|
992
|
+
};
|
|
993
|
+
case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
|
|
994
|
+
provider: "brevo",
|
|
995
|
+
catalog,
|
|
996
|
+
targeting
|
|
997
|
+
}, catalog.lists) : {
|
|
998
|
+
tag: "unavailable",
|
|
999
|
+
reason: "provider_mismatch",
|
|
1000
|
+
targeting
|
|
1001
|
+
};
|
|
1002
|
+
case "mailchimp": {
|
|
1003
|
+
if (catalog.provider !== "mailchimp") return {
|
|
1004
|
+
tag: "unavailable",
|
|
1005
|
+
reason: "provider_mismatch",
|
|
1006
|
+
targeting
|
|
1007
|
+
};
|
|
1008
|
+
const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
|
|
1009
|
+
return audience === void 0 ? {
|
|
1010
|
+
tag: "unavailable",
|
|
1011
|
+
reason: "audience_missing",
|
|
1012
|
+
value: {
|
|
1013
|
+
mode: "custom",
|
|
1014
|
+
provider: "mailchimp",
|
|
1015
|
+
catalog,
|
|
1016
|
+
targeting
|
|
1017
|
+
}
|
|
1018
|
+
} : assessMatchedChoices({
|
|
1019
|
+
provider: "mailchimp",
|
|
1020
|
+
catalog,
|
|
1021
|
+
targeting,
|
|
1022
|
+
audience
|
|
1023
|
+
}, audience.interests);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
function assessMatchedChoices(matched, choices) {
|
|
1028
|
+
const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
|
|
1029
|
+
const available = new Set(choices.map((item) => item.id));
|
|
1030
|
+
const missingIds = [...selected].filter((id) => !available.has(id));
|
|
1031
|
+
const value = {
|
|
1032
|
+
mode: "custom",
|
|
1033
|
+
...matched,
|
|
1034
|
+
choices,
|
|
1035
|
+
selectedChoices: choices.filter((item) => selected.has(item.id))
|
|
1036
|
+
};
|
|
1037
|
+
return missingIds.length > 0 ? {
|
|
1038
|
+
tag: "unavailable",
|
|
1039
|
+
reason: "choices_missing",
|
|
1040
|
+
missingIds,
|
|
1041
|
+
value
|
|
1042
|
+
} : {
|
|
1043
|
+
tag: "available",
|
|
1044
|
+
value
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
//#endregion
|
|
891
1048
|
//#region ../core/src/mailing-list-runtime.ts
|
|
892
1049
|
function parseMailingListRuntimeContext(value) {
|
|
893
1050
|
if (!isRecord$13(value)) return invalidRuntimeContext();
|
|
@@ -952,57 +1109,47 @@ function parseBrevoRuntimeProvider(value) {
|
|
|
952
1109
|
function parseMailchimpRuntimeProvider(value) {
|
|
953
1110
|
if (!Array.isArray(value.audiences)) return null;
|
|
954
1111
|
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
for (const audience of value.audiences) {
|
|
958
|
-
if (!isRecord$13(audience)) return null;
|
|
959
|
-
const id = parseMailchimpAudienceId(audience.id);
|
|
960
|
-
const name = parseName(audience.name);
|
|
961
|
-
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
962
|
-
const interests = parseMailchimpInterests(audience.interests);
|
|
963
|
-
if (interests === null) return null;
|
|
964
|
-
audiences.push({
|
|
965
|
-
id,
|
|
966
|
-
name,
|
|
967
|
-
interests
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
return {
|
|
1112
|
+
const audiences = Array.from(value.audiences, parseMailchimpAudience);
|
|
1113
|
+
return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
|
|
971
1114
|
provider: "mailchimp",
|
|
972
1115
|
defaultAudienceId,
|
|
973
1116
|
audiences
|
|
974
|
-
};
|
|
1117
|
+
} : null;
|
|
975
1118
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
interests
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1119
|
+
function parseMailchimpAudience(value) {
|
|
1120
|
+
if (!isRecord$13(value) || !Array.isArray(value.interests)) return null;
|
|
1121
|
+
const id = parseMailchimpAudienceId(value.id);
|
|
1122
|
+
const name = parseName(value.name);
|
|
1123
|
+
const interests = Array.from(value.interests, parseMailchimpInterest);
|
|
1124
|
+
return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
|
|
1125
|
+
id,
|
|
1126
|
+
name,
|
|
1127
|
+
interests
|
|
1128
|
+
} : null;
|
|
1129
|
+
}
|
|
1130
|
+
function parseMailchimpInterest(value) {
|
|
1131
|
+
if (!isRecord$13(value)) return null;
|
|
1132
|
+
const id = parseMailchimpInterestId(value.id);
|
|
1133
|
+
const name = parseName(value.name);
|
|
1134
|
+
const categoryName = parseName(value.categoryName);
|
|
1135
|
+
return id !== null && name !== null && categoryName !== null ? {
|
|
1136
|
+
id,
|
|
1137
|
+
name,
|
|
1138
|
+
categoryName
|
|
1139
|
+
} : null;
|
|
991
1140
|
}
|
|
992
1141
|
function parseNamedItems(value, parseId) {
|
|
993
1142
|
if (!Array.isArray(value)) return null;
|
|
994
|
-
const items =
|
|
995
|
-
for (const item of value) {
|
|
1143
|
+
const items = Array.from(value, (item) => {
|
|
996
1144
|
if (!isRecord$13(item)) return null;
|
|
997
1145
|
const id = parseId(item.id);
|
|
998
1146
|
const name = parseName(item.name);
|
|
999
|
-
|
|
1000
|
-
items.push({
|
|
1147
|
+
return id !== null && name !== null ? {
|
|
1001
1148
|
id,
|
|
1002
1149
|
name
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return items;
|
|
1150
|
+
} : null;
|
|
1151
|
+
});
|
|
1152
|
+
return items.every((item) => item !== null) ? items : null;
|
|
1006
1153
|
}
|
|
1007
1154
|
function parseName(value) {
|
|
1008
1155
|
if (typeof value !== "string") return null;
|
|
@@ -1018,6 +1165,7 @@ function invalidRuntimeContext() {
|
|
|
1018
1165
|
//#endregion
|
|
1019
1166
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
1020
1167
|
function parseMailingListPlacementTargeting(value) {
|
|
1168
|
+
if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
|
|
1021
1169
|
if (!isRecord$12(value)) return targetingError("shape");
|
|
1022
1170
|
if (value.mode === "default") return ok({ mode: "default" });
|
|
1023
1171
|
if (value.mode !== "custom") return targetingError("mode");
|
|
@@ -1116,14 +1264,11 @@ function parseNonEmptyUniqueIds(value, parseId) {
|
|
|
1116
1264
|
}
|
|
1117
1265
|
function parseUniqueIds(value, parseId) {
|
|
1118
1266
|
if (!Array.isArray(value)) return targetingError("targets");
|
|
1119
|
-
|
|
1120
|
-
|
|
1267
|
+
return Array.from(value).reduce((parsed, item) => {
|
|
1268
|
+
if (!parsed.ok) return parsed;
|
|
1121
1269
|
const id = parseId(item);
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
parsed.push(id);
|
|
1125
|
-
}
|
|
1126
|
-
return ok(parsed);
|
|
1270
|
+
return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
|
|
1271
|
+
}, ok([]));
|
|
1127
1272
|
}
|
|
1128
1273
|
function isRecord$12(value) {
|
|
1129
1274
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1552,6 +1697,45 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
|
1552
1697
|
};
|
|
1553
1698
|
}
|
|
1554
1699
|
//#endregion
|
|
1700
|
+
//#region ../core/src/event-preset-vocabulary.ts
|
|
1701
|
+
const EVENT_PRESET_VOCABULARY = {
|
|
1702
|
+
event: {
|
|
1703
|
+
label: "Event",
|
|
1704
|
+
pluralLabel: "Events",
|
|
1705
|
+
description: "Any event, repeating or manually dated, that does not fit the other categories."
|
|
1706
|
+
},
|
|
1707
|
+
class: {
|
|
1708
|
+
label: "Class",
|
|
1709
|
+
pluralLabel: "Classes",
|
|
1710
|
+
description: "Regular scheduled classes and group sessions."
|
|
1711
|
+
},
|
|
1712
|
+
course: {
|
|
1713
|
+
label: "Course",
|
|
1714
|
+
pluralLabel: "Courses",
|
|
1715
|
+
description: "A fixed set of dates that people book together."
|
|
1716
|
+
},
|
|
1717
|
+
term: {
|
|
1718
|
+
label: "Term",
|
|
1719
|
+
pluralLabel: "Terms",
|
|
1720
|
+
description: "A fixed term of sessions that people book together."
|
|
1721
|
+
},
|
|
1722
|
+
workshop: {
|
|
1723
|
+
label: "Workshop",
|
|
1724
|
+
pluralLabel: "Workshops",
|
|
1725
|
+
description: "One-off workshops, day sessions, or special events."
|
|
1726
|
+
},
|
|
1727
|
+
retreat: {
|
|
1728
|
+
label: "Retreat",
|
|
1729
|
+
pluralLabel: "Retreats",
|
|
1730
|
+
description: "Multi-day or residential immersive experiences."
|
|
1731
|
+
},
|
|
1732
|
+
performance: {
|
|
1733
|
+
label: "Performance",
|
|
1734
|
+
pluralLabel: "Performances",
|
|
1735
|
+
description: "Audience-facing shows, concerts, recitals, or showcases."
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
//#endregion
|
|
1555
1739
|
//#region ../media-core/src/typeGuards.ts
|
|
1556
1740
|
function isRecord$11(value) {
|
|
1557
1741
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -12223,6 +12407,14 @@ bookingPaymentOptionSchemas.flexibleBalanceConfig;
|
|
|
12223
12407
|
bookingPaymentOptionSchemas.paymentCollectionOption;
|
|
12224
12408
|
const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
|
|
12225
12409
|
bookingPaymentOptionSchemas.paymentOptionsChoice;
|
|
12410
|
+
z.strictObject({
|
|
12411
|
+
currency: z.string().trim().length(3),
|
|
12412
|
+
totalCents: nonNegativeIntegerSchema,
|
|
12413
|
+
dueNowCents: nonNegativeIntegerSchema,
|
|
12414
|
+
laterPaymentAmountsCents: z.array(nonNegativeIntegerSchema),
|
|
12415
|
+
paymentOption: z.union([createBookingPaymentOptionSchemas("strict").paymentCollectionOption, z.strictObject({ kind: z.literal("not_required") })]),
|
|
12416
|
+
promisedDiscountId: z.string().min(1).nullable().optional()
|
|
12417
|
+
});
|
|
12226
12418
|
//#endregion
|
|
12227
12419
|
//#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
|
|
12228
12420
|
const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
|
|
@@ -12463,6 +12655,10 @@ const publicEventBaseSchema = z.object({
|
|
|
12463
12655
|
eventDestinationMode: eventDestinationModeSchema.optional(),
|
|
12464
12656
|
scheduleScope: eventScheduleScopeSchema$2.optional(),
|
|
12465
12657
|
recurrence: publicEventRecurrenceSchema.optional(),
|
|
12658
|
+
scheduleSummary: z.object({
|
|
12659
|
+
recurrenceDescription: z.string(),
|
|
12660
|
+
startTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/).nullable()
|
|
12661
|
+
}).nullable().optional(),
|
|
12466
12662
|
id: z.string(),
|
|
12467
12663
|
occurrenceId: z.string(),
|
|
12468
12664
|
seriesId: z.string(),
|
|
@@ -33868,6 +34064,15 @@ const formBlockDefinition = {
|
|
|
33868
34064
|
runtime: formBlockRuntime
|
|
33869
34065
|
};
|
|
33870
34066
|
//#endregion
|
|
34067
|
+
//#region ../blocks/src/system/helpers/normalizeMailingListBlockContent.ts
|
|
34068
|
+
/** Fill the declared default without admitting or rewriting invalid custom settings. */
|
|
34069
|
+
function normalizeMailingListBlockContent(record) {
|
|
34070
|
+
return record.targeting == null ? {
|
|
34071
|
+
...record,
|
|
34072
|
+
targeting: DEFAULT_MAILING_LIST_TARGETING
|
|
34073
|
+
} : record;
|
|
34074
|
+
}
|
|
34075
|
+
//#endregion
|
|
33871
34076
|
//#region ../blocks/src/system/blocks/contact-newsletter.ts
|
|
33872
34077
|
const contactNewsletterLayout = styledSection({
|
|
33873
34078
|
children: sectionContainer([el("div", { className: "contact-newsletter-grid" }, [el("div", { className: "contact-newsletter-column contact-newsletter-contact" }, [el("div", { className: "contact-newsletter-copy" }, [text({
|
|
@@ -34031,6 +34236,10 @@ const contactNewsletterBlockDefinition = {
|
|
|
34031
34236
|
],
|
|
34032
34237
|
icon: "MailPlus"
|
|
34033
34238
|
}),
|
|
34239
|
+
contentNormalizer: {
|
|
34240
|
+
fieldIds: ["targeting"],
|
|
34241
|
+
normalize: normalizeMailingListBlockContent
|
|
34242
|
+
},
|
|
34034
34243
|
dataSchemas: { form: formDataSchema.optional() },
|
|
34035
34244
|
dataLoaders: { form: {
|
|
34036
34245
|
endpoint: "getPublicFormById",
|
|
@@ -38373,70 +38582,274 @@ const occurrenceContextSchema = z.object({
|
|
|
38373
38582
|
overrides: z.record(z.string(), z.unknown()).nullable().optional()
|
|
38374
38583
|
}).nullable();
|
|
38375
38584
|
//#endregion
|
|
38376
|
-
//#region ../blocks/src/system/runtime/
|
|
38377
|
-
|
|
38378
|
-
|
|
38379
|
-
|
|
38380
|
-
|
|
38381
|
-
|
|
38382
|
-
|
|
38383
|
-
|
|
38384
|
-
|
|
38385
|
-
|
|
38386
|
-
|
|
38387
|
-
|
|
38388
|
-
|
|
38389
|
-
"invalidEventOfferingCatalogue"
|
|
38390
|
-
])
|
|
38391
|
-
});
|
|
38392
|
-
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
38393
|
-
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
38394
|
-
if (unsupported.success) return unsupported.data;
|
|
38395
|
-
const parsed = parseEventPageSurfaceSubject(value);
|
|
38396
|
-
if (parsed.ok) return parsed.value;
|
|
38397
|
-
ctx.addIssue({
|
|
38398
|
-
code: z.ZodIssueCode.custom,
|
|
38399
|
-
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
38400
|
-
});
|
|
38401
|
-
return z.NEVER;
|
|
38402
|
-
});
|
|
38403
|
-
function resolveEventRegistrationScope(context) {
|
|
38404
|
-
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
38405
|
-
if (occurrenceSeriesId) return {
|
|
38406
|
-
kind: "occurrenceSeries",
|
|
38407
|
-
seriesId: occurrenceSeriesId
|
|
38585
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
38586
|
+
/**
|
|
38587
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
38588
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
38589
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
38590
|
+
*
|
|
38591
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
38592
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
38593
|
+
*/
|
|
38594
|
+
function getEventAvailability(event) {
|
|
38595
|
+
if (event.capacity == null) return {
|
|
38596
|
+
available: null,
|
|
38597
|
+
isFull: false
|
|
38408
38598
|
};
|
|
38409
|
-
|
|
38410
|
-
|
|
38411
|
-
|
|
38599
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
38600
|
+
if (available <= 0) return {
|
|
38601
|
+
available: 0,
|
|
38602
|
+
isFull: true
|
|
38412
38603
|
};
|
|
38413
|
-
|
|
38414
|
-
|
|
38415
|
-
|
|
38416
|
-
seriesIds: context.subject.catalogueEventSeriesIds
|
|
38604
|
+
return {
|
|
38605
|
+
available,
|
|
38606
|
+
isFull: false
|
|
38417
38607
|
};
|
|
38418
|
-
|
|
38419
|
-
|
|
38420
|
-
|
|
38608
|
+
}
|
|
38609
|
+
/**
|
|
38610
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
38611
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
38612
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
38613
|
+
*
|
|
38614
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
38615
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
38616
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
38617
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
38618
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
38619
|
+
*/
|
|
38620
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
38621
|
+
if (!attendanceMode) return event;
|
|
38622
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
38623
|
+
}
|
|
38624
|
+
/**
|
|
38625
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
38626
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
38627
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
38628
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
38629
|
+
* `capacity - registeredCount` fallback.
|
|
38630
|
+
*/
|
|
38631
|
+
function canJoinEventWaitlist(event, options) {
|
|
38632
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
38633
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
38634
|
+
}
|
|
38635
|
+
/**
|
|
38636
|
+
* Remaining places at or below which an event reads as scarce and the exact
|
|
38637
|
+
* count is worth showing. Above it, no number is shown at all: "147 places
|
|
38638
|
+
* left" is not something a visitor acts on, and it is the figure most likely
|
|
38639
|
+
* to be stale on a cached page.
|
|
38640
|
+
*
|
|
38641
|
+
* max( min(3, ceil(capacity * 0.25)), ceil(capacity * 0.05) )
|
|
38642
|
+
*
|
|
38643
|
+
* The 25% arm stops small groups shouting early (3 of 4 is not urgency); the
|
|
38644
|
+
* 5% floor stops large events staying silent until three remain.
|
|
38645
|
+
* capacity 4 -> 1, 12 -> 3, 40 -> 3, 100 -> 5, 200 -> 10.
|
|
38646
|
+
*/
|
|
38647
|
+
function lowCapacityThreshold(capacity) {
|
|
38648
|
+
return Math.max(Math.min(3, Math.ceil(capacity * .25)), Math.ceil(capacity * .05));
|
|
38649
|
+
}
|
|
38650
|
+
function getRemainingPlaces(source) {
|
|
38651
|
+
const { available, isFull } = getEventAvailability(source);
|
|
38652
|
+
if (available === null || source.capacity === null) return { kind: "unlimited" };
|
|
38653
|
+
if (isFull) return {
|
|
38654
|
+
kind: "full",
|
|
38655
|
+
waitlist: canJoinEventWaitlist(source)
|
|
38421
38656
|
};
|
|
38422
|
-
|
|
38657
|
+
if (available <= lowCapacityThreshold(source.capacity)) return {
|
|
38658
|
+
kind: "low",
|
|
38659
|
+
remaining: available
|
|
38660
|
+
};
|
|
38661
|
+
return { kind: "open" };
|
|
38423
38662
|
}
|
|
38424
|
-
|
|
38425
|
-
|
|
38426
|
-
|
|
38427
|
-
|
|
38428
|
-
|
|
38429
|
-
|
|
38430
|
-
|
|
38431
|
-
|
|
38432
|
-
|
|
38433
|
-
case "
|
|
38434
|
-
case "
|
|
38663
|
+
/**
|
|
38664
|
+
* The one place a remaining-places count becomes text. Returns `null` when
|
|
38665
|
+
* nothing should be shown: uncapped events, and capped events above the
|
|
38666
|
+
* scarcity threshold. Surfaces that need their own full-state wording pass
|
|
38667
|
+
* it in rather than re-deriving the count.
|
|
38668
|
+
*/
|
|
38669
|
+
function formatRemainingPlaces(source, wording = {}) {
|
|
38670
|
+
const remaining = getRemainingPlaces(source);
|
|
38671
|
+
switch (remaining.kind) {
|
|
38672
|
+
case "unlimited":
|
|
38673
|
+
case "open": return null;
|
|
38674
|
+
case "low": return formatPlacesLeft(remaining.remaining, wording.compact === true);
|
|
38675
|
+
case "full": return remaining.waitlist ? wording.waitlist ?? "Waitlist" : wording.full ?? "Full";
|
|
38676
|
+
}
|
|
38677
|
+
}
|
|
38678
|
+
function formatPlacesLeft(count, compact) {
|
|
38679
|
+
if (compact) return `${count} left`;
|
|
38680
|
+
return count === 1 ? "1 place left" : `${count} places left`;
|
|
38681
|
+
}
|
|
38682
|
+
function formatTicketTypeRemaining(remainingCapacity) {
|
|
38683
|
+
if (remainingCapacity === null || remainingCapacity > 3) return null;
|
|
38684
|
+
if (remainingCapacity <= 0) return "None left for this ticket type";
|
|
38685
|
+
return `${formatPlacesLeft(remainingCapacity, false)} for this ticket type`;
|
|
38686
|
+
}
|
|
38687
|
+
/**
|
|
38688
|
+
* Which capacity figure wins when they disagree.
|
|
38689
|
+
*
|
|
38690
|
+
* For a hybrid event that publishes both attendance-mode rows, **the mode
|
|
38691
|
+
* rows are authoritative and the event-level aggregate is only a summary**.
|
|
38692
|
+
* The registration write path admits or refuses per mode
|
|
38693
|
+
* (`getEffectiveOccurrenceCapacityForAttendanceMode` on the server), so the
|
|
38694
|
+
* aggregate can read full while a mode still has room, and can read open
|
|
38695
|
+
* while the mode the visitor wants is full. Believing the aggregate on a
|
|
38696
|
+
* card is how a "places available" event turns into a dead end at step two.
|
|
38697
|
+
*
|
|
38698
|
+
* Everything else — single-mode events, events that publish no rows, and the
|
|
38699
|
+
* aggregate-only helpers {@link getEventAvailability} /
|
|
38700
|
+
* {@link getRemainingPlaces} that existing callers rely on — keeps reading
|
|
38701
|
+
* the aggregate, unchanged.
|
|
38702
|
+
*/
|
|
38703
|
+
function findHybridModeRows(event) {
|
|
38704
|
+
if (event.deliveryMode !== "hybrid") return null;
|
|
38705
|
+
const rows = event.attendanceModes ?? [];
|
|
38706
|
+
const inPerson = rows.find((row) => row.mode === "in_person");
|
|
38707
|
+
const online = rows.find((row) => row.mode === "online");
|
|
38708
|
+
return inPerson && online ? {
|
|
38709
|
+
inPerson,
|
|
38710
|
+
online
|
|
38711
|
+
} : null;
|
|
38712
|
+
}
|
|
38713
|
+
/** Openness rank; higher means more room. A full mode with a waitlist beats one without. */
|
|
38714
|
+
function remainingPlacesRank(remaining) {
|
|
38715
|
+
switch (remaining.kind) {
|
|
38716
|
+
case "unlimited": return 4;
|
|
38717
|
+
case "open": return 3;
|
|
38718
|
+
case "low": return 2;
|
|
38719
|
+
case "full": return remaining.waitlist ? 1 : 0;
|
|
38720
|
+
}
|
|
38721
|
+
}
|
|
38722
|
+
function isMoreOpen(candidate, than) {
|
|
38723
|
+
const rank = remainingPlacesRank(candidate);
|
|
38724
|
+
const otherRank = remainingPlacesRank(than);
|
|
38725
|
+
if (rank !== otherRank) return rank > otherRank;
|
|
38726
|
+
return candidate.kind === "low" && than.kind === "low" ? candidate.remaining > than.remaining : false;
|
|
38727
|
+
}
|
|
38728
|
+
/** True when `candidate` has less room left than `than`. */
|
|
38729
|
+
function isScarcer(candidate, than) {
|
|
38730
|
+
return isMoreOpen(than, candidate);
|
|
38731
|
+
}
|
|
38732
|
+
const ATTENDANCE_MODE_LABEL = {
|
|
38733
|
+
in_person: "In person",
|
|
38734
|
+
online: "Online"
|
|
38735
|
+
};
|
|
38736
|
+
/** Wording for a mode with room to spare, where the count is deliberately withheld. */
|
|
38737
|
+
const PLACES_AVAILABLE = "Places available";
|
|
38738
|
+
/**
|
|
38739
|
+
* The browse-surface label for an event's remaining places. Single-mode
|
|
38740
|
+
* events get exactly the aggregate label {@link formatRemainingPlaces}
|
|
38741
|
+
* produces, and so does a hybrid event whose two modes tell the same story.
|
|
38742
|
+
* When the modes differ, both sides are named: "available" on a card is a
|
|
38743
|
+
* promise the registration wizard would otherwise have to break.
|
|
38744
|
+
*
|
|
38745
|
+
* Hybrid examples, in person full with 3 online places left:
|
|
38746
|
+
* default -> "Online: 3 places left · In person: Full"
|
|
38747
|
+
* { full: 'Sold out' } -> "Online: 3 places left · In person: Sold out"
|
|
38748
|
+
* { compact: true } -> "Online: 3 left"
|
|
38749
|
+
*/
|
|
38750
|
+
function formatEventRemainingPlaces(event, wording = {}) {
|
|
38751
|
+
const rows = findHybridModeRows(event);
|
|
38752
|
+
if (!rows) return formatRemainingPlaces(event, wording);
|
|
38753
|
+
const inPerson = formatRemainingPlaces(rows.inPerson, wording);
|
|
38754
|
+
const online = formatRemainingPlaces(rows.online, wording);
|
|
38755
|
+
if (inPerson === online) return inPerson;
|
|
38756
|
+
if (wording.compact === true) return formatCompactHybridPlaces(rows, wording);
|
|
38757
|
+
return formatBothHybridSides(rows, {
|
|
38758
|
+
inPerson,
|
|
38759
|
+
online
|
|
38760
|
+
});
|
|
38761
|
+
}
|
|
38762
|
+
/**
|
|
38763
|
+
* Both sides, the one with room first: that is the half a visitor can act on,
|
|
38764
|
+
* and it should not arrive after a full stop's worth of bad news.
|
|
38765
|
+
*/
|
|
38766
|
+
function formatBothHybridSides(rows, labels) {
|
|
38767
|
+
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(" · ");
|
|
38768
|
+
}
|
|
38769
|
+
function namedModePlaces(mode, label) {
|
|
38770
|
+
return `${ATTENDANCE_MODE_LABEL[mode]}: ${label ?? PLACES_AVAILABLE}`;
|
|
38771
|
+
}
|
|
38772
|
+
/**
|
|
38773
|
+
* Pills and timetable cells have room for one short phrase, so they name the
|
|
38774
|
+
* single mode that carries news rather than listing both: the scarce side
|
|
38775
|
+
* when there is a count to show, and otherwise the side that has closed —
|
|
38776
|
+
* "In person: Full", never "Online only", which reads as a statement about
|
|
38777
|
+
* how the event is delivered rather than about its remaining places.
|
|
38778
|
+
*/
|
|
38779
|
+
function formatCompactHybridPlaces(rows, wording) {
|
|
38780
|
+
const inPerson = getRemainingPlaces(rows.inPerson);
|
|
38781
|
+
const online = getRemainingPlaces(rows.online);
|
|
38782
|
+
if (inPerson.kind === "full" && online.kind === "full") return formatRemainingPlaces(inPerson.waitlist ? rows.inPerson : rows.online, wording);
|
|
38783
|
+
if (inPerson.kind === "full" || online.kind === "full") {
|
|
38784
|
+
const fullSide = inPerson.kind === "full" ? "in_person" : "online";
|
|
38785
|
+
const openSide = inPerson.kind === "full" ? "online" : "in_person";
|
|
38786
|
+
const openLabel = formatRemainingPlaces(rowFor(rows, openSide), wording);
|
|
38787
|
+
return openLabel !== null ? namedModePlaces(openSide, openLabel) : namedModePlaces(fullSide, formatRemainingPlaces(rowFor(rows, fullSide), wording));
|
|
38435
38788
|
}
|
|
38789
|
+
const scarcerSide = isScarcer(online, inPerson) ? "online" : "in_person";
|
|
38790
|
+
return namedModePlaces(scarcerSide, formatRemainingPlaces(rowFor(rows, scarcerSide), wording));
|
|
38791
|
+
}
|
|
38792
|
+
function rowFor(rows, mode) {
|
|
38793
|
+
return mode === "online" ? rows.online : rows.inPerson;
|
|
38436
38794
|
}
|
|
38437
38795
|
//#endregion
|
|
38796
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDisplay.ts
|
|
38797
|
+
const registrationDisplaySchema = z.object({
|
|
38798
|
+
venue: z.enum(["shown", "hidden"]),
|
|
38799
|
+
placesLeft: z.enum(["shown", "hidden"])
|
|
38800
|
+
});
|
|
38801
|
+
function resolveRegistrationDisplay(source) {
|
|
38802
|
+
return {
|
|
38803
|
+
venue: source.showVenue === false ? "hidden" : "shown",
|
|
38804
|
+
placesLeft: source.showCapacity === false ? "hidden" : "shown"
|
|
38805
|
+
};
|
|
38806
|
+
}
|
|
38807
|
+
/** Venue stays in domain data; views receive only the permitted presentation. */
|
|
38808
|
+
function shownVenue(event, display) {
|
|
38809
|
+
return display.venue === "shown" ? event.venue?.name ?? null : null;
|
|
38810
|
+
}
|
|
38811
|
+
/** Full/waitlist explanations remain visible even when optional counts are hidden. */
|
|
38812
|
+
function placesLeftLabel(source, display, wording = {}) {
|
|
38813
|
+
if ("kind" in source) return ticketPlacesLabel(source.remaining, display);
|
|
38814
|
+
if (source.deliveryMode === "hybrid" && source.attendanceModes?.length) return hybridPlacesLabel(source, display, wording);
|
|
38815
|
+
return capacityPlacesLabel(source, display, wording);
|
|
38816
|
+
}
|
|
38817
|
+
function capacityPlacesLabel(source, display, wording) {
|
|
38818
|
+
const remaining = getRemainingPlaces(source);
|
|
38819
|
+
if (display.placesLeft === "hidden" && remaining.kind !== "full") return null;
|
|
38820
|
+
switch (remaining.kind) {
|
|
38821
|
+
case "full": return formatRemainingPlaces(source, wording);
|
|
38822
|
+
case "low": return formatRemainingPlaces(source, wording);
|
|
38823
|
+
case "unlimited": return wording.unlimited ?? null;
|
|
38824
|
+
case "open": return wording.open ?? null;
|
|
38825
|
+
default: return assertNever$3(remaining);
|
|
38826
|
+
}
|
|
38827
|
+
}
|
|
38828
|
+
function hybridPlacesLabel(event, display, wording) {
|
|
38829
|
+
if (display.placesLeft === "shown") return formatEventRemainingPlaces(event, wording);
|
|
38830
|
+
return (event.attendanceModes ?? []).flatMap((mode) => {
|
|
38831
|
+
const label = placesLeftLabel(mode, display, wording);
|
|
38832
|
+
return label ? [`${mode.mode === "online" ? "Online" : "In person"}: ${label}`] : [];
|
|
38833
|
+
}).join(" · ") || null;
|
|
38834
|
+
}
|
|
38835
|
+
function ticketPlacesLabel(remaining, display) {
|
|
38836
|
+
if (remaining !== null && remaining > 0 && display.placesLeft === "hidden") return null;
|
|
38837
|
+
return formatTicketTypeRemaining(remaining);
|
|
38838
|
+
}
|
|
38839
|
+
//#endregion
|
|
38840
|
+
//#region ../blocks/src/system/runtime/api/readAuthority.ts
|
|
38841
|
+
const browserReadAuthoritySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("published") }).strict(), z.object({
|
|
38842
|
+
kind: z.literal("preview"),
|
|
38843
|
+
token: z.string().min(1)
|
|
38844
|
+
}).strict()]);
|
|
38845
|
+
//#endregion
|
|
38438
38846
|
//#region ../blocks/src/system/runtime/nodes/events/domain/dates.ts
|
|
38439
38847
|
/**
|
|
38848
|
+
* Date and time presentation for events: the single place an event's
|
|
38849
|
+
* timestamps become strings or date buckets. Calendar-grid primitives are
|
|
38850
|
+
* re-exported from @riverbankcms/calendar so block code has one import.
|
|
38851
|
+
*/
|
|
38852
|
+
/**
|
|
38440
38853
|
* The English locale a site's public dates are written in, read from the
|
|
38441
38854
|
* site's own time zone (Will, 2026-09-26: "date style from site time zone").
|
|
38442
38855
|
*
|
|
@@ -38456,6 +38869,28 @@ function eventDateLocale(siteTimeZone) {
|
|
|
38456
38869
|
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
38457
38870
|
return "en-US";
|
|
38458
38871
|
}
|
|
38872
|
+
function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
|
|
38873
|
+
const locale = options?.locale ?? "en-US";
|
|
38874
|
+
const dateTime = toScheduledBookingDateTime({
|
|
38875
|
+
startsAt: isoTimestamp,
|
|
38876
|
+
timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
|
|
38877
|
+
locale
|
|
38878
|
+
});
|
|
38879
|
+
const cased = (value) => letterCase === "capitals" ? value.toLocaleUpperCase(locale) : value;
|
|
38880
|
+
const weekday = cased(formatBookingDate(dateTime, { weekday: "short" }));
|
|
38881
|
+
const month = cased(formatBookingDate(dateTime, { month: "short" }).slice(0, 3));
|
|
38882
|
+
return {
|
|
38883
|
+
weekday,
|
|
38884
|
+
day: formatBookingDate(dateTime, { day: "numeric" }),
|
|
38885
|
+
month,
|
|
38886
|
+
label: formatBookingDate(dateTime, {
|
|
38887
|
+
weekday: "long",
|
|
38888
|
+
year: "numeric",
|
|
38889
|
+
month: "long",
|
|
38890
|
+
day: "numeric"
|
|
38891
|
+
})
|
|
38892
|
+
};
|
|
38893
|
+
}
|
|
38459
38894
|
//#endregion
|
|
38460
38895
|
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
38461
38896
|
function isRecord$7(value) {
|
|
@@ -38475,6 +38910,15 @@ function resolveRuntimeEventDestination(event) {
|
|
|
38475
38910
|
};
|
|
38476
38911
|
}
|
|
38477
38912
|
//#endregion
|
|
38913
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
38914
|
+
/**
|
|
38915
|
+
* Format an event's price directly from its pricing value (without the full
|
|
38916
|
+
* event). Same output as {@link formatEventPrice}.
|
|
38917
|
+
*/
|
|
38918
|
+
function formatEventPriceDisplay(pricing) {
|
|
38919
|
+
return formatEventPricing(pricing, { decimals: "auto" });
|
|
38920
|
+
}
|
|
38921
|
+
//#endregion
|
|
38478
38922
|
//#region ../blocks/src/system/runtime/nodes/events/domain/listWeek.ts
|
|
38479
38923
|
/** Civil weeks use the site zone, including weeks containing a clock change. */
|
|
38480
38924
|
function buildEventListWeek(anchor, startOfWeek, timeZone) {
|
|
@@ -38509,52 +38953,6 @@ function eventListWindowEvents(events, window) {
|
|
|
38509
38953
|
});
|
|
38510
38954
|
}
|
|
38511
38955
|
//#endregion
|
|
38512
|
-
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
38513
|
-
const previewStageSchema = z.enum(["preview", "published"]);
|
|
38514
|
-
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
38515
|
-
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
38516
|
-
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
38517
|
-
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
38518
|
-
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
38519
|
-
const columnOptionSchema = z.enum([
|
|
38520
|
-
"2",
|
|
38521
|
-
"3",
|
|
38522
|
-
"4"
|
|
38523
|
-
]);
|
|
38524
|
-
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
38525
|
-
const filterAutoShowSchema = z.enum([
|
|
38526
|
-
"auto",
|
|
38527
|
-
"always",
|
|
38528
|
-
"never"
|
|
38529
|
-
]);
|
|
38530
|
-
const calendarTabViewsSchema = z.enum([
|
|
38531
|
-
"both",
|
|
38532
|
-
"month",
|
|
38533
|
-
"week"
|
|
38534
|
-
]);
|
|
38535
|
-
//#endregion
|
|
38536
|
-
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
38537
|
-
/**
|
|
38538
|
-
* Determine which wizard steps to show based on context and payment requirements.
|
|
38539
|
-
*
|
|
38540
|
-
* @param hasPreSelectedContext - Whether event is pre-selected (skips event selection)
|
|
38541
|
-
* @param needsPaymentStep - Whether user must complete payment method selection
|
|
38542
|
-
* @returns Array of wizard steps to display
|
|
38543
|
-
*/
|
|
38544
|
-
function getWizardStepsForContext(hasPreSelectedContext, needsPaymentStep, paymentActive = false) {
|
|
38545
|
-
const baseSteps = hasPreSelectedContext ? ["select-tickets", "enter-details"] : [
|
|
38546
|
-
"select-event",
|
|
38547
|
-
"select-tickets",
|
|
38548
|
-
"enter-details"
|
|
38549
|
-
];
|
|
38550
|
-
if (!needsPaymentStep) return baseSteps;
|
|
38551
|
-
return paymentActive ? [
|
|
38552
|
-
...baseSteps,
|
|
38553
|
-
"select-payment",
|
|
38554
|
-
"payment"
|
|
38555
|
-
] : [...baseSteps, "select-payment"];
|
|
38556
|
-
}
|
|
38557
|
-
//#endregion
|
|
38558
38956
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDerivations.ts
|
|
38559
38957
|
function eventMatchesOccurrenceId(event, occurrenceId) {
|
|
38560
38958
|
return event.registrationSubject.kind === "occurrence" && (event.registrationSubject.occurrenceId === occurrenceId || event.selectionId === occurrenceId);
|
|
@@ -38578,6 +38976,424 @@ function resolveEventRequiresPayment(input) {
|
|
|
38578
38976
|
return publicEventPricingType(input.event.pricing) === "paid";
|
|
38579
38977
|
}
|
|
38580
38978
|
//#endregion
|
|
38979
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/utils.ts
|
|
38980
|
+
/**
|
|
38981
|
+
* The locale a site's booking dates are written in: the one the site's time
|
|
38982
|
+
* zone places it in (`eventDateLocale`, shared with event cards), or British
|
|
38983
|
+
* English when the site names no zone.
|
|
38984
|
+
*/
|
|
38985
|
+
function bookingDateLocale(siteTimeZone) {
|
|
38986
|
+
return siteTimeZone ? eventDateLocale(siteTimeZone) : "en-GB";
|
|
38987
|
+
}
|
|
38988
|
+
function bookingInstant(startsAt, input) {
|
|
38989
|
+
return toScheduledBookingDateTime({
|
|
38990
|
+
startsAt,
|
|
38991
|
+
timeZone: toBookingTimeZone(input.timeZone),
|
|
38992
|
+
locale: bookingDateLocale(input.siteTimeZone)
|
|
38993
|
+
});
|
|
38994
|
+
}
|
|
38995
|
+
/** "7:00pm": a twelve-hour clock with a lowercase, unspaced day period. */
|
|
38996
|
+
function bookingClock(startsAt, input) {
|
|
38997
|
+
return formatBookingTime(bookingInstant(startsAt, input), {
|
|
38998
|
+
hour: "numeric",
|
|
38999
|
+
minute: "2-digit",
|
|
39000
|
+
hour12: true
|
|
39001
|
+
}).replace(/\s*([ap])\.?\s?m\.?$/i, (_match, period) => `${period.toLowerCase()}m`);
|
|
39002
|
+
}
|
|
39003
|
+
/** "7:00pm – 8:15pm", or just the start when there's no distinct end. */
|
|
39004
|
+
function clockRange(input) {
|
|
39005
|
+
const start = bookingClock(input.startsAt, input);
|
|
39006
|
+
const end = input.endsAt ? bookingClock(input.endsAt, input) : null;
|
|
39007
|
+
return end && end !== start ? `${start} – ${end}` : start;
|
|
39008
|
+
}
|
|
39009
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
39010
|
+
function formatBookingScheduleSummary(event) {
|
|
39011
|
+
const summary = event.scheduleSummary;
|
|
39012
|
+
if (!summary) return null;
|
|
39013
|
+
const time = summary.startTime ? formatBookingWhen({
|
|
39014
|
+
startsAt: `1970-01-01T${summary.startTime}:00Z`,
|
|
39015
|
+
timeZone: "UTC",
|
|
39016
|
+
siteTimeZone: event.siteTimeZone
|
|
39017
|
+
}, "time") : null;
|
|
39018
|
+
return [summary.recurrenceDescription, time].filter(Boolean).join(" · ");
|
|
39019
|
+
}
|
|
39020
|
+
/** The one booking date formatter; every variant derives from it. */
|
|
39021
|
+
function formatBookingWhen(input, variant) {
|
|
39022
|
+
const instant = bookingInstant(input.startsAt, input);
|
|
39023
|
+
const day = formatBookingDate(instant, {
|
|
39024
|
+
weekday: "short",
|
|
39025
|
+
day: "numeric",
|
|
39026
|
+
month: "short"
|
|
39027
|
+
});
|
|
39028
|
+
switch (variant) {
|
|
39029
|
+
case "day": return day;
|
|
39030
|
+
case "dayLong": return formatBookingDate(instant, {
|
|
39031
|
+
weekday: "long",
|
|
39032
|
+
day: "numeric",
|
|
39033
|
+
month: "long"
|
|
39034
|
+
});
|
|
39035
|
+
case "month": return formatBookingDate(instant, { month: "long" });
|
|
39036
|
+
case "monthYear": return formatBookingDate(instant, {
|
|
39037
|
+
month: "long",
|
|
39038
|
+
year: "numeric"
|
|
39039
|
+
});
|
|
39040
|
+
case "time": return bookingClock(input.startsAt, input);
|
|
39041
|
+
case "timeRange": return clockRange(input);
|
|
39042
|
+
case "short": return `${day}, ${bookingClock(input.startsAt, input)}`;
|
|
39043
|
+
case "long": return `${day} · ${clockRange(input)}`;
|
|
39044
|
+
}
|
|
39045
|
+
}
|
|
39046
|
+
/** A single instant in the short form, e.g. "Mon 5 Oct, 7:00pm". */
|
|
39047
|
+
function formatEventDateTime(isoTimestamp, options) {
|
|
39048
|
+
return formatBookingWhen({
|
|
39049
|
+
startsAt: isoTimestamp,
|
|
39050
|
+
timeZone: options?.timeZone,
|
|
39051
|
+
siteTimeZone: options?.siteTimeZone
|
|
39052
|
+
}, "short");
|
|
39053
|
+
}
|
|
39054
|
+
/** The title an occurrence was given on its own, when it overrides the event's. */
|
|
39055
|
+
function occurrenceTitleOverride(occurrence) {
|
|
39056
|
+
const title = occurrence?.overrides?.title;
|
|
39057
|
+
return typeof title === "string" && title.trim() ? title.trim() : null;
|
|
39058
|
+
}
|
|
39059
|
+
/** The event as this page names it: an occurrence's own title wins. */
|
|
39060
|
+
function withOccurrenceTitle(event, occurrence) {
|
|
39061
|
+
const title = occurrenceTitleOverride(occurrence);
|
|
39062
|
+
return event && title ? {
|
|
39063
|
+
...event,
|
|
39064
|
+
title
|
|
39065
|
+
} : event;
|
|
39066
|
+
}
|
|
39067
|
+
function courseSchedule(sessions, siteTimeZone) {
|
|
39068
|
+
const first = sessions[0];
|
|
39069
|
+
if (!first) return null;
|
|
39070
|
+
const last = sessions[sessions.length - 1] ?? first;
|
|
39071
|
+
const firstLabel = formatEventDateTime(first.startsAt, {
|
|
39072
|
+
timeZone: first.timeZone,
|
|
39073
|
+
siteTimeZone
|
|
39074
|
+
});
|
|
39075
|
+
if (last.startsAt === first.startsAt) return `${sessions.length} session${sessions.length === 1 ? "" : "s"} · ${firstLabel}`;
|
|
39076
|
+
const lastLabel = formatEventDateTime(last.startsAt, {
|
|
39077
|
+
timeZone: last.timeZone,
|
|
39078
|
+
siteTimeZone
|
|
39079
|
+
});
|
|
39080
|
+
return `${sessions.length} sessions · ${firstLabel} – ${lastLabel}`;
|
|
39081
|
+
}
|
|
39082
|
+
/**
|
|
39083
|
+
* When a booking happens, in one line: the occurrence's date and time, or a
|
|
39084
|
+
* course's session count and first and last dates. `short` by default (bar,
|
|
39085
|
+
* confirmation); `long` adds the end time (card, panel header).
|
|
39086
|
+
*/
|
|
39087
|
+
function formatRegistrationSchedule(event, occurrence, variant = "short") {
|
|
39088
|
+
if (event.registrationSubject.kind === "wholeSeries") return courseSchedule(event.registrationSubject.sessions, event.siteTimeZone);
|
|
39089
|
+
const input = scheduleInput(event, occurrence ?? null);
|
|
39090
|
+
return input ? formatBookingWhen(input, variant) : null;
|
|
39091
|
+
}
|
|
39092
|
+
/** The occurrence's own times when the page names one, otherwise the event's. */
|
|
39093
|
+
function scheduleInput(event, occurrence) {
|
|
39094
|
+
const times = occurrence?.startsAt ? {
|
|
39095
|
+
startsAt: occurrence.startsAt,
|
|
39096
|
+
endsAt: occurrence.endsAt ?? null
|
|
39097
|
+
} : {
|
|
39098
|
+
startsAt: event.startsAt,
|
|
39099
|
+
endsAt: event.endsAt
|
|
39100
|
+
};
|
|
39101
|
+
if (!times.startsAt) return null;
|
|
39102
|
+
return {
|
|
39103
|
+
...times,
|
|
39104
|
+
timeZone: occurrence?.timeZone ?? event.timeZone ?? null,
|
|
39105
|
+
siteTimeZone: event.siteTimeZone
|
|
39106
|
+
};
|
|
39107
|
+
}
|
|
39108
|
+
//#endregion
|
|
39109
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/wizardSteps.ts
|
|
39110
|
+
function registrationRoute(input) {
|
|
39111
|
+
const base = input.chooseEvent ? [
|
|
39112
|
+
"select-event",
|
|
39113
|
+
"select-tickets",
|
|
39114
|
+
"enter-details"
|
|
39115
|
+
] : ["select-tickets", "enter-details"];
|
|
39116
|
+
switch (input.payment) {
|
|
39117
|
+
case "none": return base;
|
|
39118
|
+
case "options": return [...base, "select-payment"];
|
|
39119
|
+
case "optionsAndPayment": return [
|
|
39120
|
+
...base,
|
|
39121
|
+
"select-payment",
|
|
39122
|
+
"payment"
|
|
39123
|
+
];
|
|
39124
|
+
}
|
|
39125
|
+
}
|
|
39126
|
+
const REGISTRATION_STEP_LABELS = [
|
|
39127
|
+
"Event",
|
|
39128
|
+
"Date",
|
|
39129
|
+
"Tickets",
|
|
39130
|
+
"Places",
|
|
39131
|
+
"Your details",
|
|
39132
|
+
"How you’ll pay",
|
|
39133
|
+
"Payment"
|
|
39134
|
+
];
|
|
39135
|
+
/** Several dates of one series are a date choice; anything else is an event choice. */
|
|
39136
|
+
function getEventSelectionMode(events) {
|
|
39137
|
+
const firstSeriesId = events[0]?.seriesId;
|
|
39138
|
+
return events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId) ? "date" : "event";
|
|
39139
|
+
}
|
|
39140
|
+
/** The label facts for a surface: what the visitor chooses from, and what they book. */
|
|
39141
|
+
function registrationStepLabelContext(scopedEvents, bookedEvent) {
|
|
39142
|
+
return {
|
|
39143
|
+
eventSelection: getEventSelectionMode(scopedEvents),
|
|
39144
|
+
booksWholeSeries: bookedEvent?.registrationSubject.kind === "wholeSeries"
|
|
39145
|
+
};
|
|
39146
|
+
}
|
|
39147
|
+
/** One label owner for the live progress and the server placeholder. */
|
|
39148
|
+
function registrationStepLabel(step, context) {
|
|
39149
|
+
switch (step) {
|
|
39150
|
+
case "select-event": return context.eventSelection === "date" ? "Date" : "Event";
|
|
39151
|
+
case "select-tickets": return context.booksWholeSeries ? "Places" : "Tickets";
|
|
39152
|
+
case "enter-details": return "Your details";
|
|
39153
|
+
case "select-payment": return "How you’ll pay";
|
|
39154
|
+
case "payment": return "Payment";
|
|
39155
|
+
}
|
|
39156
|
+
}
|
|
39157
|
+
function bookingButtonText(buttonText) {
|
|
39158
|
+
return buttonText?.trim() || "Book your place";
|
|
39159
|
+
}
|
|
39160
|
+
function placesLabel(event, input, compact) {
|
|
39161
|
+
return placesLeftLabel(selectEventCapacitySource(event, input.attendanceMode), input.display, { compact });
|
|
39162
|
+
}
|
|
39163
|
+
function isFull(event, mode) {
|
|
39164
|
+
return formatRemainingPlaces(selectEventCapacitySource(event, mode), {
|
|
39165
|
+
full: "full",
|
|
39166
|
+
waitlist: "full"
|
|
39167
|
+
}) === "full";
|
|
39168
|
+
}
|
|
39169
|
+
function priceLabel(event) {
|
|
39170
|
+
return formatEventPriceDisplay(event.pricing).trim() || null;
|
|
39171
|
+
}
|
|
39172
|
+
/** The lowest price a display can mean; null when it names no paid amount. */
|
|
39173
|
+
function lowestPaidAmount(display) {
|
|
39174
|
+
switch (display.kind) {
|
|
39175
|
+
case "exact":
|
|
39176
|
+
case "from": return display.amount;
|
|
39177
|
+
case "range": return display.minAmount;
|
|
39178
|
+
case "mixed": return display.paidFromAmount;
|
|
39179
|
+
case "free":
|
|
39180
|
+
case "unavailable":
|
|
39181
|
+
case "external": return null;
|
|
39182
|
+
}
|
|
39183
|
+
}
|
|
39184
|
+
/**
|
|
39185
|
+
* One price for a set of dates: the shared label when every date costs the
|
|
39186
|
+
* same, otherwise "From" the lowest paid amount, through the one formatter.
|
|
39187
|
+
*/
|
|
39188
|
+
function seriesPriceLabel(events) {
|
|
39189
|
+
const firstEvent = events[0];
|
|
39190
|
+
if (!firstEvent) return null;
|
|
39191
|
+
const displays = events.map((event) => publicEventPricingDisplay(event.pricing));
|
|
39192
|
+
const labels = new Set(displays.map((display) => formatBookingPriceDisplay(display, { decimals: "auto" })));
|
|
39193
|
+
if (labels.size === 1) return [...labels][0] || null;
|
|
39194
|
+
const lowest = displays.flatMap((display) => {
|
|
39195
|
+
const amount = lowestPaidAmount(display);
|
|
39196
|
+
return amount === null || !("currency" in display) ? [] : [{
|
|
39197
|
+
amount,
|
|
39198
|
+
currency: display.currency
|
|
39199
|
+
}];
|
|
39200
|
+
}).reduce((best, candidate) => best === null || candidate.amount < best.amount ? candidate : best, null);
|
|
39201
|
+
return lowest ? formatBookingPriceDisplay({
|
|
39202
|
+
kind: "from",
|
|
39203
|
+
amount: lowest.amount,
|
|
39204
|
+
currency: lowest.currency
|
|
39205
|
+
}, { decimals: "auto" }) : priceLabel(firstEvent);
|
|
39206
|
+
}
|
|
39207
|
+
function dateTile(event) {
|
|
39208
|
+
if (event.registrationSubject.kind === "wholeSeries" || !event.startsAt) return null;
|
|
39209
|
+
const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
|
|
39210
|
+
return {
|
|
39211
|
+
month: rail.month,
|
|
39212
|
+
day: rail.day
|
|
39213
|
+
};
|
|
39214
|
+
}
|
|
39215
|
+
/** "Mon 5 Oct": the compact date the chips and the bar share. */
|
|
39216
|
+
function formatBookingShortDate(event) {
|
|
39217
|
+
return formatBookingWhen(event, "day");
|
|
39218
|
+
}
|
|
39219
|
+
function byStart(left, right) {
|
|
39220
|
+
return Date.parse(left.startsAt) - Date.parse(right.startsAt);
|
|
39221
|
+
}
|
|
39222
|
+
function singleEntry(event, input) {
|
|
39223
|
+
const isCourse = event.registrationSubject.kind === "wholeSeries";
|
|
39224
|
+
return {
|
|
39225
|
+
kind: "single",
|
|
39226
|
+
title: event.title,
|
|
39227
|
+
when: formatRegistrationSchedule(event, null, "long"),
|
|
39228
|
+
shortWhen: formatRegistrationSchedule(event),
|
|
39229
|
+
venue: shownVenue(event, input.display),
|
|
39230
|
+
price: priceLabel(event),
|
|
39231
|
+
places: placesLabel(event, input, false),
|
|
39232
|
+
tile: dateTile(event),
|
|
39233
|
+
action: isCourse ? `Book the ${input.noun.label}` : bookingButtonText(input.buttonText)
|
|
39234
|
+
};
|
|
39235
|
+
}
|
|
39236
|
+
function chooseDateEntry(input) {
|
|
39237
|
+
const ordered = [...input.events].sort(byStart);
|
|
39238
|
+
const first = ordered[0];
|
|
39239
|
+
const shown = ordered.slice(0, 4);
|
|
39240
|
+
return {
|
|
39241
|
+
kind: "chooseDate",
|
|
39242
|
+
title: first?.title ?? "",
|
|
39243
|
+
schedule: (first ? formatBookingScheduleSummary(first) : null) ?? (ordered.length === 1 ? "1 date" : `${ordered.length} dates`),
|
|
39244
|
+
venue: first ? shownVenue(first, input.display) : null,
|
|
39245
|
+
price: seriesPriceLabel(ordered),
|
|
39246
|
+
nextDate: first ? formatBookingShortDate(first) : null,
|
|
39247
|
+
dateCount: ordered.length,
|
|
39248
|
+
dates: shown.map((event) => ({
|
|
39249
|
+
selectionId: event.selectionId,
|
|
39250
|
+
label: formatBookingShortDate(event),
|
|
39251
|
+
places: placesLabel(event, input, true),
|
|
39252
|
+
full: isFull(event, input.attendanceMode)
|
|
39253
|
+
})),
|
|
39254
|
+
moreCount: Math.max(0, ordered.length - shown.length),
|
|
39255
|
+
action: "Choose a date"
|
|
39256
|
+
};
|
|
39257
|
+
}
|
|
39258
|
+
/** The card before a booking starts; the server renders this too. */
|
|
39259
|
+
function idleBookingEntry(input) {
|
|
39260
|
+
if (input.event) return singleEntry(input.event, input);
|
|
39261
|
+
const only = input.events.length === 1 ? input.events[0] : void 0;
|
|
39262
|
+
if (only) return singleEntry(only, input);
|
|
39263
|
+
if (getEventSelectionMode(input.events) === "date") return chooseDateEntry(input);
|
|
39264
|
+
return {
|
|
39265
|
+
kind: "chooseEvent",
|
|
39266
|
+
title: input.events[0]?.title ?? "",
|
|
39267
|
+
count: input.events.length,
|
|
39268
|
+
noun: input.noun.pluralLabel,
|
|
39269
|
+
action: "Choose an event"
|
|
39270
|
+
};
|
|
39271
|
+
}
|
|
39272
|
+
//#endregion
|
|
39273
|
+
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
39274
|
+
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
39275
|
+
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
39276
|
+
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
39277
|
+
{
|
|
39278
|
+
preset: "class",
|
|
39279
|
+
sourceKey: "eventPreset:class",
|
|
39280
|
+
dataKey: "classEvents",
|
|
39281
|
+
label: "Classes"
|
|
39282
|
+
},
|
|
39283
|
+
{
|
|
39284
|
+
preset: "workshop",
|
|
39285
|
+
sourceKey: "eventPreset:workshop",
|
|
39286
|
+
dataKey: "workshopEvents",
|
|
39287
|
+
label: "Workshops"
|
|
39288
|
+
},
|
|
39289
|
+
{
|
|
39290
|
+
preset: "retreat",
|
|
39291
|
+
sourceKey: "eventPreset:retreat",
|
|
39292
|
+
dataKey: "retreatEvents",
|
|
39293
|
+
label: "Retreats"
|
|
39294
|
+
},
|
|
39295
|
+
{
|
|
39296
|
+
preset: "performance",
|
|
39297
|
+
sourceKey: "eventPreset:performance",
|
|
39298
|
+
dataKey: "performanceEvents",
|
|
39299
|
+
label: "Performances"
|
|
39300
|
+
}
|
|
39301
|
+
];
|
|
39302
|
+
const OFFERINGS_PREVIEW_EVENT_PRESETS = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
39303
|
+
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
39304
|
+
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
39305
|
+
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
39306
|
+
kind: "eventPreset",
|
|
39307
|
+
preset: definition.preset
|
|
39308
|
+
}]));
|
|
39309
|
+
function isOfferingsPreviewSourceKey(value) {
|
|
39310
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
39311
|
+
}
|
|
39312
|
+
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
39313
|
+
if (value == null) return { kind: "legacy" };
|
|
39314
|
+
if (value.length === 0) return { kind: "default" };
|
|
39315
|
+
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
39316
|
+
return keys.length > 0 ? {
|
|
39317
|
+
kind: "custom",
|
|
39318
|
+
keys
|
|
39319
|
+
} : { kind: "default" };
|
|
39320
|
+
}
|
|
39321
|
+
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
39322
|
+
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
39323
|
+
return keys.length >= 2 ? keys : [];
|
|
39324
|
+
}
|
|
39325
|
+
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
39326
|
+
if (!isRecord$6(value)) return null;
|
|
39327
|
+
const groupOrderValue = value.groupOrder;
|
|
39328
|
+
if (Array.isArray(groupOrderValue)) {
|
|
39329
|
+
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
39330
|
+
return {
|
|
39331
|
+
...value,
|
|
39332
|
+
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
39333
|
+
};
|
|
39334
|
+
}
|
|
39335
|
+
if (groupOrderValue != null) return {
|
|
39336
|
+
...value,
|
|
39337
|
+
groupOrder: []
|
|
39338
|
+
};
|
|
39339
|
+
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$6) : []);
|
|
39340
|
+
return legacyOrder.length > 0 ? {
|
|
39341
|
+
...value,
|
|
39342
|
+
groupOrder: legacyOrder
|
|
39343
|
+
} : value;
|
|
39344
|
+
}
|
|
39345
|
+
/** Which offerings a site preset row names; one owner for "the course preset means whole-series runs". */
|
|
39346
|
+
function sourceFromPresetSummary(preset) {
|
|
39347
|
+
if (preset.engine === "event_series" && preset.canonicalBehaviour === "course") return { kind: "wholeSeries" };
|
|
39348
|
+
if (preset.engine !== "event_series") return null;
|
|
39349
|
+
if (isOfferingsPreviewEventPreset(preset.canonicalBehaviour)) return {
|
|
39350
|
+
kind: "eventPreset",
|
|
39351
|
+
preset: preset.canonicalBehaviour
|
|
39352
|
+
};
|
|
39353
|
+
return null;
|
|
39354
|
+
}
|
|
39355
|
+
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
39356
|
+
const keys = [];
|
|
39357
|
+
for (const value of values) {
|
|
39358
|
+
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
39359
|
+
if (!keys.includes(value)) keys.push(value);
|
|
39360
|
+
}
|
|
39361
|
+
return keys;
|
|
39362
|
+
}
|
|
39363
|
+
function isRecord$6(value) {
|
|
39364
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39365
|
+
}
|
|
39366
|
+
function isOfferingsPreviewEventPreset(value) {
|
|
39367
|
+
return typeof value === "string" && OFFERINGS_PREVIEW_EVENT_PRESETS.includes(value);
|
|
39368
|
+
}
|
|
39369
|
+
//#endregion
|
|
39370
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/offeringNoun.ts
|
|
39371
|
+
function offeringKindForEvent(event) {
|
|
39372
|
+
return event.registrationSubject.kind === "wholeSeries" ? "course" : event.eventPreset ?? "event";
|
|
39373
|
+
}
|
|
39374
|
+
function presetKind(preset) {
|
|
39375
|
+
const source = sourceFromPresetSummary(preset);
|
|
39376
|
+
if (!source) return null;
|
|
39377
|
+
return source.kind === "wholeSeries" ? "course" : source.preset;
|
|
39378
|
+
}
|
|
39379
|
+
/**
|
|
39380
|
+
* What the site calls this kind of offering, in lower case for use mid-sentence
|
|
39381
|
+
* ("Book the course", "3 workshops"). Site preset labels win; the canonical
|
|
39382
|
+
* name stands in when the site has none.
|
|
39383
|
+
*/
|
|
39384
|
+
function offeringNounForEvent(event, presets) {
|
|
39385
|
+
if (!event) return lowerCased(EVENT_PRESET_VOCABULARY.event);
|
|
39386
|
+
const kind = offeringKindForEvent(event);
|
|
39387
|
+
const preset = presets?.find((candidate) => presetKind(candidate) === kind);
|
|
39388
|
+
return lowerCased(preset?.label.trim() && preset.pluralLabel.trim() ? preset : EVENT_PRESET_VOCABULARY[kind]);
|
|
39389
|
+
}
|
|
39390
|
+
function lowerCased(noun) {
|
|
39391
|
+
return {
|
|
39392
|
+
label: noun.label.trim().toLocaleLowerCase(),
|
|
39393
|
+
pluralLabel: noun.pluralLabel.trim().toLocaleLowerCase()
|
|
39394
|
+
};
|
|
39395
|
+
}
|
|
39396
|
+
//#endregion
|
|
38581
39397
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationEventAdapter.ts
|
|
38582
39398
|
function toRegistrationEvent(event) {
|
|
38583
39399
|
return {
|
|
@@ -38622,6 +39438,181 @@ function toWholeSeriesRegistrationEvents(events) {
|
|
|
38622
39438
|
return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
|
|
38623
39439
|
}
|
|
38624
39440
|
//#endregion
|
|
39441
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/bookingCardDisplay.ts
|
|
39442
|
+
/**
|
|
39443
|
+
* The booking card the server renders on CMS pages (issue 1581), and the
|
|
39444
|
+
* offering noun it resolves for the wizard. Kept beside the island contract
|
|
39445
|
+
* so the server and the client agree on one card.
|
|
39446
|
+
*/
|
|
39447
|
+
const bookingHostSchema = z.enum(["overlay", "inPlace"]);
|
|
39448
|
+
const tileSchema = z.object({
|
|
39449
|
+
month: z.string(),
|
|
39450
|
+
day: z.string()
|
|
39451
|
+
}).nullable();
|
|
39452
|
+
const idleBookingEntrySchema = z.discriminatedUnion("kind", [
|
|
39453
|
+
z.object({
|
|
39454
|
+
kind: z.literal("single"),
|
|
39455
|
+
title: z.string(),
|
|
39456
|
+
when: z.string().nullable(),
|
|
39457
|
+
shortWhen: z.string().nullable(),
|
|
39458
|
+
venue: z.string().nullable(),
|
|
39459
|
+
price: z.string().nullable(),
|
|
39460
|
+
places: z.string().nullable(),
|
|
39461
|
+
tile: tileSchema,
|
|
39462
|
+
action: z.string()
|
|
39463
|
+
}),
|
|
39464
|
+
z.object({
|
|
39465
|
+
kind: z.literal("chooseDate"),
|
|
39466
|
+
title: z.string(),
|
|
39467
|
+
schedule: z.string(),
|
|
39468
|
+
venue: z.string().nullable(),
|
|
39469
|
+
price: z.string().nullable(),
|
|
39470
|
+
nextDate: z.string().nullable(),
|
|
39471
|
+
dateCount: z.number(),
|
|
39472
|
+
dates: z.array(z.object({
|
|
39473
|
+
selectionId: z.string(),
|
|
39474
|
+
label: z.string(),
|
|
39475
|
+
places: z.string().nullable(),
|
|
39476
|
+
full: z.boolean()
|
|
39477
|
+
})),
|
|
39478
|
+
moreCount: z.number(),
|
|
39479
|
+
action: z.string()
|
|
39480
|
+
}),
|
|
39481
|
+
z.object({
|
|
39482
|
+
kind: z.literal("chooseEvent"),
|
|
39483
|
+
title: z.string(),
|
|
39484
|
+
count: z.number(),
|
|
39485
|
+
noun: z.string(),
|
|
39486
|
+
action: z.string()
|
|
39487
|
+
})
|
|
39488
|
+
]);
|
|
39489
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
39490
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
39491
|
+
}
|
|
39492
|
+
function scopedRegistrationEvents(source, scopedSourceEvents) {
|
|
39493
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
39494
|
+
return {
|
|
39495
|
+
scopedEvents,
|
|
39496
|
+
preSelected: findPreSelectedEvent({
|
|
39497
|
+
scopedEvents,
|
|
39498
|
+
occurrenceContext: source.occurrenceContext
|
|
39499
|
+
})
|
|
39500
|
+
};
|
|
39501
|
+
}
|
|
39502
|
+
function nounFor(scoped, presets) {
|
|
39503
|
+
return offeringNounForEvent(scoped.preSelected ?? scoped.scopedEvents[0] ?? null, presets);
|
|
39504
|
+
}
|
|
39505
|
+
/** What the site calls the offering this block books, from its preset rows. */
|
|
39506
|
+
function resolveOfferingNoun(source, scopedSourceEvents) {
|
|
39507
|
+
return nounFor(scopedRegistrationEvents(source, scopedSourceEvents), source.bookingOfferingPresets);
|
|
39508
|
+
}
|
|
39509
|
+
function idleEntry(source, scopedSourceEvents, display) {
|
|
39510
|
+
const scoped = scopedRegistrationEvents(source, scopedSourceEvents);
|
|
39511
|
+
if (scoped.scopedEvents.length === 0) return null;
|
|
39512
|
+
return idleBookingEntry({
|
|
39513
|
+
events: scoped.scopedEvents,
|
|
39514
|
+
event: withOccurrenceTitle(scoped.preSelected, source.occurrenceContext),
|
|
39515
|
+
display,
|
|
39516
|
+
buttonText: source.buttonText,
|
|
39517
|
+
noun: nounFor(scoped, source.bookingOfferingPresets),
|
|
39518
|
+
attendanceMode: null
|
|
39519
|
+
});
|
|
39520
|
+
}
|
|
39521
|
+
/** The server's card on CMS pages, or null where the shell still applies. */
|
|
39522
|
+
function bookingCardDisplay(source, scopedSourceEvents, display) {
|
|
39523
|
+
if ((source.host ?? "overlay") !== "overlay") return null;
|
|
39524
|
+
const entry = idleEntry(source, scopedSourceEvents, display);
|
|
39525
|
+
if (!entry) return null;
|
|
39526
|
+
return {
|
|
39527
|
+
kind: "event-registration",
|
|
39528
|
+
state: "booking-card",
|
|
39529
|
+
className: source.className ?? null,
|
|
39530
|
+
entry,
|
|
39531
|
+
buttonVariant: source.buttonVariant ?? null,
|
|
39532
|
+
buttonText: source.buttonText?.trim() ?? ""
|
|
39533
|
+
};
|
|
39534
|
+
}
|
|
39535
|
+
const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
|
|
39536
|
+
kind: z.literal("unsupported"),
|
|
39537
|
+
reason: z.enum([
|
|
39538
|
+
"unsupportedSubject",
|
|
39539
|
+
"invalidEventSeriesId",
|
|
39540
|
+
"invalidEventSeriesBookingScope",
|
|
39541
|
+
"invalidEventOfferingId",
|
|
39542
|
+
"invalidEventOfferingBookingScope",
|
|
39543
|
+
"invalidEventOfferingCatalogue"
|
|
39544
|
+
])
|
|
39545
|
+
});
|
|
39546
|
+
const eventRegistrationPageSurfaceSubjectSchema = z.unknown().transform((value, ctx) => {
|
|
39547
|
+
const unsupported = unsupportedEventRegistrationPageSurfaceSubjectSchema.safeParse(value);
|
|
39548
|
+
if (unsupported.success) return unsupported.data;
|
|
39549
|
+
const parsed = parseEventPageSurfaceSubject(value);
|
|
39550
|
+
if (parsed.ok) return parsed.value;
|
|
39551
|
+
ctx.addIssue({
|
|
39552
|
+
code: z.ZodIssueCode.custom,
|
|
39553
|
+
message: `Invalid event page-surface subject (${parsed.error.kind})`
|
|
39554
|
+
});
|
|
39555
|
+
return z.NEVER;
|
|
39556
|
+
});
|
|
39557
|
+
function resolveEventRegistrationScope(context) {
|
|
39558
|
+
const occurrenceSeriesId = context.occurrenceContext?.seriesId;
|
|
39559
|
+
if (occurrenceSeriesId) return {
|
|
39560
|
+
kind: "occurrenceSeries",
|
|
39561
|
+
seriesId: occurrenceSeriesId
|
|
39562
|
+
};
|
|
39563
|
+
if (context.subject?.kind === "eventSeries") return {
|
|
39564
|
+
kind: "pageSurfaceSeries",
|
|
39565
|
+
seriesId: context.subject.eventSeriesId
|
|
39566
|
+
};
|
|
39567
|
+
if (context.subject?.kind === "eventOffering") return {
|
|
39568
|
+
kind: "pageSurfaceOffering",
|
|
39569
|
+
offeringId: context.subject.eventOfferingId,
|
|
39570
|
+
seriesIds: context.subject.catalogueEventSeriesIds
|
|
39571
|
+
};
|
|
39572
|
+
if (context.subject?.kind === "unsupported") return {
|
|
39573
|
+
kind: "unsupportedPageSurfaceSubject",
|
|
39574
|
+
reason: context.subject.reason
|
|
39575
|
+
};
|
|
39576
|
+
return { kind: "unscoped" };
|
|
39577
|
+
}
|
|
39578
|
+
function resolveEventRegistrationScopedEvents(events, context) {
|
|
39579
|
+
const scope = resolveEventRegistrationScope(context);
|
|
39580
|
+
switch (scope.kind) {
|
|
39581
|
+
case "occurrenceSeries":
|
|
39582
|
+
case "pageSurfaceSeries": return events.filter((event) => event.seriesId === scope.seriesId);
|
|
39583
|
+
case "pageSurfaceOffering": {
|
|
39584
|
+
const seriesIds = new Set(scope.seriesIds);
|
|
39585
|
+
return events.filter((event) => seriesIds.has(event.seriesId));
|
|
39586
|
+
}
|
|
39587
|
+
case "unsupportedPageSurfaceSubject": return [];
|
|
39588
|
+
case "unscoped": return [...events];
|
|
39589
|
+
}
|
|
39590
|
+
}
|
|
39591
|
+
//#endregion
|
|
39592
|
+
//#region ../blocks/src/system/runtime/nodes/shared/contract-schemas.ts
|
|
39593
|
+
const previewStageSchema = z.enum(["preview", "published"]);
|
|
39594
|
+
const registrationButtonVariantSchema = blockButtonRoleSchema;
|
|
39595
|
+
const eventButtonVariantSchema = blockButtonRoleSchema;
|
|
39596
|
+
const eventLayoutSchema = z.enum(eventCalendarListLayoutValues);
|
|
39597
|
+
const eventCalendarDisplayModeSchema = z.enum(eventCalendarDisplayModeValues);
|
|
39598
|
+
const eventCalendarDefaultViewSchema = z.enum(eventCalendarDefaultViewValues);
|
|
39599
|
+
const columnOptionSchema = z.enum([
|
|
39600
|
+
"2",
|
|
39601
|
+
"3",
|
|
39602
|
+
"4"
|
|
39603
|
+
]);
|
|
39604
|
+
const weekStartSchema = z.enum(["sunday", "monday"]);
|
|
39605
|
+
const filterAutoShowSchema = z.enum([
|
|
39606
|
+
"auto",
|
|
39607
|
+
"always",
|
|
39608
|
+
"never"
|
|
39609
|
+
]);
|
|
39610
|
+
const calendarTabViewsSchema = z.enum([
|
|
39611
|
+
"both",
|
|
39612
|
+
"month",
|
|
39613
|
+
"week"
|
|
39614
|
+
]);
|
|
39615
|
+
//#endregion
|
|
38625
39616
|
//#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
|
|
38626
39617
|
const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
|
|
38627
39618
|
const eventRecoveryRequestSchema = z.object({
|
|
@@ -38664,27 +39655,17 @@ function parseEventLoaderRecoveryRequest(value) {
|
|
|
38664
39655
|
const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
|
|
38665
39656
|
"Date",
|
|
38666
39657
|
"Tickets",
|
|
38667
|
-
"
|
|
38668
|
-
];
|
|
38669
|
-
const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
|
|
38670
|
-
"Event",
|
|
38671
|
-
"Date",
|
|
38672
|
-
"Tickets",
|
|
38673
|
-
"Details",
|
|
38674
|
-
"Payment options",
|
|
38675
|
-
"Payment"
|
|
39658
|
+
"Your details"
|
|
38676
39659
|
];
|
|
38677
39660
|
const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
|
|
38678
|
-
const
|
|
39661
|
+
const eventRegistrationCommonSchemaShape = {
|
|
38679
39662
|
demoEmailSuppressed: z.boolean().optional(),
|
|
38680
39663
|
occurrenceContext: occurrenceContextSchema.optional(),
|
|
38681
39664
|
subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
|
|
38682
39665
|
maxTickets: z.string().optional(),
|
|
38683
|
-
showVenue: z.boolean().optional(),
|
|
38684
|
-
showCapacity: z.boolean().optional(),
|
|
38685
39666
|
successMessage: z.string().optional(),
|
|
38686
39667
|
buttonVariant: registrationButtonVariantSchema.optional(),
|
|
38687
|
-
|
|
39668
|
+
host: bookingHostSchema.optional(),
|
|
38688
39669
|
spamProtectionEnabled: z.boolean().optional(),
|
|
38689
39670
|
supportEmail: z.string().optional(),
|
|
38690
39671
|
sitePasses: publicPassProductCollectionSchema.nullable().optional(),
|
|
@@ -38709,32 +39690,51 @@ const eventRegistrationSourceSchema = z.object({
|
|
|
38709
39690
|
portalToken: z.string().nullable().optional(),
|
|
38710
39691
|
previewToken: z.string().nullable().optional(),
|
|
38711
39692
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
38712
|
-
...
|
|
39693
|
+
...eventRegistrationCommonSchemaShape,
|
|
39694
|
+
showVenue: z.boolean().optional(),
|
|
39695
|
+
showCapacity: z.boolean().optional(),
|
|
38713
39696
|
events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
38714
39697
|
wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
|
|
38715
39698
|
eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
38716
39699
|
className: z.string().nullable().optional(),
|
|
38717
39700
|
buttonText: z.string().nullable().optional(),
|
|
38718
39701
|
maxTickets: z.string().nullable().optional(),
|
|
38719
|
-
stage: previewStageSchema.optional()
|
|
39702
|
+
stage: previewStageSchema.optional(),
|
|
39703
|
+
bookingOfferingPresets: z.array(z.custom((value) => typeof value === "object" && value !== null && typeof value.label === "string")).nullable().optional()
|
|
38720
39704
|
});
|
|
38721
|
-
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
38722
|
-
|
|
38723
|
-
|
|
38724
|
-
|
|
38725
|
-
|
|
38726
|
-
|
|
38727
|
-
|
|
38728
|
-
|
|
38729
|
-
|
|
38730
|
-
|
|
38731
|
-
|
|
38732
|
-
|
|
38733
|
-
|
|
38734
|
-
|
|
38735
|
-
|
|
39705
|
+
const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [
|
|
39706
|
+
z.object({
|
|
39707
|
+
kind: z.literal("event-registration"),
|
|
39708
|
+
state: z.literal("generic-shell"),
|
|
39709
|
+
className: z.string().nullable(),
|
|
39710
|
+
titleText: z.string(),
|
|
39711
|
+
bodyText: z.string(),
|
|
39712
|
+
stepLabels: z.array(z.enum(REGISTRATION_STEP_LABELS)).min(1),
|
|
39713
|
+
summaryButtonText: z.string()
|
|
39714
|
+
}),
|
|
39715
|
+
z.object({
|
|
39716
|
+
kind: z.literal("event-registration"),
|
|
39717
|
+
state: z.literal("registration-closed"),
|
|
39718
|
+
className: z.string().nullable(),
|
|
39719
|
+
titleText: z.string(),
|
|
39720
|
+
bodyText: z.string()
|
|
39721
|
+
}),
|
|
39722
|
+
z.object({
|
|
39723
|
+
kind: z.literal("event-registration"),
|
|
39724
|
+
state: z.literal("booking-card"),
|
|
39725
|
+
className: z.string().nullable(),
|
|
39726
|
+
entry: idleBookingEntrySchema,
|
|
39727
|
+
buttonVariant: registrationButtonVariantSchema.nullable(),
|
|
39728
|
+
buttonText: z.string()
|
|
39729
|
+
})
|
|
39730
|
+
]);
|
|
38736
39731
|
const eventRegistrationHydrationSchema = z.object({
|
|
38737
|
-
...
|
|
39732
|
+
...eventRegistrationCommonSchemaShape,
|
|
39733
|
+
display: registrationDisplaySchema,
|
|
39734
|
+
offeringNoun: z.object({
|
|
39735
|
+
label: z.string(),
|
|
39736
|
+
pluralLabel: z.string()
|
|
39737
|
+
}).optional(),
|
|
38738
39738
|
eventSource: eventRegistrationEventSourceSchema
|
|
38739
39739
|
});
|
|
38740
39740
|
const eventRegistrationRenderSchema = z.object({
|
|
@@ -38749,7 +39749,7 @@ z.object({
|
|
|
38749
39749
|
readAuthority: browserReadAuthoritySchema.optional(),
|
|
38750
39750
|
stage: previewStageSchema.optional()
|
|
38751
39751
|
});
|
|
38752
|
-
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
39752
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display) {
|
|
38753
39753
|
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
38754
39754
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
38755
39755
|
kind: "event-registration",
|
|
@@ -38758,6 +39758,8 @@ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvent
|
|
|
38758
39758
|
titleText: "Registration closed",
|
|
38759
39759
|
bodyText: "This run is no longer open for bookings."
|
|
38760
39760
|
};
|
|
39761
|
+
const card = bookingCardDisplay(source, scopedSourceEvents, display);
|
|
39762
|
+
if (card) return card;
|
|
38761
39763
|
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
38762
39764
|
return {
|
|
38763
39765
|
kind: "event-registration",
|
|
@@ -38774,11 +39776,14 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
38774
39776
|
if (selectedRun) {
|
|
38775
39777
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
38776
39778
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
38777
|
-
return
|
|
38778
|
-
|
|
38779
|
-
|
|
38780
|
-
|
|
38781
|
-
|
|
39779
|
+
return shellStepLabels(registrationRoute({
|
|
39780
|
+
chooseEvent: false,
|
|
39781
|
+
payment: resolveEventRequiresPayment({
|
|
39782
|
+
eligibility: null,
|
|
39783
|
+
selectedTicketType: null,
|
|
39784
|
+
event: selectedEvent
|
|
39785
|
+
}) ? "optionsAndPayment" : "none"
|
|
39786
|
+
}), registrationStepLabelContext([selectedEvent], selectedEvent));
|
|
38782
39787
|
}
|
|
38783
39788
|
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
38784
39789
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -38787,14 +39792,15 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
|
38787
39792
|
occurrenceContext: source.occurrenceContext
|
|
38788
39793
|
});
|
|
38789
39794
|
const hasPreSelectedContext = Boolean(source.occurrenceContext || preSelectedEvent);
|
|
38790
|
-
|
|
39795
|
+
const needsPaymentStep = hasPreSelectedContext && preSelectedEvent ? resolveEventRequiresPayment({
|
|
38791
39796
|
eligibility: null,
|
|
38792
39797
|
selectedTicketType: null,
|
|
38793
39798
|
event: preSelectedEvent
|
|
38794
|
-
}) : false
|
|
38795
|
-
|
|
38796
|
-
|
|
38797
|
-
|
|
39799
|
+
}) : false;
|
|
39800
|
+
return shellStepLabels(registrationRoute({
|
|
39801
|
+
chooseEvent: !hasPreSelectedContext,
|
|
39802
|
+
payment: needsPaymentStep ? "optionsAndPayment" : "none"
|
|
39803
|
+
}), registrationStepLabelContext(scopedEvents, preSelectedEvent));
|
|
38798
39804
|
}
|
|
38799
39805
|
function scopeEventRegistrationSourceEvents(source, eventSource) {
|
|
38800
39806
|
return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
|
|
@@ -38810,29 +39816,12 @@ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
|
38810
39816
|
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
38811
39817
|
return runs.length === 1 ? runs[0] : null;
|
|
38812
39818
|
}
|
|
38813
|
-
function
|
|
38814
|
-
|
|
38815
|
-
case "select-event": return isDateSelection(events) ? "Date" : "Event";
|
|
38816
|
-
case "select-tickets": return "Tickets";
|
|
38817
|
-
case "enter-details": return "Details";
|
|
38818
|
-
case "select-payment": return "Payment options";
|
|
38819
|
-
case "payment": return "Payment";
|
|
38820
|
-
case "error":
|
|
38821
|
-
case "success":
|
|
38822
|
-
case "submitting":
|
|
38823
|
-
case "verifying-payment":
|
|
38824
|
-
case "verifying-timeout":
|
|
38825
|
-
case "payment-status":
|
|
38826
|
-
case "payment-failed": return "Details";
|
|
38827
|
-
}
|
|
38828
|
-
}
|
|
38829
|
-
function isDateSelection(events) {
|
|
38830
|
-
const firstSeriesId = events[0]?.seriesId;
|
|
38831
|
-
return Boolean(events.length > 1 && firstSeriesId && events.every((event) => event.seriesId === firstSeriesId));
|
|
39819
|
+
function shellStepLabels(route, context) {
|
|
39820
|
+
return route.map((step) => registrationStepLabel(step, context));
|
|
38832
39821
|
}
|
|
38833
39822
|
function buildEventRegistrationShellBodyText(stepLabels) {
|
|
38834
|
-
if (stepLabels.includes("
|
|
38835
|
-
if (stepLabels[0] === "Tickets") return "Preparing tickets and booking details.";
|
|
39823
|
+
if (stepLabels.includes("How you’ll pay")) return "Preparing tickets, details, and payment options.";
|
|
39824
|
+
if (stepLabels[0] === "Tickets" || stepLabels[0] === "Places") return "Preparing tickets and booking details.";
|
|
38836
39825
|
return "Preparing dates, tickets, and booking details.";
|
|
38837
39826
|
}
|
|
38838
39827
|
const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
@@ -38842,6 +39831,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
38842
39831
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
38843
39832
|
},
|
|
38844
39833
|
buildRender: (source) => {
|
|
39834
|
+
const display = resolveRegistrationDisplay(source);
|
|
38845
39835
|
const eventSource = resolveEventRegistrationEventSource({
|
|
38846
39836
|
events: source.events,
|
|
38847
39837
|
wholeSeriesRunEvents: source.wholeSeriesRunEvents,
|
|
@@ -38849,7 +39839,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
38849
39839
|
});
|
|
38850
39840
|
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
|
|
38851
39841
|
return {
|
|
38852
|
-
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
39842
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents, display),
|
|
38853
39843
|
hydration: {
|
|
38854
39844
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
38855
39845
|
subject: source.subject ?? null,
|
|
@@ -38859,29 +39849,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
38859
39849
|
} : eventSource,
|
|
38860
39850
|
demoEmailSuppressed: source.demoEmailSuppressed,
|
|
38861
39851
|
maxTickets: source.maxTickets ?? void 0,
|
|
38862
|
-
|
|
38863
|
-
showCapacity: source.showCapacity,
|
|
39852
|
+
display,
|
|
38864
39853
|
successMessage: source.successMessage,
|
|
38865
39854
|
buttonVariant: source.buttonVariant,
|
|
38866
|
-
|
|
39855
|
+
host: source.host ?? "overlay",
|
|
38867
39856
|
spamProtectionEnabled: source.spamProtectionEnabled,
|
|
38868
39857
|
supportEmail: source.supportEmail,
|
|
38869
39858
|
sitePasses: source.sitePasses ?? null,
|
|
38870
39859
|
siteMemberships: source.siteMemberships ?? null,
|
|
38871
39860
|
mailingList: source.mailingList,
|
|
38872
|
-
siteName: source.siteName
|
|
39861
|
+
siteName: source.siteName,
|
|
39862
|
+
offeringNoun: resolveOfferingNoun(source, scopedSourceEvents)
|
|
38873
39863
|
}
|
|
38874
39864
|
};
|
|
38875
39865
|
}
|
|
38876
39866
|
});
|
|
38877
39867
|
function normalizeEventRegistrationEventInput(value) {
|
|
38878
|
-
if (!isRecord$
|
|
39868
|
+
if (!isRecord$5(value)) return value;
|
|
38879
39869
|
return {
|
|
38880
39870
|
...value,
|
|
38881
39871
|
destination: resolveRuntimeEventDestination(value)
|
|
38882
39872
|
};
|
|
38883
39873
|
}
|
|
38884
|
-
function isRecord$
|
|
39874
|
+
function isRecord$5(value) {
|
|
38885
39875
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38886
39876
|
}
|
|
38887
39877
|
const eventRegistrationBlockDefinition = {
|
|
@@ -38921,7 +39911,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
38921
39911
|
description: "Main heading for the registration form",
|
|
38922
39912
|
required: false,
|
|
38923
39913
|
multiline: false,
|
|
38924
|
-
defaultValue: "
|
|
39914
|
+
defaultValue: ""
|
|
38925
39915
|
},
|
|
38926
39916
|
{
|
|
38927
39917
|
id: "description",
|
|
@@ -38993,11 +39983,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
38993
39983
|
{
|
|
38994
39984
|
id: "buttonText",
|
|
38995
39985
|
type: "text",
|
|
38996
|
-
label: "
|
|
38997
|
-
description: "Text
|
|
39986
|
+
label: "Button text",
|
|
39987
|
+
description: "Text on the booking button",
|
|
38998
39988
|
required: false,
|
|
38999
39989
|
multiline: false,
|
|
39000
|
-
defaultValue: "
|
|
39990
|
+
defaultValue: "Book your place",
|
|
39001
39991
|
maxLength: 40
|
|
39002
39992
|
},
|
|
39003
39993
|
createButtonVariantField()
|
|
@@ -39029,21 +40019,21 @@ const eventRegistrationBlockDefinition = {
|
|
|
39029
40019
|
successMessage: { $bind: { from: "content.successMessage" } },
|
|
39030
40020
|
buttonText: { $bind: {
|
|
39031
40021
|
from: "content.buttonText",
|
|
39032
|
-
fallback: "
|
|
40022
|
+
fallback: "Book your place"
|
|
39033
40023
|
} },
|
|
39034
40024
|
buttonVariant: { $bind: {
|
|
39035
40025
|
from: "content.buttonVariant",
|
|
39036
40026
|
fallback: "primary"
|
|
39037
40027
|
} },
|
|
39038
|
-
overlayEnabled: { $bind: {
|
|
39039
|
-
from: "$root.eventRegistrationOverlayEnabled",
|
|
39040
|
-
fallback: false
|
|
39041
|
-
} },
|
|
39042
40028
|
events: { $bind: { from: "data.events" } },
|
|
39043
40029
|
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
39044
40030
|
loaderFailures: { $bind: { from: "$root.loaderFailures" } },
|
|
39045
40031
|
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
39046
40032
|
siteName: { $bind: { from: "$root.siteName" } },
|
|
40033
|
+
bookingOfferingPresets: { $bind: {
|
|
40034
|
+
from: "$root.bookingOfferingPresets",
|
|
40035
|
+
fallback: []
|
|
40036
|
+
} },
|
|
39047
40037
|
sitePasses: { $bind: { from: "data.sitePasses" } },
|
|
39048
40038
|
siteMemberships: { $bind: { from: "data.siteMemberships" } },
|
|
39049
40039
|
stage: { $bind: {
|
|
@@ -41613,7 +42603,21 @@ const eventCalendarBlockDefinition = {
|
|
|
41613
42603
|
list: { label: "List" }
|
|
41614
42604
|
}
|
|
41615
42605
|
}, eventCalendarContentShape),
|
|
41616
|
-
|
|
42606
|
+
contentNormalizer: {
|
|
42607
|
+
fieldIds: [
|
|
42608
|
+
"variant",
|
|
42609
|
+
"displayMode",
|
|
42610
|
+
"listLayout",
|
|
42611
|
+
"defaultCalendarView",
|
|
42612
|
+
"eventSurface",
|
|
42613
|
+
"filterEventPresets",
|
|
42614
|
+
"scheduleScope",
|
|
42615
|
+
"filterCategoryIds",
|
|
42616
|
+
"filterStaffMemberId",
|
|
42617
|
+
"filterVenueId"
|
|
42618
|
+
],
|
|
42619
|
+
normalize: normalizeEventCalendarContent
|
|
42620
|
+
},
|
|
41617
42621
|
dataSchemas: {
|
|
41618
42622
|
events: publicEventsArraySchema.optional(),
|
|
41619
42623
|
calendarWindow: calendarWindowPageSchema.optional()
|
|
@@ -42086,90 +43090,6 @@ const recurringScheduleBlockDefinition = {
|
|
|
42086
43090
|
} }
|
|
42087
43091
|
};
|
|
42088
43092
|
//#endregion
|
|
42089
|
-
//#region ../blocks/src/system/blocks/offerings-preview/model.ts
|
|
42090
|
-
const OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT = "Book";
|
|
42091
|
-
const OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE = "Nothing scheduled just yet.";
|
|
42092
|
-
const OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS = [
|
|
42093
|
-
{
|
|
42094
|
-
preset: "class",
|
|
42095
|
-
sourceKey: "eventPreset:class",
|
|
42096
|
-
dataKey: "classEvents",
|
|
42097
|
-
label: "Classes"
|
|
42098
|
-
},
|
|
42099
|
-
{
|
|
42100
|
-
preset: "workshop",
|
|
42101
|
-
sourceKey: "eventPreset:workshop",
|
|
42102
|
-
dataKey: "workshopEvents",
|
|
42103
|
-
label: "Workshops"
|
|
42104
|
-
},
|
|
42105
|
-
{
|
|
42106
|
-
preset: "retreat",
|
|
42107
|
-
sourceKey: "eventPreset:retreat",
|
|
42108
|
-
dataKey: "retreatEvents",
|
|
42109
|
-
label: "Retreats"
|
|
42110
|
-
},
|
|
42111
|
-
{
|
|
42112
|
-
preset: "performance",
|
|
42113
|
-
sourceKey: "eventPreset:performance",
|
|
42114
|
-
dataKey: "performanceEvents",
|
|
42115
|
-
label: "Performances"
|
|
42116
|
-
}
|
|
42117
|
-
];
|
|
42118
|
-
OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.preset);
|
|
42119
|
-
const OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS = [...OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => definition.sourceKey), "course"];
|
|
42120
|
-
const OFFERINGS_PREVIEW_SOURCE_KEYS = OFFERINGS_PREVIEW_AUTHORABLE_SOURCE_KEYS;
|
|
42121
|
-
Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.sourceKey, {
|
|
42122
|
-
kind: "eventPreset",
|
|
42123
|
-
preset: definition.preset
|
|
42124
|
-
}]));
|
|
42125
|
-
function isOfferingsPreviewSourceKey(value) {
|
|
42126
|
-
return typeof value === "string" && OFFERINGS_PREVIEW_SOURCE_KEYS.includes(value);
|
|
42127
|
-
}
|
|
42128
|
-
function normalizeOfferingsPreviewGroupOrder(value) {
|
|
42129
|
-
if (value == null) return { kind: "legacy" };
|
|
42130
|
-
if (value.length === 0) return { kind: "default" };
|
|
42131
|
-
const keys = uniqueOfferingsPreviewSourceKeys(value);
|
|
42132
|
-
return keys.length > 0 ? {
|
|
42133
|
-
kind: "custom",
|
|
42134
|
-
keys
|
|
42135
|
-
} : { kind: "default" };
|
|
42136
|
-
}
|
|
42137
|
-
function inferLegacyOfferingsPreviewGroupOrder(overrides) {
|
|
42138
|
-
const keys = uniqueOfferingsPreviewSourceKeys((overrides ?? []).map((override) => override.sourceKey));
|
|
42139
|
-
return keys.length >= 2 ? keys : [];
|
|
42140
|
-
}
|
|
42141
|
-
function normalizeOfferingsPreviewContentForWrite(value) {
|
|
42142
|
-
if (!isRecord$5(value)) return null;
|
|
42143
|
-
const groupOrderValue = value.groupOrder;
|
|
42144
|
-
if (Array.isArray(groupOrderValue)) {
|
|
42145
|
-
const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
|
|
42146
|
-
return {
|
|
42147
|
-
...value,
|
|
42148
|
-
groupOrder: normalized.kind === "custom" ? normalized.keys : []
|
|
42149
|
-
};
|
|
42150
|
-
}
|
|
42151
|
-
if (groupOrderValue != null) return {
|
|
42152
|
-
...value,
|
|
42153
|
-
groupOrder: []
|
|
42154
|
-
};
|
|
42155
|
-
const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$5) : []);
|
|
42156
|
-
return legacyOrder.length > 0 ? {
|
|
42157
|
-
...value,
|
|
42158
|
-
groupOrder: legacyOrder
|
|
42159
|
-
} : value;
|
|
42160
|
-
}
|
|
42161
|
-
function uniqueOfferingsPreviewSourceKeys(values) {
|
|
42162
|
-
const keys = [];
|
|
42163
|
-
for (const value of values) {
|
|
42164
|
-
if (!isOfferingsPreviewSourceKey(value)) continue;
|
|
42165
|
-
if (!keys.includes(value)) keys.push(value);
|
|
42166
|
-
}
|
|
42167
|
-
return keys;
|
|
42168
|
-
}
|
|
42169
|
-
function isRecord$5(value) {
|
|
42170
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
42171
|
-
}
|
|
42172
|
-
//#endregion
|
|
42173
43093
|
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
42174
43094
|
const groupOverrideFields = [
|
|
42175
43095
|
{
|
|
@@ -42533,7 +43453,22 @@ const offeringsPreviewEventDataSchemas = Object.fromEntries(OFFERINGS_PREVIEW_EV
|
|
|
42533
43453
|
const offeringsPreviewEventDataLoaders = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, eventPresetLoader(definition.preset)]));
|
|
42534
43454
|
const offeringsPreviewBlockDefinition = {
|
|
42535
43455
|
manifest: offeringsPreviewManifest,
|
|
42536
|
-
|
|
43456
|
+
contentNormalizer: {
|
|
43457
|
+
fieldIds: [
|
|
43458
|
+
"displayMode",
|
|
43459
|
+
"heading",
|
|
43460
|
+
"description",
|
|
43461
|
+
"itemLimit",
|
|
43462
|
+
"groupOrder",
|
|
43463
|
+
"groupOverrides",
|
|
43464
|
+
"_cardStyles",
|
|
43465
|
+
"buttonVariant",
|
|
43466
|
+
"buttonText",
|
|
43467
|
+
"emptyMessage",
|
|
43468
|
+
"_sectionStyles"
|
|
43469
|
+
],
|
|
43470
|
+
normalize: normalizeOfferingsPreviewBlockContent
|
|
43471
|
+
},
|
|
42537
43472
|
dataSchemas: {
|
|
42538
43473
|
...offeringsPreviewEventDataSchemas,
|
|
42539
43474
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
@@ -46131,11 +47066,11 @@ function buildNewsletterDisplay(source) {
|
|
|
46131
47066
|
successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
|
|
46132
47067
|
privacyNote: null
|
|
46133
47068
|
};
|
|
46134
|
-
const
|
|
46135
|
-
const choices = resolveRuntimeChoices(
|
|
47069
|
+
const assessment = assessMailingListTargeting(context, source.targeting ?? { mode: "default" });
|
|
47070
|
+
const choices = resolveRuntimeChoices(assessment);
|
|
46136
47071
|
return {
|
|
46137
47072
|
kind: "newsletter-form",
|
|
46138
|
-
availability:
|
|
47073
|
+
availability: assessment.tag === "available" ? "ready" : "unavailable",
|
|
46139
47074
|
className: source.className ?? null,
|
|
46140
47075
|
buttonLabel: form.buttonLabel,
|
|
46141
47076
|
successMessage: form.successMessage,
|
|
@@ -46192,60 +47127,12 @@ function projectNewsletterFormHydrationTarget(source) {
|
|
|
46192
47127
|
default: return assertNever$3(source);
|
|
46193
47128
|
}
|
|
46194
47129
|
}
|
|
46195
|
-
function resolveRuntimeChoices(
|
|
46196
|
-
if (
|
|
46197
|
-
|
|
46198
|
-
|
|
46199
|
-
|
|
46200
|
-
|
|
46201
|
-
id: item.id,
|
|
46202
|
-
label: item.name
|
|
46203
|
-
})) : [];
|
|
46204
|
-
}
|
|
46205
|
-
case "brevo": {
|
|
46206
|
-
const offered = new Set(targeting.selection.offeredListIds);
|
|
46207
|
-
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
46208
|
-
id: String(item.id),
|
|
46209
|
-
label: item.name
|
|
46210
|
-
})) : [];
|
|
46211
|
-
}
|
|
46212
|
-
case "mailchimp": {
|
|
46213
|
-
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
46214
|
-
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) => ({
|
|
46215
|
-
id: item.id,
|
|
46216
|
-
label: item.name
|
|
46217
|
-
})) ?? [];
|
|
46218
|
-
}
|
|
46219
|
-
}
|
|
46220
|
-
}
|
|
46221
|
-
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
46222
|
-
if (context?.tag !== "configured") return false;
|
|
46223
|
-
const provider = context.provider;
|
|
46224
|
-
if (targeting.mode === "default") switch (provider.provider) {
|
|
46225
|
-
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
46226
|
-
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
46227
|
-
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
46228
|
-
}
|
|
46229
|
-
if (targeting.provider !== provider.provider) return false;
|
|
46230
|
-
switch (targeting.provider) {
|
|
46231
|
-
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
46232
|
-
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
46233
|
-
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
46234
|
-
}
|
|
46235
|
-
}
|
|
46236
|
-
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
46237
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
46238
|
-
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
46239
|
-
}
|
|
46240
|
-
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
46241
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
46242
|
-
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
46243
|
-
}
|
|
46244
|
-
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
46245
|
-
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
46246
|
-
if (!audience) return false;
|
|
46247
|
-
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
46248
|
-
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
47130
|
+
function resolveRuntimeChoices(assessment) {
|
|
47131
|
+
if (!("value" in assessment) || assessment.value.mode !== "custom" || !("selectedChoices" in assessment.value) || assessment.value.targeting.selection.tag !== "visitor_choice") return [];
|
|
47132
|
+
return assessment.value.selectedChoices.map((item) => ({
|
|
47133
|
+
id: String(item.id),
|
|
47134
|
+
label: item.name
|
|
47135
|
+
}));
|
|
46249
47136
|
}
|
|
46250
47137
|
function parseRequiredMailingListSignupBlockId(value) {
|
|
46251
47138
|
const parsed = parseMailingListBlockId(value);
|
|
@@ -46354,6 +47241,10 @@ function sanitizeNewsletterSignupPublicContent(content) {
|
|
|
46354
47241
|
}
|
|
46355
47242
|
const newsletterSignupBlockDefinition = {
|
|
46356
47243
|
manifest: newsletterSignupManifest,
|
|
47244
|
+
contentNormalizer: {
|
|
47245
|
+
fieldIds: ["targeting"],
|
|
47246
|
+
normalize: normalizeMailingListBlockContent
|
|
47247
|
+
},
|
|
46357
47248
|
runtime: newsletterFormBlockRuntime
|
|
46358
47249
|
};
|
|
46359
47250
|
//#endregion
|
|
@@ -47086,7 +47977,20 @@ const locationMapBlockDefinition = {
|
|
|
47086
47977
|
})], { gap: "md" })
|
|
47087
47978
|
})
|
|
47088
47979
|
}),
|
|
47089
|
-
|
|
47980
|
+
contentNormalizer: {
|
|
47981
|
+
fieldIds: [
|
|
47982
|
+
"heading",
|
|
47983
|
+
"locationSource",
|
|
47984
|
+
"venueId",
|
|
47985
|
+
"location",
|
|
47986
|
+
"showAddressText",
|
|
47987
|
+
"showDirections",
|
|
47988
|
+
"directionsLabel",
|
|
47989
|
+
"zoom",
|
|
47990
|
+
"heightPx"
|
|
47991
|
+
],
|
|
47992
|
+
normalize: normalizeLocationMapContent
|
|
47993
|
+
}
|
|
47090
47994
|
};
|
|
47091
47995
|
//#endregion
|
|
47092
47996
|
//#region ../blocks/src/system/blocks/index.ts
|
|
@@ -48291,17 +49195,7 @@ const linksTransforms = [{
|
|
|
48291
49195
|
id: "links.resolve",
|
|
48292
49196
|
kind: "formatter",
|
|
48293
49197
|
summary: "Resolve LinkValue objects to href strings using the route map",
|
|
48294
|
-
run: (value, _options, context) =>
|
|
48295
|
-
if (!value || typeof value !== "object") return null;
|
|
48296
|
-
const link = value;
|
|
48297
|
-
const kind = typeof link.kind === "string" ? link.kind : null;
|
|
48298
|
-
if (kind === "internal") return resolveInternalLink(link, context);
|
|
48299
|
-
if (kind === "page") return resolvePageLink(link, context);
|
|
48300
|
-
if (kind === "entry") return resolveEntryLink(link, context);
|
|
48301
|
-
if (kind === "external" || kind === "url") return resolveExternalLink(link);
|
|
48302
|
-
if (!kind && typeof link.href === "string") return resolveExternalLink(link);
|
|
48303
|
-
return null;
|
|
48304
|
-
}
|
|
49198
|
+
run: (value, _options, context) => resolveAuthoredLinkHref(value, context)
|
|
48305
49199
|
}, {
|
|
48306
49200
|
id: "links.label",
|
|
48307
49201
|
kind: "formatter",
|
|
@@ -48328,6 +49222,21 @@ const linksTransforms = [{
|
|
|
48328
49222
|
return null;
|
|
48329
49223
|
}
|
|
48330
49224
|
}];
|
|
49225
|
+
function resolveAuthoredLinkHref(value, context = {}) {
|
|
49226
|
+
if (!value || typeof value !== "object") return null;
|
|
49227
|
+
const link = value;
|
|
49228
|
+
switch (link.kind) {
|
|
49229
|
+
case "internal": return resolveInternalLink(link, context);
|
|
49230
|
+
case "page": return resolvePageLink(link, context);
|
|
49231
|
+
case "entry": return resolveEntryLink(link, context);
|
|
49232
|
+
case "external":
|
|
49233
|
+
case "url": return resolveExternalLink(link);
|
|
49234
|
+
default: return resolvePreResolvedLink(link);
|
|
49235
|
+
}
|
|
49236
|
+
}
|
|
49237
|
+
function resolvePreResolvedLink(link) {
|
|
49238
|
+
return !(typeof link.kind === "string" ? link.kind : null) && typeof link.href === "string" ? resolveExternalLink(link) : null;
|
|
49239
|
+
}
|
|
48331
49240
|
const eventCalendarSelectionParam = {
|
|
48332
49241
|
id: "events.calendarSelectionParam",
|
|
48333
49242
|
kind: "formatter",
|