@bigz-app/booking-widget 1.1.6 → 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 +176 -181
  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 +176 -181
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.esm.js +176 -181
  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,
@@ -6484,19 +6483,15 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
6484
6483
  formData.participants,
6485
6484
  formData.customerEmail,
6486
6485
  formData.customerName,
6486
+ formData.comment,
6487
6487
  totalAmount,
6488
6488
  discountCode,
6489
6489
  giftCards,
6490
6490
  config,
6491
6491
  upsellSelections,
6492
6492
  ]);
6493
- const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
6494
- const baseTotal = eventDetails?.price
6495
- ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
6496
- : 0;
6497
- const discountAmount = discountCode?.discountAmount || 0;
6498
- const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
6499
- 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);
6500
6495
  if (isFullyCoveredByGiftCards && totalAmount <= 0) {
6501
6496
  return (jsx(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
6502
6497
  }
@@ -11006,13 +11001,6 @@ function mergeStyles(...styles) {
11006
11001
  return Object.assign({}, ...styles.filter(Boolean));
11007
11002
  }
11008
11003
 
11009
- function getEffectivePrice(upsell, round) {
11010
- const dp = upsell.discountPercent ?? 0;
11011
- if (dp <= 0)
11012
- return upsell.price;
11013
- const raw = Math.round(upsell.price * (100 - dp) / 100);
11014
- return round ? Math.floor(raw / 100) * 100 : raw;
11015
- }
11016
11004
  // Local style aliases from shared styles
11017
11005
  const cardStyles = cardStyles$1.base;
11018
11006
  const sectionHeaderStyles = sectionStyles.header;
@@ -11024,6 +11012,11 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11024
11012
  const { locale } = useLocale();
11025
11013
  const timezone = useTimezone();
11026
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
+ };
11027
11020
  const [appliedVouchers, setAppliedVouchers] = useState([]);
11028
11021
  const paymentSectionRef = useRef(null);
11029
11022
  // Payment option: "deposit" or "full" - only relevant when deposit is available
@@ -11045,6 +11038,8 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11045
11038
  const watchedParticipants = form.watch("participants");
11046
11039
  const watchedCustomerName = form.watch("customerName");
11047
11040
  const watchedCustomerEmail = form.watch("customerEmail");
11041
+ const watchedComment = form.watch("comment");
11042
+ const watchedCustomerPhone = form.watch("customerPhone");
11048
11043
  const customerNameError = form.formState.errors.customerName;
11049
11044
  const customerEmailError = form.formState.errors.customerEmail;
11050
11045
  const watchedAcceptTerms = form.watch("acceptTerms");
@@ -11094,7 +11089,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11094
11089
  participantUpsellIds.forEach(upsellId => {
11095
11090
  const upsell = upsells.find(u => u.id === upsellId);
11096
11091
  if (upsell) {
11097
- total += getEffectivePrice(upsell, roundEnabled);
11092
+ total += upsell.price;
11098
11093
  }
11099
11094
  });
11100
11095
  }
@@ -11156,6 +11151,13 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11156
11151
  participantIndices,
11157
11152
  }));
11158
11153
  }, [participantUpsells, watchedParticipants]);
11154
+ const paymentFormData = useMemo(() => ({
11155
+ customerName: watchedCustomerName,
11156
+ customerEmail: watchedCustomerEmail,
11157
+ customerPhone: watchedCustomerPhone,
11158
+ participants: watchedParticipants,
11159
+ comment: watchedComment,
11160
+ }), [watchedCustomerName, watchedCustomerEmail, watchedCustomerPhone, watchedParticipants, watchedComment]);
11159
11161
  const appliedDiscountCode = appliedVouchers.find((v) => v.type === "discount");
11160
11162
  const appliedGiftCards = appliedVouchers.filter((v) => v.type === "giftCard");
11161
11163
  const handleVoucherValidated = useCallback((voucher, _error) => {
@@ -11192,7 +11194,10 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11192
11194
  // TODO: discounts currently apply to base total only; extend when discount-applies-to-upsells flag is added
11193
11195
  let newDiscountAmount = 0;
11194
11196
  if (voucher.discountType === "percentage") {
11195
- 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
+ }
11196
11201
  }
11197
11202
  else {
11198
11203
  newDiscountAmount = voucher.discountValue || 0;
@@ -11370,7 +11375,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11370
11375
  padding: 0,
11371
11376
  }, children: "\u00D7" })] }))] }), upsells.length > 0 && (jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11372
11377
  const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11373
- 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));
11374
11379
  }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsx("div", { style: {
11375
11380
  display: "flex",
11376
11381
  flexDirection: "column",
@@ -11402,7 +11407,7 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11402
11407
  const countWithUpsell = watchedParticipants.filter((p, idx) => p.name.trim() && (participantUpsells[idx] || []).includes(upsell.id)).length;
11403
11408
  if (countWithUpsell === 0)
11404
11409
  return null;
11405
- const upsellLineTotal = getEffectivePrice(upsell, roundEnabled) * countWithUpsell;
11410
+ const upsellLineTotal = upsell.price * countWithUpsell;
11406
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));
11407
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: {
11408
11413
  fontFamily: "var(--bw-font-family)",
@@ -11545,9 +11550,9 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11545
11550
  }
11546
11551
  : null;
11547
11552
  if (systemConfig?.paymentProvider === "mollie") {
11548
- return (jsxs("div", { style: cardStyles, children: [jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: form.getValues(), totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] }));
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 })] }));
11549
11554
  }
