@riverbankcms/sdk 0.136.0 → 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 (160) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/{PreviewEditorSidebar-BU5ZlhQR.mjs → PreviewEditorSidebar-Bn6cONPa.mjs} +8 -8
  3. package/dist/{PreviewEditorUI-9XkHL-bC.mjs → PreviewEditorUI-LAwXZPSx.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-wbEpXryy.mjs → PreviewQueryProvider-ztQUdsNo.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-CnWmj-2B.mjs → SdkPreviewModeRuntime-BbbGsI_v.mjs} +596 -164
  6. package/dist/{SiteChromeCustomizeContext-B6d5zkog.mjs → SiteChromeCustomizeContext-BbkNSt5a.mjs} +2888 -1404
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +12 -298
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +21 -14
  9. package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
  10. package/dist/_dts/api/src/accessAdmin.d.ts +1 -9
  11. package/dist/_dts/api/src/accountApi.d.ts +49 -2
  12. package/dist/_dts/api/src/contentRuntime.d.ts +1 -4
  13. package/dist/_dts/api/src/domainConnection.d.ts +41 -0
  14. package/dist/_dts/api/src/endpoints.d.ts +194 -181
  15. package/dist/_dts/api/src/index.d.ts +4 -3
  16. package/dist/_dts/api/src/media.d.ts +19 -2
  17. package/dist/_dts/api/src/sdkContracts.d.ts +2 -15
  18. package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
  19. package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +61 -0
  20. package/dist/_dts/api/src/sdkThemeWire.d.ts +15 -4
  21. package/dist/_dts/api/src/siteInfrastructure.d.ts +17 -23
  22. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +7 -21
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +27 -3
  24. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
  25. package/dist/_dts/api/src/types.d.ts +1 -1
  26. package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -2
  27. package/dist/_dts/blocks/src/index.d.ts +1 -1
  28. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +9 -0
  29. package/dist/_dts/blocks/src/pageRendererBlockSupport.d.ts +75 -0
  30. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +2 -0
  31. package/dist/_dts/blocks/src/server.d.ts +1 -1
  32. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -1
  33. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  34. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -3
  35. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +34 -22
  36. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
  37. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -0
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -3
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +5 -2
  46. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +31 -0
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
  54. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +1 -1
  56. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
  57. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
  58. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
  59. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
  60. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +8 -40
  61. package/dist/_dts/db/src/index.d.ts +1 -0
  62. package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
  63. package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
  64. package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
  65. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
  66. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  67. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
  68. package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
  69. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
  70. package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
  71. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
  72. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
  73. package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
  74. package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
  75. package/dist/_dts/sdk/src/version.d.ts +1 -1
  76. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  77. package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
  78. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +25 -2
  79. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +3 -3
  80. package/dist/_dts/theme-core/src/schema.d.ts +12 -11
  81. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
  82. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +10 -0
  83. package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
  84. package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
  85. package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
  86. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -9
  87. package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
  88. package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
  89. package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
  90. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +10 -1
  91. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +1 -1
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +7 -0
  93. package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
  94. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
  95. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
  96. package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
  97. package/dist/client/{BookingConsentAgreement-DCch21a6.mjs → BookingConsentAgreement--_fUCZe-.mjs} +2 -2
  98. package/dist/client/{DiscountCodeDisclosure-DIj1T59K.mjs → DiscountCodeDisclosure-BMipSoDJ.mjs} +1 -1
  99. package/dist/client/{EventCombined.client-BWVNlXTx.mjs → EventCombined.client-CwJOxn7A.mjs} +154 -178
  100. package/dist/client/{EventListing.client-DVFCDe3i.mjs → EventListing.client-eVwiylPW.mjs} +2 -2
  101. package/dist/client/{LeafletStaticMap-BY5mIHw9.mjs → LeafletStaticMap-IKenna5u.mjs} +1 -1
  102. package/dist/client/{accordion-CK29E8rG.mjs → accordion-MGAO3PuE.mjs} +1 -1
  103. package/dist/client/{bookingForm-DFvnet-N.mjs → bookingForm-CudlQPUu.mjs} +5 -5
  104. package/dist/client/bookings.mjs +418 -79
  105. package/dist/client/capacity-BW00PO7s.mjs +271 -0
  106. package/dist/client/{carousel-BVU5NQlb.mjs → carousel-BrbGJ2Jl.mjs} +1 -1
  107. package/dist/client/{cart-BNItcZVa.mjs → cart-Bq5eU0xZ.mjs} +3 -3
  108. package/dist/client/{checkout-Bu6iCdkP.mjs → checkout-BAFVRdrK.mjs} +3 -3
  109. package/dist/client/client.mjs +2919 -1918
  110. package/dist/client/{context-BImarOAq.mjs → context-DCkiHVdD.mjs} +8 -5
  111. package/dist/client/dates-2RPXHQy4.mjs +264 -0
  112. package/dist/client/{eventCalendar-DS2h-UXD.mjs → eventCalendar-B0O-hPF7.mjs} +10 -17
  113. package/dist/client/{eventCombined-Drt4Oq9p.mjs → eventCombined-DCkDaoDI.mjs} +3 -3
  114. package/dist/client/{eventDetails-Bl2vWgTX.mjs → eventDetails-D8GG2dnD.mjs} +5 -3
  115. package/dist/client/{eventListing-CS7PHY7v.mjs → eventListing-3ssV_bxz.mjs} +3 -3
  116. package/dist/client/{eventRegistration-D-j8eNy2.mjs → eventRegistration-bPQo3kVw.mjs} +562 -309
  117. package/dist/client/{form-RMpoLTyr.mjs → form-qMv8RDkk.mjs} +2 -2
  118. package/dist/client/{headerSection-BYE3Lb3k.mjs → headerSection-CH0Sc5hX.mjs} +2 -2
  119. package/dist/client/hooks.mjs +289 -32
  120. package/dist/client/{locationMap-BxSr7Kkh.mjs → locationMap-0_xlBnNI.mjs} +2 -2
  121. package/dist/client/{newsletterForm-DerbXwFC.mjs → newsletterForm-NUW7m9RI.mjs} +2 -2
  122. package/dist/client/{productDetail-4SZCLhAf.mjs → productDetail-FBEOM7jW.mjs} +3 -3
  123. package/dist/client/{productList-D7AP4GNq.mjs → productList-R0OSGhnn.mjs} +3 -3
  124. package/dist/client/{propsDecoder-pzBeCh14.mjs → propsDecoder-pYvx_Srl.mjs} +88 -380
  125. package/dist/client/rendering/client.mjs +2616 -1637
  126. package/dist/client/rendering/islands.mjs +17 -17
  127. package/dist/client/rendering.mjs +2710 -1702
  128. package/dist/client/{scrollToBlock-CduAKf8T.mjs → scrollToBlock-ByQv96M2.mjs} +1 -1
  129. package/dist/client/{shop-Cp5p_kGe.mjs → shop-RUG9DmRE.mjs} +6 -6
  130. package/dist/client/{shop-commerce-DicXYaYX.mjs → shop-commerce-B76Jz23B.mjs} +5 -5
  131. package/dist/client/{shop-commerce-store-CGWnpY4K.mjs → shop-commerce-store-QuQNdDsD.mjs} +1 -1
  132. package/dist/client/{shopShared-BDf9ljkm.mjs → shopShared-vXU1omwJ.mjs} +3 -3
  133. package/dist/client/{useEventFilters-DeeyGYuk.mjs → useEventFilters-ByuU6HLA.mjs} +33 -18
  134. package/dist/preview-next/before-render.mjs +79 -51
  135. package/dist/preview-next/client/runtime.mjs +4 -4
  136. package/dist/preview-next/keepAlive.mjs +79 -51
  137. package/dist/preview-next/middleware.mjs +79 -51
  138. package/dist/{previewAuthStore-DbqBol0V.mjs → previewAuthStore-L_cKW8Sb.mjs} +79 -51
  139. package/dist/{sdk-runtime-19MO27F0.mjs → sdk-runtime-sUMr5d70.mjs} +2 -2
  140. package/dist/{separator-DaPLtJ1f.mjs → separator-BIHkie5i.mjs} +1 -1
  141. package/dist/server/components.mjs +2077 -1274
  142. package/dist/server/config-validation.mjs +289 -32
  143. package/dist/server/config.mjs +289 -32
  144. package/dist/server/data.mjs +289 -32
  145. package/dist/server/index.mjs +80 -52
  146. package/dist/server/next.mjs +1822 -1111
  147. package/dist/server/page-converter.mjs +167 -31
  148. package/dist/server/prebuild.mjs +1 -1
  149. package/dist/server/rendering/server.mjs +1988 -1286
  150. package/dist/server/rendering.mjs +1943 -1182
  151. package/dist/server/routing.mjs +351 -86
  152. package/dist/server/server.mjs +293 -128
  153. package/dist/server/theme-bridge.mjs +52 -8
  154. package/dist/server/theme.mjs +27 -8
  155. package/dist/styles/index.css +15 -0
  156. package/package.json +1 -1
  157. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
  158. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
  159. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
  160. /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, Gt as getLocalScheduleDate, H as formatEventTeacherLine, J as resolveEventLinkProps, K as groupEventsByDate, L as formatDate, M as buildEventRuntimeFilters, N as getEventRuntimeFiltersKey, Rt as buildBookingUtcDateWindow, U as formatTime, Ut as formatLocalScheduleDate, W as getCardOrientation, X as getEventAvailability, st as themeButtonClassName } from "./propsDecoder-pzBeCh14.mjs";
