@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.esm.js CHANGED
@@ -203,7 +203,7 @@ const de$1 = {
203
203
  "error.loadBookingData": "Fehler beim Abrufen der Buchungsdaten",
204
204
  "error.processingError": "Ein Fehler ist bei der Verarbeitung aufgetreten.",
205
205
  "error.createBooking": "Fehler beim Erstellen der Buchung",
206
- "error.createPaymentIntent": "Fehler beim Erstellen der Zahlungsabsicht",
206
+ "error.createPayment": "Fehler beim Erstellen der Zahlung",
207
207
  "error.paymentProcessing": "Fehler beim Verarbeiten der Zahlung",
208
208
  "error.paymentFailed": "Die Zahlung war nicht erfolgreich. Bitte versuche es erneut.",
209
209
  "error.paymentIncomplete": "Die Zahlung konnte nicht abgeschlossen werden. Bitte versuche es erneut.",
@@ -317,7 +317,7 @@ const de$1 = {
317
317
  "voucher.giftCardApplied": "−{{amount}} Gutschein",
318
318
  "voucher.remaining": "Rest: {{amount}}",
319
319
  "voucher.remove": "Entfernen",
320
- "voucher.alreadyHasDiscount": "Es wurde bereits ein Rabattcode angewendet. Du kannst weitere Gutscheine hinzufügen.",
320
+ "voucher.alreadyHasDiscount": "Du kannst weitere Gutscheine hinzufügen.",
321
321
  // Booking success
322
322
  "success.title": "Reservierung erfolgreich!",
323
323
  "success.bookingDetails": "Buchungsdetails",
@@ -412,7 +412,7 @@ const en = {
412
412
  "error.loadBookingData": "Error fetching booking data",
413
413
  "error.processingError": "An error occurred during processing.",
414
414
  "error.createBooking": "Error creating booking",
415
- "error.createPaymentIntent": "Error creating payment intent",
415
+ "error.createPayment": "Error creating payment",
416
416
  "error.paymentProcessing": "Error processing payment",
417
417
  "error.paymentFailed": "The payment was not successful. Please try again.",
418
418
  "error.paymentIncomplete": "The payment could not be completed. Please try again.",
@@ -621,7 +621,7 @@ const es = {
621
621
  "error.loadBookingData": "Error al obtener datos de la reserva",
622
622
  "error.processingError": "Ocurrió un error durante el procesamiento.",
623
623
  "error.createBooking": "Error al crear la reserva",
624
- "error.createPaymentIntent": "Error al crear la intención de pago",
624
+ "error.createPayment": "Error al crear el pago",
625
625
  "error.paymentProcessing": "Error al procesar el pago",
626
626
  "error.paymentFailed": "El pago no fue exitoso. Por favor, inténtalo de nuevo.",
627
627
  "error.paymentIncomplete": "El pago no pudo completarse. Por favor, inténtalo de nuevo.",
@@ -830,7 +830,7 @@ const pt = {
830
830
  "error.loadBookingData": "Erro ao obter dados da reserva",
831
831
  "error.processingError": "Ocorreu um erro durante o processamento.",
832
832
  "error.createBooking": "Erro ao criar reserva",
833
- "error.createPaymentIntent": "Erro ao criar intenção de pagamento",
833
+ "error.createPayment": "Erro ao criar pagamento",
834
834
  "error.paymentProcessing": "Erro ao processar pagamento",
835
835
  "error.paymentFailed": "O pagamento não foi bem-sucedido. Por favor, tente novamente.",
836
836
  "error.paymentIncomplete": "O pagamento não pôde ser concluído. Por favor, tente novamente.",
@@ -1039,7 +1039,7 @@ const sv = {
1039
1039
  "error.loadBookingData": "Fel vid hämtning av bokningsdata",
1040
1040
  "error.processingError": "Ett fel uppstod vid bearbetningen.",
1041
1041
  "error.createBooking": "Fel vid skapande av bokning",
1042
- "error.createPaymentIntent": "Fel vid skapande av betalningsavsikt",
1042
+ "error.createPayment": "Fel vid skapande av betalning",
1043
1043
  "error.paymentProcessing": "Fel vid bearbetning av betalning",
1044
1044
  "error.paymentFailed": "Betalningen lyckades inte. Försök igen.",
1045
1045
  "error.paymentIncomplete": "Betalningen kunde inte slutföras. Försök igen.",
@@ -4398,6 +4398,108 @@ const IconChevronLeft = ({ size = 20, color = "white", className, }) => (jsx("sv
4398
4398
  // Chevron Right icon - used for carousel navigation
4399
4399
  const IconChevronRight = ({ size = 20, color = "white", className, }) => (jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: jsx("polyline", { points: "9 18 15 12 9 6" }) }));
4400
4400
 
4401
+ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
4402
+ const t = useTranslations();
4403
+ const [isLoading, setIsLoading] = useState(false);
4404
+ const [error, setError] = useState(null);
4405
+ const handleBooking = async () => {
4406
+ setIsLoading(true);
4407
+ setError(null);
4408
+ try {
4409
+ const requestData = {
4410
+ eventInstanceId: config.eventInstanceId || eventDetails.id,
4411
+ organizationId: config.organizationId,
4412
+ participants: formData.participants.filter((p) => p.name?.trim()),
4413
+ discountCode: discountCode?.code,
4414
+ giftCardCodes: giftCards.map((gc) => gc.code),
4415
+ customerName: formData.customerName?.trim(),
4416
+ customerEmail: formData.customerEmail?.trim(),
4417
+ customerPhone: formData.customerPhone?.trim(),
4418
+ comment: formData.comment?.trim(),
4419
+ paymentMethod: "gift_card",
4420
+ ...(upsellSelections.length > 0 && { upsellSelections }),
4421
+ };
4422
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
4423
+ method: "POST",
4424
+ headers: createApiHeaders(config),
4425
+ body: JSON.stringify(createRequestBody(config, requestData)),
4426
+ });
4427
+ const data = await response.json();
4428
+ if (response.ok) {
4429
+ onSuccess({
4430
+ booking: data.booking,
4431
+ order: data.order,
4432
+ giftCardRedemptions: data.giftCardRedemptions,
4433
+ });
4434
+ }
4435
+ else {
4436
+ setError(data.error || t("error.createBooking"));
4437
+ onError(data.error || t("error.createBooking"));
4438
+ }
4439
+ }
4440
+ catch (err) {
4441
+ setError(err.message || t("error.createBooking"));
4442
+ onError(err.message || t("error.createBooking"));
4443
+ }
4444
+ finally {
4445
+ setIsLoading(false);
4446
+ }
4447
+ };
4448
+ const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4449
+ return (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxs("div", { style: {
4450
+ backgroundColor: "rgba(var(--bw-success-color), 0.15)",
4451
+ border: "1px solid rgba(var(--bw-success-color), 0.4)",
4452
+ borderRadius: "var(--bw-border-radius)",
4453
+ padding: "16px",
4454
+ }, children: [jsxs("div", { style: {
4455
+ display: "flex",
4456
+ alignItems: "center",
4457
+ gap: "8px",
4458
+ marginBottom: "8px",
4459
+ color: "var(--bw-success-color)",
4460
+ fontFamily: "var(--bw-font-family)",
4461
+ fontWeight: 600,
4462
+ }, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), jsx("div", { style: {
4463
+ fontSize: "16px",
4464
+ color: "var(--bw-text-muted)",
4465
+ fontFamily: "var(--bw-font-family)",
4466
+ }, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (jsxs("div", { style: {
4467
+ backgroundColor: "rgba(var(--bw-error-color), 0.15)",
4468
+ border: "1px solid rgba(var(--bw-error-color), 0.4)",
4469
+ borderRadius: "var(--bw-border-radius)",
4470
+ padding: "16px",
4471
+ color: "var(--bw-error-color)",
4472
+ fontSize: "16px",
4473
+ fontFamily: "var(--bw-font-family)",
4474
+ }, children: ["\u26A0\uFE0F ", error] })), jsx("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
4475
+ width: "100%",
4476
+ padding: "12px 24px",
4477
+ backgroundColor: "var(--bw-highlight-color)",
4478
+ color: "#ffffff",
4479
+ border: "none",
4480
+ borderRadius: "var(--bw-border-radius)",
4481
+ fontSize: "16px",
4482
+ fontWeight: 600,
4483
+ fontFamily: "var(--bw-font-family)",
4484
+ transition: "all 0.2s ease",
4485
+ display: "flex",
4486
+ alignItems: "center",
4487
+ justifyContent: "center",
4488
+ gap: "8px",
4489
+ cursor: isLoading ? "not-allowed" : "pointer",
4490
+ opacity: isLoading ? 0.6 : 1,
4491
+ }, children: isLoading ? (jsxs(Fragment, { children: [spinner("#ffffff"), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
4492
+ }
4493
+ /**
4494
+ * Calculate whether gift cards fully cover the order after discounts.
4495
+ */
4496
+ function isGiftCardFullyCovered(giftCards, eventPrice, participantCount, discountAmount) {
4497
+ const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4498
+ const baseTotal = eventPrice * participantCount;
4499
+ const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
4500
+ return totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
4501
+ }
4502
+
4401
4503
  const mollieLocaleMap = {
4402
4504
  de: "de_DE",
4403
4505
  en: "en_US",
@@ -4458,13 +4560,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4458
4560
  const mollieRef = useRef(null);
4459
4561
  const cardFormRef = useRef(null);
4460
4562
  const cardContainerRef = useRef(null);
4461
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
4462
- const baseTotal = eventDetails?.price
4463
- ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
4464
- : 0;
4465
- const discountAmount = discountCode?.discountAmount || 0;
4466
- const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
4467
- const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
4563
+ const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
4564
+ const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
4468
4565
  const isCreditCard = selectedMethod === "creditcard";
4469
4566
  useEffect(() => {
4470
4567
  if (isFullyCoveredByGiftCards)
@@ -4571,7 +4668,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4571
4668
  };
4572
4669
  }, [isCreditCard, mollieProfileId, mollieTestmode, isFullyCoveredByGiftCards]);
4573
4670
  if (isFullyCoveredByGiftCards && totalAmount <= 0) {
4574
- return null;
4671
+ return (jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: _onSuccess, onError: onError, upsellSelections: upsellSelections }));
4575
4672
  }
4576
4673
  const validateBeforePayment = () => {
4577
4674
  const participantCount = formData.participants.filter((p) => p.name?.trim()).length;
@@ -4613,7 +4710,7 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4613
4710
  }
4614
4711
  const { token, error: tokenError } = await mollieRef.current.createToken();
4615
4712
  if (tokenError || !token) {
4616
- setPaymentError(tokenError?.message || t("error.createPaymentIntent"));
4713
+ setPaymentError(tokenError?.message || t("error.createPayment"));
4617
4714
  return;
4618
4715
  }
4619
4716
  const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-mollie-payment"), {
@@ -4629,8 +4726,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4629
4726
  _onSuccess({ paymentIntent: { id: data.molliePaymentId } });
4630
4727
  }
4631
4728
  else {
4632
- setPaymentError(data.error || t("error.createPaymentIntent"));
4633
- onError(data.error || t("error.createPaymentIntent"));
4729
+ setPaymentError(data.error || t("error.createPayment"));
4730
+ onError(data.error || t("error.createPayment"));
4634
4731
  }
4635
4732
  }
4636
4733
  catch (err) {
@@ -4662,8 +4759,8 @@ function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discou
4662
4759
  window.location.href = data.checkoutUrl;
4663
4760
  }
4664
4761
  else {
4665
- setPaymentError(data.error || t("error.createPaymentIntent"));
4666
- onError(data.error || t("error.createPaymentIntent"));
4762
+ setPaymentError(data.error || t("error.createPayment"));
4763
+ onError(data.error || t("error.createPayment"));
4667
4764
  }
4668
4765
  }
4669
4766
  catch (err) {
@@ -6133,106 +6230,6 @@ var reactStripe_umd = {exports: {}};
6133
6230
 
6134
6231
  var reactStripe_umdExports = reactStripe_umd.exports;
6135
6232
 
6136
- // Component for bookings fully covered by gift cards (no Stripe payment needed)
6137
- function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
6138
- const t = useTranslations();
6139
- const [isLoading, setIsLoading] = useState(false);
6140
- const [error, setError] = useState(null);
6141
- const handleBooking = async () => {
6142
- setIsLoading(true);
6143
- setError(null);
6144
- try {
6145
- const requestData = {
6146
- eventInstanceId: config.eventInstanceId || eventDetails.id,
6147
- organizationId: config.organizationId,
6148
- participants: formData.participants.filter((p) => p.name?.trim()),
6149
- discountCode: discountCode?.code,
6150
- giftCardCodes: giftCards.map((gc) => gc.code),
6151
- customerName: formData.customerName?.trim(),
6152
- customerEmail: formData.customerEmail?.trim(),
6153
- customerPhone: formData.customerPhone?.trim(),
6154
- comment: formData.comment?.trim(),
6155
- paymentMethod: "gift_card",
6156
- ...(upsellSelections.length > 0 && { upsellSelections }),
6157
- };
6158
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
6159
- method: "POST",
6160
- headers: createApiHeaders(config),
6161
- body: JSON.stringify(createRequestBody(config, requestData)),
6162
- });
6163
- const data = await response.json();
6164
- if (response.ok) {
6165
- onSuccess({
6166
- booking: data.booking,
6167
- order: data.order,
6168
- giftCardRedemptions: data.giftCardRedemptions,
6169
- });
6170
- }
6171
- else {
6172
- setError(data.error || t("error.createBooking"));
6173
- onError(data.error || t("error.createBooking"));
6174
- }
6175
- }
6176
- catch (err) {
6177
- setError(err.message || t("error.createBooking"));
6178
- onError(err.message || t("error.createBooking"));
6179
- }
6180
- finally {
6181
- setIsLoading(false);
6182
- }
6183
- };
6184
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
6185
- return (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxs("div", { style: {
6186
- backgroundColor: "rgba(var(--bw-success-color), 0.15)",
6187
- border: "1px solid rgba(var(--bw-success-color), 0.4)",
6188
- borderRadius: "var(--bw-border-radius)",
6189
- padding: "16px",
6190
- }, children: [jsxs("div", { style: {
6191
- display: "flex",
6192
- alignItems: "center",
6193
- gap: "8px",
6194
- marginBottom: "8px",
6195
- color: "var(--bw-success-color)",
6196
- fontFamily: "var(--bw-font-family)",
6197
- fontWeight: 600,
6198
- }, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), jsx("div", { style: {
6199
- fontSize: "16px",
6200
- color: "var(--bw-text-muted)",
6201
- fontFamily: "var(--bw-font-family)",
6202
- }, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (jsxs("div", { style: {
6203
- backgroundColor: "rgba(var(--bw-error-color), 0.15)",
6204
- border: "1px solid rgba(var(--bw-error-color), 0.4)",
6205
- borderRadius: "var(--bw-border-radius)",
6206
- padding: "16px",
6207
- color: "var(--bw-error-color)",
6208
- fontSize: "16px",
6209
- fontFamily: "var(--bw-font-family)",
6210
- }, children: ["\u26A0\uFE0F ", error] })), jsx("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
6211
- width: "100%",
6212
- padding: "12px 24px",
6213
- backgroundColor: "var(--bw-highlight-color)",
6214
- color: "#ffffff",
6215
- border: "none",
6216
- borderRadius: "var(--bw-border-radius)",
6217
- fontSize: "16px",
6218
- fontWeight: 600,
6219
- fontFamily: "var(--bw-font-family)",
6220
- transition: "all 0.2s ease",
6221
- display: "flex",
6222
- alignItems: "center",
6223
- justifyContent: "center",
6224
- gap: "8px",
6225
- cursor: isLoading ? "not-allowed" : "pointer",
6226
- opacity: isLoading ? 0.6 : 1,
6227
- }, children: isLoading ? (jsxs(Fragment, { children: [jsx("div", { style: {
6228
- width: "16px",
6229
- height: "16px",
6230
- border: "2px solid #ffffff",
6231
- borderTopColor: "transparent",
6232
- borderRadius: "50%",
6233
- animation: "spin 1s linear infinite",
6234
- } }), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
6235
- }
6236
6233
  // Inner component that uses the Stripe hooks
6237
6234
  function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSuccess, onError, }) {
6238
6235
  const t = useTranslations();
@@ -6269,7 +6266,7 @@ function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSucce
6269
6266
  redirect: "if_required",
6270
6267
  });
6271
6268
  if (error) {
6272
- console.error("[PAYMENT_FORM] Payment confirmation error:", {
6269
+ console.error("[STRIPE_PAYMENT] Payment confirmation error:", {
6273
6270
  type: error.type,
6274
6271
  code: error.code,
6275
6272
  message: error.message,
@@ -6345,8 +6342,7 @@ function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSucce
6345
6342
  ? t("button.depositAndBook")
6346
6343
  : t("button.bookNow") })) })] }));
6347
6344
  }
6348
- // Main PaymentForm component that handles payment intent creation and Elements wrapper
6349
- function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
6345
+ function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
6350
6346
  const t = useTranslations();
6351
6347
  const [clientSecret, setClientSecret] = useState(null);
6352
6348
  const [paymentIntentId, setPaymentIntentId] = useState(null);
@@ -6407,7 +6403,7 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6407
6403
  }
6408
6404
  }, [paymentIntentId]);
6409
6405
  useEffect(() => {
6410
- const createPaymentIntent = async () => {
6406
+ const createStripePayment = async () => {
6411
6407
  if (!systemConfig || !eventDetails || !formData.participants?.length) {
6412
6408
  return;
6413
6409
  }
@@ -6448,35 +6444,38 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6448
6444
  if (!requestData.customerEmail) {
6449
6445
  throw new Error("Customer email is required");
6450
6446
  }
6451
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-payment-intent"), {
6447
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-stripe-payment"), {
6452
6448
  method: "POST",
6453
6449
  headers: createApiHeaders(config),
6454
6450
  body: JSON.stringify(createRequestBody(config, requestData)),
6455
6451
  });
6456
6452
  const data = await response.json();
6457
6453
  if (response.ok) {
6454
+ if (data.stalePaymentIntent) {
6455
+ clearPersistedPaymentIntent();
6456
+ }
6458
6457
  setClientSecret(data.clientSecret);
6459
6458
  setPaymentIntentId(data.paymentIntentId);
6460
6459
  }
6461
6460
  else {
6462
- console.error("[PAYMENT_FORM] Payment intent creation failed:", {
6461
+ console.error("[STRIPE_PAYMENT] Payment creation failed:", {
6463
6462
  status: response.status,
6464
6463
  error: data.error,
6465
6464
  details: data.details,
6466
6465
  requestData: { ...requestData, customerEmail: "[redacted]" },
6467
6466
  });
6468
- setPaymentError(data.error || t("error.createPaymentIntent"));
6467
+ setPaymentError(data.error || t("error.createPayment"));
6469
6468
  }
6470
6469
  }
6471
6470
  catch (err) {
6472
- console.error("[PAYMENT_FORM] Payment intent creation error:", err);
6473
- setPaymentError(err.message || t("error.createPaymentIntent"));
6471
+ console.error("[STRIPE_PAYMENT] Payment creation error:", err);
6472
+ setPaymentError(err.message || t("error.createPayment"));
6474
6473
  }
6475
6474
  finally {
6476
6475
  setIsCreatingPaymentIntent(false);
6477
6476
  }
6478
6477
  };
6479
- const timer = setTimeout(createPaymentIntent, 500);
6478
+ const timer = setTimeout(createStripePayment, 500);
6480
6479
  return () => clearTimeout(timer);
6481
6480
  }, [
6482
6481
  systemConfig,
@@ -6491,13 +6490,8 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6491
6490
  config,
6492
6491
  upsellSelections,
6493
6492
  ]);
6494
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
6495
- const baseTotal = eventDetails?.price
6496
- ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
6497
- : 0;
6498
- const discountAmount = discountCode?.discountAmount || 0;
6499
- const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
6500
- const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
6493
+ const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
6494
+ const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
6501
6495
  if (isFullyCoveredByGiftCards && totalAmount <= 0) {
6502
6496
  return (jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
6503
6497
  }
@@ -11007,13 +11001,6 @@ function mergeStyles(...styles) {
11007
11001
  return Object.assign({}, ...styles.filter(Boolean));
11008
11002
  }
11009
11003
 
11010
- function getEffectivePrice(upsell, round) {
11011
- const dp = upsell.discountPercent ?? 0;
11012
- if (dp <= 0)
11013
- return upsell.price;
11014
- const raw = Math.round(upsell.price * (100 - dp) / 100);
11015
- return round ? Math.floor(raw / 100) * 100 : raw;
11016
- }
11017
11004
  // Local style aliases from shared styles
11018
11005
  const cardStyles = cardStyles$1.base;
11019
11006
  const sectionHeaderStyles = sectionStyles.header;
@@ -11025,6 +11012,11 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11025
11012
  const { locale } = useLocale();
11026
11013
  const timezone = useTimezone();
11027
11014
  const roundEnabled = systemConfig?.roundPricesEnabled !== false;
11015
+ const roundDiscountUp = (minorUnits) => Math.ceil(minorUnits / 100) * 100;
11016
+ const calcPercentDiscountAmount = (baseAmount, basisPoints, round) => {
11017
+ const raw = Math.round((baseAmount * basisPoints) / 10000);
11018
+ return round ? roundDiscountUp(raw) : raw;
11019
+ };
11028
11020
  const [appliedVouchers, setAppliedVouchers] = useState([]);
11029
11021
  const paymentSectionRef = useRef(null);
11030
11022
  // Payment option: "deposit" or "full" - only relevant when deposit is available
@@ -11097,7 +11089,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11097
11089
  participantUpsellIds.forEach(upsellId => {
11098
11090
  const upsell = upsells.find(u => u.id === upsellId);
11099
11091
  if (upsell) {
11100
- total += getEffectivePrice(upsell, roundEnabled);
11092
+ total += upsell.price;
11101
11093
  }
11102
11094
  });
11103
11095
  }
@@ -11202,7 +11194,10 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11202
11194
  // TODO: discounts currently apply to base total only; extend when discount-applies-to-upsells flag is added
11203
11195
  let newDiscountAmount = 0;
11204
11196
  if (voucher.discountType === "percentage") {
11205
- newDiscountAmount = Math.round((newBaseTotal * (voucher.discountValue || 0)) / 10000);
11197
+ newDiscountAmount = calcPercentDiscountAmount(newBaseTotal, voucher.discountValue || 0, roundEnabled);
11198
+ if (voucher.restrictions?.maxDiscount) {
11199
+ newDiscountAmount = Math.min(newDiscountAmount, voucher.restrictions.maxDiscount);
11200
+ }
11206
11201
  }
11207
11202
  else {
11208
11203
  newDiscountAmount = voucher.discountValue || 0;
@@ -11380,7 +11375,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11380
11375
  padding: 0,
11381
11376
  }, children: "\u00D7" })] }))] }), upsells.length > 0 && (jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11382
11377
  const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11383
- return (jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(getEffectivePrice(upsell, roundEnabled)), ")"] })] }, upsell.id));
11378
+ return (jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11384
11379
  }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsx("div", { style: {
11385
11380
  display: "flex",
11386
11381
  flexDirection: "column",
@@ -11412,7 +11407,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11412
11407
  const countWithUpsell = watchedParticipants.filter((p, idx) => p.name.trim() && (participantUpsells[idx] || []).includes(upsell.id)).length;
11413
11408
  if (countWithUpsell === 0)
11414
11409
  return null;
11415
- const upsellLineTotal = getEffectivePrice(upsell, roundEnabled) * countWithUpsell;
11410
+ const upsellLineTotal = upsell.price * countWithUpsell;
11416
11411
  return (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px" }, children: [jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }, upsell.id));
11417
11412
  })] })), appliedVouchers.length > 0 && (jsxs(Fragment, { children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), jsx("span", { style: {
11418
11413
  fontFamily: "var(--bw-font-family)",
@@ -11557,7 +11552,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11557
11552
  if (systemConfig?.paymentProvider === "mollie") {
11558
11553
  return (jsxs("div", { style: cardStyles, children: [jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] }));
11559
11554
  }
11560
- return (jsxs("div", { style: cardStyles, children: [jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), 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() })] }));
11555
+ return (jsxs("div", { style: cardStyles, children: [jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] }));
11561
11556
  })() })] })] })] }) }));
