@ohhwells/bridge 0.1.28 → 0.1.29-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -212,13 +212,6 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
212
212
  var import_jsx_runtime2 = require("react/jsx-runtime");
213
213
  var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
214
214
  var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
215
- function getApiDomain() {
216
- const h = window.location.hostname;
217
- for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
218
- if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
219
- }
220
- return h;
221
- }
222
215
  function classRunsOnDate(cls, date, type) {
223
216
  if (type === "FIXED") {
224
217
  const d = String(date.getDate()).padStart(2, "0");
@@ -264,10 +257,10 @@ function buildTimezoneLabel(tz) {
264
257
  return tz;
265
258
  }
266
259
  }
267
- function EmptyState({ inEditor }) {
260
+ function EmptyState({ inEditor, insertAfter }) {
268
261
  const handleAddSchedule = () => {
269
262
  if (inEditor) {
270
- window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
263
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
271
264
  }
272
265
  };
273
266
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center justify-center gap-6 p-12 bg-[#FAFAF9] border-2 border-dashed border-[#E7E5E4] rounded-[10px] h-[264px] w-full box-border", children: [
@@ -492,18 +485,21 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
492
485
  const booked = getBookingsOnDate(cls, selectedDate);
493
486
  const available = cls.maxParticipants - booked;
494
487
  const isFull = available <= 0;
488
+ const isPrivate = cls.maxParticipants === 1;
495
489
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
496
490
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
497
491
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
498
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:w-[120px] sm:shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
499
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
500
- "span",
501
- {
502
- className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
503
- style: { borderColor: "#0885FE", color: "#0885FE" },
504
- children: "GROUP"
505
- }
506
- ),
492
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 sm:w-[120px] sm:shrink-0", children: [
493
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }),
494
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
495
+ "span",
496
+ {
497
+ className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium w-fit",
498
+ style: isPrivate ? { background: "#DDFBE3", color: "#199130", border: "1px solid #199130", fontWeight: 500 } : { background: "#EEEDFF", color: "#5953FF", border: "1px solid #5953FF", fontWeight: 500 },
499
+ children: isPrivate ? "PRIVATE" : "GROUP"
500
+ }
501
+ )
502
+ ] }),
507
503
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
508
504
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
509
505
  available,
@@ -576,7 +572,9 @@ function CalendarFoldIcon() {
576
572
  }
577
573
  );
578
574
  }
