@bigz-app/booking-widget 1.1.7 → 1.1.8

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.
Files changed (29) hide show
  1. package/README.md +3 -1
  2. package/dist/booking-widget.js +165 -180
  3. package/dist/booking-widget.js.map +1 -1
  4. package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
  5. package/dist/components/booking/BookingForm.d.ts +0 -1
  6. package/dist/components/booking/BookingForm.d.ts.map +1 -1
  7. package/dist/components/booking/BookingSuccessModal.d.ts.map +1 -1
  8. package/dist/components/booking/GiftCardOnlyBooking.d.ts +22 -0
  9. package/dist/components/booking/GiftCardOnlyBooking.d.ts.map +1 -0
  10. package/dist/components/booking/MolliePaymentForm.d.ts +2 -6
  11. package/dist/components/booking/MolliePaymentForm.d.ts.map +1 -1
  12. package/dist/components/booking/{PaymentForm.d.ts → StripePaymentForm.d.ts} +4 -8
  13. package/dist/components/booking/StripePaymentForm.d.ts.map +1 -0
  14. package/dist/components/booking/VoucherInput.d.ts +8 -0
  15. package/dist/components/booking/VoucherInput.d.ts.map +1 -1
  16. package/dist/components/booking/index.d.ts +2 -1
  17. package/dist/components/booking/index.d.ts.map +1 -1
  18. package/dist/components/upsells/UpsellCard.d.ts +1 -2
  19. package/dist/components/upsells/UpsellCard.d.ts.map +1 -1
  20. package/dist/components/upsells/UpsellsStep.d.ts +1 -4
  21. package/dist/components/upsells/UpsellsStep.d.ts.map +1 -1
  22. package/dist/components/upsells/index.d.ts +1 -1
  23. package/dist/components/upsells/index.d.ts.map +1 -1
  24. package/dist/index.cjs +165 -180
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.esm.js +165 -180
  27. package/dist/index.esm.js.map +1 -1
  28. package/package.json +1 -1
  29. package/dist/components/booking/PaymentForm.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -223,7 +223,7 @@ const de$1 = {
223
223
  "error.loadBookingData": "Fehler beim Abrufen der Buchungsdaten",
224
224
  "error.processingError": "Ein Fehler ist bei der Verarbeitung aufgetreten.",
225
225
  "error.createBooking": "Fehler beim Erstellen der Buchung",
226
- "error.createPaymentIntent": "Fehler beim Erstellen der Zahlungsabsicht",
226
+ "error.createPayment": "Fehler beim Erstellen der Zahlung",
227
227
  "error.paymentProcessing": "Fehler beim Verarbeiten der Zahlung",
228
228
  "error.paymentFailed": "Die Zahlung war nicht erfolgreich. Bitte versuche es erneut.",
229
229
  "error.paymentIncomplete": "Die Zahlung konnte nicht abgeschlossen werden. Bitte versuche es erneut.",
@@ -337,7 +337,7 @@ const de$1 = {
337
337
  "voucher.giftCardApplied": "−{{amount}} Gutschein",
338
338
  "voucher.remaining": "Rest: {{amount}}",
339
339
  "voucher.remove": "Entfernen",
340
- "voucher.alreadyHasDiscount": "Es wurde bereits ein Rabattcode angewendet. Du kannst weitere Gutscheine hinzufügen.",
340
+ "voucher.alreadyHasDiscount": "Du kannst weitere Gutscheine hinzufügen.",
341
341
  // Booking success
342
342
  "success.title": "Reservierung erfolgreich!",
343
343
  "success.bookingDetails": "Buchungsdetails",
@@ -432,7 +432,7 @@ const en = {
432
432
  "error.loadBookingData": "Error fetching booking data",
433
433
  "error.processingError": "An error occurred during processing.",
434
434
  "error.createBooking": "Error creating booking",
435
- "error.createPaymentIntent": "Error creating payment intent",
435
+ "error.createPayment": "Error creating payment",
436
436
  "error.paymentProcessing": "Error processing payment",
437
437
  "error.paymentFailed": "The payment was not successful. Please try again.",
438
438
  "error.paymentIncomplete": "The payment could not be completed. Please try again.",
@@ -641,7 +641,7 @@ const es = {
641
641
  "error.loadBookingData": "Error al obtener datos de la reserva",
642
642
  "error.processingError": "Ocurrió un error durante el procesamiento.",
643
643
  "error.createBooking": "Error al crear la reserva",
644
- "error.createPaymentIntent": "Error al crear la intención de pago",
644
+ "error.createPayment": "Error al crear el pago",
645
645
  "error.paymentProcessing": "Error al procesar el pago",
646
646
  "error.paymentFailed": "El pago no fue exitoso. Por favor, inténtalo de nuevo.",
647
647
  "error.paymentIncomplete": "El pago no pudo completarse. Por favor, inténtalo de nuevo.",
@@ -850,7 +850,7 @@ const pt = {
850
850
  "error.loadBookingData": "Erro ao obter dados da reserva",
851
851
  "error.processingError": "Ocorreu um erro durante o processamento.",
852
852
  "error.createBooking": "Erro ao criar reserva",
853
- "error.createPaymentIntent": "Erro ao criar intenção de pagamento",
853
+ "error.createPayment": "Erro ao criar pagamento",
854
854
  "error.paymentProcessing": "Erro ao processar pagamento",
855
855
  "error.paymentFailed": "O pagamento não foi bem-sucedido. Por favor, tente novamente.",
856
856
  "error.paymentIncomplete": "O pagamento não pôde ser concluído. Por favor, tente novamente.",
@@ -1059,7 +1059,7 @@ const sv = {
1059
1059
  "error.loadBookingData": "Fel vid hämtning av bokningsdata",
1060
1060
  "error.processingError": "Ett fel uppstod vid bearbetningen.",
1061
1061
  "error.createBooking": "Fel vid skapande av bokning",
1062
- "error.createPaymentIntent": "Fel vid skapande av betalningsavsikt",
1062
+ "error.createPayment": "Fel vid skapande av betalning",
1063
1063
  "error.paymentProcessing": "Fel vid bearbetning av betalning",
1064
1064
  "error.paymentFailed": "Betalningen lyckades inte. Försök igen.",
1065
1065
  "error.paymentIncomplete": "Betalningen kunde inte slutföras. Försök igen.",
@@ -4418,6 +4418,108 @@ const IconChevronLeft = ({ size = 20, color = "white", className, }) => (jsxRunt
4418
4418
  // Chevron Right icon - used for carousel navigation
4419
4419
  const IconChevronRight = ({ size = 20, color = "white", className, }) => (jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }));
4420
4420
 
4421
+ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
4422
+ const t = useTranslations();
4423
+ const [isLoading, setIsLoading] = React.useState(false);
4424
+ const [error, setError] = React.useState(null);
4425
+ const handleBooking = async () => {
4426
+ setIsLoading(true);
4427
+ setError(null);
4428
+ try {
4429
+ const requestData = {
4430
+ eventInstanceId: config.eventInstanceId || eventDetails.id,
4431
+ organizationId: config.organizationId,
4432
+ participants: formData.participants.filter((p) => p.name?.trim()),
4433
+ discountCode: discountCode?.code,
4434
+ giftCardCodes: giftCards.map((gc) => gc.code),
4435
+ customerName: formData.customerName?.trim(),
4436
+ customerEmail: formData.customerEmail?.trim(),
4437
+ customerPhone: formData.customerPhone?.trim(),
4438
+ comment: formData.comment?.trim(),
4439
+ paymentMethod: "gift_card",
4440
+ ...(upsellSelections.length > 0 && { upsellSelections }),
4441
+ };
4442
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
4443
+ method: "POST",
4444
+ headers: createApiHeaders(config),
4445
+ body: JSON.stringify(createRequestBody(config, requestData)),
4446
+ });
4447
+ const data = await response.json();
4448
+ if (response.ok) {
4449
+ onSuccess({
4450
+ booking: data.booking,
4451
+ order: data.order,
4452
+ giftCardRedemptions: data.giftCardRedemptions,
4453
+ });
4454
+ }
4455
+ else {
4456
+ setError(data.error || t("error.createBooking"));
4457
+ onError(data.error || t("error.createBooking"));
4458
+ }
4459
+ }
4460
+ catch (err) {
4461
+ setError(err.message || t("error.createBooking"));
4462
+ onError(err.message || t("error.createBooking"));
4463
+ }
4464
+ finally {
4465
+ setIsLoading(false);
4466
+ }
4467
+ };
4468
+ const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4469
+ return (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxRuntime.jsxs("div", { style: {
4470
+ backgroundColor: "rgba(var(--bw-success-color), 0.15)",
4471
+ border: "1px solid rgba(var(--bw-success-color), 0.4)",
4472
+ borderRadius: "var(--bw-border-radius)",
4473
+ padding: "16px",
4474
+ }, children: [jsxRuntime.jsxs("div", { style: {
4475
+ display: "flex",
4476
+ alignItems: "center",
4477
+ gap: "8px",
4478
+ marginBottom: "8px",
4479
+ color: "var(--bw-success-color)",
4480
+ fontFamily: "var(--bw-font-family)",
4481
+ fontWeight: 600,
4482
+ }, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), jsxRuntime.jsx("div", { style: {
4483
+ fontSize: "16px",
4484
+ color: "var(--bw-text-muted)",
4485
+ fontFamily: "var(--bw-font-family)",
4486
+ }, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (jsxRuntime.jsxs("div", { style: {
4487
+ backgroundColor: "rgba(var(--bw-error-color), 0.15)",
4488
+ border: "1px solid rgba(var(--bw-error-color), 0.4)",
4489
+ borderRadius: "var(--bw-border-radius)",
4490
+ padding: "16px",
4491
+ color: "var(--bw-error-color)",
4492
+ fontSize: "16px",
4493
+ fontFamily: "var(--bw-font-family)",
4494
+ }, children: ["\u26A0\uFE0F ", error] })), jsxRuntime.jsx("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
4495
+ width: "100%",
4496
+ padding: "12px 24px",
4497
+ backgroundColor: "var(--bw-highlight-color)",
4498
+ color: "#ffffff",
4499
+ border: "none",
4500
+ borderRadius: "var(--bw-border-radius)",
4501
+ fontSize: "16px",
4502
+ fontWeight: 600,
4503
+ fontFamily: "var(--bw-font-family)",
4504
+ transition: "all 0.2s ease",
4505
+ display: "flex",
4506
+ alignItems: "center",
4507
+ justifyContent: "center",
4508
+ gap: "8px",
4509
+ cursor: isLoading ? "not-allowed" : "pointer",
4510
+ opacity: isLoading ? 0.6 : 1,
4511
+ }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [spinner("#ffffff"), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
4512
+ }
4513
+ /**
4514
+ * Calculate whether gift cards fully cover the order after discounts.
4515
+ */
4516
+ function isGiftCardFullyCovered(giftCards, eventPrice, participantCount, discountAmount) {
4517
+ const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4518
+ const baseTotal = eventPrice * participantCount;
4519
+ const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
4520
+ return totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
4521
+ }
4522
+
4421
4523
  const mollieLocaleMap = {
4422
4524
  de: "de_DE",
4423
4525
  en: "en_US",
@@ -4478,13 +4580,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4478
4580
  const mollieRef = React.useRef(null);
4479
4581
  const cardFormRef = React.useRef(null);
4480
4582
  const cardContainerRef = React.useRef(null);
4481
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4482
- const baseTotal = eventDetails?.price
4483
- ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
4484
- : 0;
4485
- const discountAmount = discountCode?.discountAmount || 0;
4486
- const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
4487
- const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
4583
+ const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
4584
+ const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
4488
4585
  const isCreditCard = selectedMethod === "creditcard";
4489
4586
  React.useEffect(() => {
4490
4587
  if (isFullyCoveredByGiftCards)
@@ -4591,7 +4688,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4591
4688
  };
4592
4689
  }, [isCreditCard, mollieProfileId, mollieTestmode, isFullyCoveredByGiftCards]);
4593
4690
  if (isFullyCoveredByGiftCards && totalAmount <= 0) {
4594
- return null;
4691
+ return (jsxRuntime.jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: _onSuccess, onError: onError, upsellSelections: upsellSelections }));
4595
4692
  }
4596
4693
  const validateBeforePayment = () => {
4597
4694
  const participantCount = formData.participants.filter((p) => p.name?.trim()).length;
@@ -4633,7 +4730,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4633
4730
  }
4634
4731
  const { token, error: tokenError } = await mollieRef.current.createToken();
4635
4732
  if (tokenError || !token) {
4636
- setPaymentError(tokenError?.message || t("error.createPaymentIntent"));
4733
+ setPaymentError(tokenError?.message || t("error.createPayment"));
4637
4734
  return;
4638
4735
  }
4639
4736
  const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-mollie-payment"), {
@@ -4649,8 +4746,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4649
4746
  _onSuccess({ paymentIntent: { id: data.molliePaymentId } });
4650
4747
  }
4651
4748
  else {
4652
- setPaymentError(data.error || t("error.createPaymentIntent"));
4653
- onError(data.error || t("error.createPaymentIntent"));
4749
+ setPaymentError(data.error || t("error.createPayment"));
4750
+ onError(data.error || t("error.createPayment"));
4654
4751
  }
4655
4752
  }
4656
4753
  catch (err) {
@@ -4682,8 +4779,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4682
4779
  window.location.href = data.checkoutUrl;
4683
4780
  }
4684
4781
  else {
4685
- setPaymentError(data.error || t("error.createPaymentIntent"));
4686
- onError(data.error || t("error.createPaymentIntent"));
4782
+ setPaymentError(data.error || t("error.createPayment"));
4783
+ onError(data.error || t("error.createPayment"));
4687
4784
  }
4688
4785
  }
4689
4786
  catch (err) {
@@ -6153,106 +6250,6 @@ var reactStripe_umd = {exports: {}};
6153
6250
 
6154
6251
  var reactStripe_umdExports = reactStripe_umd.exports;
6155
6252
 
6156
- // Component for bookings fully covered by gift cards (no Stripe payment needed)
6157
- function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
6158
- const t = useTranslations();
6159
- const [isLoading, setIsLoading] = React.useState(false);
6160
- const [error, setError] = React.useState(null);
6161
- const handleBooking = async () => {
6162
- setIsLoading(true);
6163
- setError(null);
6164
- try {
6165
- const requestData = {
6166
- eventInstanceId: config.eventInstanceId || eventDetails.id,
6167
- organizationId: config.organizationId,
6168
- participants: formData.participants.filter((p) => p.name?.trim()),
6169
- discountCode: discountCode?.code,
6170
- giftCardCodes: giftCards.map((gc) => gc.code),
6171
- customerName: formData.customerName?.trim(),
6172
- customerEmail: formData.customerEmail?.trim(),
6173
- customerPhone: formData.customerPhone?.trim(),
6174
- comment: formData.comment?.trim(),
6175
- paymentMethod: "gift_card",
6176
- ...(upsellSelections.length > 0 && { upsellSelections }),
6177
- };
6178
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
6179
- method: "POST",
6180
- headers: createApiHeaders(config),
6181
- body: JSON.stringify(createRequestBody(config, requestData)),
6182
- });
6183
- const data = await response.json();
6184
- if (response.ok) {
6185
- onSuccess({
6186
- booking: data.booking,
6187
- order: data.order,
6188
- giftCardRedemptions: data.giftCardRedemptions,
6189
- });
6190
- }
6191
- else {
6192
- setError(data.error || t("error.createBooking"));
6193
- onError(data.error || t("error.createBooking"));
6194
- }
6195
- }
6196
- catch (err) {
6197
- setError(err.message || t("error.createBooking"));
6198
- onError(err.message || t("error.createBooking"));
6199
- }
6200
- finally {
6201
- setIsLoading(false);
6202
- }
6203
- };
6204
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
6205
- return (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxRuntime.jsxs("div", { style: {
6206
- backgroundColor: "rgba(var(--bw-success-color), 0.15)",
6207
- border: "1px solid rgba(var(--bw-success-color), 0.4)",
6208
- borderRadius: "var(--bw-border-radius)",
6209
- padding: "16px",
6210
- }, children: [jsxRuntime.jsxs("div", { style: {
6211
- display: "flex",
6212
- alignItems: "center",
6213
- gap: "8px",
6214
- marginBottom: "8px",
6215
- color: "var(--bw-success-color)",
6216
- fontFamily: "var(--bw-font-family)",
6217
- fontWeight: 600,
6218
- }, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), jsxRuntime.jsx("div", { style: {
6219
- fontSize: "16px",
6220
- color: "var(--bw-text-muted)",
6221
- fontFamily: "var(--bw-font-family)",
6222
- }, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (jsxRuntime.jsxs("div", { style: {
6223
- backgroundColor: "rgba(var(--bw-error-color), 0.15)",
6224
- border: "1px solid rgba(var(--bw-error-color), 0.4)",
6225
- borderRadius: "var(--bw-border-radius)",
6226
- padding: "16px",
6227
- color: "var(--bw-error-color)",
6228
- fontSize: "16px",
6229
- fontFamily: "var(--bw-font-family)",
6230
- }, children: ["\u26A0\uFE0F ", error] })), jsxRuntime.jsx("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
6231
- width: "100%",
6232
- padding: "12px 24px",
6233
- backgroundColor: "var(--bw-highlight-color)",
6234
- color: "#ffffff",
6235
- border: "none",
6236
- borderRadius: "var(--bw-border-radius)",
6237
- fontSize: "16px",
6238
- fontWeight: 600,
6239
- fontFamily: "var(--bw-font-family)",
6240
- transition: "all 0.2s ease",
6241
- display: "flex",
6242
- alignItems: "center",
6243
- justifyContent: "center",
6244
- gap: "8px",
6245
- cursor: isLoading ? "not-allowed" : "pointer",
6246
- opacity: isLoading ? 0.6 : 1,
6247
- }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { style: {
6248
- width: "16px",
6249
- height: "16px",
6250
- border: "2px solid #ffffff",
6251
- borderTopColor: "transparent",
6252
- borderRadius: "50%",
6253
- animation: "spin 1s linear infinite",
6254
- } }), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
6255
- }
6256
6253
  // Inner component that uses the Stripe hooks
6257
6254
  function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSuccess, onError, }) {
6258
6255
  const t = useTranslations();
@@ -6289,7 +6286,7 @@ function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSucce
6289
6286
  redirect: "if_required",
6290
6287
  });
6291
6288
  if (error) {
6292
- console.error("[PAYMENT_FORM] Payment confirmation error:", {
6289
+ console.error("[STRIPE_PAYMENT] Payment confirmation error:", {
6293
6290
  type: error.type,
6294
6291
  code: error.code,
6295
6292
  message: error.message,
@@ -6365,8 +6362,7 @@ function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSucce
6365
6362
  ? t("button.depositAndBook")
6366
6363
  : t("button.bookNow") })) })] }));
6367
6364
  }
6368
- // Main PaymentForm component that handles payment intent creation and Elements wrapper
6369
- function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
6365
+ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
6370
6366
  const t = useTranslations();
6371
6367
  const [clientSecret, setClientSecret] = React.useState(null);
6372
6368
  const [paymentIntentId, setPaymentIntentId] = React.useState(null);
@@ -6427,7 +6423,7 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6427
6423
  }