11550
- return (jsxs("div", { style: cardStyles, children: [jsx("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), jsx(PaymentForm, { config: config, eventDetails: eventDetails, formData: form.getValues(), 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() })] }));
11551
11556
  })() })] })] })] }) }));
11552
11557
  }
11553
11558
 
@@ -11681,7 +11686,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11681
11686
  if (targetPaymentIntentId) {
11682
11687
  setIsLoading(true);
11683
11688
  try {
11684
- 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"), {
11685
11690
  method: "POST",
11686
11691
  headers: createApiHeaders(config),
11687
11692
  body: JSON.stringify(createRequestBody(config, {
@@ -11697,7 +11702,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11697
11702
  orderItems: data.orderItems,
11698
11703
  purchases: data.purchases || [],
11699
11704
  discount: data.discount || null,
11700
- stripePaymentIntent: data.stripePaymentIntent,
11705
+ providerPaymentDetails: data.stripePaymentIntent,
11701
11706
  });
11702
11707
  setEventDetails({
11703
11708
  id: data.booking.eventInstance.id,
@@ -11705,7 +11710,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11705
11710
  description: data.booking.eventInstance.eventType.description,
11706
11711
  startTime: data.booking.eventInstance.startTime,
11707
11712
  endTime: data.booking.eventInstance.endTime,
11708
- price: data.booking.eventInstance.price || 0, // Use actual event instance price
11713
+ price: data.booking.eventInstance.price || 0,
11709
11714
  });
11710
11715
  setFormData({
11711
11716
  customerEmail: data.booking.customerEmail,
@@ -11713,9 +11718,7 @@ const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId
11713
11718
  customerPhone: data.booking.customerPhone,
11714
11719
  participants: data.booking.participants || [],
11715
11720
  });
11716
- // Set payment status from Stripe data or order status
11717
11721
  setPaymentStatus(data.stripePaymentIntent?.status || data.order.status);
11718
- // Trigger Google Ads conversion tracking if payment is successful
11719
11722
  const finalPaymentStatus = data.stripePaymentIntent?.status || data.order.status;
11720
11723
  if (finalPaymentStatus === "succeeded" &&
11721
11724
  config.googleAds?.tagId &&
@@ -13665,11 +13668,10 @@ function formatUnavailableReason(reason, t) {
13665
13668
  return t("upsells.reason.notEnoughSpots", { eventTypeName: reason.eventTypeName });
13666
13669
  }
13667
13670
  }
13668
- function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPricesEnabled = true, }) {
13671
+ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
13669
13672
  const t = useTranslations();
13670
13673
  const { locale } = useLocale();
13671
- const effectivePrice = getEffectiveUpsellPrice(upsell, roundPricesEnabled);
13672
- const totalPrice = effectivePrice * participantCount;
13674
+ const totalPrice = upsell.price * participantCount;
13673
13675
  const isDisabled = !upsell.available;
13674
13676
  const getCardStyles = () => {
13675
13677
  if (isDisabled)
@@ -13687,19 +13689,12 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, roundPrice
13687
13689
  weekday: "short",
13688
13690
  day: "numeric",
13689
13691
  month: "short",
13690
- })] }), 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
13691
13693
  ? formatUnavailableReason(upsell.unavailableReason, t)
13692
13694
  : t("upsells.notAvailable") }) }))] }));
13693
13695
  }
13694
13696
 
13695
- function getEffectiveUpsellPrice(upsell, round = true) {
13696
- const dp = upsell.discountPercent ?? 0;
13697
- if (dp <= 0)
13698
- return upsell.price;
13699
- const raw = Math.round(upsell.price * (100 - dp) / 100);
13700
- return round ? Math.floor(raw / 100) * 100 : raw;
13701
- }
13702
- 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, }) {
13703
13698
  const t = useTranslations();
13704
13699
  const selectUpsell = (upsellId) => {
13705
13700
  const exists = selectedUpsells.find((s) => s.upsellPackageId === upsellId);
@@ -13718,7 +13713,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13718
13713
  return selectedUpsells.reduce((total, selection) => {
13719
13714
  const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
13720
13715
  if (upsell) {
13721
- return total + getEffectiveUpsellPrice(upsell, roundPricesEnabled) * selection.quantity;
13716
+ return total + upsell.price * selection.quantity;
13722
13717
  }
13723
13718
  return total;
13724
13719
  }, 0);
@@ -13726,7 +13721,7 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
13726
13721
  const selectedTotal = calculateTotal();
13727
13722
  const selectedCount = selectedUpsells.length;
13728
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") })] }));
13729
- 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)] })] }))] }) }));
13730
13725
  }
13731
13726
 
13732
13727
  // Main widget component
@@ -13772,7 +13767,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13772
13767
  const [isLoadingShowAll, setIsLoadingShowAll] = useState(false);
