@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.
- package/README.md +3 -1
- package/dist/booking-widget.js +176 -181
- package/dist/booking-widget.js.map +1 -1
- package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
- package/dist/components/booking/BookingForm.d.ts +0 -1
- package/dist/components/booking/BookingForm.d.ts.map +1 -1
- package/dist/components/booking/BookingSuccessModal.d.ts.map +1 -1
- package/dist/components/booking/GiftCardOnlyBooking.d.ts +22 -0
- package/dist/components/booking/GiftCardOnlyBooking.d.ts.map +1 -0
- package/dist/components/booking/MolliePaymentForm.d.ts +2 -6
- package/dist/components/booking/MolliePaymentForm.d.ts.map +1 -1
- package/dist/components/booking/{PaymentForm.d.ts → StripePaymentForm.d.ts} +4 -8
- package/dist/components/booking/StripePaymentForm.d.ts.map +1 -0
- package/dist/components/booking/VoucherInput.d.ts +8 -0
- package/dist/components/booking/VoucherInput.d.ts.map +1 -1
- package/dist/components/booking/index.d.ts +2 -1
- package/dist/components/booking/index.d.ts.map +1 -1
- package/dist/components/upsells/UpsellCard.d.ts +1 -2
- package/dist/components/upsells/UpsellCard.d.ts.map +1 -1
- package/dist/components/upsells/UpsellsStep.d.ts +1 -4
- package/dist/components/upsells/UpsellsStep.d.ts.map +1 -1
- package/dist/components/upsells/index.d.ts +1 -1
- package/dist/components/upsells/index.d.ts.map +1 -1
- package/dist/index.cjs +176 -181
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +176 -181
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/booking/PaymentForm.d.ts.map +0 -1
package/dist/booking-widget.js
CHANGED
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
"error.loadBookingData": "Fehler beim Abrufen der Buchungsdaten",
|
|
262
262
|
"error.processingError": "Ein Fehler ist bei der Verarbeitung aufgetreten.",
|
|
263
263
|
"error.createBooking": "Fehler beim Erstellen der Buchung",
|
|
264
|
-
"error.
|
|
264
|
+
"error.createPayment": "Fehler beim Erstellen der Zahlung",
|
|
265
265
|
"error.paymentProcessing": "Fehler beim Verarbeiten der Zahlung",
|
|
266
266
|
"error.paymentFailed": "Die Zahlung war nicht erfolgreich. Bitte versuche es erneut.",
|
|
267
267
|
"error.paymentIncomplete": "Die Zahlung konnte nicht abgeschlossen werden. Bitte versuche es erneut.",
|
|
@@ -375,7 +375,7 @@
|
|
|
375
375
|
"voucher.giftCardApplied": "−{{amount}} Gutschein",
|
|
376
376
|
"voucher.remaining": "Rest: {{amount}}",
|
|
377
377
|
"voucher.remove": "Entfernen",
|
|
378
|
-
"voucher.alreadyHasDiscount": "
|
|
378
|
+
"voucher.alreadyHasDiscount": "Du kannst weitere Gutscheine hinzufügen.",
|
|
379
379
|
// Booking success
|
|
380
380
|
"success.title": "Reservierung erfolgreich!",
|
|
381
381
|
"success.bookingDetails": "Buchungsdetails",
|
|
@@ -470,7 +470,7 @@
|
|
|
470
470
|
"error.loadBookingData": "Error fetching booking data",
|
|
471
471
|
"error.processingError": "An error occurred during processing.",
|
|
472
472
|
"error.createBooking": "Error creating booking",
|
|
473
|
-
"error.
|
|
473
|
+
"error.createPayment": "Error creating payment",
|
|
474
474
|
"error.paymentProcessing": "Error processing payment",
|
|
475
475
|
"error.paymentFailed": "The payment was not successful. Please try again.",
|
|
476
476
|
"error.paymentIncomplete": "The payment could not be completed. Please try again.",
|
|
@@ -679,7 +679,7 @@
|
|
|
679
679
|
"error.loadBookingData": "Error al obtener datos de la reserva",
|
|
680
680
|
"error.processingError": "Ocurrió un error durante el procesamiento.",
|
|
681
681
|
"error.createBooking": "Error al crear la reserva",
|
|
682
|
-
"error.
|
|
682
|
+
"error.createPayment": "Error al crear el pago",
|
|
683
683
|
"error.paymentProcessing": "Error al procesar el pago",
|
|
684
684
|
"error.paymentFailed": "El pago no fue exitoso. Por favor, inténtalo de nuevo.",
|
|
685
685
|
"error.paymentIncomplete": "El pago no pudo completarse. Por favor, inténtalo de nuevo.",
|
|
@@ -888,7 +888,7 @@
|
|
|
888
888
|
"error.loadBookingData": "Erro ao obter dados da reserva",
|
|
889
889
|
"error.processingError": "Ocorreu um erro durante o processamento.",
|
|
890
890
|
"error.createBooking": "Erro ao criar reserva",
|
|
891
|
-
"error.
|
|
891
|
+
"error.createPayment": "Erro ao criar pagamento",
|
|
892
892
|
"error.paymentProcessing": "Erro ao processar pagamento",
|
|
893
893
|
"error.paymentFailed": "O pagamento não foi bem-sucedido. Por favor, tente novamente.",
|
|
894
894
|
"error.paymentIncomplete": "O pagamento não pôde ser concluído. Por favor, tente novamente.",
|
|
@@ -1097,7 +1097,7 @@
|
|
|
1097
1097
|
"error.loadBookingData": "Fel vid hämtning av bokningsdata",
|
|
1098
1098
|
"error.processingError": "Ett fel uppstod vid bearbetningen.",
|
|
1099
1099
|
"error.createBooking": "Fel vid skapande av bokning",
|
|
1100
|
-
"error.
|
|
1100
|
+
"error.createPayment": "Fel vid skapande av betalning",
|
|
1101
1101
|
"error.paymentProcessing": "Fel vid bearbetning av betalning",
|
|
1102
1102
|
"error.paymentFailed": "Betalningen lyckades inte. Försök igen.",
|
|
1103
1103
|
"error.paymentIncomplete": "Betalningen kunde inte slutföras. Försök igen.",
|
|
@@ -4497,6 +4497,108 @@
|
|
|
4497
4497
|
// Chevron Right icon - used for carousel navigation
|
|
4498
4498
|
const IconChevronRight = ({ size = 20, color = "white", className, }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: u$2("polyline", { points: "9 18 15 12 9 6" }) }));
|
|
4499
4499
|
|
|
4500
|
+
function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
|
|
4501
|
+
const t = useTranslations();
|
|
4502
|
+
const [isLoading, setIsLoading] = d$1(false);
|
|
4503
|
+
const [error, setError] = d$1(null);
|
|
4504
|
+
const handleBooking = async () => {
|
|
4505
|
+
setIsLoading(true);
|
|
4506
|
+
setError(null);
|
|
4507
|
+
try {
|
|
4508
|
+
const requestData = {
|
|
4509
|
+
eventInstanceId: config.eventInstanceId || eventDetails.id,
|
|
4510
|
+
organizationId: config.organizationId,
|
|
4511
|
+
participants: formData.participants.filter((p) => p.name?.trim()),
|
|
4512
|
+
discountCode: discountCode?.code,
|
|
4513
|
+
giftCardCodes: giftCards.map((gc) => gc.code),
|
|
4514
|
+
customerName: formData.customerName?.trim(),
|
|
4515
|
+
customerEmail: formData.customerEmail?.trim(),
|
|
4516
|
+
customerPhone: formData.customerPhone?.trim(),
|
|
4517
|
+
comment: formData.comment?.trim(),
|
|
4518
|
+
paymentMethod: "gift_card",
|
|
4519
|
+
...(upsellSelections.length > 0 && { upsellSelections }),
|
|
4520
|
+
};
|
|
4521
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
|
|
4522
|
+
method: "POST",
|
|
4523
|
+
headers: createApiHeaders(config),
|
|
4524
|
+
body: JSON.stringify(createRequestBody(config, requestData)),
|
|
4525
|
+
});
|
|
4526
|
+
const data = await response.json();
|
|
4527
|
+
if (response.ok) {
|
|
4528
|
+
onSuccess({
|
|
4529
|
+
booking: data.booking,
|
|
4530
|
+
order: data.order,
|
|
4531
|
+
giftCardRedemptions: data.giftCardRedemptions,
|
|
4532
|
+
});
|
|
4533
|
+
}
|
|
4534
|
+
else {
|
|
4535
|
+
setError(data.error || t("error.createBooking"));
|
|
4536
|
+
onError(data.error || t("error.createBooking"));
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
catch (err) {
|
|
4540
|
+
setError(err.message || t("error.createBooking"));
|
|
4541
|
+
onError(err.message || t("error.createBooking"));
|
|
4542
|
+
}
|
|
4543
|
+
finally {
|
|
4544
|
+
setIsLoading(false);
|
|
4545
|
+
}
|
|
4546
|
+
};
|
|
4547
|
+
const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
|
|
4548
|
+
return (u$2("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [u$2("div", { style: {
|
|
4549
|
+
backgroundColor: "rgba(var(--bw-success-color), 0.15)",
|
|
4550
|
+
border: "1px solid rgba(var(--bw-success-color), 0.4)",
|
|
4551
|
+
borderRadius: "var(--bw-border-radius)",
|
|
4552
|
+
padding: "16px",
|
|
4553
|
+
}, children: [u$2("div", { style: {
|
|
4554
|
+
display: "flex",
|
|
4555
|
+
alignItems: "center",
|
|
4556
|
+
gap: "8px",
|
|
4557
|
+
marginBottom: "8px",
|
|
4558
|
+
color: "var(--bw-success-color)",
|
|
4559
|
+
fontFamily: "var(--bw-font-family)",
|
|
4560
|
+
fontWeight: 600,
|
|
4561
|
+
}, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), u$2("div", { style: {
|
|
4562
|
+
fontSize: "16px",
|
|
4563
|
+
color: "var(--bw-text-muted)",
|
|
4564
|
+
fontFamily: "var(--bw-font-family)",
|
|
4565
|
+
}, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (u$2("div", { style: {
|
|
4566
|
+
backgroundColor: "rgba(var(--bw-error-color), 0.15)",
|
|
4567
|
+
border: "1px solid rgba(var(--bw-error-color), 0.4)",
|
|
4568
|
+
borderRadius: "var(--bw-border-radius)",
|
|
4569
|
+
padding: "16px",
|
|
4570
|
+
color: "var(--bw-error-color)",
|
|
4571
|
+
fontSize: "16px",
|
|
4572
|
+
fontFamily: "var(--bw-font-family)",
|
|
4573
|
+
}, children: ["\u26A0\uFE0F ", error] })), u$2("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
|
|
4574
|
+
width: "100%",
|
|
4575
|
+
padding: "12px 24px",
|
|
4576
|
+
backgroundColor: "var(--bw-highlight-color)",
|
|
4577
|
+
color: "#ffffff",
|
|
4578
|
+
border: "none",
|
|
4579
|
+
borderRadius: "var(--bw-border-radius)",
|
|
4580
|
+
fontSize: "16px",
|
|
4581
|
+
fontWeight: 600,
|
|
4582
|
+
fontFamily: "var(--bw-font-family)",
|
|
4583
|
+
transition: "all 0.2s ease",
|
|
4584
|
+
display: "flex",
|
|
4585
|
+
alignItems: "center",
|
|
4586
|
+
justifyContent: "center",
|
|
4587
|
+
gap: "8px",
|
|
4588
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
4589
|
+
opacity: isLoading ? 0.6 : 1,
|
|
4590
|
+
}, children: isLoading ? (u$2(k$3, { children: [spinner("#ffffff"), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
|
|
4591
|
+
}
|
|
4592
|
+
/**
|
|
4593
|
+
* Calculate whether gift cards fully cover the order after discounts.
|
|
4594
|
+
*/
|
|
4595
|
+
function isGiftCardFullyCovered(giftCards, eventPrice, participantCount, discountAmount) {
|
|
4596
|
+
const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
|
|
4597
|
+
const baseTotal = eventPrice * participantCount;
|
|
4598
|
+
const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
|
|
4599
|
+
return totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4500
4602
|
const mollieLocaleMap = {
|
|
4501
4603
|
de: "de_DE",
|
|
4502
4604
|
en: "en_US",
|
|
@@ -4557,13 +4659,8 @@
|
|
|
4557
4659
|
const mollieRef = A$2(null);
|
|
4558
4660
|
const cardFormRef = A$2(null);
|
|
4559
4661
|
const cardContainerRef = A$2(null);
|
|
4560
|
-
const
|
|
4561
|
-
const
|
|
4562
|
-
? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
|
|
4563
|
-
: 0;
|
|
4564
|
-
const discountAmount = discountCode?.discountAmount || 0;
|
|
4565
|
-
const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
|
|
4566
|
-
const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
|
|
4662
|
+
const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
|
|
4663
|
+
const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
|
|
4567
4664
|
const isCreditCard = selectedMethod === "creditcard";
|
|
4568
4665
|
y$1(() => {
|
|
4569
4666
|
if (isFullyCoveredByGiftCards)
|
|
@@ -4670,7 +4767,7 @@
|
|
|
4670
4767
|
};
|
|
4671
4768
|
}, [isCreditCard, mollieProfileId, mollieTestmode, isFullyCoveredByGiftCards]);
|
|
4672
4769
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
4673
|
-
return
|
|
4770
|
+
return (u$2(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: _onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
4674
4771
|
}
|
|
4675
4772
|
const validateBeforePayment = () => {
|
|
4676
4773
|
const participantCount = formData.participants.filter((p) => p.name?.trim()).length;
|
|
@@ -4712,7 +4809,7 @@
|
|
|
4712
4809
|
}
|
|
4713
4810
|
const { token, error: tokenError } = await mollieRef.current.createToken();
|
|
4714
4811
|
if (tokenError || !token) {
|
|
4715
|
-
setPaymentError(tokenError?.message || t("error.
|
|
4812
|
+
setPaymentError(tokenError?.message || t("error.createPayment"));
|
|
4716
4813
|
return;
|
|
4717
4814
|
}
|
|
4718
4815
|
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-mollie-payment"), {
|
|
@@ -4728,8 +4825,8 @@
|
|
|
4728
4825
|
_onSuccess({ paymentIntent: { id: data.molliePaymentId } });
|
|
4729
4826
|
}
|
|
4730
4827
|
else {
|
|
4731
|
-
setPaymentError(data.error || t("error.
|
|
4732
|
-
onError(data.error || t("error.
|
|
4828
|
+
setPaymentError(data.error || t("error.createPayment"));
|
|
4829
|
+
onError(data.error || t("error.createPayment"));
|
|
4733
4830
|
}
|
|
4734
4831
|
}
|
|
4735
4832
|
catch (err) {
|
|
@@ -4761,8 +4858,8 @@
|
|
|
4761
4858
|
window.location.href = data.checkoutUrl;
|
|
4762
4859
|
}
|
|
4763
4860
|
else {
|
|
4764
|
-
setPaymentError(data.error || t("error.
|
|
4765
|
-
onError(data.error || t("error.
|
|
4861
|
+
setPaymentError(data.error || t("error.createPayment"));
|
|
4862
|
+
onError(data.error || t("error.createPayment"));
|
|
4766
4863
|
}
|
|
4767
4864
|
}
|
|
4768
4865
|
catch (err) {
|
|
@@ -6259,106 +6356,6 @@
|
|
|
6259
6356
|
|
|
6260
6357
|
var reactStripe_umdExports = reactStripe_umd.exports;
|
|
6261
6358
|
|
|
6262
|
-
// Component for bookings fully covered by gift cards (no Stripe payment needed)
|
|
6263
|
-
function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, upsellSelections = [], }) {
|
|
6264
|
-
const t = useTranslations();
|
|
6265
|
-
const [isLoading, setIsLoading] = d$1(false);
|
|
6266
|
-
const [error, setError] = d$1(null);
|
|
6267
|
-
const handleBooking = async () => {
|
|
6268
|
-
setIsLoading(true);
|
|
6269
|
-
setError(null);
|
|
6270
|
-
try {
|
|
6271
|
-
const requestData = {
|
|
6272
|
-
eventInstanceId: config.eventInstanceId || eventDetails.id,
|
|
6273
|
-
organizationId: config.organizationId,
|
|
6274
|
-
participants: formData.participants.filter((p) => p.name?.trim()),
|
|
6275
|
-
discountCode: discountCode?.code,
|
|
6276
|
-
giftCardCodes: giftCards.map((gc) => gc.code),
|
|
6277
|
-
customerName: formData.customerName?.trim(),
|
|
6278
|
-
customerEmail: formData.customerEmail?.trim(),
|
|
6279
|
-
customerPhone: formData.customerPhone?.trim(),
|
|
6280
|
-
comment: formData.comment?.trim(),
|
|
6281
|
-
paymentMethod: "gift_card",
|
|
6282
|
-
...(upsellSelections.length > 0 && { upsellSelections }),
|
|
6283
|
-
};
|
|
6284
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
|
|
6285
|
-
method: "POST",
|
|
6286
|
-
headers: createApiHeaders(config),
|
|
6287
|
-
body: JSON.stringify(createRequestBody(config, requestData)),
|
|
6288
|
-
});
|
|
6289
|
-
const data = await response.json();
|
|
6290
|
-
if (response.ok) {
|
|
6291
|
-
onSuccess({
|
|
6292
|
-
booking: data.booking,
|
|
6293
|
-
order: data.order,
|
|
6294
|
-
giftCardRedemptions: data.giftCardRedemptions,
|
|
6295
|
-
});
|
|
6296
|
-
}
|
|
6297
|
-
else {
|
|
6298
|
-
setError(data.error || t("error.createBooking"));
|
|
6299
|
-
onError(data.error || t("error.createBooking"));
|
|
6300
|
-
}
|
|
6301
|
-
}
|
|
6302
|
-
catch (err) {
|
|
6303
|
-
setError(err.message || t("error.createBooking"));
|
|
6304
|
-
onError(err.message || t("error.createBooking"));
|
|
6305
|
-
}
|
|
6306
|
-
finally {
|
|
6307
|
-
setIsLoading(false);
|
|
6308
|
-
}
|
|
6309
|
-
};
|
|
6310
|
-
const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
|
|
6311
|
-
return (u$2("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [u$2("div", { style: {
|
|
6312
|
-
backgroundColor: "rgba(var(--bw-success-color), 0.15)",
|
|
6313
|
-
border: "1px solid rgba(var(--bw-success-color), 0.4)",
|
|
6314
|
-
borderRadius: "var(--bw-border-radius)",
|
|
6315
|
-
padding: "16px",
|
|
6316
|
-
}, children: [u$2("div", { style: {
|
|
6317
|
-
display: "flex",
|
|
6318
|
-
alignItems: "center",
|
|
6319
|
-
gap: "8px",
|
|
6320
|
-
marginBottom: "8px",
|
|
6321
|
-
color: "var(--bw-success-color)",
|
|
6322
|
-
fontFamily: "var(--bw-font-family)",
|
|
6323
|
-
fontWeight: 600,
|
|
6324
|
-
}, children: ["\uD83C\uDF81 ", t("payment.giftCardCovered")] }), u$2("div", { style: {
|
|
6325
|
-
fontSize: "16px",
|
|
6326
|
-
color: "var(--bw-text-muted)",
|
|
6327
|
-
fontFamily: "var(--bw-font-family)",
|
|
6328
|
-
}, children: t("payment.giftCardBalance", { amount: formatCurrency(totalGiftCardAmount) }) })] }), error && (u$2("div", { style: {
|
|
6329
|
-
backgroundColor: "rgba(var(--bw-error-color), 0.15)",
|
|
6330
|
-
border: "1px solid rgba(var(--bw-error-color), 0.4)",
|
|
6331
|
-
borderRadius: "var(--bw-border-radius)",
|
|
6332
|
-
padding: "16px",
|
|
6333
|
-
color: "var(--bw-error-color)",
|
|
6334
|
-
fontSize: "16px",
|
|
6335
|
-
fontFamily: "var(--bw-font-family)",
|
|
6336
|
-
}, children: ["\u26A0\uFE0F ", error] })), u$2("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
|
|
6337
|
-
width: "100%",
|
|
6338
|
-
padding: "12px 24px",
|
|
6339
|
-
backgroundColor: "var(--bw-highlight-color)",
|
|
6340
|
-
color: "#ffffff",
|
|
6341
|
-
border: "none",
|
|
6342
|
-
borderRadius: "var(--bw-border-radius)",
|
|
6343
|
-
fontSize: "16px",
|
|
6344
|
-
fontWeight: 600,
|
|
6345
|
-
fontFamily: "var(--bw-font-family)",
|
|
6346
|
-
transition: "all 0.2s ease",
|
|
6347
|
-
display: "flex",
|
|
6348
|
-
alignItems: "center",
|
|
6349
|
-
justifyContent: "center",
|
|
6350
|
-
gap: "8px",
|
|
6351
|
-
cursor: isLoading ? "not-allowed" : "pointer",
|
|
6352
|
-
opacity: isLoading ? 0.6 : 1,
|
|
6353
|
-
}, children: isLoading ? (u$2(k$3, { children: [u$2("div", { style: {
|
|
6354
|
-
width: "16px",
|
|
6355
|
-
height: "16px",
|
|
6356
|
-
border: "2px solid #ffffff",
|
|
6357
|
-
borderTopColor: "transparent",
|
|
6358
|
-
borderRadius: "50%",
|
|
6359
|
-
animation: "spin 1s linear infinite",
|
|
6360
|
-
} }), t("button.creatingBooking")] })) : (t("button.bookWithGiftCard")) })] }));
|
|
6361
|
-
}
|
|
6362
6359
|
// Inner component that uses the Stripe hooks
|
|
6363
6360
|
function PaymentFormInner({ config, eventDetails, formData, totalAmount, onSuccess, onError, }) {
|
|
6364
6361
|
const t = useTranslations();
|
|
@@ -6395,7 +6392,7 @@
|
|
|
6395
6392
|
redirect: "if_required",
|
|
6396
6393
|
});
|
|
6397
6394
|
if (error) {
|
|
6398
|
-
console.error("[
|
|
6395
|
+
console.error("[STRIPE_PAYMENT] Payment confirmation error:", {
|
|
6399
6396
|
type: error.type,
|
|
6400
6397
|
code: error.code,
|
|
6401
6398
|
message: error.message,
|
|
@@ -6471,8 +6468,7 @@
|
|
|
6471
6468
|
? t("button.depositAndBook")
|
|
6472
6469
|
: t("button.bookNow") })) })] }));
|
|
6473
6470
|
}
|
|
6474
|
-
|
|
6475
|
-
function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
|
|
6471
|
+
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, upsellSelections = [], }) {
|
|
6476
6472
|
const t = useTranslations();
|
|
6477
6473
|
const [clientSecret, setClientSecret] = d$1(null);
|
|
6478
6474
|
const [paymentIntentId, setPaymentIntentId] = d$1(null);
|
|
@@ -6533,7 +6529,7 @@
|
|
|
6533
6529
|
}
|
|
6534
6530
|
}, [paymentIntentId]);
|
|
6535
6531
|
y$1(() => {
|
|
6536
|
-
const
|
|
6532
|
+
const createStripePayment = async () => {
|
|
6537
6533
|
if (!systemConfig || !eventDetails || !formData.participants?.length) {
|
|
6538
6534
|
return;
|
|
6539
6535
|
}
|
|
@@ -6574,35 +6570,38 @@
|
|
|
6574
6570
|
if (!requestData.customerEmail) {
|
|
6575
6571
|
throw new Error("Customer email is required");
|
|
6576
6572
|
}
|
|
6577
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-payment
|
|
6573
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-stripe-payment"), {
|
|
6578
6574
|
method: "POST",
|
|
6579
6575
|
headers: createApiHeaders(config),
|
|
6580
6576
|
body: JSON.stringify(createRequestBody(config, requestData)),
|
|
6581
6577
|
});
|
|
6582
6578
|
const data = await response.json();
|
|
6583
6579
|
if (response.ok) {
|
|
6580
|
+
if (data.stalePaymentIntent) {
|
|
6581
|
+
clearPersistedPaymentIntent();
|
|
6582
|
+
}
|
|
6584
6583
|
setClientSecret(data.clientSecret);
|
|
6585
6584
|
setPaymentIntentId(data.paymentIntentId);
|
|
6586
6585
|
}
|
|
6587
6586
|
else {
|
|
6588
|
-
console.error("[
|
|
6587
|
+
console.error("[STRIPE_PAYMENT] Payment creation failed:", {
|
|
6589
6588
|
status: response.status,
|
|
6590
6589
|
error: data.error,
|
|
6591
6590
|
details: data.details,
|
|
6592
6591
|
requestData: { ...requestData, customerEmail: "[redacted]" },
|
|
6593
6592
|
});
|
|
6594
|
-
setPaymentError(data.error || t("error.
|
|
6593
|
+
setPaymentError(data.error || t("error.createPayment"));
|
|
6595
6594
|
}
|
|
6596
6595
|
}
|
|
6597
6596
|
catch (err) {
|
|
6598
|
-
console.error("[
|
|
6599
|
-
setPaymentError(err.message || t("error.
|
|
6597
|
+
console.error("[STRIPE_PAYMENT] Payment creation error:", err);
|
|
6598
|
+
setPaymentError(err.message || t("error.createPayment"));
|
|
6600
6599
|
}
|
|
6601
6600
|
finally {
|
|
6602
6601
|
setIsCreatingPaymentIntent(false);
|
|
6603
6602
|
}
|
|
6604
6603
|
};
|
|
6605
|
-
const timer = setTimeout(
|
|
6604
|
+
const timer = setTimeout(createStripePayment, 500);
|
|
6606
6605
|
return () => clearTimeout(timer);
|
|
6607
6606
|
}, [
|
|
6608
6607
|
systemConfig,
|
|
@@ -6610,19 +6609,15 @@
|
|
|
6610
6609
|
formData.participants,
|
|
6611
6610
|
formData.customerEmail,
|
|
6612
6611
|
formData.customerName,
|
|
6612
|
+
formData.comment,
|
|
6613
6613
|
totalAmount,
|
|
6614
6614
|
discountCode,
|
|
6615
6615
|
giftCards,
|
|
6616
6616
|
config,
|
|
6617
6617
|
upsellSelections,
|
|
6618
6618
|
]);
|
|
6619
|
-
const
|
|
6620
|
-
const
|
|
6621
|
-
? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
|
|
6622
|
-
: 0;
|
|
6623
|
-
const discountAmount = discountCode?.discountAmount || 0;
|
|
6624
|
-
const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
|
|
6625
|
-
const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
|
|
6619
|
+
const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
|
|
6620
|
+
const isFullyCoveredByGiftCards = isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
|
|
6626
6621
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
6627
6622
|
return (u$2(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
6628
6623
|
}
|
|
@@ -11132,13 +11127,6 @@
|
|
|
11132
11127
|
return Object.assign({}, ...styles.filter(Boolean));
|
|
11133
11128
|
}
|
|
11134
11129
|
|
|
11135
|
-
function getEffectivePrice(upsell, round) {
|
|
11136
|
-
const dp = upsell.discountPercent ?? 0;
|
|
11137
|
-
if (dp <= 0)
|
|
11138
|
-
return upsell.price;
|
|
11139
|
-
const raw = Math.round(upsell.price * (100 - dp) / 100);
|
|
11140
|
-
return round ? Math.floor(raw / 100) * 100 : raw;
|
|
11141
|
-
}
|
|
11142
11130
|
// Local style aliases from shared styles
|
|
11143
11131
|
const cardStyles = cardStyles$1.base;
|
|
11144
11132
|
const sectionHeaderStyles = sectionStyles.header;
|
|
@@ -11150,6 +11138,11 @@
|
|
|
11150
11138
|
const { locale } = useLocale();
|
|
11151
11139
|
const timezone = useTimezone();
|
|
11152
11140
|
const roundEnabled = systemConfig?.roundPricesEnabled !== false;
|
|
11141
|
+
const roundDiscountUp = (minorUnits) => Math.ceil(minorUnits / 100) * 100;
|
|
11142
|
+
const calcPercentDiscountAmount = (baseAmount, basisPoints, round) => {
|
|
11143
|
+
const raw = Math.round((baseAmount * basisPoints) / 10000);
|
|
11144
|
+
return round ? roundDiscountUp(raw) : raw;
|
|
11145
|
+
};
|
|
11153
11146
|
const [appliedVouchers, setAppliedVouchers] = d$1([]);
|
|
11154
11147
|
const paymentSectionRef = A$2(null);
|
|
11155
11148
|
// Payment option: "deposit" or "full" - only relevant when deposit is available
|
|
@@ -11171,6 +11164,8 @@
|
|
|
11171
11164
|
const watchedParticipants = form.watch("participants");
|
|
11172
11165
|
const watchedCustomerName = form.watch("customerName");
|
|
11173
11166
|
const watchedCustomerEmail = form.watch("customerEmail");
|
|
11167
|
+
const watchedComment = form.watch("comment");
|
|
11168
|
+
const watchedCustomerPhone = form.watch("customerPhone");
|
|
11174
11169
|
const customerNameError = form.formState.errors.customerName;
|
|
11175
11170
|
const customerEmailError = form.formState.errors.customerEmail;
|
|
11176
11171
|
const watchedAcceptTerms = form.watch("acceptTerms");
|
|
@@ -11220,7 +11215,7 @@
|
|
|
11220
11215
|
participantUpsellIds.forEach(upsellId => {
|
|
11221
11216
|
const upsell = upsells.find(u => u.id === upsellId);
|
|
11222
11217
|
if (upsell) {
|
|
11223
|
-
total +=
|
|
11218
|
+
total += upsell.price;
|
|
11224
11219
|
}
|
|
11225
11220
|
});
|
|
11226
11221
|
}
|
|
@@ -11282,6 +11277,13 @@
|
|
|
11282
11277
|
participantIndices,
|
|
11283
11278
|
}));
|
|
11284
11279
|
}, [participantUpsells, watchedParticipants]);
|
|
11280
|
+
const paymentFormData = T$2(() => ({
|
|
11281
|
+
customerName: watchedCustomerName,
|
|
11282
|
+
customerEmail: watchedCustomerEmail,
|
|
11283
|
+
customerPhone: watchedCustomerPhone,
|
|
11284
|
+
participants: watchedParticipants,
|
|
11285
|
+
comment: watchedComment,
|
|
11286
|
+
}), [watchedCustomerName, watchedCustomerEmail, watchedCustomerPhone, watchedParticipants, watchedComment]);
|
|
11285
11287
|
const appliedDiscountCode = appliedVouchers.find((v) => v.type === "discount");
|
|
11286
11288
|
const appliedGiftCards = appliedVouchers.filter((v) => v.type === "giftCard");
|
|
11287
11289
|
const handleVoucherValidated = q$2((voucher, _error) => {
|
|
@@ -11318,7 +11320,10 @@
|
|
|
11318
11320
|
// TODO: discounts currently apply to base total only; extend when discount-applies-to-upsells flag is added
|
|
11319
11321
|
let newDiscountAmount = 0;
|
|
11320
11322
|
if (voucher.discountType === "percentage") {
|
|
11321
|
-
newDiscountAmount =
|
|
11323
|
+
newDiscountAmount = calcPercentDiscountAmount(newBaseTotal, voucher.discountValue || 0, roundEnabled);
|
|
11324
|
+
if (voucher.restrictions?.maxDiscount) {
|
|
11325
|
+
newDiscountAmount = Math.min(newDiscountAmount, voucher.restrictions.maxDiscount);
|
|
11326
|
+
}
|
|
11322
11327
|
}
|
|
11323
11328
|
else {
|
|
11324
11329
|
newDiscountAmount = voucher.discountValue || 0;
|
|
@@ -11496,7 +11501,7 @@
|
|
|
11496
11501
|
padding: 0,
|
|
11497
11502
|
}, children: "\u00D7" })] }))] }), upsells.length > 0 && (u$2("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
|
|
11498
11503
|
const isSelected = (participantUpsells[index] || []).includes(upsell.id);
|
|
11499
|
-
return (u$2("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [u$2("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), u$2("span", { style: { fontWeight: 500 }, children: upsell.name }), u$2("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(
|
|
11504
|
+
return (u$2("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [u$2("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), u$2("span", { style: { fontWeight: 500 }, children: upsell.name }), u$2("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
|
|
11500
11505
|
}) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (u$2("div", { style: {
|
|
11501
11506
|
display: "flex",
|
|
11502
11507
|
flexDirection: "column",
|
|
@@ -11528,7 +11533,7 @@
|
|
|
11528
11533
|
const countWithUpsell = watchedParticipants.filter((p, idx) => p.name.trim() && (participantUpsells[idx] || []).includes(upsell.id)).length;
|
|
11529
11534
|
if (countWithUpsell === 0)
|
|
11530
11535
|
return null;
|
|
11531
|
-
const upsellLineTotal =
|
|
11536
|
+
const upsellLineTotal = upsell.price * countWithUpsell;
|
|
11532
11537
|
return (u$2("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px" }, children: [u$2("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), u$2("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }, upsell.id));
|
|
11533
11538
|
})] })), appliedVouchers.length > 0 && (u$2(k$3, { children: [u$2("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [u$2("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), u$2("span", { style: {
|
|
11534
11539
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -11671,9 +11676,9 @@
|
|
|
11671
11676
|
}
|
|
11672
11677
|
: null;
|
|
11673
11678
|
if (systemConfig?.paymentProvider === "mollie") {
|
|
11674
|
-
return (u$2("div", { style: cardStyles, children: [u$2("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), u$2(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData:
|
|
11679
|
+
return (u$2("div", { style: cardStyles, children: [u$2("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), u$2(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 })] }));
|
|
11675
11680
|
}
|
|
11676
|
-
return (u$2("div", { style: cardStyles, children: [u$2("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), u$2(
|
|
11681
|
+
return (u$2("div", { style: cardStyles, children: [u$2("h2", { style: { ...sectionHeaderStyles }, children: t$1("summary.payment") }), u$2(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() })] }));
|
|
11677
11682
|
})() })] })] })] }) }));
|
|
11678
11683
|
}
|
|
11679
11684
|
|
|
@@ -11807,7 +11812,7 @@
|
|
|
11807
11812
|
if (targetPaymentIntentId) {
|
|
11808
11813
|
setIsLoading(true);
|
|
11809
11814
|
try {
|
|
11810
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment
|
|
11815
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/get-booking-by-payment"), {
|
|
11811
11816
|
method: "POST",
|
|
11812
11817
|
headers: createApiHeaders(config),
|
|
11813
11818
|
body: JSON.stringify(createRequestBody(config, {
|
|
@@ -11823,7 +11828,7 @@
|
|
|
11823
11828
|
orderItems: data.orderItems,
|
|
11824
11829
|
purchases: data.purchases || [],
|
|
11825
11830
|
discount: data.discount || null,
|
|
11826
|
-
|
|
11831
|
+
providerPaymentDetails: data.stripePaymentIntent,
|
|
11827
11832
|
});
|
|
11828
11833
|
setEventDetails({
|
|
11829
11834
|
id: data.booking.eventInstance.id,
|
|
@@ -11831,7 +11836,7 @@
|
|
|
11831
11836
|
description: data.booking.eventInstance.eventType.description,
|
|
11832
11837
|
startTime: data.booking.eventInstance.startTime,
|
|
11833
11838
|
endTime: data.booking.eventInstance.endTime,
|
|
11834
|
-
price: data.booking.eventInstance.price || 0,
|
|
11839
|
+
price: data.booking.eventInstance.price || 0,
|
|
11835
11840
|
});
|
|
11836
11841
|
setFormData({
|
|
11837
11842
|
customerEmail: data.booking.customerEmail,
|
|
@@ -11839,9 +11844,7 @@
|
|
|
11839
11844
|
customerPhone: data.booking.customerPhone,
|
|
11840
11845
|
participants: data.booking.participants || [],
|
|
11841
11846
|
});
|
|
11842
|
-
// Set payment status from Stripe data or order status
|
|
11843
11847
|
setPaymentStatus(data.stripePaymentIntent?.status || data.order.status);
|
|
11844
|
-
// Trigger Google Ads conversion tracking if payment is successful
|
|
11845
11848
|
const finalPaymentStatus = data.stripePaymentIntent?.status || data.order.status;
|
|
11846
11849
|
if (finalPaymentStatus === "succeeded" &&
|
|
11847
11850
|
config.googleAds?.tagId &&
|
|
@@ -13791,11 +13794,10 @@
|
|
|
13791
13794
|
return t("upsells.reason.notEnoughSpots", { eventTypeName: reason.eventTypeName });
|
|
13792
13795
|
}
|
|
13793
13796
|
}
|
|
13794
|
-
function UpsellCard({ upsell, isSelected, participantCount, onSelect,
|
|
13797
|
+
function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
|
|
13795
13798
|
const t = useTranslations();
|
|
13796
13799
|
const { locale } = useLocale();
|
|
13797
|
-
const
|
|
13798
|
-
const totalPrice = effectivePrice * participantCount;
|
|
13800
|
+
const totalPrice = upsell.price * participantCount;
|
|
13799
13801
|
const isDisabled = !upsell.available;
|
|
13800
13802
|
const getCardStyles = () => {
|
|
13801
13803
|
if (isDisabled)
|
|
@@ -13813,19 +13815,12 @@
|
|
|
13813
13815
|
weekday: "short",
|
|
13814
13816
|
day: "numeric",
|
|
13815
13817
|
month: "short",
|
|
13816
|
-
})] }), u$2("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), u$2("div", { style: priceContainerStyles, children: [u$2("span", { style: pricePerPersonStyles, children: [formatCurrency(
|
|
13818
|
+
})] }), u$2("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), u$2("div", { style: priceContainerStyles, children: [u$2("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (u$2("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (u$2("div", { style: unavailableOverlayStyles, children: u$2("span", { children: upsell.unavailableReason
|
|
13817
13819
|
? formatUnavailableReason(upsell.unavailableReason, t)
|
|
13818
13820
|
: t("upsells.notAvailable") }) }))] }));
|
|
13819
13821
|
}
|
|
13820
13822
|
|
|
13821
|
-
function
|
|
13822
|
-
const dp = upsell.discountPercent ?? 0;
|
|
13823
|
-
if (dp <= 0)
|
|
13824
|
-
return upsell.price;
|
|
13825
|
-
const raw = Math.round(upsell.price * (100 - dp) / 100);
|
|
13826
|
-
return round ? Math.floor(raw / 100) * 100 : raw;
|
|
13827
|
-
}
|
|
13828
|
-
function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, roundPricesEnabled = true, }) {
|
|
13823
|
+
function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, isOpen, onClose, onSelect, onContinue, onBack, }) {
|
|
13829
13824
|
const t = useTranslations();
|
|
13830
13825
|
const selectUpsell = (upsellId) => {
|
|
13831
13826
|
const exists = selectedUpsells.find((s) => s.upsellPackageId === upsellId);
|
|
@@ -13844,7 +13839,7 @@
|
|
|
13844
13839
|
return selectedUpsells.reduce((total, selection) => {
|
|
13845
13840
|
const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
|
|
13846
13841
|
if (upsell) {
|
|
13847
|
-
return total +
|
|
13842
|
+
return total + upsell.price * selection.quantity;
|
|
13848
13843
|
}
|
|
13849
13844
|
return total;
|
|
13850
13845
|
}, 0);
|
|
@@ -13852,7 +13847,7 @@
|
|
|
13852
13847
|
const selectedTotal = calculateTotal();
|
|
13853
13848
|
const selectedCount = selectedUpsells.length;
|
|
13854
13849
|
const footerContent = (u$2(k$3, { children: [u$2("button", { type: "button", onClick: onBack, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: t("common.back") }), u$2("button", { type: "button", onClick: onContinue, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: selectedCount === 0 ? t("button.continueWithout") : t("button.continue") })] }));
|
|
13855
|
-
return (u$2(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: u$2("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (u$2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), u$2("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (u$2("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: u$2("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (u$2(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id)
|
|
13850
|
+
return (u$2(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: u$2("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (u$2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), u$2("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (u$2("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: u$2("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (u$2(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (u$2("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: [u$2("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), u$2("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
|
|
13856
13851
|
}
|
|
13857
13852
|
|
|
13858
13853
|
// Main widget component
|
|
@@ -13898,7 +13893,7 @@
|
|
|
13898
13893
|
const [isLoadingShowAll, setIsLoadingShowAll] = d$1(false);
|
|
13899
13894
|
const [error, setError] = d$1(null);
|
|
13900
13895
|
const [isSuccess, setIsSuccess] = d$1(false);
|
|
13901
|
-
const [
|
|
13896
|
+
const [successPaymentId, setSuccessPaymentId] = d$1(null);
|
|
13902
13897
|
const [systemConfig, setSystemConfig] = d$1(null);
|
|
13903
13898
|
// PERFORMANCE OPTIMIZATION: Lazy component loading
|
|
13904
13899
|
const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = d$1(false);
|
|
@@ -13964,7 +13959,7 @@
|
|
|
13964
13959
|
const stripeReturn = detectStripeReturn();
|
|
13965
13960
|
if (stripeReturn) {
|
|
13966
13961
|
if (stripeReturn.redirectStatus === "succeeded") {
|
|
13967
|
-
|
|
13962
|
+
setSuccessPaymentId(stripeReturn.paymentIntent);
|
|
13968
13963
|
setIsSuccess(true);
|
|
13969
13964
|
}
|
|
13970
13965
|
else if (stripeReturn.redirectStatus === "failed") {
|
|
@@ -14319,7 +14314,7 @@
|
|
|
14319
14314
|
};
|
|
14320
14315
|
const handleBookingSuccess = (result) => {
|
|
14321
14316
|
setIsSuccess(true);
|
|
14322
|
-
|
|
14317
|
+
setSuccessPaymentId(result.paymentIntent.id);
|
|
14323
14318
|
setSidebarOpen(false);
|
|
14324
14319
|
setShouldRenderBookingForm(false);
|
|
14325
14320
|
config.onSuccess?.(result);
|
|
@@ -14517,7 +14512,7 @@
|
|
|
14517
14512
|
setIsSuccess(false);
|
|
14518
14513
|
setCurrentStep("eventTypes");
|
|
14519
14514
|
setShowingPreview(true);
|
|
14520
|
-
|
|
14515
|
+
setSuccessPaymentId(null);
|
|
14521
14516
|
setShouldRenderInstanceSelection(false);
|
|
14522
14517
|
setShouldRenderUpsells(false);
|
|
14523
14518
|
setShouldRenderBookingForm(false);
|
|
@@ -14528,7 +14523,7 @@
|
|
|
14528
14523
|
url.searchParams.delete("payment_intent_client_secret");
|
|
14529
14524
|
url.searchParams.delete("redirect_status");
|
|
14530
14525
|
window.history.replaceState({}, "", url.toString());
|
|
14531
|
-
}, config: config, onError: setError, paymentIntentId:
|
|
14526
|
+
}, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (u$2(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
14532
14527
|
}
|
|
14533
14528
|
if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
|
|
14534
14529
|
return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
|
|
@@ -14541,7 +14536,7 @@
|
|
|
14541
14536
|
setIsSuccess(false);
|
|
14542
14537
|
setCurrentStep("eventTypes");
|
|
14543
14538
|
setShowingPreview(true);
|
|
14544
|
-
|
|
14539
|
+
setSuccessPaymentId(null);
|
|
14545
14540
|
setShouldRenderInstanceSelection(false);
|
|
14546
14541
|
setShouldRenderBookingForm(false);
|
|
14547
14542
|
const url = new URL(window.location.href);
|
|
@@ -14549,7 +14544,7 @@
|
|
|
14549
14544
|
url.searchParams.delete("payment_intent_client_secret");
|
|
14550
14545
|
url.searchParams.delete("redirect_status");
|
|
14551
14546
|
window.history.replaceState({}, "", url.toString());
|
|
14552
|
-
}, config: config, onError: setError, paymentIntentId:
|
|
14547
|
+
}, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (u$2(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
14553
14548
|
}
|
|
14554
14549
|
if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
|
|
14555
14550
|
return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, style: {
|
|
@@ -14578,11 +14573,11 @@
|
|
|
14578
14573
|
setShouldRenderInstanceSelection(true);
|
|
14579
14574
|
}
|
|
14580
14575
|
}, children: config.buttonText ||
|
|
14581
|
-
(isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack
|
|
14576
|
+
(isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
14582
14577
|
setIsSuccess(false);
|
|
14583
14578
|
setCurrentStep("eventTypes");
|
|
14584
14579
|
setSidebarOpen(false);
|
|
14585
|
-
|
|
14580
|
+
setSuccessPaymentId(null);
|
|
14586
14581
|
setShouldRenderInstanceSelection(false);
|
|
14587
14582
|
setShouldRenderUpsells(false);
|
|
14588
14583
|
setShouldRenderBookingForm(false);
|
|
@@ -14593,7 +14588,7 @@
|
|
|
14593
14588
|
url.searchParams.delete("payment_intent_client_secret");
|
|
14594
14589
|
url.searchParams.delete("redirect_status");
|
|
14595
14590
|
window.history.replaceState({}, "", url.toString());
|
|
14596
|
-
}, config: config, onError: setError, paymentIntentId:
|
|
14591
|
+
}, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (u$2(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
14597
14592
|
}
|
|
14598
14593
|
// Cards mode (default) - show event type selection
|
|
14599
14594
|
const cardsView = (u$2(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
|
|
@@ -14625,10 +14620,10 @@
|
|
|
14625
14620
|
};
|
|
14626
14621
|
};
|
|
14627
14622
|
const backHandlers = getBackHandlers();
|
|
14628
|
-
return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack
|
|
14623
|
+
return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
14629
14624
|
setIsSuccess(false);
|
|
14630
14625
|
setCurrentStep("eventTypes");
|
|
14631
|
-
|
|
14626
|
+
setSuccessPaymentId(null);
|
|
14632
14627
|
setShouldRenderInstanceSelection(false);
|
|
14633
14628
|
setShouldRenderUpsells(false);
|
|
14634
14629
|
setShouldRenderBookingForm(false);
|
|
@@ -14639,7 +14634,7 @@
|
|
|
14639
14634
|
url.searchParams.delete("payment_intent_client_secret");
|
|
14640
14635
|
url.searchParams.delete("redirect_status");
|
|
14641
14636
|
window.history.replaceState({}, "", url.toString());
|
|
14642
|
-
}, config: config, onError: setError, paymentIntentId:
|
|
14637
|
+
}, config: config, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (u$2(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
14643
14638
|
}
|
|
14644
14639
|
function UniversalBookingWidget(props) {
|
|
14645
14640
|
const [languagePolicy, setLanguagePolicy] = d$1(null);
|