6428
6424
  }, [paymentIntentId]);
6429
6425
  React.useEffect(() => {
6430
- const createPaymentIntent = async () => {
6426
+ const createStripePayment = async () => {
6431
6427
  if (!systemConfig || !eventDetails || !formData.participants?.length) {
6432
6428
  return;
6433
6429
  }
@@ -6468,35 +6464,38 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6468
6464
  if (!requestData.customerEmail) {
6469
6465
  throw new Error("Customer email is required");
6470
6466
  }
6471
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-payment-intent"), {
6467
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-stripe-payment"), {
6472
6468
  method: "POST",
6473
6469
  headers: createApiHeaders(config),
6474
6470
  body: JSON.stringify(createRequestBody(config, requestData)),
6475
6471
  });
6476
6472
  const data = await response.json();
6477
6473
  if (response.ok) {
6474
+ if (data.stalePaymentIntent) {
6475
+ clearPersistedPaymentIntent();
6476
+ }
6478
6477
  setClientSecret(data.clientSecret);
6479
6478
  setPaymentIntentId(data.paymentIntentId);
6480
6479
  }
6481
6480
  else {
6482
- console.error("[PAYMENT_FORM] Payment intent creation failed:", {
6481
+ console.error("[STRIPE_PAYMENT] Payment creation failed:", {
6483
6482
  status: response.status,
6484
6483
  error: data.error,
6485
6484
  details: data.details,
6486
6485
  requestData: { ...requestData, customerEmail: "[redacted]" },
6487
6486
  });
6488
- setPaymentError(data.error || t("error.createPaymentIntent"));
6487
+ setPaymentError(data.error || t("error.createPayment"));
6489
6488
  }
6490
6489
  }
6491
6490
  catch (err) {
6492
- console.error("[PAYMENT_FORM] Payment intent creation error:", err);
6493
- setPaymentError(err.message || t("error.createPaymentIntent"));
6491
+ console.error("[STRIPE_PAYMENT] Payment creation error:", err);
6492
+ setPaymentError(err.message || t("error.createPayment"));
6494
6493
  }
6495
6494
  finally {
6496
6495
  setIsCreatingPaymentIntent(false);
6497
6496
  }
6498
6497
  };
6499
- const timer = setTimeout(createPaymentIntent, 500);
6498
+ const timer = setTimeout(createStripePayment, 500);
6500
6499
  return () => clearTimeout(timer);
6501
6500
  }, [
6502
6501
  systemConfig,
@@ -6511,13 +6510,8 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6511
6510
  config,
6512
6511
  upsellSelections,
6513
6512
  ]);
