@ohhwells/bridge 0.1.19 → 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 +715 -279
- 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 +690 -254
- package/dist/index.js.map +1 -1
- package/dist/styles.css +193 -27
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -41,12 +41,167 @@ __export(index_exports, {
|
|
|
41
41
|
module.exports = __toCommonJS(index_exports);
|
|
42
42
|
|
|
43
43
|
// src/OhhwellsBridge.tsx
|
|
44
|
-
var
|
|
44
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
45
45
|
var import_client = require("react-dom/client");
|
|
46
|
+
var import_react_dom = require("react-dom");
|
|
46
47
|
|
|
47
48
|
// src/ui/SchedulingWidget.tsx
|
|
48
|
-
var
|
|
49
|
+
var import_react2 = require("react");
|
|
50
|
+
|
|
51
|
+
// src/ui/EmailCaptureModal.tsx
|
|
52
|
+
var import_react = require("react");
|
|
53
|
+
var import_radix_ui = require("radix-ui");
|
|
49
54
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
55
|
+
function Spinner() {
|
|
56
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
57
|
+
"svg",
|
|
58
|
+
{
|
|
59
|
+
width: "32",
|
|
60
|
+
height: "32",
|
|
61
|
+
viewBox: "0 0 32 32",
|
|
62
|
+
fill: "none",
|
|
63
|
+
style: { animation: "ohw-spin 0.75s linear infinite" },
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes ohw-spin { to { transform: rotate(360deg); } }` }),
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "16", cy: "16", r: "12", stroke: "#e5e7eb", strokeWidth: "3" }),
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
68
|
+
"path",
|
|
69
|
+
{
|
|
70
|
+
d: "M16 4a12 12 0 0 1 12 12",
|
|
71
|
+
stroke: "#3b82f6",
|
|
72
|
+
strokeWidth: "3",
|
|
73
|
+
strokeLinecap: "round"
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
81
|
+
const [email, setEmail] = (0, import_react.useState)("");
|
|
82
|
+
const [submittedEmail, setSubmittedEmail] = (0, import_react.useState)("");
|
|
83
|
+
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
84
|
+
const [success, setSuccess] = (0, import_react.useState)(false);
|
|
85
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
86
|
+
const isBook = title === "Confirm your spot";
|
|
87
|
+
const handleSubmit = async () => {
|
|
88
|
+
if (!email.trim()) return;
|
|
89
|
+
setLoading(true);
|
|
90
|
+
setError(null);
|
|
91
|
+
try {
|
|
92
|
+
await onSubmit(email.trim());
|
|
93
|
+
setSubmittedEmail(email.trim());
|
|
94
|
+
setSuccess(true);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
97
|
+
} finally {
|
|
98
|
+
setLoading(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const handleKeyDown = (e) => {
|
|
102
|
+
if (e.key === "Enter" && !loading) handleSubmit();
|
|
103
|
+
};
|
|
104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Dialog.Root, { open: true, onOpenChange: (open) => {
|
|
105
|
+
if (!open) onClose();
|
|
106
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_radix_ui.Dialog.Portal, { children: [
|
|
107
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
108
|
+
import_radix_ui.Dialog.Overlay,
|
|
109
|
+
{
|
|
110
|
+
className: "fixed inset-0 z-50",
|
|
111
|
+
style: { background: "rgba(0,0,0,0.45)" }
|
|
112
|
+
}
|
|
113
|
+
),
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
115
|
+
import_radix_ui.Dialog.Content,
|
|
116
|
+
{
|
|
117
|
+
className: "fixed left-1/2 top-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl shadow-xl outline-none font-body box-border overflow-hidden",
|
|
118
|
+
style: { maxWidth: 400 },
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start justify-between gap-3 p-6", children: [
|
|
121
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
123
|
+
import_radix_ui.Dialog.Title,
|
|
124
|
+
{
|
|
125
|
+
className: "font-body text-xl font-bold m-0 leading-tight",
|
|
126
|
+
style: { color: "var(--color-dark,#200C02)" },
|
|
127
|
+
children: success ? isBook ? "Reservation confirmed!" : "You're on the waitlist!" : title
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
import_radix_ui.Dialog.Description,
|
|
132
|
+
{
|
|
133
|
+
className: "font-body text-sm m-0",
|
|
134
|
+
style: { color: "#6B7280" },
|
|
135
|
+
children: success ? isBook ? `A confirmation email has been sent to ${submittedEmail}.` : "We'll let you know via email if someone cancels." : subtitle
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
140
|
+
import_radix_ui.Dialog.Close,
|
|
141
|
+
{
|
|
142
|
+
className: "shrink-0 w-7 h-7 flex items-center justify-center rounded-full bg-transparent border-none cursor-pointer mt-0.5 absolute top-2.5 right-1.5",
|
|
143
|
+
style: { color: "#6B7280" },
|
|
144
|
+
"aria-label": "Close",
|
|
145
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
146
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
147
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
148
|
+
] })
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
] }),
|
|
152
|
+
!success && (loading ? (
|
|
153
|
+
/* Loading state — full body replaced */
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center justify-center gap-3 px-7 py-12", children: [
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-sm m-0", style: { color: "#6B7280" }, children: "Please wait" })
|
|
157
|
+
] })
|
|
158
|
+
) : (
|
|
159
|
+
/* Email form */
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-7 pt-2 pb-6", children: [
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1.5 mb-8", children: [
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "font-body text-sm font-medium", style: { color: "var(--color-dark,#200C02)" }, children: "Email" }),
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
164
|
+
"input",
|
|
165
|
+
{
|
|
166
|
+
type: "email",
|
|
167
|
+
value: email,
|
|
168
|
+
onChange: (e) => setEmail(e.target.value),
|
|
169
|
+
onKeyDown: handleKeyDown,
|
|
170
|
+
placeholder: "hello@gmail.com",
|
|
171
|
+
autoFocus: true,
|
|
172
|
+
className: "w-full h-10 px-3 rounded-lg border font-body text-sm outline-none box-border",
|
|
173
|
+
style: {
|
|
174
|
+
borderColor: "#E7E5E4",
|
|
175
|
+
background: "#fff",
|
|
176
|
+
color: "var(--color-dark,#200C02)"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
),
|
|
180
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-xs text-red-500 m-0", children: error })
|
|
181
|
+
] }),
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
183
|
+
"button",
|
|
184
|
+
{
|
|
185
|
+
onClick: handleSubmit,
|
|
186
|
+
disabled: !email.trim(),
|
|
187
|
+
className: "h-9 px-5 rounded-lg font-body text-sm font-semibold cursor-pointer border-none disabled:opacity-50 disabled:cursor-not-allowed",
|
|
188
|
+
style: {
|
|
189
|
+
background: "var(--color-primary,#3D312B)",
|
|
190
|
+
color: "var(--color-light,#FEFFF0)"
|
|
191
|
+
},
|
|
192
|
+
children: "Send"
|
|
193
|
+
}
|
|
194
|
+
) })
|
|
195
|
+
] })
|
|
196
|
+
))
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
] }) });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/ui/SchedulingWidget.tsx
|
|
204
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
50
205
|
var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
51
206
|
var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
52
207
|
function getApiDomain() {
|
|
@@ -107,8 +262,8 @@ function EmptyState({ inEditor }) {
|
|
|
107
262
|
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
108
263
|
}
|
|
109
264
|
};
|
|
110
|
-
return /* @__PURE__ */ (0,
|
|
111
|
-
/* @__PURE__ */ (0,
|
|
265
|
+
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: [
|
|
266
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-10 h-10 bg-[#F5F5F4] rounded-[10px] flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
112
267
|
"svg",
|
|
113
268
|
{
|
|
114
269
|
width: "20",
|
|
@@ -120,20 +275,20 @@ function EmptyState({ inEditor }) {
|
|
|
120
275
|
strokeLinecap: "round",
|
|
121
276
|
strokeLinejoin: "round",
|
|
122
277
|
children: [
|
|
123
|
-
/* @__PURE__ */ (0,
|
|
124
|
-
/* @__PURE__ */ (0,
|
|
125
|
-
/* @__PURE__ */ (0,
|
|
126
|
-
/* @__PURE__ */ (0,
|
|
127
|
-
/* @__PURE__ */ (0,
|
|
128
|
-
/* @__PURE__ */ (0,
|
|
278
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
|
|
281
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
|
|
282
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
|
|
129
284
|
]
|
|
130
285
|
}
|
|
131
286
|
) }),
|
|
132
|
-
/* @__PURE__ */ (0,
|
|
133
|
-
/* @__PURE__ */ (0,
|
|
134
|
-
/* @__PURE__ */ (0,
|
|
287
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
|
|
289
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-base font-normal text-center text-(--color-accent,#A89B83) m-0", children: "Add a scheduling widget to get instant bookings." })
|
|
135
290
|
] }),
|
|
136
|
-
/* @__PURE__ */ (0,
|
|
291
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
137
292
|
"button",
|
|
138
293
|
{
|
|
139
294
|
onClick: handleAddSchedule,
|
|
@@ -149,119 +304,249 @@ function LoadingSkeleton() {
|
|
|
149
304
|
backgroundSize: "200% 100%",
|
|
150
305
|
animation: "ohw-shimmer 1.5s infinite"
|
|
151
306
|
};
|
|
152
|
-
return /* @__PURE__ */ (0,
|
|
153
|
-
/* @__PURE__ */ (0,
|
|
154
|
-
/* @__PURE__ */ (0,
|
|
155
|
-
/* @__PURE__ */ (0,
|
|
156
|
-
/* @__PURE__ */ (0,
|
|
307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
308
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
|
|
309
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex h-[70px] items-stretch", children: Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col justify-between items-center px-1", children: [
|
|
310
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
|
|
311
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
|
|
157
312
|
] }, i)) }),
|
|
158
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ (0,
|
|
159
|
-
/* @__PURE__ */ (0,
|
|
160
|
-
/* @__PURE__ */ (0,
|
|
161
|
-
|
|
162
|
-
/* @__PURE__ */ (0,
|
|
163
|
-
/* @__PURE__ */ (0,
|
|
313
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
314
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:hidden", children: [
|
|
315
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0", children: [
|
|
316
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100px", height: "16px", borderRadius: "4px" } }),
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "52px", height: "20px", borderRadius: "999px" } }),
|
|
318
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "60px", height: "14px", borderRadius: "4px" } })
|
|
164
319
|
] }),
|
|
165
|
-
/* @__PURE__ */ (0,
|
|
166
|
-
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
321
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "75%", height: "16px", borderRadius: "4px" } }),
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "50%", height: "14px", borderRadius: "4px" } }),
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100%", height: "44px", borderRadius: "8px" } })
|
|
324
|
+
] })
|
|
167
325
|
] }),
|
|
168
|
-
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hidden sm:flex items-center gap-[60px] py-4", children: [
|
|
327
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
|
|
331
|
+
] }),
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
|
|
334
|
+
] }),
|
|
335
|
+
i < 2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
|
|
169
336
|
] }, i))
|
|
170
337
|
] });
|
|
171
338
|
}
|
|
172
|
-
function ScheduleView({ schedule, dates, selectedIdx, onSelectDate }) {
|
|
173
|
-
const todayMs = (0,
|
|
339
|
+
function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
|
|
340
|
+
const todayMs = (0, import_react2.useMemo)(() => {
|
|
174
341
|
const d = /* @__PURE__ */ new Date();
|
|
175
342
|
d.setHours(0, 0, 0, 0);
|
|
176
343
|
return d.getTime();
|
|
177
344
|
}, []);
|
|
178
|
-
const
|
|
345
|
+
const scrollRef = (0, import_react2.useRef)(null);
|
|
346
|
+
const [canScrollLeft, setCanScrollLeft] = (0, import_react2.useState)(false);
|
|
347
|
+
const [canScrollRight, setCanScrollRight] = (0, import_react2.useState)(false);
|
|
348
|
+
const updateScrollState = () => {
|
|
349
|
+
const el = scrollRef.current;
|
|
350
|
+
if (!el) return;
|
|
351
|
+
setCanScrollLeft(el.scrollLeft > 0);
|
|
352
|
+
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
353
|
+
};
|
|
354
|
+
(0, import_react2.useEffect)(() => {
|
|
355
|
+
const el = scrollRef.current;
|
|
356
|
+
if (!el) return;
|
|
357
|
+
updateScrollState();
|
|
358
|
+
el.addEventListener("scroll", updateScrollState);
|
|
359
|
+
const ro = new ResizeObserver(updateScrollState);
|
|
360
|
+
ro.observe(el);
|
|
361
|
+
return () => {
|
|
362
|
+
el.removeEventListener("scroll", updateScrollState);
|
|
363
|
+
ro.disconnect();
|
|
364
|
+
};
|
|
365
|
+
}, [dates]);
|
|
366
|
+
const scroll = (dir) => {
|
|
367
|
+
scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
|
|
368
|
+
};
|
|
369
|
+
const isDragging = (0, import_react2.useRef)(false);
|
|
370
|
+
const dragStartX = (0, import_react2.useRef)(0);
|
|
371
|
+
const dragStartScrollLeft = (0, import_react2.useRef)(0);
|
|
372
|
+
const onDragStart = (e) => {
|
|
373
|
+
if (!scrollRef.current) return;
|
|
374
|
+
isDragging.current = true;
|
|
375
|
+
dragStartX.current = e.clientX;
|
|
376
|
+
dragStartScrollLeft.current = scrollRef.current.scrollLeft;
|
|
377
|
+
scrollRef.current.style.cursor = "grabbing";
|
|
378
|
+
scrollRef.current.style.userSelect = "none";
|
|
379
|
+
};
|
|
380
|
+
const onDragMove = (e) => {
|
|
381
|
+
if (!isDragging.current || !scrollRef.current) return;
|
|
382
|
+
const delta = e.clientX - dragStartX.current;
|
|
383
|
+
scrollRef.current.scrollLeft = dragStartScrollLeft.current - delta;
|
|
384
|
+
};
|
|
385
|
+
const onDragEnd = () => {
|
|
386
|
+
if (!scrollRef.current) return;
|
|
387
|
+
isDragging.current = false;
|
|
388
|
+
scrollRef.current.style.cursor = "grab";
|
|
389
|
+
scrollRef.current.style.userSelect = "";
|
|
390
|
+
};
|
|
391
|
+
const datesWithClasses = (0, import_react2.useMemo)(
|
|
179
392
|
() => new Set(dates.map(
|
|
180
393
|
(d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
|
|
181
394
|
).filter((i) => i >= 0)),
|
|
182
395
|
[dates, schedule]
|
|
183
396
|
);
|
|
184
397
|
const selectedDate = dates[selectedIdx];
|
|
185
|
-
const selectedClasses = (0,
|
|
398
|
+
const selectedClasses = (0, import_react2.useMemo)(
|
|
186
399
|
() => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
|
|
187
400
|
[schedule, selectedDate]
|
|
188
401
|
);
|
|
189
|
-
return /* @__PURE__ */ (0,
|
|
190
|
-
/* @__PURE__ */ (0,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
403
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative w-full", children: [
|
|
404
|
+
canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
405
|
+
"button",
|
|
406
|
+
{
|
|
407
|
+
onClick: () => scroll("left"),
|
|
408
|
+
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",
|
|
409
|
+
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
410
|
+
"aria-label": "Scroll left",
|
|
411
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "15 18 9 12 15 6" }) })
|
|
412
|
+
}
|
|
413
|
+
),
|
|
414
|
+
canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
415
|
+
"button",
|
|
416
|
+
{
|
|
417
|
+
onClick: () => scroll("right"),
|
|
418
|
+
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",
|
|
419
|
+
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
420
|
+
"aria-label": "Scroll right",
|
|
421
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "9 18 15 12 9 6" }) })
|
|
422
|
+
}
|
|
423
|
+
),
|
|
424
|
+
canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
196
425
|
"div",
|
|
197
426
|
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
427
|
+
className: "sm:hidden absolute left-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
428
|
+
style: { background: "linear-gradient(to right, var(--color-light,#FEFFF0), transparent)" }
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
432
|
+
"div",
|
|
433
|
+
{
|
|
434
|
+
className: "sm:hidden absolute right-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
435
|
+
style: { background: "linear-gradient(to left, var(--color-light,#FEFFF0), transparent)" }
|
|
436
|
+
}
|
|
437
|
+
),
|
|
438
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
439
|
+
"div",
|
|
440
|
+
{
|
|
441
|
+
ref: scrollRef,
|
|
442
|
+
className: "overflow-x-auto w-full",
|
|
443
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none", touchAction: "pan-x", cursor: "grab" },
|
|
444
|
+
onMouseDown: onDragStart,
|
|
445
|
+
onMouseMove: onDragMove,
|
|
446
|
+
onMouseUp: onDragEnd,
|
|
447
|
+
onMouseLeave: onDragEnd,
|
|
448
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex", style: { width: `max(100%, ${dates.length * 60}px)` }, children: dates.map((date, i) => {
|
|
449
|
+
const isToday = date.getTime() === todayMs;
|
|
450
|
+
const isSelected = i === selectedIdx;
|
|
451
|
+
const clickable = datesWithClasses.has(i);
|
|
452
|
+
const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
|
|
453
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
203
454
|
"div",
|
|
204
455
|
{
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
children:
|
|
208
|
-
"span",
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
456
|
+
onClick: () => clickable && onSelectDate(i),
|
|
457
|
+
className: `flex-1 h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
|
|
458
|
+
children: [
|
|
459
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
|
|
460
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
461
|
+
"div",
|
|
462
|
+
{
|
|
463
|
+
className: "w-10 h-10 rounded-full flex items-center justify-center",
|
|
464
|
+
style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
|
|
465
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
466
|
+
"span",
|
|
467
|
+
{
|
|
468
|
+
className: "font-body text-xl font-bold text-center tracking-display-tight",
|
|
469
|
+
style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
|
|
470
|
+
children: date.getDate()
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
)
|
|
475
|
+
]
|
|
476
|
+
},
|
|
477
|
+
i
|
|
478
|
+
);
|
|
479
|
+
}) })
|
|
480
|
+
}
|
|
481
|
+
)
|
|
482
|
+
] }),
|
|
483
|
+
selectedClasses.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-base text-(--color-accent,#A89B83) text-center py-8 m-0", children: "No classes scheduled for this day." }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-col", children: selectedClasses.map((cls, i) => {
|
|
223
484
|
const booked = getBookingsOnDate(cls, selectedDate);
|
|
224
485
|
const available = cls.maxParticipants - booked;
|
|
225
486
|
const isFull = available <= 0;
|
|
226
|
-
return /* @__PURE__ */ (0,
|
|
227
|
-
/* @__PURE__ */ (0,
|
|
228
|
-
/* @__PURE__ */ (0,
|
|
229
|
-
|
|
230
|
-
/* @__PURE__ */ (0,
|
|
231
|
-
|
|
487
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
|
|
490
|
+
/* @__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) }) }),
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
492
|
+
"span",
|
|
493
|
+
{
|
|
494
|
+
className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
|
|
495
|
+
style: { borderColor: "#0885FE", color: "#0885FE" },
|
|
496
|
+
children: "GROUP"
|
|
497
|
+
}
|
|
498
|
+
),
|
|
499
|
+
/* @__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: [
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
501
|
+
available,
|
|
502
|
+
"/",
|
|
503
|
+
cls.maxParticipants
|
|
504
|
+
] }),
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
506
|
+
] }) })
|
|
232
507
|
] }),
|
|
233
|
-
/* @__PURE__ */ (0,
|
|
234
|
-
/* @__PURE__ */ (0,
|
|
235
|
-
|
|
236
|
-
"
|
|
237
|
-
cls.maxParticipants
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
511
|
+
cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
238
512
|
] }),
|
|
239
|
-
/* @__PURE__ */ (0,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 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: [
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
515
|
+
available,
|
|
516
|
+
"/",
|
|
517
|
+
cls.maxParticipants
|
|
518
|
+
] }),
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
520
|
+
] }) }),
|
|
521
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
522
|
+
"button",
|
|
523
|
+
{
|
|
524
|
+
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",
|
|
525
|
+
style: isFull ? {
|
|
526
|
+
background: "transparent",
|
|
527
|
+
border: "1px solid var(--color-dark, #200C02)",
|
|
528
|
+
color: "var(--color-dark, #200C02)"
|
|
529
|
+
} : {
|
|
530
|
+
background: "var(--color-primary, #3D312B)",
|
|
531
|
+
border: "none",
|
|
532
|
+
color: "var(--color-light, #FEFFF0)"
|
|
533
|
+
},
|
|
534
|
+
onClick: () => {
|
|
535
|
+
if (!cls.id) return;
|
|
536
|
+
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
537
|
+
},
|
|
538
|
+
children: isFull ? "Join Waitlist" : "Book Now"
|
|
539
|
+
}
|
|
540
|
+
)
|
|
541
|
+
] })
|
|
257
542
|
] }),
|
|
258
|
-
i < selectedClasses.length - 1 && /* @__PURE__ */ (0,
|
|
543
|
+
i < selectedClasses.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
|
|
259
544
|
] }, cls.id ?? i);
|
|
260
545
|
}) })
|
|
261
546
|
] });
|
|
262
547
|
}
|
|
263
548
|
function CalendarFoldIcon() {
|
|
264
|
-
return /* @__PURE__ */ (0,
|
|
549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
265
550
|
"svg",
|
|
266
551
|
{
|
|
267
552
|
width: "16",
|
|
@@ -274,22 +559,23 @@ function CalendarFoldIcon() {
|
|
|
274
559
|
strokeLinejoin: "round",
|
|
275
560
|
style: { flexShrink: 0 },
|
|
276
561
|
children: [
|
|
277
|
-
/* @__PURE__ */ (0,
|
|
278
|
-
/* @__PURE__ */ (0,
|
|
279
|
-
/* @__PURE__ */ (0,
|
|
280
|
-
/* @__PURE__ */ (0,
|
|
281
|
-
/* @__PURE__ */ (0,
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 2v4" }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 2v4" }),
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 17V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11Z" }),
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 10h18" }),
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
|
|
282
567
|
]
|
|
283
568
|
}
|
|
284
569
|
);
|
|
285
570
|
}
|
|
286
|
-
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
287
|
-
const [schedule, setSchedule] = (0,
|
|
288
|
-
const [loading, setLoading] = (0,
|
|
289
|
-
const [inEditor, setInEditor] = (0,
|
|
290
|
-
const [isHovered, setIsHovered] = (0,
|
|
291
|
-
const
|
|
292
|
-
const
|
|
571
|
+
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
|
|
572
|
+
const [schedule, setSchedule] = (0, import_react2.useState)(null);
|
|
573
|
+
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
574
|
+
const [inEditor, setInEditor] = (0, import_react2.useState)(false);
|
|
575
|
+
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
|
|
576
|
+
const [modalState, setModalState] = (0, import_react2.useState)(null);
|
|
577
|
+
const switchScheduleIdRef = (0, import_react2.useRef)(null);
|
|
578
|
+
const dates = (0, import_react2.useMemo)(() => {
|
|
293
579
|
const today = /* @__PURE__ */ new Date();
|
|
294
580
|
today.setHours(0, 0, 0, 0);
|
|
295
581
|
return Array.from({ length: 14 }, (_, i) => {
|
|
@@ -298,8 +584,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
298
584
|
return d;
|
|
299
585
|
});
|
|
300
586
|
}, []);
|
|
301
|
-
const [selectedIdx, setSelectedIdx] = (0,
|
|
302
|
-
(0,
|
|
587
|
+
const [selectedIdx, setSelectedIdx] = (0, import_react2.useState)(0);
|
|
588
|
+
(0, import_react2.useEffect)(() => {
|
|
303
589
|
if (!schedule?.classes) return;
|
|
304
590
|
for (let i = 0; i < dates.length; i++) {
|
|
305
591
|
if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
|
|
@@ -308,7 +594,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
308
594
|
}
|
|
309
595
|
}
|
|
310
596
|
}, [schedule, dates]);
|
|
311
|
-
(0,
|
|
597
|
+
(0, import_react2.useEffect)(() => {
|
|
312
598
|
if (typeof window === "undefined") return;
|
|
313
599
|
const isInEditor = window.self !== window.top;
|
|
314
600
|
setInEditor(isInEditor);
|
|
@@ -324,18 +610,21 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
324
610
|
}, 5e3) : null;
|
|
325
611
|
const handler = (e) => {
|
|
326
612
|
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
613
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
327
614
|
setSchedule(null);
|
|
328
615
|
setLoading(false);
|
|
329
616
|
return;
|
|
330
617
|
}
|
|
331
618
|
if (e.data?.type === "ow:switch-schedule") {
|
|
619
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
332
620
|
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
333
621
|
initialized = false;
|
|
334
622
|
setLoading(true);
|
|
335
|
-
window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
623
|
+
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
336
624
|
return;
|
|
337
625
|
}
|
|
338
626
|
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
627
|
+
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
339
628
|
if (initialized && switchScheduleIdRef.current === null) return;
|
|
340
629
|
initialized = true;
|
|
341
630
|
if (timer) clearTimeout(timer);
|
|
@@ -346,11 +635,16 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
346
635
|
setSchedule(target);
|
|
347
636
|
setLoading(false);
|
|
348
637
|
if (notifyOnConnect && target && !isSwitching) {
|
|
349
|
-
window.parent.postMessage({
|
|
638
|
+
window.parent.postMessage({
|
|
639
|
+
type: "ow:schedule-connected",
|
|
640
|
+
schedule: { id: target.id, name: target.name },
|
|
641
|
+
insertAfter
|
|
642
|
+
}, "*");
|
|
643
|
+
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
350
644
|
}
|
|
351
645
|
};
|
|
352
646
|
window.addEventListener("message", handler);
|
|
353
|
-
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
647
|
+
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
354
648
|
return () => {
|
|
355
649
|
window.removeEventListener("message", handler);
|
|
356
650
|
if (timer) clearTimeout(timer);
|
|
@@ -394,31 +688,51 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
394
688
|
return void 0;
|
|
395
689
|
}
|
|
396
690
|
})() : void 0;
|
|
691
|
+
const handleModalSubmit = async (email) => {
|
|
692
|
+
if (!modalState) return;
|
|
693
|
+
const { mode, classId, classDate } = modalState;
|
|
694
|
+
const endpoint = mode === "book" ? `${API_URL}/api/schedule/class/${classId}/booking` : `${API_URL}/api/schedule/class/${classId}/waitlist`;
|
|
695
|
+
const res = await fetch(endpoint, {
|
|
696
|
+
method: "POST",
|
|
697
|
+
headers: { "Content-Type": "application/json" },
|
|
698
|
+
body: JSON.stringify({ classDate: classDate.toISOString(), email })
|
|
699
|
+
});
|
|
700
|
+
if (!res.ok) {
|
|
701
|
+
const data = await res.json().catch(() => ({}));
|
|
702
|
+
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
703
|
+
}
|
|
704
|
+
};
|
|
397
705
|
const handleReplaceSchedule = () => {
|
|
398
706
|
setIsHovered(false);
|
|
399
707
|
if (schedule) {
|
|
400
|
-
window.parent.postMessage({
|
|
708
|
+
window.parent.postMessage({
|
|
709
|
+
type: "ow:schedule-connected",
|
|
710
|
+
schedule: { id: schedule.id, name: schedule.name },
|
|
711
|
+
insertAfter
|
|
712
|
+
}, "*");
|
|
401
713
|
} else {
|
|
402
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
714
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
403
715
|
}
|
|
404
716
|
};
|
|
405
|
-
|
|
717
|
+
const sectionId = `scheduling-${insertAfter}`;
|
|
718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
406
719
|
"section",
|
|
407
720
|
{
|
|
408
|
-
"data-ohw-section":
|
|
409
|
-
|
|
721
|
+
"data-ohw-section": sectionId,
|
|
722
|
+
"data-ohw-scheduling-anchor": insertAfter,
|
|
723
|
+
className: "w-full box-border py-10 px-5 sm:py-20 sm:px-16 font-body bg-(--color-light,#FEFFF0) relative",
|
|
410
724
|
onMouseEnter: () => inEditor && setIsHovered(true),
|
|
411
725
|
onMouseLeave: () => setIsHovered(false),
|
|
412
726
|
children: [
|
|
413
|
-
inEditor && isHovered && !!schedule && /* @__PURE__ */ (0,
|
|
727
|
+
inEditor && isHovered && !!schedule && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
414
728
|
"div",
|
|
415
729
|
{
|
|
416
730
|
className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
|
|
417
731
|
onClick: handleReplaceSchedule,
|
|
418
732
|
children: [
|
|
419
|
-
/* @__PURE__ */ (0,
|
|
420
|
-
/* @__PURE__ */ (0,
|
|
421
|
-
/* @__PURE__ */ (0,
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
422
736
|
"div",
|
|
423
737
|
{
|
|
424
738
|
className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
|
|
@@ -430,7 +744,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
430
744
|
color: "#0C0A09"
|
|
431
745
|
},
|
|
432
746
|
children: [
|
|
433
|
-
/* @__PURE__ */ (0,
|
|
747
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CalendarFoldIcon, {}),
|
|
434
748
|
"Replace schedule"
|
|
435
749
|
]
|
|
436
750
|
}
|
|
@@ -438,24 +752,34 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
|
438
752
|
]
|
|
439
753
|
}
|
|
440
754
|
),
|
|
441
|
-
/* @__PURE__ */ (0,
|
|
442
|
-
/* @__PURE__ */ (0,
|
|
443
|
-
/* @__PURE__ */ (0,
|
|
444
|
-
schedule?.description && /* @__PURE__ */ (0,
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
|
|
758
|
+
schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
445
759
|
] }),
|
|
446
|
-
/* @__PURE__ */ (0,
|
|
447
|
-
timezoneLabel && /* @__PURE__ */ (0,
|
|
448
|
-
/* @__PURE__ */ (0,
|
|
760
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
761
|
+
timezoneLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
762
|
+
/* @__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)(
|
|
449
763
|
ScheduleView,
|
|
450
764
|
{
|
|
451
765
|
schedule,
|
|
452
766
|
dates,
|
|
453
767
|
selectedIdx,
|
|
454
|
-
onSelectDate: setSelectedIdx
|
|
768
|
+
onSelectDate: setSelectedIdx,
|
|
769
|
+
onOpenModal: inEditor ? void 0 : (mode, classId, classDate) => setModalState({ mode, classId, classDate })
|
|
455
770
|
}
|
|
456
771
|
) })
|
|
457
772
|
] })
|
|
458
|
-
] })
|
|
773
|
+
] }),
|
|
774
|
+
modalState && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
775
|
+
EmailCaptureModal,
|
|
776
|
+
{
|
|
777
|
+
title: modalState.mode === "book" ? "Confirm your spot" : "Leave your email",
|
|
778
|
+
subtitle: modalState.mode === "book" ? "We'll send your booking confirmation here." : "We'll let you know when spots open up!",
|
|
779
|
+
onSubmit: handleModalSubmit,
|
|
780
|
+
onClose: () => setModalState(null)
|
|
781
|
+
}
|
|
782
|
+
)
|
|
459
783
|
]
|
|
460
784
|
}
|
|
461
785
|
);
|
|
@@ -3781,8 +4105,8 @@ var cva = (base, config) => (props) => {
|
|
|
3781
4105
|
};
|
|
3782
4106
|
|
|
3783
4107
|
// src/ui/toggle.tsx
|
|
3784
|
-
var
|
|
3785
|
-
var
|
|
4108
|
+
var import_radix_ui2 = require("radix-ui");
|
|
4109
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
3786
4110
|
var toggleVariants = cva(
|
|
3787
4111
|
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
3788
4112
|
{
|
|
@@ -3809,8 +4133,8 @@ function Toggle({
|
|
|
3809
4133
|
size,
|
|
3810
4134
|
...props
|
|
3811
4135
|
}) {
|
|
3812
|
-
return /* @__PURE__ */ (0,
|
|
3813
|
-
|
|
4136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4137
|
+
import_radix_ui2.Toggle.Root,
|
|
3814
4138
|
{
|
|
3815
4139
|
"data-slot": "toggle",
|
|
3816
4140
|
className: cn(toggleVariants({ variant, size, className })),
|
|
@@ -3820,7 +4144,7 @@ function Toggle({
|
|
|
3820
4144
|
}
|
|
3821
4145
|
|
|
3822
4146
|
// src/ui/toggle-group.tsx
|
|
3823
|
-
var
|
|
4147
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
3824
4148
|
var ToggleGroupContext = React2.createContext({
|
|
3825
4149
|
value: "",
|
|
3826
4150
|
onValueChange: () => {
|
|
@@ -3833,13 +4157,13 @@ function ToggleGroup({
|
|
|
3833
4157
|
children,
|
|
3834
4158
|
...props
|
|
3835
4159
|
}) {
|
|
3836
|
-
return /* @__PURE__ */ (0,
|
|
4160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3837
4161
|
"div",
|
|
3838
4162
|
{
|
|
3839
4163
|
role: "group",
|
|
3840
4164
|
className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
|
|
3841
4165
|
...props,
|
|
3842
|
-
children: /* @__PURE__ */ (0,
|
|
4166
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
|
|
3843
4167
|
}
|
|
3844
4168
|
);
|
|
3845
4169
|
}
|
|
@@ -3850,7 +4174,7 @@ function ToggleGroupItem({
|
|
|
3850
4174
|
...props
|
|
3851
4175
|
}) {
|
|
3852
4176
|
const { value: groupValue, onValueChange } = React2.useContext(ToggleGroupContext);
|
|
3853
|
-
return /* @__PURE__ */ (0,
|
|
4177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3854
4178
|
Toggle,
|
|
3855
4179
|
{
|
|
3856
4180
|
pressed: groupValue === value,
|
|
@@ -3870,7 +4194,7 @@ function ToggleGroupItem({
|
|
|
3870
4194
|
}
|
|
3871
4195
|
|
|
3872
4196
|
// src/OhhwellsBridge.tsx
|
|
3873
|
-
var
|
|
4197
|
+
var import_react_dom2 = require("react-dom");
|
|
3874
4198
|
var import_navigation = require("next/navigation");
|
|
3875
4199
|
|
|
3876
4200
|
// src/lib/session-search.ts
|
|
@@ -3892,7 +4216,7 @@ function isEditSessionActive() {
|
|
|
3892
4216
|
}
|
|
3893
4217
|
|
|
3894
4218
|
// src/ui/badge.tsx
|
|
3895
|
-
var
|
|
4219
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3896
4220
|
var badgeVariants = cva(
|
|
3897
4221
|
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
3898
4222
|
{
|
|
@@ -3910,11 +4234,11 @@ var badgeVariants = cva(
|
|
|
3910
4234
|
}
|
|
3911
4235
|
);
|
|
3912
4236
|
function Badge({ className, variant, ...props }) {
|
|
3913
|
-
return /* @__PURE__ */ (0,
|
|
4237
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
3914
4238
|
}
|
|
3915
4239
|
|
|
3916
4240
|
// src/OhhwellsBridge.tsx
|
|
3917
|
-
var
|
|
4241
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3918
4242
|
var PRIMARY = "#0885FE";
|
|
3919
4243
|
var IMAGE_FADE_MS = 300;
|
|
3920
4244
|
function runOpacityFade(el, onDone) {
|
|
@@ -3975,24 +4299,135 @@ function getSectionsTracker() {
|
|
|
3975
4299
|
}
|
|
3976
4300
|
return el;
|
|
3977
4301
|
}
|
|
3978
|
-
function
|
|
3979
|
-
const
|
|
3980
|
-
|
|
3981
|
-
|
|
4302
|
+
function updateSectionScheduleId(insertAfter, scheduleId) {
|
|
4303
|
+
const tracker = getSectionsTracker();
|
|
4304
|
+
let sections = [];
|
|
4305
|
+
try {
|
|
4306
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
4307
|
+
} catch {
|
|
4308
|
+
}
|
|
4309
|
+
const currentPath = window.location.pathname;
|
|
4310
|
+
const updated = sections.map((s) => {
|
|
4311
|
+
if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
|
|
4312
|
+
if (s.pagePath && s.pagePath !== currentPath) return s;
|
|
4313
|
+
return { ...s, scheduleId };
|
|
4314
|
+
});
|
|
4315
|
+
tracker.textContent = JSON.stringify(updated);
|
|
4316
|
+
return tracker.textContent ?? "[]";
|
|
4317
|
+
}
|
|
4318
|
+
function schedulingSectionId(insertAfter) {
|
|
4319
|
+
return `scheduling-${insertAfter}`;
|
|
4320
|
+
}
|
|
4321
|
+
var INSERT_BEFORE_MARKER = ":before:";
|
|
4322
|
+
function parseSchedulingInsertAfter(insertAfter) {
|
|
4323
|
+
const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
|
|
4324
|
+
if (idx < 0) return { anchor: insertAfter, insertBefore: null };
|
|
4325
|
+
return {
|
|
4326
|
+
anchor: insertAfter.slice(0, idx),
|
|
4327
|
+
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
4328
|
+
};
|
|
4329
|
+
}
|
|
4330
|
+
function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
|
|
4331
|
+
const parsed = parseSchedulingInsertAfter(insertAfter);
|
|
4332
|
+
const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
|
|
4333
|
+
const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
|
|
4334
|
+
return { effectiveInsertAfter, insertBefore };
|
|
4335
|
+
}
|
|
4336
|
+
function getSchedulingMountPoint(insertAfter) {
|
|
4337
|
+
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
4338
|
+
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
4339
|
+
if (!anchorEl && anchor === "scheduling") {
|
|
4340
|
+
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
4341
|
+
anchorEl = widgets.at(-1) ?? null;
|
|
4342
|
+
}
|
|
4343
|
+
if (!anchorEl) return null;
|
|
4344
|
+
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
4345
|
+
}
|
|
4346
|
+
function schedulingMountDepth(insertAfter) {
|
|
4347
|
+
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
4348
|
+
return insertAfter.split(INSERT_BEFORE_MARKER).length - 1;
|
|
4349
|
+
}
|
|
4350
|
+
function getPageSchedulingEntries(raw) {
|
|
4351
|
+
if (!raw) return [];
|
|
4352
|
+
try {
|
|
4353
|
+
const entries = JSON.parse(raw);
|
|
4354
|
+
const currentPath = window.location.pathname;
|
|
4355
|
+
return entries.filter((e) => e.type === "scheduling" && (!e.pagePath || e.pagePath === currentPath));
|
|
4356
|
+
} catch {
|
|
4357
|
+
return [];
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
function isSchedulingWidgetMissing(entry) {
|
|
4361
|
+
const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
|
|
4362
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
4363
|
+
}
|
|
4364
|
+
function hasMissingSchedulingWidgets(entries) {
|
|
4365
|
+
return entries.some(isSchedulingWidgetMissing);
|
|
4366
|
+
}
|
|
4367
|
+
function retryMissingSchedulingMounts(entries, notifyOnConnect = false) {
|
|
4368
|
+
if (!hasMissingSchedulingWidgets(entries)) return;
|
|
4369
|
+
mountSchedulingEntries(entries, notifyOnConnect);
|
|
4370
|
+
}
|
|
4371
|
+
function initSectionsFromContent(content, removeExisting = false) {
|
|
4372
|
+
const raw = content["__ohw_sections"];
|
|
4373
|
+
if (!raw) return;
|
|
4374
|
+
try {
|
|
4375
|
+
if (removeExisting) {
|
|
4376
|
+
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => el.remove());
|
|
4377
|
+
}
|
|
4378
|
+
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
4379
|
+
if (inEditor) getSectionsTracker().textContent = raw;
|
|
4380
|
+
const pageEntries = getPageSchedulingEntries(raw);
|
|
4381
|
+
mountSchedulingEntries(pageEntries, false);
|
|
4382
|
+
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
|
|
4383
|
+
setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
|
|
4384
|
+
} catch {
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
|
|
4388
|
+
const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
|
|
4389
|
+
const sectionId = schedulingSectionId(effectiveInsertAfter);
|
|
4390
|
+
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
4391
|
+
const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
|
|
4392
|
+
if (!mountPoint) return false;
|
|
3982
4393
|
const container = document.createElement("div");
|
|
3983
4394
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
3984
|
-
|
|
3985
|
-
|
|
4395
|
+
if (insertBefore) {
|
|
4396
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
|
|
4397
|
+
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
4398
|
+
if (!beforePoint) return false;
|
|
4399
|
+
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
4400
|
+
} else {
|
|
4401
|
+
let tail = mountPoint;
|
|
4402
|
+
while (tail.nextElementSibling?.dataset.ohwSectionContainer === "scheduling") {
|
|
4403
|
+
tail = tail.nextElementSibling;
|
|
4404
|
+
}
|
|
4405
|
+
tail.insertAdjacentElement("afterend", container);
|
|
4406
|
+
}
|
|
4407
|
+
const root = (0, import_client.createRoot)(container);
|
|
4408
|
+
(0, import_react_dom.flushSync)(() => {
|
|
4409
|
+
root.render(
|
|
4410
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4411
|
+
SchedulingWidget,
|
|
4412
|
+
{
|
|
4413
|
+
notifyOnConnect,
|
|
4414
|
+
initialScheduleId: scheduleId,
|
|
4415
|
+
insertAfter: effectiveInsertAfter
|
|
4416
|
+
}
|
|
4417
|
+
)
|
|
4418
|
+
);
|
|
4419
|
+
});
|
|
3986
4420
|
const tracker = getSectionsTracker();
|
|
3987
4421
|
let sections = [];
|
|
3988
4422
|
try {
|
|
3989
4423
|
sections = JSON.parse(tracker.textContent || "[]");
|
|
3990
4424
|
} catch {
|
|
3991
4425
|
}
|
|
3992
|
-
|
|
4426
|
+
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
4427
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
|
|
3993
4428
|
sections.push({
|
|
3994
4429
|
type: "scheduling",
|
|
3995
|
-
insertAfter,
|
|
4430
|
+
insertAfter: effectiveInsertAfter,
|
|
3996
4431
|
pagePath: window.location.pathname,
|
|
3997
4432
|
...scheduleId ? { scheduleId } : {}
|
|
3998
4433
|
});
|
|
@@ -4000,6 +4435,17 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId)
|
|
|
4000
4435
|
}
|
|
4001
4436
|
return true;
|
|
4002
4437
|
}
|
|
4438
|
+
function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
4439
|
+
const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
|
|
4440
|
+
for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
|
|
4441
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
4442
|
+
const { insertAfter, scheduleId } = pending[i];
|
|
4443
|
+
if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
|
|
4444
|
+
pending.splice(i, 1);
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4003
4449
|
function collectEditableNodes() {
|
|
4004
4450
|
return Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
4005
4451
|
if (el.dataset.ohwEditable === "image") {
|
|
@@ -4157,7 +4603,7 @@ var TOOLBAR_GROUPS = [
|
|
|
4157
4603
|
];
|
|
4158
4604
|
function GlowFrame({ rect, elRef }) {
|
|
4159
4605
|
const GAP = 6;
|
|
4160
|
-
return /* @__PURE__ */ (0,
|
|
4606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4161
4607
|
"div",
|
|
4162
4608
|
{
|
|
4163
4609
|
ref: elRef,
|
|
@@ -4208,7 +4654,7 @@ function FloatingToolbar({
|
|
|
4208
4654
|
activeCommands
|
|
4209
4655
|
}) {
|
|
4210
4656
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
4211
|
-
return /* @__PURE__ */ (0,
|
|
4657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4212
4658
|
"div",
|
|
4213
4659
|
{
|
|
4214
4660
|
ref: elRef,
|
|
@@ -4231,11 +4677,11 @@ function FloatingToolbar({
|
|
|
4231
4677
|
pointerEvents: "auto",
|
|
4232
4678
|
whiteSpace: "nowrap"
|
|
4233
4679
|
},
|
|
4234
|
-
children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
4235
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
4680
|
+
children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react3.default.Fragment, { children: [
|
|
4681
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
|
|
4236
4682
|
btns.map((btn) => {
|
|
4237
4683
|
const isActive = activeCommands.has(btn.cmd);
|
|
4238
|
-
return /* @__PURE__ */ (0,
|
|
4684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4239
4685
|
"button",
|
|
4240
4686
|
{
|
|
4241
4687
|
title: btn.title,
|
|
@@ -4261,7 +4707,7 @@ function FloatingToolbar({
|
|
|
4261
4707
|
flexShrink: 0,
|
|
4262
4708
|
padding: 6
|
|
4263
4709
|
},
|
|
4264
|
-
children: /* @__PURE__ */ (0,
|
|
4710
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4265
4711
|
"svg",
|
|
4266
4712
|
{
|
|
4267
4713
|
width: "16",
|
|
@@ -4294,7 +4740,7 @@ function StateToggle({
|
|
|
4294
4740
|
states,
|
|
4295
4741
|
onStateChange
|
|
4296
4742
|
}) {
|
|
4297
|
-
return /* @__PURE__ */ (0,
|
|
4743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4298
4744
|
ToggleGroup,
|
|
4299
4745
|
{
|
|
4300
4746
|
"data-ohw-state-toggle": "",
|
|
@@ -4308,18 +4754,35 @@ function StateToggle({
|
|
|
4308
4754
|
left: rect.right - 8,
|
|
4309
4755
|
transform: "translateX(-100%)"
|
|
4310
4756
|
},
|
|
4311
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
4757
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
4312
4758
|
}
|
|
4313
4759
|
);
|
|
4314
4760
|
}
|
|
4315
4761
|
var contentCache = /* @__PURE__ */ new Map();
|
|
4762
|
+
function resolveSubdomain(subdomainFromQuery) {
|
|
4763
|
+
if (subdomainFromQuery) return subdomainFromQuery;
|
|
4764
|
+
if (typeof window !== "undefined") {
|
|
4765
|
+
const parts = window.location.hostname.split(".");
|
|
4766
|
+
if (parts.length >= 3 && parts[0] !== "www") return parts[0];
|
|
4767
|
+
}
|
|
4768
|
+
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
|
|
4769
|
+
if (siteUrl) {
|
|
4770
|
+
try {
|
|
4771
|
+
const host = new URL(siteUrl).hostname;
|
|
4772
|
+
const siteParts = host.split(".");
|
|
4773
|
+
if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
|
|
4774
|
+
} catch {
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
return "";
|
|
4778
|
+
}
|
|
4316
4779
|
function OhhwellsBridge() {
|
|
4317
4780
|
const pathname = (0, import_navigation.usePathname)();
|
|
4318
4781
|
const router = (0, import_navigation.useRouter)();
|
|
4319
4782
|
const searchParams = (0, import_navigation.useSearchParams)();
|
|
4320
4783
|
const isEditMode = isEditSessionActive();
|
|
4321
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
4322
|
-
(0,
|
|
4784
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react3.useState)(null);
|
|
4785
|
+
(0, import_react3.useEffect)(() => {
|
|
4323
4786
|
const figtreeFontId = "ohw-figtree-font";
|
|
4324
4787
|
if (!document.getElementById(figtreeFontId)) {
|
|
4325
4788
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -4342,44 +4805,40 @@ function OhhwellsBridge() {
|
|
|
4342
4805
|
};
|
|
4343
4806
|
}, []);
|
|
4344
4807
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
4345
|
-
const subdomain = subdomainFromQuery
|
|
4346
|
-
|
|
4347
|
-
const parts = window.location.hostname.split(".");
|
|
4348
|
-
return parts.length >= 3 && parts[0] !== "www" ? parts[0] : "";
|
|
4349
|
-
})();
|
|
4350
|
-
const postToParent = (0, import_react2.useCallback)((data) => {
|
|
4808
|
+
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
4809
|
+
const postToParent = (0, import_react3.useCallback)((data) => {
|
|
4351
4810
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
4352
4811
|
window.parent.postMessage(data, "*");
|
|
4353
4812
|
}
|
|
4354
4813
|
}, []);
|
|
4355
|
-
const [fetchState, setFetchState] = (0,
|
|
4356
|
-
const autoSaveTimers = (0,
|
|
4357
|
-
const activeElRef = (0,
|
|
4358
|
-
const originalContentRef = (0,
|
|
4359
|
-
const activeStateElRef = (0,
|
|
4360
|
-
const parentScrollRef = (0,
|
|
4361
|
-
const toolbarElRef = (0,
|
|
4362
|
-
const glowElRef = (0,
|
|
4363
|
-
const hoveredImageRef = (0,
|
|
4364
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
4365
|
-
const hoveredGapRef = (0,
|
|
4366
|
-
const imageUnhoverTimerRef = (0,
|
|
4367
|
-
const imageShowTimerRef = (0,
|
|
4368
|
-
const editStylesRef = (0,
|
|
4369
|
-
const activateRef = (0,
|
|
4814
|
+
const [fetchState, setFetchState] = (0, import_react3.useState)("idle");
|
|
4815
|
+
const autoSaveTimers = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
4816
|
+
const activeElRef = (0, import_react3.useRef)(null);
|
|
4817
|
+
const originalContentRef = (0, import_react3.useRef)(null);
|
|
4818
|
+
const activeStateElRef = (0, import_react3.useRef)(null);
|
|
4819
|
+
const parentScrollRef = (0, import_react3.useRef)(null);
|
|
4820
|
+
const toolbarElRef = (0, import_react3.useRef)(null);
|
|
4821
|
+
const glowElRef = (0, import_react3.useRef)(null);
|
|
4822
|
+
const hoveredImageRef = (0, import_react3.useRef)(null);
|
|
4823
|
+
const hoveredImageHasTextOverlapRef = (0, import_react3.useRef)(false);
|
|
4824
|
+
const hoveredGapRef = (0, import_react3.useRef)(null);
|
|
4825
|
+
const imageUnhoverTimerRef = (0, import_react3.useRef)(null);
|
|
4826
|
+
const imageShowTimerRef = (0, import_react3.useRef)(null);
|
|
4827
|
+
const editStylesRef = (0, import_react3.useRef)(null);
|
|
4828
|
+
const activateRef = (0, import_react3.useRef)(() => {
|
|
4370
4829
|
});
|
|
4371
|
-
const deactivateRef = (0,
|
|
4830
|
+
const deactivateRef = (0, import_react3.useRef)(() => {
|
|
4372
4831
|
});
|
|
4373
|
-
const refreshActiveCommandsRef = (0,
|
|
4832
|
+
const refreshActiveCommandsRef = (0, import_react3.useRef)(() => {
|
|
4374
4833
|
});
|
|
4375
|
-
const postToParentRef = (0,
|
|
4834
|
+
const postToParentRef = (0, import_react3.useRef)(postToParent);
|
|
4376
4835
|
postToParentRef.current = postToParent;
|
|
4377
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
4378
|
-
const [toggleState, setToggleState] = (0,
|
|
4379
|
-
const [maxBadge, setMaxBadge] = (0,
|
|
4380
|
-
const [activeCommands, setActiveCommands] = (0,
|
|
4381
|
-
const [sectionGap, setSectionGap] = (0,
|
|
4382
|
-
(0,
|
|
4836
|
+
const [toolbarRect, setToolbarRect] = (0, import_react3.useState)(null);
|
|
4837
|
+
const [toggleState, setToggleState] = (0, import_react3.useState)(null);
|
|
4838
|
+
const [maxBadge, setMaxBadge] = (0, import_react3.useState)(null);
|
|
4839
|
+
const [activeCommands, setActiveCommands] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
|
|
4840
|
+
const [sectionGap, setSectionGap] = (0, import_react3.useState)(null);
|
|
4841
|
+
(0, import_react3.useEffect)(() => {
|
|
4383
4842
|
const update = () => {
|
|
4384
4843
|
const el = activeElRef.current;
|
|
4385
4844
|
if (el) setToolbarRect(el.getBoundingClientRect());
|
|
@@ -4403,10 +4862,10 @@ function OhhwellsBridge() {
|
|
|
4403
4862
|
vvp.removeEventListener("resize", update);
|
|
4404
4863
|
};
|
|
4405
4864
|
}, []);
|
|
4406
|
-
const refreshStateRules = (0,
|
|
4865
|
+
const refreshStateRules = (0, import_react3.useCallback)(() => {
|
|
4407
4866
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
4408
4867
|
}, []);
|
|
4409
|
-
const deactivate = (0,
|
|
4868
|
+
const deactivate = (0, import_react3.useCallback)(() => {
|
|
4410
4869
|
const el = activeElRef.current;
|
|
4411
4870
|
if (!el) return;
|
|
4412
4871
|
const key = el.dataset.ohwKey;
|
|
@@ -4431,7 +4890,7 @@ function OhhwellsBridge() {
|
|
|
4431
4890
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
4432
4891
|
postToParent({ type: "ow:exit-edit" });
|
|
4433
4892
|
}, [postToParent]);
|
|
4434
|
-
const activate = (0,
|
|
4893
|
+
const activate = (0, import_react3.useCallback)((el) => {
|
|
4435
4894
|
if (activeElRef.current === el) return;
|
|
4436
4895
|
deactivate();
|
|
4437
4896
|
if (hoveredImageRef.current) {
|
|
@@ -4449,25 +4908,13 @@ function OhhwellsBridge() {
|
|
|
4449
4908
|
}, [deactivate, postToParent]);
|
|
4450
4909
|
activateRef.current = activate;
|
|
4451
4910
|
deactivateRef.current = deactivate;
|
|
4452
|
-
(0,
|
|
4911
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
4453
4912
|
if (!subdomain || isEditMode) {
|
|
4454
4913
|
setFetchState("done");
|
|
4455
4914
|
return;
|
|
4456
4915
|
}
|
|
4457
4916
|
const applyContent = (content) => {
|
|
4458
4917
|
const imageLoads = [];
|
|
4459
|
-
document.querySelectorAll("[data-ohw-section-container]").forEach((el) => el.remove());
|
|
4460
|
-
if (content["__ohw_sections"]) {
|
|
4461
|
-
try {
|
|
4462
|
-
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4463
|
-
const currentPath = window.location.pathname;
|
|
4464
|
-
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4465
|
-
if (pagePath && pagePath !== currentPath) return;
|
|
4466
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4467
|
-
});
|
|
4468
|
-
} catch {
|
|
4469
|
-
}
|
|
4470
|
-
}
|
|
4471
4918
|
for (const [key, val] of Object.entries(content)) {
|
|
4472
4919
|
if (key === "__ohw_sections") continue;
|
|
4473
4920
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -4488,6 +4935,7 @@ function OhhwellsBridge() {
|
|
|
4488
4935
|
}
|
|
4489
4936
|
});
|
|
4490
4937
|
}
|
|
4938
|
+
initSectionsFromContent(content, true);
|
|
4491
4939
|
return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
|
|
4492
4940
|
}) : Promise.resolve();
|
|
4493
4941
|
};
|
|
@@ -4512,22 +4960,13 @@ function OhhwellsBridge() {
|
|
|
4512
4960
|
cancelled = true;
|
|
4513
4961
|
};
|
|
4514
4962
|
}, [subdomain, isEditMode, pathname]);
|
|
4515
|
-
(0,
|
|
4963
|
+
(0, import_react3.useEffect)(() => {
|
|
4516
4964
|
if (!subdomain || isEditMode) return;
|
|
4965
|
+
let debounceTimer = null;
|
|
4517
4966
|
const applyFromCache = () => {
|
|
4518
4967
|
const content = contentCache.get(subdomain);
|
|
4519
4968
|
if (!content) return;
|
|
4520
|
-
|
|
4521
|
-
try {
|
|
4522
|
-
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4523
|
-
const currentPath = window.location.pathname;
|
|
4524
|
-
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4525
|
-
if (pagePath && pagePath !== currentPath) return;
|
|
4526
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4527
|
-
});
|
|
4528
|
-
} catch {
|
|
4529
|
-
}
|
|
4530
|
-
}
|
|
4969
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
4531
4970
|
for (const [key, val] of Object.entries(content)) {
|
|
4532
4971
|
if (key === "__ohw_sections") continue;
|
|
4533
4972
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -4543,21 +4982,28 @@ function OhhwellsBridge() {
|
|
|
4543
4982
|
});
|
|
4544
4983
|
}
|
|
4545
4984
|
};
|
|
4546
|
-
|
|
4547
|
-
|
|
4985
|
+
const scheduleApply = () => {
|
|
4986
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
4987
|
+
debounceTimer = setTimeout(applyFromCache, 150);
|
|
4988
|
+
};
|
|
4989
|
+
scheduleApply();
|
|
4990
|
+
const observer = new MutationObserver(scheduleApply);
|
|
4548
4991
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
4549
|
-
return () =>
|
|
4550
|
-
|
|
4551
|
-
|
|
4992
|
+
return () => {
|
|
4993
|
+
observer.disconnect();
|
|
4994
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
4995
|
+
};
|
|
4996
|
+
}, [subdomain, isEditMode, pathname]);
|
|
4997
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
4552
4998
|
const el = document.getElementById("ohw-loader");
|
|
4553
4999
|
if (!el) return;
|
|
4554
5000
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
4555
5001
|
el.style.display = visible ? "flex" : "none";
|
|
4556
5002
|
}, [subdomain, fetchState]);
|
|
4557
|
-
(0,
|
|
5003
|
+
(0, import_react3.useEffect)(() => {
|
|
4558
5004
|
postToParent({ type: "ow:navigation", path: pathname });
|
|
4559
5005
|
}, [pathname, postToParent]);
|
|
4560
|
-
(0,
|
|
5006
|
+
(0, import_react3.useEffect)(() => {
|
|
4561
5007
|
if (!isEditMode) return;
|
|
4562
5008
|
const measure = () => {
|
|
4563
5009
|
const h = document.body.scrollHeight;
|
|
@@ -4581,7 +5027,7 @@ function OhhwellsBridge() {
|
|
|
4581
5027
|
window.removeEventListener("resize", handleResize);
|
|
4582
5028
|
};
|
|
4583
5029
|
}, [pathname, isEditMode, postToParent]);
|
|
4584
|
-
(0,
|
|
5030
|
+
(0, import_react3.useEffect)(() => {
|
|
4585
5031
|
if (!subdomainFromQuery || isEditMode) return;
|
|
4586
5032
|
const handleClick = (e) => {
|
|
4587
5033
|
const anchor = e.target.closest("a");
|
|
@@ -4597,7 +5043,7 @@ function OhhwellsBridge() {
|
|
|
4597
5043
|
document.addEventListener("click", handleClick, true);
|
|
4598
5044
|
return () => document.removeEventListener("click", handleClick, true);
|
|
4599
5045
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
4600
|
-
(0,
|
|
5046
|
+
(0, import_react3.useEffect)(() => {
|
|
4601
5047
|
if (!isEditMode) {
|
|
4602
5048
|
editStylesRef.current?.base.remove();
|
|
4603
5049
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -5120,17 +5566,10 @@ function OhhwellsBridge() {
|
|
|
5120
5566
|
if (e.data?.type !== "ow:hydrate") return;
|
|
5121
5567
|
const content = e.data.content;
|
|
5122
5568
|
if (!content) return;
|
|
5569
|
+
let sectionsJson = null;
|
|
5123
5570
|
for (const [key, val] of Object.entries(content)) {
|
|
5124
5571
|
if (key === "__ohw_sections") {
|
|
5125
|
-
|
|
5126
|
-
const entries = JSON.parse(val);
|
|
5127
|
-
const tracker = getSectionsTracker();
|
|
5128
|
-
tracker.textContent = val;
|
|
5129
|
-
entries.forEach(({ type, insertAfter, scheduleId }) => {
|
|
5130
|
-
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
5131
|
-
});
|
|
5132
|
-
} catch {
|
|
5133
|
-
}
|
|
5572
|
+
sectionsJson = val;
|
|
5134
5573
|
continue;
|
|
5135
5574
|
}
|
|
5136
5575
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -5144,6 +5583,9 @@ function OhhwellsBridge() {
|
|
|
5144
5583
|
}
|
|
5145
5584
|
});
|
|
5146
5585
|
}
|
|
5586
|
+
if (sectionsJson) {
|
|
5587
|
+
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
5588
|
+
}
|
|
5147
5589
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
5148
5590
|
};
|
|
5149
5591
|
window.addEventListener("message", handleHydrate);
|
|
@@ -5194,9 +5636,9 @@ function OhhwellsBridge() {
|
|
|
5194
5636
|
};
|
|
5195
5637
|
const handleInsertSection = (e) => {
|
|
5196
5638
|
if (e.data?.type !== "ow:insert-section") return;
|
|
5197
|
-
const { widgetType, insertAfter } = e.data;
|
|
5639
|
+
const { widgetType, insertAfter, insertBefore } = e.data;
|
|
5198
5640
|
if (widgetType !== "scheduling") return;
|
|
5199
|
-
const inserted = mountSchedulingWidget(insertAfter, true);
|
|
5641
|
+
const inserted = mountSchedulingWidget(insertAfter, true, void 0, insertBefore ?? null);
|
|
5200
5642
|
if (inserted) {
|
|
5201
5643
|
const tracker = getSectionsTracker();
|
|
5202
5644
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
@@ -5207,39 +5649,31 @@ function OhhwellsBridge() {
|
|
|
5207
5649
|
const handleSwitchSchedule = (e) => {
|
|
5208
5650
|
if (e.data?.type !== "ow:switch-schedule") return;
|
|
5209
5651
|
const scheduleId = e.data.scheduleId;
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
const
|
|
5218
|
-
const
|
|
5219
|
-
|
|
5220
|
-
);
|
|
5221
|
-
|
|
5222
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5652
|
+
const insertAfter = e.data.insertAfter;
|
|
5653
|
+
if (!scheduleId || !insertAfter) return;
|
|
5654
|
+
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
5655
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5656
|
+
};
|
|
5657
|
+
const handleScheduleLinked = (e) => {
|
|
5658
|
+
if (e.data?.type !== "ow:schedule-linked") return;
|
|
5659
|
+
const scheduleId = e.data.scheduleId;
|
|
5660
|
+
const insertAfter = e.data.insertAfter;
|
|
5661
|
+
if (!scheduleId || !insertAfter) return;
|
|
5662
|
+
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
5663
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5223
5664
|
};
|
|
5224
5665
|
const handleClearSchedulingWidget = (e) => {
|
|
5225
5666
|
if (e.data?.type !== "ow:clear-scheduling-widget") return;
|
|
5226
|
-
const
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
} catch {
|
|
5231
|
-
}
|
|
5232
|
-
const currentPath = window.location.pathname;
|
|
5233
|
-
const updated = sections.map(
|
|
5234
|
-
(s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId: null } : s
|
|
5235
|
-
);
|
|
5236
|
-
tracker.textContent = JSON.stringify(updated);
|
|
5237
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5667
|
+
const insertAfter = e.data.insertAfter;
|
|
5668
|
+
if (!insertAfter) return;
|
|
5669
|
+
const text = updateSectionScheduleId(insertAfter, null);
|
|
5670
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
5238
5671
|
};
|
|
5239
5672
|
const handleRemoveSchedulingSection = (e) => {
|
|
5240
5673
|
if (e.data?.type !== "ow:remove-scheduling-section") return;
|
|
5241
|
-
|
|
5242
|
-
|
|
5674
|
+
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => {
|
|
5675
|
+
el.remove();
|
|
5676
|
+
});
|
|
5243
5677
|
const tracker = getSectionsTracker();
|
|
5244
5678
|
let sections = [];
|
|
5245
5679
|
try {
|
|
@@ -5358,6 +5792,7 @@ function OhhwellsBridge() {
|
|
|
5358
5792
|
window.addEventListener("message", handleSave);
|
|
5359
5793
|
window.addEventListener("message", handleInsertSection);
|
|
5360
5794
|
window.addEventListener("message", handleSwitchSchedule);
|
|
5795
|
+
window.addEventListener("message", handleScheduleLinked);
|
|
5361
5796
|
window.addEventListener("message", handleClearSchedulingWidget);
|
|
5362
5797
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
5363
5798
|
window.addEventListener("message", handleImageUrl);
|
|
@@ -5396,6 +5831,7 @@ function OhhwellsBridge() {
|
|
|
5396
5831
|
window.removeEventListener("message", handleSave);
|
|
5397
5832
|
window.removeEventListener("message", handleInsertSection);
|
|
5398
5833
|
window.removeEventListener("message", handleSwitchSchedule);
|
|
5834
|
+
window.removeEventListener("message", handleScheduleLinked);
|
|
5399
5835
|
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
5400
5836
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
5401
5837
|
window.removeEventListener("message", handleImageUrl);
|
|
@@ -5412,7 +5848,7 @@ function OhhwellsBridge() {
|
|
|
5412
5848
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
5413
5849
|
};
|
|
5414
5850
|
}, [isEditMode, refreshStateRules]);
|
|
5415
|
-
(0,
|
|
5851
|
+
(0, import_react3.useEffect)(() => {
|
|
5416
5852
|
if (!isEditMode) return;
|
|
5417
5853
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
5418
5854
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -5434,13 +5870,13 @@ function OhhwellsBridge() {
|
|
|
5434
5870
|
clearTimeout(timer);
|
|
5435
5871
|
};
|
|
5436
5872
|
}, [pathname, isEditMode, refreshStateRules, postToParent]);
|
|
5437
|
-
const handleCommand = (0,
|
|
5873
|
+
const handleCommand = (0, import_react3.useCallback)((cmd) => {
|
|
5438
5874
|
document.execCommand(cmd, false);
|
|
5439
5875
|
activeElRef.current?.focus();
|
|
5440
5876
|
if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
|
|
5441
5877
|
refreshActiveCommandsRef.current();
|
|
5442
5878
|
}, []);
|
|
5443
|
-
const handleStateChange = (0,
|
|
5879
|
+
const handleStateChange = (0, import_react3.useCallback)((state) => {
|
|
5444
5880
|
if (!activeStateElRef.current) return;
|
|
5445
5881
|
const el = activeStateElRef.current;
|
|
5446
5882
|
if (state === "Default") {
|
|
@@ -5453,13 +5889,13 @@ function OhhwellsBridge() {
|
|
|
5453
5889
|
}
|
|
5454
5890
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
5455
5891
|
}, [deactivate]);
|
|
5456
|
-
return bridgeRoot ? (0,
|
|
5457
|
-
/* @__PURE__ */ (0,
|
|
5458
|
-
toolbarRect && /* @__PURE__ */ (0,
|
|
5459
|
-
/* @__PURE__ */ (0,
|
|
5460
|
-
/* @__PURE__ */ (0,
|
|
5892
|
+
return bridgeRoot ? (0, import_react_dom2.createPortal)(
|
|
5893
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5894
|
+
toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5895
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
|
|
5896
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
|
|
5461
5897
|
] }),
|
|
5462
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
5898
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
5463
5899
|
"div",
|
|
5464
5900
|
{
|
|
5465
5901
|
"data-ohw-max-badge": "",
|
|
@@ -5485,7 +5921,7 @@ function OhhwellsBridge() {
|
|
|
5485
5921
|
]
|
|
5486
5922
|
}
|
|
5487
5923
|
),
|
|
5488
|
-
toggleState && /* @__PURE__ */ (0,
|
|
5924
|
+
toggleState && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5489
5925
|
StateToggle,
|
|
5490
5926
|
{
|
|
5491
5927
|
rect: toggleState.rect,
|
|
@@ -5494,15 +5930,15 @@ function OhhwellsBridge() {
|
|
|
5494
5930
|
onStateChange: handleStateChange
|
|
5495
5931
|
}
|
|
5496
5932
|
),
|
|
5497
|
-
sectionGap && /* @__PURE__ */ (0,
|
|
5933
|
+
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
5498
5934
|
"div",
|
|
5499
5935
|
{
|
|
5500
5936
|
"data-ohw-section-insert-line": "",
|
|
5501
5937
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
5502
5938
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
5503
5939
|
children: [
|
|
5504
|
-
/* @__PURE__ */ (0,
|
|
5505
|
-
/* @__PURE__ */ (0,
|
|
5940
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
5941
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5506
5942
|
Badge,
|
|
5507
5943
|
{
|
|
5508
5944
|
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
@@ -5515,7 +5951,7 @@ function OhhwellsBridge() {
|
|
|
5515
5951
|
children: "Add Section"
|
|
5516
5952
|
}
|
|
5517
5953
|
),
|
|
5518
|
-
/* @__PURE__ */ (0,
|
|
5954
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
5519
5955
|
]
|
|
5520
5956
|
}
|
|
5521
5957
|
)
|