4
- import { a as EventCardClient, i as EventPaginatedListView, n as useEventPagination, o as EventFilters, r as toError, t as useEventFilters } from "./useEventFilters-DeeyGYuk.mjs";
5
- import { n as useBlockApi } from "./context-BImarOAq.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 = [
@@ -207,34 +209,80 @@ const TabBar = ({ tabs, activeTab, onTabChange, className }) => {
207
209
  };
208
210
  //#endregion
209
211
  //#region ../blocks/src/system/runtime/hooks/useCalendarEvents.state.ts
210
- function calendarEventCacheLoadReducer(state, action) {
211
- switch (action.type) {
212
- case "started": return {
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, {
213
249
  kind: "loading",
214
- scope: action.scope
215
- };
216
- case "succeeded": return sameCalendarLoadScope(state, action.scope) ? { kind: "idle" } : state;
217
- case "failed": return sameCalendarLoadScope(state, action.scope) ? {
218
- kind: "error",
219
- scope: action.scope,
220
- error: action.error
221
- } : state;
222
- default: return assertNever(action);
250
+ request,
251
+ events: month?.events ?? []
252
+ });
223
253
  }
254
+ return next;
224
255
  }
225
- function projectCalendarLoadState(state, scope) {
226
- if (state.kind === "idle" || !sameCalendarLoadScope(state, scope)) return { kind: "idle" };
227
- return state.kind === "loading" ? { kind: "loading" } : {
228
- kind: "error",
229
- error: state.error
230
- };
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;
231
272
  }
