@bigz-app/booking-widget 1.4.4 → 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 -17103
- package/dist/booking-widget.js.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/WaitlistDialog.d.ts +10 -0
- package/dist/components/events/WaitlistDialog.d.ts.map +1 -0
- 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 +561 -359
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +548 -346
- package/dist/index.esm.js.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",
|
|
@@ -2262,6 +2134,7 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2262
2134
|
const categoryId = urlParams.get("categoryId") || urlParams.get("category");
|
|
2263
2135
|
const eventTypeId = urlParams.get("eventTypeId") || urlParams.get("type");
|
|
2264
2136
|
const eventTypeIds = urlParams.get("eventTypeIds") || urlParams.get("types");
|
|
2137
|
+
const partnerContractId = urlParams.get("partnerContractId") || urlParams.get("contractId");
|
|
2265
2138
|
const voucherValue = urlParams.get("voucherValue");
|
|
2266
2139
|
const voucherCategory = urlParams.get("voucherCategory");
|
|
2267
2140
|
const voucherEventType = urlParams.get("voucherEventType");
|
|
@@ -2274,11 +2147,14 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2274
2147
|
: ["0", "false", "no", "off"].includes(voucherCardIntegration.toLowerCase())
|
|
2275
2148
|
? false
|
|
2276
2149
|
: undefined;
|
|
2277
|
-
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;
|
|
2278
2151
|
if (eventInstanceId && !Number.isNaN(Number(eventInstanceId))) {
|
|
2279
2152
|
return {
|
|
2280
2153
|
...omitSelectionKeys(baseConfig),
|
|
2281
2154
|
eventInstanceId: Number(eventInstanceId),
|
|
2155
|
+
...(partnerContractId
|
|
2156
|
+
? { partnerContractId }
|
|
2157
|
+
: {}),
|
|
2282
2158
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2283
2159
|
};
|
|
2284
2160
|
}
|
|
@@ -2286,6 +2162,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2286
2162
|
return {
|
|
2287
2163
|
...omitSelectionKeys(baseConfig),
|
|
2288
2164
|
categoryId: Number(categoryId),
|
|
2165
|
+
...(partnerContractId
|
|
2166
|
+
? { partnerContractId }
|
|
2167
|
+
: {}),
|
|
2289
2168
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2290
2169
|
};
|
|
2291
2170
|
}
|
|
@@ -2293,6 +2172,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2293
2172
|
return {
|
|
2294
2173
|
...omitSelectionKeys(baseConfig),
|
|
2295
2174
|
eventTypeId: Number(eventTypeId),
|
|
2175
|
+
...(partnerContractId
|
|
2176
|
+
? { partnerContractId }
|
|
2177
|
+
: {}),
|
|
2296
2178
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2297
2179
|
};
|
|
2298
2180
|
}
|
|
@@ -2305,6 +2187,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2305
2187
|
return {
|
|
2306
2188
|
...omitSelectionKeys(baseConfig),
|
|
2307
2189
|
eventTypeIds: typeIds,
|
|
2190
|
+
...(partnerContractId
|
|
2191
|
+
? { partnerContractId }
|
|
2192
|
+
: {}),
|
|
2308
2193
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2309
2194
|
};
|
|
2310
2195
|
}
|
|
@@ -2321,6 +2206,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2321
2206
|
if (parsedVoucherValues.length || parsedVoucherCategories.length || parsedVoucherEventTypes.length) {
|
|
2322
2207
|
return {
|
|
2323
2208
|
...baseConfig,
|
|
2209
|
+
...(partnerContractId
|
|
2210
|
+
? { partnerContractId }
|
|
2211
|
+
: {}),
|
|
2324
2212
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2325
2213
|
...(parsedVoucherValues.length > 0
|
|
2326
2214
|
? { voucherValue: parsedVoucherValues.length === 1 ? parsedVoucherValues[0] : parsedVoucherValues }
|
|
@@ -2338,6 +2226,9 @@ const inferConfigFromUrl = (baseConfig) => {
|
|
|
2338
2226
|
}
|
|
2339
2227
|
return {
|
|
2340
2228
|
...baseConfig,
|
|
2229
|
+
...(partnerContractId
|
|
2230
|
+
? { partnerContractId }
|
|
2231
|
+
: {}),
|
|
2341
2232
|
...(parsedVoucherCardIntegration !== undefined ? { voucherIntegration: parsedVoucherCardIntegration } : {}),
|
|
2342
2233
|
};
|
|
2343
2234
|
};
|
|
@@ -6350,6 +6241,7 @@ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, gif
|
|
|
6350
6241
|
customerPhone: formData.customerPhone?.trim(),
|
|
6351
6242
|
comment: formData.comment?.trim(),
|
|
6352
6243
|
paymentMethod: "gift_card",
|
|
6244
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6353
6245
|
...(upsellSelections.length > 0 && { upsellSelections }),
|
|
6354
6246
|
};
|
|
6355
6247
|
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
|
|
@@ -6626,6 +6518,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6626
6518
|
customerEmail: formData.customerEmail?.trim(),
|
|
6627
6519
|
customerPhone: formData.customerPhone?.trim(),
|
|
6628
6520
|
comment: formData.comment?.trim(),
|
|
6521
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6629
6522
|
...(cardToken && { cardToken }),
|
|
6630
6523
|
...(selectedMethod && !cardToken && { method: selectedMethod }),
|
|
6631
6524
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
@@ -6852,6 +6745,170 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6852
6745
|
}, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [spinner("var(--bw-surface-color)"), " ", buttonLabel] })) : (buttonLabel) }))] }));
|
|
6853
6746
|
}
|
|
6854
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
|
+
|
|
6855
6912
|
// Inner component that uses the Stripe hooks
|
|
6856
6913
|
function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onError, }) {
|
|
6857
6914
|
const t = useTranslations();
|
|
@@ -6880,13 +6937,25 @@ function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onEr
|
|
|
6880
6937
|
},
|
|
6881
6938
|
}, submitContent: jsxRuntime.jsx(jsxRuntime.Fragment, { children: submitLabel }), loadingContent: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [spinner("var(--bw-surface-color)"), " ", t("button.processingPayment")] }) }));
|
|
6882
6939
|
}
|
|
6883
|
-
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 = [], }) {
|
|
6884
6941
|
const t = useTranslations();
|
|
6885
6942
|
const { locale } = useLocale();
|
|
6886
6943
|
const [clientSecret, setClientSecret] = React.useState(null);
|
|
6887
6944
|
const [paymentIntentId, setPaymentIntentId] = React.useState(null);
|
|
6888
6945
|
const [isCreatingPaymentIntent, setIsCreatingPaymentIntent] = React.useState(false);
|
|
6889
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]);
|
|
6890
6959
|
const storageKey = typeof window !== "undefined"
|
|
6891
6960
|
? `bw_pi_${config?.organizationId}_${config?.eventInstanceId || eventDetails?.id}`
|
|
6892
6961
|
: "";
|
|
@@ -6965,6 +7034,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
6965
7034
|
customerEmail: formData.customerEmail?.trim(),
|
|
6966
7035
|
customerPhone: formData.customerPhone?.trim(),
|
|
6967
7036
|
comment: formData.comment?.trim(),
|
|
7037
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6968
7038
|
...(paymentIntentId && { paymentIntentId }),
|
|
6969
7039
|
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
6970
7040
|
};
|
|
@@ -7034,7 +7104,7 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
7034
7104
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
7035
7105
|
return (jsxRuntime.jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
7036
7106
|
}
|
|
7037
|
-
if (isCreatingPaymentIntent || !clientSecret) {
|
|
7107
|
+
if (isCreatingPaymentIntent || !clientSecret || !stripePromise) {
|
|
7038
7108
|
return (jsxRuntime.jsxs("div", { style: {
|
|
7039
7109
|
display: "flex",
|
|
7040
7110
|
alignItems: "center",
|
|
@@ -7072,6 +7142,49 @@ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discou
|
|
|
7072
7142
|
}, onError: onError }) }));
|
|
7073
7143
|
}
|
|
7074
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
|
+
|
|
7075
7188
|
const FLAG_EMOJIS = {
|
|
7076
7189
|
de: "🇩🇪",
|
|
7077
7190
|
en: "🇬🇧",
|
|
@@ -11483,6 +11596,11 @@ const buttonStyles = {
|
|
|
11483
11596
|
color: "var(--bw-text-muted)",
|
|
11484
11597
|
border: "1px solid var(--bw-border-color)",
|
|
11485
11598
|
},
|
|
11599
|
+
// Size variants
|
|
11600
|
+
small: {
|
|
11601
|
+
padding: "8px 12px",
|
|
11602
|
+
fontSize: "13px",
|
|
11603
|
+
},
|
|
11486
11604
|
// Full width modifier
|
|
11487
11605
|
fullWidth: {
|
|
11488
11606
|
width: "100%",
|
|
@@ -11555,6 +11673,12 @@ const sectionStyles = {
|
|
|
11555
11673
|
// TEXT
|
|
11556
11674
|
// ============================================
|
|
11557
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
|
+
},
|
|
11558
11682
|
muted: {
|
|
11559
11683
|
fontSize: "14px",
|
|
11560
11684
|
color: "var(--bw-text-muted)",
|
|
@@ -11624,7 +11748,7 @@ const sectionHeaderStyles$1 = sectionStyles.header;
|
|
|
11624
11748
|
const labelStyles$1 = formStyles.label;
|
|
11625
11749
|
const inputStyles$1 = formStyles.input;
|
|
11626
11750
|
const errorTextStyles$1 = formStyles.error;
|
|
11627
|
-
function BookingForm({ config, eventDetails,
|
|
11751
|
+
function BookingForm({ config, eventDetails, onSuccess, onError, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], persistedState = null, onPersistedStateChange, }) {
|
|
11628
11752
|
const t$1 = useTranslations();
|
|
11629
11753
|
const { locale } = useLocale();
|
|
11630
11754
|
const timezone = useTimezone();
|
|
@@ -11824,7 +11948,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
11824
11948
|
newTotal: appliedDiscountCode.newTotal,
|
|
11825
11949
|
}
|
|
11826
11950
|
: null;
|
|
11827
|
-
const hasPaymentProvider =
|
|
11951
|
+
const hasPaymentProvider = systemConfig?.paymentProvider === "stripe" || systemConfig?.paymentProvider === "mollie";
|
|
11828
11952
|
const handleVoucherValidated = React.useCallback((voucher, _error) => {
|
|
11829
11953
|
if (voucher) {
|
|
11830
11954
|
setAppliedVouchers((prev) => [...prev, voucher]);
|
|
@@ -12090,7 +12214,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12090
12214
|
...inputStyles$1,
|
|
12091
12215
|
resize: "vertical",
|
|
12092
12216
|
minHeight: "80px",
|
|
12093
|
-
} })] })] })] })), 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: {
|
|
12094
12218
|
color: "var(--bw-text-color)",
|
|
12095
12219
|
fontWeight: 500,
|
|
12096
12220
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -12194,7 +12318,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
|
|
|
12194
12318
|
fontFamily: "var(--bw-font-family)",
|
|
12195
12319
|
marginTop: "8px",
|
|
12196
12320
|
textAlign: "right",
|
|
12197
|
-
}, 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() })] })))] }))] }) }));
|
|
12198
12322
|
}
|
|
12199
12323
|
|
|
12200
12324
|
/**
|
|
@@ -13303,6 +13427,8 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13303
13427
|
const [stripeAppearance, setStripeAppearance] = React.useState(null);
|
|
13304
13428
|
// Initialize Stripe
|
|
13305
13429
|
React.useEffect(() => {
|
|
13430
|
+
if (!isOpen)
|
|
13431
|
+
return;
|
|
13306
13432
|
if (paymentProvider !== "stripe")
|
|
13307
13433
|
return;
|
|
13308
13434
|
if (systemConfig?.stripePublishableKey && !stripePromise) {
|
|
@@ -13314,7 +13440,7 @@ function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClos
|
|
|
13314
13440
|
}
|
|
13315
13441
|
setStripePromise(loadStripe(systemConfig.stripePublishableKey, stripeOptions));
|
|
13316
13442
|
}
|
|
13317
|
-
}, [paymentProvider, systemConfig, locale, stripePromise]);
|
|
13443
|
+
}, [isOpen, paymentProvider, systemConfig, locale, stripePromise]);
|
|
13318
13444
|
// Initialize Stripe appearance
|
|
13319
13445
|
React.useEffect(() => {
|
|
13320
13446
|
const container = document.querySelector(".booking-widget-container");
|
|
@@ -14278,8 +14404,17 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14278
14404
|
if (!item)
|
|
14279
14405
|
return jsxRuntime.jsx("div", { style: { height: "34px" } }, i);
|
|
14280
14406
|
const hasDiscount = item.basePrice > 0 && item.price < item.basePrice;
|
|
14281
|
-
|
|
14282
|
-
|
|
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: {
|
|
14283
14418
|
height: "34px",
|
|
14284
14419
|
display: "grid",
|
|
14285
14420
|
gridTemplateColumns: "auto 1fr auto 20px",
|
|
@@ -14288,12 +14423,13 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14288
14423
|
width: "100%",
|
|
14289
14424
|
fontSize: "13px",
|
|
14290
14425
|
color: "var(--bw-text-muted)",
|
|
14291
|
-
cursor: onInstancePreview ? "pointer" : "default",
|
|
14426
|
+
cursor: onInstancePreview && isRowBookable ? "pointer" : "default",
|
|
14292
14427
|
borderRadius: "4px",
|
|
14293
14428
|
padding: "0 2px",
|
|
14294
14429
|
transition: "background 0.15s",
|
|
14295
14430
|
boxSizing: "border-box",
|
|
14296
|
-
|
|
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));
|
|
14297
14433
|
}) }), hasMoreDates && (jsxRuntime.jsx("button", { type: "button", onClick: (e) => {
|
|
14298
14434
|
e.stopPropagation();
|
|
14299
14435
|
onEventTypeSelect(eventType);
|
|
@@ -14382,6 +14518,74 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
|
|
|
14382
14518
|
}) }) })), jsxRuntime.jsx(PaymentLogosStrip, {}), jsxRuntime.jsx(EventTypeDetailsDialog, { isOpen: detailsDialogOpen, onClose: handleCloseDetails, eventType: selectedEventTypeForDetails, onEventTypeSelect: onEventTypeSelect })] }));
|
|
14383
14519
|
}
|
|
14384
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
|
+
|
|
14385
14589
|
const getAllocationBadgeInfo = (availableSpots, maxParticipants, t) => {
|
|
14386
14590
|
const availabilityRatio = availableSpots / maxParticipants;
|
|
14387
14591
|
if (availabilityRatio >= 0.6)
|
|
@@ -14506,12 +14710,13 @@ const PriceDisplay = ({ price, yearPrices, t }) => {
|
|
|
14506
14710
|
boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
|
|
14507
14711
|
}, children: formatCurrency(price) }));
|
|
14508
14712
|
};
|
|
14509
|
-
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, }) {
|
|
14510
14714
|
const t = useTranslations();
|
|
14511
14715
|
const { locale } = useLocale();
|
|
14512
14716
|
const timezone = useTimezone();
|
|
14513
14717
|
const [selectedEventInstanceId, setSelectedEventInstanceId] = React.useState(null);
|
|
14514
14718
|
const [openGroups, setOpenGroups] = React.useState(new Set());
|
|
14719
|
+
const [waitlistEvent, setWaitlistEvent] = React.useState(null);
|
|
14515
14720
|
const getMonthPriceDisplayInfo = (minPrice) => {
|
|
14516
14721
|
return getPriceDisplayInfo(minPrice, yearPrices, t);
|
|
14517
14722
|
};
|
|
@@ -14672,116 +14877,127 @@ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInst
|
|
|
14672
14877
|
fontFamily: "var(--bw-font-family)",
|
|
14673
14878
|
}, children: t("instances.noAvailable") }), jsxRuntime.jsx("p", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t("instances.noAvailableMessage") })] }) }) }));
|
|
14674
14879
|
}
|
|
14675
|
-
return (jsxRuntime.
|
|
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
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
14755
|
-
|
|
14756
|
-
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
14770
|
-
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
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) }))] }));
|
|
14785
15001
|
}
|
|
14786
15002
|
|
|
14787
15003
|
function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText, showAllButton, isLoadingEventDetails = false, isLoadingShowAll = false, isLoading = false, count = 3, }) {
|
|
@@ -15675,6 +15891,7 @@ let buffer = [];
|
|
|
15675
15891
|
let flushTimer = null;
|
|
15676
15892
|
let currentApiBaseUrl = "";
|
|
15677
15893
|
let currentOrganizationId = "";
|
|
15894
|
+
let currentPartnerContractId = null;
|
|
15678
15895
|
const FLUSH_INTERVAL_MS = 3000;
|
|
15679
15896
|
function flush() {
|
|
15680
15897
|
if (buffer.length === 0)
|
|
@@ -15716,9 +15933,10 @@ function scheduleFlush() {
|
|
|
15716
15933
|
/**
|
|
15717
15934
|
* Initialise the analytics module. Must be called once before `trackEvent`.
|
|
15718
15935
|
*/
|
|
15719
|
-
function initAnalytics(apiBaseUrl, organizationId) {
|
|
15936
|
+
function initAnalytics(apiBaseUrl, organizationId, options) {
|
|
15720
15937
|
currentApiBaseUrl = apiBaseUrl;
|
|
15721
15938
|
currentOrganizationId = organizationId;
|
|
15939
|
+
currentPartnerContractId = options?.partnerContractId?.trim() || null;
|
|
15722
15940
|
if (typeof window !== "undefined") {
|
|
15723
15941
|
window.addEventListener("pagehide", flush);
|
|
15724
15942
|
window.addEventListener("visibilitychange", () => {
|
|
@@ -15735,9 +15953,12 @@ function trackEvent(event, properties = {}) {
|
|
|
15735
15953
|
return;
|
|
15736
15954
|
if (!currentOrganizationId)
|
|
15737
15955
|
return;
|
|
15956
|
+
const mergedProperties = currentPartnerContractId
|
|
15957
|
+
? { ...properties, partnerContractId: currentPartnerContractId }
|
|
15958
|
+
: properties;
|
|
15738
15959
|
buffer.push({
|
|
15739
15960
|
event,
|
|
15740
|
-
properties,
|
|
15961
|
+
properties: mergedProperties,
|
|
15741
15962
|
domain: window.location.hostname,
|
|
15742
15963
|
url: window.location.href,
|
|
15743
15964
|
referrer: document.referrer,
|
|
@@ -15813,7 +16034,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15813
16034
|
const [sidebarOpen, setSidebarOpen] = React.useState(false);
|
|
15814
16035
|
// Booking flow state
|
|
15815
16036
|
const [eventDetails, setEventDetails] = React.useState(null);
|
|
15816
|
-
const [stripePromise, setStripePromise] = React.useState(null);
|
|
15817
16037
|
// SEPARATED LOADING STATES
|
|
15818
16038
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
15819
16039
|
const [isLoadingEventInstances, setIsLoadingEventInstances] = React.useState(false);
|
|
@@ -15948,7 +16168,9 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15948
16168
|
React.useEffect(() => {
|
|
15949
16169
|
if (!analyticsInitRef.current && config.organizationId) {
|
|
15950
16170
|
analyticsInitRef.current = true;
|
|
15951
|
-
initAnalytics(config.apiBaseUrl, config.organizationId
|
|
16171
|
+
initAnalytics(config.apiBaseUrl, config.organizationId, {
|
|
16172
|
+
partnerContractId: config.partnerContractId,
|
|
16173
|
+
});
|
|
15952
16174
|
trackEvent("widget_loaded", {
|
|
15953
16175
|
viewMode,
|
|
15954
16176
|
eventTypeId: config.eventTypeId,
|
|
@@ -15957,7 +16179,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15957
16179
|
isStandaloneVoucherMode,
|
|
15958
16180
|
});
|
|
15959
16181
|
}
|
|
15960
|
-
}, [config.organizationId, config.apiBaseUrl]);
|
|
16182
|
+
}, [config.organizationId, config.apiBaseUrl, config.partnerContractId, viewMode, config.eventTypeId, config.categoryId, config.eventInstanceId, isStandaloneVoucherMode]);
|
|
15961
16183
|
// Fire widget pageview once when Google Ads config is received from API
|
|
15962
16184
|
const pageviewFiredRef = React.useRef(false);
|
|
15963
16185
|
React.useEffect(() => {
|
|
@@ -15971,6 +16193,23 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15971
16193
|
const initializeWidget = async () => {
|
|
15972
16194
|
try {
|
|
15973
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
|
+
}
|
|
15974
16213
|
// Load voucher config in parallel if voucher mode is requested or there's event selection
|
|
15975
16214
|
if (isVoucherModeRequested || hasEventSelection) {
|
|
15976
16215
|
void loadVoucherConfig();
|
|
@@ -16106,11 +16345,18 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16106
16345
|
setVoucherPurchaseResult(voucherData.voucherResult);
|
|
16107
16346
|
setIsSuccess(true);
|
|
16108
16347
|
setSuccessPaymentId(null);
|
|
16348
|
+
return;
|
|
16109
16349
|
}
|
|
16110
16350
|
}
|
|
16111
16351
|
catch {
|
|
16112
|
-
//
|
|
16113
|
-
}
|
|
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);
|
|
16114
16360
|
};
|
|
16115
16361
|
if (!isLoading) {
|
|
16116
16362
|
void handleMollieVoucherReturn();
|
|
@@ -16299,27 +16545,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16299
16545
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16300
16546
|
});
|
|
16301
16547
|
}
|
|
16302
|
-
if (data.stripePublishableKey) {
|
|
16303
|
-
const stripeOptions = {
|
|
16304
|
-
locale: locale,
|
|
16305
|
-
};
|
|
16306
|
-
if (data.connectedAccountId) {
|
|
16307
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16308
|
-
}
|
|
16309
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16310
|
-
try {
|
|
16311
|
-
void (window.parent === window || window.parent.location.href);
|
|
16312
|
-
if (!stripeOptions.betas) {
|
|
16313
|
-
stripeOptions.betas = [];
|
|
16314
|
-
}
|
|
16315
|
-
}
|
|
16316
|
-
catch {
|
|
16317
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16318
|
-
stripeOptions.betas = [];
|
|
16319
|
-
}
|
|
16320
|
-
}
|
|
16321
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16322
|
-
}
|
|
16323
16548
|
if (!skipInstanceAutoSelectRef.current && data.eventInstances.length === 1) {
|
|
16324
16549
|
setSelectedEventInstance(data.eventInstances[0]);
|
|
16325
16550
|
setCurrentStep("booking");
|
|
@@ -16359,29 +16584,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16359
16584
|
roundPricesEnabled: data.roundPricesEnabled ?? true,
|
|
16360
16585
|
widgetPaymentMode: data.widgetPaymentMode ?? "all",
|
|
16361
16586
|
});
|
|
16362
|
-
if (!stripePromise && data.stripePublishableKey) {
|
|
16363
|
-
const stripeOptions = {
|
|
16364
|
-
locale: locale,
|
|
16365
|
-
};
|
|
16366
|
-
if (data.connectedAccountId) {
|
|
16367
|
-
stripeOptions.stripeAccount = data.connectedAccountId;
|
|
16368
|
-
}
|
|
16369
|
-
if (typeof window !== "undefined" && window.document) {
|
|
16370
|
-
try {
|
|
16371
|
-
// Check if we have parent access (not in a cross-origin iframe)
|
|
16372
|
-
void (window.parent === window || window.parent.location.href);
|
|
16373
|
-
stripeOptions.apiVersion = "2025-02-24.acacia";
|
|
16374
|
-
if (!stripeOptions.betas) {
|
|
16375
|
-
stripeOptions.betas = [];
|
|
16376
|
-
}
|
|
16377
|
-
}
|
|
16378
|
-
catch {
|
|
16379
|
-
console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
|
|
16380
|
-
stripeOptions.betas = [];
|
|
16381
|
-
}
|
|
16382
|
-
}
|
|
16383
|
-
setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
|
|
16384
|
-
}
|
|
16385
16587
|
}
|
|
16386
16588
|
else {
|
|
16387
16589
|
const errorMessage = data.error || t("error.loadEventDetails");
|
|
@@ -16650,12 +16852,12 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16650
16852
|
startTime: cardPreviewItem.startTime,
|
|
16651
16853
|
endTime: cardPreviewItem.startTime,
|
|
16652
16854
|
price: cardPreviewItem.price,
|
|
16653
|
-
maxParticipants: cardPreviewItem.availableSpots
|
|
16654
|
-
participantCount:
|
|
16855
|
+
maxParticipants: Math.max(cardPreviewItem.availableSpots, 0),
|
|
16856
|
+
participantCount: 0,
|
|
16655
16857
|
availableSpots: cardPreviewItem.availableSpots,
|
|
16656
16858
|
durationDays: 1,
|
|
16657
16859
|
durationPerDay: 1,
|
|
16658
|
-
bookingOpen:
|
|
16860
|
+
bookingOpen: cardPreviewItem.bookingOpen && cardPreviewItem.availableSpots > 0,
|
|
16659
16861
|
}
|
|
16660
16862
|
: null;
|
|
16661
16863
|
if (eventInstance) {
|
|
@@ -16843,7 +17045,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16843
17045
|
}
|
|
16844
17046
|
// Main view based on view mode
|
|
16845
17047
|
if (viewMode === "next-events" && showingPreview) {
|
|
16846
|
-
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,
|
|
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: () => {
|
|
16847
17049
|
setIsSuccess(false);
|
|
16848
17050
|
setCurrentStep("eventTypes");
|
|
16849
17051
|
setShowingPreview(true);
|
|
@@ -16864,7 +17066,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16864
17066
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
16865
17067
|
}
|
|
16866
17068
|
if (viewMode === "specials" && showingPreview) {
|
|
16867
|
-
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: () => {
|
|
16868
17070
|
setIsSuccess(false);
|
|
16869
17071
|
setCurrentStep("eventTypes");
|
|
16870
17072
|
setShowingPreview(true);
|
|
@@ -16884,7 +17086,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16884
17086
|
}, isOpen: currentStep === "eventInstances", onClose: () => {
|
|
16885
17087
|
setShowingPreview(true);
|
|
16886
17088
|
setCurrentStep("eventTypes");
|
|
16887
|
-
}, 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: () => {
|
|
16888
17090
|
setIsSuccess(false);
|
|
16889
17091
|
setCurrentStep("eventTypes");
|
|
16890
17092
|
setShowingPreview(true);
|
|
@@ -16940,7 +17142,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16940
17142
|
setShouldRenderInstanceSelection(true);
|
|
16941
17143
|
}
|
|
16942
17144
|
}, children: [isButtonBusy && jsxRuntime.jsx(Spinner, { size: 20, borderColor: "var(--bw-button-text-color, #ffffff)" }), config.buttonText ||
|
|
16943
|
-
(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,
|
|
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: () => {
|
|
16944
17146
|
setIsSuccess(false);
|
|
16945
17147
|
setCurrentStep("eventTypes");
|
|
16946
17148
|
setSidebarOpen(false);
|
|
@@ -17001,7 +17203,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
17001
17203
|
};
|
|
17002
17204
|
};
|
|
17003
17205
|
const backHandlers = getBackHandlers();
|
|
17004
|
-
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: () => {
|
|
17005
17207
|
setIsSuccess(false);
|
|
17006
17208
|
setCurrentStep("eventTypes");
|
|
17007
17209
|
setSuccessPaymentId(null);
|