6514
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
6515
- const baseTotal = eventDetails?.price
6516
- ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
6517
- : 0;
6518
- const discountAmount = discountCode?.discountAmount || 0;
6519
- const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
6520
- const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
6513
+ const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
6514
+ const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
6521
6515
  if (isFullyCoveredByGiftCards && totalAmount <= 0) {
6522
6516
  return (jsxRuntime.jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
6523
6517
  }
@@ -11027,13 +11021,6 @@ function mergeStyles(...styles) {
11027
11021
  return Object.assign({}, ...styles.filter(Boolean));
11028
11022
  }
11029
11023
 
11030
- function getEffectivePrice(upsell, round) {
11031
- const dp = upsell.discountPercent ?? 0;
11032
- if (dp <= 0)
11033
- return upsell.price;
11034
- const raw = Math.round(upsell.price * (100 - dp) / 100);
11035
- return round ? Math.floor(raw / 100) * 100 : raw;
11036
- }
11037
11024
  // Local style aliases from shared styles
11038
11025
  const cardStyles = cardStyles$1.base;
11039
11026
  const sectionHeaderStyles = sectionStyles.header;
@@ -11045,6 +11032,11 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11045
11032
  const { locale } = useLocale();
11046
11033
  const timezone = useTimezone();
11047
11034
  const roundEnabled = systemConfig?.roundPricesEnabled !== false;
11035
+ const roundDiscountUp = (minorUnits) => Math.ceil(minorUnits / 100) * 100;
11036
+ const calcPercentDiscountAmount = (baseAmount, basisPoints, round) => {
11037
+ const raw = Math.round((baseAmount * basisPoints) / 10000);
11038
+ return round ? roundDiscountUp(raw) : raw;
11039
+ };
11048
11040
  const [appliedVouchers, setAppliedVouchers] = React.useState([]);
11049
11041
  const paymentSectionRef = React.useRef(null);
11050
11042
  // Payment option: "deposit" or "full" - only relevant when deposit is available
@@ -11117,7 +11109,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11117
11109
  participantUpsellIds.forEach(upsellId => {
11118
11110
  const upsell = upsells.find(u => u.id === upsellId);
11119
11111
  if (upsell) {
11120
- total += getEffectivePrice(upsell, roundEnabled);
11112
+ total += upsell.price;
11121
11113
  }
11122
11114
  });
11123
11115
  }