11562
11557
  }
11563
11558
 
@@ -11691,7 +11686,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11691
11686
  if (targetPaymentIntentId) {
11692
11687
  setIsLoading(true);
11693
11688
  try {
11694
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment-intent"), {
11689
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment"), {
11695
11690
  method: "POST",
11696
11691
  headers: createApiHeaders(config),
11697
11692
  body: JSON.stringify(createRequestBody(config, {
@@ -11707,7 +11702,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11707
11702
  orderItems: data.orderItems,
11708
11703
  purchases: data.purchases || [],
11709
11704
  discount: data.discount || null,
11710
- stripePaymentIntent: data.stripePaymentIntent,
11705
+ providerPaymentDetails: data.stripePaymentIntent,
11711
11706
  });
11712
11707
  setEventDetails({
11713
11708
  id: data.booking.eventInstance.id,
@@ -11715,7 +11710,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11715
11710
  description: data.booking.eventInstance.eventType.description,
11716
11711
  startTime: data.booking.eventInstance.startTime,
11717
11712
  endTime: data.booking.eventInstance.endTime,
11718
- price: data.booking.eventInstance.price || 0, // Use actual event instance price
11713
+ price: data.booking.eventInstance.price || 0,
11719
11714
  });
11720
11715
  setFormData({
11721
11716
  customerEmail: data.booking.customerEmail,
@@ -11723,9 +11718,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11723
11718
  customerPhone: data.booking.customerPhone,
11724
11719
  participants: data.booking.participants || [],
11725
11720
  });
11726
- // Set payment status from Stripe data or order status
11727
11721
  setPaymentStatus(data.stripePaymentIntent?.status || data.order.status);
11728
- // Trigger Google Ads conversion tracking if payment is successful
11729
11722
  const finalPaymentStatus = data.stripePaymentIntent?.status || data.order.status;
11730
11723
  if (finalPaymentStatus === "succeeded" &&
11731
11724
  config.googleAds?.tagId &&
@@ -13675,11 +13668,10 @@ function formatUnavailableReason(reason, t) {
13675
13668
  return t("upsells.reason.notEnoughSpots", { eventTypeName: reason.eventTypeName });
13676
13669
  }
13677
13670
  }
13678
- function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPricesEnabled = true, }) {
13671
+ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
13679
13672
  const t = useTranslations();
13680
13673
  const { locale } = useLocale();
13681
- const effectivePrice = getEffectiveUpsellPrice(upsell, roundPricesEnabled);
13682
- const totalPrice = effectivePrice * participantCount;
13674
+ const totalPrice = upsell.price * participantCount;
13683
13675
  const isDisabled = !upsell.available;
13684
13676
  const getCardStyles = () => {
13685
13677
  if (isDisabled)
@@ -13697,19 +13689,12 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPrice
13697
13689
  weekday: "short",
13698
13690
  day: "numeric",
13699
13691
  month: "short",
13700
- })] }), jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxs("div", { style: priceContainerStyles, children: [jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(effectivePrice), "/", t("common.perPerson")] }), participantCount > 1 && (jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsx("div", { style: unavailableOverlayStyles, children: jsx("span", { children: upsell.unavailableReason
13692
+ })] }), jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxs("div", { style: priceContainerStyles, children: [jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsx("div", { style: unavailableOverlayStyles, children: jsx("span", { children: upsell.unavailableReason
13701
13693
  ? formatUnavailableReason(upsell.unavailableReason, t)
13702
13694
  : t("upsells.notAvailable") }) }))] }));
