@riverbankcms/sdk 0.135.1 → 0.137.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.
Files changed (220) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +4 -8
  3. package/dist/{PreviewEditorSidebar-D4p_5TdY.mjs → PreviewEditorSidebar-Bn6cONPa.mjs} +8 -8
  4. package/dist/{PreviewEditorUI-D0cRoTX1.mjs → PreviewEditorUI-LAwXZPSx.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-DcgaESkm.mjs → PreviewQueryProvider-ztQUdsNo.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-BKLtM3Nz.mjs → SdkPreviewModeRuntime-BbbGsI_v.mjs} +621 -238
  7. package/dist/{SiteChromeCustomizeContext-61X2m7QV.mjs → SiteChromeCustomizeContext-BbkNSt5a.mjs} +5041 -2407
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +18 -850
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +412 -2316
  10. package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
  11. package/dist/_dts/api/src/accessAdmin.d.ts +1 -9
  12. package/dist/_dts/api/src/accountApi.d.ts +49 -2
  13. package/dist/_dts/api/src/contentRuntime.d.ts +7 -4
  14. package/dist/_dts/api/src/domainConnection.d.ts +41 -0
  15. package/dist/_dts/api/src/endpoints.d.ts +201 -181
  16. package/dist/_dts/api/src/index.d.ts +5 -3
  17. package/dist/_dts/api/src/media.d.ts +19 -2
  18. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  19. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +26 -0
  20. package/dist/_dts/api/src/sdkBlockContentAdmission.d.ts +5 -0
  21. package/dist/_dts/api/src/sdkContracts.d.ts +2 -15
  22. package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
  23. package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +61 -0
  24. package/dist/_dts/api/src/sdkThemeWire.d.ts +21 -436
  25. package/dist/_dts/api/src/siteInfrastructure.d.ts +17 -23
  26. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +7 -21
  27. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +27 -3
  28. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
  29. package/dist/_dts/api/src/types.d.ts +1 -1
  30. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +2 -3
  31. package/dist/_dts/block-form/src/utils/slug.d.ts +6 -0
  32. package/dist/_dts/blocks/src/PageRenderer.d.ts +13 -7
  33. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +48 -0
  34. package/dist/_dts/blocks/src/definitions.d.ts +14 -0
  35. package/dist/_dts/blocks/src/index.d.ts +4 -3
  36. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +49 -0
  37. package/dist/_dts/blocks/src/pageRendererBlockSupport.d.ts +75 -0
  38. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +2 -0
  39. package/dist/_dts/blocks/src/server.d.ts +2 -2
  40. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -1
  41. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  42. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +78 -0
  43. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +2 -18
  44. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +103 -16
  45. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  46. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +4 -2
  47. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  48. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  49. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +19 -0
  50. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +52 -0
  51. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  52. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +47 -21
  53. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +38 -9
  54. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
  55. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +3 -1
  56. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -0
  57. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
  58. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
  59. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
  60. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
  61. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
  62. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +8 -3
  63. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -0
  64. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +5 -2
  65. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
  66. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.client.d.ts +2 -2
  67. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +40 -0
  68. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  69. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +43 -0
  70. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
  71. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
  72. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
  73. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
  74. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
  75. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +31 -0
  76. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +3 -1
  77. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.d.ts +4 -0
  78. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  79. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalContext.d.ts +3 -2
  80. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
  81. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +4 -1
  82. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +31 -3
  83. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +3 -1
  84. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +9 -1
  85. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
  86. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
  87. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +4 -3
  88. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -1
  89. package/dist/_dts/calendar/src/grid.d.ts +24 -66
  90. package/dist/_dts/calendar/src/index.d.ts +2 -2
  91. package/dist/_dts/calendar/src/timetable.d.ts +5 -9
  92. package/dist/_dts/commerce/src/purchase/allocation.d.ts +11 -0
  93. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
  94. package/dist/_dts/commerce/src/purchase/index.d.ts +3 -0
  95. package/dist/_dts/commerce/src/purchase/settlement.d.ts +33 -0
  96. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +8 -0
  97. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -0
  98. package/dist/_dts/core/src/slug.d.ts +20 -5
  99. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +8 -40
  100. package/dist/_dts/db/src/index.d.ts +1 -0
  101. package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
  102. package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
  103. package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
  104. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +1 -1
  105. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
  106. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  107. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
  108. package/dist/_dts/preview-next/src/client/preview/headerInteractionPaletteSurfaceState.d.ts +2 -1
  109. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
  110. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
  111. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
  112. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
  113. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
  114. package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
  115. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +6 -0
  116. package/dist/_dts/sdk/src/public-api/contracts.d.ts +7 -2
  117. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +10 -6
  118. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +0 -1
  119. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  120. package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +3 -0
  121. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -0
  122. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  123. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +17 -0
  124. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +9 -3
  125. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +1 -1
  126. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  127. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +7 -4
  128. package/dist/_dts/sdk/src/version.d.ts +1 -1
  129. package/dist/_dts/theme-core/src/cards/types.d.ts +8 -8
  130. package/dist/_dts/theme-core/src/data.d.ts +12 -0
  131. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  132. package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
  133. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +25 -2
  134. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -6
  135. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +9 -810
  136. package/dist/_dts/theme-core/src/schema.d.ts +460 -1285
  137. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
  138. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +223 -1
  139. package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
  140. package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
  141. package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
  142. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -38
  143. package/dist/_dts/theme-core/src/site-styles/headerLayoutStyles.d.ts +10 -0
  144. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +8 -5
  145. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +4 -4
  146. package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
  147. package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
  148. package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
  149. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +25 -2
  150. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +465 -0
  151. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +168 -0
  152. package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
  153. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
  154. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
  155. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
  156. package/dist/client/{BookingConsentAgreement-Bz9znbpn.mjs → BookingConsentAgreement--_fUCZe-.mjs} +2 -2
  157. package/dist/client/{DiscountCodeDisclosure-35Ru8yB9.mjs → DiscountCodeDisclosure-BMipSoDJ.mjs} +1 -1
  158. package/dist/client/{EventCombined.client-BKB0ZxRR.mjs → EventCombined.client-CwJOxn7A.mjs} +274 -278
  159. package/dist/client/{EventListing.client-Dx8I21ok.mjs → EventListing.client-eVwiylPW.mjs} +2 -2
  160. package/dist/client/{LeafletStaticMap-CEWx-Bhe.mjs → LeafletStaticMap-IKenna5u.mjs} +1 -1
  161. package/dist/client/{accordion-KIDsKTwS.mjs → accordion-MGAO3PuE.mjs} +1 -1
  162. package/dist/client/{bookingForm-D96Rmp-5.mjs → bookingForm-CudlQPUu.mjs} +5 -5
  163. package/dist/client/bookings.mjs +476 -98
  164. package/dist/client/capacity-BW00PO7s.mjs +271 -0
  165. package/dist/client/{carousel-YwUgyL66.mjs → carousel-BrbGJ2Jl.mjs} +1 -1
  166. package/dist/client/{cart-BbwuNrUT.mjs → cart-Bq5eU0xZ.mjs} +3 -3
  167. package/dist/client/{checkout-hp1ucmEY.mjs → checkout-BAFVRdrK.mjs} +3 -3
  168. package/dist/client/client.mjs +4641 -2721
  169. package/dist/client/{context-DljQn8L5.mjs → context-DCkiHVdD.mjs} +20 -5
  170. package/dist/client/dates-2RPXHQy4.mjs +264 -0
  171. package/dist/client/{eventCalendar-DU4iNLpo.mjs → eventCalendar-B0O-hPF7.mjs} +261 -126
  172. package/dist/client/{eventCombined-CZuupW8m.mjs → eventCombined-DCkDaoDI.mjs} +3 -3
  173. package/dist/client/{eventDetails-DPQWwCIi.mjs → eventDetails-D8GG2dnD.mjs} +7 -4
  174. package/dist/client/{eventListing-C7oMidwS.mjs → eventListing-3ssV_bxz.mjs} +3 -3
  175. package/dist/client/{eventRegistration-zEiunlUs.mjs → eventRegistration-bPQo3kVw.mjs} +610 -313
  176. package/dist/client/{form-D2KIyCVJ.mjs → form-qMv8RDkk.mjs} +2 -2
  177. package/dist/client/{headerSection-CK5uChUK.mjs → headerSection-CH0Sc5hX.mjs} +2 -2
  178. package/dist/client/hooks.mjs +2514 -308
  179. package/dist/client/{locationMap-DLQNH1ln.mjs → locationMap-0_xlBnNI.mjs} +2 -2
  180. package/dist/client/{newsletterForm-ZuhIG7fZ.mjs → newsletterForm-NUW7m9RI.mjs} +2 -2
  181. package/dist/client/{productDetail-7hIcGeae.mjs → productDetail-FBEOM7jW.mjs} +3 -3
  182. package/dist/client/{productList-T4Cii1ot.mjs → productList-R0OSGhnn.mjs} +3 -3
  183. package/dist/client/{propsDecoder-mB0aC_Fi.mjs → propsDecoder-pYvx_Srl.mjs} +179 -401
  184. package/dist/client/rendering/client.mjs +3496 -2223
  185. package/dist/client/rendering/islands.mjs +17 -17
  186. package/dist/client/rendering.mjs +4400 -2510
  187. package/dist/client/{scrollToBlock-Du5mHgvL.mjs → scrollToBlock-ByQv96M2.mjs} +1 -1
  188. package/dist/client/{shop-B5zAcKZn.mjs → shop-RUG9DmRE.mjs} +6 -6
  189. package/dist/client/{shop-commerce-BKBZB6l5.mjs → shop-commerce-B76Jz23B.mjs} +5 -5
  190. package/dist/client/{shop-commerce-store-Cq4qlNtQ.mjs → shop-commerce-store-QuQNdDsD.mjs} +1 -1
  191. package/dist/client/{shopShared-DYGzEs9D.mjs → shopShared-vXU1omwJ.mjs} +3 -3
  192. package/dist/client/{useEventFilters-Bphkda8m.mjs → useEventFilters-ByuU6HLA.mjs} +33 -18
  193. package/dist/preview-next/before-render.mjs +86 -51
  194. package/dist/preview-next/client/runtime.mjs +4 -4
  195. package/dist/preview-next/keepAlive.mjs +86 -51
  196. package/dist/preview-next/middleware.mjs +86 -51
  197. package/dist/{previewAuthStore-C7ksxt5b.mjs → previewAuthStore-L_cKW8Sb.mjs} +86 -51
  198. package/dist/{sdk-runtime-BbIC8G4J.mjs → sdk-runtime-sUMr5d70.mjs} +2 -2
  199. package/dist/{separator-CadhAtI7.mjs → separator-BIHkie5i.mjs} +1 -1
  200. package/dist/server/components.mjs +4397 -2960
  201. package/dist/server/config-validation.mjs +354 -145
  202. package/dist/server/config.mjs +354 -145
  203. package/dist/server/data.mjs +354 -144
  204. package/dist/server/index.mjs +201 -55
  205. package/dist/server/manifest.mjs +0 -1
  206. package/dist/server/next.mjs +4046 -2611
  207. package/dist/server/page-converter.mjs +225 -122
  208. package/dist/server/prebuild.mjs +1 -1
  209. package/dist/server/rendering/server.mjs +4105 -2636
  210. package/dist/server/rendering.mjs +4522 -3087
  211. package/dist/server/routing.mjs +3289 -1637
  212. package/dist/server/server.mjs +23175 -21079
  213. package/dist/server/theme-bridge.mjs +708 -272
  214. package/dist/server/theme.mjs +29 -25
  215. package/dist/styles/index.css +624 -181
  216. package/package.json +1 -1
  217. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
  218. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
  219. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
  220. /package/dist/_dts/blocks/src/system/runtime/nodes/events/{shared → domain}/destination.d.ts +0 -0