@@ -11222,7 +11214,10 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11222
11214
  // TODO: discounts currently apply to base total only; extend when discount-applies-to-upsells flag is added
11223
11215
  let newDiscountAmount = 0;
11224
11216
  if (voucher.discountType === "percentage") {
11225
- newDiscountAmount = Math.round((newBaseTotal * (voucher.discountValue || 0)) / 10000);
11217
+ newDiscountAmount = calcPercentDiscountAmount(newBaseTotal, voucher.discountValue || 0, roundEnabled);
11218
+ if (voucher.restrictions?.maxDiscount) {
11219
+ newDiscountAmount = Math.min(newDiscountAmount, voucher.restrictions.maxDiscount);
11220
+ }
11226
11221
  }
11227
11222
  else {
11228
11223
  newDiscountAmount = voucher.discountValue || 0;
@@ -11400,7 +11395,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11400
11395
  padding: 0,
11401
11396
  }, children: "\u00D7" })] }))] }), upsells.length > 0 && (jsxRuntime.jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11402
11397
  const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11403
- return (jsxRuntime.jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsxRuntime.jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxRuntime.jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(getEffectivePrice(upsell, roundEnabled)), ")"] })] }, upsell.id));
11398
+ return (jsxRuntime.jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsxRuntime.jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxRuntime.jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11404
11399
  }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsxRuntime.jsx("div", { style: {
11405
11400
  display: "flex",
11406
11401
  flexDirection: "column",
@@ -11432,7 +11427,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11432
11427
  const countWithUpsell = watchedParticipants.filter((p, idx) => p.name.trim() && (participantUpsells[idx] || []).includes(upsell.id)).length;
11433
11428
  if (countWithUpsell === 0)
11434
11429
  return null;
11435
- const upsellLineTotal = getEffectivePrice(upsell, roundEnabled) * countWithUpsell;
11430
+ const upsellLineTotal = upsell.price * countWithUpsell;
11436
11431
  return (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px" }, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }, upsell.id));
11437
11432
  })] })), appliedVouchers.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { 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("summary.subtotal") }), jsxRuntime.jsx("span", { style: {
11438
11433
  fontFamily: "var(--bw-font-family)",
@@ -11577,7 +11572,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11577
11572
  if (systemConfig?.paymentProvider === "mollie") {
11578
11573
  return (jsxRuntime.jsxs("div", { style: cardStyles, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles }, 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 })] }));