232
- function sameCalendarLoadScope(state, scope) {
233
- if (state.kind === "idle") return false;
234
- return state.scope.filtersKey === scope.filtersKey && state.scope.anchorDate.year === scope.anchorDate.year && state.scope.anchorDate.month === scope.anchorDate.month && state.scope.anchorDate.day === scope.anchorDate.day;
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());
235
277
  }
236
- function toCalendarEventCacheLoadError(error) {
237
- return toError(error, "Unknown error");
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" };
238
286
  }
239
287
  //#endregion
240
288
  //#region ../blocks/src/system/runtime/hooks/useCalendarEvents.ts
@@ -246,7 +294,7 @@ function toCalendarEventCacheLoadError(error) {
246
294
  */
247
295
  /** Maximum events to fetch per calendar request (covers 3 months of events) */
248
296
  const CALENDAR_FETCH_LIMIT = 200;
249
- async function loadCalendarEventPages(loadPage, request, isCurrent) {
297
+ async function loadCalendarEventPages(loadPage, request) {
250
298
  const events = [];
251
299
  let afterStartsAt;
252
300
  let afterId;
@@ -257,7 +305,6 @@ async function loadCalendarEventPages(loadPage, request, isCurrent) {
257
305
  afterId,
258
306
  limit: CALENDAR_FETCH_LIMIT
259
307
  });
260
- if (!isCurrent()) return null;
261
308
  events.push(...page);
262
309
  if (page.length < CALENDAR_FETCH_LIMIT) return events;
263
310
  const last = page[page.length - 1];
@@ -267,12 +314,6 @@ async function loadCalendarEventPages(loadPage, request, isCurrent) {
267
314
  afterId = last.occurrenceId;
268
315
  }
269
316
  }
270
- /**
271
- * Generate a cache key for a month
272
- */
273
- function getMonthKey(date) {
274
- return `${date.year}-${String(date.month).padStart(2, "0")}`;
275
- }
276
317
  function useCalendarViewport({ view = "month", startOfWeek = "monday", initialDate }) {
277
318
  const [viewDate, setViewDate] = useState(initialDate);
278
319
  const viewport = useMemo(() => buildCalendarViewport({
@@ -303,167 +344,102 @@ function useCalendarViewport({ view = "month", startOfWeek = "monday", initialDa
303
344
  }, [initialDate])
304
345
  };
305
346
  }
306
- function addEventsToCalendarCache(cache, events, timeZone) {
307
- for (const event of events) {
308
- const monthKey = getMonthKey(getLocalScheduleDate(new Date(event.startsAt), timeZone));
309
- const existing = cache.get(monthKey) ?? [];
310
- if (!existing.some((cachedEvent) => cachedEvent.id === event.id)) cache.set(monthKey, [...existing, event]);
311
- }
312
- }
313
- function useInitiallySeededCalendarCache(initialEvents, timeZone) {
314
- const cacheRef = useRef(/* @__PURE__ */ new Map());
315
- const seededRef = useRef(false);
316
- if (!seededRef.current) {
317
- addEventsToCalendarCache(cacheRef.current, initialEvents, timeZone);
318
- seededRef.current = true;
319
- }
320
- return cacheRef;
321
- }
322
- function readEventsFromCalendarCache(cache, viewDate) {
323
- const allEvents = [];
324
- for (let offset = -1; offset <= 1; offset += 1) {
325
- const monthEvents = cache.get(getMonthKey(addMonths(viewDate, offset))) ?? [];
326
- allEvents.push(...monthEvents);
327
- }
328
- const seen = /* @__PURE__ */ new Set();
329
- return allEvents.filter((event) => {
330
- if (seen.has(event.id)) return false;
331
- seen.add(event.id);
332
- return true;
333
- }).sort((left, right) => new Date(left.startsAt).getTime() - new Date(right.startsAt).getTime());
334
- }
335
347
  /**
336
- * Owns event loading and month-window caching for a supplied viewport anchor.
337
- * 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.
338
350
  */
339
351
  function useCalendarEventCache({ viewDate, initialEvents = [], preloadMonths = 1, filters, stage, timeZone }) {
340
352
  const { getPublicEvents } = useBlockApi();
341
- const [loadState, dispatchLoadState] = useReducer(calendarEventCacheLoadReducer, { kind: "idle" });
342
- const [cacheVersion, setCacheVersion] = useState(0);
343
- const filtersKey = useMemo(() => getEventRuntimeFiltersKey(filters), [
344
- filters?.categoryIds,
345
- filters?.eventPresets,
346
- filters?.eventSurface,
347
- filters?.scheduleScope,
348
- filters?.staffMemberId,
349
- filters?.venueId
350
- ]);
351
- const cacheRef = useInitiallySeededCalendarCache(initialEvents, timeZone);
352
- const loadedMonthsRef = useRef(/* @__PURE__ */ new Set());
353
- const fetchingRef = useRef(/* @__PURE__ */ new Set());
354
- const requestIdRef = useRef(0);
355
- const initializedFiltersKeyRef = useRef(null);
356
- useEffect(() => {
357
- if (initializedFiltersKeyRef.current === filtersKey) return;
358
- initializedFiltersKeyRef.current = filtersKey;
359
- cacheRef.current = /* @__PURE__ */ new Map();
360
- loadedMonthsRef.current = /* @__PURE__ */ new Set();
361
- fetchingRef.current = /* @__PURE__ */ new Set();
362
- requestIdRef.current += 1;
363
- addEventsToCalendarCache(cacheRef.current, initialEvents, timeZone);
364
- setCacheVersion((v) => v + 1);
365
- }, [
366
- filtersKey,
367
- initialEvents,
353
+ const context = useMemo(() => ({
354
+ getPublicEvents,
355
+ filters,
356
+ stage,
368
357
  timeZone
369
- ]);
370
- const fetchEventsForRange = useCallback(async (from, to, targetMonths, scope) => {
371
- const monthsToFetch = targetMonths.filter((m) => !loadedMonthsRef.current.has(m) && !fetchingRef.current.has(m));
372
- if (monthsToFetch.length === 0) return;
373
- monthsToFetch.forEach((m) => fetchingRef.current.add(m));
374
- const currentRequestId = ++requestIdRef.current;
375
- dispatchLoadState({
376
- type: "started",
377
- scope
378
- });
379
- try {
380
- const result = await loadCalendarEventPages(getPublicEvents, {
381
- from,
382
- to,
383
- stage,
384
- detailLevel: "listing",
385
- eventSurface: filters?.eventSurface,
386
- eventPresets: filters?.eventPresets,
387
- scheduleScope: filters?.scheduleScope,
388
- categoryIds: filters?.categoryIds,
389
- staffMemberId: filters?.staffMemberId,
390
- venueId: filters?.venueId
391
- }, () => currentRequestId === requestIdRef.current);
392
- if (result === null) return;
393
- for (const event of result) {
394
- const monthKey = getMonthKey(getLocalScheduleDate(new Date(event.startsAt), timeZone));
395
- const existing = cacheRef.current.get(monthKey) || [];
396
- if (!existing.some((e) => e.id === event.id)) cacheRef.current.set(monthKey, [...existing, event]);
397
- }
398
- for (const month of monthsToFetch) {
399
- loadedMonthsRef.current.add(month);
400
- if (!cacheRef.current.has(month)) cacheRef.current.set(month, []);
401
- }
402
- setCacheVersion((v) => v + 1);
403
- dispatchLoadState({
404
- type: "succeeded",
405
- scope
406
- });
407
- } catch (err) {
408
- monthsToFetch.forEach((m) => fetchingRef.current.delete(m));
409
- if (currentRequestId === requestIdRef.current) dispatchLoadState({
410
- type: "failed",
411
- scope,
412
- error: toCalendarEventCacheLoadError(err)
413
- });
414
- } finally {
415
- monthsToFetch.forEach((m) => fetchingRef.current.delete(m));
416
- }
417
- }, [
358
+ }), [
418
359
  getPublicEvents,
419
- filters?.categoryIds,
420
- filters?.eventPresets,
421
- filters?.eventSurface,
422
- filters?.scheduleScope,
423
- filters?.staffMemberId,
424
- filters?.venueId,
360
+ getEventRuntimeFiltersKey(filters),
425
361
  stage,
426
362
  timeZone
427
363
  ]);
428
- const ensureEventsLoaded = useCallback((date) => {
429
- const targetMonths = [];
430
- for (let i = -preloadMonths; i <= preloadMonths; i++) {
431
- const targetDate = addMonths(date, i);
432
- targetMonths.push(getMonthKey(targetDate));
433
- }
434
- const unloadedMonths = targetMonths.filter((m) => !loadedMonthsRef.current.has(m) && !fetchingRef.current.has(m));
435
- if (unloadedMonths.length > 0) {
436
- const startDate = getStartOfMonth(addMonths(date, -preloadMonths));
437
- const endDate = getEndOfMonth(addMonths(date, preloadMonths));
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
+ });
395
+ try {
438
396
  const range = buildBookingUtcDateWindow({
439
- startDate: formatLocalScheduleDate(startDate),
440
- endDate: formatLocalScheduleDate(endDate),
397
+ startDate: formatLocalScheduleDate(getStartOfMonth(addMonths(viewDate, -preloadMonths))),
398
+ endDate: formatLocalScheduleDate(getEndOfMonth(addMonths(viewDate, preloadMonths))),
441
399
  timeZone
442
400
  });
443
- const scope = {
444
- anchorDate: date,
445
- filtersKey
446
- };
447
- fetchEventsForRange(range.startAt.toISOString(), (/* @__PURE__ */ new Date(range.endExclusive.getTime() - 1)).toISOString(), unloadedMonths, scope);
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
412
+ });
413
+ } catch (error) {
414
+ apply({
415
+ kind: "failed",
416
+ request: planned,
417
+ error: toError(error, "Failed to load events")
418
+ });
448
419
  }
449
420
  }, [
421
+ context,
422
+ viewDate.year,
423
+ viewDate.month,
450
424
  preloadMonths,
451
- fetchEventsForRange,
452
- filtersKey,
453
425
  timeZone
454
426
  ]);
455
427
  useEffect(() => {
456
- ensureEventsLoaded(viewDate);
457
- }, [viewDate, ensureEventsLoaded]);
428
+ if (request) runRequest(request);
429
+ }, [request, runRequest]);
458
430
  const retryCurrentView = useCallback(() => {
459
- ensureEventsLoaded(viewDate);
460
- }, [ensureEventsLoaded, viewDate]);
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
+ ]);
461
440
  return {
462
- events: useMemo(() => readEventsFromCalendarCache(cacheRef.current, viewDate), [viewDate, cacheVersion]),
463
- loadState: projectCalendarLoadState(loadState, useMemo(() => ({
464
- anchorDate: viewDate,
465
- filtersKey
466
- }), [filtersKey, viewDate])),
441
+ events: selectCalendarEvents(snapshot.cache, displayMonths),
442
+ loadState: projectCalendarLoadState(snapshot.cache, months),
467
443
  retryCurrentView
468
444
  };