@@ -1,11 +1,13 @@
1
1
  "use client";
2
2
  import { D as clsx } from "./colorStyles-CrxJrPjJ.mjs";
3
- import { At as assertNever, B as formatEventPrice, G as getContainerClass, H as formatEventTeacherLine, J as resolveEventLinkProps, K as groupEventsByDate, L as formatDate, M as buildEventRuntimeFilters, N as getEventRuntimeFiltersKey, U as formatTime, W as getCardOrientation, X as getEventAvailability, st as themeButtonClassName } from "./propsDecoder-mB0aC_Fi.mjs";
4
- import { a as EventCardClient, i as EventPaginatedListView, n as useEventPagination, o as EventFilters, r as toError, t as useEventFilters } from "./useEventFilters-Bphkda8m.mjs";
5
- import { n as useBlockApi } from "./context-DljQn8L5.mjs";
3
+ import { Dt as buildBookingUtcDateWindow, Ft as getLocalScheduleDate, L as getCardOrientation, M as buildEventRuntimeFilters, N as getEventRuntimeFiltersKey, Nt as formatLocalScheduleDate, R as getContainerClass, X as themeButtonClassName, z as formatEventPrice } from "./propsDecoder-pYvx_Srl.mjs";
4
+ import { a as EventCardClient, i as EventPaginatedListView, n as useEventPagination, o as EventFilters, r as toError, s as formatEventTeacherLine, t as useEventFilters } from "./useEventFilters-ByuU6HLA.mjs";
5
+ import { r as formatEventRemainingPlaces, u as isEventFull } from "./capacity-BW00PO7s.mjs";
6
+ import { a as groupEventsByDate, i as formatTime, l as resolveEventLinkProps, t as formatDate } from "./dates-2RPXHQy4.mjs";
7
+ import { n as useBlockApi } from "./context-DCkiHVdD.mjs";
6
8
  import { t as createBodyThemePortalRoot } from "./themePortalRoot-AGs4cE7t.mjs";