13773
13768
  const [error, setError] = useState(null);
13774
13769
  const [isSuccess, setIsSuccess] = useState(false);
13775
- const [successPaymentIntentId, setSuccessPaymentIntentId] = useState(null);
13770
+ const [successPaymentId, setSuccessPaymentId] = useState(null);
13776
13771
  const [systemConfig, setSystemConfig] = useState(null);
13777
13772
  // PERFORMANCE OPTIMIZATION: Lazy component loading
13778
13773
  const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = useState(false);
@@ -13838,7 +13833,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
13838
13833
  const stripeReturn = detectStripeReturn();
13839
13834
  if (stripeReturn) {
13840
13835
  if (stripeReturn.redirectStatus === "succeeded") {
13841
- setSuccessPaymentIntentId(stripeReturn.paymentIntent);
13836
+ setSuccessPaymentId(stripeReturn.paymentIntent);
13842
13837
  setIsSuccess(true);
13843
13838
  }
13844
13839
  else if (stripeReturn.redirectStatus === "failed") {
@@ -14193,7 +14188,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14193
14188
  };
14194
14189
  const handleBookingSuccess = (result) => {
14195
14190
  setIsSuccess(true);
14196
- setSuccessPaymentIntentId(result.paymentIntent.id);
14191
+ setSuccessPaymentId(result.paymentIntent.id);
14197
14192
  setSidebarOpen(false);
14198
14193
  setShouldRenderBookingForm(false);
14199
14194
  config.onSuccess?.(result);
@@ -14391,7 +14386,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14391
14386
  setIsSuccess(false);
14392
14387
  setCurrentStep("eventTypes");
14393
14388
  setShowingPreview(true);
14394
- setSuccessPaymentIntentId(null);
14389
+ setSuccessPaymentId(null);
14395
14390
  setShouldRenderInstanceSelection(false);
14396
14391
  setShouldRenderUpsells(false);
14397
14392
  setShouldRenderBookingForm(false);
@@ -14402,7 +14397,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14402
14397
  url.searchParams.delete("payment_intent_client_secret");
14403
14398
  url.searchParams.delete("redirect_status");
14404
14399
  window.history.replaceState({}, "", url.toString());
14405
- }, 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 }))] }));
14406
14401
  }
14407
14402
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
14408
14403
  return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
@@ -14415,7 +14410,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14415
14410
  setIsSuccess(false);
14416
14411
  setCurrentStep("eventTypes");
14417
14412
  setShowingPreview(true);
14418
- setSuccessPaymentIntentId(null);
14413
+ setSuccessPaymentId(null);
14419
14414
  setShouldRenderInstanceSelection(false);
14420
14415
  setShouldRenderBookingForm(false);
14421
14416
  const url = new URL(window.location.href);
@@ -14423,7 +14418,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14423
14418
  url.searchParams.delete("payment_intent_client_secret");
14424
14419
  url.searchParams.delete("redirect_status");
14425
14420
  window.history.replaceState({}, "", url.toString());
14426
- }, 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 }))] }));
14427
14422
  }
14428
14423
  if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
14429
14424
  return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, style: {
@@ -14452,11 +14447,11 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14452
14447
  setShouldRenderInstanceSelection(true);
14453
14448
  }
14454
14449
  }, children: config.buttonText ||
14455
- (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: () => {
14456
14451
  setIsSuccess(false);
14457
14452
  setCurrentStep("eventTypes");
14458
14453
  setSidebarOpen(false);
14459
- setSuccessPaymentIntentId(null);
14454
+ setSuccessPaymentId(null);
14460
14455
  setShouldRenderInstanceSelection(false);
14461
14456
  setShouldRenderUpsells(false);
14462
14457
  setShouldRenderBookingForm(false);
@@ -14467,7 +14462,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14467
14462
  url.searchParams.delete("payment_intent_client_secret");
14468
14463
  url.searchParams.delete("redirect_status");
14469
14464
  window.history.replaceState({}, "", url.toString());
14470
- }, 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 }))] }));
14471
14466
  }
14472
14467
  // Cards mode (default) - show event type selection
14473
14468
  const cardsView = (jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
@@ -14499,10 +14494,10 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14499
14494
  };
14500
14495
  };
14501
14496
  const backHandlers = getBackHandlers();
14502
- 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: () => {
14503
14498
  setIsSuccess(false);
14504
14499
  setCurrentStep("eventTypes");
14505
- setSuccessPaymentIntentId(null);
14500
+ setSuccessPaymentId(null);
14506
14501
  setShouldRenderInstanceSelection(false);
14507
14502
  setShouldRenderUpsells(false);
14508
14503
  setShouldRenderBookingForm(false);
@@ -14513,7 +14508,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
14513
14508
  url.searchParams.delete("payment_intent_client_secret");
14514
14509
  url.searchParams.delete("redirect_status");
14515
14510
  window.history.replaceState({}, "", url.toString());
14516
- }, 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 }))] }));
14517
14512
  }
14518
14513
  function UniversalBookingWidget(props) {
14519
14514
  const [languagePolicy, setLanguagePolicy] = useState(null);