@ohhwells/bridge 0.1.20 → 0.1.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 +325 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +323 -129
- package/dist/index.js.map +1 -1
- package/dist/styles.css +81 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
4
|
import React3, { useCallback, useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
|
+
import { flushSync } from "react-dom";
|
|
6
7
|
|
|
7
8
|
// src/ui/SchedulingWidget.tsx
|
|
8
9
|
import { useEffect, useMemo, useRef, useState as useState2 } from "react";
|
|
@@ -270,7 +271,19 @@ function LoadingSkeleton() {
|
|
|
270
271
|
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
|
|
271
272
|
] }, i)) }),
|
|
272
273
|
[0, 1, 2].map((i) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
273
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex
|
|
274
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-4 py-4 sm:hidden", children: [
|
|
275
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2 shrink-0", children: [
|
|
276
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "100px", height: "16px", borderRadius: "4px" } }),
|
|
277
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "52px", height: "20px", borderRadius: "999px" } }),
|
|
278
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "60px", height: "14px", borderRadius: "4px" } })
|
|
279
|
+
] }),
|
|
280
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
281
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "75%", height: "16px", borderRadius: "4px" } }),
|
|
282
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "50%", height: "14px", borderRadius: "4px" } }),
|
|
283
|
+
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "100%", height: "44px", borderRadius: "8px" } })
|
|
284
|
+
] })
|
|
285
|
+
] }),
|
|
286
|
+
/* @__PURE__ */ jsxs2("div", { className: "hidden sm:flex items-center gap-[60px] py-4", children: [
|
|
274
287
|
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
|
|
275
288
|
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
276
289
|
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
|
|
@@ -313,6 +326,28 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
313
326
|
const scroll = (dir) => {
|
|
314
327
|
scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
|
|
315
328
|
};
|
|
329
|
+
const isDragging = useRef(false);
|
|
330
|
+
const dragStartX = useRef(0);
|
|
331
|
+
const dragStartScrollLeft = useRef(0);
|
|
332
|
+
const onDragStart = (e) => {
|
|
333
|
+
if (!scrollRef.current) return;
|
|
334
|
+
isDragging.current = true;
|
|
335
|
+
dragStartX.current = e.clientX;
|
|
336
|
+
dragStartScrollLeft.current = scrollRef.current.scrollLeft;
|
|
337
|
+
scrollRef.current.style.cursor = "grabbing";
|
|
338
|
+
scrollRef.current.style.userSelect = "none";
|
|
339
|
+
};
|
|
340
|
+
const onDragMove = (e) => {
|
|
341
|
+
if (!isDragging.current || !scrollRef.current) return;
|
|
342
|
+
const delta = e.clientX - dragStartX.current;
|
|
343
|
+
scrollRef.current.scrollLeft = dragStartScrollLeft.current - delta;
|
|
344
|
+
};
|
|
345
|
+
const onDragEnd = () => {
|
|
346
|
+
if (!scrollRef.current) return;
|
|
347
|
+
isDragging.current = false;
|
|
348
|
+
scrollRef.current.style.cursor = "grab";
|
|
349
|
+
scrollRef.current.style.userSelect = "";
|
|
350
|
+
};
|
|
316
351
|
const datesWithClasses = useMemo(
|
|
317
352
|
() => new Set(dates.map(
|
|
318
353
|
(d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
|
|
@@ -330,7 +365,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
330
365
|
"button",
|
|
331
366
|
{
|
|
332
367
|
onClick: () => scroll("left"),
|
|
333
|
-
className: "absolute left-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8
|
|
368
|
+
className: "hidden sm:flex absolute left-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8 items-center justify-center rounded-full border-none cursor-pointer",
|
|
334
369
|
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
335
370
|
"aria-label": "Scroll left",
|
|
336
371
|
children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "var(--color-dark,#200C02)", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("polyline", { points: "15 18 9 12 15 6" }) })
|
|
@@ -340,23 +375,36 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
340
375
|
"button",
|
|
341
376
|
{
|
|
342
377
|
onClick: () => scroll("right"),
|
|
343
|
-
className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8
|
|
378
|
+
className: "hidden sm:flex absolute right-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8 items-center justify-center rounded-full border-none cursor-pointer",
|
|
344
379
|
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
345
380
|
"aria-label": "Scroll right",
|
|
346
381
|
children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "var(--color-dark,#200C02)", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("polyline", { points: "9 18 15 12 9 6" }) })
|
|
347
382
|
}
|
|
348
383
|
),
|
|
384
|
+
canScrollLeft && /* @__PURE__ */ jsx2(
|
|
385
|
+
"div",
|
|
386
|
+
{
|
|
387
|
+
className: "sm:hidden absolute left-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
388
|
+
style: { background: "linear-gradient(to right, var(--color-light,#FEFFF0), transparent)" }
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
canScrollRight && /* @__PURE__ */ jsx2(
|
|
392
|
+
"div",
|
|
393
|
+
{
|
|
394
|
+
className: "sm:hidden absolute right-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
395
|
+
style: { background: "linear-gradient(to left, var(--color-light,#FEFFF0), transparent)" }
|
|
396
|
+
}
|
|
397
|
+
),
|
|
349
398
|
/* @__PURE__ */ jsx2(
|
|
350
399
|
"div",
|
|
351
400
|
{
|
|
352
401
|
ref: scrollRef,
|
|
353
402
|
className: "overflow-x-auto w-full",
|
|
354
|
-
style: {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
},
|
|
403
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none", touchAction: "pan-x", cursor: "grab" },
|
|
404
|
+
onMouseDown: onDragStart,
|
|
405
|
+
onMouseMove: onDragMove,
|
|
406
|
+
onMouseUp: onDragEnd,
|
|
407
|
+
onMouseLeave: onDragEnd,
|
|
360
408
|
children: /* @__PURE__ */ jsx2("div", { className: "flex", style: { width: `max(100%, ${dates.length * 60}px)` }, children: dates.map((date, i) => {
|
|
361
409
|
const isToday = date.getTime() === todayMs;
|
|
362
410
|
const isSelected = i === selectedIdx;
|
|
@@ -397,40 +445,60 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
397
445
|
const available = cls.maxParticipants - booked;
|
|
398
446
|
const isFull = available <= 0;
|
|
399
447
|
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
400
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-[60px]
|
|
401
|
-
/* @__PURE__ */
|
|
402
|
-
|
|
403
|
-
/* @__PURE__ */ jsx2(
|
|
404
|
-
|
|
448
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
|
|
449
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
|
|
450
|
+
/* @__PURE__ */ jsx2("div", { className: "sm:w-[120px] sm:shrink-0", children: /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
|
|
451
|
+
/* @__PURE__ */ jsx2(
|
|
452
|
+
"span",
|
|
453
|
+
{
|
|
454
|
+
className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
|
|
455
|
+
style: { borderColor: "#0885FE", color: "#0885FE" },
|
|
456
|
+
children: "GROUP"
|
|
457
|
+
}
|
|
458
|
+
),
|
|
459
|
+
/* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
460
|
+
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
461
|
+
available,
|
|
462
|
+
"/",
|
|
463
|
+
cls.maxParticipants
|
|
464
|
+
] }),
|
|
465
|
+
/* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
466
|
+
] }) })
|
|
405
467
|
] }),
|
|
406
|
-
/* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */ jsxs2("
|
|
408
|
-
|
|
409
|
-
"
|
|
410
|
-
cls.maxParticipants
|
|
468
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
469
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
470
|
+
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
471
|
+
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
411
472
|
] }),
|
|
412
|
-
/* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
473
|
+
/* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
474
|
+
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
475
|
+
available,
|
|
476
|
+
"/",
|
|
477
|
+
cls.maxParticipants
|
|
478
|
+
] }),
|
|
479
|
+
/* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
480
|
+
] }) }),
|
|
481
|
+
/* @__PURE__ */ jsx2(
|
|
482
|
+
"button",
|
|
483
|
+
{
|
|
484
|
+
className: "w-full sm:w-[200px] sm:shrink-0 px-5 py-[10px] flex items-center justify-center rounded-lg font-body text-base font-bold cursor-pointer box-border",
|
|
485
|
+
style: isFull ? {
|
|
486
|
+
background: "transparent",
|
|
487
|
+
border: "1px solid var(--color-dark, #200C02)",
|
|
488
|
+
color: "var(--color-dark, #200C02)"
|
|
489
|
+
} : {
|
|
490
|
+
background: "var(--color-primary, #3D312B)",
|
|
491
|
+
border: "none",
|
|
492
|
+
color: "var(--color-light, #FEFFF0)"
|
|
493
|
+
},
|
|
494
|
+
onClick: () => {
|
|
495
|
+
if (!cls.id) return;
|
|
496
|
+
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
497
|
+
},
|
|
498
|
+
children: isFull ? "Join Waitlist" : "Book Now"
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
] })
|
|
434
502
|
] }),
|
|
435
503
|
i < selectedClasses.length - 1 && /* @__PURE__ */ jsx2("div", { className: "h-px bg-black/20" })
|
|
436
504
|
] }, cls.id ?? i);
|
|
@@ -460,7 +528,7 @@ function CalendarFoldIcon() {
|
|
|
460
528
|
}
|
|
461
529
|
);
|
|
462
530
|
}
|
|
463
|
-
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
531
|
+
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
|
|
464
532
|
const [schedule, setSchedule] = useState2(null);
|
|
465
533
|
const [loading, setLoading] = useState2(true);
|
|
466
534
|
const [inEditor, setInEditor] = useState2(false);
|
|
@@ -502,18 +570,21 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
502
570
|
}, 5e3) : null;
|
|
503
571
|
const handler = (e) => {
|
|
504
572
|
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
573
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
505
574
|
setSchedule(null);
|
|
506
575
|
setLoading(false);
|
|
507
576
|
return;
|
|
508
577
|
}
|
|
509
578
|
if (e.data?.type === "ow:switch-schedule") {
|
|
579
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
510
580
|
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
511
581
|
initialized = false;
|
|
512
582
|
setLoading(true);
|
|
513
|
-
window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
583
|
+
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
514
584
|
return;
|
|
515
585
|
}
|
|
516
586
|
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
587
|
+
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
517
588
|
if (initialized && switchScheduleIdRef.current === null) return;
|
|
518
589
|
initialized = true;
|
|
519
590
|
if (timer) clearTimeout(timer);
|
|
@@ -524,11 +595,16 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
524
595
|
setSchedule(target);
|
|
525
596
|
setLoading(false);
|
|
526
597
|
if (notifyOnConnect && target && !isSwitching) {
|
|
527
|
-
window.parent.postMessage({
|
|
598
|
+
window.parent.postMessage({
|
|
599
|
+
type: "ow:schedule-connected",
|
|
600
|
+
schedule: { id: target.id, name: target.name },
|
|
601
|
+
insertAfter
|
|
602
|
+
}, "*");
|
|
603
|
+
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
528
604
|
}
|
|
529
605
|
};
|
|
530
606
|
window.addEventListener("message", handler);
|
|
531
|
-
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
607
|
+
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
532
608
|
return () => {
|
|
533
609
|
window.removeEventListener("message", handler);
|
|
534
610
|
if (timer) clearTimeout(timer);
|
|
@@ -589,16 +665,22 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
589
665
|
const handleReplaceSchedule = () => {
|
|
590
666
|
setIsHovered(false);
|
|
591
667
|
if (schedule) {
|
|
592
|
-
window.parent.postMessage({
|
|
668
|
+
window.parent.postMessage({
|
|
669
|
+
type: "ow:schedule-connected",
|
|
670
|
+
schedule: { id: schedule.id, name: schedule.name },
|
|
671
|
+
insertAfter
|
|
672
|
+
}, "*");
|
|
593
673
|
} else {
|
|
594
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
674
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
595
675
|
}
|
|
596
676
|
};
|
|
677
|
+
const sectionId = `scheduling-${insertAfter}`;
|
|
597
678
|
return /* @__PURE__ */ jsxs2(
|
|
598
679
|
"section",
|
|
599
680
|
{
|
|
600
|
-
"data-ohw-section":
|
|
601
|
-
|
|
681
|
+
"data-ohw-section": sectionId,
|
|
682
|
+
"data-ohw-scheduling-anchor": insertAfter,
|
|
683
|
+
className: "w-full box-border py-10 px-5 sm:py-20 sm:px-16 font-body bg-(--color-light,#FEFFF0) relative",
|
|
602
684
|
onMouseEnter: () => inEditor && setIsHovered(true),
|
|
603
685
|
onMouseLeave: () => setIsHovered(false),
|
|
604
686
|
children: [
|
|
@@ -632,12 +714,12 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
632
714
|
),
|
|
633
715
|
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
634
716
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
635
|
-
/* @__PURE__ */ jsx2("h2", { className: "font-display text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
|
|
717
|
+
/* @__PURE__ */ jsx2("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
|
|
636
718
|
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
637
719
|
] }),
|
|
638
720
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
639
721
|
timezoneLabel && /* @__PURE__ */ jsx2("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
640
|
-
/* @__PURE__ */ jsx2("div", { className: "w-full p-10 box-border", children: loading ? /* @__PURE__ */ jsx2(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx2(EmptyState, { inEditor }) : /* @__PURE__ */ jsx2(
|
|
722
|
+
/* @__PURE__ */ jsx2("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ jsx2(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx2(EmptyState, { inEditor }) : /* @__PURE__ */ jsx2(
|
|
641
723
|
ScheduleView,
|
|
642
724
|
{
|
|
643
725
|
schedule,
|
|
@@ -4177,24 +4259,135 @@ function getSectionsTracker() {
|
|
|
4177
4259
|
}
|
|
4178
4260
|
return el;
|
|
4179
4261
|
}
|
|
4180
|
-
function
|
|
4181
|
-
const
|
|
4182
|
-
|
|
4183
|
-
|
|
4262
|
+
function updateSectionScheduleId(insertAfter, scheduleId) {
|
|
4263
|
+
const tracker = getSectionsTracker();
|
|
4264
|
+
let sections = [];
|
|
4265
|
+
try {
|
|
4266
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
4267
|
+
} catch {
|
|
4268
|
+
}
|
|
4269
|
+
const currentPath = window.location.pathname;
|
|
4270
|
+
const updated = sections.map((s) => {
|
|
4271
|
+
if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
|
|
4272
|
+
if (s.pagePath && s.pagePath !== currentPath) return s;
|
|
4273
|
+
return { ...s, scheduleId };
|
|
4274
|
+
});
|
|
4275
|
+
tracker.textContent = JSON.stringify(updated);
|
|
4276
|
+
return tracker.textContent ?? "[]";
|
|
4277
|
+
}
|
|
4278
|
+
function schedulingSectionId(insertAfter) {
|
|
4279
|
+
return `scheduling-${insertAfter}`;
|
|
4280
|
+
}
|
|
4281
|
+
var INSERT_BEFORE_MARKER = ":before:";
|
|
4282
|
+
function parseSchedulingInsertAfter(insertAfter) {
|
|
4283
|
+
const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
|
|
4284
|
+
if (idx < 0) return { anchor: insertAfter, insertBefore: null };
|
|
4285
|
+
return {
|
|
4286
|
+
anchor: insertAfter.slice(0, idx),
|
|
4287
|
+
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
4288
|
+
};
|
|
4289
|
+
}
|
|
4290
|
+
function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
|
|
4291
|
+
const parsed = parseSchedulingInsertAfter(insertAfter);
|
|
4292
|
+
const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
|
|
4293
|
+
const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
|
|
4294
|
+
return { effectiveInsertAfter, insertBefore };
|
|
4295
|
+
}
|
|
4296
|
+
function getSchedulingMountPoint(insertAfter) {
|
|
4297
|
+
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
4298
|
+
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
4299
|
+
if (!anchorEl && anchor === "scheduling") {
|
|
4300
|
+
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
4301
|
+
anchorEl = widgets.at(-1) ?? null;
|
|
4302
|
+
}
|
|
4303
|
+
if (!anchorEl) return null;
|
|
4304
|
+
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
4305
|
+
}
|
|
4306
|
+
function schedulingMountDepth(insertAfter) {
|
|
4307
|
+
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
4308
|
+
return insertAfter.split(INSERT_BEFORE_MARKER).length - 1;
|
|
4309
|
+
}
|
|
4310
|
+
function getPageSchedulingEntries(raw) {
|
|
4311
|
+
if (!raw) return [];
|
|
4312
|
+
try {
|
|
4313
|
+
const entries = JSON.parse(raw);
|
|
4314
|
+
const currentPath = window.location.pathname;
|
|
4315
|
+
return entries.filter((e) => e.type === "scheduling" && (!e.pagePath || e.pagePath === currentPath));
|
|
4316
|
+
} catch {
|
|
4317
|
+
return [];
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
function isSchedulingWidgetMissing(entry) {
|
|
4321
|
+
const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
|
|
4322
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
4323
|
+
}
|
|
4324
|
+
function hasMissingSchedulingWidgets(entries) {
|
|
4325
|
+
return entries.some(isSchedulingWidgetMissing);
|
|
4326
|
+
}
|
|
4327
|
+
function retryMissingSchedulingMounts(entries, notifyOnConnect = false) {
|
|
4328
|
+
if (!hasMissingSchedulingWidgets(entries)) return;
|
|
4329
|
+
mountSchedulingEntries(entries, notifyOnConnect);
|
|
4330
|
+
}
|
|
4331
|
+
function initSectionsFromContent(content, removeExisting = false) {
|
|
4332
|
+
const raw = content["__ohw_sections"];
|
|
4333
|
+
if (!raw) return;
|
|
4334
|
+
try {
|
|
4335
|
+
if (removeExisting) {
|
|
4336
|
+
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => el.remove());
|
|
4337
|
+
}
|
|
4338
|
+
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
4339
|
+
if (inEditor) getSectionsTracker().textContent = raw;
|
|
4340
|
+
const pageEntries = getPageSchedulingEntries(raw);
|
|
4341
|
+
mountSchedulingEntries(pageEntries, false);
|
|
4342
|
+
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
|
|
4343
|
+
setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
|
|
4344
|
+
} catch {
|
|
4345
|
+
}
|
|
4346
|
+
}
|
|
4347
|
+
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
|
|
4348
|
+
const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
|
|
4349
|
+
const sectionId = schedulingSectionId(effectiveInsertAfter);
|
|
4350
|
+
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
4351
|
+
const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
|
|
4352
|
+
if (!mountPoint) return false;
|
|
4184
4353
|
const container = document.createElement("div");
|
|
4185
4354
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
4186
|
-
|
|
4187
|
-
|
|
4355
|
+
if (insertBefore) {
|
|
4356
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
|
|
4357
|
+
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
4358
|
+
if (!beforePoint) return false;
|
|
4359
|
+
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
4360
|
+
} else {
|
|
4361
|
+
let tail = mountPoint;
|
|
4362
|
+
while (tail.nextElementSibling?.dataset.ohwSectionContainer === "scheduling") {
|
|
4363
|
+
tail = tail.nextElementSibling;
|
|
4364
|
+
}
|
|
4365
|
+
tail.insertAdjacentElement("afterend", container);
|
|
4366
|
+
}
|
|
4367
|
+
const root = createRoot(container);
|
|
4368
|
+
flushSync(() => {
|
|
4369
|
+
root.render(
|
|
4370
|
+
/* @__PURE__ */ jsx6(
|
|
4371
|
+
SchedulingWidget,
|
|
4372
|
+
{
|
|
4373
|
+
notifyOnConnect,
|
|
4374
|
+
initialScheduleId: scheduleId,
|
|
4375
|
+
insertAfter: effectiveInsertAfter
|
|
4376
|
+
}
|
|
4377
|
+
)
|
|
4378
|
+
);
|
|
4379
|
+
});
|
|
4188
4380
|
const tracker = getSectionsTracker();
|
|
4189
4381
|
let sections = [];
|
|
4190
4382
|
try {
|
|
4191
4383
|
sections = JSON.parse(tracker.textContent || "[]");
|
|
4192
4384
|
} catch {
|
|
4193
4385
|
}
|
|
4194
|
-
|
|
4386
|
+
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
4387
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
|
|
4195
4388
|
sections.push({
|
|
4196
4389
|
type: "scheduling",
|
|
4197
|
-
insertAfter,
|
|
4390
|
+
insertAfter: effectiveInsertAfter,
|
|
4198
4391
|
pagePath: window.location.pathname,
|
|
4199
4392
|
...scheduleId ? { scheduleId } : {}
|
|
4200
4393
|
});
|
|
@@ -4202,6 +4395,17 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId)
|
|
|
4202
4395
|
}
|
|
4203
4396
|
return true;
|
|
4204
4397
|
}
|
|
4398
|
+
function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
4399
|
+
const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
|
|
4400
|
+
for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
|
|
4401
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
4402
|
+
const { insertAfter, scheduleId } = pending[i];
|
|
4403
|
+
if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
|
|
4404
|
+
pending.splice(i, 1);
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4205
4409
|
function collectEditableNodes() {
|
|
4206
4410
|
return Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
4207
4411
|
if (el.dataset.ohwEditable === "image") {
|
|
@@ -4515,6 +4719,23 @@ function StateToggle({
|
|
|
4515
4719
|
);
|
|
4516
4720
|
}
|
|
4517
4721
|
var contentCache = /* @__PURE__ */ new Map();
|
|
4722
|
+
function resolveSubdomain(subdomainFromQuery) {
|
|
4723
|
+
if (subdomainFromQuery) return subdomainFromQuery;
|
|
4724
|
+
if (typeof window !== "undefined") {
|
|
4725
|
+
const parts = window.location.hostname.split(".");
|
|
4726
|
+
if (parts.length >= 3 && parts[0] !== "www") return parts[0];
|
|
4727
|
+
}
|
|
4728
|
+
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
|
|
4729
|
+
if (siteUrl) {
|
|
4730
|
+
try {
|
|
4731
|
+
const host = new URL(siteUrl).hostname;
|
|
4732
|
+
const siteParts = host.split(".");
|
|
4733
|
+
if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
|
|
4734
|
+
} catch {
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
return "";
|
|
4738
|
+
}
|
|
4518
4739
|
function OhhwellsBridge() {
|
|
4519
4740
|
const pathname = usePathname();
|
|
4520
4741
|
const router = useRouter();
|
|
@@ -4544,11 +4765,7 @@ function OhhwellsBridge() {
|
|
|
4544
4765
|
};
|
|
4545
4766
|
}, []);
|
|
4546
4767
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
4547
|
-
const subdomain = subdomainFromQuery
|
|
4548
|
-
if (typeof window === "undefined") return "";
|
|
4549
|
-
const parts = window.location.hostname.split(".");
|
|
4550
|
-
return parts.length >= 3 && parts[0] !== "www" ? parts[0] : "";
|
|
4551
|
-
})();
|
|
4768
|
+
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
4552
4769
|
const postToParent = useCallback((data) => {
|
|
4553
4770
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
4554
4771
|
window.parent.postMessage(data, "*");
|
|
@@ -4658,18 +4875,6 @@ function OhhwellsBridge() {
|
|
|
4658
4875
|
}
|
|
4659
4876
|
const applyContent = (content) => {
|
|
4660
4877
|
const imageLoads = [];
|
|
4661
|
-
document.querySelectorAll("[data-ohw-section-container]").forEach((el) => el.remove());
|
|
4662
|
-
if (content["__ohw_sections"]) {
|
|
4663
|
-
try {
|
|
4664
|
-
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4665
|
-
const currentPath = window.location.pathname;
|
|
4666
|
-
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4667
|
-
if (pagePath && pagePath !== currentPath) return;
|
|
4668
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4669
|
-
});
|
|
4670
|
-
} catch {
|
|
4671
|
-
}
|
|
4672
|
-
}
|
|
4673
4878
|
for (const [key, val] of Object.entries(content)) {
|
|
4674
4879
|
if (key === "__ohw_sections") continue;
|
|
4675
4880
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -4690,6 +4895,7 @@ function OhhwellsBridge() {
|
|
|
4690
4895
|
}
|
|
4691
4896
|
});
|
|
4692
4897
|
}
|
|
4898
|
+
initSectionsFromContent(content, true);
|
|
4693
4899
|
return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
|
|
4694
4900
|
}) : Promise.resolve();
|
|
4695
4901
|
};
|
|
@@ -4716,20 +4922,11 @@ function OhhwellsBridge() {
|
|
|
4716
4922
|
}, [subdomain, isEditMode, pathname]);
|
|
4717
4923
|
useEffect2(() => {
|
|
4718
4924
|
if (!subdomain || isEditMode) return;
|
|
4925
|
+
let debounceTimer = null;
|
|
4719
4926
|
const applyFromCache = () => {
|
|
4720
4927
|
const content = contentCache.get(subdomain);
|
|
4721
4928
|
if (!content) return;
|
|
4722
|
-
|
|
4723
|
-
try {
|
|
4724
|
-
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4725
|
-
const currentPath = window.location.pathname;
|
|
4726
|
-
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4727
|
-
if (pagePath && pagePath !== currentPath) return;
|
|
4728
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4729
|
-
});
|
|
4730
|
-
} catch {
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4929
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
4733
4930
|
for (const [key, val] of Object.entries(content)) {
|
|
4734
4931
|
if (key === "__ohw_sections") continue;
|
|
4735
4932
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -4745,11 +4942,18 @@ function OhhwellsBridge() {
|
|
|
4745
4942
|
});
|
|
4746
4943
|
}
|
|
4747
4944
|
};
|
|
4748
|
-
|
|
4749
|
-
|
|
4945
|
+
const scheduleApply = () => {
|
|
4946
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
4947
|
+
debounceTimer = setTimeout(applyFromCache, 150);
|
|
4948
|
+
};
|
|
4949
|
+
scheduleApply();
|
|
4950
|
+
const observer = new MutationObserver(scheduleApply);
|
|
4750
4951
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
4751
|
-
return () =>
|
|
4752
|
-
|
|
4952
|
+
return () => {
|
|
4953
|
+
observer.disconnect();
|
|
4954
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
4955
|
+
};
|
|
4956
|
+
}, [subdomain, isEditMode, pathname]);
|
|
4753
4957
|
useLayoutEffect(() => {
|
|
4754
4958
|
const el = document.getElementById("ohw-loader");
|
|
4755
4959
|
if (!el) return;
|
|
@@ -5322,17 +5526,10 @@ function OhhwellsBridge() {
|
|
|
5322
5526
|
if (e.data?.type !== "ow:hydrate") return;
|
|
5323
5527
|
const content = e.data.content;
|
|
5324
5528
|
if (!content) return;
|
|
5529
|
+
let sectionsJson = null;
|
|
5325
5530
|
for (const [key, val] of Object.entries(content)) {
|
|
5326
5531
|
if (key === "__ohw_sections") {
|
|
5327
|
-
|
|
5328
|
-
const entries = JSON.parse(val);
|
|
5329
|
-
const tracker = getSectionsTracker();
|
|
5330
|
-
tracker.textContent = val;
|
|
5331
|
-
entries.forEach(({ type, insertAfter, scheduleId }) => {
|
|
5332
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
5333
|
-
});
|
|
5334
|
-
} catch {
|
|
5335
|
-
}
|
|
5532
|
+
sectionsJson = val;
|
|
5336
5533
|
continue;
|
|
5337
5534
|
}
|
|
5338
5535
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -5346,6 +5543,9 @@ function OhhwellsBridge() {
|
|
|
5346
5543
|
}
|
|
5347
5544
|
});
|
|
5348
5545
|
}
|
|
5546
|
+
if (sectionsJson) {
|
|
5547
|
+
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
5548
|
+
}
|
|
5349
5549
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
5350
5550
|
};
|
|
5351
5551
|
window.addEventListener("message", handleHydrate);
|
|
@@ -5396,9 +5596,9 @@ function OhhwellsBridge() {
|
|
|
5396
5596
|
};
|
|
5397
5597
|
const handleInsertSection = (e) => {
|
|
5398
5598
|
if (e.data?.type !== "ow:insert-section") return;
|
|
5399
|
-
const { widgetType, insertAfter } = e.data;
|
|
5599
|
+
const { widgetType, insertAfter, insertBefore } = e.data;
|
|
5400
5600
|
if (widgetType !== "scheduling") return;
|
|
5401
|
-
const inserted = mountSchedulingWidget(insertAfter, true);
|
|
5601
|
+
const inserted = mountSchedulingWidget(insertAfter, true, void 0, insertBefore ?? null);
|
|
5402
5602
|
if (inserted) {
|
|
5403
5603
|
const tracker = getSectionsTracker();
|
|
5404
5604
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
@@ -5409,39 +5609,31 @@ function OhhwellsBridge() {
|
|
|
5409
5609
|
const handleSwitchSchedule = (e) => {
|
|
5410
5610
|
if (e.data?.type !== "ow:switch-schedule") return;
|
|
5411
5611
|
const scheduleId = e.data.scheduleId;
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
const
|
|
5420
|
-
const
|
|
5421
|
-
|
|
5422
|
-
);
|
|
5423
|
-
|
|
5424
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5612
|
+
const insertAfter = e.data.insertAfter;
|
|
5613
|
+
if (!scheduleId || !insertAfter) return;
|
|
5614
|
+
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
5615
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5616
|
+
};
|
|
5617
|
+
const handleScheduleLinked = (e) => {
|
|
5618
|
+
if (e.data?.type !== "ow:schedule-linked") return;
|
|
5619
|
+
const scheduleId = e.data.scheduleId;
|
|
5620
|
+
const insertAfter = e.data.insertAfter;
|
|
5621
|
+
if (!scheduleId || !insertAfter) return;
|
|
5622
|
+
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
5623
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5425
5624
|
};
|
|
5426
5625
|
const handleClearSchedulingWidget = (e) => {
|
|
5427
5626
|
if (e.data?.type !== "ow:clear-scheduling-widget") return;
|
|
5428
|
-
const
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
} catch {
|
|
5433
|
-
}
|
|
5434
|
-
const currentPath = window.location.pathname;
|
|
5435
|
-
const updated = sections.map(
|
|
5436
|
-
(s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId: null } : s
|
|
5437
|
-
);
|
|
5438
|
-
tracker.textContent = JSON.stringify(updated);
|
|
5439
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5627
|
+
const insertAfter = e.data.insertAfter;
|
|
5628
|
+
if (!insertAfter) return;
|
|
5629
|
+
const text = updateSectionScheduleId(insertAfter, null);
|
|
5630
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5440
5631
|
};
|
|
5441
5632
|
const handleRemoveSchedulingSection = (e) => {
|
|
5442
5633
|
if (e.data?.type !== "ow:remove-scheduling-section") return;
|
|
5443
|
-
|
|
5444
|
-
|
|
5634
|
+
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => {
|
|
5635
|
+
el.remove();
|
|
5636
|
+
});
|
|
5445
5637
|
const tracker = getSectionsTracker();
|
|
5446
5638
|
let sections = [];
|
|
5447
5639
|
try {
|
|
@@ -5560,6 +5752,7 @@ function OhhwellsBridge() {
|
|
|
5560
5752
|
window.addEventListener("message", handleSave);
|
|
5561
5753
|
window.addEventListener("message", handleInsertSection);
|
|
5562
5754
|
window.addEventListener("message", handleSwitchSchedule);
|
|
5755
|
+
window.addEventListener("message", handleScheduleLinked);
|
|
5563
5756
|
window.addEventListener("message", handleClearSchedulingWidget);
|
|
5564
5757
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
5565
5758
|
window.addEventListener("message", handleImageUrl);
|
|
@@ -5598,6 +5791,7 @@ function OhhwellsBridge() {
|
|
|
5598
5791
|
window.removeEventListener("message", handleSave);
|
|
5599
5792
|
window.removeEventListener("message", handleInsertSection);
|
|
5600
5793
|
window.removeEventListener("message", handleSwitchSchedule);
|
|
5794
|
+
window.removeEventListener("message", handleScheduleLinked);
|
|
5601
5795
|
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
5602
5796
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
5603
5797
|
window.removeEventListener("message", handleImageUrl);
|