579
- function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
575
+ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter: insertAfterProp }) {
576
+ const autoId = (0, import_react2.useId)();
577
+ const insertAfter = insertAfterProp ?? autoId;
580
578
  const [schedule, setSchedule] = (0, import_react2.useState)(null);
581
579
  const [loading, setLoading] = (0, import_react2.useState)(true);
582
580
  const [inEditor, setInEditor] = (0, import_react2.useState)(false);
@@ -606,88 +604,99 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
606
604
  if (typeof window === "undefined") return;
607
605
  const isInEditor = window.self !== window.top;
608
606
  setInEditor(isInEditor);
609
- if (isInEditor) {
610
- const startEmpty = initialScheduleId === null;
611
- if (startEmpty) setLoading(false);
612
- let initialized = startEmpty;
613
- const timer = !startEmpty ? setTimeout(() => {
614
- if (!initialized) {
607
+ function loadWithId(effectiveId) {
608
+ if (isInEditor) {
609
+ const startEmpty = effectiveId === null;
610
+ if (startEmpty) setLoading(false);
611
+ let initialized = startEmpty;
612
+ const timer = !startEmpty ? setTimeout(() => {
613
+ if (!initialized) {
614
+ initialized = true;
615
+ setLoading(false);
616
+ }
617
+ }, 5e3) : null;
618
+ const handler = (e) => {
619
+ if (e.data?.type === "ow:clear-scheduling-widget") {
620
+ if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
621
+ setSchedule(null);
622
+ setLoading(false);
623
+ return;
624
+ }
625
+ if (e.data?.type === "ow:switch-schedule") {
626
+ if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
627
+ switchScheduleIdRef.current = e.data.scheduleId ?? null;
628
+ initialized = false;
629
+ setLoading(true);
630
+ window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
631
+ return;
632
+ }
633
+ if (e.data?.type !== "ow:user-schedules-response") return;
634
+ if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
635
+ if (initialized && switchScheduleIdRef.current === null) return;
615
636
  initialized = true;
637
+ if (timer) clearTimeout(timer);
638
+ const schedules = e.data.schedules ?? [];
639
+ const isSwitching = switchScheduleIdRef.current !== null;
640
+ const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : effectiveId ? schedules.find((s) => s.id === effectiveId) ?? schedules[0] ?? null : schedules[0] ?? null;
641
+ switchScheduleIdRef.current = null;
642
+ setSchedule(target);
616
643
  setLoading(false);
644
+ if (notifyOnConnect && target && !isSwitching) {
645
+ window.parent.postMessage({
646
+ type: "ow:schedule-connected",
647
+ schedule: { id: target.id, name: target.name },
648
+ insertAfter
649
+ }, "*");
650
+ window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
651
+ }
652
+ };
653
+ window.addEventListener("message", handler);
654
+ if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
655
+ return () => {
656
+ window.removeEventListener("message", handler);
657
+ if (timer) clearTimeout(timer);
658
+ };
659
+ }
660
+ if (!effectiveId) {
661
+ setLoading(false);
662
+ return;
663
+ }
664
+ ;
665
+ (async () => {
666
+ try {
667
+ const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
668
+ const data = await res.json();
669
+ setSchedule(data?.id ? data : null);
670
+ } catch {
617
671
  }
618
- }, 5e3) : null;
619
- const handler = (e) => {
620
- if (e.data?.type === "ow:clear-scheduling-widget") {
621
- if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
622
- setSchedule(null);
623
- setLoading(false);
624
- return;
625
- }
626
- if (e.data?.type === "ow:switch-schedule") {
627
- if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
628
- switchScheduleIdRef.current = e.data.scheduleId ?? null;
629
- initialized = false;
630
- setLoading(true);
631
- window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
632
- return;
633
- }
634
- if (e.data?.type !== "ow:user-schedules-response") return;
635
- if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
636
- if (initialized && switchScheduleIdRef.current === null) return;
637
- initialized = true;
638
- if (timer) clearTimeout(timer);
639
- const schedules = e.data.schedules ?? [];
640
- const isSwitching = switchScheduleIdRef.current !== null;
641
- const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : initialScheduleId ? schedules.find((s) => s.id === initialScheduleId) ?? schedules[0] ?? null : schedules[0] ?? null;
642
- switchScheduleIdRef.current = null;
643
- setSchedule(target);
644
672
  setLoading(false);
645
- if (notifyOnConnect && target && !isSwitching) {
646
- window.parent.postMessage({
647
- type: "ow:schedule-connected",
648
- schedule: { id: target.id, name: target.name },
649
- insertAfter
650
- }, "*");
651
- window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
673
+ })();
674
+ }
675
+ if (initialScheduleId === void 0) {
676
+ let done = false;
677
+ let innerCleanup;
678
+ const timer = setTimeout(() => {
679
+ if (!done) {
680
+ done = true;
681
+ setLoading(false);
652
682
  }
683
+ }, 2e3);
684
+ const configHandler = (e) => {
685
+ if (e.data?.type !== "ow:schedule-config" || e.data.insertAfter !== insertAfter || done) return;
686
+ done = true;
687
+ clearTimeout(timer);
688
+ window.removeEventListener("message", configHandler);
689
+ innerCleanup = loadWithId(e.data.scheduleId ?? null);
653
690
  };
654
- window.addEventListener("message", handler);
655
- if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
691
+ window.addEventListener("message", configHandler);
692
+ window.postMessage({ type: "ow:request-schedule-config", insertAfter }, "*");
656
693
  return () => {
657
- window.removeEventListener("message", handler);
658
- if (timer) clearTimeout(timer);
694
+ window.removeEventListener("message", configHandler);
695
+ clearTimeout(timer);
696
+ innerCleanup?.();
659
697
  };
660
698
  }
661
- if (initialScheduleId === null) {
662
- setLoading(false);
663
- return;
664
- }
665
- ;
666
- (async () => {
667
- try {
668
- if (initialScheduleId) {
669
- const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
670
- const data = await res.json();
671
- setSchedule(data?.id ? data : null);
672
- } else {
673
- const domain = getApiDomain();
674
- const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
675
- const slugs = await sitemapRes.json();
676
- if (!Array.isArray(slugs) || !slugs.length) {
677
- setLoading(false);
678
- return;
679
- }
680
- const { slug } = [...slugs].sort(
681
- (a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
682
- )[0];
683
- const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
684
- const data = await res.json();
685
- setSchedule(data?.id ? data : null);
686
- }
687
- } catch {
688
- }
689
- setLoading(false);
690
- })();
699
+ return loadWithId(initialScheduleId) ?? void 0;
691
700
  }, []);
692
701
  const timezoneLabel = schedule?.timezone ? (() => {
693
702
  try {
@@ -722,6 +731,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
722
731
  window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
723
732
  }
724
733
  };
734
+ if (!inEditor && !loading && !schedule) return null;
725
735
  const sectionId = `scheduling-${insertAfter}`;
726
736
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
727
737
  "section",
@@ -767,7 +777,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
767
777
  ] }),
768
778
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
769
779
  timezoneLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
770
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { inEditor }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
780
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { inEditor, insertAfter }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
771
781
  ScheduleView,
772
782
  {
773
783
  schedule,
@@ -4311,7 +4321,10 @@ function isValidUrl(urlString) {
4311
4321
  const hostname = url.hostname;
4312
4322
  if (!hostname || hostname.length === 0) return false;
4313
4323
  if (hostname.includes(" ")) return false;
4314
- return hostname.includes(".") || hostname === "localhost";
4324
+ if (hostname === "localhost") return true;
4325
+ if (!hostname.includes(".")) return false;
4326
+ if (!/[a-z]/i.test(hostname)) return false;
4327
+ return true;
4315
4328
  } catch {
4316
4329
  return false;
4317
4330
  }
@@ -4322,12 +4335,19 @@ function normalizeUrl(value) {
4322
4335
  return `https://${trimmed}`;
4323
4336
  }
4324
4337
  function validateUrlInput(value, pages, allPages) {
4325
- if (!value.trim()) return "";
4326
- const filtered = pages.filter((p) => p.title.toLowerCase().startsWith(value.toLowerCase()));
4327
- if (filtered.length > 0) return "";
4328
- const matchingPage = allPages.find((p) => p.title.toLowerCase() === value.toLowerCase());
4329
- if (matchingPage) return "";
4330
- if (!isValidUrl(normalizeUrl(value))) {
4338
+ const trimmed = value.trim();
4339
+ if (!trimmed) return "";
4340
+ const exactPage = allPages.find((p) => p.title.toLowerCase() === trimmed.toLowerCase());
4341
+ if (exactPage) return "";
4342
+ const hasPrefixMatch = pages.some((p) => p.title.toLowerCase().startsWith(trimmed.toLowerCase()));
4343
+ if (hasPrefixMatch) {
4344
+ return "Select a page from the list or enter a valid URL";
4345
+ }
4346
+ const hasScheme = /^https?:\/\//i.test(trimmed);
4347
+ if (!hasScheme && !trimmed.includes(".")) {
4348
+ return "Please enter a valid URL (e.g., https://example.com)";
4349
+ }
4350
+ if (!isValidUrl(normalizeUrl(trimmed))) {
4331
4351
  return "Please enter a valid URL (e.g., https://example.com)";
4332
4352
  }
4333
4353
  return "";
@@ -4870,9 +4890,8 @@ function useLinkModalState({
4870
4890
  setUrlError("");
4871
4891
  const filtered = value.trim() ? availablePages.filter((p) => p.title.toLowerCase().startsWith(value.toLowerCase())) : availablePages;
4872
4892
  setDropdownOpen(filtered.length > 0);
4873
- if (value.trim() && filtered.length === 0) {
4874
- const error = validateUrlInput(value, availablePages, pages);
4875
- if (error) setUrlError(error);
4893
+ if (value.trim()) {
4894
+ setUrlError(validateUrlInput(value, availablePages, pages));
4876
4895
  }
4877
4896
  };
4878
4897
  const handlePageSelect = (page) => {
@@ -5316,9 +5335,14 @@ function initSectionsFromContent(content, removeExisting = false) {
5316
5335
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
5317
5336
  if (inEditor) getSectionsTracker().textContent = raw;
5318
5337
  const pageEntries = getPageSchedulingEntries(raw);
5319
- mountSchedulingEntries(pageEntries, false);
5320
- requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
5321
- setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
5338
+ const preExisting = pageEntries.filter((e) => !isSchedulingWidgetMissing(e));
5339
+ const notifyForEntry = inEditor ? (e) => !e.scheduleId : false;
5340
+ mountSchedulingEntries(pageEntries, notifyForEntry);
5341
+ requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry));
5342
+ setTimeout(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry), 250);
5343
+ for (const entry of preExisting) {
5344
+ window.postMessage({ type: "ow:schedule-config", insertAfter: entry.insertAfter, scheduleId: entry.scheduleId ?? null }, "*");
5345
+ }
5322
5346
  } catch {
5323
5347
  }
5324
5348
  }
@@ -5377,8 +5401,9 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
5377
5401
  const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
5378
5402
  for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
5379
5403
  for (let i = pending.length - 1; i >= 0; i--) {
5380
- const { insertAfter, scheduleId } = pending[i];
5381
- if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
5404
+ const entry = pending[i];
5405
+ const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
5406
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
5382
5407
  pending.splice(i, 1);
5383
5408
  }
5384
5409
  }
@@ -5856,6 +5881,8 @@ function OhhwellsBridge() {
5856
5881
  });
5857
5882
  const postToParentRef = (0, import_react5.useRef)(postToParent);
5858
5883
  postToParentRef.current = postToParent;
5884
+ const sectionsLoadedRef = (0, import_react5.useRef)(false);
5885
+ const pendingScheduleConfigRequests = (0, import_react5.useRef)([]);
5859
5886
  const [toolbarRect, setToolbarRect] = (0, import_react5.useState)(null);
5860
5887
  const [toggleState, setToggleState] = (0, import_react5.useState)(null);
5861
5888
  const [maxBadge, setMaxBadge] = (0, import_react5.useState)(null);
@@ -5961,6 +5988,29 @@ function OhhwellsBridge() {
5961
5988
  const refreshStateRules = (0, import_react5.useCallback)(() => {
5962
5989
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
5963
5990
  }, []);
5991
+ const processConfigRequest = (0, import_react5.useCallback)((insertAfterVal) => {
5992
+ const tracker = getSectionsTracker();
5993
+ let entries = [];
5994
+ try {
5995
+ entries = JSON.parse(tracker.textContent || "[]");
5996
+ } catch {
5997
+ }
5998
+ const path = window.location.pathname;
5999
+ const entry = entries.find(
6000
+ (e) => e.type === "scheduling" && e.insertAfter === insertAfterVal && (!e.pagePath || e.pagePath === path)
6001
+ );
6002
+ if (entry) {
6003
+ window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: entry.scheduleId ?? null }, "*");
6004
+ return;
6005
+ }
6006
+ const newEntry = { type: "scheduling", insertAfter: insertAfterVal, pagePath: path };
6007
+ entries.push(newEntry);
6008
+ tracker.textContent = JSON.stringify(entries);
6009
+ if (isEditMode) {
6010
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
6011
+ }
6012
+ window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6013
+ }, [isEditMode]);
5964
6014
  const deactivate = (0, import_react5.useCallback)(() => {
5965
6015
  const el = activeElRef.current;
5966
6016
  if (!el) return;
@@ -6037,6 +6087,8 @@ function OhhwellsBridge() {
6037
6087
  applyLinkByKey(key, val);
6038
6088
  }
6039
6089
  initSectionsFromContent(content, true);
6090
+ sectionsLoadedRef.current = true;
6091
+ pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
6040
6092
  return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
6041
6093
  }) : Promise.resolve();
6042
6094
  };