11579
11574
  }
11580
- return (jsxRuntime.jsxs("div", { style: cardStyles, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), jsxRuntime.jsx(PaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] }));
11575
+ return (jsxRuntime.jsxs("div", { style: cardStyles, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles }, 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, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] }));
11581
11576
  })() })] })] })] }) }));
11582
11577
  }
11583
11578
 
@@ -11711,7 +11706,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11711
11706
  if (targetPaymentIntentId) {
11712
11707
  setIsLoading(true);
11713
11708
  try {
11714
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment-intent"), {
11709
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment"), {
11715
11710
  method: "POST",
11716
11711
  headers: createApiHeaders(config),
11717
11712
  body: JSON.stringify(createRequestBody(config, {
@@ -11727,7 +11722,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11727
11722
  orderItems: data.orderItems,
11728
11723
  purchases: data.purchases || [],
11729
11724
  discount: data.discount || null,
11730
- stripePaymentIntent: data.stripePaymentIntent,
11725
+ providerPaymentDetails: data.stripePaymentIntent,
11731
11726
  });
11732
11727
  setEventDetails({
11733
11728
  id: data.booking.eventInstance.id,
@@ -11735,7 +11730,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11735
11730
  description: data.booking.eventInstance.eventType.description,
11736
11731
  startTime: data.booking.eventInstance.startTime,
11737
11732
  endTime: data.booking.eventInstance.endTime,
11738
- price: data.booking.eventInstance.price || 0, // Use actual event instance price
11733
+ price: data.booking.eventInstance.price || 0,
11739
11734
  });
11740
11735
  setFormData({
11741
11736
  customerEmail: data.booking.customerEmail,
@@ -11743,9 +11738,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11743
11738
  customerPhone: data.booking.customerPhone,
11744
11739
  participants: data.booking.participants || [],
11745
11740
  });
11746
- // Set payment status from Stripe data or order status
11747
11741
  setPaymentStatus(data.stripePaymentIntent?.status || data.order.status);
11748
- // Trigger Google Ads conversion tracking if payment is successful
11749
11742
  const finalPaymentStatus = data.stripePaymentIntent?.status || data.order.status;
11750
11743
  if (finalPaymentStatus === "succeeded" &&
11751
11744
  config.googleAds?.tagId &&
@@ -13695,11 +13688,10 @@ function formatUnavailableReason(reason, t) {
13695
13688
  return t("upsells.reason.notEnoughSpots", { eventTypeName: reason.eventTypeName });
13696
13689
  }
13697
13690
  }
13698
- function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPricesEnabled = true, }) {
13691
+ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
13699
13692
  const t = useTranslations();
13700
13693
  const { locale } = useLocale();
13701
- const effectivePrice = getEffectiveUpsellPrice(upsell, roundPricesEnabled);
13702
- const totalPrice = effectivePrice * participantCount;
13694
+ const totalPrice = upsell.price * participantCount;
13703
13695
  const isDisabled = !upsell.available;
13704
13696
  const getCardStyles = () => {
13705
13697
  if (isDisabled)
@@ -13717,19 +13709,12 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPrice
13717
13709
  weekday: "short",
13718
13710
  day: "numeric",
13719
13711
  month: "short",
13720
- })] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxRuntime.jsxs("div", { style: priceContainerStyles, children: [jsxRuntime.jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(effectivePrice), "/", t("common.perPerson")] }), participantCount > 1 && (jsxRuntime.jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsxRuntime.jsx("div", { style: unavailableOverlayStyles, children: jsxRuntime.jsx("span", { children: upsell.unavailableReason
13712
+ })] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxRuntime.jsxs("div", { style: priceContainerStyles, children: [jsxRuntime.jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxRuntime.jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsxRuntime.jsx("div", { style: unavailableOverlayStyles, children: jsxRuntime.jsx("span", { children: upsell.unavailableReason
13721
13713
  ? formatUnavailableReason(upsell.unavailableReason, t)
13722
13714
  : t("upsells.notAvailable") }) }))] }));
