@riverbankcms/sdk 0.88.0 → 0.89.1

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 (103) hide show
  1. package/dist/{PreviewEditorSidebar-EVRS3C7T.mjs → PreviewEditorSidebar-JDR64FEC.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-54WD4IGE.mjs → PreviewEditorUI-67TMJMAF.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-ZBEMRV7N.mjs +8 -0
  4. package/dist/_dts/api/src/accessAdmin.d.ts +7 -0
  5. package/dist/_dts/api/src/endpoints.d.ts +8 -0
  6. package/dist/_dts/api/src/index.d.ts +2 -2
  7. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +5 -1
  8. package/dist/_dts/api/src/siteMembers.d.ts +6 -1
  9. package/dist/_dts/api/src/types.d.ts +1 -1
  10. package/dist/_dts/blocks/src/system/icons/cta.d.ts +3 -3
  11. package/dist/_dts/blocks/src/system/icons/index.d.ts +1 -0
  12. package/dist/_dts/blocks/src/system/icons/registry.d.ts +2 -2
  13. package/dist/_dts/blocks/src/system/icons/semantic.d.ts +3 -3
  14. package/dist/_dts/blocks/src/system/icons/svg.d.ts +72 -0
  15. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +1 -0
  16. package/dist/_dts/blocks/src/system/runtime/hooks/loadStateError.d.ts +1 -0
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.d.ts +1 -1
  18. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.state.d.ts +55 -0
  19. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableSlots.state.d.ts +39 -0
  20. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.d.ts +4 -27
  21. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.state.d.ts +40 -0
  22. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -0
  23. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.state.d.ts +31 -0
  24. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.d.ts +3 -3
  25. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.state.d.ts +39 -0
  26. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventPaginatedListView.client.d.ts +1 -1
  27. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.state.d.ts +24 -2
  28. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.state.d.ts +24 -0
  29. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.state.d.ts +35 -0
  30. package/dist/_dts/content-model/src/entry-slots/types.d.ts +54 -0
  31. package/dist/_dts/core/src/branded.d.ts +7 -0
  32. package/dist/_dts/core/src/index.d.ts +1 -0
  33. package/dist/_dts/core/src/site-route-target.d.ts +40 -0
  34. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +159 -2
  35. package/dist/_dts/media-core/src/fileDomain.d.ts +4 -0
  36. package/dist/_dts/sdk/src/client/runtimeCachePolicy.d.ts +160 -0
  37. package/dist/_dts/sdk/src/client/types.d.ts +26 -1
  38. package/dist/_dts/sdk/src/index.d.ts +3 -1
  39. package/dist/_dts/sdk/src/version.d.ts +1 -1
  40. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  41. package/dist/{chunk-YDMBIIS5.mjs → chunk-7N46MZHI.mjs} +1 -1
  42. package/dist/{chunk-7KOO7RPP.mjs → chunk-7YUAXONX.mjs} +1007 -353
  43. package/dist/{chunk-O4LVYUVH.mjs → chunk-F645A5UV.mjs} +18 -0
  44. package/dist/{chunk-ER4UIW4X.mjs → chunk-HKJQERFR.mjs} +7 -7
  45. package/dist/{chunk-K3JWH6HE.mjs → chunk-TGBJWKMP.mjs} +1 -1
  46. package/dist/{chunk-HVOBXA3Y.mjs → chunk-ZQRBLCW5.mjs} +2 -2
  47. package/dist/cli/index.mjs +668 -18
  48. package/dist/client/{accordion-PT5CGW5N.mjs → accordion-MUCVNGQ7.mjs} +2 -2
  49. package/dist/client/{bookingForm-2HLRTEYS.mjs → bookingForm-PKD6EFIE.mjs} +192 -76
  50. package/dist/client/bookings.mjs +436 -191
  51. package/dist/client/{carousel-Z2LKYSWA.mjs → carousel-3TKQSNJC.mjs} +4 -3
  52. package/dist/client/{cart-ND5IK4A6.mjs → cart-6XHSZK23.mjs} +8 -7
  53. package/dist/client/{checkout-EYUSGAY7.mjs → checkout-FVSPM6FI.mjs} +8 -7
  54. package/dist/client/chunk-6N7YRNYU.mjs +183 -0
  55. package/dist/client/{chunk-O5JNI3E4.mjs → chunk-7DH35FGA.mjs} +2 -2
  56. package/dist/client/{chunk-BAWHZ5GM.mjs → chunk-CQKKFEQD.mjs} +195 -61
  57. package/dist/client/{chunk-X7GVFB7Y.mjs → chunk-EY42X22F.mjs} +3 -3
  58. package/dist/client/{chunk-6DVPO44G.mjs → chunk-FHU6PFPM.mjs} +1 -1
  59. package/dist/client/{chunk-H4MHEXYS.mjs → chunk-LQFDYWPJ.mjs} +1 -1
  60. package/dist/client/{chunk-MHBEWDT7.mjs → chunk-RSQWWUAD.mjs} +122 -50
  61. package/dist/client/{chunk-GOFO7HRH.mjs → chunk-STJ2NCQM.mjs} +1 -1
  62. package/dist/client/{chunk-DIRW2LNG.mjs → chunk-UQFY4AHX.mjs} +272 -198
  63. package/dist/client/{chunk-WCVK4MBJ.mjs → chunk-VGLXACVK.mjs} +1 -1
  64. package/dist/client/{chunk-BL66UWGD.mjs → chunk-ZJZZA5EP.mjs} +6 -6
  65. package/dist/client/{chunk-S4G65LGR.mjs → chunk-ZT5XE7FK.mjs} +1 -1
  66. package/dist/client/client.mjs +3823 -3507
  67. package/dist/client/{courseRegistration-H3AZBUEG.mjs → courseRegistration-ATZSYDHM.mjs} +6 -6
  68. package/dist/client/{eventCalendar-FPKJGLGS.mjs → eventCalendar-6T2UGKKP.mjs} +10 -9
  69. package/dist/client/{eventCombined-QCGIZBUY.mjs → eventCombined-Q4VANXVF.mjs} +10 -9
  70. package/dist/client/{eventDetails-HIT3BJWU.mjs → eventDetails-DW37E7VW.mjs} +10 -9
  71. package/dist/client/{eventListing-R4HNWJDN.mjs → eventListing-XURTSAUW.mjs} +10 -9
  72. package/dist/client/{eventRegistration-Q7BYY5HF.mjs → eventRegistration-MRKEVAXW.mjs} +10 -9
  73. package/dist/client/{form-NI6YOG6S.mjs → form-WZZFFGMU.mjs} +3 -3
  74. package/dist/client/{headerSection-SDYGII36.mjs → headerSection-EQYVQBLM.mjs} +3 -3
  75. package/dist/client/hooks.mjs +18 -0
  76. package/dist/client/{locationMap-BDETEUQD.mjs → locationMap-MFF5VAZR.mjs} +3 -3
  77. package/dist/client/{newsletterForm-EKYIU67X.mjs → newsletterForm-JQ77UYIE.mjs} +60 -24
  78. package/dist/client/{productDetail-5UTGNN76.mjs → productDetail-25LMT3IZ.mjs} +8 -7
  79. package/dist/client/{productList-7YA5KXZQ.mjs → productList-5ABEMKUG.mjs} +8 -7
  80. package/dist/client/rendering/client.mjs +3266 -3528
  81. package/dist/client/rendering/islands.mjs +19 -19
  82. package/dist/client/rendering.mjs +3143 -3452
  83. package/dist/client/{shop-AIMUMZYC.mjs → shop-OMMQZ6YO.mjs} +8 -7
  84. package/dist/preview-next/before-render.mjs +18 -0
  85. package/dist/preview-next/client/runtime.mjs +5 -5
  86. package/dist/preview-next/middleware.mjs +18 -0
  87. package/dist/{sdk-runtime-NW472WNT.mjs → sdk-runtime-WNLBZ3ZH.mjs} +6 -6
  88. package/dist/server/components.mjs +1068 -1540
  89. package/dist/server/config-validation.mjs +18 -0
  90. package/dist/server/config.mjs +18 -0
  91. package/dist/server/data.mjs +18 -0
  92. package/dist/server/index.mjs +847 -261
  93. package/dist/server/next.mjs +1708 -1555
  94. package/dist/server/prebuild.mjs +1 -1
  95. package/dist/server/rendering/server.mjs +1068 -1540
  96. package/dist/server/rendering.mjs +1074 -1546
  97. package/dist/server/routing.mjs +314 -9
  98. package/dist/server/server.mjs +668 -25
  99. package/dist/server/theme-bridge.mjs +26 -0
  100. package/dist/styles/index.css +26 -0
  101. package/package.json +2 -1
  102. package/dist/SdkPreviewModeRuntime-ZALZDJEK.mjs +0 -8
  103. /package/dist/client/{chunk-LI2C6M5O.mjs → chunk-25W2EQUN.mjs} +0 -0
@@ -11950,7 +11950,7 @@ function FeedbackMessage({
11950
11950
  }
11951
11951
 
11952
11952
  // ../blocks/src/system/runtime/nodes/booking-form.client.tsx
11953
- import React3, { useRef as useRef7, useState as useState5 } from "react";
11953
+ import React3, { useRef as useRef7, useState as useState3 } from "react";
11954
11954
 
11955
11955
  // ../altcha/src/AltchaWidget.tsx
11956
11956
  import { useEffect, useRef } from "react";
@@ -12037,9 +12037,9 @@ import React2, {
12037
12037
  useEffect as useEffect6,
12038
12038
  useLayoutEffect,
12039
12039
  useMemo as useMemo2,
12040
- useReducer as useReducer2,
12040
+ useReducer as useReducer4,
12041
12041
  useRef as useRef5,
12042
- useState as useState4
12042
+ useState as useState2
12043
12043
  } from "react";
12044
12044
 
12045
12045
  // ../../node_modules/.pnpm/altcha-lib@1.4.1/node_modules/altcha-lib/dist/helpers.js
@@ -12066,7 +12066,7 @@ function getChallengeUrl() {
12066
12066
  }
12067
12067
 
12068
12068
  // ../blocks/src/system/runtime/hooks/useAvailableDates.ts
12069
- import { useState, useEffect as useEffect3, useCallback, useRef as useRef3 } from "react";
12069
+ import { useEffect as useEffect3, useCallback, useReducer, useRef as useRef3 } from "react";
12070
12070
 
12071
12071
  // ../blocks/src/utils/date-formatting.ts
12072
12072
  var BOOKING_FETCH_CHUNK_DAYS = 14;
@@ -12175,6 +12175,75 @@ function useVisibleTabPolling({
12175
12175
  }, [enabled, intervalMs, jitterMs, minVisibleRefreshIntervalMs]);
12176
12176
  }
12177
12177
 
12178
+ // ../blocks/src/system/runtime/hooks/useAvailableDates.state.ts
12179
+ function createEmptyAvailableDatesData() {
12180
+ return {
12181
+ availableDates: /* @__PURE__ */ new Set(),
12182
+ hasMore: false,
12183
+ loadedRange: null,
12184
+ nextStartDate: null
12185
+ };
12186
+ }
12187
+ function createInitialAvailableDatesState() {
12188
+ return {
12189
+ tag: "idle",
12190
+ data: createEmptyAvailableDatesData()
12191
+ };
12192
+ }
12193
+ var initialAvailableDatesState = createInitialAvailableDatesState();
12194
+ function getAvailableDates(state) {
12195
+ return state.data.availableDates;
12196
+ }
12197
+ function getAvailableDatesLoadedRange(state) {
12198
+ return state.data.loadedRange;
12199
+ }
12200
+ function getAvailableDatesNextStartDate(state) {
12201
+ return state.data.nextStartDate;
12202
+ }
12203
+ function hasMoreAvailableDates(state) {
12204
+ return state.data.hasMore;
12205
+ }
12206
+ function isLoadingAvailableDates(state) {
12207
+ return state.tag === "loading";
12208
+ }
12209
+ function isRefreshingAvailableDates(state) {
12210
+ return state.tag === "refreshing";
12211
+ }
12212
+ function getAvailableDatesError(state) {
12213
+ return state.tag === "error" ? state.message : null;
12214
+ }
12215
+ function mergeAvailableDates(previous, action) {
12216
+ const availableDates = action.append ? new Set(previous.availableDates) : /* @__PURE__ */ new Set();
12217
+ for (const date of action.dates) {
12218
+ availableDates.add(date);
12219
+ }
12220
+ return {
12221
+ availableDates,
12222
+ hasMore: action.hasMore,
12223
+ loadedRange: {
12224
+ start: action.append && previous.loadedRange ? previous.loadedRange.start : action.startDate,
12225
+ end: action.endDate
12226
+ },
12227
+ nextStartDate: action.nextStartDate
12228
+ };
12229
+ }
12230
+ function availableDatesReducer(state, action) {
12231
+ switch (action.type) {
12232
+ case "query-cleared":
12233
+ return { tag: "idle", data: createEmptyAvailableDatesData() };
12234
+ case "load-started":
12235
+ return { tag: "loading", data: state.data };
12236
+ case "refresh-started":
12237
+ return { tag: "refreshing", data: state.data };
12238
+ case "load-succeeded":
12239
+ return { tag: "loaded", data: mergeAvailableDates(state.data, action) };
12240
+ case "load-failed":
12241
+ return { tag: "error", data: state.data, message: action.message };
12242
+ default:
12243
+ return assertNever11(action);
12244
+ }
12245
+ }
12246
+
12178
12247
  // ../blocks/src/system/runtime/hooks/useAvailableDates.ts
12179
12248
  var AVAILABILITY_REFRESH_INTERVAL_MS = 3e4;
12180
12249
  var AVAILABILITY_REFRESH_JITTER_MS = 5e3;
@@ -12187,25 +12256,23 @@ function useAvailableDates({
12187
12256
  initialDays = 30
12188
12257
  }) {
12189
12258
  const api = useBlockApi();
12190
- const [availableDates, setAvailableDates] = useState(/* @__PURE__ */ new Set());
12191
- const [isLoading, setIsLoading] = useState(false);
12192
- const [isRefreshing, setIsRefreshing] = useState(false);
12193
- const [error, setError] = useState(null);
12194
- const [hasMore, setHasMore] = useState(false);
12195
- const [loadedRange, setLoadedRange] = useState(null);
12196
- const nextStartDateRef = useRef3(null);
12259
+ const [state, dispatch] = useReducer(
12260
+ availableDatesReducer,
12261
+ createInitialAvailableDatesState()
12262
+ );
12197
12263
  const requestIdRef = useRef3(0);
12264
+ const loadedRange = getAvailableDatesLoadedRange(state);
12265
+ const isLoading = isLoadingAvailableDates(state);
12266
+ const nextStartDate = getAvailableDatesNextStartDate(state);
12198
12267
  const fetchDates = useCallback(
12199
12268
  async (startDate, endDate, append = false, mode = "load") => {
12200
12269
  if (!serviceId) return;
12201
12270
  const requestId = ++requestIdRef.current;
12202
12271
  if (mode === "refresh") {
12203
- setIsRefreshing(true);
12272
+ dispatch({ type: "refresh-started" });
12204
12273
  } else {
12205
- setIsLoading(true);
12206
- setIsRefreshing(false);
12274
+ dispatch({ type: "load-started" });
12207
12275
  }
12208
- setError(null);
12209
12276
  try {
12210
12277
  const data = await api.getAvailableDates({
12211
12278
  serviceId,
@@ -12215,38 +12282,29 @@ function useAvailableDates({
12215
12282
  resourceId
12216
12283
  });
12217
12284
  if (requestId !== requestIdRef.current) return;
12218
- setAvailableDates((prev) => {
12219
- const newSet = append ? new Set(prev) : /* @__PURE__ */ new Set();
12220
- data.dates.forEach((d) => newSet.add(d));
12221
- return newSet;
12285
+ dispatch({
12286
+ type: "load-succeeded",
12287
+ dates: data.dates,
12288
+ hasMore: data.hasMore,
12289
+ nextStartDate: data.nextStartDate || null,
12290
+ startDate: data.startDate,
12291
+ endDate: data.endDate,
12292
+ append
12222
12293
  });
12223
- setHasMore(data.hasMore);
12224
- nextStartDateRef.current = data.nextStartDate || null;
12225
- setLoadedRange((prev) => ({
12226
- start: append && prev ? prev.start : data.startDate,
12227
- end: data.endDate
12228
- }));
12229
12294
  } catch (err3) {
12230
12295
  if (requestId !== requestIdRef.current) return;
12231
- setError(
12232
- err3 instanceof Error ? err3.message : "Failed to load available dates"
12233
- );
12234
- } finally {
12235
- if (mode === "refresh" && requestId === requestIdRef.current) {
12236
- setIsRefreshing(false);
12237
- } else if (requestId === requestIdRef.current) {
12238
- setIsLoading(false);
12239
- }
12296
+ dispatch({
12297
+ type: "load-failed",
12298
+ message: err3 instanceof Error ? err3.message : "Failed to load available dates"
12299
+ });
12240
12300
  }
12241
12301
  },
12242
12302
  [api, serviceId, resourceId, timezone]
12243
12303
  );
12244
12304
  useEffect3(() => {
12245
12305
  if (!serviceId) {
12246
- setAvailableDates(/* @__PURE__ */ new Set());
12247
- setLoadedRange(null);
12248
- setHasMore(false);
12249
- setIsRefreshing(false);
12306
+ requestIdRef.current += 1;
12307
+ dispatch({ type: "query-cleared" });
12250
12308
  return;
12251
12309
  }
12252
12310
  const now = /* @__PURE__ */ new Date();
@@ -12270,8 +12328,8 @@ function useAvailableDates({
12270
12328
  }
12271
12329
  });
12272
12330
  const loadMore = useCallback(() => {
12273
- if (!nextStartDateRef.current || isLoading) return;
12274
- const start = nextStartDateRef.current;
12331
+ if (!nextStartDate || isLoading) return;
12332
+ const start = nextStartDate;
12275
12333
  const end = formatLocalScheduleDate(
12276
12334
  addLocalScheduleDays(
12277
12335
  parseBookingLocalDate(start),
@@ -12279,20 +12337,86 @@ function useAvailableDates({
12279
12337
  )
12280
12338
  );
12281
12339
  void fetchDates(start, end, true);
12282
- }, [fetchDates, isLoading]);
12340
+ }, [fetchDates, isLoading, nextStartDate]);
12283
12341
  return {
12284
- availableDates,
12342
+ availableDates: getAvailableDates(state),
12285
12343
  isLoading,
12286
- isRefreshing,
12287
- error,
12288
- hasMore,
12344
+ isRefreshing: isRefreshingAvailableDates(state),
12345
+ error: getAvailableDatesError(state),
12346
+ hasMore: hasMoreAvailableDates(state),
12289
12347
  loadMore,
12290
12348
  loadedRange
12291
12349
  };
12292
12350
  }
12293
12351
 
12294
12352
  // ../blocks/src/system/runtime/hooks/useAvailableSlots.ts
12295
- import { useState as useState2, useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4 } from "react";
12353
+ import { useCallback as useCallback2, useEffect as useEffect4, useReducer as useReducer2, useRef as useRef4 } from "react";
12354
+
12355
+ // ../blocks/src/system/runtime/hooks/useAvailableSlots.state.ts
12356
+ var initialAvailableSlotsState = { tag: "idle" };
12357
+ function getAvailableSlots(state) {
12358
+ switch (state.tag) {
12359
+ case "idle":
12360
+ case "loading":
12361
+ return [];
12362
+ case "loaded":
12363
+ case "refreshing":
12364
+ case "error":
12365
+ return state.slots;
12366
+ default:
12367
+ return assertNever11(state);
12368
+ }
12369
+ }
12370
+ function hasLoadedAvailableSlots(state) {
12371
+ switch (state.tag) {
12372
+ case "idle":
12373
+ return false;
12374
+ case "loading":
12375
+ case "refreshing":
12376
+ case "error":
12377
+ return state.hasLoaded;
12378
+ case "loaded":
12379
+ return true;
12380
+ default:
12381
+ return assertNever11(state);
12382
+ }
12383
+ }
12384
+ function isLoadingAvailableSlots(state) {
12385
+ return state.tag === "loading";
12386
+ }
12387
+ function isRefreshingAvailableSlots(state) {
12388
+ return state.tag === "refreshing";
12389
+ }
12390
+ function getAvailableSlotsError(state) {
12391
+ return state.tag === "error" ? state.message : null;
12392
+ }
12393
+ function availableSlotsReducer(state, action) {
12394
+ switch (action.type) {
12395
+ case "query-cleared":
12396
+ return { tag: "idle" };
12397
+ case "load-started":
12398
+ return { tag: "loading", hasLoaded: hasLoadedAvailableSlots(state) };
12399
+ case "refresh-started":
12400
+ return {
12401
+ tag: "refreshing",
12402
+ slots: getAvailableSlots(state),
12403
+ hasLoaded: hasLoadedAvailableSlots(state)
12404
+ };
12405
+ case "load-succeeded":
12406
+ return { tag: "loaded", slots: action.slots };
12407
+ case "load-failed":
12408
+ return {
12409
+ tag: "error",
12410
+ slots: getAvailableSlots(state),
12411
+ hasLoaded: hasLoadedAvailableSlots(state),
12412
+ message: action.message
12413
+ };
12414
+ default:
12415
+ return assertNever11(action);
12416
+ }
12417
+ }
12418
+
12419
+ // ../blocks/src/system/runtime/hooks/useAvailableSlots.ts
12296
12420
  var AVAILABILITY_REFRESH_INTERVAL_MS2 = 3e4;
12297
12421
  var AVAILABILITY_REFRESH_JITTER_MS2 = 5e3;
12298
12422
  function useAvailableSlots({
@@ -12304,31 +12428,23 @@ function useAvailableSlots({
12304
12428
  timezone
12305
12429
  }) {
12306
12430
  const api = useBlockApi();
12307
- const [slots, setSlots] = useState2([]);
12308
- const [isLoading, setIsLoading] = useState2(false);
12309
- const [isRefreshing, setIsRefreshing] = useState2(false);
12310
- const [hasLoaded, setHasLoaded] = useState2(false);
12311
- const [error, setError] = useState2(null);
12431
+ const [state, dispatch] = useReducer2(
12432
+ availableSlotsReducer,
12433
+ initialAvailableSlotsState
12434
+ );
12312
12435
  const requestIdRef = useRef4(0);
12313
12436
  const fetchSlots = useCallback2(
12314
12437
  async (mode) => {
12315
12438
  const requestId = ++requestIdRef.current;
12316
12439
  if (!selectedDate || !serviceId) {
12317
- setSlots([]);
12318
- setIsLoading(false);
12319
- setIsRefreshing(false);
12320
- setHasLoaded(false);
12321
- setError(null);
12440
+ dispatch({ type: "query-cleared" });
12322
12441
  return;
12323
12442
  }
12324
12443
  if (mode === "refresh") {
12325
- setIsRefreshing(true);
12444
+ dispatch({ type: "refresh-started" });
12326
12445
  } else {
12327
- setIsLoading(true);
12328
- setIsRefreshing(false);
12329
- setSlots([]);
12446
+ dispatch({ type: "load-started" });
12330
12447
  }
12331
- setError(null);
12332
12448
  try {
12333
12449
  const result = await api.getAvailableSlots({
12334
12450
  serviceId,
@@ -12338,24 +12454,19 @@ function useAvailableSlots({
12338
12454
  resourceId
12339
12455
  });
12340
12456
  if (requestId !== requestIdRef.current) return;
12341
- setSlots(
12342
- result.slots.map((slot) => ({
12457
+ dispatch({
12458
+ type: "load-succeeded",
12459
+ slots: result.slots.map((slot) => ({
12343
12460
  ...slot,
12344
12461
  resourceId: unsafeAsAppointmentResourceId(slot.resourceId)
12345
12462
  }))
12346
- );
12347
- setHasLoaded(true);
12463
+ });
12348
12464
  } catch (err3) {
12349
12465
  if (requestId !== requestIdRef.current) return;
12350
- setError(
12351
- err3 instanceof Error ? err3.message : "Failed to load available times"
12352
- );
12353
- } finally {
12354
- if (mode === "refresh" && requestId === requestIdRef.current) {
12355
- setIsRefreshing(false);
12356
- } else if (requestId === requestIdRef.current) {
12357
- setIsLoading(false);
12358
- }
12466
+ dispatch({
12467
+ type: "load-failed",
12468
+ message: err3 instanceof Error ? err3.message : "Failed to load available times"
12469
+ });
12359
12470
  }
12360
12471
  },
12361
12472
  [selectedDate, serviceId, resourceId, timezone, api]
@@ -12372,11 +12483,17 @@ function useAvailableSlots({
12372
12483
  jitterMs: AVAILABILITY_REFRESH_JITTER_MS2,
12373
12484
  onPoll: () => fetchSlots("refresh")
12374
12485
  });
12375
- return { slots, isLoading, isRefreshing, hasLoaded, error };
12486
+ return {
12487
+ slots: getAvailableSlots(state),
12488
+ isLoading: isLoadingAvailableSlots(state),
12489
+ isRefreshing: isRefreshingAvailableSlots(state),
12490
+ hasLoaded: hasLoadedAvailableSlots(state),
12491
+ error: getAvailableSlotsError(state)
12492
+ };
12376
12493
  }
12377
12494
 
12378
12495
  // ../blocks/src/system/runtime/hooks/useBookingSubmission.ts
12379
- import { useReducer } from "react";
12496
+ import { useReducer as useReducer3 } from "react";
12380
12497
 
12381
12498
  // ../blocks/src/system/runtime/hooks/useBookingSubmission.state.ts
12382
12499
  var initialBookingSubmissionState = {
@@ -12414,7 +12531,7 @@ function selectIsSubmitting(state) {
12414
12531
  // ../blocks/src/system/runtime/hooks/useBookingSubmission.ts
12415
12532
  function useBookingSubmission(_siteId) {
12416
12533
  const api = useBlockApi();
12417
- const [state, dispatch] = useReducer(
12534
+ const [state, dispatch] = useReducer3(
12418
12535
  bookingSubmissionReducer,
12419
12536
  initialBookingSubmissionState
12420
12537
  );
@@ -12469,14 +12586,14 @@ function useBookingSubmission(_siteId) {
12469
12586
  }
12470
12587
 
12471
12588
  // ../blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.ts
12472
- import { useEffect as useEffect5, useState as useState3 } from "react";
12589
+ import { useEffect as useEffect5, useState } from "react";
12473
12590
  function useDiscountCodeUi(options) {
12474
- const [discountUiOpen, setDiscountUiOpen] = useState3(false);
12475
- const [discountCode, setDiscountCode] = useState3("");
12476
- const [discountsAvailable, setDiscountsAvailable] = useState3(false);
12477
- const [manualCodeEntryAllowed, setManualCodeEntryAllowed] = useState3(false);
12478
- const [autoAppliedDiscount, setAutoAppliedDiscount] = useState3(null);
12479
- const [discountsAvailableLoading, setDiscountsAvailableLoading] = useState3(false);
12591
+ const [discountUiOpen, setDiscountUiOpen] = useState(false);
12592
+ const [discountCode, setDiscountCode] = useState("");
12593
+ const [discountsAvailable, setDiscountsAvailable] = useState(false);
12594
+ const [manualCodeEntryAllowed, setManualCodeEntryAllowed] = useState(false);
12595
+ const [autoAppliedDiscount, setAutoAppliedDiscount] = useState(null);
12596
+ const [discountsAvailableLoading, setDiscountsAvailableLoading] = useState(false);
12480
12597
  useEffect5(() => {
12481
12598
  let cancelled = false;
12482
12599
  async function checkDiscountAvailability() {
@@ -13589,11 +13706,11 @@ function useHeadlessBookingFlow(options) {
13589
13706
  }),
13590
13707
  [defaultResourceId, defaultServiceId, options.initialData]
13591
13708
  );
13592
- const [state, dispatch] = useReducer2(bookingFlowReducer, initialState);
13709
+ const [state, dispatch] = useReducer4(bookingFlowReducer, initialState);
13593
13710
  const api = useBlockApi();
13594
- const [resourcesState, setResourcesState] = useState4({ tag: "idle" });
13711
+ const [resourcesState, setResourcesState] = useState2({ tag: "idle" });
13595
13712
  const resourcesRequestIdRef = useRef5(0);
13596
- const [appointmentPackages, setAppointmentPackages] = useState4({ tag: "idle" });
13713
+ const [appointmentPackages, setAppointmentPackages] = useState2({ tag: "idle" });
13597
13714
  const appointmentPackagesRequestIdRef = useRef5(0);
13598
13715
  const selectedServiceId = state.selectedServiceId ?? defaultServiceId;
13599
13716
  const selectedResourceId = state.selectedResourceId ?? defaultResourceId;
@@ -14166,7 +14283,7 @@ function useLatestRef(value) {
14166
14283
  import { useMemo as useMemo3 } from "react";
14167
14284
 
14168
14285
  // ../blocks/src/system/runtime/hooks/usePolling.ts
14169
- import { useEffect as useEffect7, useCallback as useCallback4, useReducer as useReducer3, useRef as useRef6 } from "react";
14286
+ import { useEffect as useEffect7, useCallback as useCallback4, useReducer as useReducer5, useRef as useRef6 } from "react";
14170
14287
 
14171
14288
  // ../blocks/src/system/runtime/hooks/usePolling.state.ts
14172
14289
  function createInitialPollingState() {
@@ -14240,7 +14357,7 @@ function pollingReducer(state, action) {
14240
14357
  var DEFAULT_MAX_ATTEMPTS = 10;
14241
14358
  var DEFAULT_POLL_INTERVAL = 1e3;
14242
14359
  function usePolling(config) {
14243
- const [state, dispatch] = useReducer3(
14360
+ const [state, dispatch] = useReducer5(
14244
14361
  pollingReducer,
14245
14362
  void 0,
14246
14363
  createInitialPollingState
@@ -15467,7 +15584,7 @@ var BookingFormClient = ({
15467
15584
  const initialResourceId = render.hydration.resourceId ?? void 0;
15468
15585
  const isPortalRebook = render.hydration.rebookContext?.kind === "portal_rebook";
15469
15586
  const hasLoggedRebookCompletionRef = useRef7(false);
15470
- const [redirectState] = useState5(
15587
+ const [redirectState] = useState3(
15471
15588
  () => getBookingRedirectStateFromLocation(getBookingRedirectLocationSnapshot())
15472
15589
  );
15473
15590
  const showSpamProtection = render.hydration.spamProtectionEnabled ?? isSpamProtectionEnabled();
@@ -16117,7 +16234,7 @@ function findSelectedTicketType(input) {
16117
16234
  }
16118
16235
 
16119
16236
  // ../blocks/src/system/runtime/nodes/event-registration/hooks.ts
16120
- import { useState as useState6, useEffect as useEffect8, useCallback as useCallback5, useRef as useRef8, useReducer as useReducer4 } from "react";
16237
+ import { useState as useState4, useEffect as useEffect8, useCallback as useCallback5, useRef as useRef8, useReducer as useReducer6 } from "react";
16121
16238
 
16122
16239
  // ../blocks/src/system/runtime/nodes/event-registration/hooks.state.ts
16123
16240
  var initialEligibilityLookupState = {
@@ -16177,8 +16294,8 @@ function existingRegistrationLookupReducer(state, action) {
16177
16294
  // ../blocks/src/system/runtime/nodes/event-registration/hooks.ts
16178
16295
  function usePortalAuth() {
16179
16296
  const api = useBlockApi();
16180
- const [authState, setAuthState] = useState6("checking");
16181
- const [profile, setProfile] = useState6(null);
16297
+ const [authState, setAuthState] = useState4("checking");
16298
+ const [profile, setProfile] = useState4(null);
16182
16299
  useEffect8(() => {
16183
16300
  let cancelled = false;
16184
16301
  async function checkPortalAuth() {
@@ -16225,7 +16342,7 @@ function usePortalAuth() {
16225
16342
  }
16226
16343
  function useEligibility(params) {
16227
16344
  const api = useBlockApi();
16228
- const [state, dispatch] = useReducer4(
16345
+ const [state, dispatch] = useReducer6(
16229
16346
  eligibilityLookupReducer,
16230
16347
  initialEligibilityLookupState
16231
16348
  );
@@ -16284,7 +16401,7 @@ function useExistingEventRegistration({
16284
16401
  occurrenceId
16285
16402
  }) {
16286
16403
  const api = useBlockApi();
16287
- const [state, dispatch] = useReducer4(
16404
+ const [state, dispatch] = useReducer6(
16288
16405
  existingRegistrationLookupReducer,
16289
16406
  initialExistingRegistrationLookupState
16290
16407
  );
@@ -16491,7 +16608,7 @@ function cleanupStaleRegistrations() {
16491
16608
  }
16492
16609
 
16493
16610
  // ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.ts
16494
- import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo6, useReducer as useReducer5, useState as useState8 } from "react";
16611
+ import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo6, useReducer as useReducer8, useState as useState5 } from "react";
16495
16612
 
16496
16613
  // ../blocks/src/system/runtime/nodes/event-registration/validation.ts
16497
16614
  function validateFormData2(formData) {
@@ -16508,7 +16625,55 @@ function validateFormData2(formData) {
16508
16625
  }
16509
16626
 
16510
16627
  // ../blocks/src/system/runtime/shared/useWaitlistClaim.ts
16511
- import { useEffect as useEffect9, useState as useState7, useSyncExternalStore } from "react";
16628
+ import { useEffect as useEffect9, useReducer as useReducer7, useSyncExternalStore } from "react";
16629
+
16630
+ // ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
16631
+ var DEFAULT_WAITLIST_CLAIM_ERROR = "Failed to resolve waitlist claim";
16632
+ function createInitialWaitlistClaimState(hasToken) {
16633
+ return hasToken ? { kind: "resolving" } : { kind: "idle" };
16634
+ }
16635
+ function waitlistClaimReducer(_state, action) {
16636
+ switch (action.type) {
16637
+ case "cleared":
16638
+ return { kind: "idle" };
16639
+ case "started":
16640
+ return { kind: "resolving" };
16641
+ case "resolved":
16642
+ return { kind: "resolved", claim: action.claim };
16643
+ case "failed":
16644
+ return action.failure;
16645
+ }
16646
+ }
16647
+ function toWaitlistClaimResolveFailure(error) {
16648
+ const message = error instanceof Error ? error.message : DEFAULT_WAITLIST_CLAIM_ERROR;
16649
+ if (isUnauthorizedBlockApiError(error)) {
16650
+ return { kind: "portal-login-required", message };
16651
+ }
16652
+ return { kind: "error", message };
16653
+ }
16654
+ function isUnauthorizedBlockApiError(error) {
16655
+ return error instanceof Error && error.name === "BlockApiError" && hasStatus(error) && error.status === 401;
16656
+ }
16657
+ function hasStatus(value) {
16658
+ return typeof value === "object" && value !== null && "status" in value;
16659
+ }
16660
+ function getWaitlistClaim(state) {
16661
+ return state.kind === "resolved" ? state.claim : null;
16662
+ }
16663
+ function getWaitlistClaimError(state) {
16664
+ return state.kind === "error" ? state.message : null;
16665
+ }
16666
+ function getWaitlistClaimLoginMessage(state) {
16667
+ return state.kind === "portal-login-required" ? state.message : null;
16668
+ }
16669
+ function requiresWaitlistClaimPortalLogin(state) {
16670
+ return state.kind === "portal-login-required";
16671
+ }
16672
+ function isWaitlistClaimLoading(state) {
16673
+ return state.kind === "resolving";
16674
+ }
16675
+
16676
+ // ../blocks/src/system/runtime/shared/useWaitlistClaim.ts
16512
16677
  var WAITLIST_CLAIM_LOCATION_EVENT = "riverbank:waitlist-claim-location-change";
16513
16678
  var historyPatched = false;
16514
16679
  function emitWaitlistClaimLocationChange() {
@@ -16566,46 +16731,29 @@ function useWaitlistClaim() {
16566
16731
  getWaitlistClaimTokenSnapshot,
16567
16732
  () => null
16568
16733
  );
16569
- const [claim, setClaim] = useState7(null);
16570
- const [error, setError] = useState7(null);
16571
- const [loginMessage, setLoginMessage] = useState7(null);
16572
- const [requiresPortalLogin, setRequiresPortalLogin] = useState7(false);
16573
- const [isLoading, setIsLoading] = useState7(() => Boolean(token));
16734
+ const [state, dispatch] = useReducer7(
16735
+ waitlistClaimReducer,
16736
+ Boolean(token),
16737
+ createInitialWaitlistClaimState
16738
+ );
16574
16739
  useEffect9(() => {
16575
16740
  let cancelled = false;
16576
16741
  async function resolveClaim() {
16577
16742
  if (!token) {
16578
- setClaim(null);
16579
- setError(null);
16580
- setLoginMessage(null);
16581
- setRequiresPortalLogin(false);
16582
- setIsLoading(false);
16743
+ dispatch({ type: "cleared" });
16583
16744
  return;
16584
16745
  }
16585
- setIsLoading(true);
16586
- setClaim(null);
16587
- setError(null);
16588
- setLoginMessage(null);
16589
- setRequiresPortalLogin(false);
16746
+ dispatch({ type: "started" });
16590
16747
  try {
16591
16748
  const result = await api.resolveWaitlistClaim({ claimToken: token });
16592
16749
  if (cancelled) return;
16593
- setClaim(result);
16750
+ dispatch({ type: "resolved", claim: result });
16594
16751
  } catch (claimError) {
16595
16752
  if (cancelled) return;
16596
- const message = claimError instanceof Error ? claimError.message : "Failed to resolve waitlist claim";
16597
- setClaim(null);
16598
- if (claimError instanceof BlockApiError && claimError.status === 401) {
16599
- setRequiresPortalLogin(true);
16600
- setLoginMessage(message);
16601
- setError(null);
16602
- } else {
16603
- setError(message);
16604
- }
16605
- } finally {
16606
- if (!cancelled) {
16607
- setIsLoading(false);
16608
- }
16753
+ dispatch({
16754
+ type: "failed",
16755
+ failure: toWaitlistClaimResolveFailure(claimError)
16756
+ });
16609
16757
  }
16610
16758
  }
16611
16759
  void resolveClaim();
@@ -16615,11 +16763,11 @@ function useWaitlistClaim() {
16615
16763
  }, [api, token]);
16616
16764
  return {
16617
16765
  token,
16618
- claim,
16619
- error,
16620
- loginMessage,
16621
- requiresPortalLogin,
16622
- isLoading
16766
+ claim: getWaitlistClaim(state),
16767
+ error: getWaitlistClaimError(state),
16768
+ loginMessage: getWaitlistClaimLoginMessage(state),
16769
+ requiresPortalLogin: requiresWaitlistClaimPortalLogin(state),
16770
+ isLoading: isWaitlistClaimLoading(state)
16623
16771
  };
16624
16772
  }
16625
16773
 
@@ -16907,7 +17055,7 @@ function useEventRegistrationWizard(options) {
16907
17055
  [scopedEvents, options.occurrenceContext]
16908
17056
  );
16909
17057
  const hasPreSelectedContext = !!(options.occurrenceContext || preSelectedEvent);
16910
- const [flowState, dispatchFlow] = useReducer5(
17058
+ const [flowState, dispatchFlow] = useReducer8(
16911
17059
  registrationFlowReducer,
16912
17060
  hasPreSelectedContext,
16913
17061
  createInitialRegistrationFlowState
@@ -16915,24 +17063,24 @@ function useEventRegistrationWizard(options) {
16915
17063
  const step = flowState.step;
16916
17064
  const ticketsCount = flowState.ticketsCount;
16917
17065
  const paymentSelection = flowState.paymentSelection;
16918
- const [selectedEvent, setSelectedEvent] = useState8(preSelectedEvent ?? null);
16919
- const [formData, setFormData] = useState8({ name: "", email: "", phone: "", notes: "" });
16920
- const [errors, setErrors] = useState8({});
16921
- const [guests, setGuests] = useState8([]);
16922
- const [guestErrors, setGuestErrors] = useState8({});
16923
- const [guestSectionShake, setGuestSectionShake] = useState8(false);
16924
- const [selectedAttendanceMode, setSelectedAttendanceMode] = useState8(
17066
+ const [selectedEvent, setSelectedEvent] = useState5(preSelectedEvent ?? null);
17067
+ const [formData, setFormData] = useState5({ name: "", email: "", phone: "", notes: "" });
17068
+ const [errors, setErrors] = useState5({});
17069
+ const [guests, setGuests] = useState5([]);
17070
+ const [guestErrors, setGuestErrors] = useState5({});
17071
+ const [guestSectionShake, setGuestSectionShake] = useState5(false);
17072
+ const [selectedAttendanceMode, setSelectedAttendanceMode] = useState5(
16925
17073
  preSelectedEvent?.deliveryMode === "online" ? "online" : preSelectedEvent?.deliveryMode === "in_person" ? "in_person" : null
16926
17074
  );
16927
- const [selectedTicketTypeId, setSelectedTicketTypeId] = useState8(null);
16928
- const [registrationResult, setRegistrationResult] = useState8(null);
16929
- const [errorMessage, setErrorMessage] = useState8("");
16930
- const [altchaSolution, setAltchaSolution] = useState8(null);
17075
+ const [selectedTicketTypeId, setSelectedTicketTypeId] = useState5(null);
17076
+ const [registrationResult, setRegistrationResult] = useState5(null);
17077
+ const [errorMessage, setErrorMessage] = useState5("");
17078
+ const [altchaSolution, setAltchaSolution] = useState5(null);
16931
17079
  const { authState: portalAuthState, profile: portalProfile } = usePortalAuth();
16932
17080
  const waitlistClaim = useWaitlistClaim();
16933
- const [showMagicLinkModal, setShowMagicLinkModal] = useState8(false);
16934
- const [pendingAttendeeId, setPendingAttendeeId] = useState8(null);
16935
- const [paymentStepState, setPaymentStepState] = useState8({
17081
+ const [showMagicLinkModal, setShowMagicLinkModal] = useState5(false);
17082
+ const [pendingAttendeeId, setPendingAttendeeId] = useState5(null);
17083
+ const [paymentStepState, setPaymentStepState] = useState5({
16936
17084
  status: "loading",
16937
17085
  canContinue: false,
16938
17086
  buttonText: "Continue",
@@ -18406,63 +18554,140 @@ function resolvePaymentModel(wizard) {
18406
18554
  }
18407
18555
 
18408
18556
  // ../blocks/src/system/runtime/hooks/useBookingFormConfig.ts
18409
- import { useState as useState9, useEffect as useEffect12 } from "react";
18557
+ import { useEffect as useEffect12, useReducer as useReducer9 } from "react";
18558
+
18559
+ // ../blocks/src/system/runtime/hooks/useBookingFormConfig.state.ts
18560
+ var EMPTY_SNAPSHOT = Object.freeze({
18561
+ formConfig: null,
18562
+ services: []
18563
+ });
18564
+ function createInitialBookingFormConfigState() {
18565
+ return {
18566
+ tag: "loading",
18567
+ previous: EMPTY_SNAPSHOT
18568
+ };
18569
+ }
18570
+ function bookingFormConfigReducer(state, action) {
18571
+ switch (action.type) {
18572
+ case "load-started":
18573
+ return {
18574
+ tag: "loading",
18575
+ previous: toBookingFormConfigSnapshot(state)
18576
+ };
18577
+ case "form-loaded": {
18578
+ const previous = toBookingFormConfigSnapshot(state);
18579
+ return {
18580
+ tag: "loading",
18581
+ previous: {
18582
+ formConfig: action.formConfig,
18583
+ services: previous.formConfig?.id === action.formConfig.id ? previous.services : []
18584
+ }
18585
+ };
18586
+ }
18587
+ case "load-succeeded":
18588
+ return {
18589
+ tag: "loaded",
18590
+ formConfig: action.formConfig,
18591
+ services: action.services
18592
+ };
18593
+ case "services-load-failed": {
18594
+ const previous = toBookingFormConfigSnapshot(state);
18595
+ return previous.formConfig ? {
18596
+ tag: "loaded",
18597
+ formConfig: previous.formConfig,
18598
+ services: previous.services
18599
+ } : {
18600
+ tag: "error",
18601
+ message: action.message,
18602
+ previous
18603
+ };
18604
+ }
18605
+ case "load-failed":
18606
+ return {
18607
+ tag: "error",
18608
+ message: action.message,
18609
+ previous: toBookingFormConfigSnapshot(state)
18610
+ };
18611
+ default:
18612
+ return assertNever11(action);
18613
+ }
18614
+ }
18615
+ function selectBookingFormConfig(state) {
18616
+ return toBookingFormConfigSnapshot(state).formConfig;
18617
+ }
18618
+ function selectBookingFormServices(state) {
18619
+ return toBookingFormConfigSnapshot(state).services;
18620
+ }
18621
+ function selectBookingFormConfigIsLoading(state) {
18622
+ return state.tag === "loading";
18623
+ }
18624
+ function selectBookingFormConfigError(state) {
18625
+ return state.tag === "error" ? state.message : null;
18626
+ }
18627
+ function toBookingFormConfigSnapshot(state) {
18628
+ switch (state.tag) {
18629
+ case "loading":
18630
+ case "error":
18631
+ return state.previous;
18632
+ case "loaded":
18633
+ return {
18634
+ formConfig: state.formConfig,
18635
+ services: state.services
18636
+ };
18637
+ default:
18638
+ return assertNever11(state);
18639
+ }
18640
+ }
18641
+
18642
+ // ../blocks/src/system/runtime/hooks/useBookingFormConfig.ts
18410
18643
  function useBookingFormConfig(siteId, formId) {
18411
18644
  const api = useBlockApi();
18412
- const [formConfig, setFormConfig] = useState9(null);
18413
- const [services, setServices] = useState9([]);
18414
- const [isLoading, setIsLoading] = useState9(true);
18415
- const [error, setError] = useState9(null);
18645
+ const [state, dispatch] = useReducer9(
18646
+ bookingFormConfigReducer,
18647
+ void 0,
18648
+ createInitialBookingFormConfigState
18649
+ );
18650
+ const formConfig = selectBookingFormConfig(state);
18651
+ const services = selectBookingFormServices(state);
18416
18652
  useEffect12(() => {
18417
18653
  let mounted = true;
18418
18654
  async function loadFormAndServices() {
18655
+ dispatch({ type: "load-started" });
18419
18656
  try {
18420
- setIsLoading(true);
18421
- setError(null);
18422
18657
  const formResponse = await api.getForm(formId, siteId);
18423
18658
  if (!mounted) return;
18424
- const rawData = formResponse.form;
18425
- const normalizedForm = {
18426
- id: rawData.id,
18427
- name: rawData.name,
18428
- slug: rawData.slug,
18429
- settings: rawData.settingsJson ?? rawData.settings,
18430
- schema: rawData.schemaJson ?? rawData.schema
18431
- };
18432
- setFormConfig(normalizedForm);
18433
- if (!normalizedForm.settings?.serviceId && !normalizedForm.settings?.serviceIds) {
18434
- try {
18435
- const servicesData = await api.getBookingServices();
18436
- if (mounted) {
18437
- setServices(servicesData.services || []);
18438
- }
18439
- } catch {
18440
- }
18441
- } else if (normalizedForm.settings?.serviceIds && normalizedForm.settings.serviceIds.length > 0) {
18442
- try {
18443
- const servicesData = await api.getBookingServices({ ids: normalizedForm.settings.serviceIds });
18444
- if (mounted) {
18445
- setServices(servicesData.services || []);
18446
- }
18447
- } catch {
18448
- }
18449
- } else if (normalizedForm.settings?.serviceId) {
18450
- try {
18451
- const serviceData = await api.getBookingService(normalizedForm.settings.serviceId);
18452
- if (mounted) {
18453
- setServices([serviceData.service]);
18454
- }
18455
- } catch {
18659
+ const normalizedForm = normalizeBookingFormConfig(formResponse.form);
18660
+ if (!normalizedForm) {
18661
+ throw new Error("Invalid booking form response.");
18662
+ }
18663
+ dispatch({
18664
+ type: "form-loaded",
18665
+ formConfig: normalizedForm
18666
+ });
18667
+ try {
18668
+ const services2 = await loadBookingFormServices(api, normalizedForm);
18669
+ if (!mounted) return;
18670
+ dispatch({
18671
+ type: "load-succeeded",
18672
+ formConfig: normalizedForm,
18673
+ services: services2
18674
+ });
18675
+ } catch (err3) {
18676
+ console.warn("Failed to load booking form services:", err3);
18677
+ if (mounted) {
18678
+ dispatch({
18679
+ type: "services-load-failed",
18680
+ message: "Failed to load booking services."
18681
+ });
18456
18682
  }
18457
18683
  }
18458
18684
  } catch (err3) {
18459
18685
  console.error("Failed to load form:", err3);
18460
18686
  if (mounted) {
18461
- setError("Failed to load booking form. Please try again later.");
18462
- }
18463
- } finally {
18464
- if (mounted) {
18465
- setIsLoading(false);
18687
+ dispatch({
18688
+ type: "load-failed",
18689
+ message: "Failed to load booking form. Please try again later."
18690
+ });
18466
18691
  }
18467
18692
  }
18468
18693
  }
@@ -18471,7 +18696,27 @@ function useBookingFormConfig(siteId, formId) {
18471
18696
  mounted = false;
18472
18697
  };
18473
18698
  }, [siteId, formId, api]);
18474
- return { formConfig, services, isLoading, error };
18699
+ return {
18700
+ formConfig,
18701
+ services,
18702
+ isLoading: selectBookingFormConfigIsLoading(state),
18703
+ error: selectBookingFormConfigError(state)
18704
+ };
18705
+ }
18706
+ async function loadBookingFormServices(api, formConfig) {
18707
+ if (!formConfig.settings?.serviceId && !formConfig.settings?.serviceIds) {
18708
+ const servicesData = await api.getBookingServices();
18709
+ return normalizeBookingServices(servicesData.services);
18710
+ }
18711
+ if (formConfig.settings?.serviceIds && formConfig.settings.serviceIds.length > 0) {
18712
+ const servicesData = await api.getBookingServices({ ids: [...formConfig.settings.serviceIds] });
18713
+ return normalizeBookingServices(servicesData.services);
18714
+ }
18715
+ if (formConfig.settings?.serviceId) {
18716
+ const serviceData = await api.getBookingService(formConfig.settings.serviceId);
18717
+ return normalizeBookingServices([serviceData.service]);
18718
+ }
18719
+ return [];
18475
18720
  }
18476
18721
 
18477
18722
  // src/bookings/index.ts