7
9
  import { t as ModalShell } from "./ModalShell-CqkBvBIC.mjs";
8
- import React, { createContext, useCallback, useContext, useEffect, useId, useMemo, useReducer, useRef, useState } from "react";
10
+ import React, { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
9
11
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
12
  //#region ../calendar/src/grid.ts
11
13
  const DAY_NAMES = [
@@ -31,111 +33,73 @@ const MONTH_NAMES = [
31
33
  "November",
32
34
  "December"
33
35
  ];
34
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
35
36
  function formatDateKey(date) {
36
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
37
+ return `${String(date.year).padStart(4, "0")}-${String(date.month).padStart(2, "0")}-${String(date.day).padStart(2, "0")}`;
37
38
  }
38
- /**
39
- * True when `date` and `now` are the same local calendar day.
40
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
41
- * but tests and snapshot-rendering should pass an explicit value.
42
- */
43
- function isToday(date, now = /* @__PURE__ */ new Date()) {
44
- return isSameLocalDay(date, now);
39
+ function isToday(date, today) {
40
+ return isSameCalendarDay(date, today);
45
41
  }
46
- /** True when two dates fall on the same local calendar day. */
47
- function isSameLocalDay(left, right) {
48
- return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
42
+ function isSameCalendarDay(left, right) {
43
+ return left.year === right.year && left.month === right.month && left.day === right.day;
49
44
  }
50
- /**
51
- * Add (or subtract) months to a date, clamping the day-of-month to the
52
- * target month's last day. Avoids JS Date overflow (Jan 29 + 1 month → Mar 1
53
- * in non-leap years).
54
- */
55
- function addMonths(date, months) {
56
- const year = date.getFullYear();
57
- const month = date.getMonth();
58
- const day = date.getDate();
59
- const hours = date.getHours();
60
- const minutes = date.getMinutes();
61
- const seconds = date.getSeconds();
62
- const ms = date.getMilliseconds();
63
- const base = new Date(year, month + months, 1, hours, minutes, seconds, ms);
64
- const lastDayOfTargetMonth = new Date(base.getFullYear(), base.getMonth() + 1, 0).getDate();
65
- base.setDate(Math.min(day, lastDayOfTargetMonth));
66
- return base;
45
+ function getStartOfMonth(date) {
46
+ return {
47
+ year: date.year,
48
+ month: date.month,
49
+ day: 1
50
+ };
67
51
  }
68
- /** Add (or subtract) days while preserving local time-of-day fields. */
69
- function addDays(date, days) {
70
- const result = new Date(date);
71
- result.setDate(result.getDate() + days);
72
- return result;
52
+ function getEndOfMonth(date) {
53
+ return addDays(addMonths(getStartOfMonth(date), 1), -1);
73
54
  }
74
- /** Shift a calendar anchor by the natural unit for a viewport kind. */
75
- function shiftCalendarAnchorDate(date, view, steps) {
76
- if (view === "week") return addDays(date, steps * 7);
77
- return addMonths(date, steps);
55
+ function addMonths(date, months) {
56
+ const target = new Date(Date.UTC(date.year, date.month - 1 + months, 1, 12));
57
+ const year = target.getUTCFullYear();
58
+ const month = target.getUTCMonth() + 1;
59
+ const lastDay = new Date(Date.UTC(year, month, 0, 12)).getUTCDate();
60
+ return {
61
+ year,
62
+ month,
63
+ day: Math.min(date.day, lastDay)
64
+ };
78
65
  }
79
- /**
80
- * Get an inclusive 3-month window around `date`, returned as ISO strings
81
- * with UTC midnight bounds. Suitable for prefetching event windows when
82
- * the consumer handles timezone conversion downstream.
83
- */
84
- function getThreeMonthRange(date) {
85
- const year = date.getFullYear();
86
- const month = date.getMonth();
87
- const prevStart = new Date(year, month - 1, 1);
88
- const nextEnd = new Date(year, month + 2, 0);
66
+ function addDays(date, days) {
67
+ const result = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12));
89
68
  return {
90
- from: `${formatDateKey(prevStart)}T00:00:00Z`,
91
- to: `${formatDateKey(nextEnd)}T23:59:59Z`
69
+ year: result.getUTCFullYear(),
70
+ month: result.getUTCMonth() + 1,
71
+ day: result.getUTCDate()
92
72
  };
93
73
  }
94
- /**
95
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
96
- * days) including padding from prior/next months for a stable grid.
97
- */
74
+ function shiftCalendarAnchorDate(date, view, steps) {
75
+ return view === "week" ? addDays(date, steps * 7) : addMonths(date, steps);
76
+ }
98
77
  function getMonthCalendarDays(year, month, startOfWeek) {
99
- const firstDayOfMonth = new Date(year, month, 1);
100
- const lastDayOfMonth = new Date(year, month + 1, 0);
101
- let startOffset = firstDayOfMonth.getDay();
102
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
103
- const days = [];
104
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
105
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
106
- while (days.length < 42) {
107
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
108
- days.push(new Date(year, month + 1, nextDay));
109
- }
110
- return days;
78
+ const firstDay = {
79
+ year,
80
+ month,
81
+ day: 1
82
+ };
83
+ const dayOfWeek = getDayOfWeek(firstDay);
84
+ const gridStart = addDays(firstDay, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
85
+ return Array.from({ length: 42 }, (_, index) => addDays(gridStart, index));
111
86
  }
112
- /** Build the 7 dates of the week containing `baseDate`. */
113
87
  function getWeekCalendarDays(baseDate, startOfWeek) {
114
- const days = [];
115
- const dayOfWeek = baseDate.getDay();
116
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
117
- const weekStart = new Date(baseDate);
118
- weekStart.setDate(baseDate.getDate() - daysToStart);
119
- for (let i = 0; i < 7; i++) {
120
- const date = new Date(weekStart);
121
- date.setDate(weekStart.getDate() + i);
122
- days.push(date);
123
- }
124
- return days;
88
+ const dayOfWeek = getDayOfWeek(baseDate);
89
+ const weekStart = addDays(baseDate, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
90
+ return Array.from({ length: 7 }, (_, index) => addDays(weekStart, index));
91
+ }
92
+ function getDayOfWeek(date) {
93
+ return new Date(Date.UTC(date.year, date.month - 1, date.day, 12)).getUTCDay();
125
94
  }
126
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
127
95
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
128
96
  const days = getWeekCalendarDays(baseDate, startOfWeek);
129
97
  assertWeekCalendarDays(days);
130
98
  return days;
131
99
  }
132
100
  function assertWeekCalendarDays(days) {
133
- if (days.length !== 7) throw new Error("Expected week calendar helper to return exactly 7 days");
101
+ if (days.length !== 7) throw new Error("Expected exactly 7 calendar days");
134
102
  }
135
- /**
136
- * Day-name labels reordered for the chosen week start. Pass a custom
137
- * `dayNames` array (length 7, Sunday-first) to localize.
138
- */
139
103
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
140
104
  if (startOfWeek === "monday") {
141
105
  const sunday = dayNames[0] ?? "Sun";
@@ -143,22 +107,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
143
107
  }
144
108
  return [...dayNames];
145
109
  }
146
- /**
147
- * Header title for a calendar view.
148
- * - month: "January 2025"
149
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
150
- */
151
110
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
152
111
  if (view === "week") {
153
112
  const weekStart = days[0];
154
113
  const weekEnd = days[6];
155
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
156
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
157
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
158
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
159
- return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
114
+ if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
115
+ const startMonth = monthNames[weekStart.month - 1] ?? "";
116
+ const endMonth = monthNames[weekEnd.month - 1] ?? "";
117
+ if (weekStart.month === weekEnd.month) return `${startMonth} ${weekStart.day} - ${weekEnd.day}, ${weekEnd.year}`;
118
+ return `${startMonth} ${weekStart.day} - ${endMonth} ${weekEnd.day}, ${weekEnd.year}`;
160
119
  }
161
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
120
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
162
121
  }
163
122
  function buildCalendarViewport(input) {
164
123
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -168,10 +127,10 @@ function buildCalendarViewport(input) {
168
127
  kind: "week",
169
128
  anchorDate: input.anchorDate,
170
129
  days,
171
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
130
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
172
131
  };
173
132
  }
174
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
133
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
175
134
  return {
176
135
  kind: "month",
177
136
  anchorDate: input.anchorDate,
@@ -250,25 +209,80 @@ const TabBar = ({ tabs, activeTab, onTabChange, className }) => {
250
209
  };
251
210
  //#endregion
252
211
  //#region ../blocks/src/system/runtime/hooks/useCalendarEvents.state.ts
253
- function calendarEventCacheLoadReducer(_state, action) {
254
- switch (action.type) {
255
- case "started": return { kind: "loading" };
256
- case "succeeded": return { kind: "idle" };
257
- case "failed": return {
258
- kind: "error",
259
- error: action.error
260
- };
261
- default: return assertNever(action);
212
+ function calendarMonthKey(date) {
213
+ return `${date.year}-${String(date.month).padStart(2, "0")}`;
214
+ }
215
+ function calendarWindowMonths(date, radius) {
216
+ const months = [];
217
+ for (let offset = -radius; offset <= radius; offset++) months.push(calendarMonthKey(addMonths(date, offset)));
218
+ return months;
219
+ }
220
+ function groupEvents(events, timeZone) {
221
+ const grouped = /* @__PURE__ */ new Map();
222
+ for (const event of events) {
223
+ const key = calendarMonthKey(getLocalScheduleDate(new Date(event.startsAt), timeZone));
224
+ const month = grouped.get(key) ?? [];
225
+ if (!month.some((existing) => existing.id === event.id)) month.push(event);
226
+ grouped.set(key, month);
227
+ }
228
+ return grouped;
229
+ }
230
+ function seedCalendarCache(events, timeZone) {
231
+ return new Map([...groupEvents(events, timeZone)].map(([key, values]) => [key, {
232
+ kind: "seeded",
233
+ events: values
234
+ }]));
235
+ }
236
+ function planCalendarRequest(state, months, retry) {
237
+ const missing = months.filter((key) => {
238
+ const month = state.get(key);
239
+ return !month || month.kind === "seeded" || retry && month.kind === "failed";
240
+ });
241
+ return missing.length > 0 ? { months: missing } : null;
242
+ }
243
+ function startCalendarRequest(state, request) {
244
+ const next = new Map(state);
245
+ for (const key of request.months) {
246
+ const month = state.get(key);
247
+ if (month?.kind === "loading" || month?.kind === "ready") continue;
248
+ next.set(key, {
249
+ kind: "loading",
250
+ request,
251
+ events: month?.events ?? []
252
+ });
262
253
  }
254
+ return next;
263
255
  }
264
- function toCalendarEventCacheLoadError(error) {
265
- return toError(error, "Unknown error");
256
+ function calendarCacheReducer(state, action) {
257
+ if (action.kind === "started") return startCalendarRequest(state, action.request);
258
+ const next = new Map(state);
259
+ const grouped = action.kind === "succeeded" ? groupEvents(action.events, action.timeZone) : null;
260
+ for (const key of action.request.months) {
261
+ const month = state.get(key);
262
+ if (month?.kind === "loading" && month.request === action.request) next.set(key, action.kind === "succeeded" ? {
263
+ kind: "ready",
264
+ events: grouped?.get(key) ?? []
265
+ } : {
266
+ kind: "failed",
267
+ error: action.error,
268
+ events: month.events
269
+ });
270
+ }
271
+ return next;
266
272
  }
267
- function isCalendarEventCacheLoading(state) {
268
- return state.kind === "loading";
273
+ function selectCalendarEvents(state, months) {
274
+ const events = /* @__PURE__ */ new Map();
275
+ for (const key of months) for (const event of state.get(key)?.events ?? []) events.set(event.id, event);
276
+ return [...events.values()].sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime());
269
277
  }
270
- function getCalendarEventCacheError(state) {
271
- return state.kind === "error" ? state.error : null;
278
+ function projectCalendarLoadState(state, months) {
279
+ const entries = months.map((key) => state.get(key));
280
+ const failed = entries.find((entry) => entry?.kind === "failed");
281
+ if (failed?.kind === "failed") return {
282
+ kind: "error",
283
+ error: failed.error
284
+ };
285
+ return entries.some((entry) => !entry || entry.kind === "seeded" || entry.kind === "loading") ? { kind: "loading" } : { kind: "idle" };
272
286
  }
273
287
  //#endregion
274
288
  //#region ../blocks/src/system/runtime/hooks/useCalendarEvents.ts
@@ -280,18 +294,28 @@ function getCalendarEventCacheError(state) {
280
294
  */
281
295
  /** Maximum events to fetch per calendar request (covers 3 months of events) */
282
296
  const CALENDAR_FETCH_LIMIT = 200;
283
- /**
284
- * Generate a cache key for a month
285
- */
286
- function getMonthKey(date) {
287
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
297
+ async function loadCalendarEventPages(loadPage, request) {
298
+ const events = [];
299
+ let afterStartsAt;
300
+ let afterId;
301
+ for (;;) {
302
+ const page = await loadPage({
303
+ ...request,
304
+ afterStartsAt,
305
+ afterId,
306
+ limit: CALENDAR_FETCH_LIMIT
307
+ });
308
+ events.push(...page);
309
+ if (page.length < CALENDAR_FETCH_LIMIT) return events;
310
+ const last = page[page.length - 1];
311
+ if (!last) return events;
312
+ if (last.startsAt === afterStartsAt && last.occurrenceId === afterId) throw new Error("Calendar event pagination cursor did not advance");
313
+ afterStartsAt = last.startsAt;
314
+ afterId = last.occurrenceId;
315
+ }
288
316
  }
289
- /**
290
- * Owns calendar viewport state only: selected anchor date, derived visible
291
- * period, and navigation by the natural unit for the active view.
292
- */
293
- function useCalendarViewport({ view = "month", startOfWeek = "monday", initialDate } = {}) {
294
- const [viewDate, setViewDate] = useState(() => initialDate ?? /* @__PURE__ */ new Date());
317
+ function useCalendarViewport({ view = "month", startOfWeek = "monday", initialDate }) {
318
+ const [viewDate, setViewDate] = useState(initialDate);
295
319
  const viewport = useMemo(() => buildCalendarViewport({
296
320
  view,
297
321
  anchorDate: viewDate,
@@ -316,168 +340,135 @@ function useCalendarViewport({ view = "month", startOfWeek = "monday", initialDa
316
340
  goToPrevious,
317
341
  goToNext,
318
342
  goToToday: useCallback(() => {
319
- setViewDate(/* @__PURE__ */ new Date());
320
- }, [])
343
+ setViewDate(initialDate);
344
+ }, [initialDate])
321
345
  };
322
346
  }
323
347
  /**
324
- * Owns event loading and month-window caching for a supplied viewport anchor.
325
- * It does not decide navigation semantics or visible calendar days.
348
+ * The reducer owns month data and request ownership. The hook only performs I/O.
349
+ * Requests for other months remain useful until the query context changes.
326
350
  */
327
- function useCalendarEventCache({ viewDate, initialEvents = [], preloadMonths = 1, filters, stage }) {
351
+ function useCalendarEventCache({ viewDate, initialEvents = [], preloadMonths = 1, filters, stage, timeZone }) {
328
352
  const { getPublicEvents } = useBlockApi();
329
- const [loadState, dispatchLoadState] = useReducer(calendarEventCacheLoadReducer, { kind: "idle" });
330
- const [cacheVersion, setCacheVersion] = useState(0);
331
- const filtersKey = useMemo(() => getEventRuntimeFiltersKey(filters), [
332
- filters?.categoryIds,
333
- filters?.eventPresets,
334
- filters?.eventSurface,
335
- filters?.scheduleScope,
336
- filters?.staffMemberId,
337
- filters?.venueId
353
+ const context = useMemo(() => ({
354
+ getPublicEvents,
355
+ filters,
356
+ stage,
357
+ timeZone
358
+ }), [
359
+ getPublicEvents,
360
+ getEventRuntimeFiltersKey(filters),
361
+ stage,
362
+ timeZone
338
363
  ]);
339
- const cacheRef = useRef(/* @__PURE__ */ new Map());
340
- const loadedMonthsRef = useRef(/* @__PURE__ */ new Set());
341
- const fetchingRef = useRef(/* @__PURE__ */ new Set());
342
- const requestIdRef = useRef(0);
343
- const initializedFiltersKeyRef = useRef(null);
344
- useEffect(() => {
345
- if (initializedFiltersKeyRef.current === filtersKey) return;
346
- initializedFiltersKeyRef.current = filtersKey;
347
- cacheRef.current = /* @__PURE__ */ new Map();
348
- loadedMonthsRef.current = /* @__PURE__ */ new Set();
349
- fetchingRef.current = /* @__PURE__ */ new Set();
350
- requestIdRef.current += 1;
351
- if (initialEvents.length > 0) for (const event of initialEvents) {
352
- const monthKey = getMonthKey(new Date(event.startsAt));
353
- const existing = cacheRef.current.get(monthKey) || [];
354
- if (!existing.some((e) => e.id === event.id)) cacheRef.current.set(monthKey, [...existing, event]);
355
- }
356
- setCacheVersion((v) => v + 1);
357
- }, [filtersKey, initialEvents]);
358
- const fetchEventsForRange = useCallback(async (from, to, targetMonths) => {
359
- const monthsToFetch = targetMonths.filter((m) => !loadedMonthsRef.current.has(m) && !fetchingRef.current.has(m));
360
- if (monthsToFetch.length === 0) return;
361
- monthsToFetch.forEach((m) => fetchingRef.current.add(m));
362
- const currentRequestId = ++requestIdRef.current;
363
- dispatchLoadState({ type: "started" });
364
+ const [snapshot, setSnapshot] = useState(() => ({
365
+ context,
366
+ cache: seedCalendarCache(initialEvents, timeZone)
367
+ }));
368
+ if (snapshot.context !== context) setSnapshot({
369
+ context,
370
+ cache: seedCalendarCache(initialEvents, timeZone)
371
+ });
372
+ const months = useMemo(() => calendarWindowMonths(viewDate, preloadMonths), [
373
+ viewDate.year,
374
+ viewDate.month,
375
+ preloadMonths
376
+ ]);
377
+ const displayMonths = useMemo(() => calendarWindowMonths(viewDate, 1), [viewDate.year, viewDate.month]);
378
+ const request = useMemo(() => snapshot.context === context ? planCalendarRequest(snapshot.cache, months, false) : null, [
379
+ snapshot,
380
+ context,
381
+ months
382
+ ]);
383
+ const launched = useRef(/* @__PURE__ */ new WeakSet());
384
+ const runRequest = useCallback(async (planned) => {
385
+ if (launched.current.has(planned)) return;
386
+ launched.current.add(planned);
387
+ const apply = (action) => setSnapshot((current) => current.context === context ? {
388
+ context,
389
+ cache: calendarCacheReducer(current.cache, action)
390
+ } : current);
391
+ apply({
392
+ kind: "started",
393
+ request: planned
394
+ });
364
395
  try {
365
- const result = await getPublicEvents({
366
- from,
367
- to,
368
- limit: CALENDAR_FETCH_LIMIT,
369
- stage,
370
- detailLevel: "listing",
371
- eventSurface: filters?.eventSurface,
372
- eventPresets: filters?.eventPresets,
373
- scheduleScope: filters?.scheduleScope,
374
- categoryIds: filters?.categoryIds,
375
- staffMemberId: filters?.staffMemberId,
376
- venueId: filters?.venueId
396
+ const range = buildBookingUtcDateWindow({
397
+ startDate: formatLocalScheduleDate(getStartOfMonth(addMonths(viewDate, -preloadMonths))),
398
+ endDate: formatLocalScheduleDate(getEndOfMonth(addMonths(viewDate, preloadMonths))),
399
+ timeZone
400
+ });
401
+ apply({
402
+ kind: "succeeded",
403
+ request: planned,
404
+ events: await loadCalendarEventPages(context.getPublicEvents, {
405
+ ...context.filters,
406
+ stage: context.stage,
407
+ from: range.startAt.toISOString(),
408
+ to: (/* @__PURE__ */ new Date(range.endExclusive.getTime() - 1)).toISOString(),
409
+ detailLevel: "listing"
410
+ }),
411
+ timeZone
377
412
  });
378
- if (currentRequestId === requestIdRef.current) {
379
- for (const event of result) {
380
- const monthKey = getMonthKey(new Date(event.startsAt));
381
- const existing = cacheRef.current.get(monthKey) || [];
382
- if (!existing.some((e) => e.id === event.id)) cacheRef.current.set(monthKey, [...existing, event]);
383
- }
384
- for (const month of monthsToFetch) {
385
- loadedMonthsRef.current.add(month);
386
- if (!cacheRef.current.has(month)) cacheRef.current.set(month, []);
387
- }
388
- setCacheVersion((v) => v + 1);
389
- dispatchLoadState({ type: "succeeded" });
390
- }
391
- } catch (err) {
392
- if (currentRequestId === requestIdRef.current) dispatchLoadState({
393
- type: "failed",
394
- error: toCalendarEventCacheLoadError(err)
413
+ } catch (error) {
414
+ apply({
415
+ kind: "failed",
416
+ request: planned,
417
+ error: toError(error, "Failed to load events")
395
418
  });
396
- } finally {
397
- monthsToFetch.forEach((m) => fetchingRef.current.delete(m));
398
419
  }
399
420
  }, [
400
- getPublicEvents,
401
- filters?.categoryIds,
402
- filters?.eventPresets,
403
- filters?.eventSurface,
404
- filters?.scheduleScope,
405
- filters?.staffMemberId,
406
- filters?.venueId,
407
- stage
421
+ context,
422
+ viewDate.year,
423
+ viewDate.month,
424
+ preloadMonths,
425
+ timeZone
408
426
  ]);
409
- const ensureEventsLoaded = useCallback((date) => {
410
- const targetMonths = [];
411
- for (let i = -preloadMonths; i <= preloadMonths; i++) {
412
- const targetDate = addMonths(date, i);
413
- targetMonths.push(getMonthKey(targetDate));
414
- }
415
- const unloadedMonths = targetMonths.filter((m) => !loadedMonthsRef.current.has(m) && !fetchingRef.current.has(m));
416
- if (unloadedMonths.length > 0) {
417
- const range = getThreeMonthRange(date);
418
- fetchEventsForRange(range.from, range.to, unloadedMonths);
419
- }
420
- }, [preloadMonths, fetchEventsForRange]);
421
427
  useEffect(() => {
422
- ensureEventsLoaded(viewDate);
423
- }, [viewDate, ensureEventsLoaded]);
428
+ if (request) runRequest(request);
429
+ }, [request, runRequest]);
430
+ const retryCurrentView = useCallback(() => {
431
+ if (snapshot.context !== context) return;
432
+ const retry = planCalendarRequest(snapshot.cache, months, true);
433
+ if (retry) runRequest(retry);
434
+ }, [
435
+ snapshot,
436
+ context,
437
+ months,
438
+ runRequest
439
+ ]);
424
440
  return {
425
- events: useMemo(() => {
426
- const allEvents = [];
427
- for (let i = -1; i <= 1; i++) {
428
- const monthKey = getMonthKey(addMonths(viewDate, i));
429
- const monthEvents = cacheRef.current.get(monthKey) || [];
430
- allEvents.push(...monthEvents);
431
- }
432
- const seen = /* @__PURE__ */ new Set();
433
- return allEvents.filter((e) => {
434
- if (seen.has(e.id)) return false;
435
- seen.add(e.id);
436
- return true;
437
- }).sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime());
438
- }, [viewDate, cacheVersion]),
439
- loading: isCalendarEventCacheLoading(loadState),
440
- error: getCalendarEventCacheError(loadState)
441
+ events: selectCalendarEvents(snapshot.cache, displayMonths),
442
+ loadState: projectCalendarLoadState(snapshot.cache, months),
443
+ retryCurrentView
441
444
  };
442
445
  }
443
- /**
444
- * Hook for calendar event management with month-based caching.
445
- *
446
- * Pre-fetches 3 months (previous, current, next) and caches by month.
447
- * Navigation within cached range is instant; fetches at boundaries.
448
- *
449
- * @example
450
- * ```tsx
451
- * const { events, viewDate, loading, goToPrevious, goToNext } = useCalendarEvents({
452
- * siteId: 'site-123',
453
- * initialEvents: serverEvents,
454
- * });
455
- * ```
456
- */
457
- function useCalendarEvents({ siteId: _siteId, initialEvents = [], view = "month", startOfWeek = "monday", preloadMonths = 1, filters, stage }) {
446
+ function useCalendarEvents({ siteId: _siteId, initialEvents = [], view = "month", startOfWeek = "monday", preloadMonths = 1, filters, stage, calendarContext }) {
458
447
  const { viewDate, viewport, goToDate, goToPrevious, goToNext, goToToday } = useCalendarViewport({
459
448
  view,
460
- startOfWeek
449
+ startOfWeek,
450
+ initialDate: calendarContext.initialToday
461
451
  });
462
- const { events, loading, error } = useCalendarEventCache({
452
+ const { events, loadState, retryCurrentView } = useCalendarEventCache({
463
453
  viewDate,
464
454
  initialEvents,
465
455
  preloadMonths,
466
456
  filters,
467
- stage
457
+ stage,
458
+ timeZone: calendarContext.timeZone
468
459
  });
469
460
  return {
470
461
  events,
471
462
  viewDate,
472
463
  viewport,
473
- loading,
474
- error,
464
+ loadState,
475
465
  setViewDate: useCallback((date) => {
476
466
  goToDate(date);
477
467
  }, [goToDate]),
478
468
  goToPrevious,
479
469
  goToNext,
480
- goToToday
470
+ goToToday,
471
+ retryCurrentView
481
472
  };
482
473
  }
483
474
  //#endregion
@@ -544,9 +535,9 @@ function useEventModal() {
544
535
  * Clicking an event opens the EventDetailModal.
545
536
  * Clicking "+N more" opens the DayEventsModal.
546
537
  */
547
- const CalendarDayCell = ({ date, events, isCurrentMonth }) => {
538
+ const CalendarDayCell = ({ date, events, isCurrentMonth, today: currentDate }) => {
548
539
  const { openEventModal, openDayModal } = useEventModal();
549
- const today = isToday(date);
540
+ const today = isToday(date, currentDate);
550
541
  const dayClasses = [
551
542
  "event-calendar-day",
552
543
  !isCurrentMonth && "event-calendar-day--other-month",
@@ -562,7 +553,7 @@ const CalendarDayCell = ({ date, events, isCurrentMonth }) => {
562
553
  className: dayClasses,
563
554
  children: [/* @__PURE__ */ jsx("div", {
564
555
  className: "event-calendar-day-number",
565
- children: date.getDate()
556
+ children: date.day
566
557
  }), /* @__PURE__ */ jsxs("div", {
567
558
  className: "event-calendar-events",
568
559
  children: [events.slice(0, 3).map((event) => {
@@ -608,8 +599,8 @@ const AgendaEventCard = ({ event, showCapacity, onClick }) => {
608
599
  const eventLinkProps = resolveEventLinkProps(event);
609
600
  const categoryColor = event.eventCategory?.color || "rgb(var(--tb-accent))";
610
601
  const price = formatEventPrice(event);
611
- const { available, isFull } = getEventAvailability(event);
612
- const capacity = showCapacity && available != null ? isFull ? "Full" : `${available} spots left` : null;
602
+ const capacity = showCapacity ? formatEventRemainingPlaces(event) : null;
603
+ const isFull = isEventFull(event);
613
604
  const title = event.title;
614
605
  const timeZone = event.timeZone ?? null;
615
606
  const teacherLine = formatEventTeacherLine(event);
@@ -694,9 +685,9 @@ const FULL_DAY_NAMES = [
694
685
  * @returns "Monday, January 13"
695
686
  */
696
687
  function formatAgendaDayHeader(date) {
697
- const dayName = FULL_DAY_NAMES[date.getDay()];
698
- const monthName = MONTH_NAMES[date.getMonth()];
699
- return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.getDate()}`;
688
+ const dayName = FULL_DAY_NAMES[getDayOfWeek(date)];
689
+ const monthName = MONTH_NAMES[date.month - 1];
690
+ return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.day}`;
700
691
  }
701
692
  /**
702
693
  * WeekAgendaView Component
@@ -704,14 +695,14 @@ function formatAgendaDayHeader(date) {
704
695
  * Displays a week of events in an agenda/list style with rich event details.
705
696
  * Shows all 7 days with date headers, empty days show "No events scheduled".
706
697
  */
707
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
708
- const eventsByDate = groupEventsByDate(events);
698
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
699
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
709
700
  return /* @__PURE__ */ jsx("div", {
710
701
  className: "event-agenda-week",
711
702
  children: days.map((date) => {
712
703
  const dateKey = formatDateKey(date);
713
704
  const dayEvents = eventsByDate.get(dateKey) || [];
714
- const today = isToday(date);
705
+ const today = isToday(date, currentDate);
715
706
  return /* @__PURE__ */ jsxs("div", {
716
707
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
717
708
  children: [/* @__PURE__ */ jsx("div", {
@@ -810,7 +801,7 @@ function EventDetailModal({ event, showCapacity, onClose, portalRoot, cardRole =
810
801
  * Clicking an event triggers onSelectEvent (typically opens EventDetailModal).
811
802
  */
812
803
  function DayEventsModal({ date, events, showCapacity, onClose, onSelectEvent, portalRoot }) {
813
- const formattedDate = formatDate(date.toISOString());
804
+ const formattedDate = formatDate(`${formatLocalScheduleDate(date)}T12:00:00Z`);
814
805
  return /* @__PURE__ */ jsxs(ModalShell, {
815
806
  title: formattedDate,
816
807
  titleId: "ec-day-modal-title",
@@ -950,7 +941,8 @@ function toEventCombinedControllerProps(props) {
950
941
  buttonVariant: props.render.display.buttonVariant,
951
942
  buttonText: props.render.display.buttonText,
952
943
  emptyMessage: props.render.display.emptyMessage,
953
- className: props.render.display.className ?? void 0
944
+ className: props.render.display.className ?? void 0,
945
+ calendarContext: props.render.hydration.calendarContext
954
946
  };
955
947
  }
956
948
  /**
@@ -962,7 +954,7 @@ function toEventCombinedControllerProps(props) {
962
954
  const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout = "stack", listColumns = "3", eventsPerPage = 12, paginationAction = {
963
955
  kind: "loadMore",
964
956
  label: "Load more events"
965
- }, startOfWeek = "monday", calendarTabViews = "both", defaultCalendarView, showFilters, showCategoryFilter = "auto", showVenueFilter, showStaffFilter, eventSurface, filterEventPresets, scheduleScope, filterCategoryIds, filterStaffMemberId, filterVenueId, showVenue, showMap, showCapacity, cardRole, buttonVariant = "primary", buttonText = "Book", emptyMessage = "No upcoming events scheduled.", className }) => {
957
+ }, startOfWeek = "monday", calendarTabViews = "both", defaultCalendarView, showFilters, showCategoryFilter = "auto", showVenueFilter, showStaffFilter, eventSurface, filterEventPresets, scheduleScope, filterCategoryIds, filterStaffMemberId, filterVenueId, showVenue, showMap, showCapacity, cardRole, buttonVariant = "primary", buttonText = "Book", emptyMessage = "No upcoming events scheduled.", className, calendarContext }) => {
966
958
  const fetchInitialEventsOnMount = initialEvents == null;
967
959
  const resolvedShowFilters = showFilters ?? true;
968
960
  const resolvedShowVenueFilter = showVenueFilter ?? false;
@@ -1020,7 +1012,7 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1020
1012
  pageSize,
1021
1013
  stage
1022
1014
  });
1023
- const { events: calendarEventsRaw, viewDate, viewport, loading: calendarLoading, goToPrevious, goToNext, goToToday } = useCalendarEvents({
1015
+ const { events: calendarEventsRaw, viewDate, viewport, loadState: calendarLoadState, goToPrevious, goToNext, goToToday } = useCalendarEvents({
1024
1016
  siteId,
1025
1017
  initialEvents: useMemo(() => {
1026
1018
  return getEventRuntimeFiltersKey(initialListFilters) === getEventRuntimeFiltersKey(listFilters) ? initialEvents ?? [] : [];
@@ -1033,9 +1025,10 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1033
1025
  startOfWeek,
1034
1026
  preloadMonths: 1,
1035
1027
  filters: listFilters,
1036
- stage
1028
+ stage,
1029
+ calendarContext
1037
1030
  });
1038
- const eventsByDate = useMemo(() => groupEventsByDate(calendarEventsRaw), [calendarEventsRaw]);
1031
+ const eventsByDate = useMemo(() => groupEventsByDate(calendarEventsRaw, calendarContext.timeZone), [calendarContext.timeZone, calendarEventsRaw]);
1039
1032
  const dayNames = useMemo(() => getOrderedDayNames(startOfWeek), [startOfWeek]);
1040
1033
  const tabs = [{
1041
1034
  id: "list",
@@ -1137,7 +1130,7 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1137
1130
  }),
1138
1131
  /* @__PURE__ */ jsxs("h3", {
1139
1132
  className: "event-calendar-title",
1140
- children: [viewport.title, calendarLoading && /* @__PURE__ */ jsx("span", {
1133
+ children: [viewport.title, calendarLoadState.kind === "loading" && /* @__PURE__ */ jsx("span", {
1141
1134
  className: "rb-ml-2 rb-caption status-muted",
1142
1135
  children: "(loading...)"
1143
1136
  })]
@@ -1176,7 +1169,9 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1176
1169
  days: viewport.days,
1177
1170
  events: calendarEventsRaw,
1178
1171
  emptyMessage: "No events scheduled",
1179
- showCapacity: resolvedShowCapacity
1172
+ showCapacity: resolvedShowCapacity,
1173
+ calendarTimeZone: calendarContext.timeZone,
1174
+ today: calendarContext.initialToday
1180
1175
  }) : /* @__PURE__ */ jsxs("div", {
1181
1176
  className: "event-calendar-container",
1182
1177
  children: [/* @__PURE__ */ jsx("div", {
@@ -1192,12 +1187,13 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1192
1187
  return /* @__PURE__ */ jsx(CalendarDayCell, {
1193
1188
  date,
1194
1189
  events: eventsByDate.get(dateKey) || [],
1195
- isCurrentMonth: date.getMonth() === viewDate.getMonth()
1190
+ isCurrentMonth: date.month === viewDate.month,
1191
+ today: calendarContext.initialToday
1196
1192
  }, dateKey);
1197
1193
  })
1198
1194
  })]
1199
1195
  }),
1200
- calendarEventsRaw.length === 0 && !calendarLoading && /* @__PURE__ */ jsx("p", {
1196
+ calendarEventsRaw.length === 0 && calendarLoadState.kind === "idle" && /* @__PURE__ */ jsx("p", {
1201
1197
  className: "event-calendar-empty",
1202
1198
  children: emptyMessage
1203
1199
  })
@@ -1213,4 +1209,4 @@ const EventCombinedClient = ({ events: initialEvents, siteId, stage, listLayout
1213
1209
  };
1214
1210
  const EventCombinedIslandClient = (props) => /* @__PURE__ */ jsx(EventCombinedClient, { ...toEventCombinedControllerProps(props) });
1215
1211
  //#endregion
1216
- export { CalendarDayCell as a, useCalendarEvents as c, getOrderedDayNames as d, getWeekCalendarDayTuple as f, isToday as h, WeekAgendaView as i, MONTH_NAMES as l, isSameLocalDay as m, EventCombinedIslandClient as n, EventModalProvider as o, getWeekCalendarDays as p, EventModals as r, useEventModal as s, EventCombinedClient as t, formatDateKey as u };
1212
+ export { CalendarDayCell as a, useCalendarEvents as c, formatDateKey as d, getDayOfWeek as f, isToday as g, isSameCalendarDay as h, WeekAgendaView as i, MONTH_NAMES as l, getWeekCalendarDays as m, EventCombinedIslandClient as n, EventModalProvider as o, getOrderedDayNames as p, EventModals as r, useEventModal as s, EventCombinedClient as t, addDays as u };