13723
13715
  }
13724
13716
 
13725
- function getEffectiveUpsellPrice(upsell, round = true) {
13726
- const dp = upsell.discountPercent ?? 0;
13727
- if (dp <= 0)
13728
- return upsell.price;
13729
- const raw = Math.round(upsell.price * (100 - dp) / 100);
13730
- return round ? Math.floor(raw / 100) * 100 : raw;
13731
- }
13732
- function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, roundPricesEnabled = true, }) {
13717
+ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, }) {
13733
13718
  const t = useTranslations();
13734
13719
  const selectUpsell = (upsellId) => {
13735
13720
  const exists = selectedUpsells.find((s) => s.upsellPackageId === upsellId);
@@ -13748,7 +13733,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13748
13733
  return selectedUpsells.reduce((total, selection) => {
13749
13734
  const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
13750
13735
  if (upsell) {
13751
- return total + getEffectiveUpsellPrice(upsell, roundPricesEnabled) * selection.quantity;
13736
+ return total + upsell.price * selection.quantity;
13752
13737
  }
13753
13738
  return total;
13754
13739
  }, 0);
@@ -13756,7 +13741,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13756
13741
  const selectedTotal = calculateTotal();
13757
13742
  const selectedCount = selectedUpsells.length;
13758
13743
  const footerContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: onBack, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: t("common.back") }), jsxRuntime.jsx("button", { type: "button", onClick: onContinue, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: selectedCount === 0 ? t("button.continueWithout") : t("button.continue") })] }));
