@bigz-app/booking-widget 1.4.3 → 1.4.5
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/booking-widget.js +17305 -17065
- package/dist/booking-widget.js.map +1 -1
- package/dist/components/Sidebar.d.ts.map +1 -1
- package/dist/components/UniversalBookingWidget.d.ts +12 -4
- package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
- package/dist/components/booking/BookingForm.d.ts +1 -3
- package/dist/components/booking/BookingForm.d.ts.map +1 -1
- package/dist/components/booking/GiftCardOnlyBooking.d.ts.map +1 -1
- package/dist/components/booking/HoldCountdown.d.ts +10 -0
- package/dist/components/booking/HoldCountdown.d.ts.map +1 -0
- package/dist/components/booking/MolliePaymentForm.d.ts.map +1 -1
- package/dist/components/booking/StripePaymentForm.d.ts +1 -2
- package/dist/components/booking/StripePaymentForm.d.ts.map +1 -1
- package/dist/components/events/EventInstanceSelection.d.ts +3 -1
- package/dist/components/events/EventInstanceSelection.d.ts.map +1 -1
- package/dist/components/events/EventTypeDetailsDialog.d.ts +0 -1
- package/dist/components/events/EventTypeDetailsDialog.d.ts.map +1 -1
- package/dist/components/events/EventTypeSelection.d.ts +1 -1
- package/dist/components/events/EventTypeSelection.d.ts.map +1 -1
- package/dist/components/events/NextEventsPreview.d.ts +3 -1
- package/dist/components/events/NextEventsPreview.d.ts.map +1 -1
- package/dist/components/events/WaitlistDialog.d.ts +10 -0
- package/dist/components/events/WaitlistDialog.d.ts.map +1 -0
- package/dist/components/shared/Button.d.ts.map +1 -1
- package/dist/components/shared/SectionHeader.d.ts.map +1 -1
- package/dist/components/voucher/VoucherPurchaseForm.d.ts +0 -1
- package/dist/components/voucher/VoucherPurchaseForm.d.ts.map +1 -1
- package/dist/components/voucher/useVoucherConfig.d.ts +0 -1
- package/dist/components/voucher/useVoucherConfig.d.ts.map +1 -1
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/index.cjs +620 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +607 -367
- package/dist/index.esm.js.map +1 -1
- package/dist/styles/StyleProvider.d.ts.map +1 -1
- package/dist/styles/shared-styles.d.ts.map +1 -1
- package/dist/utils/analytics.d.ts +3 -1
- package/dist/utils/analytics.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/validation/booking-schema.d.ts +4 -4
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -4,170 +4,6 @@ import { createRoot } from 'react-dom/client';
|
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import ReactDOM, { createPortal } from 'react-dom';
|
|
6
6
|
|
|
7
|
-
var V3_URL = 'https://js.stripe.com/v3';
|
|
8
|
-
var V3_URL_REGEX = /^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;
|
|
9
|
-
var EXISTING_SCRIPT_MESSAGE = 'loadStripe.setLoadParameters was called but an existing Stripe.js script already exists in the document; existing script parameters will be used';
|
|
10
|
-
var findScript = function findScript() {
|
|
11
|
-
var scripts = document.querySelectorAll("script[src^=\"".concat(V3_URL, "\"]"));
|
|
12
|
-
|
|
13
|
-
for (var i = 0; i < scripts.length; i++) {
|
|
14
|
-
var script = scripts[i];
|
|
15
|
-
|
|
16
|
-
if (!V3_URL_REGEX.test(script.src)) {
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return script;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return null;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
var injectScript = function injectScript(params) {
|
|
27
|
-
var queryString = '';
|
|
28
|
-
var script = document.createElement('script');
|
|
29
|
-
script.src = "".concat(V3_URL).concat(queryString);
|
|
30
|
-
var headOrBody = document.head || document.body;
|
|
31
|
-
|
|
32
|
-
if (!headOrBody) {
|
|
33
|
-
throw new Error('Expected document.body not to be null. Stripe.js requires a <body> element.');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
headOrBody.appendChild(script);
|
|
37
|
-
return script;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
var registerWrapper = function registerWrapper(stripe, startTime) {
|
|
41
|
-
if (!stripe || !stripe._registerWrapper) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
stripe._registerWrapper({
|
|
46
|
-
name: 'stripe-js',
|
|
47
|
-
version: "4.6.0",
|
|
48
|
-
startTime: startTime
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
var stripePromise = null;
|
|
53
|
-
var onErrorListener = null;
|
|
54
|
-
var onLoadListener = null;
|
|
55
|
-
|
|
56
|
-
var onError = function onError(reject) {
|
|
57
|
-
return function () {
|
|
58
|
-
reject(new Error('Failed to load Stripe.js'));
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
var onLoad = function onLoad(resolve, reject) {
|
|
63
|
-
return function () {
|
|
64
|
-
if (window.Stripe) {
|
|
65
|
-
resolve(window.Stripe);
|
|
66
|
-
} else {
|
|
67
|
-
reject(new Error('Stripe.js not available'));
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
var loadScript = function loadScript(params) {
|
|
73
|
-
// Ensure that we only attempt to load Stripe.js at most once
|
|
74
|
-
if (stripePromise !== null) {
|
|
75
|
-
return stripePromise;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
stripePromise = new Promise(function (resolve, reject) {
|
|
79
|
-
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
80
|
-
// Resolve to null when imported server side. This makes the module
|
|
81
|
-
// safe to import in an isomorphic code base.
|
|
82
|
-
resolve(null);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (window.Stripe) {
|
|
87
|
-
resolve(window.Stripe);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
var script = findScript();
|
|
93
|
-
|
|
94
|
-
if (script && params) ; else if (!script) {
|
|
95
|
-
script = injectScript(params);
|
|
96
|
-
} else if (script && onLoadListener !== null && onErrorListener !== null) {
|
|
97
|
-
var _script$parentNode;
|
|
98
|
-
|
|
99
|
-
// remove event listeners
|
|
100
|
-
script.removeEventListener('load', onLoadListener);
|
|
101
|
-
script.removeEventListener('error', onErrorListener); // if script exists, but we are reloading due to an error,
|
|
102
|
-
// reload script to trigger 'load' event
|
|
103
|
-
|
|
104
|
-
(_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
|
|
105
|
-
script = injectScript(params);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
onLoadListener = onLoad(resolve, reject);
|
|
109
|
-
onErrorListener = onError(reject);
|
|
110
|
-
script.addEventListener('load', onLoadListener);
|
|
111
|
-
script.addEventListener('error', onErrorListener);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
reject(error);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
}); // Resets stripePromise on error
|
|
117
|
-
|
|
118
|
-
return stripePromise["catch"](function (error) {
|
|
119
|
-
stripePromise = null;
|
|
120
|
-
return Promise.reject(error);
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
124
|
-
if (maybeStripe === null) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
var stripe = maybeStripe.apply(undefined, args);
|
|
129
|
-
registerWrapper(stripe, startTime);
|
|
130
|
-
return stripe;
|
|
131
|
-
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
132
|
-
|
|
133
|
-
var stripePromise$1;
|
|
134
|
-
var loadCalled = false;
|
|
135
|
-
|
|
136
|
-
var getStripePromise = function getStripePromise() {
|
|
137
|
-
if (stripePromise$1) {
|
|
138
|
-
return stripePromise$1;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
stripePromise$1 = loadScript(null)["catch"](function (error) {
|
|
142
|
-
// clear cache on error
|
|
143
|
-
stripePromise$1 = null;
|
|
144
|
-
return Promise.reject(error);
|
|
145
|
-
});
|
|
146
|
-
return stripePromise$1;
|
|
147
|
-
}; // Execute our own script injection after a tick to give users time to do their
|
|
148
|
-
// own script injection.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Promise.resolve().then(function () {
|
|
152
|
-
return getStripePromise();
|
|
153
|
-
})["catch"](function (error) {
|
|
154
|
-
if (!loadCalled) {
|
|
155
|
-
console.warn(error);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
var loadStripe = function loadStripe() {
|
|
159
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
160
|
-
args[_key] = arguments[_key];
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
loadCalled = true;
|
|
164
|
-
var startTime = Date.now(); // if previous attempts are unsuccessful, will re-load script
|
|
165
|
-
|
|
166
|
-
return getStripePromise().then(function (maybeStripe) {
|
|
167
|
-
return initStripe(maybeStripe, args, startTime);
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
|
|
171
7
|
const de$1 = {
|
|
172
8
|
// Common
|
|
173
9
|
"common.back": "← Zurück",
|
|
@@ -247,6 +83,24 @@ const de$1 = {
|
|
|
247
83
|
"instances.bestPrice": "bester Preis !!!",
|
|
248
84
|
"instances.goodPrice": "günstiger Preis",
|
|
249
85
|
"instances.oclock": "Uhr",
|
|
86
|
+
// Warteliste
|
|
87
|
+
"waitlist.joinCta": "Auf die Warteliste",
|
|
88
|
+
"waitlist.title": "Auf die Warteliste setzen",
|
|
89
|
+
"waitlist.subtitle": "{{name}} ist ausgebucht. Hinterlassen Sie Ihre Daten und wir melden uns, falls ein Platz frei wird.",
|
|
90
|
+
"waitlist.name": "Name",
|
|
91
|
+
"waitlist.email": "E-Mail",
|
|
92
|
+
"waitlist.phone": "Telefon (optional)",
|
|
93
|
+
"waitlist.requiredFields": "Bitte geben Sie Ihren Namen und Ihre E-Mail-Adresse ein.",
|
|
94
|
+
"waitlist.join": "Eintragen",
|
|
95
|
+
"waitlist.submitting": "Wird eingetragen...",
|
|
96
|
+
"waitlist.cancel": "Abbrechen",
|
|
97
|
+
"waitlist.submitError": "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.",
|
|
98
|
+
"waitlist.successTitle": "Sie sind auf der Liste!",
|
|
99
|
+
"waitlist.successMessage": "Sie sind Nummer {{position}} auf der Warteliste. Wir melden uns, sobald ein Platz frei wird.",
|
|
100
|
+
"waitlist.done": "Fertig",
|
|
101
|
+
// Reservierungs-Countdown
|
|
102
|
+
"hold.reservedFor": "Platz reserviert für {{time}}",
|
|
103
|
+
"hold.expired": "Ihre Reservierung ist abgelaufen",
|
|
250
104
|
// Next events preview
|
|
251
105
|
"nextEvents.title": "Nächste verfügbare Termine",
|
|
252
106
|
"nextEvents.subtitle": "Wähle einen Termin aus oder zeige alle verfügbaren Termine an",
|
|
@@ -537,6 +391,24 @@ const en = {
|
|
|
537
391
|
"instances.bestPrice": "best price !!!",
|
|
538
392
|
"instances.goodPrice": "good price",
|
|
539
393
|
"instances.oclock": "",
|
|
394
|
+
// Waitlist
|
|
395
|
+
"waitlist.joinCta": "Join waitlist",
|
|
396
|
+
"waitlist.title": "Join the waitlist",
|
|
397
|
+
"waitlist.subtitle": "{{name}} is fully booked. Leave your details and we'll contact you if a spot opens up.",
|
|
398
|
+
"waitlist.name": "Name",
|
|
399
|
+
"waitlist.email": "Email",
|
|
400
|
+
"waitlist.phone": "Phone (optional)",
|
|
401
|
+
"waitlist.requiredFields": "Please enter your name and email.",
|
|
402
|
+
"waitlist.join": "Join waitlist",
|
|
403
|
+
"waitlist.submitting": "Joining...",
|
|
404
|
+
"waitlist.cancel": "Cancel",
|
|
405
|
+
"waitlist.submitError": "Something went wrong. Please try again.",
|
|
406
|
+
"waitlist.successTitle": "You're on the list!",
|
|
407
|
+
"waitlist.successMessage": "You are number {{position}} on the waitlist. We'll be in touch if a spot becomes available.",
|
|
408
|
+
"waitlist.done": "Done",
|
|
409
|
+
// Slot hold countdown
|
|
410
|
+
"hold.reservedFor": "Slot reserved for {{time}}",
|
|
411
|
+
"hold.expired": "Your reservation has expired",
|
|
540
412
|
// Next events preview
|
|
541
413
|
"nextEvents.title": "Next available dates",
|
|
542
414
|
"nextEvents.subtitle": "Select a date or view all available dates",
|
|
@@ -2045,6 +1917,28 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2045
1917
|
c = `0x${c.join("")}`;
|
|
2046
1918
|
return [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(",");
|
|
2047
1919
|
};
|
|
1920
|
+
// Pick a readable text color (dark or light) for content sitting on top of
|
|
1921
|
+
// the given background color. Bright/neon highlights (teal, matrix green,
|
|
1922
|
+
// gold, etc.) need dark text — white text on them is unreadable.
|
|
1923
|
+
const getContrastingTextColor = (color, lightColor = "#ffffff", darkColor = "#0e1420") => {
|
|
1924
|
+
let rgb;
|
|
1925
|
+
if (color.startsWith("#")) {
|
|
1926
|
+
rgb = hexToRgb(color);
|
|
1927
|
+
}
|
|
1928
|
+
else if (color.startsWith("rgb")) {
|
|
1929
|
+
rgb = color.replace(/rgba?\(|\)/g, "").split(",").slice(0, 3).join(",");
|
|
1930
|
+
}
|
|
1931
|
+
else {
|
|
1932
|
+
return lightColor; // Can't parse (e.g. hsl/oklch/semantic) — keep existing default
|
|
1933
|
+
}
|
|
1934
|
+
const [r, g, b] = rgb.split(",").map((n) => parseInt(n, 10) / 255);
|
|
1935
|
+
if ([r, g, b].some((n) => Number.isNaN(n)))
|
|
1936
|
+
return lightColor;
|
|
1937
|
+
// Relative luminance (sRGB, WCAG)
|
|
1938
|
+
const toLinear = (n) => (n <= 0.03928 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4));
|
|
1939
|
+
const luminance = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
1940
|
+
return luminance > 0.45 ? darkColor : lightColor;
|
|
1941
|
+
};
|
|
2048
1942
|
const colors = config.colors || {};
|
|
2049
1943
|
const finalColors = {
|
|
2050
1944
|
highlight: getCSSValue(colors.highlight, themeDefaults.highlight),
|
|
@@ -2064,7 +1958,7 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2064
1958
|
"--bw-surface-color": finalColors.surface,
|
|
2065
1959
|
"--bw-text-color": finalColors.text,
|
|
2066
1960
|
"--bw-text-muted": addOpacity(finalColors.text, 0.7),
|
|
2067
|
-
"--bw-button-text-color": themeDefaults.buttonTextColor ||
|
|
1961
|
+
"--bw-button-text-color": themeDefaults.buttonTextColor || getContrastingTextColor(finalColors.highlight),
|
|
2068
1962
|
"--bw-border-color": finalColors.border,
|
|
2069
1963
|
"--bw-success-color": finalColors.success,
|
|
2070
1964
|
"--bw-warning-color": finalColors.warning,
|
|
@@ -2082,6 +1976,9 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2082
1976
|
"--bw-highlight-muted": addOpacity(finalColors.highlight, 0.1),
|
|
2083
1977
|
"--bw-highlight-subtle": addOpacity(finalColors.highlight, 0.05),
|
|
2084
1978
|
"--bw-text-subtle": addOpacity(finalColors.text, 0.4),
|
|
1979
|
+
// Some themes (neon-brutalism) call for uppercased titles & buttons
|
|
1980
|
+
"--bw-text-transform": themeName === "dark-neon-brutalism" ? "uppercase" : "none",
|
|
1981
|
+
"--bw-letter-spacing": themeName === "dark-neon-brutalism" ? "0.04em" : "normal",
|
|
2085
1982
|
colorScheme: (["navy-night", "green-deep", "green-matrix", "gold-luxury", "purple-electric", "dark-neon-brutalism", "amber-retro", "orange-raw"].includes(themeName) || themeName.startsWith("dark-")) ? "dark" : "light",
|
|
2086
1983
|
};
|
|
2087
1984
|
}, [
|
|
@@ -2217,6 +2114,7 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2217
2114
|
const categoryId = urlParams.get("categoryId") || urlParams.get("category");
|
|
2218
2115
|
const eventTypeId = urlParams.get("eventTypeId") || urlParams.get("type");
|
|
2219
2116
|
const eventTypeIds = urlParams.get("eventTypeIds") || urlParams.get("types");
|
|
2117
|
+
const partnerContractId = urlParams.get("partnerContractId") || urlParams.get("contractId");
|
|
2220
2118
|
const voucherValue = urlParams.get("voucherValue");
|
|
2221
2119
|
const voucherCategory = urlParams.get("voucherCategory");
|
|
2222
2120
|
const voucherEventType = urlParams.get("voucherEventType");
|
|
@@ -2229,11 +2127,14 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2229
2127
|
: ["0", "false", "no", "off"].includes(voucherCardIntegration.toLowerCase())
|
|
2230
2128
|
? false
|
|
2231
2129
|
: undefined;
|
|
2232
|
-
const omitSelectionKeys = ({ categoryId: _c, eventTypeId: _e, eventTypeIds: _es, eventInstanceId: _i, voucherValue: _vv, voucherCategory: _vc, voucherEventType: _ve, voucherImageId: _vi, ...rest }) => rest;
|
|
2130
|
+
const omitSelectionKeys = ({ categoryId: _c, eventTypeId: _e, eventTypeIds: _es, eventInstanceId: _i, voucherValue: _vv, voucherCategory: _vc, voucherEventType: _ve, voucherImageId: _vi, partnerContractId: _pc, ...rest }) => rest;
|
|
2233
2131
|
if (eventInstanceId && !Number.isNaN(Number(eventInstanceId))) {
|
|
2234
2132
|
return {
|
|
2235
2133
|
...omitSelectionKeys(baseConfig),
|
|
2236
2134
|
eventInstanceId: Number(eventInstanceId),
|
|
2135
|
+
...(partnerContractId
|
|
2136
|
+
? { partnerContractId }
|
|
2137
|
+
: {}),
|
|
2237
2138
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2238
2139
|
};
|
|
2239
2140
|
}
|
|
@@ -2241,6 +2142,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2241
2142
|
return {
|
|
2242
2143
|
...omitSelectionKeys(baseConfig),
|
|
2243
2144
|
categoryId: Number(categoryId),
|
|
2145
|
+
...(partnerContractId
|
|
2146
|
+
? { partnerContractId }
|
|
2147
|
+
: {}),
|
|
2244
2148
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2245
2149
|
};
|
|
2246
2150
|
}
|
|
@@ -2248,6 +2152,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2248
2152
|
return {
|
|
2249
2153
|
...omitSelectionKeys(baseConfig),
|
|
2250
2154
|
eventTypeId: Number(eventTypeId),
|
|
2155
|
+
...(partnerContractId
|
|
2156
|
+
? { partnerContractId }
|
|
2157
|
+
: {}),
|
|
2251
2158
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2252
2159
|
};
|
|
2253
2160
|
}
|
|
@@ -2260,6 +2167,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2260
2167
|
return {
|
|
2261
2168
|
...omitSelectionKeys(baseConfig),
|
|
2262
2169
|
eventTypeIds: typeIds,
|
|
2170
|
+
...(partnerContractId
|
|
2171
|
+
? { partnerContractId }
|
|
2172
|
+
: {}),
|
|
2263
2173
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2264
2174
|
};
|
|
2265
2175
|
}
|
|
@@ -2276,6 +2186,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2276
2186
|
if (parsedVoucherValues.length || parsedVoucherCategories.length || parsedVoucherEventTypes.length) {
|
|
2277
2187
|
return {
|
|
2278
2188
|
...baseConfig,
|
|
2189
|
+
...(partnerContractId
|
|
2190
|
+
? { partnerContractId }
|
|
2191
|
+
: {}),
|
|
2279
2192
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2280
2193
|
...(parsedVoucherValues.length > 0
|
|
2281
2194
|
? { voucherValue: parsedVoucherValues.length === 1 ? parsedVoucherValues[0] : parsedVoucherValues }
|
|
@@ -2293,6 +2206,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2293
2206
|
}
|
|
2294
2207
|
return {
|
|
2295
2208
|
...baseConfig,
|
|
2209
|
+
...(partnerContractId
|
|
2210
|
+
? { partnerContractId }
|
|
2211
|
+
: {}),
|
|
2296
2212
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2297
2213
|
};
|
|
2298
2214
|
};
|
|
@@ -6305,6 +6221,7 @@ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, gif
|
|
|
6305
6221
|
customerPhone: formData.customerPhone?.trim(),
|
|
6306
6222
|
comment: formData.comment?.trim(),
|
|
6307
6223
|
paymentMethod: "gift_card",
|
|
6224
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6308
6225
|
...(upsellSelections.length > 0 && { upsellSelections }),
|
|
6309
6226
|
};
|
|
6310
6227
|
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
|
|
@@ -6581,6 +6498,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6581
6498
|
customerEmail: formData.customerEmail?.trim(),
|
|
6582
6499
|
customerPhone: formData.customerPhone?.trim(),
|
|
6583
6500
|
comment: formData.comment?.trim(),
|
|
6501
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6584
6502
|
...(cardToken && { cardToken }),
|
|
6585
6503
|
...(selectedMethod && !cardToken && { method: selectedMethod }),
|
|
6586
6504
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
@@ -6807,6 +6725,170 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6807
6725
|
}, children: isLoading ? (jsxs(Fragment, { children: [spinner("var(--bw-surface-color)"), " ", buttonLabel] })) : (buttonLabel) }))] }));
|
|
6808
6726
|
}
|
|
6809
6727
|
|
|
6728
|
+
var V3_URL = 'https://js.stripe.com/v3';
|
|
6729
|
+
var V3_URL_REGEX = /^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;
|
|
6730
|
+
var EXISTING_SCRIPT_MESSAGE = 'loadStripe.setLoadParameters was called but an existing Stripe.js script already exists in the document; existing script parameters will be used';
|
|
6731
|
+
var findScript = function findScript() {
|
|
6732
|
+
var scripts = document.querySelectorAll("script[src^=\"".concat(V3_URL, "\"]"));
|
|
6733
|
+
|
|
6734
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
6735
|
+
var script = scripts[i];
|
|
6736
|
+
|
|
6737
|
+
if (!V3_URL_REGEX.test(script.src)) {
|
|
6738
|
+
continue;
|
|
6739
|
+
}
|
|
6740
|
+
|
|
6741
|
+
return script;
|
|
6742
|
+
}
|
|
6743
|
+
|
|
6744
|
+
return null;
|
|
6745
|
+
};
|
|
6746
|
+
|
|
6747
|
+
var injectScript = function injectScript(params) {
|
|
6748
|
+
var queryString = '';
|
|
6749
|
+
var script = document.createElement('script');
|
|
6750
|
+
script.src = "".concat(V3_URL).concat(queryString);
|
|
6751
|
+
var headOrBody = document.head || document.body;
|
|
6752
|
+
|
|
6753
|
+
if (!headOrBody) {
|
|
6754
|
+
throw new Error('Expected document.body not to be null. Stripe.js requires a <body> element.');
|
|
6755
|
+
}
|
|
6756
|
+
|
|
6757
|
+
headOrBody.appendChild(script);
|
|
6758
|
+
return script;
|
|
6759
|
+
};
|
|
6760
|
+
|
|
6761
|
+
var registerWrapper = function registerWrapper(stripe, startTime) {
|
|
6762
|
+
if (!stripe || !stripe._registerWrapper) {
|
|
6763
|
+
return;
|
|
6764
|
+
}
|
|
6765
|
+
|
|
6766
|
+
stripe._registerWrapper({
|
|
6767
|
+
name: 'stripe-js',
|
|
6768
|
+
version: "4.6.0",
|
|
6769
|
+
startTime: startTime
|
|
6770
|
+
});
|
|
6771
|
+
};
|
|
6772
|
+
|
|
6773
|
+
var stripePromise = null;
|
|
6774
|
+
var onErrorListener = null;
|
|
6775
|
+
var onLoadListener = null;
|
|
6776
|
+
|
|
6777
|
+
var onError = function onError(reject) {
|
|
6778
|
+
return function () {
|
|
6779
|
+
reject(new Error('Failed to load Stripe.js'));
|
|
6780
|
+
};
|
|
6781
|
+
};
|
|
6782
|
+
|
|
6783
|
+
var onLoad = function onLoad(resolve, reject) {
|
|
6784
|
+
return function () {
|
|
6785
|
+
if (window.Stripe) {
|
|
6786
|
+
resolve(window.Stripe);
|
|
6787
|
+
} else {
|
|
6788
|
+
reject(new Error('Stripe.js not available'));
|
|
6789
|
+
}
|
|
6790
|
+
};
|
|
6791
|
+
};
|
|
6792
|
+
|
|
6793
|
+
var loadScript = function loadScript(params) {
|
|
6794
|
+
// Ensure that we only attempt to load Stripe.js at most once
|
|
6795
|
+
if (stripePromise !== null) {
|
|
6796
|
+
return stripePromise;
|
|
6797
|
+
}
|
|
6798
|
+
|
|
6799
|
+
stripePromise = new Promise(function (resolve, reject) {
|
|
6800
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
6801
|
+
// Resolve to null when imported server side. This makes the module
|
|
6802
|
+
// safe to import in an isomorphic code base.
|
|
6803
|
+
resolve(null);
|
|
6804
|
+
return;
|
|
6805
|
+
}
|
|
6806
|
+
|
|
6807
|
+
if (window.Stripe) {
|
|
6808
|
+
resolve(window.Stripe);
|
|
6809
|
+
return;
|
|
6810
|
+
}
|
|
6811
|
+
|
|
6812
|
+
try {
|
|
6813
|
+
var script = findScript();
|
|
6814
|
+
|
|
6815
|
+
if (script && params) ; else if (!script) {
|
|
6816
|
+
script = injectScript(params);
|
|
6817
|
+
} else if (script && onLoadListener !== null && onErrorListener !== null) {
|
|
6818
|
+
var _script$parentNode;
|
|
6819
|
+
|
|
6820
|
+
// remove event listeners
|
|
6821
|
+
script.removeEventListener('load', onLoadListener);
|
|
6822
|
+
script.removeEventListener('error', onErrorListener); // if script exists, but we are reloading due to an error,
|
|
6823
|
+
// reload script to trigger 'load' event
|
|
6824
|
+
|
|
6825
|
+
(_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
|
|
6826
|
+
script = injectScript(params);
|
|
6827
|
+
}
|
|
6828
|
+
|
|
6829
|
+
onLoadListener = onLoad(resolve, reject);
|
|
6830
|
+
onErrorListener = onError(reject);
|
|
6831
|
+
script.addEventListener('load', onLoadListener);
|
|
6832
|
+
script.addEventListener('error', onErrorListener);
|
|
6833
|
+
} catch (error) {
|
|
6834
|
+
reject(error);
|
|
6835
|
+
return;
|
|
6836
|
+
}
|
|
6837
|
+
}); // Resets stripePromise on error
|
|
6838
|
+
|
|
6839
|
+
return stripePromise["catch"](function (error) {
|
|
6840
|
+
stripePromise = null;
|
|
6841
|
+
return Promise.reject(error);
|
|
6842
|
+
});
|
|
6843
|
+
};
|
|
6844
|
+
var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
6845
|
+
if (maybeStripe === null) {
|
|
6846
|
+
return null;
|
|
6847
|
+
}
|
|
6848
|
+
|
|
6849
|
+
var stripe = maybeStripe.apply(undefined, args);
|
|
6850
|
+
registerWrapper(stripe, startTime);
|
|
6851
|
+
return stripe;
|
|
6852
|
+
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
6853
|
+
|
|
6854
|
+
var stripePromise$1;
|
|
6855
|
+
var loadCalled = false;
|
|
6856
|
+
|
|
6857
|
+
var getStripePromise = function getStripePromise() {
|
|
6858
|
+
if (stripePromise$1) {
|
|
6859
|
+
return stripePromise$1;
|
|
6860
|
+
}
|
|
6861
|
+
|
|
6862
|
+
stripePromise$1 = loadScript(null)["catch"](function (error) {
|
|
6863
|
+
// clear cache on error
|
|
6864
|
+
stripePromise$1 = null;
|
|
6865
|
+
return Promise.reject(error);
|
|
6866
|
+
});
|
|
6867
|
+
return stripePromise$1;
|
|
6868
|
+
}; // Execute our own script injection after a tick to give users time to do their
|
|
6869
|
+
// own script injection.
|
|
6870
|
+
|
|
6871
|
+
|
|
6872
|
+
Promise.resolve().then(function () {
|
|
6873
|
+
return getStripePromise();
|
|
6874
|
+
})["catch"](function (error) {
|
|
6875
|
+
if (!loadCalled) {
|
|
6876
|
+
console.warn(error);
|
|
6877
|
+
}
|
|
6878
|
+
});
|
|
6879
|
+
var loadStripe = function loadStripe() {
|
|
6880
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
6881
|
+
args[_key] = arguments[_key];
|
|
6882
|
+
}
|
|
6883
|
+
|
|
6884
|
+
loadCalled = true;
|
|
6885
|
+
var startTime = Date.now(); // if previous attempts are unsuccessful, will re-load script
|
|
6886
|
+
|
|
6887
|
+
return getStripePromise().then(function (maybeStripe) {
|
|
6888
|
+
return initStripe(maybeStripe, args, startTime);
|
|
6889
|
+
});
|
|
6890
|
+
};
|
|
6891
|
+
|
|
6810
6892
|
// Inner component that uses the Stripe hooks
|
|
6811
6893
|
function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onError, }) {
|
|
6812
6894
|
const t = useTranslations();
|
|
@@ -6835,13 +6917,25 @@ function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onEr
|
|
|
6835
6917
|
},
|
|
6836
6918
|
}, submitContent: jsx(Fragment, { children: submitLabel }), loadingContent: jsxs(Fragment, { children: [spinner("var(--bw-surface-color)"), " ", t("button.processingPayment")] }) }));
|
|
6837
6919
|
}
|
|
6838
|
-
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig,
|
|
6920
|
+
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripeAppearance, upsellSelections = [], }) {
|
|
6839
6921
|
const t = useTranslations();
|
|
6840
6922
|
const { locale } = useLocale();
|
|
6841
6923
|
const [clientSecret, setClientSecret] = useState(null);
|
|
6842
6924
|
const [paymentIntentId, setPaymentIntentId] = useState(null);
|
|
6843
6925
|
const [isCreatingPaymentIntent, setIsCreatingPaymentIntent] = useState(false);
|
|
6844
6926
|
const [paymentError, setPaymentError] = useState(null);
|
|
6927
|
+
const stripePromise = useMemo(() => {
|
|
6928
|
+
if (!systemConfig?.stripePublishableKey) {
|
|
6929
|
+
return null;
|
|
6930
|
+
}
|
|
6931
|
+
const stripeOptions = {
|
|
6932
|
+
locale: locale,
|
|
6933
|
+
};
|
|
6934
|
+
if (systemConfig.connectedAccountId) {
|
|
6935
|
+
stripeOptions.stripeAccount = systemConfig.connectedAccountId;
|
|
6936
|
+
}
|
|
6937
|
+
return loadStripe(systemConfig.stripePublishableKey, stripeOptions);
|
|
6938
|
+
}, [systemConfig?.stripePublishableKey, systemConfig?.connectedAccountId, locale]);
|
|
6845
6939
|
const storageKey = typeof window !== "undefined"
|
|
6846
6940
|
? `bw_pi_${config?.organizationId}_${config?.eventInstanceId || eventDetails?.id}`
|
|
6847
6941
|
: "";
|
|
@@ -6920,6 +7014,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6920
7014
|
customerEmail: formData.customerEmail?.trim(),
|
|
6921
7015
|
customerPhone: formData.customerPhone?.trim(),
|
|
6922
7016
|
comment: formData.comment?.trim(),
|
|
7017
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6923
7018
|
...(paymentIntentId && { paymentIntentId }),
|
|
6924
7019
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
6925
7020
|
};
|
|
@@ -6989,7 +7084,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6989
7084
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
6990
7085
|
return (jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
6991
7086
|
}
|
|
6992
|
-
if (isCreatingPaymentIntent || !clientSecret) {
|
|
7087
|
+
if (isCreatingPaymentIntent || !clientSecret || !stripePromise) {
|
|
6993
7088
|
return (jsxs("div", { style: {
|
|
6994
7089
|
display: "flex",
|
|
6995
7090
|
alignItems: "center",
|
|
@@ -7027,6 +7122,49 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
7027
7122
|
}, onError: onError }) }));
|
|
7028
7123
|
}
|
|
7029
7124
|
|
|
7125
|
+
const HOLD_DURATION_SECONDS = 15 * 60;
|
|
7126
|
+
/**
|
|
7127
|
+
* Shows the remaining time on the 15-minute slot hold that the server places on
|
|
7128
|
+
* the pending order while the customer completes checkout. The timer is started
|
|
7129
|
+
* client-side when the payment step opens — matching the moment the pending
|
|
7130
|
+
* order (and its `holdExpiresAt`) is created server-side.
|
|
7131
|
+
*/
|
|
7132
|
+
function HoldCountdown({ onExpire }) {
|
|
7133
|
+
const t = useTranslations();
|
|
7134
|
+
const [remaining, setRemaining] = useState(HOLD_DURATION_SECONDS);
|
|
7135
|
+
useEffect(() => {
|
|
7136
|
+
const startedAt = Date.now();
|
|
7137
|
+
const interval = setInterval(() => {
|
|
7138
|
+
const elapsed = Math.floor((Date.now() - startedAt) / 1000);
|
|
7139
|
+
const left = Math.max(0, HOLD_DURATION_SECONDS - elapsed);
|
|
7140
|
+
setRemaining(left);
|
|
7141
|
+
if (left <= 0) {
|
|
7142
|
+
clearInterval(interval);
|
|
7143
|
+
onExpire?.();
|
|
7144
|
+
}
|
|
7145
|
+
}, 1000);
|
|
7146
|
+
return () => clearInterval(interval);
|
|
7147
|
+
}, [onExpire]);
|
|
7148
|
+
const minutes = Math.floor(remaining / 60);
|
|
7149
|
+
const seconds = remaining % 60;
|
|
7150
|
+
const formatted = `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
7151
|
+
const isLow = remaining <= 60;
|
|
7152
|
+
return (jsxs("div", { style: {
|
|
7153
|
+
display: "flex",
|
|
7154
|
+
alignItems: "center",
|
|
7155
|
+
gap: "8px",
|
|
7156
|
+
padding: "10px 14px",
|
|
7157
|
+
borderRadius: "var(--bw-border-radius)",
|
|
7158
|
+
border: `1px solid ${isLow ? "var(--bw-error-color)" : "var(--bw-border-color)"}`,
|
|
7159
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
7160
|
+
color: isLow ? "var(--bw-error-color)" : "var(--bw-text-color)",
|
|
7161
|
+
fontFamily: "var(--bw-font-family)",
|
|
7162
|
+
fontSize: "14px",
|
|
7163
|
+
}, children: [jsx(IconClock, {}), jsx("span", { children: remaining > 0
|
|
7164
|
+
? t("hold.reservedFor", { time: formatted })
|
|
7165
|
+
: t("hold.expired") })] }));
|
|
7166
|
+
}
|
|
7167
|
+
|
|
7030
7168
|
const FLAG_EMOJIS = {
|
|
7031
7169
|
de: "🇩🇪",
|
|
7032
7170
|
en: "🇬🇧",
|
|
@@ -7241,6 +7379,8 @@ function Sidebar({ isOpen, onClose, title, children, width = "450px", footer, })
|
|
|
7241
7379
|
fontSize: "16px",
|
|
7242
7380
|
color: "var(--bw-text-color)",
|
|
7243
7381
|
fontFamily: "var(--bw-font-family)",
|
|
7382
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
7383
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
7244
7384
|
flex: 1,
|
|
7245
7385
|
paddingRight: "12px",
|
|
7246
7386
|
minWidth: 0,
|
|
@@ -11418,6 +11558,8 @@ const buttonBase = {
|
|
|
11418
11558
|
transition: "all 0.2s ease",
|
|
11419
11559
|
whiteSpace: "nowrap",
|
|
11420
11560
|
border: "none",
|
|
11561
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
11562
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
11421
11563
|
};
|
|
11422
11564
|
// CSS class name for button hover effects
|
|
11423
11565
|
const buttonClassName = "bw-button-hover";
|
|
@@ -11434,6 +11576,11 @@ const buttonStyles = {
|
|
|
11434
11576
|
color: "var(--bw-text-muted)",
|
|
11435
11577
|
border: "1px solid var(--bw-border-color)",
|
|
11436
11578
|
},
|
|
11579
|
+
// Size variants
|
|
11580
|
+
small: {
|
|
11581
|
+
padding: "8px 12px",
|
|
11582
|
+
fontSize: "13px",
|
|
11583
|
+
},
|
|
11437
11584
|
// Full width modifier
|
|
11438
11585
|
fullWidth: {
|
|
11439
11586
|
width: "100%",
|
|
@@ -11506,6 +11653,12 @@ const sectionStyles = {
|
|
|
11506
11653
|
// TEXT
|
|
11507
11654
|
// ============================================
|
|
11508
11655
|
const textStyles = {
|
|
11656
|
+
body: {
|
|
11657
|
+
fontSize: "14px",
|
|
11658
|
+
color: "var(--bw-text-color)",
|
|
11659
|
+
fontFamily: "var(--bw-font-family)",
|
|
11660
|
+
lineHeight: 1.5,
|
|
11661
|
+
},
|
|
11509
11662
|
muted: {
|
|
11510
11663
|
fontSize: "14px",
|
|
11511
11664
|
color: "var(--bw-text-muted)",
|
|
@@ -11575,7 +11728,7 @@ const sectionHeaderStyles$1 = sectionStyles.header;
|
|
|
11575
11728
|
const labelStyles$1 = formStyles.label;
|
|
11576
11729
|
const inputStyles$1 = formStyles.input;
|
|
11577
11730
|
const errorTextStyles$1 = formStyles.error;
|
|
11578
|
-
function BookingForm({ config, eventDetails,
|
|
11731
|
+
function BookingForm({ config, eventDetails, onSuccess, onError, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], persistedState = null, onPersistedStateChange, }) {
|
|
11579
11732
|
const t$1 = useTranslations();
|
|
11580
11733
|
const { locale } = useLocale();
|
|
11581
11734
|
const timezone = useTimezone();
|
|
@@ -11775,7 +11928,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
11775
11928
|
newTotal: appliedDiscountCode.newTotal,
|
|
11776
11929
|
}
|
|
11777
11930
|
: null;
|
|
11778
|
-
const hasPaymentProvider =
|
|
11931
|
+
const hasPaymentProvider = systemConfig?.paymentProvider === "stripe" || systemConfig?.paymentProvider === "mollie";
|
|
11779
11932
|
const handleVoucherValidated = useCallback((voucher, _error) => {
|
|
11780
11933
|
if (voucher) {
|
|
11781
11934
|
setAppliedVouchers((prev) => [...prev, voucher]);
|
|
@@ -12041,7 +12194,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12041
12194
|
...inputStyles$1,
|
|
12042
12195
|
resize: "vertical",
|
|
12043
12196
|
minHeight: "80px",
|
|
12044
|
-
} })] })] })] })), checkoutStep === "payment" && (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxs("div", { style: {
|
|
12197
|
+
} })] })] })] })), checkoutStep === "payment" && (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsx(HoldCountdown, {}), jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxs("div", { style: {
|
|
12045
12198
|
color: "var(--bw-text-color)",
|
|
12046
12199
|
fontWeight: 500,
|
|
12047
12200
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -12145,7 +12298,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12145
12298
|
fontFamily: "var(--bw-font-family)",
|
|
12146
12299
|
marginTop: "8px",
|
|
12147
12300
|
textAlign: "right",
|
|
12148
|
-
}, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), depositsOnlyBlocked && (jsx("div", { style: cardStyles$1, children: jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.depositNotConfigured") }) })), !hasPaymentProvider && !depositsOnlyBlocked && (jsx("div", { style: cardStyles$1, children: jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && !depositsOnlyBlocked && (systemConfig?.paymentProvider === "mollie" ? (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] })) : (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null,
|
|
12301
|
+
}, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), depositsOnlyBlocked && (jsx("div", { style: cardStyles$1, children: jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.depositNotConfigured") }) })), !hasPaymentProvider && !depositsOnlyBlocked && (jsx("div", { style: cardStyles$1, children: jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && !depositsOnlyBlocked && (systemConfig?.paymentProvider === "mollie" ? (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] })) : (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] })))] }))] }) }));
|
|
12149
12302
|
}
|
|
12150
12303
|
|
|
12151
12304
|
/**
|
|
@@ -12826,19 +12979,21 @@ function EventTypeDetailsDialog({ isOpen, onClose, eventType, onEventTypeSelect,
|
|
|
12826
12979
|
textAlign: "right",
|
|
12827
12980
|
}, children: jsxs("span", { children: [t("common.from"), " ", formatCurrency(eventType.minPrice)] }) })] }), isAvailable && (jsxs("button", { onClick: handleBookingClick, style: {
|
|
12828
12981
|
backgroundColor: "var(--bw-highlight-color)",
|
|
12829
|
-
color: "#ffffff",
|
|
12982
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
12830
12983
|
padding: "14px 28px",
|
|
12831
12984
|
border: "none",
|
|
12832
12985
|
borderRadius: "var(--bw-border-radius)",
|
|
12833
12986
|
fontSize: "16px",
|
|
12834
12987
|
fontWeight: 600,
|
|
12835
12988
|
fontFamily: "var(--bw-font-family)",
|
|
12989
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
12990
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
12836
12991
|
display: "flex",
|
|
12837
12992
|
alignItems: "center",
|
|
12838
12993
|
gap: "8px",
|
|
12839
12994
|
cursor: "pointer",
|
|
12840
12995
|
transition: "all 0.2s ease",
|
|
12841
|
-
}, children: [jsx(IconWave, { size: 20, color: "
|
|
12996
|
+
}, children: [jsx(IconWave, { size: 20, color: "var(--bw-button-text-color, #ffffff)" }), t("button.bookNow")] }))] }), !isAvailable && (jsx("div", { style: {
|
|
12842
12997
|
position: "absolute",
|
|
12843
12998
|
inset: 0,
|
|
12844
12999
|
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
@@ -13252,6 +13407,8 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13252
13407
|
const [stripeAppearance, setStripeAppearance] = useState(null);
|
|
13253
13408
|
// Initialize Stripe
|
|
13254
13409
|
useEffect(() => {
|
|
13410
|
+
if (!isOpen)
|
|
13411
|
+
return;
|
|
13255
13412
|
if (paymentProvider !== "stripe")
|
|
13256
13413
|
return;
|
|
13257
13414
|
if (systemConfig?.stripePublishableKey && !stripePromise) {
|
|
@@ -13263,7 +13420,7 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13263
13420
|
}
|
|
13264
13421
|
setStripePromise(loadStripe(systemConfig.stripePublishableKey, stripeOptions));
|
|
13265
13422
|
}
|
|
13266
|
-
}, [paymentProvider, systemConfig, locale, stripePromise]);
|
|
13423
|
+
}, [isOpen, paymentProvider, systemConfig, locale, stripePromise]);
|
|
13267
13424
|
// Initialize Stripe appearance
|
|
13268
13425
|
useEffect(() => {
|
|
13269
13426
|
const container = document.querySelector(".booking-widget-container");
|
|
@@ -14124,15 +14281,15 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14124
14281
|
backgroundColor: isAvailable
|
|
14125
14282
|
? "var(--bw-success-color)"
|
|
14126
14283
|
: "var(--bw-error-color)",
|
|
14127
|
-
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsx("div", { style: {
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14284
|
+
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), eventType.images && eventType.images.length > 0 && (jsxs(Fragment, { children: [jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsx("div", { style: {
|
|
14285
|
+
fontSize: "13px",
|
|
14286
|
+
color: "var(--bw-surface-color)",
|
|
14287
|
+
fontWeight: 600,
|
|
14288
|
+
backgroundColor: "var(--bw-highlight-color)",
|
|
14289
|
+
padding: "2px 8px",
|
|
14290
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14291
|
+
fontFamily: "var(--bw-font-family)",
|
|
14292
|
+
}, children: eventType.category.name }) }), jsx("div", { className: "event-type-img", style: { position: "relative", width: "100%", height: "300px" }, children: jsx(ImageCarousel, { images: eventType.images, eventName: eventType.name }) })] })), jsxs("div", { className: "event-type-content", style: {
|
|
14136
14293
|
padding: "12px 18px",
|
|
14137
14294
|
display: "flex",
|
|
14138
14295
|
flexDirection: "column",
|
|
@@ -14227,8 +14384,17 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14227
14384
|
if (!item)
|
|
14228
14385
|
return jsx("div", { style: { height: "34px" } }, i);
|
|
14229
14386
|
const hasDiscount = item.basePrice > 0 && item.price < item.basePrice;
|
|
14230
|
-
|
|
14231
|
-
|
|
14387
|
+
const isRowBookable = item.bookingOpen && item.availableSpots > 0;
|
|
14388
|
+
return (jsxs("div", { onClick: (e) => {
|
|
14389
|
+
e.stopPropagation();
|
|
14390
|
+
if (isRowBookable) {
|
|
14391
|
+
onInstancePreview?.(item.id, eventType.id);
|
|
14392
|
+
}
|
|
14393
|
+
}, onMouseEnter: (e) => {
|
|
14394
|
+
if (onInstancePreview && isRowBookable) {
|
|
14395
|
+
e.currentTarget.style.backgroundColor = "var(--bw-highlight-subtle)";
|
|
14396
|
+
}
|
|
14397
|
+
}, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = "transparent"; }, style: {
|
|
14232
14398
|
height: "34px",
|
|
14233
14399
|
display: "grid",
|
|
14234
14400
|
gridTemplateColumns: "auto 1fr auto 20px",
|
|
@@ -14237,12 +14403,13 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14237
14403
|
width: "100%",
|
|
14238
14404
|
fontSize: "13px",
|
|
14239
14405
|
color: "var(--bw-text-muted)",
|
|
14240
|
-
cursor: onInstancePreview ? "pointer" : "default",
|
|
14406
|
+
cursor: onInstancePreview && isRowBookable ? "pointer" : "default",
|
|
14241
14407
|
borderRadius: "4px",
|
|
14242
14408
|
padding: "0 2px",
|
|
14243
14409
|
transition: "background 0.15s",
|
|
14244
14410
|
boxSizing: "border-box",
|
|
14245
|
-
|
|
14411
|
+
opacity: isRowBookable ? 1 : 0.55,
|
|
14412
|
+
}, children: [jsxs("span", { style: { whiteSpace: "nowrap", display: "flex", alignItems: "center", gap: "3px" }, children: [item.isSpecial && (jsx("span", { style: { color: "var(--bw-highlight-color)", fontSize: "11px", lineHeight: 1 }, children: "\u2605" })), formatWeekday(item.startTime, timezone, locale), " ", formatDate(item.startTime, timezone, locale)] }), jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", opacity: 0.75 }, children: item.name }), jsxs("span", { style: { display: "flex", alignItems: "center", gap: "4px", whiteSpace: "nowrap" }, children: [hasDiscount && (jsx("span", { style: { textDecoration: "line-through", opacity: 0.55, fontSize: "11px" }, children: formatCurrency(item.basePrice) })), jsx("span", { style: { fontWeight: 700, color: item.isSpecial ? "var(--bw-highlight-color)" : "var(--bw-text-color)" }, children: formatCurrency(item.price) })] }), item.isSpecial && item.specialDescription ? (jsx(InfoBadge, { text: item.specialDescription })) : (jsx("span", {}))] }, item.id));
|
|
14246
14413
|
}) }), hasMoreDates && (jsx("button", { type: "button", onClick: (e) => {
|
|
14247
14414
|
e.stopPropagation();
|
|
14248
14415
|
onEventTypeSelect(eventType);
|
|
@@ -14294,12 +14461,14 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14294
14461
|
transition: "all 0.2s ease",
|
|
14295
14462
|
}, children: t("button.moreDetails") })), isAvailable && (jsxs("div", { style: {
|
|
14296
14463
|
backgroundColor: "var(--bw-highlight-color)",
|
|
14297
|
-
color: "var(--bw-
|
|
14464
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
14298
14465
|
padding: "12px 14px",
|
|
14299
14466
|
borderRadius: "var(--bw-border-radius)",
|
|
14300
14467
|
fontSize: "clamp(1rem, 2vw, 16px)",
|
|
14301
14468
|
fontWeight: 600,
|
|
14302
14469
|
fontFamily: "var(--bw-font-family)",
|
|
14470
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
14471
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
14303
14472
|
display: "flex",
|
|
14304
14473
|
alignItems: "center",
|
|
14305
14474
|
justifyContent: "center",
|
|
@@ -14308,7 +14477,7 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14308
14477
|
border: "none",
|
|
14309
14478
|
cursor: "pointer",
|
|
14310
14479
|
transition: "all 0.2s ease",
|
|
14311
|
-
}, children: [jsx(IconWave, { size: 15, color: "var(--bw-
|
|
14480
|
+
}, children: [jsx(IconWave, { size: 15, color: "var(--bw-button-text-color, #ffffff)" }), " ", t("button.bookNow")] }))] })] })] }), showVoucherAttachment && onVoucherClick && (jsx(VoucherAttachment, { onClick: () => onVoucherClick(eventType.id) })), !isAvailable && (jsx("div", { style: {
|
|
14312
14481
|
position: "absolute",
|
|
14313
14482
|
inset: 0,
|
|
14314
14483
|
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
@@ -14329,6 +14498,74 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14329
14498
|
}) }) })), jsx(PaymentLogosStrip, {}), jsx(EventTypeDetailsDialog, { isOpen: detailsDialogOpen, onClose: handleCloseDetails, eventType: selectedEventTypeForDetails, onEventTypeSelect: onEventTypeSelect })] }));
|
|
14330
14499
|
}
|
|
14331
14500
|
|
|
14501
|
+
function WaitlistDialog({ apiBaseUrl, organizationId, eventInstanceId, eventName, onClose, }) {
|
|
14502
|
+
const t = useTranslations();
|
|
14503
|
+
const [name, setName] = useState("");
|
|
14504
|
+
const [email, setEmail] = useState("");
|
|
14505
|
+
const [phone, setPhone] = useState("");
|
|
14506
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
14507
|
+
const [error, setError] = useState(null);
|
|
14508
|
+
const [position, setPosition] = useState(null);
|
|
14509
|
+
const handleSubmit = async () => {
|
|
14510
|
+
setError(null);
|
|
14511
|
+
if (!name.trim() || !email.trim()) {
|
|
14512
|
+
setError(t("waitlist.requiredFields"));
|
|
14513
|
+
return;
|
|
14514
|
+
}
|
|
14515
|
+
setIsSubmitting(true);
|
|
14516
|
+
try {
|
|
14517
|
+
const response = await fetch(getApiUrl(apiBaseUrl, "/booking/waitlist"), {
|
|
14518
|
+
method: "POST",
|
|
14519
|
+
headers: { "Content-Type": "application/json" },
|
|
14520
|
+
body: JSON.stringify({
|
|
14521
|
+
organizationId,
|
|
14522
|
+
eventInstanceId,
|
|
14523
|
+
name: name.trim(),
|
|
14524
|
+
email: email.trim(),
|
|
14525
|
+
phone: phone.trim() || undefined,
|
|
14526
|
+
}),
|
|
14527
|
+
});
|
|
14528
|
+
if (!response.ok) {
|
|
14529
|
+
throw new Error("request_failed");
|
|
14530
|
+
}
|
|
14531
|
+
const data = (await response.json());
|
|
14532
|
+
setPosition(data.position ?? null);
|
|
14533
|
+
}
|
|
14534
|
+
catch {
|
|
14535
|
+
setError(t("waitlist.submitError"));
|
|
14536
|
+
}
|
|
14537
|
+
finally {
|
|
14538
|
+
setIsSubmitting(false);
|
|
14539
|
+
}
|
|
14540
|
+
};
|
|
14541
|
+
return (jsx("div", { style: {
|
|
14542
|
+
position: "fixed",
|
|
14543
|
+
inset: 0,
|
|
14544
|
+
zIndex: 1000,
|
|
14545
|
+
display: "flex",
|
|
14546
|
+
alignItems: "center",
|
|
14547
|
+
justifyContent: "center",
|
|
14548
|
+
backgroundColor: "rgba(15, 23, 42, 0.6)",
|
|
14549
|
+
padding: "16px",
|
|
14550
|
+
fontFamily: "var(--bw-font-family)",
|
|
14551
|
+
}, onClick: onClose, children: jsx("div", { style: {
|
|
14552
|
+
width: "100%",
|
|
14553
|
+
maxWidth: "420px",
|
|
14554
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
14555
|
+
border: "1px solid var(--bw-border-color)",
|
|
14556
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14557
|
+
padding: "24px",
|
|
14558
|
+
}, onClick: (e) => e.stopPropagation(), children: position !== null ? (jsxs("div", { style: { textAlign: "center" }, children: [jsx("h3", { style: {
|
|
14559
|
+
margin: "0 0 8px",
|
|
14560
|
+
color: "var(--bw-highlight-color)",
|
|
14561
|
+
fontSize: "18px",
|
|
14562
|
+
}, children: t("waitlist.successTitle") }), jsx("p", { style: mergeStyles(textStyles.body, { marginBottom: "20px" }), children: t("waitlist.successMessage", { position }) }), jsx("button", { type: "button", style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), onClick: onClose, children: t("waitlist.done") })] })) : (jsxs(Fragment, { children: [jsx("h3", { style: {
|
|
14563
|
+
margin: "0 0 4px",
|
|
14564
|
+
color: "var(--bw-highlight-color)",
|
|
14565
|
+
fontSize: "18px",
|
|
14566
|
+
}, children: t("waitlist.title") }), jsx("p", { style: mergeStyles(textStyles.muted, { marginBottom: "16px" }), children: t("waitlist.subtitle", { name: eventName }) }), jsxs("div", { style: { marginBottom: "12px" }, children: [jsx("label", { style: formStyles.label, htmlFor: "wl-name", children: t("waitlist.name") }), jsx("input", { id: "wl-name", style: formStyles.input, value: name, onChange: (e) => setName(e.target.value) })] }), jsxs("div", { style: { marginBottom: "12px" }, children: [jsx("label", { style: formStyles.label, htmlFor: "wl-email", children: t("waitlist.email") }), jsx("input", { id: "wl-email", type: "email", style: formStyles.input, value: email, onChange: (e) => setEmail(e.target.value) })] }), jsxs("div", { style: { marginBottom: "12px" }, children: [jsx("label", { style: formStyles.label, htmlFor: "wl-phone", children: t("waitlist.phone") }), jsx("input", { id: "wl-phone", type: "tel", style: formStyles.input, value: phone, onChange: (e) => setPhone(e.target.value) })] }), error && jsx("p", { style: formStyles.error, children: error }), jsxs("div", { style: { display: "flex", gap: "8px", marginTop: "16px" }, children: [jsx("button", { type: "button", style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), onClick: onClose, disabled: isSubmitting, children: t("waitlist.cancel") }), jsx("button", { type: "button", style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), onClick: handleSubmit, disabled: isSubmitting, children: isSubmitting ? t("waitlist.submitting") : t("waitlist.join") })] })] })) }) }));
|
|
14567
|
+
}
|
|
14568
|
+
|
|
14332
14569
|
const getAllocationBadgeInfo = (availableSpots, maxParticipants, t) => {
|
|
14333
14570
|
const availabilityRatio = availableSpots / maxParticipants;
|
|
14334
14571
|
if (availabilityRatio >= 0.6)
|
|
@@ -14453,12 +14690,13 @@ const PriceDisplay = ({ price, yearPrices, t }) => {
|
|
|
14453
14690
|
boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
|
|
14454
14691
|
}, children: formatCurrency(price) }));
|
|
14455
14692
|
};
|
|
14456
|
-
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, }) {
|
|
14693
|
+
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, }) {
|
|
14457
14694
|
const t = useTranslations();
|
|
14458
14695
|
const { locale } = useLocale();
|
|
14459
14696
|
const timezone = useTimezone();
|
|
14460
14697
|
const [selectedEventInstanceId, setSelectedEventInstanceId] = useState(null);
|
|
14461
14698
|
const [openGroups, setOpenGroups] = useState(new Set());
|
|
14699
|
+
const [waitlistEvent, setWaitlistEvent] = useState(null);
|
|
14462
14700
|
const getMonthPriceDisplayInfo = (minPrice) => {
|
|
14463
14701
|
return getPriceDisplayInfo(minPrice, yearPrices, t);
|
|
14464
14702
|
};
|
|
@@ -14619,119 +14857,130 @@ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInst
|
|
|
14619
14857
|
fontFamily: "var(--bw-font-family)",
|
|
14620
14858
|
}, children: t("instances.noAvailable") }), jsx("p", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t("instances.noAvailableMessage") })] }) }) }));
|
|
14621
14859
|
}
|
|
14622
|
-
return (
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14648
|
-
|
|
14649
|
-
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
|
|
14667
|
-
|
|
14668
|
-
|
|
14669
|
-
|
|
14670
|
-
|
|
14671
|
-
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14707
|
-
|
|
14708
|
-
|
|
14709
|
-
|
|
14710
|
-
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
|
|
14715
|
-
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
|
|
14723
|
-
|
|
14724
|
-
|
|
14725
|
-
|
|
14726
|
-
|
|
14727
|
-
|
|
14728
|
-
|
|
14729
|
-
|
|
14730
|
-
|
|
14731
|
-
|
|
14860
|
+
return (jsxs(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `${selectedEventType?.name}`, footer: footerNav, children: [jsxs("div", { style: { padding: "20px 10px" }, children: [jsx(FlowProgress, { currentStep: "date", hasUpsellsStep: hasUpsellsStep }), jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: monthYearGroups.map(({ key, label, events, minPrice, year }, idx) => {
|
|
14861
|
+
const monthPriceDisplayInfo = getMonthPriceDisplayInfo(minPrice);
|
|
14862
|
+
return (jsxs(Fragment$1, { children: [idx > 0 && monthYearGroups[idx - 1].year !== year && (jsx("div", { style: { height: "1px", backgroundColor: "var(--bw-border-color)", margin: "4px 0" } })), jsx(Accordion, { title: label, priceInfo: jsx("div", { style: {
|
|
14863
|
+
fontSize: "16px",
|
|
14864
|
+
fontWeight: 500,
|
|
14865
|
+
marginLeft: "auto",
|
|
14866
|
+
padding: "4px 8px",
|
|
14867
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14868
|
+
backgroundColor: monthPriceDisplayInfo
|
|
14869
|
+
? monthPriceDisplayInfo.backgroundColor
|
|
14870
|
+
: "#14532d",
|
|
14871
|
+
color: monthPriceDisplayInfo
|
|
14872
|
+
? monthPriceDisplayInfo.textColor
|
|
14873
|
+
: "#4ade80",
|
|
14874
|
+
boxShadow: monthPriceDisplayInfo
|
|
14875
|
+
? "0 2px 4px rgba(0, 0, 0, 0.2)"
|
|
14876
|
+
: undefined,
|
|
14877
|
+
}, children: `${t("common.from")} ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", paddingTop: "12px" }, children: events.map((event) => {
|
|
14878
|
+
const availableSpots = event.maxParticipants - event.participantCount;
|
|
14879
|
+
const isFullyBooked = availableSpots === 0;
|
|
14880
|
+
const startDate = new Date(event.startTime);
|
|
14881
|
+
const isPastEvent = today.toISOString() >= startDate.toISOString();
|
|
14882
|
+
const isDisabled = isFullyBooked || isPastEvent || !event.bookingOpen;
|
|
14883
|
+
const canWaitlist = isFullyBooked &&
|
|
14884
|
+
!isPastEvent &&
|
|
14885
|
+
!!apiBaseUrl &&
|
|
14886
|
+
!!organizationId;
|
|
14887
|
+
return (jsxs("div", { style: {
|
|
14888
|
+
position: "relative",
|
|
14889
|
+
border: "1px solid var(--bw-border-color)",
|
|
14890
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
14891
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14892
|
+
padding: "16px 10px",
|
|
14893
|
+
transition: "all 0.2s ease",
|
|
14894
|
+
fontFamily: "var(--bw-font-family)",
|
|
14895
|
+
opacity: isDisabled && !canWaitlist ? 0.3 : 1,
|
|
14896
|
+
filter: isDisabled && !canWaitlist ? "grayscale(40%)" : "none",
|
|
14897
|
+
cursor: isDisabled
|
|
14898
|
+
? canWaitlist
|
|
14899
|
+
? "default"
|
|
14900
|
+
: "not-allowed"
|
|
14901
|
+
: "pointer",
|
|
14902
|
+
}, onClick: () => {
|
|
14903
|
+
if (!isDisabled) {
|
|
14904
|
+
handleEventInstanceSelect(event);
|
|
14905
|
+
}
|
|
14906
|
+
}, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (jsx("div", { style: {
|
|
14907
|
+
position: "absolute",
|
|
14908
|
+
inset: 0,
|
|
14909
|
+
backgroundColor: "rgba(15, 23, 42, 0.8)",
|
|
14910
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14911
|
+
display: "flex",
|
|
14912
|
+
alignItems: "center",
|
|
14913
|
+
justifyContent: "center",
|
|
14914
|
+
}, children: jsx("div", { style: {
|
|
14915
|
+
width: "32px",
|
|
14916
|
+
height: "32px",
|
|
14917
|
+
color: "var(--bw-highlight-color)",
|
|
14918
|
+
opacity: 0.8,
|
|
14919
|
+
fontSize: "32px",
|
|
14920
|
+
}, children: spinner() }) })), jsx(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), jsx(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants, t: t }), jsxs("div", { style: {
|
|
14921
|
+
display: "flex",
|
|
14922
|
+
justifyContent: "space-between",
|
|
14923
|
+
width: "100%",
|
|
14924
|
+
alignItems: "flex-start",
|
|
14925
|
+
gap: "12px",
|
|
14926
|
+
marginBottom: "4px",
|
|
14927
|
+
}, children: [jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsx("div", { style: {
|
|
14928
|
+
fontSize: "16px",
|
|
14929
|
+
transition: "all 0.2s ease",
|
|
14930
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14931
|
+
borderTop: "4px solid var(--bw-border-color)",
|
|
14932
|
+
border: "1px solid var(--bw-border-color)",
|
|
14933
|
+
width: "40px",
|
|
14934
|
+
height: "40px",
|
|
14935
|
+
display: "flex",
|
|
14936
|
+
alignItems: "center",
|
|
14937
|
+
justifyContent: "center",
|
|
14938
|
+
fontWeight: 700,
|
|
14939
|
+
color: "var(--bw-text-color)",
|
|
14940
|
+
backgroundColor: "var(--bw-background-color)",
|
|
14941
|
+
}, children: startDate.getDate() }), jsxs("div", { style: {
|
|
14942
|
+
fontSize: "16px",
|
|
14943
|
+
color: "var(--bw-text-color)",
|
|
14944
|
+
display: "flex",
|
|
14945
|
+
flexDirection: "column",
|
|
14946
|
+
alignItems: "flex-start",
|
|
14947
|
+
justifyContent: "flex-start",
|
|
14948
|
+
lineHeight: 1.25,
|
|
14949
|
+
}, children: [jsxs("div", { children: [jsx("span", { style: { fontWeight: 600, marginBottom: "2px", textTransform: "capitalize" }, children: formatWeekday(event.startTime, timezone, locale) }), formatWeekday(event.startTime, timezone, locale) !==
|
|
14950
|
+
formatWeekday(event.endTime, timezone, locale) && (jsxs(Fragment, { children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), jsx("span", { style: { fontWeight: 600, marginBottom: "2px", textTransform: "capitalize" }, children: formatWeekday(event.endTime, timezone, locale) })] }))] }), jsx("div", { children: formatWeekday(event.startTime, timezone, locale) ===
|
|
14951
|
+
formatWeekday(event.endTime, timezone, locale) ? (jsxs(Fragment, { children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.startTime, timezone, locale) }), jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.endTime, timezone, locale) })] })) : (jsxs("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: [formatTime(event.startTime, timezone, locale), " ", t("instances.oclock")] })) })] }), jsxs("span", { style: {
|
|
14952
|
+
fontSize: "12px",
|
|
14953
|
+
fontWeight: 400,
|
|
14954
|
+
color: "var(--bw-text-muted)",
|
|
14955
|
+
marginLeft: "6px",
|
|
14956
|
+
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
|
14957
|
+
whiteSpace: "nowrap",
|
|
14958
|
+
padding: "2px 6px",
|
|
14959
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14960
|
+
}, children: [event.durationDays, " ", event.durationDays > 1 ? t("common.days") : t("common.day")] })] }), jsx("div", { style: {
|
|
14961
|
+
textAlign: "right",
|
|
14962
|
+
display: "flex",
|
|
14963
|
+
flexDirection: "column",
|
|
14964
|
+
alignItems: "flex-end",
|
|
14965
|
+
}, children: jsx(PriceDisplay, { price: event.price, yearPrices: yearPrices, t: t }) })] }), event.name !== selectedEventType?.name && (jsx("h4", { style: {
|
|
14966
|
+
fontSize: "16px",
|
|
14967
|
+
fontWeight: 600,
|
|
14968
|
+
color: "var(--bw-text-color)",
|
|
14969
|
+
lineHeight: 1.25,
|
|
14970
|
+
margin: "0 0 2px 0",
|
|
14971
|
+
display: "flex",
|
|
14972
|
+
alignItems: "center",
|
|
14973
|
+
gap: "8px",
|
|
14974
|
+
maxWidth: "230px",
|
|
14975
|
+
}, children: event.name })), canWaitlist && (jsx("button", { type: "button", style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth, buttonStyles.small, { marginTop: "8px" }), onClick: (e) => {
|
|
14976
|
+
e.stopPropagation();
|
|
14977
|
+
setWaitlistEvent(event);
|
|
14978
|
+
}, children: t("waitlist.joinCta") }))] }, event.id));
|
|
14979
|
+
}) }) })] }, key));
|
|
14980
|
+
}) })] }), waitlistEvent && apiBaseUrl && organizationId && (jsx(WaitlistDialog, { apiBaseUrl: apiBaseUrl, organizationId: organizationId, eventInstanceId: waitlistEvent.id, eventName: waitlistEvent.name, onClose: () => setWaitlistEvent(null) }))] }));
|
|
14732
14981
|
}
|
|
14733
14982
|
|
|
14734
|
-
function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText, showAllButton, isLoadingEventDetails = false, isLoadingShowAll = false, isLoading = false, }) {
|
|
14983
|
+
function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText, showAllButton, isLoadingEventDetails = false, isLoadingShowAll = false, isLoading = false, count = 3, }) {
|
|
14735
14984
|
const t = useTranslations();
|
|
14736
14985
|
const { locale } = useLocale();
|
|
14737
14986
|
const timezone = useTimezone();
|
|
@@ -14783,7 +15032,7 @@ function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText
|
|
|
14783
15032
|
};
|
|
14784
15033
|
// Show loading skeleton
|
|
14785
15034
|
if (isLoading) {
|
|
14786
|
-
return jsx(NextEventsSkeleton, { count:
|
|
15035
|
+
return jsx(NextEventsSkeleton, { count: count });
|
|
14787
15036
|
}
|
|
14788
15037
|
if (events.length === 0) {
|
|
14789
15038
|
return (jsx("div", { style: { maxWidth: "500px", margin: "0 auto", padding: "16px" }, children: jsxs("div", { style: {
|
|
@@ -15622,6 +15871,7 @@ let buffer = [];
|
|
|
15622
15871
|
let flushTimer = null;
|
|
15623
15872
|
let currentApiBaseUrl = "";
|
|
15624
15873
|
let currentOrganizationId = "";
|
|
15874
|
+
let currentPartnerContractId = null;
|
|
15625
15875
|
const FLUSH_INTERVAL_MS = 3000;
|
|
15626
15876
|
function flush() {
|
|
15627
15877
|
if (buffer.length === 0)
|
|
@@ -15663,9 +15913,10 @@ function scheduleFlush() {
|
|
|
15663
15913
|
/**
|
|
15664
15914
|
* Initialise the analytics module. Must be called once before `trackEvent`.
|
|
15665
15915
|
*/
|
|
15666
|
-
function initAnalytics(apiBaseUrl, organizationId) {
|
|
15916
|
+
function initAnalytics(apiBaseUrl, organizationId, options) {
|
|
15667
15917
|
currentApiBaseUrl = apiBaseUrl;
|
|
15668
15918
|
currentOrganizationId = organizationId;
|
|
15919
|
+
currentPartnerContractId = options?.partnerContractId?.trim() || null;
|
|
15669
15920
|
if (typeof window !== "undefined") {
|
|
15670
15921
|
window.addEventListener("pagehide", flush);
|
|
15671
15922
|
window.addEventListener("visibilitychange", () => {
|
|
@@ -15682,9 +15933,12 @@ function trackEvent(event, properties = {}) {
|
|
|
15682
15933
|
return;
|
|
15683
15934
|
if (!currentOrganizationId)
|
|
15684
15935
|
return;
|
|
15936
|
+
const mergedProperties = currentPartnerContractId
|
|
15937
|
+
? { ...properties, partnerContractId: currentPartnerContractId }
|
|
15938
|
+
: properties;
|
|
15685
15939
|
buffer.push({
|
|
15686
15940
|
event,
|
|
15687
|
-
properties,
|
|
15941
|
+
properties: mergedProperties,
|
|
15688
15942
|
domain: window.location.hostname,
|
|
15689
15943
|
url: window.location.href,
|
|
15690
15944
|
referrer: document.referrer,
|
|
@@ -15760,7 +16014,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15760
16014
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
15761
16015
|
// Booking flow state
|
|
15762
16016
|
const [eventDetails, setEventDetails] = useState(null);
|
|
15763
|
-
const [stripePromise, setStripePromise] = useState(null);
|
|
15764
16017
|
// SEPARATED LOADING STATES
|
|
15765
16018
|
const [isLoading, setIsLoading] = useState(true);
|
|
15766
16019
|
const [isLoadingEventInstances, setIsLoadingEventInstances] = useState(false);
|
|
@@ -15895,7 +16148,9 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15895
16148
|
useEffect(() => {
|
|
15896
16149
|
if (!analyticsInitRef.current && config.organizationId) {
|
|
15897
16150
|
analyticsInitRef.current = true;
|
|
15898
|
-
initAnalytics(config.apiBaseUrl, config.organizationId
|
|
16151
|
+
initAnalytics(config.apiBaseUrl, config.organizationId, {
|
|
16152
|
+
partnerContractId: config.partnerContractId,
|
|
16153
|
+
});
|
|
15899
16154
|
trackEvent("widget_loaded", {
|
|
15900
16155
|
viewMode,
|
|
15901
16156
|
eventTypeId: config.eventTypeId,
|
|
@@ -15904,7 +16159,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15904
16159
|
isStandaloneVoucherMode,
|
|
15905
16160
|
});
|
|
15906
16161
|
}
|
|
15907
|
-
}, [config.organizationId, config.apiBaseUrl]);
|
|
16162
|
+
}, [config.organizationId, config.apiBaseUrl, config.partnerContractId, viewMode, config.eventTypeId, config.categoryId, config.eventInstanceId, isStandaloneVoucherMode]);
|
|
15908
16163
|
// Fire widget pageview once when Google Ads config is received from API
|
|
15909
16164
|
const pageviewFiredRef = useRef(false);
|
|
15910
16165
|
useEffect(() => {
|
|
@@ -15918,6 +16173,23 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15918
16173
|
const initializeWidget = async () => {
|
|
15919
16174
|
try {
|
|
15920
16175
|
setIsLoading(true);
|
|
16176
|
+
if (config.partnerContractId) {
|
|
16177
|
+
const validationResponse = await fetch(getApiUrl(config.apiBaseUrl, `/booking/validate-partner?organizationId=${encodeURIComponent(config.organizationId)}&contractId=${config.partnerContractId}`), {
|
|
16178
|
+
method: "GET",
|
|
16179
|
+
headers: createApiHeaders(config, locale),
|
|
16180
|
+
});
|
|
16181
|
+
if (!validationResponse.ok) {
|
|
16182
|
+
setError("Invalid partner configuration");
|
|
16183
|
+
config.onError?.("Invalid partner configuration");
|
|
16184
|
+
return;
|
|
16185
|
+
}
|
|
16186
|
+
const validationData = (await validationResponse.json());
|
|
16187
|
+
if (!validationData.valid) {
|
|
16188
|
+
setError("Invalid partner configuration");
|
|
16189
|
+
config.onError?.("Invalid partner configuration");
|
|
16190
|
+
return;
|
|
16191
|
+
}
|
|
16192
|
+
}
|
|
15921
16193
|
// Load voucher config in parallel if voucher mode is requested or there's event selection
|
|
15922
16194
|
if (isVoucherModeRequested || hasEventSelection) {
|
|
15923
16195
|
void loadVoucherConfig();
|
|
@@ -16053,11 +16325,18 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16053
16325
|
setVoucherPurchaseResult(voucherData.voucherResult);
|
|
16054
16326
|
setIsSuccess(true);
|
|
16055
16327
|
setSuccessPaymentId(null);
|
|
16328
|
+
return;
|
|
16056
16329
|
}
|
|
16057
16330
|
}
|
|
16058
16331
|
catch {
|
|
16059
|
-
//
|
|
16060
|
-
}
|
|
16332
|
+
// Fall back to booking success flow if voucher lookup fails.
|
|
16333
|
+
}
|
|
16334
|
+
// Not a voucher purchase: treat as a booking return and open the
|
|
16335
|
+
// booking confirmation, mirroring the Stripe redirect handler.
|
|
16336
|
+
trackEvent("booking_completed", { paymentIntentId: mollieReturn.molliePaymentId, source: "mollie_redirect" });
|
|
16337
|
+
setVoucherPurchaseResult(null);
|
|
16338
|
+
setSuccessPaymentId(mollieReturn.molliePaymentId);
|
|
16339
|
+
setIsSuccess(true);
|
|
16061
16340
|
};
|
|
16062
16341
|
if (!isLoading) {
|
|
16063
16342
|
void handleMollieVoucherReturn();
|
|
@@ -16246,27 +16525,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16246
16525
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16247
16526
|
});
|
|
16248
16527
|
}
|
|
16249
|
-
if (data.stripePublishableKey) {
|
|
16250
|
-
const stripeOptions = {
|
|
16251
|
-
locale: locale,
|
|
16252
|
-
};
|
|
16253
|
-
if (data.connectedAccountId) {
|
|
16254
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16255
|
-
}
|
|
16256
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16257
|
-
try {
|
|
16258
|
-
void (window.parent === window || window.parent.location.href);
|
|
16259
|
-
if (!stripeOptions.betas) {
|
|
16260
|
-
stripeOptions.betas = [];
|
|
16261
|
-
}
|
|
16262
|
-
}
|
|
16263
|
-
catch {
|
|
16264
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16265
|
-
stripeOptions.betas = [];
|
|
16266
|
-
}
|
|
16267
|
-
}
|
|
16268
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16269
|
-
}
|
|
16270
16528
|
if (!skipInstanceAutoSelectRef.current && data.eventInstances.length === 1) {
|
|
16271
16529
|
setSelectedEventInstance(data.eventInstances[0]);
|
|
16272
16530
|
setCurrentStep("booking");
|
|
@@ -16306,29 +16564,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16306
16564
|
roundPricesEnabled: data.roundPricesEnabled ?? true,
|
|
16307
16565
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16308
16566
|
});
|
|
16309
|
-
if (!stripePromise && data.stripePublishableKey) {
|
|
16310
|
-
const stripeOptions = {
|
|
16311
|
-
locale: locale,
|
|
16312
|
-
};
|
|
16313
|
-
if (data.connectedAccountId) {
|
|
16314
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16315
|
-
}
|
|
16316
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16317
|
-
try {
|
|
16318
|
-
// Check if we have parent access (not in a cross-origin iframe)
|
|
16319
|
-
void (window.parent === window || window.parent.location.href);
|
|
16320
|
-
stripeOptions.apiVersion = "2025-02-24.acacia";
|
|
16321
|
-
if (!stripeOptions.betas) {
|
|
16322
|
-
stripeOptions.betas = [];
|
|
16323
|
-
}
|
|
16324
|
-
}
|
|
16325
|
-
catch {
|
|
16326
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16327
|
-
stripeOptions.betas = [];
|
|
16328
|
-
}
|
|
16329
|
-
}
|
|
16330
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16331
|
-
}
|
|
16332
16567
|
}
|
|
16333
16568
|
else {
|
|
16334
16569
|
const errorMessage = data.error || t("error.loadEventDetails");
|
|
@@ -16597,12 +16832,12 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16597
16832
|
startTime: cardPreviewItem.startTime,
|
|
16598
16833
|
endTime: cardPreviewItem.startTime,
|
|
16599
16834
|
price: cardPreviewItem.price,
|
|
16600
|
-
maxParticipants: cardPreviewItem.availableSpots
|
|
16601
|
-
participantCount:
|
|
16835
|
+
maxParticipants: Math.max(cardPreviewItem.availableSpots, 0),
|
|
16836
|
+
participantCount: 0,
|
|
16602
16837
|
availableSpots: cardPreviewItem.availableSpots,
|
|
16603
16838
|
durationDays: 1,
|
|
16604
16839
|
durationPerDay: 1,
|
|
16605
|
-
bookingOpen:
|
|
16840
|
+
bookingOpen: cardPreviewItem.bookingOpen && cardPreviewItem.availableSpots > 0,
|
|
16606
16841
|
}
|
|
16607
16842
|
: null;
|
|
16608
16843
|
if (eventInstance) {
|
|
@@ -16790,7 +17025,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16790
17025
|
}
|
|
16791
17026
|
// Main view based on view mode
|
|
16792
17027
|
if (viewMode === "next-events" && showingPreview) {
|
|
16793
|
-
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17028
|
+
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading, count: nextEventsSettings.count }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16794
17029
|
setIsSuccess(false);
|
|
16795
17030
|
setCurrentStep("eventTypes");
|
|
16796
17031
|
setShowingPreview(true);
|
|
@@ -16811,7 +17046,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16811
17046
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16812
17047
|
}
|
|
16813
17048
|
if (viewMode === "specials" && showingPreview) {
|
|
16814
|
-
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17049
|
+
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16815
17050
|
setIsSuccess(false);
|
|
16816
17051
|
setCurrentStep("eventTypes");
|
|
16817
17052
|
setShowingPreview(true);
|
|
@@ -16825,13 +17060,13 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16825
17060
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16826
17061
|
}
|
|
16827
17062
|
if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
|
|
16828
|
-
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
|
|
17063
|
+
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading, count: nextEventsSettings.count }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
|
|
16829
17064
|
setShowingPreview(true);
|
|
16830
17065
|
setCurrentStep("eventTypes");
|
|
16831
17066
|
}, isOpen: currentStep === "eventInstances", onClose: () => {
|
|
16832
17067
|
setShowingPreview(true);
|
|
16833
17068
|
setCurrentStep("eventTypes");
|
|
16834
|
-
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
17069
|
+
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16835
17070
|
setIsSuccess(false);
|
|
16836
17071
|
setCurrentStep("eventTypes");
|
|
16837
17072
|
setShowingPreview(true);
|
|
@@ -16848,8 +17083,11 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16848
17083
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16849
17084
|
}
|
|
16850
17085
|
if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
|
|
17086
|
+
// Busy only while genuinely loading. Note: we intentionally do NOT key off
|
|
17087
|
+
// `shouldRenderInstanceSelection && !sidebarOpen` — that flag stays true after the
|
|
17088
|
+
// sidebar is closed (only `sidebarOpen` resets), which left the spinner stuck on.
|
|
16851
17089
|
const isButtonBusy = (isDirectInstanceMode && isLoadingEventDetails) ||
|
|
16852
|
-
(!isDirectInstanceMode &&
|
|
17090
|
+
(!isDirectInstanceMode && isLoadingEventInstances);
|
|
16853
17091
|
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, style: {
|
|
16854
17092
|
display: "flex",
|
|
16855
17093
|
justifyContent: "center",
|
|
@@ -16860,13 +17098,15 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16860
17098
|
alignItems: "center",
|
|
16861
17099
|
gap: "10px",
|
|
16862
17100
|
backgroundColor: "var(--bw-highlight-color)",
|
|
16863
|
-
color: "
|
|
17101
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
16864
17102
|
padding: "16px 32px",
|
|
16865
17103
|
border: "none",
|
|
16866
17104
|
borderRadius: "var(--bw-border-radius)",
|
|
16867
17105
|
fontSize: "18px",
|
|
16868
17106
|
fontWeight: 600,
|
|
16869
17107
|
fontFamily: "var(--bw-font-family)",
|
|
17108
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
17109
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
16870
17110
|
boxShadow: "var(--bw-shadow-md)",
|
|
16871
17111
|
cursor: isButtonBusy ? "default" : "pointer",
|
|
16872
17112
|
opacity: isButtonBusy ? 0.85 : 1,
|
|
@@ -16881,8 +17121,8 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16881
17121
|
setSidebarOpen(true);
|
|
16882
17122
|
setShouldRenderInstanceSelection(true);
|
|
16883
17123
|
}
|
|
16884
|
-
}, children: [isButtonBusy && jsx(Spinner, { size: 20, borderColor: "
|
|
16885
|
-
(isDirectInstanceMode ? t("button.bookNow") : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17124
|
+
}, children: [isButtonBusy && jsx(Spinner, { size: 20, borderColor: "var(--bw-button-text-color, #ffffff)" }), config.buttonText ||
|
|
17125
|
+
(isDirectInstanceMode ? t("button.bookNow") : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16886
17126
|
setIsSuccess(false);
|
|
16887
17127
|
setCurrentStep("eventTypes");
|
|
16888
17128
|
setSidebarOpen(false);
|
|
@@ -16943,7 +17183,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16943
17183
|
};
|
|
16944
17184
|
};
|
|
16945
17185
|
const backHandlers = getBackHandlers();
|
|
16946
|
-
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17186
|
+
return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
|
|
16947
17187
|
setIsSuccess(false);
|
|
16948
17188
|
setCurrentStep("eventTypes");
|
|
16949
17189
|
setSuccessPaymentId(null);
|
|
@@ -17007,7 +17247,7 @@ function styleInject(css, ref) {
|
|
|
17007
17247
|
}
|
|
17008
17248
|
}
|
|
17009
17249
|
|
|
17010
|
-
var css_248z = ".booking-widget-container{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;color:var(--bw-text-color,#1e293b);direction:ltr;display:block;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;position:relative;text-align:left}.booking-widget-container *,.booking-widget-container :after,.booking-widget-container :before{box-sizing:border-box;margin:0;padding:0}.booking-widget-container input,.booking-widget-container select,.booking-widget-container textarea{font-family:inherit;font-size:inherit;line-height:inherit}.booking-widget-container button{background:none;border:none;cursor:pointer;font-family:inherit;font-size:inherit}.booking-widget-container a{color:inherit;text-decoration:none}.booking-widget-container img{display:block;height:auto;max-width:100%;vertical-align:middle}.booking-widget-container ol,.booking-widget-container ul{list-style:none}.booking-widget-container h1,.booking-widget-container h2,.booking-widget-container h3,.booking-widget-container h4,.booking-widget-container h5,.booking-widget-container h6{font-size:inherit;font-weight:inherit}#booking-widget-portal{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);direction:ltr;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;text-align:left}#booking-widget-portal *,#booking-widget-portal :after,#booking-widget-portal :before{box-sizing:border-box}#booking-widget-portal-root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);line-height:1.5}:root{--bw-highlight-color:#00b1aa;--bw-highlight-color-rgb:0,177,170;--bw-background-color:#f8fdfe;--bw-surface-color:#fff;--bw-text-color:#0e7490;--bw-text-muted:rgba(14,116,144,.7);--bw-border-color:#bae6fd;--bw-success-color:#38bdf8;--bw-warning-color:#fbbf24;--bw-error-color:#f43f5e;--bw-border-radius:18px;--bw-border-radius-small:calc(var(--bw-border-radius)*0.8);--bw-spacing:16px;--bw-spacing-large:24px;--bw-font-family:\"Inter\",system-ui,sans-serif;--bw-font-size:14px;--bw-font-size-large:18px;--bw-font-size-small:12px;--bw-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);--bw-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--bw-highlight-muted:rgba(0,177,170,.1);--bw-highlight-subtle:rgba(0,177,170,.05);--bw-text-subtle:rgba(14,116,144,.4)}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-out{0%{opacity:1}to{opacity:0}}@keyframes slide-in-right{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes slide-out-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(100%)}}@keyframes slide-in-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.animate-spin{animation:spin 1s linear infinite}.animate-shimmer{animation:shimmer 2s infinite}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-in-up{animation:slide-in-up .3s ease-out}.animate-scale-in{animation:scale-in .2s ease-out}.skeleton-shimmer{overflow:hidden;position:relative}.skeleton-shimmer:after{animation:shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.3),transparent);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.bw-btn{transition:all .2s ease!important}.bw-btn:hover:not(:disabled):not([disabled]){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-btn:active:not(:disabled):not([disabled]){box-shadow:0 2px 4px rgba(0,0,0,.1)}.bw-btn-primary:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);filter:brightness(1.1)}.bw-btn-secondary:hover:not(:disabled):not([disabled]){background-color:var(--bw-surface-color);border-color:var(--bw-highlight-color);color:var(--bw-highlight-color)}.bw-btn-ghost:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-muted)}.bw-btn-outline:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);color:var(--bw-button-text-color,#fff)}.bw-btn:disabled,.bw-btn[disabled]{cursor:not-allowed!important;opacity:.5!important}button[class*=bw-btn],button[style*=transition]{transition:all .2s ease!important}button[data-variant=primary]:hover:not(:disabled),button[style*=\"--bw-highlight-color\"]:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);filter:brightness(1.1);transform:translateY(-1px)}button[data-variant=secondary]:hover:not(:disabled){border-color:var(--bw-highlight-color)!important;color:var(--bw-highlight-color)!important}button[data-variant=ghost]:hover:not(:disabled){background-color:var(--bw-highlight-muted)!important}button[data-variant=outline]:hover:not(:disabled){background-color:var(--bw-highlight-color)!important;color:var(--bw-button-text-color,#fff)!important}.bw-button-hover:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-button-hover:active:not(:disabled){box-shadow:0 2px 4px rgba(0,0,0,.1);transform:translateY(0)}@media (max-width:768px){.sidebar-mobile{border-radius:0!important;max-width:100%!important;width:100%!important}}@media (max-width:600px){.event-type-list{gap:12px!important;padding:8px!important}.event-type-card{flex:1 1 100%!important;max-width:100%!important;padding:0!important}.event-type-img{height:160px!important}.event-type-title{font-size:1.1rem!important}.event-type-desc{font-size:.8rem!important;max-height:100px!important;min-height:100px!important}.event-type-content{padding:16px 24px!important}}.event-type-markdown{overflow:visible!important}.event-type-markdown p{color:var(--bw-text-muted);font-family:var(--bw-font-family);line-height:1.6;margin:0 0 8px}.event-type-markdown p:last-child{margin-bottom:0}.event-type-markdown h2{font-size:18px!important;font-weight:700!important;margin:12px 0 6px!important}.event-type-markdown h2,.event-type-markdown h3{color:var(--bw-text-color)!important;line-height:1.3!important}.event-type-markdown h3{font-size:16px!important;font-weight:600!important;margin:10px 0 4px!important}.event-type-markdown strong{color:var(--bw-text-color);font-weight:600}.event-type-markdown em{font-style:italic}.event-type-markdown u{text-decoration:underline}.event-type-markdown ul{list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ul li{color:var(--bw-text-muted)!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ul li:before{color:var(--bw-text-color)!important;content:\"•\"!important;font-weight:700!important;left:-16px!important;position:absolute!important;top:0!important}.event-type-markdown ol{counter-reset:list-counter!important;list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ol li{color:var(--bw-text-muted)!important;counter-increment:list-counter!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ol li:before{color:var(--bw-text-color)!important;content:counter(list-counter) \".\"!important;font-weight:700!important;left:-20px!important;position:absolute!important;top:0!important}.event-type-markdown blockquote{border-left:2px solid var(--bw-border-color);color:var(--bw-text-muted);font-style:italic;margin:4px 0;padding-left:12px}.event-type-markdown a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{color:var(--bw-text-color);font-weight:600;margin-bottom:.5em}.markdown-content h1{font-size:1.5em}.markdown-content h2{font-size:1.25em}.markdown-content h3{font-size:1.1em}.markdown-content p{line-height:1.6;margin-bottom:1em}.markdown-content ol,.markdown-content ul{margin-bottom:1em;padding-left:1.5em}.markdown-content ul{list-style-type:disc}.markdown-content ol{list-style-type:decimal}.markdown-content li{margin-bottom:.25em}.markdown-content a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content a:hover{opacity:.8}.markdown-content strong{font-weight:600}.markdown-content em{font-style:italic}.markdown-content code{background:var(--bw-highlight-subtle);border-radius:4px;font-family:monospace;font-size:.9em;padding:.125em .25em}.markdown-content blockquote{border-left:3px solid var(--bw-highlight-color);color:var(--bw-text-muted);margin:1em 0;padding-left:1em}.print-only{display:none}.print-hidden{display:block}@media print{.print-only{display:block}.print-hidden{display:none!important}.print-booking-header{border-bottom:2px solid #000;display:block;margin-bottom:24px;padding-bottom:16px;text-align:center}.print-booking-header h1{font-size:24px;margin:0 0 8px}.print-booking-header .subtitle{color:#666;font-size:14px}.print-booking-card{border:1px solid #ccc;border-radius:8px;margin-bottom:16px;padding:16px;page-break-inside:avoid}.print-section-title{border-bottom:1px solid #ddd;display:block;font-size:16px;font-weight:600;margin-bottom:12px;padding-bottom:8px}.print-detail-grid{display:grid;gap:12px;grid-template-columns:1fr 1fr}.print-detail-item{margin-bottom:8px}.print-detail-label{color:#666;font-size:12px;margin-bottom:4px}.print-detail-value{font-size:14px;font-weight:600}.print-status-badge{border-radius:9999px;display:inline-block;font-size:12px;font-weight:600;padding:4px 12px}.print-status-paid{background-color:#dcfce7;color:#166534;display:inline-block}.print-participant{align-items:center;background-color:#f9fafb;border-radius:4px;display:flex;justify-content:space-between;margin-bottom:8px;padding:8px}.print-participant-name{font-weight:600}.print-participant-age{color:#666;font-size:12px}.print-payment-summary{display:block}.print-payment-row{border-bottom:1px solid #eee;display:flex;justify-content:space-between;padding:4px 0}.print-payment-row:last-child{border-bottom:none;font-weight:600}.print-footer{border-top:1px solid #ddd;color:#666;display:block;font-size:12px;margin-top:24px;padding-top:16px;text-align:center}.print-footer p{margin:4px 0}}";
|
|
17250
|
+
var css_248z = ".booking-widget-container{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;color:var(--bw-text-color,#1e293b);direction:ltr;display:block;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;position:relative;text-align:left}.booking-widget-container *,.booking-widget-container :after,.booking-widget-container :before{box-sizing:border-box;margin:0;padding:0}.booking-widget-container input,.booking-widget-container select,.booking-widget-container textarea{font-family:inherit;font-size:inherit;line-height:inherit}.booking-widget-container button{background:none;border:none;cursor:pointer;font-family:inherit;font-size:inherit}.booking-widget-container a{color:inherit;text-decoration:none}.booking-widget-container img{display:block;height:auto;max-width:100%;vertical-align:middle}.booking-widget-container ol,.booking-widget-container ul{list-style:none}.booking-widget-container h1,.booking-widget-container h2,.booking-widget-container h3,.booking-widget-container h4,.booking-widget-container h5,.booking-widget-container h6{font-size:inherit;font-weight:inherit}#booking-widget-portal{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);direction:ltr;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;text-align:left}#booking-widget-portal *,#booking-widget-portal :after,#booking-widget-portal :before{box-sizing:border-box}#booking-widget-portal-root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);line-height:1.5}:root{--bw-highlight-color:#00b1aa;--bw-highlight-color-rgb:0,177,170;--bw-background-color:#f8fdfe;--bw-surface-color:#fff;--bw-text-color:#0e7490;--bw-text-muted:rgba(14,116,144,.7);--bw-border-color:#bae6fd;--bw-success-color:#38bdf8;--bw-warning-color:#fbbf24;--bw-error-color:#f43f5e;--bw-border-radius:18px;--bw-border-radius-small:calc(var(--bw-border-radius)*0.8);--bw-spacing:16px;--bw-spacing-large:24px;--bw-font-family:\"Inter\",system-ui,sans-serif;--bw-font-size:14px;--bw-font-size-large:18px;--bw-font-size-small:12px;--bw-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);--bw-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--bw-highlight-muted:rgba(0,177,170,.1);--bw-highlight-subtle:rgba(0,177,170,.05);--bw-text-subtle:rgba(14,116,144,.4)}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-out{0%{opacity:1}to{opacity:0}}@keyframes slide-in-right{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes slide-out-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(100%)}}@keyframes slide-in-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.animate-spin{animation:spin 1s linear infinite}.animate-shimmer{animation:shimmer 2s infinite}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-in-up{animation:slide-in-up .3s ease-out}.animate-scale-in{animation:scale-in .2s ease-out}.skeleton-shimmer{overflow:hidden;position:relative}.skeleton-shimmer:after{animation:shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.3),transparent);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.bw-btn{letter-spacing:var(--bw-letter-spacing,normal);text-transform:var(--bw-text-transform,none);transition:all .2s ease!important}.bw-btn:hover:not(:disabled):not([disabled]){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-btn:active:not(:disabled):not([disabled]){box-shadow:0 2px 4px rgba(0,0,0,.1)}.bw-btn-primary:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);filter:brightness(1.1)}.bw-btn-secondary:hover:not(:disabled):not([disabled]){background-color:var(--bw-surface-color);border-color:var(--bw-highlight-color);color:var(--bw-highlight-color)}.bw-btn-ghost:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-muted)}.bw-btn-outline:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);color:var(--bw-button-text-color,#fff)}.bw-btn:disabled,.bw-btn[disabled]{cursor:not-allowed!important;opacity:.5!important}button[class*=bw-btn],button[style*=transition]{transition:all .2s ease!important}button[data-variant=primary]:hover:not(:disabled),button[style*=\"--bw-highlight-color\"]:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);filter:brightness(1.1);transform:translateY(-1px)}button[data-variant=secondary]:hover:not(:disabled){border-color:var(--bw-highlight-color)!important;color:var(--bw-highlight-color)!important}button[data-variant=ghost]:hover:not(:disabled){background-color:var(--bw-highlight-muted)!important}button[data-variant=outline]:hover:not(:disabled){background-color:var(--bw-highlight-color)!important;color:var(--bw-button-text-color,#fff)!important}.bw-button-hover:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-button-hover:active:not(:disabled){box-shadow:0 2px 4px rgba(0,0,0,.1);transform:translateY(0)}@media (max-width:768px){.sidebar-mobile{border-radius:0!important;max-width:100%!important;width:100%!important}}@media (max-width:600px){.event-type-list{gap:12px!important;padding:8px!important}.event-type-card{flex:1 1 100%!important;max-width:100%!important;padding:0!important}.event-type-img{height:160px!important}.event-type-title{font-size:1.1rem!important}.event-type-desc{font-size:.8rem!important;max-height:100px!important;min-height:100px!important}.event-type-content{padding:16px 24px!important}}.event-type-markdown{overflow:visible!important}.event-type-markdown p{color:var(--bw-text-muted);font-family:var(--bw-font-family);line-height:1.6;margin:0 0 8px}.event-type-markdown p:last-child{margin-bottom:0}.event-type-markdown h2{font-size:18px!important;font-weight:700!important;margin:12px 0 6px!important}.event-type-markdown h2,.event-type-markdown h3{color:var(--bw-text-color)!important;line-height:1.3!important}.event-type-markdown h3{font-size:16px!important;font-weight:600!important;margin:10px 0 4px!important}.event-type-markdown strong{color:var(--bw-text-color);font-weight:600}.event-type-markdown em{font-style:italic}.event-type-markdown u{text-decoration:underline}.event-type-markdown ul{list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ul li{color:var(--bw-text-muted)!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ul li:before{color:var(--bw-text-color)!important;content:\"•\"!important;font-weight:700!important;left:-16px!important;position:absolute!important;top:0!important}.event-type-markdown ol{counter-reset:list-counter!important;list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ol li{color:var(--bw-text-muted)!important;counter-increment:list-counter!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ol li:before{color:var(--bw-text-color)!important;content:counter(list-counter) \".\"!important;font-weight:700!important;left:-20px!important;position:absolute!important;top:0!important}.event-type-markdown blockquote{border-left:2px solid var(--bw-border-color);color:var(--bw-text-muted);font-style:italic;margin:4px 0;padding-left:12px}.event-type-markdown a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{color:var(--bw-text-color);font-weight:600;margin-bottom:.5em}.markdown-content h1{font-size:1.5em}.markdown-content h2{font-size:1.25em}.markdown-content h3{font-size:1.1em}.markdown-content p{line-height:1.6;margin-bottom:1em}.markdown-content ol,.markdown-content ul{margin-bottom:1em;padding-left:1.5em}.markdown-content ul{list-style-type:disc}.markdown-content ol{list-style-type:decimal}.markdown-content li{margin-bottom:.25em}.markdown-content a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content a:hover{opacity:.8}.markdown-content strong{font-weight:600}.markdown-content em{font-style:italic}.markdown-content code{background:var(--bw-highlight-subtle);border-radius:4px;font-family:monospace;font-size:.9em;padding:.125em .25em}.markdown-content blockquote{border-left:3px solid var(--bw-highlight-color);color:var(--bw-text-muted);margin:1em 0;padding-left:1em}.print-only{display:none}.print-hidden{display:block}@media print{.print-only{display:block}.print-hidden{display:none!important}.print-booking-header{border-bottom:2px solid #000;display:block;margin-bottom:24px;padding-bottom:16px;text-align:center}.print-booking-header h1{font-size:24px;margin:0 0 8px}.print-booking-header .subtitle{color:#666;font-size:14px}.print-booking-card{border:1px solid #ccc;border-radius:8px;margin-bottom:16px;padding:16px;page-break-inside:avoid}.print-section-title{border-bottom:1px solid #ddd;display:block;font-size:16px;font-weight:600;margin-bottom:12px;padding-bottom:8px}.print-detail-grid{display:grid;gap:12px;grid-template-columns:1fr 1fr}.print-detail-item{margin-bottom:8px}.print-detail-label{color:#666;font-size:12px;margin-bottom:4px}.print-detail-value{font-size:14px;font-weight:600}.print-status-badge{border-radius:9999px;display:inline-block;font-size:12px;font-weight:600;padding:4px 12px}.print-status-paid{background-color:#dcfce7;color:#166534;display:inline-block}.print-participant{align-items:center;background-color:#f9fafb;border-radius:4px;display:flex;justify-content:space-between;margin-bottom:8px;padding:8px}.print-participant-name{font-weight:600}.print-participant-age{color:#666;font-size:12px}.print-payment-summary{display:block}.print-payment-row{border-bottom:1px solid #eee;display:flex;justify-content:space-between;padding:4px 0}.print-payment-row:last-child{border-bottom:none;font-weight:600}.print-footer{border-top:1px solid #ddd;color:#666;display:block;font-size:12px;margin-top:24px;padding-top:16px;text-align:center}.print-footer p{margin:4px 0}}";
|
|
17011
17251
|
styleInject(css_248z);
|
|
17012
17252
|
|
|
17013
17253
|
// Export init function for vanilla JS usage
|