@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.cjs
CHANGED
|
@@ -6,188 +6,24 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
var ReactDOM = require('react-dom');
|
|
7
7
|
|
|
8
8
|
function _interopNamespaceDefault(e) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
17
19
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
n.default = e;
|
|
22
|
-
return Object.freeze(n);
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
26
26
|
|
|
27
|
-
var V3_URL = 'https://js.stripe.com/v3';
|
|
28
|
-
var V3_URL_REGEX = /^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;
|
|
29
|
-
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';
|
|
30
|
-
var findScript = function findScript() {
|
|
31
|
-
var scripts = document.querySelectorAll("script[src^=\"".concat(V3_URL, "\"]"));
|
|
32
|
-
|
|
33
|
-
for (var i = 0; i < scripts.length; i++) {
|
|
34
|
-
var script = scripts[i];
|
|
35
|
-
|
|
36
|
-
if (!V3_URL_REGEX.test(script.src)) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return script;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return null;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
var injectScript = function injectScript(params) {
|
|
47
|
-
var queryString = '';
|
|
48
|
-
var script = document.createElement('script');
|
|
49
|
-
script.src = "".concat(V3_URL).concat(queryString);
|
|
50
|
-
var headOrBody = document.head || document.body;
|
|
51
|
-
|
|
52
|
-
if (!headOrBody) {
|
|
53
|
-
throw new Error('Expected document.body not to be null. Stripe.js requires a <body> element.');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
headOrBody.appendChild(script);
|
|
57
|
-
return script;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
var registerWrapper = function registerWrapper(stripe, startTime) {
|
|
61
|
-
if (!stripe || !stripe._registerWrapper) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
stripe._registerWrapper({
|
|
66
|
-
name: 'stripe-js',
|
|
67
|
-
version: "4.6.0",
|
|
68
|
-
startTime: startTime
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
var stripePromise = null;
|
|
73
|
-
var onErrorListener = null;
|
|
74
|
-
var onLoadListener = null;
|
|
75
|
-
|
|
76
|
-
var onError = function onError(reject) {
|
|
77
|
-
return function () {
|
|
78
|
-
reject(new Error('Failed to load Stripe.js'));
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
var onLoad = function onLoad(resolve, reject) {
|
|
83
|
-
return function () {
|
|
84
|
-
if (window.Stripe) {
|
|
85
|
-
resolve(window.Stripe);
|
|
86
|
-
} else {
|
|
87
|
-
reject(new Error('Stripe.js not available'));
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
var loadScript = function loadScript(params) {
|
|
93
|
-
// Ensure that we only attempt to load Stripe.js at most once
|
|
94
|
-
if (stripePromise !== null) {
|
|
95
|
-
return stripePromise;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
stripePromise = new Promise(function (resolve, reject) {
|
|
99
|
-
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
100
|
-
// Resolve to null when imported server side. This makes the module
|
|
101
|
-
// safe to import in an isomorphic code base.
|
|
102
|
-
resolve(null);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (window.Stripe) {
|
|
107
|
-
resolve(window.Stripe);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
var script = findScript();
|
|
113
|
-
|
|
114
|
-
if (script && params) ; else if (!script) {
|
|
115
|
-
script = injectScript(params);
|
|
116
|
-
} else if (script && onLoadListener !== null && onErrorListener !== null) {
|
|
117
|
-
var _script$parentNode;
|
|
118
|
-
|
|
119
|
-
// remove event listeners
|
|
120
|
-
script.removeEventListener('load', onLoadListener);
|
|
121
|
-
script.removeEventListener('error', onErrorListener); // if script exists, but we are reloading due to an error,
|
|
122
|
-
// reload script to trigger 'load' event
|
|
123
|
-
|
|
124
|
-
(_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
|
|
125
|
-
script = injectScript(params);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
onLoadListener = onLoad(resolve, reject);
|
|
129
|
-
onErrorListener = onError(reject);
|
|
130
|
-
script.addEventListener('load', onLoadListener);
|
|
131
|
-
script.addEventListener('error', onErrorListener);
|
|
132
|
-
} catch (error) {
|
|
133
|
-
reject(error);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
}); // Resets stripePromise on error
|
|
137
|
-
|
|
138
|
-
return stripePromise["catch"](function (error) {
|
|
139
|
-
stripePromise = null;
|
|
140
|
-
return Promise.reject(error);
|
|
141
|
-
});
|
|
142
|
-
};
|
|
143
|
-
var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
144
|
-
if (maybeStripe === null) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
var stripe = maybeStripe.apply(undefined, args);
|
|
149
|
-
registerWrapper(stripe, startTime);
|
|
150
|
-
return stripe;
|
|
151
|
-
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
152
|
-
|
|
153
|
-
var stripePromise$1;
|
|
154
|
-
var loadCalled = false;
|
|
155
|
-
|
|
156
|
-
var getStripePromise = function getStripePromise() {
|
|
157
|
-
if (stripePromise$1) {
|
|
158
|
-
return stripePromise$1;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
stripePromise$1 = loadScript(null)["catch"](function (error) {
|
|
162
|
-
// clear cache on error
|
|
163
|
-
stripePromise$1 = null;
|
|
164
|
-
return Promise.reject(error);
|
|
165
|
-
});
|
|
166
|
-
return stripePromise$1;
|
|
167
|
-
}; // Execute our own script injection after a tick to give users time to do their
|
|
168
|
-
// own script injection.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Promise.resolve().then(function () {
|
|
172
|
-
return getStripePromise();
|
|
173
|
-
})["catch"](function (error) {
|
|
174
|
-
if (!loadCalled) {
|
|
175
|
-
console.warn(error);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
var loadStripe = function loadStripe() {
|
|
179
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
180
|
-
args[_key] = arguments[_key];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
loadCalled = true;
|
|
184
|
-
var startTime = Date.now(); // if previous attempts are unsuccessful, will re-load script
|
|
185
|
-
|
|
186
|
-
return getStripePromise().then(function (maybeStripe) {
|
|
187
|
-
return initStripe(maybeStripe, args, startTime);
|
|
188
|
-
});
|
|
189
|
-
};
|
|
190
|
-
|
|
191
27
|
const de$1 = {
|
|
192
28
|
// Common
|
|
193
29
|
"common.back": "← Zurück",
|
|
@@ -267,6 +103,24 @@ const de$1 = {
|
|
|
267
103
|
"instances.bestPrice": "bester Preis !!!",
|
|
268
104
|
"instances.goodPrice": "günstiger Preis",
|
|
269
105
|
"instances.oclock": "Uhr",
|
|
106
|
+
// Warteliste
|
|
107
|
+
"waitlist.joinCta": "Auf die Warteliste",
|
|
108
|
+
"waitlist.title": "Auf die Warteliste setzen",
|
|
109
|
+
"waitlist.subtitle": "{{name}} ist ausgebucht. Hinterlassen Sie Ihre Daten und wir melden uns, falls ein Platz frei wird.",
|
|
110
|
+
"waitlist.name": "Name",
|
|
111
|
+
"waitlist.email": "E-Mail",
|
|
112
|
+
"waitlist.phone": "Telefon (optional)",
|
|
113
|
+
"waitlist.requiredFields": "Bitte geben Sie Ihren Namen und Ihre E-Mail-Adresse ein.",
|
|
114
|
+
"waitlist.join": "Eintragen",
|
|
115
|
+
"waitlist.submitting": "Wird eingetragen...",
|
|
116
|
+
"waitlist.cancel": "Abbrechen",
|
|
117
|
+
"waitlist.submitError": "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.",
|
|
118
|
+
"waitlist.successTitle": "Sie sind auf der Liste!",
|
|
119
|
+
"waitlist.successMessage": "Sie sind Nummer {{position}} auf der Warteliste. Wir melden uns, sobald ein Platz frei wird.",
|
|
120
|
+
"waitlist.done": "Fertig",
|
|
121
|
+
// Reservierungs-Countdown
|
|
122
|
+
"hold.reservedFor": "Platz reserviert für {{time}}",
|
|
123
|
+
"hold.expired": "Ihre Reservierung ist abgelaufen",
|
|
270
124
|
// Next events preview
|
|
271
125
|
"nextEvents.title": "Nächste verfügbare Termine",
|
|
272
126
|
"nextEvents.subtitle": "Wähle einen Termin aus oder zeige alle verfügbaren Termine an",
|
|
@@ -557,6 +411,24 @@ const en = {
|
|
|
557
411
|
"instances.bestPrice": "best price !!!",
|
|
558
412
|
"instances.goodPrice": "good price",
|
|
559
413
|
"instances.oclock": "",
|
|
414
|
+
// Waitlist
|
|
415
|
+
"waitlist.joinCta": "Join waitlist",
|
|
416
|
+
"waitlist.title": "Join the waitlist",
|
|
417
|
+
"waitlist.subtitle": "{{name}} is fully booked. Leave your details and we'll contact you if a spot opens up.",
|
|
418
|
+
"waitlist.name": "Name",
|
|
419
|
+
"waitlist.email": "Email",
|
|
420
|
+
"waitlist.phone": "Phone (optional)",
|
|
421
|
+
"waitlist.requiredFields": "Please enter your name and email.",
|
|
422
|
+
"waitlist.join": "Join waitlist",
|
|
423
|
+
"waitlist.submitting": "Joining...",
|
|
424
|
+
"waitlist.cancel": "Cancel",
|
|
425
|
+
"waitlist.submitError": "Something went wrong. Please try again.",
|
|
426
|
+
"waitlist.successTitle": "You're on the list!",
|
|
427
|
+
"waitlist.successMessage": "You are number {{position}} on the waitlist. We'll be in touch if a spot becomes available.",
|
|
428
|
+
"waitlist.done": "Done",
|
|
429
|
+
// Slot hold countdown
|
|
430
|
+
"hold.reservedFor": "Slot reserved for {{time}}",
|
|
431
|
+
"hold.expired": "Your reservation has expired",
|
|
560
432
|
// Next events preview
|
|
561
433
|
"nextEvents.title": "Next available dates",
|
|
562
434
|
"nextEvents.subtitle": "Select a date or view all available dates",
|
|
@@ -2065,6 +1937,28 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2065
1937
|
c = `0x${c.join("")}`;
|
|
2066
1938
|
return [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(",");
|
|
2067
1939
|
};
|
|
1940
|
+
// Pick a readable text color (dark or light) for content sitting on top of
|
|
1941
|
+
// the given background color. Bright/neon highlights (teal, matrix green,
|
|
1942
|
+
// gold, etc.) need dark text — white text on them is unreadable.
|
|
1943
|
+
const getContrastingTextColor = (color, lightColor = "#ffffff", darkColor = "#0e1420") => {
|
|
1944
|
+
let rgb;
|
|
1945
|
+
if (color.startsWith("#")) {
|
|
1946
|
+
rgb = hexToRgb(color);
|
|
1947
|
+
}
|
|
1948
|
+
else if (color.startsWith("rgb")) {
|
|
1949
|
+
rgb = color.replace(/rgba?\(|\)/g, "").split(",").slice(0, 3).join(",");
|
|
1950
|
+
}
|
|
1951
|
+
else {
|
|
1952
|
+
return lightColor; // Can't parse (e.g. hsl/oklch/semantic) — keep existing default
|
|
1953
|
+
}
|
|
1954
|
+
const [r, g, b] = rgb.split(",").map((n) => parseInt(n, 10) / 255);
|
|
1955
|
+
if ([r, g, b].some((n) => Number.isNaN(n)))
|
|
1956
|
+
return lightColor;
|
|
1957
|
+
// Relative luminance (sRGB, WCAG)
|
|
1958
|
+
const toLinear = (n) => (n <= 0.03928 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4));
|
|
1959
|
+
const luminance = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
1960
|
+
return luminance > 0.45 ? darkColor : lightColor;
|
|
1961
|
+
};
|
|
2068
1962
|
const colors = config.colors || {};
|
|
2069
1963
|
const finalColors = {
|
|
2070
1964
|
highlight: getCSSValue(colors.highlight, themeDefaults.highlight),
|
|
@@ -2084,7 +1978,7 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2084
1978
|
"--bw-surface-color": finalColors.surface,
|
|
2085
1979
|
"--bw-text-color": finalColors.text,
|
|
2086
1980
|
"--bw-text-muted": addOpacity(finalColors.text, 0.7),
|
|
2087
|
-
"--bw-button-text-color": themeDefaults.buttonTextColor ||
|
|
1981
|
+
"--bw-button-text-color": themeDefaults.buttonTextColor || getContrastingTextColor(finalColors.highlight),
|
|
2088
1982
|
"--bw-border-color": finalColors.border,
|
|
2089
1983
|
"--bw-success-color": finalColors.success,
|
|
2090
1984
|
"--bw-warning-color": finalColors.warning,
|
|
@@ -2102,6 +1996,9 @@ const StyleProvider = ({ config, children, }) => {
|
|
|
2102
1996
|
"--bw-highlight-muted": addOpacity(finalColors.highlight, 0.1),
|
|
2103
1997
|
"--bw-highlight-subtle": addOpacity(finalColors.highlight, 0.05),
|
|
2104
1998
|
"--bw-text-subtle": addOpacity(finalColors.text, 0.4),
|
|
1999
|
+
// Some themes (neon-brutalism) call for uppercased titles & buttons
|
|
2000
|
+
"--bw-text-transform": themeName === "dark-neon-brutalism" ? "uppercase" : "none",
|
|
2001
|
+
"--bw-letter-spacing": themeName === "dark-neon-brutalism" ? "0.04em" : "normal",
|
|
2105
2002
|
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",
|
|
2106
2003
|
};
|
|
2107
2004
|
}, [
|
|
@@ -2237,6 +2134,7 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2237
2134
|
const categoryId = urlParams.get("categoryId") || urlParams.get("category");
|
|
2238
2135
|
const eventTypeId = urlParams.get("eventTypeId") || urlParams.get("type");
|
|
2239
2136
|
const eventTypeIds = urlParams.get("eventTypeIds") || urlParams.get("types");
|
|
2137
|
+
const partnerContractId = urlParams.get("partnerContractId") || urlParams.get("contractId");
|
|
2240
2138
|
const voucherValue = urlParams.get("voucherValue");
|
|
2241
2139
|
const voucherCategory = urlParams.get("voucherCategory");
|
|
2242
2140
|
const voucherEventType = urlParams.get("voucherEventType");
|
|
@@ -2249,11 +2147,14 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2249
2147
|
: ["0", "false", "no", "off"].includes(voucherCardIntegration.toLowerCase())
|
|
2250
2148
|
? false
|
|
2251
2149
|
: undefined;
|
|
2252
|
-
const omitSelectionKeys = ({ categoryId: _c, eventTypeId: _e, eventTypeIds: _es, eventInstanceId: _i, voucherValue: _vv, voucherCategory: _vc, voucherEventType: _ve, voucherImageId: _vi, ...rest }) => rest;
|
|
2150
|
+
const omitSelectionKeys = ({ categoryId: _c, eventTypeId: _e, eventTypeIds: _es, eventInstanceId: _i, voucherValue: _vv, voucherCategory: _vc, voucherEventType: _ve, voucherImageId: _vi, partnerContractId: _pc, ...rest }) => rest;
|
|
2253
2151
|
if (eventInstanceId && !Number.isNaN(Number(eventInstanceId))) {
|
|
2254
2152
|
return {
|
|
2255
2153
|
...omitSelectionKeys(baseConfig),
|
|
2256
2154
|
eventInstanceId: Number(eventInstanceId),
|
|
2155
|
+
...(partnerContractId
|
|
2156
|
+
? { partnerContractId }
|
|
2157
|
+
: {}),
|
|
2257
2158
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2258
2159
|
};
|
|
2259
2160
|
}
|
|
@@ -2261,6 +2162,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2261
2162
|
return {
|
|
2262
2163
|
...omitSelectionKeys(baseConfig),
|
|
2263
2164
|
categoryId: Number(categoryId),
|
|
2165
|
+
...(partnerContractId
|
|
2166
|
+
? { partnerContractId }
|
|
2167
|
+
: {}),
|
|
2264
2168
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2265
2169
|
};
|
|
2266
2170
|
}
|
|
@@ -2268,6 +2172,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2268
2172
|
return {
|
|
2269
2173
|
...omitSelectionKeys(baseConfig),
|
|
2270
2174
|
eventTypeId: Number(eventTypeId),
|
|
2175
|
+
...(partnerContractId
|
|
2176
|
+
? { partnerContractId }
|
|
2177
|
+
: {}),
|
|
2271
2178
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2272
2179
|
};
|
|
2273
2180
|
}
|
|
@@ -2280,6 +2187,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2280
2187
|
return {
|
|
2281
2188
|
...omitSelectionKeys(baseConfig),
|
|
2282
2189
|
eventTypeIds: typeIds,
|
|
2190
|
+
...(partnerContractId
|
|
2191
|
+
? { partnerContractId }
|
|
2192
|
+
: {}),
|
|
2283
2193
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2284
2194
|
};
|
|
2285
2195
|
}
|
|
@@ -2296,6 +2206,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2296
2206
|
if (parsedVoucherValues.length || parsedVoucherCategories.length || parsedVoucherEventTypes.length) {
|
|
2297
2207
|
return {
|
|
2298
2208
|
...baseConfig,
|
|
2209
|
+
...(partnerContractId
|
|
2210
|
+
? { partnerContractId }
|
|
2211
|
+
: {}),
|
|
2299
2212
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2300
2213
|
...(parsedVoucherValues.length > 0
|
|
2301
2214
|
? { voucherValue: parsedVoucherValues.length === 1 ? parsedVoucherValues[0] : parsedVoucherValues }
|
|
@@ -2313,6 +2226,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2313
2226
|
}
|
|
2314
2227
|
return {
|
|
2315
2228
|
...baseConfig,
|
|
2229
|
+
...(partnerContractId
|
|
2230
|
+
? { partnerContractId }
|
|
2231
|
+
: {}),
|
|
2316
2232
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2317
2233
|
};
|
|
2318
2234
|
};
|
|
@@ -6325,6 +6241,7 @@ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, gif
|
|
|
6325
6241
|
customerPhone: formData.customerPhone?.trim(),
|
|
6326
6242
|
comment: formData.comment?.trim(),
|
|
6327
6243
|
paymentMethod: "gift_card",
|
|
6244
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6328
6245
|
...(upsellSelections.length > 0 && { upsellSelections }),
|
|
6329
6246
|
};
|
|
6330
6247
|
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
|
|
@@ -6601,6 +6518,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6601
6518
|
customerEmail: formData.customerEmail?.trim(),
|
|
6602
6519
|
customerPhone: formData.customerPhone?.trim(),
|
|
6603
6520
|
comment: formData.comment?.trim(),
|
|
6521
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6604
6522
|
...(cardToken && { cardToken }),
|
|
6605
6523
|
...(selectedMethod && !cardToken && { method: selectedMethod }),
|
|
6606
6524
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
@@ -6827,6 +6745,170 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6827
6745
|
}, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [spinner("var(--bw-surface-color)"), " ", buttonLabel] })) : (buttonLabel) }))] }));
|
|
6828
6746
|
}
|
|
6829
6747
|
|
|
6748
|
+
var V3_URL = 'https://js.stripe.com/v3';
|
|
6749
|
+
var V3_URL_REGEX = /^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;
|
|
6750
|
+
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';
|
|
6751
|
+
var findScript = function findScript() {
|
|
6752
|
+
var scripts = document.querySelectorAll("script[src^=\"".concat(V3_URL, "\"]"));
|
|
6753
|
+
|
|
6754
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
6755
|
+
var script = scripts[i];
|
|
6756
|
+
|
|
6757
|
+
if (!V3_URL_REGEX.test(script.src)) {
|
|
6758
|
+
continue;
|
|
6759
|
+
}
|
|
6760
|
+
|
|
6761
|
+
return script;
|
|
6762
|
+
}
|
|
6763
|
+
|
|
6764
|
+
return null;
|
|
6765
|
+
};
|
|
6766
|
+
|
|
6767
|
+
var injectScript = function injectScript(params) {
|
|
6768
|
+
var queryString = '';
|
|
6769
|
+
var script = document.createElement('script');
|
|
6770
|
+
script.src = "".concat(V3_URL).concat(queryString);
|
|
6771
|
+
var headOrBody = document.head || document.body;
|
|
6772
|
+
|
|
6773
|
+
if (!headOrBody) {
|
|
6774
|
+
throw new Error('Expected document.body not to be null. Stripe.js requires a <body> element.');
|
|
6775
|
+
}
|
|
6776
|
+
|
|
6777
|
+
headOrBody.appendChild(script);
|
|
6778
|
+
return script;
|
|
6779
|
+
};
|
|
6780
|
+
|
|
6781
|
+
var registerWrapper = function registerWrapper(stripe, startTime) {
|
|
6782
|
+
if (!stripe || !stripe._registerWrapper) {
|
|
6783
|
+
return;
|
|
6784
|
+
}
|
|
6785
|
+
|
|
6786
|
+
stripe._registerWrapper({
|
|
6787
|
+
name: 'stripe-js',
|
|
6788
|
+
version: "4.6.0",
|
|
6789
|
+
startTime: startTime
|
|
6790
|
+
});
|
|
6791
|
+
};
|
|
6792
|
+
|
|
6793
|
+
var stripePromise = null;
|
|
6794
|
+
var onErrorListener = null;
|
|
6795
|
+
var onLoadListener = null;
|
|
6796
|
+
|
|
6797
|
+
var onError = function onError(reject) {
|
|
6798
|
+
return function () {
|
|
6799
|
+
reject(new Error('Failed to load Stripe.js'));
|
|
6800
|
+
};
|
|
6801
|
+
};
|
|
6802
|
+
|
|
6803
|
+
var onLoad = function onLoad(resolve, reject) {
|
|
6804
|
+
return function () {
|
|
6805
|
+
if (window.Stripe) {
|
|
6806
|
+
resolve(window.Stripe);
|
|
6807
|
+
} else {
|
|
6808
|
+
reject(new Error('Stripe.js not available'));
|
|
6809
|
+
}
|
|
6810
|
+
};
|
|
6811
|
+
};
|
|
6812
|
+
|
|
6813
|
+
var loadScript = function loadScript(params) {
|
|
6814
|
+
// Ensure that we only attempt to load Stripe.js at most once
|
|
6815
|
+
if (stripePromise !== null) {
|
|
6816
|
+
return stripePromise;
|
|
6817
|
+
}
|
|
6818
|
+
|
|
6819
|
+
stripePromise = new Promise(function (resolve, reject) {
|
|
6820
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
6821
|
+
// Resolve to null when imported server side. This makes the module
|
|
6822
|
+
// safe to import in an isomorphic code base.
|
|
6823
|
+
resolve(null);
|
|
6824
|
+
return;
|
|
6825
|
+
}
|
|
6826
|
+
|
|
6827
|
+
if (window.Stripe) {
|
|
6828
|
+
resolve(window.Stripe);
|
|
6829
|
+
return;
|
|
6830
|
+
}
|
|
6831
|
+
|
|
6832
|
+
try {
|
|
6833
|
+
var script = findScript();
|
|
6834
|
+
|
|
6835
|
+
if (script && params) ; else if (!script) {
|
|
6836
|
+
script = injectScript(params);
|
|
6837
|
+
} else if (script && onLoadListener !== null && onErrorListener !== null) {
|
|
6838
|
+
var _script$parentNode;
|
|
6839
|
+
|
|
6840
|
+
// remove event listeners
|
|
6841
|
+
script.removeEventListener('load', onLoadListener);
|
|
6842
|
+
script.removeEventListener('error', onErrorListener); // if script exists, but we are reloading due to an error,
|
|
6843
|
+
// reload script to trigger 'load' event
|
|
6844
|
+
|
|
6845
|
+
(_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
|
|
6846
|
+
script = injectScript(params);
|
|
6847
|
+
}
|
|
6848
|
+
|
|
6849
|
+
onLoadListener = onLoad(resolve, reject);
|
|
6850
|
+
onErrorListener = onError(reject);
|
|
6851
|
+
script.addEventListener('load', onLoadListener);
|
|
6852
|
+
script.addEventListener('error', onErrorListener);
|
|
6853
|
+
} catch (error) {
|
|
6854
|
+
reject(error);
|
|
6855
|
+
return;
|
|
6856
|
+
}
|
|
6857
|
+
}); // Resets stripePromise on error
|
|
6858
|
+
|
|
6859
|
+
return stripePromise["catch"](function (error) {
|
|
6860
|
+
stripePromise = null;
|
|
6861
|
+
return Promise.reject(error);
|
|
6862
|
+
});
|
|
6863
|
+
};
|
|
6864
|
+
var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
6865
|
+
if (maybeStripe === null) {
|
|
6866
|
+
return null;
|
|
6867
|
+
}
|
|
6868
|
+
|
|
6869
|
+
var stripe = maybeStripe.apply(undefined, args);
|
|
6870
|
+
registerWrapper(stripe, startTime);
|
|
6871
|
+
return stripe;
|
|
6872
|
+
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
6873
|
+
|
|
6874
|
+
var stripePromise$1;
|
|
6875
|
+
var loadCalled = false;
|
|
6876
|
+
|
|
6877
|
+
var getStripePromise = function getStripePromise() {
|
|
6878
|
+
if (stripePromise$1) {
|
|
6879
|
+
return stripePromise$1;
|
|
6880
|
+
}
|
|
6881
|
+
|
|
6882
|
+
stripePromise$1 = loadScript(null)["catch"](function (error) {
|
|
6883
|
+
// clear cache on error
|
|
6884
|
+
stripePromise$1 = null;
|
|
6885
|
+
return Promise.reject(error);
|
|
6886
|
+
});
|
|
6887
|
+
return stripePromise$1;
|
|
6888
|
+
}; // Execute our own script injection after a tick to give users time to do their
|
|
6889
|
+
// own script injection.
|
|
6890
|
+
|
|
6891
|
+
|
|
6892
|
+
Promise.resolve().then(function () {
|
|
6893
|
+
return getStripePromise();
|
|
6894
|
+
})["catch"](function (error) {
|
|
6895
|
+
if (!loadCalled) {
|
|
6896
|
+
console.warn(error);
|
|
6897
|
+
}
|
|
6898
|
+
});
|
|
6899
|
+
var loadStripe = function loadStripe() {
|
|
6900
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
6901
|
+
args[_key] = arguments[_key];
|
|
6902
|
+
}
|
|
6903
|
+
|
|
6904
|
+
loadCalled = true;
|
|
6905
|
+
var startTime = Date.now(); // if previous attempts are unsuccessful, will re-load script
|
|
6906
|
+
|
|
6907
|
+
return getStripePromise().then(function (maybeStripe) {
|
|
6908
|
+
return initStripe(maybeStripe, args, startTime);
|
|
6909
|
+
});
|
|
6910
|
+
};
|
|
6911
|
+
|
|
6830
6912
|
// Inner component that uses the Stripe hooks
|
|
6831
6913
|
function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onError, }) {
|
|
6832
6914
|
const t = useTranslations();
|
|
@@ -6855,13 +6937,25 @@ function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onEr
|
|
|
6855
6937
|
},
|
|
6856
6938
|
}, submitContent: jsxRuntime.jsx(jsxRuntime.Fragment, { children: submitLabel }), loadingContent: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [spinner("var(--bw-surface-color)"), " ", t("button.processingPayment")] }) }));
|
|
6857
6939
|
}
|
|
6858
|
-
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig,
|
|
6940
|
+
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripeAppearance, upsellSelections = [], }) {
|
|
6859
6941
|
const t = useTranslations();
|
|
6860
6942
|
const { locale } = useLocale();
|
|
6861
6943
|
const [clientSecret, setClientSecret] = React.useState(null);
|
|
6862
6944
|
const [paymentIntentId, setPaymentIntentId] = React.useState(null);
|
|
6863
6945
|
const [isCreatingPaymentIntent, setIsCreatingPaymentIntent] = React.useState(false);
|
|
6864
6946
|
const [paymentError, setPaymentError] = React.useState(null);
|
|
6947
|
+
const stripePromise = React.useMemo(() => {
|
|
6948
|
+
if (!systemConfig?.stripePublishableKey) {
|
|
6949
|
+
return null;
|
|
6950
|
+
}
|
|
6951
|
+
const stripeOptions = {
|
|
6952
|
+
locale: locale,
|
|
6953
|
+
};
|
|
6954
|
+
if (systemConfig.connectedAccountId) {
|
|
6955
|
+
stripeOptions.stripeAccount = systemConfig.connectedAccountId;
|
|
6956
|
+
}
|
|
6957
|
+
return loadStripe(systemConfig.stripePublishableKey, stripeOptions);
|
|
6958
|
+
}, [systemConfig?.stripePublishableKey, systemConfig?.connectedAccountId, locale]);
|
|
6865
6959
|
const storageKey = typeof window !== "undefined"
|
|
6866
6960
|
? `bw_pi_${config?.organizationId}_${config?.eventInstanceId || eventDetails?.id}`
|
|
6867
6961
|
: "";
|
|
@@ -6940,6 +7034,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6940
7034
|
customerEmail: formData.customerEmail?.trim(),
|
|
6941
7035
|
customerPhone: formData.customerPhone?.trim(),
|
|
6942
7036
|
comment: formData.comment?.trim(),
|
|
7037
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6943
7038
|
...(paymentIntentId && { paymentIntentId }),
|
|
6944
7039
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
6945
7040
|
};
|
|
@@ -7009,7 +7104,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
7009
7104
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
7010
7105
|
return (jsxRuntime.jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
7011
7106
|
}
|
|
7012
|
-
if (isCreatingPaymentIntent || !clientSecret) {
|
|
7107
|
+
if (isCreatingPaymentIntent || !clientSecret || !stripePromise) {
|
|
7013
7108
|
return (jsxRuntime.jsxs("div", { style: {
|
|
7014
7109
|
display: "flex",
|
|
7015
7110
|
alignItems: "center",
|
|
@@ -7047,6 +7142,49 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
7047
7142
|
}, onError: onError }) }));
|
|
7048
7143
|
}
|
|
7049
7144
|
|
|
7145
|
+
const HOLD_DURATION_SECONDS = 15 * 60;
|
|
7146
|
+
/**
|
|
7147
|
+
* Shows the remaining time on the 15-minute slot hold that the server places on
|
|
7148
|
+
* the pending order while the customer completes checkout. The timer is started
|
|
7149
|
+
* client-side when the payment step opens — matching the moment the pending
|
|
7150
|
+
* order (and its `holdExpiresAt`) is created server-side.
|
|
7151
|
+
*/
|
|
7152
|
+
function HoldCountdown({ onExpire }) {
|
|
7153
|
+
const t = useTranslations();
|
|
7154
|
+
const [remaining, setRemaining] = React.useState(HOLD_DURATION_SECONDS);
|
|
7155
|
+
React.useEffect(() => {
|
|
7156
|
+
const startedAt = Date.now();
|
|
7157
|
+
const interval = setInterval(() => {
|
|
7158
|
+
const elapsed = Math.floor((Date.now() - startedAt) / 1000);
|
|
7159
|
+
const left = Math.max(0, HOLD_DURATION_SECONDS - elapsed);
|
|
7160
|
+
setRemaining(left);
|
|
7161
|
+
if (left <= 0) {
|
|
7162
|
+
clearInterval(interval);
|
|
7163
|
+
onExpire?.();
|
|
7164
|
+
}
|
|
7165
|
+
}, 1000);
|
|
7166
|
+
return () => clearInterval(interval);
|
|
7167
|
+
}, [onExpire]);
|
|
7168
|
+
const minutes = Math.floor(remaining / 60);
|
|
7169
|
+
const seconds = remaining % 60;
|
|
7170
|
+
const formatted = `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
7171
|
+
const isLow = remaining <= 60;
|
|
7172
|
+
return (jsxRuntime.jsxs("div", { style: {
|
|
7173
|
+
display: "flex",
|
|
7174
|
+
alignItems: "center",
|
|
7175
|
+
gap: "8px",
|
|
7176
|
+
padding: "10px 14px",
|
|
7177
|
+
borderRadius: "var(--bw-border-radius)",
|
|
7178
|
+
border: `1px solid ${isLow ? "var(--bw-error-color)" : "var(--bw-border-color)"}`,
|
|
7179
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
7180
|
+
color: isLow ? "var(--bw-error-color)" : "var(--bw-text-color)",
|
|
7181
|
+
fontFamily: "var(--bw-font-family)",
|
|
7182
|
+
fontSize: "14px",
|
|
7183
|
+
}, children: [jsxRuntime.jsx(IconClock, {}), jsxRuntime.jsx("span", { children: remaining > 0
|
|
7184
|
+
? t("hold.reservedFor", { time: formatted })
|
|
7185
|
+
: t("hold.expired") })] }));
|
|
7186
|
+
}
|
|
7187
|
+
|
|
7050
7188
|
const FLAG_EMOJIS = {
|
|
7051
7189
|
de: "🇩🇪",
|
|
7052
7190
|
en: "🇬🇧",
|
|
@@ -7261,6 +7399,8 @@ function Sidebar({ isOpen, onClose, title, children, width = "450px", footer, })
|
|
|
7261
7399
|
fontSize: "16px",
|
|
7262
7400
|
color: "var(--bw-text-color)",
|
|
7263
7401
|
fontFamily: "var(--bw-font-family)",
|
|
7402
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
7403
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
7264
7404
|
flex: 1,
|
|
7265
7405
|
paddingRight: "12px",
|
|
7266
7406
|
minWidth: 0,
|
|
@@ -11438,6 +11578,8 @@ const buttonBase = {
|
|
|
11438
11578
|
transition: "all 0.2s ease",
|
|
11439
11579
|
whiteSpace: "nowrap",
|
|
11440
11580
|
border: "none",
|
|
11581
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
11582
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
11441
11583
|
};
|
|
11442
11584
|
// CSS class name for button hover effects
|
|
11443
11585
|
const buttonClassName = "bw-button-hover";
|
|
@@ -11454,6 +11596,11 @@ const buttonStyles = {
|
|
|
11454
11596
|
color: "var(--bw-text-muted)",
|
|
11455
11597
|
border: "1px solid var(--bw-border-color)",
|
|
11456
11598
|
},
|
|
11599
|
+
// Size variants
|
|
11600
|
+
small: {
|
|
11601
|
+
padding: "8px 12px",
|
|
11602
|
+
fontSize: "13px",
|
|
11603
|
+
},
|
|
11457
11604
|
// Full width modifier
|
|
11458
11605
|
fullWidth: {
|
|
11459
11606
|
width: "100%",
|
|
@@ -11526,6 +11673,12 @@ const sectionStyles = {
|
|
|
11526
11673
|
// TEXT
|
|
11527
11674
|
// ============================================
|
|
11528
11675
|
const textStyles = {
|
|
11676
|
+
body: {
|
|
11677
|
+
fontSize: "14px",
|
|
11678
|
+
color: "var(--bw-text-color)",
|
|
11679
|
+
fontFamily: "var(--bw-font-family)",
|
|
11680
|
+
lineHeight: 1.5,
|
|
11681
|
+
},
|
|
11529
11682
|
muted: {
|
|
11530
11683
|
fontSize: "14px",
|
|
11531
11684
|
color: "var(--bw-text-muted)",
|
|
@@ -11595,7 +11748,7 @@ const sectionHeaderStyles$1 = sectionStyles.header;
|
|
|
11595
11748
|
const labelStyles$1 = formStyles.label;
|
|
11596
11749
|
const inputStyles$1 = formStyles.input;
|
|
11597
11750
|
const errorTextStyles$1 = formStyles.error;
|
|
11598
|
-
function BookingForm({ config, eventDetails,
|
|
11751
|
+
function BookingForm({ config, eventDetails, onSuccess, onError, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], persistedState = null, onPersistedStateChange, }) {
|
|
11599
11752
|
const t$1 = useTranslations();
|
|
11600
11753
|
const { locale } = useLocale();
|
|
11601
11754
|
const timezone = useTimezone();
|
|
@@ -11795,7 +11948,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
11795
11948
|
newTotal: appliedDiscountCode.newTotal,
|
|
11796
11949
|
}
|
|
11797
11950
|
: null;
|
|
11798
|
-
const hasPaymentProvider =
|
|
11951
|
+
const hasPaymentProvider = systemConfig?.paymentProvider === "stripe" || systemConfig?.paymentProvider === "mollie";
|
|
11799
11952
|
const handleVoucherValidated = React.useCallback((voucher, _error) => {
|
|
11800
11953
|
if (voucher) {
|
|
11801
11954
|
setAppliedVouchers((prev) => [...prev, voucher]);
|
|
@@ -12061,7 +12214,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12061
12214
|
...inputStyles$1,
|
|
12062
12215
|
resize: "vertical",
|
|
12063
12216
|
minHeight: "80px",
|
|
12064
|
-
} })] })] })] })), checkoutStep === "payment" && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxRuntime.jsxs("div", { style: {
|
|
12217
|
+
} })] })] })] })), checkoutStep === "payment" && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsx(HoldCountdown, {}), jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxRuntime.jsxs("div", { style: {
|
|
12065
12218
|
color: "var(--bw-text-color)",
|
|
12066
12219
|
fontWeight: 500,
|
|
12067
12220
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -12165,7 +12318,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12165
12318
|
fontFamily: "var(--bw-font-family)",
|
|
12166
12319
|
marginTop: "8px",
|
|
12167
12320
|
textAlign: "right",
|
|
12168
|
-
}, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), depositsOnlyBlocked && (jsxRuntime.jsx("div", { style: cardStyles$1, children: jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.depositNotConfigured") }) })), !hasPaymentProvider && !depositsOnlyBlocked && (jsxRuntime.jsx("div", { style: cardStyles$1, children: jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && !depositsOnlyBlocked && (systemConfig?.paymentProvider === "mollie" ? (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.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 })] })) : (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null,
|
|
12321
|
+
}, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), depositsOnlyBlocked && (jsxRuntime.jsx("div", { style: cardStyles$1, children: jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.depositNotConfigured") }) })), !hasPaymentProvider && !depositsOnlyBlocked && (jsxRuntime.jsx("div", { style: cardStyles$1, children: jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && !depositsOnlyBlocked && (systemConfig?.paymentProvider === "mollie" ? (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.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 })] })) : (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.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() })] })))] }))] }) }));
|
|
12169
12322
|
}
|
|
12170
12323
|
|
|
12171
12324
|
/**
|
|
@@ -12846,19 +12999,21 @@ function EventTypeDetailsDialog({ isOpen, onClose, eventType, onEventTypeSelect,
|
|
|
12846
12999
|
textAlign: "right",
|
|
12847
13000
|
}, children: jsxRuntime.jsxs("span", { children: [t("common.from"), " ", formatCurrency(eventType.minPrice)] }) })] }), isAvailable && (jsxRuntime.jsxs("button", { onClick: handleBookingClick, style: {
|
|
12848
13001
|
backgroundColor: "var(--bw-highlight-color)",
|
|
12849
|
-
color: "#ffffff",
|
|
13002
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
12850
13003
|
padding: "14px 28px",
|
|
12851
13004
|
border: "none",
|
|
12852
13005
|
borderRadius: "var(--bw-border-radius)",
|
|
12853
13006
|
fontSize: "16px",
|
|
12854
13007
|
fontWeight: 600,
|
|
12855
13008
|
fontFamily: "var(--bw-font-family)",
|
|
13009
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
13010
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
12856
13011
|
display: "flex",
|
|
12857
13012
|
alignItems: "center",
|
|
12858
13013
|
gap: "8px",
|
|
12859
13014
|
cursor: "pointer",
|
|
12860
13015
|
transition: "all 0.2s ease",
|
|
12861
|
-
}, children: [jsxRuntime.jsx(IconWave, { size: 20, color: "
|
|
13016
|
+
}, children: [jsxRuntime.jsx(IconWave, { size: 20, color: "var(--bw-button-text-color, #ffffff)" }), t("button.bookNow")] }))] }), !isAvailable && (jsxRuntime.jsx("div", { style: {
|
|
12862
13017
|
position: "absolute",
|
|
12863
13018
|
inset: 0,
|
|
12864
13019
|
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
@@ -13272,6 +13427,8 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13272
13427
|
const [stripeAppearance, setStripeAppearance] = React.useState(null);
|
|
13273
13428
|
// Initialize Stripe
|
|
13274
13429
|
React.useEffect(() => {
|
|
13430
|
+
if (!isOpen)
|
|
13431
|
+
return;
|
|
13275
13432
|
if (paymentProvider !== "stripe")
|
|
13276
13433
|
return;
|
|
13277
13434
|
if (systemConfig?.stripePublishableKey && !stripePromise) {
|
|
@@ -13283,7 +13440,7 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13283
13440
|
}
|
|
13284
13441
|
setStripePromise(loadStripe(systemConfig.stripePublishableKey, stripeOptions));
|
|
13285
13442
|
}
|
|
13286
|
-
}, [paymentProvider, systemConfig, locale, stripePromise]);
|
|
13443
|
+
}, [isOpen, paymentProvider, systemConfig, locale, stripePromise]);
|
|
13287
13444
|
// Initialize Stripe appearance
|
|
13288
13445
|
React.useEffect(() => {
|
|
13289
13446
|
const container = document.querySelector(".booking-widget-container");
|
|
@@ -14144,15 +14301,15 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14144
14301
|
backgroundColor: isAvailable
|
|
14145
14302
|
? "var(--bw-success-color)"
|
|
14146
14303
|
: "var(--bw-error-color)",
|
|
14147
|
-
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), jsxRuntime.jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsxRuntime.jsx("div", { style: {
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14304
|
+
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), eventType.images && eventType.images.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsxRuntime.jsx("div", { style: {
|
|
14305
|
+
fontSize: "13px",
|
|
14306
|
+
color: "var(--bw-surface-color)",
|
|
14307
|
+
fontWeight: 600,
|
|
14308
|
+
backgroundColor: "var(--bw-highlight-color)",
|
|
14309
|
+
padding: "2px 8px",
|
|
14310
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14311
|
+
fontFamily: "var(--bw-font-family)",
|
|
14312
|
+
}, children: eventType.category.name }) }), jsxRuntime.jsx("div", { className: "event-type-img", style: { position: "relative", width: "100%", height: "300px" }, children: jsxRuntime.jsx(ImageCarousel, { images: eventType.images, eventName: eventType.name }) })] })), jsxRuntime.jsxs("div", { className: "event-type-content", style: {
|
|
14156
14313
|
padding: "12px 18px",
|
|
14157
14314
|
display: "flex",
|
|
14158
14315
|
flexDirection: "column",
|
|
@@ -14247,8 +14404,17 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14247
14404
|
if (!item)
|
|
14248
14405
|
return jsxRuntime.jsx("div", { style: { height: "34px" } }, i);
|
|
14249
14406
|
const hasDiscount = item.basePrice > 0 && item.price < item.basePrice;
|
|
14250
|
-
|
|
14251
|
-
|
|
14407
|
+
const isRowBookable = item.bookingOpen && item.availableSpots > 0;
|
|
14408
|
+
return (jsxRuntime.jsxs("div", { onClick: (e) => {
|
|
14409
|
+
e.stopPropagation();
|
|
14410
|
+
if (isRowBookable) {
|
|
14411
|
+
onInstancePreview?.(item.id, eventType.id);
|
|
14412
|
+
}
|
|
14413
|
+
}, onMouseEnter: (e) => {
|
|
14414
|
+
if (onInstancePreview && isRowBookable) {
|
|
14415
|
+
e.currentTarget.style.backgroundColor = "var(--bw-highlight-subtle)";
|
|
14416
|
+
}
|
|
14417
|
+
}, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = "transparent"; }, style: {
|
|
14252
14418
|
height: "34px",
|
|
14253
14419
|
display: "grid",
|
|
14254
14420
|
gridTemplateColumns: "auto 1fr auto 20px",
|
|
@@ -14257,12 +14423,13 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14257
14423
|
width: "100%",
|
|
14258
14424
|
fontSize: "13px",
|
|
14259
14425
|
color: "var(--bw-text-muted)",
|
|
14260
|
-
cursor: onInstancePreview ? "pointer" : "default",
|
|
14426
|
+
cursor: onInstancePreview && isRowBookable ? "pointer" : "default",
|
|
14261
14427
|
borderRadius: "4px",
|
|
14262
14428
|
padding: "0 2px",
|
|
14263
14429
|
transition: "background 0.15s",
|
|
14264
14430
|
boxSizing: "border-box",
|
|
14265
|
-
|
|
14431
|
+
opacity: isRowBookable ? 1 : 0.55,
|
|
14432
|
+
}, children: [jsxRuntime.jsxs("span", { style: { whiteSpace: "nowrap", display: "flex", alignItems: "center", gap: "3px" }, children: [item.isSpecial && (jsxRuntime.jsx("span", { style: { color: "var(--bw-highlight-color)", fontSize: "11px", lineHeight: 1 }, children: "\u2605" })), formatWeekday(item.startTime, timezone, locale), " ", formatDate(item.startTime, timezone, locale)] }), jsxRuntime.jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", opacity: 0.75 }, children: item.name }), jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: "4px", whiteSpace: "nowrap" }, children: [hasDiscount && (jsxRuntime.jsx("span", { style: { textDecoration: "line-through", opacity: 0.55, fontSize: "11px" }, children: formatCurrency(item.basePrice) })), jsxRuntime.jsx("span", { style: { fontWeight: 700, color: item.isSpecial ? "var(--bw-highlight-color)" : "var(--bw-text-color)" }, children: formatCurrency(item.price) })] }), item.isSpecial && item.specialDescription ? (jsxRuntime.jsx(InfoBadge, { text: item.specialDescription })) : (jsxRuntime.jsx("span", {}))] }, item.id));
|
|
14266
14433
|
}) }), hasMoreDates && (jsxRuntime.jsx("button", { type: "button", onClick: (e) => {
|
|
14267
14434
|
e.stopPropagation();
|
|
14268
14435
|
onEventTypeSelect(eventType);
|
|
@@ -14314,12 +14481,14 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14314
14481
|
transition: "all 0.2s ease",
|
|
14315
14482
|
}, children: t("button.moreDetails") })), isAvailable && (jsxRuntime.jsxs("div", { style: {
|
|
14316
14483
|
backgroundColor: "var(--bw-highlight-color)",
|
|
14317
|
-
color: "var(--bw-
|
|
14484
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
14318
14485
|
padding: "12px 14px",
|
|
14319
14486
|
borderRadius: "var(--bw-border-radius)",
|
|
14320
14487
|
fontSize: "clamp(1rem, 2vw, 16px)",
|
|
14321
14488
|
fontWeight: 600,
|
|
14322
14489
|
fontFamily: "var(--bw-font-family)",
|
|
14490
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
14491
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
14323
14492
|
display: "flex",
|
|
14324
14493
|
alignItems: "center",
|
|
14325
14494
|
justifyContent: "center",
|
|
@@ -14328,7 +14497,7 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14328
14497
|
border: "none",
|
|
14329
14498
|
cursor: "pointer",
|
|
14330
14499
|
transition: "all 0.2s ease",
|
|
14331
|
-
}, children: [jsxRuntime.jsx(IconWave, { size: 15, color: "var(--bw-
|
|
14500
|
+
}, children: [jsxRuntime.jsx(IconWave, { size: 15, color: "var(--bw-button-text-color, #ffffff)" }), " ", t("button.bookNow")] }))] })] })] }), showVoucherAttachment && onVoucherClick && (jsxRuntime.jsx(VoucherAttachment, { onClick: () => onVoucherClick(eventType.id) })), !isAvailable && (jsxRuntime.jsx("div", { style: {
|
|
14332
14501
|
position: "absolute",
|
|
14333
14502
|
inset: 0,
|
|
14334
14503
|
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
@@ -14349,6 +14518,74 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14349
14518
|
}) }) })), jsxRuntime.jsx(PaymentLogosStrip, {}), jsxRuntime.jsx(EventTypeDetailsDialog, { isOpen: detailsDialogOpen, onClose: handleCloseDetails, eventType: selectedEventTypeForDetails, onEventTypeSelect: onEventTypeSelect })] }));
|
|
14350
14519
|
}
|
|
14351
14520
|
|
|
14521
|
+
function WaitlistDialog({ apiBaseUrl, organizationId, eventInstanceId, eventName, onClose, }) {
|
|
14522
|
+
const t = useTranslations();
|
|
14523
|
+
const [name, setName] = React.useState("");
|
|
14524
|
+
const [email, setEmail] = React.useState("");
|
|
14525
|
+
const [phone, setPhone] = React.useState("");
|
|
14526
|
+
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
14527
|
+
const [error, setError] = React.useState(null);
|
|
14528
|
+
const [position, setPosition] = React.useState(null);
|
|
14529
|
+
const handleSubmit = async () => {
|
|
14530
|
+
setError(null);
|
|
14531
|
+
if (!name.trim() || !email.trim()) {
|
|
14532
|
+
setError(t("waitlist.requiredFields"));
|
|
14533
|
+
return;
|
|
14534
|
+
}
|
|
14535
|
+
setIsSubmitting(true);
|
|
14536
|
+
try {
|
|
14537
|
+
const response = await fetch(getApiUrl(apiBaseUrl, "/booking/waitlist"), {
|
|
14538
|
+
method: "POST",
|
|
14539
|
+
headers: { "Content-Type": "application/json" },
|
|
14540
|
+
body: JSON.stringify({
|
|
14541
|
+
organizationId,
|
|
14542
|
+
eventInstanceId,
|
|
14543
|
+
name: name.trim(),
|
|
14544
|
+
email: email.trim(),
|
|
14545
|
+
phone: phone.trim() || undefined,
|
|
14546
|
+
}),
|
|
14547
|
+
});
|
|
14548
|
+
if (!response.ok) {
|
|
14549
|
+
throw new Error("request_failed");
|
|
14550
|
+
}
|
|
14551
|
+
const data = (await response.json());
|
|
14552
|
+
setPosition(data.position ?? null);
|
|
14553
|
+
}
|
|
14554
|
+
catch {
|
|
14555
|
+
setError(t("waitlist.submitError"));
|
|
14556
|
+
}
|
|
14557
|
+
finally {
|
|
14558
|
+
setIsSubmitting(false);
|
|
14559
|
+
}
|
|
14560
|
+
};
|
|
14561
|
+
return (jsxRuntime.jsx("div", { style: {
|
|
14562
|
+
position: "fixed",
|
|
14563
|
+
inset: 0,
|
|
14564
|
+
zIndex: 1000,
|
|
14565
|
+
display: "flex",
|
|
14566
|
+
alignItems: "center",
|
|
14567
|
+
justifyContent: "center",
|
|
14568
|
+
backgroundColor: "rgba(15, 23, 42, 0.6)",
|
|
14569
|
+
padding: "16px",
|
|
14570
|
+
fontFamily: "var(--bw-font-family)",
|
|
14571
|
+
}, onClick: onClose, children: jsxRuntime.jsx("div", { style: {
|
|
14572
|
+
width: "100%",
|
|
14573
|
+
maxWidth: "420px",
|
|
14574
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
14575
|
+
border: "1px solid var(--bw-border-color)",
|
|
14576
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14577
|
+
padding: "24px",
|
|
14578
|
+
}, onClick: (e) => e.stopPropagation(), children: position !== null ? (jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [jsxRuntime.jsx("h3", { style: {
|
|
14579
|
+
margin: "0 0 8px",
|
|
14580
|
+
color: "var(--bw-highlight-color)",
|
|
14581
|
+
fontSize: "18px",
|
|
14582
|
+
}, children: t("waitlist.successTitle") }), jsxRuntime.jsx("p", { style: mergeStyles(textStyles.body, { marginBottom: "20px" }), children: t("waitlist.successMessage", { position }) }), jsxRuntime.jsx("button", { type: "button", style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), onClick: onClose, children: t("waitlist.done") })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h3", { style: {
|
|
14583
|
+
margin: "0 0 4px",
|
|
14584
|
+
color: "var(--bw-highlight-color)",
|
|
14585
|
+
fontSize: "18px",
|
|
14586
|
+
}, children: t("waitlist.title") }), jsxRuntime.jsx("p", { style: mergeStyles(textStyles.muted, { marginBottom: "16px" }), children: t("waitlist.subtitle", { name: eventName }) }), jsxRuntime.jsxs("div", { style: { marginBottom: "12px" }, children: [jsxRuntime.jsx("label", { style: formStyles.label, htmlFor: "wl-name", children: t("waitlist.name") }), jsxRuntime.jsx("input", { id: "wl-name", style: formStyles.input, value: name, onChange: (e) => setName(e.target.value) })] }), jsxRuntime.jsxs("div", { style: { marginBottom: "12px" }, children: [jsxRuntime.jsx("label", { style: formStyles.label, htmlFor: "wl-email", children: t("waitlist.email") }), jsxRuntime.jsx("input", { id: "wl-email", type: "email", style: formStyles.input, value: email, onChange: (e) => setEmail(e.target.value) })] }), jsxRuntime.jsxs("div", { style: { marginBottom: "12px" }, children: [jsxRuntime.jsx("label", { style: formStyles.label, htmlFor: "wl-phone", children: t("waitlist.phone") }), jsxRuntime.jsx("input", { id: "wl-phone", type: "tel", style: formStyles.input, value: phone, onChange: (e) => setPhone(e.target.value) })] }), error && jsxRuntime.jsx("p", { style: formStyles.error, children: error }), jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px", marginTop: "16px" }, children: [jsxRuntime.jsx("button", { type: "button", style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), onClick: onClose, disabled: isSubmitting, children: t("waitlist.cancel") }), jsxRuntime.jsx("button", { type: "button", style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), onClick: handleSubmit, disabled: isSubmitting, children: isSubmitting ? t("waitlist.submitting") : t("waitlist.join") })] })] })) }) }));
|
|
14587
|
+
}
|
|
14588
|
+
|
|
14352
14589
|
const getAllocationBadgeInfo = (availableSpots, maxParticipants, t) => {
|
|
14353
14590
|
const availabilityRatio = availableSpots / maxParticipants;
|
|
14354
14591
|
if (availabilityRatio >= 0.6)
|
|
@@ -14473,12 +14710,13 @@ const PriceDisplay = ({ price, yearPrices, t }) => {
|
|
|
14473
14710
|
boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
|
|
14474
14711
|
}, children: formatCurrency(price) }));
|
|
14475
14712
|
};
|
|
14476
|
-
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, }) {
|
|
14713
|
+
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, }) {
|
|
14477
14714
|
const t = useTranslations();
|
|
14478
14715
|
const { locale } = useLocale();
|
|
14479
14716
|
const timezone = useTimezone();
|
|
14480
14717
|
const [selectedEventInstanceId, setSelectedEventInstanceId] = React.useState(null);
|
|
14481
14718
|
const [openGroups, setOpenGroups] = React.useState(new Set());
|
|
14719
|
+
const [waitlistEvent, setWaitlistEvent] = React.useState(null);
|
|
14482
14720
|
const getMonthPriceDisplayInfo = (minPrice) => {
|
|
14483
14721
|
return getPriceDisplayInfo(minPrice, yearPrices, t);
|
|
14484
14722
|
};
|
|
@@ -14639,119 +14877,130 @@ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInst
|
|
|
14639
14877
|
fontFamily: "var(--bw-font-family)",
|
|
14640
14878
|
}, children: t("instances.noAvailable") }), jsxRuntime.jsx("p", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t("instances.noAvailableMessage") })] }) }) }));
|
|
14641
14879
|
}
|
|
14642
|
-
return (jsxRuntime.
|
|
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
|
-
|
|
14732
|
-
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14880
|
+
return (jsxRuntime.jsxs(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `${selectedEventType?.name}`, footer: footerNav, children: [jsxRuntime.jsxs("div", { style: { padding: "20px 10px" }, children: [jsxRuntime.jsx(FlowProgress, { currentStep: "date", hasUpsellsStep: hasUpsellsStep }), jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: monthYearGroups.map(({ key, label, events, minPrice, year }, idx) => {
|
|
14881
|
+
const monthPriceDisplayInfo = getMonthPriceDisplayInfo(minPrice);
|
|
14882
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [idx > 0 && monthYearGroups[idx - 1].year !== year && (jsxRuntime.jsx("div", { style: { height: "1px", backgroundColor: "var(--bw-border-color)", margin: "4px 0" } })), jsxRuntime.jsx(Accordion, { title: label, priceInfo: jsxRuntime.jsx("div", { style: {
|
|
14883
|
+
fontSize: "16px",
|
|
14884
|
+
fontWeight: 500,
|
|
14885
|
+
marginLeft: "auto",
|
|
14886
|
+
padding: "4px 8px",
|
|
14887
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14888
|
+
backgroundColor: monthPriceDisplayInfo
|
|
14889
|
+
? monthPriceDisplayInfo.backgroundColor
|
|
14890
|
+
: "#14532d",
|
|
14891
|
+
color: monthPriceDisplayInfo
|
|
14892
|
+
? monthPriceDisplayInfo.textColor
|
|
14893
|
+
: "#4ade80",
|
|
14894
|
+
boxShadow: monthPriceDisplayInfo
|
|
14895
|
+
? "0 2px 4px rgba(0, 0, 0, 0.2)"
|
|
14896
|
+
: undefined,
|
|
14897
|
+
}, children: `${t("common.from")} ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", paddingTop: "12px" }, children: events.map((event) => {
|
|
14898
|
+
const availableSpots = event.maxParticipants - event.participantCount;
|
|
14899
|
+
const isFullyBooked = availableSpots === 0;
|
|
14900
|
+
const startDate = new Date(event.startTime);
|
|
14901
|
+
const isPastEvent = today.toISOString() >= startDate.toISOString();
|
|
14902
|
+
const isDisabled = isFullyBooked || isPastEvent || !event.bookingOpen;
|
|
14903
|
+
const canWaitlist = isFullyBooked &&
|
|
14904
|
+
!isPastEvent &&
|
|
14905
|
+
!!apiBaseUrl &&
|
|
14906
|
+
!!organizationId;
|
|
14907
|
+
return (jsxRuntime.jsxs("div", { style: {
|
|
14908
|
+
position: "relative",
|
|
14909
|
+
border: "1px solid var(--bw-border-color)",
|
|
14910
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
14911
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14912
|
+
padding: "16px 10px",
|
|
14913
|
+
transition: "all 0.2s ease",
|
|
14914
|
+
fontFamily: "var(--bw-font-family)",
|
|
14915
|
+
opacity: isDisabled && !canWaitlist ? 0.3 : 1,
|
|
14916
|
+
filter: isDisabled && !canWaitlist ? "grayscale(40%)" : "none",
|
|
14917
|
+
cursor: isDisabled
|
|
14918
|
+
? canWaitlist
|
|
14919
|
+
? "default"
|
|
14920
|
+
: "not-allowed"
|
|
14921
|
+
: "pointer",
|
|
14922
|
+
}, onClick: () => {
|
|
14923
|
+
if (!isDisabled) {
|
|
14924
|
+
handleEventInstanceSelect(event);
|
|
14925
|
+
}
|
|
14926
|
+
}, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (jsxRuntime.jsx("div", { style: {
|
|
14927
|
+
position: "absolute",
|
|
14928
|
+
inset: 0,
|
|
14929
|
+
backgroundColor: "rgba(15, 23, 42, 0.8)",
|
|
14930
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14931
|
+
display: "flex",
|
|
14932
|
+
alignItems: "center",
|
|
14933
|
+
justifyContent: "center",
|
|
14934
|
+
}, children: jsxRuntime.jsx("div", { style: {
|
|
14935
|
+
width: "32px",
|
|
14936
|
+
height: "32px",
|
|
14937
|
+
color: "var(--bw-highlight-color)",
|
|
14938
|
+
opacity: 0.8,
|
|
14939
|
+
fontSize: "32px",
|
|
14940
|
+
}, children: spinner() }) })), jsxRuntime.jsx(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), jsxRuntime.jsx(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants, t: t }), jsxRuntime.jsxs("div", { style: {
|
|
14941
|
+
display: "flex",
|
|
14942
|
+
justifyContent: "space-between",
|
|
14943
|
+
width: "100%",
|
|
14944
|
+
alignItems: "flex-start",
|
|
14945
|
+
gap: "12px",
|
|
14946
|
+
marginBottom: "4px",
|
|
14947
|
+
}, children: [jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsxRuntime.jsx("div", { style: {
|
|
14948
|
+
fontSize: "16px",
|
|
14949
|
+
transition: "all 0.2s ease",
|
|
14950
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14951
|
+
borderTop: "4px solid var(--bw-border-color)",
|
|
14952
|
+
border: "1px solid var(--bw-border-color)",
|
|
14953
|
+
width: "40px",
|
|
14954
|
+
height: "40px",
|
|
14955
|
+
display: "flex",
|
|
14956
|
+
alignItems: "center",
|
|
14957
|
+
justifyContent: "center",
|
|
14958
|
+
fontWeight: 700,
|
|
14959
|
+
color: "var(--bw-text-color)",
|
|
14960
|
+
backgroundColor: "var(--bw-background-color)",
|
|
14961
|
+
}, children: startDate.getDate() }), jsxRuntime.jsxs("div", { style: {
|
|
14962
|
+
fontSize: "16px",
|
|
14963
|
+
color: "var(--bw-text-color)",
|
|
14964
|
+
display: "flex",
|
|
14965
|
+
flexDirection: "column",
|
|
14966
|
+
alignItems: "flex-start",
|
|
14967
|
+
justifyContent: "flex-start",
|
|
14968
|
+
lineHeight: 1.25,
|
|
14969
|
+
}, children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { style: { fontWeight: 600, marginBottom: "2px", textTransform: "capitalize" }, children: formatWeekday(event.startTime, timezone, locale) }), formatWeekday(event.startTime, timezone, locale) !==
|
|
14970
|
+
formatWeekday(event.endTime, timezone, locale) && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), jsxRuntime.jsx("span", { style: { fontWeight: 600, marginBottom: "2px", textTransform: "capitalize" }, children: formatWeekday(event.endTime, timezone, locale) })] }))] }), jsxRuntime.jsx("div", { children: formatWeekday(event.startTime, timezone, locale) ===
|
|
14971
|
+
formatWeekday(event.endTime, timezone, locale) ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.startTime, timezone, locale) }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.endTime, timezone, locale) })] })) : (jsxRuntime.jsxs("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: [formatTime(event.startTime, timezone, locale), " ", t("instances.oclock")] })) })] }), jsxRuntime.jsxs("span", { style: {
|
|
14972
|
+
fontSize: "12px",
|
|
14973
|
+
fontWeight: 400,
|
|
14974
|
+
color: "var(--bw-text-muted)",
|
|
14975
|
+
marginLeft: "6px",
|
|
14976
|
+
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
|
14977
|
+
whiteSpace: "nowrap",
|
|
14978
|
+
padding: "2px 6px",
|
|
14979
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14980
|
+
}, children: [event.durationDays, " ", event.durationDays > 1 ? t("common.days") : t("common.day")] })] }), jsxRuntime.jsx("div", { style: {
|
|
14981
|
+
textAlign: "right",
|
|
14982
|
+
display: "flex",
|
|
14983
|
+
flexDirection: "column",
|
|
14984
|
+
alignItems: "flex-end",
|
|
14985
|
+
}, children: jsxRuntime.jsx(PriceDisplay, { price: event.price, yearPrices: yearPrices, t: t }) })] }), event.name !== selectedEventType?.name && (jsxRuntime.jsx("h4", { style: {
|
|
14986
|
+
fontSize: "16px",
|
|
14987
|
+
fontWeight: 600,
|
|
14988
|
+
color: "var(--bw-text-color)",
|
|
14989
|
+
lineHeight: 1.25,
|
|
14990
|
+
margin: "0 0 2px 0",
|
|
14991
|
+
display: "flex",
|
|
14992
|
+
alignItems: "center",
|
|
14993
|
+
gap: "8px",
|
|
14994
|
+
maxWidth: "230px",
|
|
14995
|
+
}, children: event.name })), canWaitlist && (jsxRuntime.jsx("button", { type: "button", style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth, buttonStyles.small, { marginTop: "8px" }), onClick: (e) => {
|
|
14996
|
+
e.stopPropagation();
|
|
14997
|
+
setWaitlistEvent(event);
|
|
14998
|
+
}, children: t("waitlist.joinCta") }))] }, event.id));
|
|
14999
|
+
}) }) })] }, key));
|
|
15000
|
+
}) })] }), waitlistEvent && apiBaseUrl && organizationId && (jsxRuntime.jsx(WaitlistDialog, { apiBaseUrl: apiBaseUrl, organizationId: organizationId, eventInstanceId: waitlistEvent.id, eventName: waitlistEvent.name, onClose: () => setWaitlistEvent(null) }))] }));
|
|
14752
15001
|
}
|
|
14753
15002
|
|
|
14754
|
-
function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText, showAllButton, isLoadingEventDetails = false, isLoadingShowAll = false, isLoading = false, }) {
|
|
15003
|
+
function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText, showAllButton, isLoadingEventDetails = false, isLoadingShowAll = false, isLoading = false, count = 3, }) {
|
|
14755
15004
|
const t = useTranslations();
|
|
14756
15005
|
const { locale } = useLocale();
|
|
14757
15006
|
const timezone = useTimezone();
|
|
@@ -14803,7 +15052,7 @@ function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText
|
|
|
14803
15052
|
};
|
|
14804
15053
|
// Show loading skeleton
|
|
14805
15054
|
if (isLoading) {
|
|
14806
|
-
return jsxRuntime.jsx(NextEventsSkeleton, { count:
|
|
15055
|
+
return jsxRuntime.jsx(NextEventsSkeleton, { count: count });
|
|
14807
15056
|
}
|
|
14808
15057
|
if (events.length === 0) {
|
|
14809
15058
|
return (jsxRuntime.jsx("div", { style: { maxWidth: "500px", margin: "0 auto", padding: "16px" }, children: jsxRuntime.jsxs("div", { style: {
|
|
@@ -15642,6 +15891,7 @@ let buffer = [];
|
|
|
15642
15891
|
let flushTimer = null;
|
|
15643
15892
|
let currentApiBaseUrl = "";
|
|
15644
15893
|
let currentOrganizationId = "";
|
|
15894
|
+
let currentPartnerContractId = null;
|
|
15645
15895
|
const FLUSH_INTERVAL_MS = 3000;
|
|
15646
15896
|
function flush() {
|
|
15647
15897
|
if (buffer.length === 0)
|
|
@@ -15683,9 +15933,10 @@ function scheduleFlush() {
|
|
|
15683
15933
|
/**
|
|
15684
15934
|
* Initialise the analytics module. Must be called once before `trackEvent`.
|
|
15685
15935
|
*/
|
|
15686
|
-
function initAnalytics(apiBaseUrl, organizationId) {
|
|
15936
|
+
function initAnalytics(apiBaseUrl, organizationId, options) {
|
|
15687
15937
|
currentApiBaseUrl = apiBaseUrl;
|
|
15688
15938
|
currentOrganizationId = organizationId;
|
|
15939
|
+
currentPartnerContractId = options?.partnerContractId?.trim() || null;
|
|
15689
15940
|
if (typeof window !== "undefined") {
|
|
15690
15941
|
window.addEventListener("pagehide", flush);
|
|
15691
15942
|
window.addEventListener("visibilitychange", () => {
|
|
@@ -15702,9 +15953,12 @@ function trackEvent(event, properties = {}) {
|
|
|
15702
15953
|
return;
|
|
15703
15954
|
if (!currentOrganizationId)
|
|
15704
15955
|
return;
|
|
15956
|
+
const mergedProperties = currentPartnerContractId
|
|
15957
|
+
? { ...properties, partnerContractId: currentPartnerContractId }
|
|
15958
|
+
: properties;
|
|
15705
15959
|
buffer.push({
|
|
15706
15960
|
event,
|
|
15707
|
-
properties,
|
|
15961
|
+
properties: mergedProperties,
|
|
15708
15962
|
domain: window.location.hostname,
|
|
15709
15963
|
url: window.location.href,
|
|
15710
15964
|
referrer: document.referrer,
|
|
@@ -15780,7 +16034,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15780
16034
|
const [sidebarOpen, setSidebarOpen] = React.useState(false);
|
|
15781
16035
|
// Booking flow state
|
|
15782
16036
|
const [eventDetails, setEventDetails] = React.useState(null);
|
|
15783
|
-
const [stripePromise, setStripePromise] = React.useState(null);
|
|
15784
16037
|
// SEPARATED LOADING STATES
|
|
15785
16038
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
15786
16039
|
const [isLoadingEventInstances, setIsLoadingEventInstances] = React.useState(false);
|
|
@@ -15915,7 +16168,9 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15915
16168
|
React.useEffect(() => {
|
|
15916
16169
|
if (!analyticsInitRef.current && config.organizationId) {
|
|
15917
16170
|
analyticsInitRef.current = true;
|
|
15918
|
-
initAnalytics(config.apiBaseUrl, config.organizationId
|
|
16171
|
+
initAnalytics(config.apiBaseUrl, config.organizationId, {
|
|
16172
|
+
partnerContractId: config.partnerContractId,
|
|
16173
|
+
});
|
|
15919
16174
|
trackEvent("widget_loaded", {
|
|
15920
16175
|
viewMode,
|
|
15921
16176
|
eventTypeId: config.eventTypeId,
|
|
@@ -15924,7 +16179,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15924
16179
|
isStandaloneVoucherMode,
|
|
15925
16180
|
});
|
|
15926
16181
|
}
|
|
15927
|
-
}, [config.organizationId, config.apiBaseUrl]);
|
|
16182
|
+
}, [config.organizationId, config.apiBaseUrl, config.partnerContractId, viewMode, config.eventTypeId, config.categoryId, config.eventInstanceId, isStandaloneVoucherMode]);
|
|
15928
16183
|
// Fire widget pageview once when Google Ads config is received from API
|
|
15929
16184
|
const pageviewFiredRef = React.useRef(false);
|
|
15930
16185
|
React.useEffect(() => {
|
|
@@ -15938,6 +16193,23 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15938
16193
|
const initializeWidget = async () => {
|
|
15939
16194
|
try {
|
|
15940
16195
|
setIsLoading(true);
|
|
16196
|
+
if (config.partnerContractId) {
|
|
16197
|
+
const validationResponse = await fetch(getApiUrl(config.apiBaseUrl, `/booking/validate-partner?organizationId=${encodeURIComponent(config.organizationId)}&contractId=${config.partnerContractId}`), {
|
|
16198
|
+
method: "GET",
|
|
16199
|
+
headers: createApiHeaders(config, locale),
|
|
16200
|
+
});
|
|
16201
|
+
if (!validationResponse.ok) {
|
|
16202
|
+
setError("Invalid partner configuration");
|
|
16203
|
+
config.onError?.("Invalid partner configuration");
|
|
16204
|
+
return;
|
|
16205
|
+
}
|
|
16206
|
+
const validationData = (await validationResponse.json());
|
|
16207
|
+
if (!validationData.valid) {
|
|
16208
|
+
setError("Invalid partner configuration");
|
|
16209
|
+
config.onError?.("Invalid partner configuration");
|
|
16210
|
+
return;
|
|
16211
|
+
}
|
|
16212
|
+
}
|
|
15941
16213
|
// Load voucher config in parallel if voucher mode is requested or there's event selection
|
|
15942
16214
|
if (isVoucherModeRequested || hasEventSelection) {
|
|
15943
16215
|
void loadVoucherConfig();
|
|
@@ -16073,11 +16345,18 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16073
16345
|
setVoucherPurchaseResult(voucherData.voucherResult);
|
|
16074
16346
|
setIsSuccess(true);
|
|
16075
16347
|
setSuccessPaymentId(null);
|
|
16348
|
+
return;
|
|
16076
16349
|
}
|
|
16077
16350
|
}
|
|
16078
16351
|
catch {
|
|
16079
|
-
//
|
|
16080
|
-
}
|
|
16352
|
+
// Fall back to booking success flow if voucher lookup fails.
|
|
16353
|
+
}
|
|
16354
|
+
// Not a voucher purchase: treat as a booking return and open the
|
|
16355
|
+
// booking confirmation, mirroring the Stripe redirect handler.
|
|
16356
|
+
trackEvent("booking_completed", { paymentIntentId: mollieReturn.molliePaymentId, source: "mollie_redirect" });
|
|
16357
|
+
setVoucherPurchaseResult(null);
|
|
16358
|
+
setSuccessPaymentId(mollieReturn.molliePaymentId);
|
|
16359
|
+
setIsSuccess(true);
|
|
16081
16360
|
};
|
|
16082
16361
|
if (!isLoading) {
|
|
16083
16362
|
void handleMollieVoucherReturn();
|
|
@@ -16266,27 +16545,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16266
16545
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16267
16546
|
});
|
|
16268
16547
|
}
|
|
16269
|
-
if (data.stripePublishableKey) {
|
|
16270
|
-
const stripeOptions = {
|
|
16271
|
-
locale: locale,
|
|
16272
|
-
};
|
|
16273
|
-
if (data.connectedAccountId) {
|
|
16274
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16275
|
-
}
|
|
16276
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16277
|
-
try {
|
|
16278
|
-
void (window.parent === window || window.parent.location.href);
|
|
16279
|
-
if (!stripeOptions.betas) {
|
|
16280
|
-
stripeOptions.betas = [];
|
|
16281
|
-
}
|
|
16282
|
-
}
|
|
16283
|
-
catch {
|
|
16284
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16285
|
-
stripeOptions.betas = [];
|
|
16286
|
-
}
|
|
16287
|
-
}
|
|
16288
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16289
|
-
}
|
|
16290
16548
|
if (!skipInstanceAutoSelectRef.current && data.eventInstances.length === 1) {
|
|
16291
16549
|
setSelectedEventInstance(data.eventInstances[0]);
|
|
16292
16550
|
setCurrentStep("booking");
|
|
@@ -16326,29 +16584,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16326
16584
|
roundPricesEnabled: data.roundPricesEnabled ?? true,
|
|
16327
16585
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16328
16586
|
});
|
|
16329
|
-
if (!stripePromise && data.stripePublishableKey) {
|
|
16330
|
-
const stripeOptions = {
|
|
16331
|
-
locale: locale,
|
|
16332
|
-
};
|
|
16333
|
-
if (data.connectedAccountId) {
|
|
16334
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16335
|
-
}
|
|
16336
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16337
|
-
try {
|
|
16338
|
-
// Check if we have parent access (not in a cross-origin iframe)
|
|
16339
|
-
void (window.parent === window || window.parent.location.href);
|
|
16340
|
-
stripeOptions.apiVersion = "2025-02-24.acacia";
|
|
16341
|
-
if (!stripeOptions.betas) {
|
|
16342
|
-
stripeOptions.betas = [];
|
|
16343
|
-
}
|
|
16344
|
-
}
|
|
16345
|
-
catch {
|
|
16346
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16347
|
-
stripeOptions.betas = [];
|
|
16348
|
-
}
|
|
16349
|
-
}
|
|
16350
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16351
|
-
}
|
|
16352
16587
|
}
|
|
16353
16588
|
else {
|
|
16354
16589
|
const errorMessage = data.error || t("error.loadEventDetails");
|
|
@@ -16617,12 +16852,12 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16617
16852
|
startTime: cardPreviewItem.startTime,
|
|
16618
16853
|
endTime: cardPreviewItem.startTime,
|
|
16619
16854
|
price: cardPreviewItem.price,
|
|
16620
|
-
maxParticipants: cardPreviewItem.availableSpots
|
|
16621
|
-
participantCount:
|
|
16855
|
+
maxParticipants: Math.max(cardPreviewItem.availableSpots, 0),
|
|
16856
|
+
participantCount: 0,
|
|
16622
16857
|
availableSpots: cardPreviewItem.availableSpots,
|
|
16623
16858
|
durationDays: 1,
|
|
16624
16859
|
durationPerDay: 1,
|
|
16625
|
-
bookingOpen:
|
|
16860
|
+
bookingOpen: cardPreviewItem.bookingOpen && cardPreviewItem.availableSpots > 0,
|
|
16626
16861
|
}
|
|
16627
16862
|
: null;
|
|
16628
16863
|
if (eventInstance) {
|
|
@@ -16810,7 +17045,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16810
17045
|
}
|
|
16811
17046
|
// Main view based on view mode
|
|
16812
17047
|
if (viewMode === "next-events" && showingPreview) {
|
|
16813
|
-
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17048
|
+
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.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 && (jsxRuntime.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 })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16814
17049
|
setIsSuccess(false);
|
|
16815
17050
|
setCurrentStep("eventTypes");
|
|
16816
17051
|
setShowingPreview(true);
|
|
@@ -16831,7 +17066,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16831
17066
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16832
17067
|
}
|
|
16833
17068
|
if (viewMode === "specials" && showingPreview) {
|
|
16834
|
-
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17069
|
+
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsxRuntime.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 })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16835
17070
|
setIsSuccess(false);
|
|
16836
17071
|
setCurrentStep("eventTypes");
|
|
16837
17072
|
setShowingPreview(true);
|
|
@@ -16845,13 +17080,13 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16845
17080
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16846
17081
|
}
|
|
16847
17082
|
if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
|
|
16848
|
-
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
|
|
17083
|
+
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading, count: nextEventsSettings.count }), shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
|
|
16849
17084
|
setShowingPreview(true);
|
|
16850
17085
|
setCurrentStep("eventTypes");
|
|
16851
17086
|
}, isOpen: currentStep === "eventInstances", onClose: () => {
|
|
16852
17087
|
setShowingPreview(true);
|
|
16853
17088
|
setCurrentStep("eventTypes");
|
|
16854
|
-
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
17089
|
+
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16855
17090
|
setIsSuccess(false);
|
|
16856
17091
|
setCurrentStep("eventTypes");
|
|
16857
17092
|
setShowingPreview(true);
|
|
@@ -16868,8 +17103,11 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16868
17103
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16869
17104
|
}
|
|
16870
17105
|
if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
|
|
17106
|
+
// Busy only while genuinely loading. Note: we intentionally do NOT key off
|
|
17107
|
+
// `shouldRenderInstanceSelection && !sidebarOpen` — that flag stays true after the
|
|
17108
|
+
// sidebar is closed (only `sidebarOpen` resets), which left the spinner stuck on.
|
|
16871
17109
|
const isButtonBusy = (isDirectInstanceMode && isLoadingEventDetails) ||
|
|
16872
|
-
(!isDirectInstanceMode &&
|
|
17110
|
+
(!isDirectInstanceMode && isLoadingEventInstances);
|
|
16873
17111
|
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, style: {
|
|
16874
17112
|
display: "flex",
|
|
16875
17113
|
justifyContent: "center",
|
|
@@ -16880,13 +17118,15 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16880
17118
|
alignItems: "center",
|
|
16881
17119
|
gap: "10px",
|
|
16882
17120
|
backgroundColor: "var(--bw-highlight-color)",
|
|
16883
|
-
color: "
|
|
17121
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
16884
17122
|
padding: "16px 32px",
|
|
16885
17123
|
border: "none",
|
|
16886
17124
|
borderRadius: "var(--bw-border-radius)",
|
|
16887
17125
|
fontSize: "18px",
|
|
16888
17126
|
fontWeight: 600,
|
|
16889
17127
|
fontFamily: "var(--bw-font-family)",
|
|
17128
|
+
textTransform: "var(--bw-text-transform, none)",
|
|
17129
|
+
letterSpacing: "var(--bw-letter-spacing, normal)",
|
|
16890
17130
|
boxShadow: "var(--bw-shadow-md)",
|
|
16891
17131
|
cursor: isButtonBusy ? "default" : "pointer",
|
|
16892
17132
|
opacity: isButtonBusy ? 0.85 : 1,
|
|
@@ -16901,8 +17141,8 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16901
17141
|
setSidebarOpen(true);
|
|
16902
17142
|
setShouldRenderInstanceSelection(true);
|
|
16903
17143
|
}
|
|
16904
|
-
}, children: [isButtonBusy && jsxRuntime.jsx(Spinner, { size: 20, borderColor: "
|
|
16905
|
-
(isDirectInstanceMode ? t("button.bookNow") : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsxRuntime.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 && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17144
|
+
}, children: [isButtonBusy && jsxRuntime.jsx(Spinner, { size: 20, borderColor: "var(--bw-button-text-color, #ffffff)" }), config.buttonText ||
|
|
17145
|
+
(isDirectInstanceMode ? t("button.bookNow") : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsxRuntime.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 && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.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 })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
16906
17146
|
setIsSuccess(false);
|
|
16907
17147
|
setCurrentStep("eventTypes");
|
|
16908
17148
|
setSidebarOpen(false);
|
|
@@ -16963,7 +17203,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16963
17203
|
};
|
|
16964
17204
|
};
|
|
16965
17205
|
const backHandlers = getBackHandlers();
|
|
16966
|
-
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails,
|
|
17206
|
+
return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsxRuntime.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 && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.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 })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
|
|
16967
17207
|
setIsSuccess(false);
|
|
16968
17208
|
setCurrentStep("eventTypes");
|
|
16969
17209
|
setSuccessPaymentId(null);
|
|
@@ -17027,7 +17267,7 @@ function styleInject(css, ref) {
|
|
|
17027
17267
|
}
|
|
17028
17268
|
}
|
|
17029
17269
|
|
|
17030
|
-
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}}";
|
|
17270
|
+
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}}";
|
|
17031
17271
|
styleInject(css_248z);
|
|
17032
17272
|
|
|
17033
17273
|
// Export init function for vanilla JS usage
|