13759
- return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsxRuntime.jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsxRuntime.jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsxRuntime.jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id), roundPricesEnabled: roundPricesEnabled }, upsell.id))) })), selectedCount > 0 && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: [jsxRuntime.jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
13744
+ return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsxRuntime.jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsxRuntime.jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsxRuntime.jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: [jsxRuntime.jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
13760
13745
  }
13761
13746
 
13762
13747
  // Main widget component
@@ -13802,7 +13787,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13802
13787
  const [isLoadingShowAll, setIsLoadingShowAll] = React.useState(false);
13803
13788
  const [error, setError] = React.useState(null);
13804
13789
  const [isSuccess, setIsSuccess] = React.useState(false);
13805
- const [successPaymentIntentId, setSuccessPaymentIntentId] = React.useState(null);
13790
+ const [successPaymentId, setSuccessPaymentId] = React.useState(null);
13806
13791
  const [systemConfig, setSystemConfig] = React.useState(null);
13807
13792
  // PERFORMANCE OPTIMIZATION: Lazy component loading
13808
13793
  const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = React.useState(false);
@@ -13868,7 +13853,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13868
13853
  const stripeReturn = detectStripeReturn();
13869
13854
  if (stripeReturn) {
13870
13855
  if (stripeReturn.redirectStatus === "succeeded") {
13871
- setSuccessPaymentIntentId(stripeReturn.paymentIntent);
13856
+ setSuccessPaymentId(stripeReturn.paymentIntent);
13872
13857
  setIsSuccess(true);
13873
13858
  }
13874
13859
  else if (stripeReturn.redirectStatus === "failed") {
@@ -14223,7 +14208,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14223
14208
  };
14224
14209
  const handleBookingSuccess = (result) => {
14225
14210
  setIsSuccess(true);
14226
- setSuccessPaymentIntentId(result.paymentIntent.id);
14211
+ setSuccessPaymentId(result.paymentIntent.id);
14227
14212
  setSidebarOpen(false);
14228
14213
  setShouldRenderBookingForm(false);
14229
14214
  config.onSuccess?.(result);
@@ -14421,7 +14406,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14421
14406
  setIsSuccess(false);
14422
14407
  setCurrentStep("eventTypes");
14423
14408
  setShowingPreview(true);
14424
- setSuccessPaymentIntentId(null);
14409
+ setSuccessPaymentId(null);
14425
14410
  setShouldRenderInstanceSelection(false);
14426
14411
  setShouldRenderUpsells(false);
14427
14412
  setShouldRenderBookingForm(false);
@@ -14432,7 +14417,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14432
14417
  url.searchParams.delete("payment_intent_client_secret");
14433
14418
  url.searchParams.delete("redirect_status");
14434
14419
  window.history.replaceState({}, "", url.toString());
14435
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14420
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14436
14421
  }
14437
14422
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
14438
14423
  return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
@@ -14445,7 +14430,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14445
14430
  setIsSuccess(false);
14446
14431
  setCurrentStep("eventTypes");
14447
14432
  setShowingPreview(true);
14448
- setSuccessPaymentIntentId(null);
14433
+ setSuccessPaymentId(null);
14449
14434
  setShouldRenderInstanceSelection(false);
14450
14435
  setShouldRenderBookingForm(false);
14451
14436
  const url = new URL(window.location.href);
@@ -14453,7 +14438,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14453
14438
  url.searchParams.delete("payment_intent_client_secret");
14454
14439
  url.searchParams.delete("redirect_status");
14455
14440
  window.history.replaceState({}, "", url.toString());
14456
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14441
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14457
14442
  }
14458
14443
  if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
14459
14444
  return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, style: {
@@ -14482,11 +14467,11 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14482
14467
  setShouldRenderInstanceSelection(true);
14483
14468
  }
14484
14469
  }, children: config.buttonText ||