469
445
  }
@@ -623,8 +599,8 @@ const AgendaEventCard = ({ event, showCapacity, onClick }) => {
623
599
  const eventLinkProps = resolveEventLinkProps(event);
624
600
  const categoryColor = event.eventCategory?.color || "rgb(var(--tb-accent))";
625
601
  const price = formatEventPrice(event);
626
- const { available, isFull } = getEventAvailability(event);
627
- const capacity = showCapacity && available != null ? isFull ? "Full" : `${available} spots left` : null;
602
+ const capacity = showCapacity ? formatEventRemainingPlaces(event) : null;
603
+ const isFull = isEventFull(event);
628
604
  const title = event.title;
629
605
  const timeZone = event.timeZone ?? null;
630
606
  const teacherLine = formatEventTeacherLine(event);
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { M as buildEventRuntimeFilters } from "./propsDecoder-pzBeCh14.mjs";
3
- import { i as EventPaginatedListView, n as useEventPagination, o as EventFilters, t as useEventFilters } from "./useEventFilters-DeeyGYuk.mjs";
2
+ import { M as buildEventRuntimeFilters } from "./propsDecoder-pYvx_Srl.mjs";
3
+ import { i as EventPaginatedListView, n as useEventPagination, o as EventFilters, t as useEventFilters } from "./useEventFilters-ByuU6HLA.mjs";
4
4
  import { useId, useMemo } from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region ../blocks/src/system/runtime/nodes/events/EventListing.client.tsx
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { kt as isRecord } from "./propsDecoder-pzBeCh14.mjs";
2
+ import { vt as isRecord } from "./propsDecoder-pYvx_Srl.mjs";
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region ../blocks/src/system/runtime/nodes/shared/LeafletStaticMap.tsx
@@ -1,4 +1,4 @@
1
- import { t as defineIslandPropsDecoder } from "./propsDecoder-pzBeCh14.mjs";
1
+ import { t as defineIslandPropsDecoder } from "./propsDecoder-pYvx_Srl.mjs";
2
2
  //#region src/rendering/islands/enhancers/accordion.ts
3
3
  const decode = defineIslandPropsDecoder("accordion");
4
4
  function parseDefaultValues(value) {
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { S as unsafeAsPassId, _ as unsafeAsAppointmentResourceId, b as unsafeAsFormId, v as unsafeAsAppointmentServiceId, y as unsafeAsCustomerPassId } from "./colorStyles-CrxJrPjJ.mjs";
3
- import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator, r as SpinnerNode, t as BookingConsentAgreement } from "./BookingConsentAgreement-DCch21a6.mjs";
4
- import { At as assertNever, Ct as toSelectedCollectionOptionKind, Dt as isBookingRequirementConsentFieldId, Et as BOOKING_FORM_DATA_RESERVED_KEYS, Ft as reportWorkflowError, It as reportWorkflowSuccess, Kt as parseBookingLocalDate, Lt as addLocalScheduleDays, Mt as err, Pt as okWith, St as resolveDefaultBookingServiceId, Tt as resolveSelectedAppointmentConsent, Ut as formatLocalScheduleDate, Vt as formatBookingInstant, _t as parseBookingCurrencyInputToCents, bt as resolveBookingPaymentStep, dt as formatBookingCentsAsCurrencyInput, ft as formatBookingSubmissionPreparationError, gt as isBookingServiceSlidingAmountInRange, ht as getBookingSuccessMessage, jt as clearWorkflowFeedback, lt as logger, mt as getBookingServiceSlidingScale, pt as getBookingRedirectStateFromLocation, qt as resolveBookingTimeZoneId, st as themeButtonClassName, t as defineIslandPropsDecoder, tn as formatCurrencyAmount, ut as deriveBookingFormViewState, vt as prepareBookingSubmission, wt as projectSelectedAppointmentConsentIntoForm, xt as resolveBookingSiteId, yt as resolveAppointmentCheckoutVerificationState } from "./propsDecoder-pzBeCh14.mjs";
5
- import { n as useBlockApi, t as BlockApiProvider } from "./context-BImarOAq.mjs";
3
+ import { a as buildBookingPaymentSelectionViewModel, i as usePolling, n as StepIndicator, r as SpinnerNode, t as BookingConsentAgreement } from "./BookingConsentAgreement--_fUCZe-.mjs";
4
+ import { $ as deriveBookingFormViewState, Ct as okWith, Et as addLocalScheduleDays, It as parseBookingLocalDate, Kt as formatCurrencyAmount, Lt as resolveBookingTimeZoneId, Nt as formatLocalScheduleDate, Q as logger, Tt as reportWorkflowSuccess, X as themeButtonClassName, at as isBookingServiceSlidingAmountInRange, bt as clearWorkflowFeedback, ct as resolveAppointmentCheckoutVerificationState, dt as resolveDefaultBookingServiceId, et as formatBookingCentsAsCurrencyInput, ft as toSelectedCollectionOptionKind, gt as isBookingRequirementConsentFieldId, ht as BOOKING_FORM_DATA_RESERVED_KEYS, it as getBookingSuccessMessage, jt as formatBookingInstant, lt as resolveBookingPaymentStep, mt as resolveSelectedAppointmentConsent, nt as getBookingRedirectStateFromLocation, ot as parseBookingCurrencyInputToCents, pt as projectSelectedAppointmentConsentIntoForm, rt as getBookingServiceSlidingScale, st as prepareBookingSubmission, t as defineIslandPropsDecoder, tt as formatBookingSubmissionPreparationError, ut as resolveBookingSiteId, wt as reportWorkflowError, xt as err, yt as assertNever } from "./propsDecoder-pYvx_Srl.mjs";
5
+ import { n as useBlockApi, t as BlockApiProvider } from "./context-DCkiHVdD.mjs";
6
6
  import { n as isSpamProtectionEnabled, r as AltchaWidget, t as getChallengeUrl } from "./src-B833rYRr.mjs";
7
- import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-CduAKf8T.mjs";
8
- import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-DIj1T59K.mjs";
7
+ import { a as CheckIcon, i as StateIcon, n as useDiscountCodeUi, r as TerminalPanel, t as scrollToBlock } from "./scrollToBlock-ByQv96M2.mjs";
8
+ import { t as DiscountCodeDisclosure } from "./DiscountCodeDisclosure-BMipSoDJ.mjs";
9
9
  import { t as FeedbackMessage } from "./FeedbackMessage-CtLvvS_d.mjs";
10
10
  import { n as getFieldValidationControlProps, t as FieldValidationMessage } from "./FieldValidationMessage-AYanWFb-.mjs";
11
11
  import { t as buildCheckoutReturnUrls } from "./checkoutUrls-BuseL0dw.mjs";