@riverbankcms/sdk 0.74.0 → 0.75.0
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/{PreviewEditorSidebar-5XL7M3OM.mjs → PreviewEditorSidebar-U2IHCBYN.mjs} +3 -3
- package/dist/{PreviewEditorUI-ZDFRDJID.mjs → PreviewEditorUI-ZGH2RQNP.mjs} +3 -3
- package/dist/SdkPreviewModeRuntime-MTUGBTLQ.mjs +8 -0
- package/dist/_dts/api/src/cache-tags.d.ts +22 -0
- package/dist/_dts/api/src/contentRuntime.d.ts +1 -0
- package/dist/_dts/api/src/endpoints.d.ts +24 -24
- package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +2 -1
- package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +4 -1
- package/dist/_dts/blocks/src/client/booking-form.d.ts +2 -0
- package/dist/_dts/blocks/src/client/carousel.d.ts +1 -0
- package/dist/_dts/blocks/src/client/course-registration.d.ts +2 -0
- package/dist/_dts/blocks/src/client/events.d.ts +4 -0
- package/dist/_dts/blocks/src/client/form.d.ts +2 -0
- package/dist/_dts/blocks/src/client/header.d.ts +1 -0
- package/dist/_dts/blocks/src/client/location-map.d.ts +1 -0
- package/dist/_dts/blocks/src/client/newsletter-form.d.ts +2 -0
- package/dist/_dts/blocks/src/client/shop.d.ts +6 -0
- package/dist/_dts/blocks/src/lib/video.d.ts +2 -0
- package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +21 -1
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/events/index.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/header-section.client.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/header-section.server.d.ts +1 -0
- package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +5 -0
- package/dist/_dts/preview-next/src/client/preview/SiteChromeEditableSurface.d.ts +12 -2
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -0
- package/dist/_dts/sdk/src/rendering/islands/deferredVideoEmbeds.d.ts +2 -0
- package/dist/_dts/sdk/src/rendering/server.d.ts +3 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/{chunk-YY7K3QD2.mjs → chunk-BGMNDF6T.mjs} +7 -7
- package/dist/{chunk-2MIWNFJM.mjs → chunk-GFE74WRD.mjs} +309 -84
- package/dist/{chunk-CEQBBLMJ.mjs → chunk-RWXQBRQZ.mjs} +1 -1
- package/dist/{chunk-7RX72SK2.mjs → chunk-VX7B5VAC.mjs} +36 -25
- package/dist/{chunk-YRJKZEQ3.mjs → chunk-Z7JLNTJR.mjs} +1 -1
- package/dist/{chunk-CBD47MTM.mjs → chunk-ZSHFGFUG.mjs} +2 -2
- package/dist/cli/index.mjs +3395 -3753
- package/dist/client/{accordion-ZZVXWV3N.mjs → accordion-T2UD2ZTH.mjs} +1 -1
- package/dist/client/bookingForm-GUP75FKN.mjs +3022 -0
- package/dist/client/bookings.mjs +19 -10
- package/dist/client/{carousel-25WK2H7G.mjs → carousel-2NQA6V57.mjs} +3 -2
- package/dist/client/cart-5TFIAFDS.mjs +18 -0
- package/dist/client/checkout-TP4WAHZE.mjs +18 -0
- package/dist/client/chunk-2PHQZ666.mjs +383 -0
- package/dist/client/chunk-3DCJ45Z2.mjs +36 -0
- package/dist/client/chunk-3PEDD5KJ.mjs +146 -0
- package/dist/client/chunk-CY2ZTSE5.mjs +204 -0
- package/dist/client/chunk-F7LHOKEH.mjs +146 -0
- package/dist/client/{chunk-6VGXRE34.mjs → chunk-FU2QRZMX.mjs} +6 -6
- package/dist/client/chunk-I2MMZO53.mjs +6 -0
- package/dist/client/chunk-II7O4XN3.mjs +2206 -0
- package/dist/client/chunk-M3L3KYYR.mjs +1181 -0
- package/dist/client/chunk-NWOUL6JY.mjs +1378 -0
- package/dist/client/chunk-OJPZEZU2.mjs +31 -0
- package/dist/client/chunk-RTZ3JKKX.mjs +178 -0
- package/dist/client/chunk-TQ5MSPDX.mjs +74 -0
- package/dist/client/chunk-VUAOE3AG.mjs +5592 -0
- package/dist/client/chunk-WJXXNDSE.mjs +245 -0
- package/dist/client/chunk-YLMKMCSJ.mjs +86 -0
- package/dist/client/chunk-ZLMS67RR.mjs +106 -0
- package/dist/client/client.mjs +51626 -52074
- package/dist/client/courseRegistration-5DPU6PDY.mjs +1737 -0
- package/dist/client/{eventCalendar-X6GIPYFM.mjs → eventCalendar-F3GZGTEF.mjs} +13 -2
- package/dist/client/{eventCombined-EZUOPM3G.mjs → eventCombined-BQOB6QMY.mjs} +13 -2
- package/dist/client/eventDetails-PEM2EJWE.mjs +25 -0
- package/dist/client/{eventListing-HEFGAETC.mjs → eventListing-YMIQPVME.mjs} +13 -2
- package/dist/client/{eventRegistration-3LCP2V3P.mjs → eventRegistration-4I6ZNDUF.mjs} +13 -2
- package/dist/client/form-ZJVAYZ6G.mjs +300 -0
- package/dist/client/headerSection-TOT5MGTF.mjs +729 -0
- package/dist/client/hooks.mjs +49 -33
- package/dist/client/locationMap-J66NZREU.mjs +227 -0
- package/dist/client/newsletterForm-ET2XUMRO.mjs +208 -0
- package/dist/client/productDetail-C2XIH7C5.mjs +18 -0
- package/dist/client/productList-T2AZLFTP.mjs +18 -0
- package/dist/client/rendering/client.mjs +11763 -12445
- package/dist/client/rendering/islands.mjs +98 -21
- package/dist/client/rendering.mjs +46778 -47229
- package/dist/client/shop-UZ6IUZXD.mjs +20 -0
- package/dist/preview-next/before-render.mjs +37 -25
- package/dist/preview-next/client/runtime.mjs +5 -5
- package/dist/preview-next/middleware.mjs +37 -25
- package/dist/{sdk-runtime-OHNONZ5U.mjs → sdk-runtime-JCUQM63Y.mjs} +6 -6
- package/dist/server/components.mjs +409 -266
- package/dist/server/config-validation.mjs +49 -33
- package/dist/server/config.mjs +49 -33
- package/dist/server/data.mjs +49 -33
- package/dist/server/index.mjs +45 -33
- package/dist/server/next.mjs +405 -262
- package/dist/server/page-converter.mjs +12 -8
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +493 -265
- package/dist/server/rendering.mjs +411 -268
- package/dist/server/routing.mjs +49 -33
- package/dist/server/server.mjs +50 -34
- package/dist/server/theme-bridge.mjs +5 -0
- package/dist/styles/index.css +5 -0
- package/package.json +2 -1
- package/dist/SdkPreviewModeRuntime-CRYNDSPL.mjs +0 -8
- package/dist/client/bookingForm-4X77HKDS.mjs +0 -34
- package/dist/client/cart-JWD2VRFU.mjs +0 -11
- package/dist/client/checkout-V7KYGWL7.mjs +0 -11
- package/dist/client/chunk-5IYGMTUE.mjs +0 -18614
- package/dist/client/chunk-RKCFVIMS.mjs +0 -26
- package/dist/client/courseRegistration-O6ZPK4YT.mjs +0 -29
- package/dist/client/eventDetails-3WODIXET.mjs +0 -14
- package/dist/client/form-AKXQMY6Z.mjs +0 -85
- package/dist/client/headerSection-5KHCMU6B.mjs +0 -12
- package/dist/client/locationMap-7HIADW76.mjs +0 -14
- package/dist/client/newsletterForm-5N4YTMU3.mjs +0 -60
- package/dist/client/productDetail-IZUA7ZP3.mjs +0 -11
- package/dist/client/productList-KWIIJE6I.mjs +0 -11
- package/dist/client/shop-XZQFRQWZ.mjs +0 -13
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// ../blocks/src/system/runtime/shared/components/ModalShell.tsx
|
|
6
|
+
var modalBodyScrollLockCount = 0;
|
|
7
|
+
var modalBodyOriginalOverflow = null;
|
|
8
|
+
function lockBodyScroll() {
|
|
9
|
+
if (typeof document === "undefined") {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (modalBodyScrollLockCount === 0) {
|
|
13
|
+
modalBodyOriginalOverflow = document.body.style.overflow;
|
|
14
|
+
document.body.style.overflow = "hidden";
|
|
15
|
+
}
|
|
16
|
+
modalBodyScrollLockCount += 1;
|
|
17
|
+
}
|
|
18
|
+
function unlockBodyScroll() {
|
|
19
|
+
if (typeof document === "undefined" || modalBodyScrollLockCount === 0) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
modalBodyScrollLockCount -= 1;
|
|
23
|
+
if (modalBodyScrollLockCount === 0) {
|
|
24
|
+
document.body.style.overflow = modalBodyOriginalOverflow ?? "";
|
|
25
|
+
modalBodyOriginalOverflow = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function ModalShell({
|
|
29
|
+
title,
|
|
30
|
+
titleId,
|
|
31
|
+
onClose,
|
|
32
|
+
children,
|
|
33
|
+
portalRoot,
|
|
34
|
+
portal = false,
|
|
35
|
+
overlayClassName,
|
|
36
|
+
modalClassName,
|
|
37
|
+
renderSrOnlyTitle = false,
|
|
38
|
+
renderHeader,
|
|
39
|
+
headerClassName,
|
|
40
|
+
titleClassName,
|
|
41
|
+
closeButtonClassName,
|
|
42
|
+
closeIcon
|
|
43
|
+
}) {
|
|
44
|
+
const closeButtonRef = React.useRef(null);
|
|
45
|
+
const onCloseRef = React.useRef(onClose);
|
|
46
|
+
onCloseRef.current = onClose;
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
closeButtonRef.current?.focus();
|
|
49
|
+
const onKeyDown = (event) => {
|
|
50
|
+
if (event.key === "Escape") {
|
|
51
|
+
onCloseRef.current();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
document.addEventListener("keydown", onKeyDown);
|
|
55
|
+
lockBodyScroll();
|
|
56
|
+
return () => {
|
|
57
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
58
|
+
unlockBodyScroll();
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
61
|
+
const srOnlyTitle = renderSrOnlyTitle ? /* @__PURE__ */ jsx(
|
|
62
|
+
"h2",
|
|
63
|
+
{
|
|
64
|
+
id: titleId,
|
|
65
|
+
style: {
|
|
66
|
+
position: "absolute",
|
|
67
|
+
width: 1,
|
|
68
|
+
height: 1,
|
|
69
|
+
padding: 0,
|
|
70
|
+
margin: -1,
|
|
71
|
+
overflow: "hidden",
|
|
72
|
+
clip: "rect(0,0,0,0)",
|
|
73
|
+
whiteSpace: "nowrap",
|
|
74
|
+
border: 0
|
|
75
|
+
},
|
|
76
|
+
children: title
|
|
77
|
+
}
|
|
78
|
+
) : null;
|
|
79
|
+
const header = renderHeader ? renderHeader({ title, titleId, onClose, closeButtonRef }) : /* @__PURE__ */ jsxs("div", { className: headerClassName, children: [
|
|
80
|
+
!renderSrOnlyTitle ? /* @__PURE__ */ jsx("h3", { className: titleClassName, id: titleId, children: title }) : null,
|
|
81
|
+
/* @__PURE__ */ jsx(
|
|
82
|
+
"button",
|
|
83
|
+
{
|
|
84
|
+
ref: closeButtonRef,
|
|
85
|
+
type: "button",
|
|
86
|
+
className: closeButtonClassName,
|
|
87
|
+
onClick: onClose,
|
|
88
|
+
"aria-label": "Close",
|
|
89
|
+
children: closeIcon ?? "\xD7"
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
] });
|
|
93
|
+
const modal = /* @__PURE__ */ jsx("div", { className: overlayClassName, onClick: onClose, children: /* @__PURE__ */ jsxs(
|
|
94
|
+
"div",
|
|
95
|
+
{
|
|
96
|
+
className: modalClassName,
|
|
97
|
+
onClick: (event) => event.stopPropagation(),
|
|
98
|
+
role: "dialog",
|
|
99
|
+
"aria-modal": "true",
|
|
100
|
+
"aria-labelledby": titleId,
|
|
101
|
+
children: [
|
|
102
|
+
srOnlyTitle,
|
|
103
|
+
header,
|
|
104
|
+
children
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
) });
|
|
108
|
+
if (!portal) {
|
|
109
|
+
return modal;
|
|
110
|
+
}
|
|
111
|
+
if (typeof document === "undefined") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
if (!portalRoot) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return createPortal(modal, portalRoot);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ../blocks/src/system/runtime/shared/utils/checkoutRoute.ts
|
|
121
|
+
function resolveDedicatedCheckoutTarget(pathname) {
|
|
122
|
+
const internalPublishedMatch = pathname.match(
|
|
123
|
+
/^\/internal-sites\/([^/]+)\/([^/]+)\/published(?:\/.*)?$/
|
|
124
|
+
);
|
|
125
|
+
if (internalPublishedMatch) {
|
|
126
|
+
const hostKey = internalPublishedMatch[1];
|
|
127
|
+
const siteIdentifier = internalPublishedMatch[2];
|
|
128
|
+
if (hostKey && siteIdentifier) {
|
|
129
|
+
return {
|
|
130
|
+
kind: "internal_published_preview",
|
|
131
|
+
hostKey,
|
|
132
|
+
siteIdentifier
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { kind: "public" };
|
|
137
|
+
}
|
|
138
|
+
function resolveDedicatedCheckoutPath(pathname) {
|
|
139
|
+
const target = resolveDedicatedCheckoutTarget(pathname);
|
|
140
|
+
if (target.kind === "internal_published_preview") {
|
|
141
|
+
return `/internal-sites/${target.hostKey}/${target.siteIdentifier}/published/checkout`;
|
|
142
|
+
}
|
|
143
|
+
return "/checkout";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { ModalShell, resolveDedicatedCheckoutPath };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useBlockApi, BlockApiError } from './chunk-M3L3KYYR.mjs';
|
|
3
|
+
import { themeButtonClassName } from './chunk-FU2QRZMX.mjs';
|
|
4
|
+
import { useState, useSyncExternalStore, useEffect } from 'react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function MagicLinkForm({
|
|
8
|
+
initialEmail = "",
|
|
9
|
+
title,
|
|
10
|
+
subtitle,
|
|
11
|
+
buttonText = "Send login link",
|
|
12
|
+
successMessage = "Check your email for a login link to sign in.",
|
|
13
|
+
onSuccess,
|
|
14
|
+
classPrefix = "er",
|
|
15
|
+
compact = false
|
|
16
|
+
}) {
|
|
17
|
+
const api = useBlockApi();
|
|
18
|
+
const [email, setEmail] = useState(initialEmail);
|
|
19
|
+
const [loading, setLoading] = useState(false);
|
|
20
|
+
const [success, setSuccess] = useState(false);
|
|
21
|
+
const [error, setError] = useState(null);
|
|
22
|
+
const handleSubmit = async (e) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const normalizedEmail = email.trim().toLowerCase();
|
|
25
|
+
if (!normalizedEmail || loading) return;
|
|
26
|
+
setLoading(true);
|
|
27
|
+
setError(null);
|
|
28
|
+
try {
|
|
29
|
+
const redirectTo = `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
30
|
+
await api.sendMagicLink({
|
|
31
|
+
email: normalizedEmail,
|
|
32
|
+
redirectUrl: `${window.location.origin}/api/portal/callback?redirect_to=${encodeURIComponent(redirectTo)}`
|
|
33
|
+
});
|
|
34
|
+
setSuccess(true);
|
|
35
|
+
onSuccess?.();
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error("Magic link error:", err);
|
|
38
|
+
setError(err instanceof Error ? err.message : "Failed to send. Please try again.");
|
|
39
|
+
} finally {
|
|
40
|
+
setLoading(false);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const handleReset = () => {
|
|
44
|
+
setSuccess(false);
|
|
45
|
+
setEmail("");
|
|
46
|
+
setError(null);
|
|
47
|
+
};
|
|
48
|
+
if (success) {
|
|
49
|
+
return /* @__PURE__ */ jsxs("div", { className: `${classPrefix}-magic-link-success`, children: [
|
|
50
|
+
/* @__PURE__ */ jsx("p", { className: `${classPrefix}-portal-auth-text ${classPrefix}-portal-auth-text--success`, children: successMessage }),
|
|
51
|
+
!compact && /* @__PURE__ */ jsx(
|
|
52
|
+
"button",
|
|
53
|
+
{
|
|
54
|
+
type: "button",
|
|
55
|
+
className: classPrefix === "cp" ? themeButtonClassName({ variant: "secondary", size: "md" }) : `${classPrefix}-modal-btn ${classPrefix}-modal-btn--secondary`,
|
|
56
|
+
onClick: handleReset,
|
|
57
|
+
children: "Try a different email"
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: `${classPrefix}-magic-link-form`, children: [
|
|
63
|
+
title && /* @__PURE__ */ jsx("h3", { className: `${classPrefix}-magic-link-title`, children: title }),
|
|
64
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: `${classPrefix}-portal-auth-text`, children: subtitle }),
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
"input",
|
|
67
|
+
{
|
|
68
|
+
type: "email",
|
|
69
|
+
className: classPrefix === "cp" ? "cp-input" : `${classPrefix}-form__input`,
|
|
70
|
+
placeholder: "your@email.com",
|
|
71
|
+
value: email,
|
|
72
|
+
onChange: (e) => setEmail(e.target.value),
|
|
73
|
+
autoFocus: !compact,
|
|
74
|
+
required: true,
|
|
75
|
+
disabled: loading
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
error && /* @__PURE__ */ jsx("p", { className: `${classPrefix}-portal-auth-text ${classPrefix}-portal-auth-text--error`, children: error }),
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
"button",
|
|
81
|
+
{
|
|
82
|
+
type: "submit",
|
|
83
|
+
className: classPrefix === "cp" ? themeButtonClassName({ variant: "primary", size: "md" }) : `${classPrefix}-modal-btn`,
|
|
84
|
+
disabled: !email.trim() || loading,
|
|
85
|
+
children: loading ? "Sending..." : buttonText
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
var WAITLIST_CLAIM_LOCATION_EVENT = "riverbank:waitlist-claim-location-change";
|
|
91
|
+
var historyPatched = false;
|
|
92
|
+
function emitWaitlistClaimLocationChange() {
|
|
93
|
+
if (typeof window === "undefined") return;
|
|
94
|
+
window.dispatchEvent(new Event(WAITLIST_CLAIM_LOCATION_EVENT));
|
|
95
|
+
}
|
|
96
|
+
function ensureWaitlistClaimLocationTracking() {
|
|
97
|
+
if (typeof window === "undefined" || historyPatched) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
historyPatched = true;
|
|
101
|
+
const history = window.history;
|
|
102
|
+
if (history.__riverbankWaitlistClaimPatched__) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const wrapHistoryMethod = (method) => {
|
|
106
|
+
return function patched(...args) {
|
|
107
|
+
method.apply(this, args);
|
|
108
|
+
emitWaitlistClaimLocationChange();
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
try {
|
|
112
|
+
history.pushState = wrapHistoryMethod(history.pushState);
|
|
113
|
+
history.replaceState = wrapHistoryMethod(history.replaceState);
|
|
114
|
+
history.__riverbankWaitlistClaimPatched__ = true;
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
window.addEventListener("popstate", emitWaitlistClaimLocationChange);
|
|
118
|
+
}
|
|
119
|
+
function getWaitlistClaimTokenFromUrl() {
|
|
120
|
+
if (typeof window === "undefined") {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const token = new URLSearchParams(window.location.search).get("waitlist_claim")?.trim() ?? "";
|
|
124
|
+
return token.length > 0 ? token : null;
|
|
125
|
+
}
|
|
126
|
+
function subscribeToWaitlistClaimToken(callback) {
|
|
127
|
+
if (typeof window === "undefined") {
|
|
128
|
+
return () => {
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
ensureWaitlistClaimLocationTracking();
|
|
132
|
+
window.addEventListener(WAITLIST_CLAIM_LOCATION_EVENT, callback);
|
|
133
|
+
return () => {
|
|
134
|
+
window.removeEventListener(WAITLIST_CLAIM_LOCATION_EVENT, callback);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function getWaitlistClaimTokenSnapshot() {
|
|
138
|
+
return getWaitlistClaimTokenFromUrl();
|
|
139
|
+
}
|
|
140
|
+
function useWaitlistClaim() {
|
|
141
|
+
const api = useBlockApi();
|
|
142
|
+
const token = useSyncExternalStore(
|
|
143
|
+
subscribeToWaitlistClaimToken,
|
|
144
|
+
getWaitlistClaimTokenSnapshot,
|
|
145
|
+
() => null
|
|
146
|
+
);
|
|
147
|
+
const [claim, setClaim] = useState(null);
|
|
148
|
+
const [error, setError] = useState(null);
|
|
149
|
+
const [loginMessage, setLoginMessage] = useState(null);
|
|
150
|
+
const [requiresPortalLogin, setRequiresPortalLogin] = useState(false);
|
|
151
|
+
const [isLoading, setIsLoading] = useState(() => Boolean(token));
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
let cancelled = false;
|
|
154
|
+
async function resolveClaim() {
|
|
155
|
+
if (!token) {
|
|
156
|
+
setClaim(null);
|
|
157
|
+
setError(null);
|
|
158
|
+
setLoginMessage(null);
|
|
159
|
+
setRequiresPortalLogin(false);
|
|
160
|
+
setIsLoading(false);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
setIsLoading(true);
|
|
164
|
+
setClaim(null);
|
|
165
|
+
setError(null);
|
|
166
|
+
setLoginMessage(null);
|
|
167
|
+
setRequiresPortalLogin(false);
|
|
168
|
+
try {
|
|
169
|
+
const result = await api.resolveWaitlistClaim({ claimToken: token });
|
|
170
|
+
if (cancelled) return;
|
|
171
|
+
setClaim(result);
|
|
172
|
+
} catch (claimError) {
|
|
173
|
+
if (cancelled) return;
|
|
174
|
+
const message = claimError instanceof Error ? claimError.message : "Failed to resolve waitlist claim";
|
|
175
|
+
setClaim(null);
|
|
176
|
+
if (claimError instanceof BlockApiError && claimError.status === 401) {
|
|
177
|
+
setRequiresPortalLogin(true);
|
|
178
|
+
setLoginMessage(message);
|
|
179
|
+
setError(null);
|
|
180
|
+
} else {
|
|
181
|
+
setError(message);
|
|
182
|
+
}
|
|
183
|
+
} finally {
|
|
184
|
+
if (!cancelled) {
|
|
185
|
+
setIsLoading(false);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
resolveClaim();
|
|
190
|
+
return () => {
|
|
191
|
+
cancelled = true;
|
|
192
|
+
};
|
|
193
|
+
}, [api, token]);
|
|
194
|
+
return {
|
|
195
|
+
token,
|
|
196
|
+
claim,
|
|
197
|
+
error,
|
|
198
|
+
loginMessage,
|
|
199
|
+
requiresPortalLogin,
|
|
200
|
+
isLoading
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export { MagicLinkForm, useWaitlistClaim };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { isRecord } from './chunk-I2MMZO53.mjs';
|
|
3
|
+
import { useRef, useState, useEffect } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var LEAFLET_CSS = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css";
|
|
7
|
+
var LEAFLET_CSS_INTEGRITY = "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=";
|
|
8
|
+
var LEAFLET_JS = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js";
|
|
9
|
+
var LEAFLET_JS_INTEGRITY = "sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=";
|
|
10
|
+
var leafletLoaded = false;
|
|
11
|
+
var leafletLoadPromise = null;
|
|
12
|
+
function isLeafletApi(value) {
|
|
13
|
+
if (!isRecord(value)) return false;
|
|
14
|
+
return typeof value.map === "function" && typeof value.tileLayer === "function" && typeof value.marker === "function";
|
|
15
|
+
}
|
|
16
|
+
function loadLeaflet() {
|
|
17
|
+
if (leafletLoaded) return Promise.resolve();
|
|
18
|
+
if (leafletLoadPromise) return leafletLoadPromise;
|
|
19
|
+
leafletLoadPromise = new Promise((resolve, reject) => {
|
|
20
|
+
if (typeof window !== "undefined" && isLeafletApi(Reflect.get(window, "L"))) {
|
|
21
|
+
leafletLoaded = true;
|
|
22
|
+
resolve();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const link = document.createElement("link");
|
|
26
|
+
link.rel = "stylesheet";
|
|
27
|
+
link.href = LEAFLET_CSS;
|
|
28
|
+
link.integrity = LEAFLET_CSS_INTEGRITY;
|
|
29
|
+
link.crossOrigin = "anonymous";
|
|
30
|
+
document.head.appendChild(link);
|
|
31
|
+
const script = document.createElement("script");
|
|
32
|
+
script.src = LEAFLET_JS;
|
|
33
|
+
script.integrity = LEAFLET_JS_INTEGRITY;
|
|
34
|
+
script.crossOrigin = "anonymous";
|
|
35
|
+
script.async = true;
|
|
36
|
+
script.onload = () => {
|
|
37
|
+
leafletLoaded = true;
|
|
38
|
+
resolve();
|
|
39
|
+
};
|
|
40
|
+
script.onerror = () => {
|
|
41
|
+
leafletLoadPromise = null;
|
|
42
|
+
reject(new Error("Failed to load Leaflet"));
|
|
43
|
+
};
|
|
44
|
+
document.head.appendChild(script);
|
|
45
|
+
});
|
|
46
|
+
return leafletLoadPromise;
|
|
47
|
+
}
|
|
48
|
+
var LeafletStaticMap = ({
|
|
49
|
+
location,
|
|
50
|
+
label,
|
|
51
|
+
className = "",
|
|
52
|
+
height = 200,
|
|
53
|
+
zoom = 15
|
|
54
|
+
}) => {
|
|
55
|
+
const mapContainerRef = useRef(null);
|
|
56
|
+
const mapRef = useRef(null);
|
|
57
|
+
const markerRef = useRef(null);
|
|
58
|
+
const [loading, setLoading] = useState(true);
|
|
59
|
+
const [error, setError] = useState(null);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
let mounted = true;
|
|
62
|
+
async function initMap() {
|
|
63
|
+
try {
|
|
64
|
+
await loadLeaflet();
|
|
65
|
+
if (!mounted || !mapContainerRef.current) return;
|
|
66
|
+
const L = Reflect.get(window, "L");
|
|
67
|
+
if (!isLeafletApi(L)) {
|
|
68
|
+
throw new Error("Leaflet not available");
|
|
69
|
+
}
|
|
70
|
+
if (!mapRef.current) {
|
|
71
|
+
const map = L.map(mapContainerRef.current, {
|
|
72
|
+
scrollWheelZoom: false,
|
|
73
|
+
dragging: true,
|
|
74
|
+
zoomControl: true
|
|
75
|
+
});
|
|
76
|
+
const tileLayer = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
|
77
|
+
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
78
|
+
});
|
|
79
|
+
tileLayer.addTo(map);
|
|
80
|
+
const marker = L.marker([location.lat, location.lng]);
|
|
81
|
+
marker.addTo(map);
|
|
82
|
+
map.setView([location.lat, location.lng], zoom);
|
|
83
|
+
if (label) {
|
|
84
|
+
marker.bindPopup(label);
|
|
85
|
+
}
|
|
86
|
+
mapRef.current = map;
|
|
87
|
+
markerRef.current = {
|
|
88
|
+
bindPopup(content) {
|
|
89
|
+
marker.bindPopup(content);
|
|
90
|
+
return this;
|
|
91
|
+
},
|
|
92
|
+
setLatLng(latlng) {
|
|
93
|
+
marker.setLatLng(latlng);
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
setLoading(false);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (mounted) {
|
|
101
|
+
setError(err instanceof Error ? err.message : "Failed to load map");
|
|
102
|
+
setLoading(false);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
initMap();
|
|
107
|
+
return () => {
|
|
108
|
+
mounted = false;
|
|
109
|
+
if (mapRef.current) {
|
|
110
|
+
mapRef.current.remove();
|
|
111
|
+
mapRef.current = null;
|
|
112
|
+
markerRef.current = null;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}, []);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!mapRef.current || !markerRef.current) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
mapRef.current.setView([location.lat, location.lng], zoom);
|
|
121
|
+
markerRef.current.setLatLng([location.lat, location.lng]);
|
|
122
|
+
if (label) {
|
|
123
|
+
markerRef.current.bindPopup(label);
|
|
124
|
+
}
|
|
125
|
+
}, [location.lat, location.lng, label, zoom]);
|
|
126
|
+
if (error) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return /* @__PURE__ */ jsx(
|
|
130
|
+
"div",
|
|
131
|
+
{
|
|
132
|
+
ref: mapContainerRef,
|
|
133
|
+
className: `leaflet-static-map ${className}`,
|
|
134
|
+
style: {
|
|
135
|
+
height,
|
|
136
|
+
width: "100%",
|
|
137
|
+
borderRadius: "0.5rem",
|
|
138
|
+
overflow: "hidden",
|
|
139
|
+
backgroundColor: loading ? "rgb(var(--tb-surface))" : void 0
|
|
140
|
+
},
|
|
141
|
+
"aria-label": label ? `Map showing ${label}` : "Location map"
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export { LeafletStaticMap };
|
|
@@ -5228,7 +5228,7 @@ var COLUMN_CLASSES = {
|
|
|
5228
5228
|
};
|
|
5229
5229
|
function getContainerClass(layout, columns) {
|
|
5230
5230
|
if (layout === "compact") {
|
|
5231
|
-
return "rb-flex rb-flex-col rb-gap-2";
|
|
5231
|
+
return "event-listing-compact-container rb-flex rb-flex-col rb-gap-2";
|
|
5232
5232
|
}
|
|
5233
5233
|
if (layout === "stack") {
|
|
5234
5234
|
return "rb-flex rb-flex-col rb-gap-6";
|
|
@@ -5359,7 +5359,7 @@ function formatEventPrice(event) {
|
|
|
5359
5359
|
}
|
|
5360
5360
|
function resolveEventCta(event, buttonText) {
|
|
5361
5361
|
const { isFull: isSoldOut } = getEventAvailability(event);
|
|
5362
|
-
const defaultButtonText = event.kind === "course_session" ? "
|
|
5362
|
+
const defaultButtonText = event.kind === "course_session" ? "Book course" : "Book now";
|
|
5363
5363
|
const effectiveButtonText = buttonText ?? defaultButtonText;
|
|
5364
5364
|
if (isSoldOut) {
|
|
5365
5365
|
return { label: "Sold out", href: event.path, hidden: true };
|
|
@@ -5771,7 +5771,7 @@ var eventListingBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
5771
5771
|
containerClass: getContainerClass(layout, source.columns ?? "3"),
|
|
5772
5772
|
cardVariant: source.cardVariant ?? "default",
|
|
5773
5773
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
5774
|
-
buttonText: source.buttonText ?? "
|
|
5774
|
+
buttonText: source.buttonText ?? "Book now",
|
|
5775
5775
|
showVenue: source.showVenue ?? true,
|
|
5776
5776
|
showMap: source.showMap ?? true,
|
|
5777
5777
|
showCapacity: source.showCapacity ?? true,
|
|
@@ -5945,7 +5945,7 @@ function buildEventCalendarDisplay(source) {
|
|
|
5945
5945
|
),
|
|
5946
5946
|
filterVenueId: normalizeEventVenueId(source.filterVenueId),
|
|
5947
5947
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
5948
|
-
buttonText: source.buttonText ?? "
|
|
5948
|
+
buttonText: source.buttonText ?? "Book now",
|
|
5949
5949
|
showVenue: source.showVenue ?? true,
|
|
5950
5950
|
showMap: source.showMap ?? true,
|
|
5951
5951
|
showCapacity: source.showCapacity ?? true,
|
|
@@ -6150,7 +6150,7 @@ function buildEventCombinedDisplay(source) {
|
|
|
6150
6150
|
showMap: source.showMap ?? true,
|
|
6151
6151
|
showCapacity: source.showCapacity ?? true,
|
|
6152
6152
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
6153
|
-
buttonText: source.buttonText ?? "
|
|
6153
|
+
buttonText: source.buttonText ?? "Book now",
|
|
6154
6154
|
emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
|
|
6155
6155
|
};
|
|
6156
6156
|
}
|
|
@@ -7614,4 +7614,4 @@ function defineIslandPropsDecoder(kind) {
|
|
|
7614
7614
|
};
|
|
7615
7615
|
}
|
|
7616
7616
|
|
|
7617
|
-
export { BOOKING_FORM_DATA_RESERVED_KEYS, DateTimeTile, EMPTY_COMMERCE_CART_STATE, EmptyState, EventCard, EventCompactRow, MAX_EVENTS_PER_DAY, MONTH_NAMES, addMonths, assertNever, buildCartDisplay, buildEventCalendarListingRender, buildPassCartItem, buildProductCardDisplay, buildProductCartItem, buildProductDetailDisplay, buildTimetableModel, defineIslandPropsDecoder, deriveBookingFormViewState, err, formatBookingSubmissionPreparationError, formatCalendarTitle, formatCommercePrice, formatCoursePriceAmount, formatCoursePriceDisplay, formatDate, formatDateKey, formatEventDateParts, formatEventPrice, formatEventTeacherLine, formatInterval, formatTime, getBookingRedirectStateFromLocation, getBookingSuccessMessage, getCardOrientation, getContainerClass, getEventAvailability, getMonthCalendarDays, getOrderedDayNames, getShopDisplayForItems, getThreeMonthRange, getWeekCalendarDays, groupEventsByDate, isEventContentType, isToday, normalizeEventBlockKind, normalizeIdList, ok, okWith, parseStoredCommerceCartState, prepareBookingSubmission, productItemKey, reduceCommerceCart, resolveAppointmentCheckoutVerificationState, resolveBookingPaymentStep, resolveBookingSiteId, resolveCoursePricingState, resolveDefaultBookingServiceId, themeButtonClassName,
|
|
7617
|
+
export { BOOKING_FORM_DATA_RESERVED_KEYS, DateTimeTile, EMPTY_COMMERCE_CART_STATE, EmptyState, EventCard, EventCompactRow, MAX_EVENTS_PER_DAY, MONTH_NAMES, addMonths, assertNever, buildCartDisplay, buildEventCalendarListingRender, buildPassCartItem, buildProductCardDisplay, buildProductCartItem, buildProductDetailDisplay, buildTimetableModel, defineIslandPropsDecoder, deriveBookingFormViewState, err, formatBookingSubmissionPreparationError, formatCalendarTitle, formatCommercePrice, formatCoursePriceAmount, formatCoursePriceDisplay, formatDate, formatDateKey, formatEventDateParts, formatEventPrice, formatEventTeacherLine, formatInterval, formatTime, getBookingRedirectStateFromLocation, getBookingSuccessMessage, getCardOrientation, getContainerClass, getEventAvailability, getMonthCalendarDays, getOrderedDayNames, getShopDisplayForItems, getThreeMonthRange, getWeekCalendarDays, groupEventsByDate, isEventContentType, isToday, normalizeEventBlockKind, normalizeIdList, ok, okWith, parseStoredCommerceCartState, prepareBookingSubmission, productItemKey, reduceCommerceCart, resolveAppointmentCheckoutVerificationState, resolveBookingPaymentStep, resolveBookingSiteId, resolveCoursePricingState, resolveDefaultBookingServiceId, themeButtonClassName, toSelectedCollectionOptionKind };
|