14485
- (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack, roundPricesEnabled: systemConfig?.roundPricesEnabled !== false })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), onBackToEventTypes: () => setSidebarOpen(false), selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14470
+ (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), 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, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), onBackToEventTypes: () => setSidebarOpen(false), selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14486
14471
  setIsSuccess(false);
14487
14472
  setCurrentStep("eventTypes");
14488
14473
  setSidebarOpen(false);
14489
- setSuccessPaymentIntentId(null);
14474
+ setSuccessPaymentId(null);
14490
14475
  setShouldRenderInstanceSelection(false);
14491
14476
  setShouldRenderUpsells(false);
14492
14477
  setShouldRenderBookingForm(false);
@@ -14497,7 +14482,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14497
14482
  url.searchParams.delete("payment_intent_client_secret");
14498
14483
  url.searchParams.delete("redirect_status");
14499
14484
  window.history.replaceState({}, "", url.toString());
14500
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14485
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14501
14486
  }
14502
14487
  // Cards mode (default) - show event type selection
14503
14488
  const cardsView = (jsxRuntime.jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
@@ -14529,10 +14514,10 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14529
14514
  };
14530
14515
  };
14531
14516
  const backHandlers = getBackHandlers();
14532
- 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 })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack, roundPricesEnabled: systemConfig?.roundPricesEnabled !== false })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: backHandlers.onBackToEventInstances, onBackToEventTypes: backHandlers.onBackToEventTypes, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14517
+ 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 })), 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, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: backHandlers.onBackToEventInstances, onBackToEventTypes: backHandlers.onBackToEventTypes, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14533
14518
  setIsSuccess(false);
14534
14519
  setCurrentStep("eventTypes");
14535
- setSuccessPaymentIntentId(null);
14520
+ setSuccessPaymentId(null);
14536
14521
  setShouldRenderInstanceSelection(false);
14537
14522
  setShouldRenderUpsells(false);
14538
14523
  setShouldRenderBookingForm(false);
@@ -14543,7 +14528,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14543
14528
  url.searchParams.delete("payment_intent_client_secret");
14544
14529
  url.searchParams.delete("redirect_status");
14545
14530
  window.history.replaceState({}, "", url.toString());
14546
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14531
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14547
14532
  }
14548
14533
  function UniversalBookingWidget(props) {
14549
14534
  const [languagePolicy, setLanguagePolicy] = React.useState(null);