13703
13695
  }
13704
13696
 
13705
- function getEffectiveUpsellPrice(upsell, round = true) {
13706
- const dp = upsell.discountPercent ?? 0;
13707
- if (dp <= 0)
13708
- return upsell.price;
13709
- const raw = Math.round(upsell.price * (100 - dp) / 100);
13710
- return round ? Math.floor(raw / 100) * 100 : raw;
13711
- }
13712
- function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, roundPricesEnabled = true, }) {
13697
+ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, }) {
13713
13698
  const t = useTranslations();
13714
13699
  const selectUpsell = (upsellId) => {
13715
13700
  const exists = selectedUpsells.find((s) => s.upsellPackageId === upsellId);
@@ -13728,7 +13713,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13728
13713
  return selectedUpsells.reduce((total, selection) => {
13729
13714
  const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
13730
13715
  if (upsell) {
13731
- return total + getEffectiveUpsellPrice(upsell, roundPricesEnabled) * selection.quantity;
13716
+ return total + upsell.price * selection.quantity;
13732
13717
  }
13733
13718
  return total;
13734
13719
  }, 0);
@@ -13736,7 +13721,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13736
13721
  const selectedTotal = calculateTotal();
13737
13722
  const selectedCount = selectedUpsells.length;
13738
13723
  const footerContent = (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: onBack, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: t("common.back") }), jsx("button", { type: "button", onClick: onContinue, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: selectedCount === 0 ? t("button.continueWithout") : t("button.continue") })] }));