@@ -6733,6 +6785,8 @@ function OhhwellsBridge() {
6733
6785
  }
6734
6786
  if (sectionsJson) {
6735
6787
  initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
6788
+ sectionsLoadedRef.current = true;
6789
+ pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
6736
6790
  }
6737
6791
  postToParentRef.current({ type: "ow:hydrate-done" });
6738
6792
  };
@@ -7005,6 +7059,22 @@ function OhhwellsBridge() {
7005
7059
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
7006
7060
  };
7007
7061
  }, [isEditMode, refreshStateRules]);
7062
+ (0, import_react5.useEffect)(() => {
7063
+ const handler = (e) => {
7064
+ if (e.data?.type !== "ow:request-schedule-config") return;
7065
+ const insertAfterVal = e.data.insertAfter;
7066
+ if (!insertAfterVal) return;
7067
+ if (!sectionsLoadedRef.current) {
7068
+ if (!pendingScheduleConfigRequests.current.includes(insertAfterVal)) {
7069
+ pendingScheduleConfigRequests.current.push(insertAfterVal);
7070
+ }
7071
+ return;
7072
+ }
7073
+ processConfigRequest(insertAfterVal);
7074
+ };
7075
+ window.addEventListener("message", handler);
7076
+ return () => window.removeEventListener("message", handler);
7077
+ }, [processConfigRequest]);
7008
7078
  (0, import_react5.useEffect)(() => {
7009
7079
  if (!isEditMode) return;
7010
7080
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {