@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/README.md +362 -304
- package/dist/index.cjs +178 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +181 -111
- package/dist/index.js.map +1 -1
- package/dist/styles.css +8 -8
- package/package.json +48 -48
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.
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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",
|
|
655
|
-
|
|
691
|
+
window.addEventListener("message", configHandler);
|
|
692
|
+
window.postMessage({ type: "ow:request-schedule-config", insertAfter }, "*");
|
|
656
693
|
return () => {
|
|
657
|
-
window.removeEventListener("message",
|
|
658
|
-
|
|
694
|
+
window.removeEventListener("message", configHandler);
|
|
695
|
+
clearTimeout(timer);
|
|
696
|
+
innerCleanup?.();
|
|
659
697
|
};
|
|
660
698
|
}
|
|
661
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
if (
|
|
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()
|
|
4874
|
-
|
|
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
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
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
|
|
5381
|
-
|
|
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) => {
|