13739
- return (jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id), roundPricesEnabled: roundPricesEnabled }, upsell.id))) })), selectedCount > 0 && (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: [jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
13724
+ return (jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (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: [jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
13740
13725
  }
13741
13726
 
13742
13727
  // Main widget component
@@ -13782,7 +13767,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13782
13767
  const [isLoadingShowAll, setIsLoadingShowAll] = useState(false);
13783
13768
  const [error, setError] = useState(null);
13784
13769
  const [isSuccess, setIsSuccess] = useState(false);
13785
- const [successPaymentIntentId, setSuccessPaymentIntentId] = useState(null);
13770
+ const [successPaymentId, setSuccessPaymentId] = useState(null);
13786
13771
  const [systemConfig, setSystemConfig] = useState(null);
13787
13772
  // PERFORMANCE OPTIMIZATION: Lazy component loading
13788
13773
  const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = useState(false);
@@ -13848,7 +13833,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13848
13833
  const stripeReturn = detectStripeReturn();
13849
13834
  if (stripeReturn) {
13850
13835
  if (stripeReturn.redirectStatus === "succeeded") {
13851
- setSuccessPaymentIntentId(stripeReturn.paymentIntent);
13836
+ setSuccessPaymentId(stripeReturn.paymentIntent);
13852
13837
  setIsSuccess(true);
13853
13838
  }
13854
13839
  else if (stripeReturn.redirectStatus === "failed") {
@@ -14203,7 +14188,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14203
14188
  };
14204
14189
  const handleBookingSuccess = (result) => {
14205
14190
  setIsSuccess(true);
14206
- setSuccessPaymentIntentId(result.paymentIntent.id);
14191
+ setSuccessPaymentId(result.paymentIntent.id);
14207
14192
  setSidebarOpen(false);
14208
14193
  setShouldRenderBookingForm(false);
14209
14194
  config.onSuccess?.(result);
@@ -14401,7 +14386,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14401
14386
  setIsSuccess(false);
14402
14387
  setCurrentStep("eventTypes");
14403
14388
  setShowingPreview(true);
14404
- setSuccessPaymentIntentId(null);
14389
+ setSuccessPaymentId(null);
14405
14390
  setShouldRenderInstanceSelection(false);
14406
14391
  setShouldRenderUpsells(false);
14407
14392
  setShouldRenderBookingForm(false);
@@ -14412,7 +14397,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14412
14397
  url.searchParams.delete("payment_intent_client_secret");
14413
14398
  url.searchParams.delete("redirect_status");
14414
14399
  window.history.replaceState({}, "", url.toString());
14415
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14400
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14416
14401
  }
14417
14402
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
14418
14403
  return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
@@ -14425,7 +14410,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14425
14410
  setIsSuccess(false);
14426
14411
  setCurrentStep("eventTypes");
14427
14412
  setShowingPreview(true);
14428
- setSuccessPaymentIntentId(null);
14413
+ setSuccessPaymentId(null);
14429
14414
  setShouldRenderInstanceSelection(false);
14430
14415
  setShouldRenderBookingForm(false);
14431
14416
  const url = new URL(window.location.href);
@@ -14433,7 +14418,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14433
14418
  url.searchParams.delete("payment_intent_client_secret");
14434
14419
  url.searchParams.delete("redirect_status");
14435
14420
  window.history.replaceState({}, "", url.toString());
14436
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14421
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14437
14422
  }
14438
14423
  if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
14439
14424
  return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, style: {
@@ -14462,11 +14447,11 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14462
14447
  setShouldRenderInstanceSelection(true);
14463
14448
  }
14464
14449
  }, children: config.buttonText ||
14465
- (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (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 && (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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14450
+ (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14466
14451
  setIsSuccess(false);
14467
14452
  setCurrentStep("eventTypes");
14468
14453
  setSidebarOpen(false);
14469
- setSuccessPaymentIntentId(null);
14454
+ setSuccessPaymentId(null);
14470
14455
  setShouldRenderInstanceSelection(false);
14471
14456
  setShouldRenderUpsells(false);
14472
14457
  setShouldRenderBookingForm(false);
@@ -14477,7 +14462,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14477
14462
  url.searchParams.delete("payment_intent_client_secret");
14478
14463
  url.searchParams.delete("redirect_status");
14479
14464
  window.history.replaceState({}, "", url.toString());
14480
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14465
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14481
14466
  }
14482
14467
  // Cards mode (default) - show event type selection
14483
14468
  const cardsView = (jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
@@ -14509,10 +14494,10 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14509
14494
  };
14510
14495
  };
14511
14496
  const backHandlers = getBackHandlers();
14512
- return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (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 && (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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14497
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
14513
14498
  setIsSuccess(false);
14514
14499
  setCurrentStep("eventTypes");
14515
- setSuccessPaymentIntentId(null);
14500
+ setSuccessPaymentId(null);
14516
14501
  setShouldRenderInstanceSelection(false);
14517
14502
  setShouldRenderUpsells(false);
14518
14503
  setShouldRenderBookingForm(false);
@@ -14523,7 +14508,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14523
14508
  url.searchParams.delete("payment_intent_client_secret");
14524
14509
  url.searchParams.delete("redirect_status");
14525
14510
  window.history.replaceState({}, "", url.toString());
14526
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14511
+ }, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
14527
14512
  }
14528
14513
  function UniversalBookingWidget(props) {
14529
14514
  const [languagePolicy, setLanguagePolicy] = useState(null);