@bigz-app/booking-widget 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -245,6 +245,8 @@ const de$1 = {
245
245
  "button.depositAndBook": "Anzahlen & buchen",
246
246
  "button.continueWithout": "Weiter ohne Extras",
247
247
  "button.continue": "Weiter",
248
+ "button.continueToPayment": "Weiter zur Zahlung",
249
+ "button.backToDetails": "Zurück zu den Angaben",
248
250
  "button.addExtras": "Extras hinzufügen",
249
251
  // Event types
250
252
  "events.noEventsAvailable": "Keine Veranstaltungen verfügbar",
@@ -437,6 +439,8 @@ const de$1 = {
437
439
  "upsells.noExtras": "Keine Extras für diese Buchung verfügbar.",
438
440
  "upsells.selected": "{{count}} Extra ausgewählt",
439
441
  "upsells.selectedPlural": "{{count}} Extras ausgewählt",
442
+ "upsells.savePercent": "{{percent}}% sparen",
443
+ "booking.paymentUnavailable": "Online-Zahlung ist für diese Buchung nicht verfügbar. Bitte kontaktiere uns, um die Reservierung abzuschließen.",
440
444
  "upsells.spotsFree": "{{count}} Plätze frei",
441
445
  "upsells.notAvailable": "Nicht verfügbar",
442
446
  "upsells.reason.outOfStock": "{{productName}} ist nicht auf Lager",
@@ -521,6 +525,8 @@ const en = {
521
525
  "button.depositAndBook": "Pay deposit & book",
522
526
  "button.continueWithout": "Continue without extras",
523
527
  "button.continue": "Continue",
528
+ "button.continueToPayment": "Continue to payment",
529
+ "button.backToDetails": "Back to details",
524
530
  "button.addExtras": "Add extras",
525
531
  // Event types
526
532
  "events.noEventsAvailable": "No events available",
@@ -713,6 +719,8 @@ const en = {
713
719
  "upsells.noExtras": "No extras available for this booking.",
714
720
  "upsells.selected": "{{count}} extra selected",
715
721
  "upsells.selectedPlural": "{{count}} extras selected",
722
+ "upsells.savePercent": "Save {{percent}}%",
723
+ "booking.paymentUnavailable": "Online payment is not available for this booking. Please contact us to complete your reservation.",
716
724
  "upsells.spotsFree": "{{count}} spots available",
717
725
  "upsells.notAvailable": "Not available",
718
726
  "upsells.reason.outOfStock": "{{productName}} is out of stock",
@@ -797,6 +805,8 @@ const es = {
797
805
  "button.depositAndBook": "Pagar depósito y reservar",
798
806
  "button.continueWithout": "Continuar sin extras",
799
807
  "button.continue": "Continuar",
808
+ "button.continueToPayment": "Continuar al pago",
809
+ "button.backToDetails": "Volver a los datos",
800
810
  "button.addExtras": "Añadir extras",
801
811
  // Event types
802
812
  "events.noEventsAvailable": "No hay eventos disponibles",
@@ -989,6 +999,8 @@ const es = {
989
999
  "upsells.noExtras": "No hay extras disponibles para esta reserva.",
990
1000
  "upsells.selected": "{{count}} extra seleccionado",
991
1001
  "upsells.selectedPlural": "{{count}} extras seleccionados",
1002
+ "upsells.savePercent": "Ahorra {{percent}}%",
1003
+ "booking.paymentUnavailable": "El pago en línea no está disponible para esta reserva. Contáctanos para completarla.",
992
1004
  "upsells.spotsFree": "{{count}} plazas disponibles",
993
1005
  "upsells.notAvailable": "No disponible",
994
1006
  "upsells.reason.outOfStock": "{{productName}} está agotado",
@@ -1073,6 +1085,8 @@ const pt = {
1073
1085
  "button.depositAndBook": "Pagar sinal e reservar",
1074
1086
  "button.continueWithout": "Continuar sem extras",
1075
1087
  "button.continue": "Continuar",
1088
+ "button.continueToPayment": "Continuar para pagamento",
1089
+ "button.backToDetails": "Voltar aos dados",
1076
1090
  "button.addExtras": "Adicionar extras",
1077
1091
  // Event types
1078
1092
  "events.noEventsAvailable": "Sem eventos disponíveis",
@@ -1265,6 +1279,8 @@ const pt = {
1265
1279
  "upsells.noExtras": "Sem extras disponíveis para esta reserva.",
1266
1280
  "upsells.selected": "{{count}} extra selecionado",
1267
1281
  "upsells.selectedPlural": "{{count}} extras selecionados",
1282
+ "upsells.savePercent": "Poupa {{percent}}%",
1283
+ "booking.paymentUnavailable": "O pagamento online não está disponível para esta reserva. Contacta-nos para concluir a reserva.",
1268
1284
  "upsells.spotsFree": "{{count}} lugares disponíveis",
1269
1285
  "upsells.notAvailable": "Não disponível",
1270
1286
  "upsells.reason.outOfStock": "{{productName}} está esgotado",
@@ -1349,6 +1365,8 @@ const sv = {
1349
1365
  "button.depositAndBook": "Betala handpenning & boka",
1350
1366
  "button.continueWithout": "Fortsätt utan tillägg",
1351
1367
  "button.continue": "Fortsätt",
1368
+ "button.continueToPayment": "Fortsätt till betalning",
1369
+ "button.backToDetails": "Tillbaka till uppgifter",
1352
1370
  "button.addExtras": "Lägg till tillägg",
1353
1371
  // Event types
1354
1372
  "events.noEventsAvailable": "Inga evenemang tillgängliga",
@@ -1541,6 +1559,8 @@ const sv = {
1541
1559
  "upsells.noExtras": "Inga tillägg tillgängliga för denna bokning.",
1542
1560
  "upsells.selected": "{{count}} tillägg valt",
1543
1561
  "upsells.selectedPlural": "{{count}} tillägg valda",
1562
+ "upsells.savePercent": "Spara {{percent}}%",
1563
+ "booking.paymentUnavailable": "Onlinebetalning är inte tillgänglig för denna bokning. Kontakta oss för att slutföra bokningen.",
1544
1564
  "upsells.spotsFree": "{{count}} platser lediga",
1545
1565
  "upsells.notAvailable": "Inte tillgängligt",
1546
1566
  "upsells.reason.outOfStock": "{{productName}} är slut i lager",
@@ -11473,7 +11493,7 @@ const sectionHeaderStyles$1 = sectionStyles.header;
11473
11493
  const labelStyles$1 = formStyles.label;
11474
11494
  const inputStyles$1 = formStyles.input;
11475
11495
  const errorTextStyles$1 = formStyles.error;
11476
- function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError, onBackToEventInstances, onBackToEventTypes, selectedEventType, selectedEventInstance, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], }) {
11496
+ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], persistedState = null, onPersistedStateChange, }) {
11477
11497
  const t$1 = useTranslations();
11478
11498
  const { locale } = useLocale();
11479
11499
  const timezone = useTimezone();
@@ -11485,15 +11505,16 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11485
11505
  const raw = Math.round((baseAmount * basisPoints) / 10000);
11486
11506
  return round ? roundDiscountUp(raw) : raw;
11487
11507
  };
11488
- const [appliedVouchers, setAppliedVouchers] = React.useState([]);
11489
- const paymentSectionRef = React.useRef(null);
11508
+ const [appliedVouchers, setAppliedVouchers] = React.useState(() => persistedState?.appliedVouchers ?? []);
11509
+ const [checkoutStep, setCheckoutStep] = React.useState(() => persistedState?.checkoutStep ?? "details");
11490
11510
  // Payment option: "deposit" or "full" - only relevant when deposit is available
11491
- const [paymentOption, setPaymentOption] = React.useState("deposit");
11511
+ const [paymentOption, setPaymentOption] = React.useState(() => persistedState?.paymentOption ?? "deposit");
11492
11512
  // Per-participant upsell selections: participantIndex -> array of upsell package IDs
11493
- const [participantUpsells, setParticipantUpsells] = React.useState({});
11513
+ const [participantUpsells, setParticipantUpsells] = React.useState(() => persistedState?.participantUpsells ?? {});
11514
+ const wasOpenRef = React.useRef(false);
11494
11515
  const form = useForm({
11495
11516
  resolver: t(createBookingFormSchema(t$1, participantFieldsConfig)),
11496
- defaultValues: {
11517
+ defaultValues: persistedState?.formData ?? {
11497
11518
  customerName: "",
11498
11519
  customerEmail: "",
11499
11520
  customerPhone: "",
@@ -11503,6 +11524,28 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11503
11524
  acceptTerms: false,
11504
11525
  },
11505
11526
  });
11527
+ const persistState = React.useCallback(() => {
11528
+ onPersistedStateChange?.({
11529
+ formData: form.getValues(),
11530
+ checkoutStep,
11531
+ paymentOption,
11532
+ appliedVouchers,
11533
+ participantUpsells,
11534
+ });
11535
+ }, [onPersistedStateChange, form, checkoutStep, paymentOption, appliedVouchers, participantUpsells]);
11536
+ React.useEffect(() => {
11537
+ if (isOpen && !wasOpenRef.current && persistedState) {
11538
+ form.reset(persistedState.formData);
11539
+ setCheckoutStep(persistedState.checkoutStep);
11540
+ setPaymentOption(persistedState.paymentOption);
11541
+ setAppliedVouchers(persistedState.appliedVouchers);
11542
+ setParticipantUpsells(persistedState.participantUpsells);
11543
+ }
11544
+ if (!isOpen && wasOpenRef.current) {
11545
+ persistState();
11546
+ }
11547
+ wasOpenRef.current = isOpen;
11548
+ }, [isOpen, persistedState, form, persistState]);
11506
11549
  const watchedParticipants = form.watch("participants");
11507
11550
  const participantCount = watchedParticipants.length;
11508
11551
  const watchedCustomerName = form.watch("customerName");
@@ -11627,6 +11670,18 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11627
11670
  }), [watchedCustomerName, watchedCustomerEmail, watchedCustomerPhone, watchedParticipants, watchedComment]);
11628
11671
  const appliedDiscountCode = appliedVouchers.find((v) => v.type === "discount");
11629
11672
  const appliedGiftCards = appliedVouchers.filter((v) => v.type === "giftCard");
11673
+ const discountCodeProp = appliedDiscountCode
11674
+ ? {
11675
+ id: appliedDiscountCode.id,
11676
+ code: appliedDiscountCode.code,
11677
+ description: appliedDiscountCode.description || undefined,
11678
+ type: appliedDiscountCode.discountType || "percentage",
11679
+ value: appliedDiscountCode.discountValue || 0,
11680
+ discountAmount: appliedDiscountCode.discountAmount,
11681
+ newTotal: appliedDiscountCode.newTotal,
11682
+ }
11683
+ : null;
11684
+ const hasPaymentProvider = Boolean(stripePromise || systemConfig?.paymentProvider === "mollie");
11630
11685
  const handleVoucherValidated = React.useCallback((voucher, _error) => {
11631
11686
  if (voucher) {
11632
11687
  setAppliedVouchers((prev) => [...prev, voucher]);
@@ -11738,19 +11793,12 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11738
11793
  });
11739
11794
  }, [config]);
11740
11795
  const handleClose = () => {
11796
+ persistState();
11797
+ setCheckoutStep("details");
11741
11798
  onClose();
11742
- if (selectedEventInstance && selectedEventType) {
11743
- onBackToEventInstances?.();
11744
- }
11745
- else if (selectedEventType) {
11746
- onBackToEventTypes?.();
11747
- }
11748
- };
11749
- const scrollToPayment = () => {
11750
- paymentSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
11751
11799
  };
11752
11800
  // Footer navigation
11753
- const footerContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: handleClose, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: t$1("common.back") }), jsxRuntime.jsx("button", { type: "button", onClick: scrollToPayment, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: t$1("button.toPayment") })] }));
11801
+ const footerContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: checkoutStep === "payment" ? () => setCheckoutStep("details") : handleClose, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: checkoutStep === "payment" ? t$1("button.backToDetails") : t$1("common.back") }), checkoutStep === "details" && (jsxRuntime.jsx("button", { type: "button", onClick: () => setCheckoutStep("payment"), disabled: !isReadyForPayment() || !hasPaymentProvider, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: t$1("button.continueToPayment") }))] }));
11754
11802
  if (!eventDetails.bookingOpen) {
11755
11803
  return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.notPossible"), children: jsxRuntime.jsx("div", { style: {
11756
11804
  display: "flex",
@@ -11767,264 +11815,211 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11767
11815
  fontFamily: "var(--bw-font-family)",
11768
11816
  }, children: t$1("booking.notPossible") }), jsxRuntime.jsx("p", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.notPossibleMessage") })] }) }) }));
11769
11817
  }
11770
- return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.title", { name: eventDetails.name }), footer: footerContent, children: jsxRuntime.jsxs("div", { className: "booking-widget-container", style: { padding: "16px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.eventDetails") }), jsxRuntime.jsxs("div", { style: {
11771
- display: "grid",
11772
- gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11773
- gap: "12px",
11774
- fontSize: "14px",
11775
- }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11776
- color: "var(--bw-text-muted)",
11777
- fontFamily: "var(--bw-font-family)",
11778
- display: "flex",
11779
- alignItems: "center",
11780
- gap: "4px",
11781
- }, children: [jsxRuntime.jsx(IconCalendar, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.date")] }), jsxRuntime.jsxs("span", { style: {
11782
- color: "var(--bw-text-color)",
11783
- fontWeight: 500,
11784
- fontFamily: "var(--bw-font-family)",
11785
- }, children: [formatEventDate(eventDetails.startTime, timezone, locale), " \u2022 ", formatTime(eventDetails.startTime, timezone, locale)] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11786
- color: "var(--bw-text-muted)",
11787
- fontFamily: "var(--bw-font-family)",
11788
- display: "flex",
11789
- alignItems: "center",
11790
- gap: "4px",
11791
- }, children: [jsxRuntime.jsx(IconClock, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.duration")] }), jsxRuntime.jsxs("span", { style: {
11792
- color: "var(--bw-text-color)",
11793
- fontWeight: 500,
11794
- fontFamily: "var(--bw-font-family)",
11795
- }, children: [eventDetails.durationDays, " ", eventDetails.durationDays > 1 ? t$1("common.days") : t$1("common.day")] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11796
- color: "var(--bw-text-muted)",
11797
- fontFamily: "var(--bw-font-family)",
11818
+ return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.title", { name: eventDetails.name }), footer: footerContent, children: jsxRuntime.jsxs("div", { className: "booking-widget-container", style: { padding: "16px" }, children: [checkoutStep === "details" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.eventDetails") }), jsxRuntime.jsxs("div", { style: {
11819
+ display: "grid",
11820
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11821
+ gap: "12px",
11822
+ fontSize: "14px",
11823
+ }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11824
+ color: "var(--bw-text-muted)",
11825
+ fontFamily: "var(--bw-font-family)",
11826
+ display: "flex",
11827
+ alignItems: "center",
11828
+ gap: "4px",
11829
+ }, children: [jsxRuntime.jsx(IconCalendar, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.date")] }), jsxRuntime.jsxs("span", { style: {
11830
+ color: "var(--bw-text-color)",
11831
+ fontWeight: 500,
11832
+ fontFamily: "var(--bw-font-family)",
11833
+ }, children: [formatEventDate(eventDetails.startTime, timezone, locale), " \u2022 ", formatTime(eventDetails.startTime, timezone, locale)] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11834
+ color: "var(--bw-text-muted)",
11835
+ fontFamily: "var(--bw-font-family)",
11836
+ display: "flex",
11837
+ alignItems: "center",
11838
+ gap: "4px",
11839
+ }, children: [jsxRuntime.jsx(IconClock, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.duration")] }), jsxRuntime.jsxs("span", { style: {
11840
+ color: "var(--bw-text-color)",
11841
+ fontWeight: 500,
11842
+ fontFamily: "var(--bw-font-family)",
11843
+ }, children: [eventDetails.durationDays, " ", eventDetails.durationDays > 1 ? t$1("common.days") : t$1("common.day")] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxRuntime.jsxs("span", { style: {
11844
+ color: "var(--bw-text-muted)",
11845
+ fontFamily: "var(--bw-font-family)",
11846
+ display: "flex",
11847
+ alignItems: "center",
11848
+ gap: "4px",
11849
+ }, children: [jsxRuntime.jsx(IconMoney, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.price")] }), jsxRuntime.jsxs("span", { style: {
11850
+ color: "var(--bw-text-color)",
11851
+ fontWeight: 500,
11852
+ fontFamily: "var(--bw-font-family)",
11853
+ }, children: [formatCurrency(eventDetails.price), " ", t$1("common.perPerson")] })] })] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.contactInfo") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxRuntime.jsxs("div", { style: {
11854
+ display: "grid",
11855
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11856
+ gap: "16px",
11857
+ }, children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerName", style: labelStyles$1, children: t$1("booking.name") }), jsxRuntime.jsx("input", { id: "customerName", ...form.register("customerName"), type: "text", style: inputStyles$1, placeholder: t$1("booking.namePlaceholder") }), customerNameError && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: customerNameError.message }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerEmail", style: labelStyles$1, children: t$1("booking.email") }), jsxRuntime.jsx("input", { id: "customerEmail", ...form.register("customerEmail"), type: "email", style: inputStyles$1, placeholder: t$1("booking.emailPlaceholder") }), customerEmailError && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: customerEmailError.message }))] })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerPhone", style: labelStyles$1, children: t$1("booking.phone") }), jsxRuntime.jsx("input", { id: "customerPhone", ...form.register("customerPhone"), type: "tel", style: inputStyles$1, placeholder: t$1("booking.phonePlaceholder") })] }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", border: "1px solid var(--bw-border-color)", padding: "16px", borderRadius: "var(--bw-border-radius)" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsxRuntime.jsx("input", { id: "acceptTerms", ...form.register("acceptTerms"), type: "checkbox", style: formStyles.checkbox }), jsxRuntime.jsxs("label", { htmlFor: "acceptTerms", style: {
11858
+ fontSize: "14px",
11859
+ color: "var(--bw-text-muted)",
11860
+ fontFamily: "var(--bw-font-family)",
11861
+ maxWidth: "calc(100% - 32px)",
11862
+ overflowWrap: "break-word",
11863
+ cursor: "pointer",
11864
+ }, children: [t$1("booking.acceptTerms"), " ", jsxRuntime.jsx("a", { href: eventDetails.agbUrl || "/terms", style: { color: "var(--bw-highlight-color)", textDecoration: "none" }, target: "_blank", rel: "noopener noreferrer", children: t$1("booking.terms") }), "*"] })] }), form.formState.errors.acceptTerms && (jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, marginTop: "8px" }, children: form.formState.errors.acceptTerms.message }))] })] })] }), jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("div", { style: {
11798
11865
  display: "flex",
11866
+ justifyContent: "space-between",
11799
11867
  alignItems: "center",
11800
- gap: "4px",
11801
- }, children: [jsxRuntime.jsx(IconMoney, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.price")] }), jsxRuntime.jsxs("span", { style: {
11802
- color: "var(--bw-text-color)",
11803
- fontWeight: 500,
11804
- fontFamily: "var(--bw-font-family)",
11805
- }, children: [formatCurrency(eventDetails.price), " ", t$1("common.perPerson")] })] })] })] }), jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.contactInfo") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxRuntime.jsxs("div", { style: {
11806
- display: "grid",
11807
- gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11808
- gap: "16px",
11809
- }, children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerName", style: labelStyles$1, children: t$1("booking.name") }), jsxRuntime.jsx("input", { id: "customerName", ...form.register("customerName"), type: "text", style: inputStyles$1, placeholder: t$1("booking.namePlaceholder") }), customerNameError && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: customerNameError.message }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerEmail", style: labelStyles$1, children: t$1("booking.email") }), jsxRuntime.jsx("input", { id: "customerEmail", ...form.register("customerEmail"), type: "email", style: inputStyles$1, placeholder: t$1("booking.emailPlaceholder") }), customerEmailError && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: customerEmailError.message }))] })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "customerPhone", style: labelStyles$1, children: t$1("booking.phone") }), jsxRuntime.jsx("input", { id: "customerPhone", ...form.register("customerPhone"), type: "tel", style: inputStyles$1, placeholder: t$1("booking.phonePlaceholder") })] }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", border: "1px solid var(--bw-border-color)", padding: "16px", borderRadius: "var(--bw-border-radius)" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsxRuntime.jsx("input", { id: "acceptTerms", ...form.register("acceptTerms"), type: "checkbox", style: formStyles.checkbox }), jsxRuntime.jsxs("label", { htmlFor: "acceptTerms", style: {
11868
+ marginBottom: "16px",
11869
+ }, children: jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: 0 }, children: t$1("booking.participants") }) }), jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [watchedParticipants.map((_, index) => (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [participantFieldsConfig.name.enabled && (jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-name-${index}`, style: labelStyles$1, children: t$1("booking.participantName") }), jsxRuntime.jsx("input", { id: `participant-name-${index}`, ...form.register(`participants.${index}.name`), type: "text", style: inputStyles$1, placeholder: t$1("booking.participantNamePlaceholder") }), form.formState.errors.participants?.[index]?.name && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.name?.message }))] })), participantFieldsConfig.age.enabled && (jsxRuntime.jsxs("div", { style: { width: "80px" }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-age-${index}`, style: labelStyles$1, children: t$1("booking.participantAge") }), jsxRuntime.jsx("input", { id: `participant-age-${index}`, ...form.register(`participants.${index}.age`, {
11870
+ setValueAs: (value) => {
11871
+ if (value === "" || value === null || value === undefined) {
11872
+ return undefined;
11873
+ }
11874
+ const num = Number(value);
11875
+ return Number.isNaN(num) ? undefined : num;
11876
+ },
11877
+ }), type: "number", min: "0", max: "120", style: inputStyles$1, placeholder: "25" })] })), watchedParticipants.length > 1 && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { style: { ...labelStyles$1, visibility: "hidden" }, children: "\u00A0" }), jsxRuntime.jsx("button", { type: "button", onClick: () => removeParticipant(index), style: {
11878
+ color: "var(--bw-error-color)",
11879
+ backgroundColor: "var(--bw-surface-color)",
11880
+ border: "1px solid var(--bw-border-color)",
11881
+ borderRadius: "50%",
11882
+ width: "36px",
11883
+ height: "36px",
11884
+ display: "flex",
11885
+ alignItems: "center",
11886
+ justifyContent: "center",
11887
+ cursor: "pointer",
11888
+ transition: "all 0.2s ease",
11889
+ fontSize: "24px",
11890
+ fontWeight: 700,
11891
+ fontFamily: "var(--bw-font-family)",
11892
+ padding: 0,
11893
+ }, children: "\u00D7" })] }))] }), participantFieldsConfig.level.enabled && (jsxRuntime.jsxs("div", { style: { minWidth: "140px" }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-level-${index}`, style: labelStyles$1, children: t$1("booking.participantLevel") }), jsxRuntime.jsxs("select", { id: `participant-level-${index}`, ...form.register(`participants.${index}.level`), style: inputStyles$1, children: [jsxRuntime.jsx("option", { value: "", children: t$1("booking.participantLevelPlaceholder") }), participantLevelOptions.map((level) => (jsxRuntime.jsx("option", { value: level, children: t$1(`level.${level}`) }, level)))] }), form.formState.errors.participants?.[index]?.level && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.level?.message }))] })), upsells.length > 0 && (jsxRuntime.jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11894
+ const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11895
+ return (jsxRuntime.jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsxRuntime.jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxRuntime.jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11896
+ }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsxRuntime.jsx("div", { style: {
11897
+ display: "flex",
11898
+ flexDirection: "column",
11899
+ alignItems: "center",
11900
+ marginTop: "12px",
11901
+ }, children: jsxRuntime.jsx("button", { type: "button", onClick: addParticipant, style: {
11902
+ color: "#ffffff",
11903
+ fontSize: "14px",
11904
+ fontWeight: 600,
11905
+ padding: "8px 16px",
11906
+ borderRadius: "var(--bw-border-radius)",
11907
+ backgroundColor: "var(--bw-highlight-color)",
11908
+ border: "1px solid var(--bw-highlight-color)",
11909
+ cursor: "pointer",
11910
+ transition: "all 0.2s ease",
11911
+ marginBottom: "4px",
11912
+ fontFamily: "var(--bw-font-family)",
11913
+ boxShadow: "0 2px 8px 0 var(--bw-highlight-color)",
11914
+ }, children: t$1("booking.addParticipant", { number: watchedParticipants.length + 1 }) }) })) : (jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.maxSpotsReached", { count: eventDetails.availableSpots }) }))] })] }), jsxRuntime.jsx(VoucherInput, { config: config, orderValue: baseTotal, eventInstanceId: eventDetails?.id, customerEmail: watchedCustomerEmail, onVoucherValidated: handleVoucherValidated, appliedVouchers: appliedVouchers, onRemoveVoucher: handleRemoveVoucher, disabled: !eventDetails }), jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("label", { htmlFor: "booking-comment", style: labelStyles$1, children: t$1("booking.comment") }), jsxRuntime.jsx("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: t$1("booking.commentPlaceholder"), rows: 3, style: {
11915
+ ...inputStyles$1,
11916
+ resize: "vertical",
11917
+ minHeight: "80px",
11918
+ } })] })] })] })), checkoutStep === "payment" && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxRuntime.jsxs("div", { style: {
11919
+ color: "var(--bw-text-color)",
11920
+ fontWeight: 500,
11921
+ fontFamily: "var(--bw-font-family)",
11922
+ }, children: [jsxRuntime.jsxs("span", { style: { fontWeight: 200 }, children: [watchedParticipants.length > 1 ? watchedParticipants.length : 1, " x "] }), " ", formatCurrency(eventDetails.price)] })] }), upsellsTotal > 0 && (jsxRuntime.jsxs("div", { style: { marginTop: "8px", paddingTop: "8px", borderTop: "1px dashed var(--bw-border-color)" }, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)", fontSize: "13px", display: "block", marginBottom: "4px" }, children: [t$1("common.extras"), ":"] }), upsells.map((upsell) => {
11923
+ // Count how many participants have this upsell selected
11924
+ const countWithUpsell = watchedParticipants.filter((_, idx) => (participantUpsells[idx] || []).includes(upsell.id)).length;
11925
+ if (countWithUpsell === 0)
11926
+ return null;
11927
+ const upsellLineTotal = upsell.price * countWithUpsell;
11928
+ return (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "2px", fontSize: "13px" }, children: jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }) }, upsell.id));
11929
+ })] })), appliedVouchers.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), jsxRuntime.jsx("span", { style: {
11930
+ fontFamily: "var(--bw-font-family)",
11931
+ color: totalDiscount > 0 ? "var(--bw-text-muted)" : "var(--bw-text-muted)",
11932
+ textDecoration: totalDiscount > 0 ? "line-through" : "none",
11933
+ }, children: formatCurrency(baseTotal) })] }), appliedDiscountCode && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: {
11934
+ color: "var(--bw-success-color)",
11935
+ fontFamily: "var(--bw-font-family)",
11810
11936
  fontSize: "14px",
11937
+ }, children: t$1("summary.discount", { code: appliedDiscountCode.code }) }), jsxRuntime.jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(appliedDiscountCode.discountAmount)] })] })), appliedGiftCards.map((giftCard) => (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: {
11938
+ color: "var(--bw-success-color)",
11939
+ fontFamily: "var(--bw-font-family)",
11940
+ fontSize: "14px",
11941
+ }, children: t$1("summary.giftCard", { code: giftCard.code }) }), jsxRuntime.jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(giftCard.balanceToUse || giftCard.discountAmount)] })] }, giftCard.code)))] })), jsxRuntime.jsxs("div", { style: {
11942
+ borderTop: "1px solid var(--bw-border-color)",
11943
+ paddingTop: "12px",
11944
+ }, children: [hasDepositOption && (jsxRuntime.jsxs("div", { style: {
11945
+ display: "flex",
11946
+ justifyContent: "space-between",
11947
+ alignItems: "center",
11948
+ fontSize: "14px",
11949
+ marginBottom: "12px",
11950
+ }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.totalAmount") }), jsxRuntime.jsx("span", { style: {
11811
11951
  color: "var(--bw-text-muted)",
11812
11952
  fontFamily: "var(--bw-font-family)",
11813
- maxWidth: "calc(100% - 32px)",
11814
- overflowWrap: "break-word",
11953
+ fontWeight: 500,
11954
+ }, children: formatCurrency(totalAmount) })] })), hasDepositOption && (jsxRuntime.jsxs("div", { style: {
11955
+ display: "flex",
11956
+ gap: "8px",
11957
+ marginBottom: "16px",
11958
+ }, children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setPaymentOption("deposit"), style: {
11959
+ flex: 1,
11960
+ padding: "12px",
11961
+ borderRadius: "var(--bw-border-radius)",
11962
+ border: paymentOption === "deposit"
11963
+ ? "2px solid var(--bw-highlight-color)"
11964
+ : "1px solid var(--bw-border-color)",
11965
+ backgroundColor: paymentOption === "deposit"
11966
+ ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11967
+ : "var(--bw-surface-color)",
11815
11968
  cursor: "pointer",
11816
- }, children: [t$1("booking.acceptTerms"), " ", jsxRuntime.jsx("a", { href: eventDetails.agbUrl || "/terms", style: { color: "var(--bw-highlight-color)", textDecoration: "none" }, target: "_blank", rel: "noopener noreferrer", children: t$1("booking.terms") }), "*"] })] }), form.formState.errors.acceptTerms && (jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, marginTop: "8px" }, children: form.formState.errors.acceptTerms.message }))] })] })] }), jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("div", { style: {
11817
- display: "flex",
11818
- justifyContent: "space-between",
11819
- alignItems: "center",
11820
- marginBottom: "16px",
11821
- }, children: jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: 0 }, children: t$1("booking.participants") }) }), jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [watchedParticipants.map((_, index) => (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [participantFieldsConfig.name.enabled && (jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-name-${index}`, style: labelStyles$1, children: t$1("booking.participantName") }), jsxRuntime.jsx("input", { id: `participant-name-${index}`, ...form.register(`participants.${index}.name`), type: "text", style: inputStyles$1, placeholder: t$1("booking.participantNamePlaceholder") }), form.formState.errors.participants?.[index]?.name && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.name?.message }))] })), participantFieldsConfig.age.enabled && (jsxRuntime.jsxs("div", { style: { width: "80px" }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-age-${index}`, style: labelStyles$1, children: t$1("booking.participantAge") }), jsxRuntime.jsx("input", { id: `participant-age-${index}`, ...form.register(`participants.${index}.age`, {
11822
- setValueAs: (value) => {
11823
- if (value === "" || value === null || value === undefined) {
11824
- return undefined;
11825
- }
11826
- const num = Number(value);
11827
- return Number.isNaN(num) ? undefined : num;
11828
- },
11829
- }), type: "number", min: "0", max: "120", style: inputStyles$1, placeholder: "25" })] })), watchedParticipants.length > 1 && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { style: { ...labelStyles$1, visibility: "hidden" }, children: "\u00A0" }), jsxRuntime.jsx("button", { type: "button", onClick: () => removeParticipant(index), style: {
11830
- color: "var(--bw-error-color)",
11831
- backgroundColor: "var(--bw-surface-color)",
11832
- border: "1px solid var(--bw-border-color)",
11833
- borderRadius: "50%",
11834
- width: "36px",
11835
- height: "36px",
11836
- display: "flex",
11837
- alignItems: "center",
11838
- justifyContent: "center",
11839
- cursor: "pointer",
11840
- transition: "all 0.2s ease",
11841
- fontSize: "24px",
11969
+ fontFamily: "var(--bw-font-family)",
11970
+ transition: "all 0.2s ease",
11971
+ }, children: [jsxRuntime.jsx("div", { style: {
11972
+ fontSize: "13px",
11973
+ color: "var(--bw-text-muted)",
11974
+ marginBottom: "4px",
11975
+ }, children: t$1("summary.deposit") }), jsxRuntime.jsx("div", { style: {
11976
+ fontSize: "18px",
11842
11977
  fontWeight: 700,
11843
- fontFamily: "var(--bw-font-family)",
11844
- padding: 0,
11845
- }, children: "\u00D7" })] }))] }), participantFieldsConfig.level.enabled && (jsxRuntime.jsxs("div", { style: { minWidth: "140px" }, children: [jsxRuntime.jsx("label", { htmlFor: `participant-level-${index}`, style: labelStyles$1, children: t$1("booking.participantLevel") }), jsxRuntime.jsxs("select", { id: `participant-level-${index}`, ...form.register(`participants.${index}.level`), style: inputStyles$1, children: [jsxRuntime.jsx("option", { value: "", children: t$1("booking.participantLevelPlaceholder") }), participantLevelOptions.map((level) => (jsxRuntime.jsx("option", { value: level, children: t$1(`level.${level}`) }, level)))] }), form.formState.errors.participants?.[index]?.level && (jsxRuntime.jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.level?.message }))] })), upsells.length > 0 && (jsxRuntime.jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11846
- const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11847
- return (jsxRuntime.jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsxRuntime.jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxRuntime.jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11848
- }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsxRuntime.jsx("div", { style: {
11849
- display: "flex",
11850
- flexDirection: "column",
11851
- alignItems: "center",
11852
- marginTop: "12px",
11853
- }, children: jsxRuntime.jsx("button", { type: "button", onClick: addParticipant, style: {
11854
- color: "#ffffff",
11855
- fontSize: "14px",
11856
- fontWeight: 600,
11857
- padding: "8px 16px",
11858
- borderRadius: "var(--bw-border-radius)",
11859
- backgroundColor: "var(--bw-highlight-color)",
11860
- border: "1px solid var(--bw-highlight-color)",
11861
- cursor: "pointer",
11862
- transition: "all 0.2s ease",
11863
- marginBottom: "4px",
11864
- fontFamily: "var(--bw-font-family)",
11865
- boxShadow: "0 2px 8px 0 var(--bw-highlight-color)",
11866
- }, children: t$1("booking.addParticipant", { number: watchedParticipants.length + 1 }) }) })) : (jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.maxSpotsReached", { count: eventDetails.availableSpots }) }))] })] }), jsxRuntime.jsx(VoucherInput, { config: config, orderValue: baseTotal, eventInstanceId: eventDetails?.id, customerEmail: watchedCustomerEmail, onVoucherValidated: handleVoucherValidated, appliedVouchers: appliedVouchers, onRemoveVoucher: handleRemoveVoucher, disabled: !eventDetails }), jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("label", { htmlFor: "booking-comment", style: labelStyles$1, children: t$1("booking.comment") }), jsxRuntime.jsx("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: t$1("booking.commentPlaceholder"), rows: 3, style: {
11867
- ...inputStyles$1,
11868
- resize: "vertical",
11869
- minHeight: "80px",
11870
- } })] }), jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxRuntime.jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxRuntime.jsxs("div", { style: {
11871
- color: "var(--bw-text-color)",
11872
- fontWeight: 500,
11978
+ color: paymentOption === "deposit"
11979
+ ? "var(--bw-highlight-color)"
11980
+ : "var(--bw-text-color)",
11981
+ }, children: formatCurrency(depositAmount) })] }), jsxRuntime.jsxs("button", { type: "button", onClick: () => setPaymentOption("full"), style: {
11982
+ flex: 1,
11983
+ padding: "12px",
11984
+ borderRadius: "var(--bw-border-radius)",
11985
+ border: paymentOption === "full"
11986
+ ? "2px solid var(--bw-highlight-color)"
11987
+ : "1px solid var(--bw-border-color)",
11988
+ backgroundColor: paymentOption === "full"
11989
+ ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11990
+ : "var(--bw-surface-color)",
11991
+ cursor: "pointer",
11873
11992
  fontFamily: "var(--bw-font-family)",
11874
- }, children: [jsxRuntime.jsxs("span", { style: { fontWeight: 200 }, children: [watchedParticipants.length > 1 ? watchedParticipants.length : 1, " x "] }), " ", formatCurrency(eventDetails.price)] })] }), upsellsTotal > 0 && (jsxRuntime.jsxs("div", { style: { marginTop: "8px", paddingTop: "8px", borderTop: "1px dashed var(--bw-border-color)" }, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)", fontSize: "13px", display: "block", marginBottom: "4px" }, children: [t$1("common.extras"), ":"] }), upsells.map((upsell) => {
11875
- // Count how many participants have this upsell selected
11876
- const countWithUpsell = watchedParticipants.filter((_, idx) => (participantUpsells[idx] || []).includes(upsell.id)).length;
11877
- if (countWithUpsell === 0)
11878
- return null;
11879
- const upsellLineTotal = upsell.price * countWithUpsell;
11880
- return (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px" }, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }, upsell.id));
11881
- })] })), appliedVouchers.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), jsxRuntime.jsx("span", { style: {
11882
- fontFamily: "var(--bw-font-family)",
11883
- color: totalDiscount > 0 ? "var(--bw-text-muted)" : "var(--bw-text-muted)",
11884
- textDecoration: totalDiscount > 0 ? "line-through" : "none",
11885
- }, children: formatCurrency(baseTotal) })] }), appliedDiscountCode && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: {
11886
- color: "var(--bw-success-color)",
11887
- fontFamily: "var(--bw-font-family)",
11888
- fontSize: "14px",
11889
- }, children: t$1("summary.discount", { code: appliedDiscountCode.code }) }), jsxRuntime.jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(appliedDiscountCode.discountAmount)] })] })), appliedGiftCards.map((giftCard) => (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxRuntime.jsx("span", { style: {
11890
- color: "var(--bw-success-color)",
11891
- fontFamily: "var(--bw-font-family)",
11892
- fontSize: "14px",
11893
- }, children: t$1("summary.giftCard", { code: giftCard.code }) }), jsxRuntime.jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(giftCard.balanceToUse || giftCard.discountAmount)] })] }, giftCard.code)))] })), jsxRuntime.jsxs("div", { style: {
11894
- borderTop: "1px solid var(--bw-border-color)",
11895
- paddingTop: "12px",
11896
- }, children: [hasDepositOption && (jsxRuntime.jsxs("div", { style: {
11897
- display: "flex",
11898
- gap: "8px",
11899
- marginBottom: "16px",
11900
- }, children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setPaymentOption("deposit"), style: {
11901
- flex: 1,
11902
- padding: "12px",
11903
- borderRadius: "var(--bw-border-radius)",
11904
- border: paymentOption === "deposit"
11905
- ? "2px solid var(--bw-highlight-color)"
11906
- : "1px solid var(--bw-border-color)",
11907
- backgroundColor: paymentOption === "deposit"
11908
- ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11909
- : "var(--bw-surface-color)",
11910
- cursor: "pointer",
11911
- fontFamily: "var(--bw-font-family)",
11912
- transition: "all 0.2s ease",
11913
- }, children: [jsxRuntime.jsx("div", { style: {
11914
- fontSize: "13px",
11915
- color: "var(--bw-text-muted)",
11916
- marginBottom: "4px",
11917
- }, children: t$1("summary.deposit") }), jsxRuntime.jsx("div", { style: {
11918
- fontSize: "18px",
11919
- fontWeight: 700,
11920
- color: paymentOption === "deposit"
11921
- ? "var(--bw-highlight-color)"
11922
- : "var(--bw-text-color)",
11923
- }, children: formatCurrency(depositAmount) })] }), jsxRuntime.jsxs("button", { type: "button", onClick: () => setPaymentOption("full"), style: {
11924
- flex: 1,
11925
- padding: "12px",
11926
- borderRadius: "var(--bw-border-radius)",
11927
- border: paymentOption === "full"
11928
- ? "2px solid var(--bw-highlight-color)"
11929
- : "1px solid var(--bw-border-color)",
11930
- backgroundColor: paymentOption === "full"
11931
- ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11932
- : "var(--bw-surface-color)",
11933
- cursor: "pointer",
11934
- fontFamily: "var(--bw-font-family)",
11935
- transition: "all 0.2s ease",
11936
- }, children: [jsxRuntime.jsx("div", { style: {
11937
- fontSize: "13px",
11938
- color: "var(--bw-text-muted)",
11939
- marginBottom: "4px",
11940
- }, children: t$1("summary.payFull") }), jsxRuntime.jsx("div", { style: {
11941
- fontSize: "18px",
11942
- fontWeight: 700,
11943
- color: paymentOption === "full"
11944
- ? "var(--bw-highlight-color)"
11945
- : "var(--bw-text-color)",
11946
- }, children: formatCurrency(totalAmount) })] })] })), hasDepositOption && paymentOption === "deposit" && (jsxRuntime.jsxs("div", { style: {
11947
- display: "flex",
11948
- justifyContent: "space-between",
11949
- alignItems: "center",
11950
- fontSize: "14px",
11951
- marginBottom: "8px",
11952
- }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.totalAmount") }), jsxRuntime.jsx("span", { style: {
11993
+ transition: "all 0.2s ease",
11994
+ }, children: [jsxRuntime.jsx("div", { style: {
11995
+ fontSize: "13px",
11953
11996
  color: "var(--bw-text-muted)",
11954
- fontFamily: "var(--bw-font-family)",
11955
- fontWeight: 500,
11956
- }, children: formatCurrency(totalAmount) })] })), jsxRuntime.jsxs("div", { style: {
11957
- display: "flex",
11958
- justifyContent: "space-between",
11959
- alignItems: "center",
11960
- fontSize: "18px",
11961
- fontWeight: 600,
11962
- }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-color)", fontFamily: "var(--bw-font-family)" }, children: hasDepositOption && paymentOption === "deposit"
11963
- ? t$1("summary.payToday")
11964
- : t$1("summary.totalAmount") }), jsxRuntime.jsx("span", { style: {
11965
- color: "var(--bw-highlight-color)",
11966
- fontFamily: "var(--bw-font-family)",
11997
+ marginBottom: "4px",
11998
+ }, children: t$1("summary.payFull") }), jsxRuntime.jsx("div", { style: {
11999
+ fontSize: "18px",
11967
12000
  fontWeight: 700,
11968
- }, children: formatCurrency(paymentAmount) })] }), hasDepositOption && paymentOption === "deposit" && (jsxRuntime.jsx("div", { style: {
11969
- fontSize: "12px",
11970
- color: "var(--bw-text-muted)",
12001
+ color: paymentOption === "full"
12002
+ ? "var(--bw-highlight-color)"
12003
+ : "var(--bw-text-color)",
12004
+ }, children: formatCurrency(totalAmount) })] })] })), jsxRuntime.jsxs("div", { style: {
12005
+ display: "flex",
12006
+ justifyContent: "space-between",
12007
+ alignItems: "center",
12008
+ fontSize: "18px",
12009
+ fontWeight: 600,
12010
+ }, children: [jsxRuntime.jsx("span", { style: { color: "var(--bw-text-color)", fontFamily: "var(--bw-font-family)" }, children: hasDepositOption && paymentOption === "deposit"
12011
+ ? t$1("summary.payToday")
12012
+ : t$1("summary.totalAmount") }), jsxRuntime.jsx("span", { style: {
12013
+ color: "var(--bw-highlight-color)",
11971
12014
  fontFamily: "var(--bw-font-family)",
11972
- marginTop: "8px",
11973
- textAlign: "right",
11974
- }, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), jsxRuntime.jsx("div", { ref: paymentSectionRef, children: (stripePromise || systemConfig?.paymentProvider === "mollie") &&
11975
- (() => {
11976
- if (!isReadyForPayment()) {
11977
- const participantsWithNames = watchedParticipants.filter((p) => p.name?.trim()).length;
11978
- const totalParticipantRows = watchedParticipants.length;
11979
- const participantsWithoutNames = totalParticipantRows - participantsWithNames;
11980
- const missing = [];
11981
- if (participantFieldsConfig.name.required) {
11982
- if (participantsWithNames === 0) {
11983
- missing.push(t$1("payment.needParticipant"));
11984
- }
11985
- else if (participantsWithoutNames > 0) {
11986
- missing.push(t$1("payment.needAllNames", { count: totalParticipantRows }));
11987
- }
11988
- }
11989
- if (participantsWithNames > (eventDetails?.availableSpots || 0)) {
11990
- missing.push(t$1("payment.reduceParticipants", { count: eventDetails?.availableSpots || 0 }));
11991
- }
11992
- if (!watchedCustomerName || watchedCustomerName.trim().length < 2 || customerNameError) {
11993
- missing.push(t$1("payment.needValidName"));
11994
- }
11995
- if (!watchedCustomerEmail || watchedCustomerEmail.trim().length === 0 || customerEmailError) {
11996
- missing.push(t$1("payment.needValidEmail"));
11997
- }
11998
- if (!watchedAcceptTerms) {
11999
- missing.push(t$1("payment.needAcceptTerms"));
12000
- }
12001
- const message = missing.length > 0
12002
- ? t$1("payment.missingFields", { fields: missing.join(", ") })
12003
- : t$1("payment.fillRequired");
12004
- return (jsxRuntime.jsx("div", { style: {
12005
- ...cardStyles$1,
12006
- border: "1px solid var(--bw-warning-color)",
12007
- color: "var(--bw-warning-color)",
12015
+ fontWeight: 700,
12016
+ }, children: formatCurrency(paymentAmount) })] }), hasDepositOption && paymentOption === "deposit" && (jsxRuntime.jsx("div", { style: {
12017
+ fontSize: "12px",
12018
+ color: "var(--bw-text-muted)",
12008
12019
  fontFamily: "var(--bw-font-family)",
12009
- textAlign: "center",
12010
- }, children: message }));
12011
- }
12012
- const discountCodeProp = appliedDiscountCode
12013
- ? {
12014
- id: appliedDiscountCode.id,
12015
- code: appliedDiscountCode.code,
12016
- description: appliedDiscountCode.description || undefined,
12017
- type: appliedDiscountCode.discountType || "percentage",
12018
- value: appliedDiscountCode.discountValue || 0,
12019
- discountAmount: appliedDiscountCode.discountAmount,
12020
- newTotal: appliedDiscountCode.newTotal,
12021
- }
12022
- : null;
12023
- if (systemConfig?.paymentProvider === "mollie") {
12024
- return (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] }));
12025
- }
12026
- return (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] }));
12027
- })() })] })] })] }) }));
12020
+ marginTop: "8px",
12021
+ textAlign: "right",
12022
+ }, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), !hasPaymentProvider && (jsxRuntime.jsx("div", { style: cardStyles$1, children: jsxRuntime.jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && (systemConfig?.paymentProvider === "mollie" ? (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] })) : (jsxRuntime.jsxs("div", { style: cardStyles$1, children: [jsxRuntime.jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsxRuntime.jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] })))] }))] }) }));
12028
12023
  }
12029
12024
 
12030
12025
  /**
@@ -15191,12 +15186,11 @@ function PromoDialog({ config, onClose, onCtaClick }) {
15191
15186
  return ReactDOM.createPortal(dialogContent, portalContainer);
15192
15187
  }
15193
15188
 
15194
- // Upsell card styles
15195
15189
  const cardBaseStyles = {
15196
15190
  position: "relative",
15197
15191
  display: "flex",
15198
15192
  flexDirection: "column",
15199
- padding: "16px",
15193
+ padding: "12px",
15200
15194
  backgroundColor: "var(--bw-surface-color)",
15201
15195
  borderWidth: "2px",
15202
15196
  borderStyle: "solid",
@@ -15216,19 +15210,13 @@ const cardDisabledStyles = {
15216
15210
  opacity: 0.6,
15217
15211
  cursor: "not-allowed",
15218
15212
  };
15219
- const checkboxContainerStyles = {
15220
- position: "absolute",
15221
- bottom: "12px",
15222
- left: "12px",
15223
- zIndex: 1,
15224
- };
15225
15213
  const checkboxInnerStyles = {
15226
- width: "24px",
15227
- height: "24px",
15214
+ width: "48px",
15215
+ height: "48px",
15228
15216
  borderWidth: "2px",
15229
15217
  borderStyle: "solid",
15230
15218
  borderColor: "var(--bw-border-color)",
15231
- borderRadius: "6px",
15219
+ borderRadius: "12px",
15232
15220
  display: "flex",
15233
15221
  alignItems: "center",
15234
15222
  justifyContent: "center",
@@ -15240,13 +15228,13 @@ const checkboxSelectedStyles = {
15240
15228
  borderColor: "var(--bw-highlight-color)",
15241
15229
  backgroundColor: "var(--bw-highlight-color)",
15242
15230
  };
15243
- const imageContainerStyles = {
15244
- width: "100%",
15245
- height: "120px",
15246
- marginBottom: "12px",
15231
+ const previewImageContainerStyles = {
15232
+ width: "56px",
15233
+ height: "56px",
15247
15234
  borderRadius: "calc(var(--bw-border-radius) - 4px)",
15248
15235
  overflow: "hidden",
15249
15236
  backgroundColor: "var(--bw-background-color)",
15237
+ flexShrink: 0,
15250
15238
  };
15251
15239
  const imageStyles = {
15252
15240
  width: "100%",
@@ -15261,23 +15249,53 @@ const imagePlaceholderStyles = {
15261
15249
  justifyContent: "center",
15262
15250
  color: "var(--bw-text-muted)",
15263
15251
  };
15264
- const nameStyles = {
15252
+ const previewNameStyles = {
15265
15253
  fontSize: "16px",
15266
15254
  fontWeight: 600,
15267
15255
  color: "var(--bw-text-color)",
15268
- margin: "0 0 6px 0",
15269
- paddingRight: "36px",
15256
+ margin: 0,
15257
+ fontFamily: "var(--bw-font-family)",
15258
+ };
15259
+ const previewHeaderStyles = {
15260
+ display: "flex",
15261
+ alignItems: "center",
15262
+ gap: "10px",
15263
+ };
15264
+ const previewPriceStyles = {
15265
+ fontSize: "13px",
15266
+ color: "var(--bw-text-muted)",
15267
+ marginTop: "2px",
15270
15268
  fontFamily: "var(--bw-font-family)",
15271
15269
  };
15270
+ const headerRightStyles = {
15271
+ marginLeft: "auto",
15272
+ display: "flex",
15273
+ alignItems: "center",
15274
+ gap: "8px",
15275
+ };
15276
+ const chevronStyles = {
15277
+ fontSize: "12px",
15278
+ color: "var(--bw-text-muted)",
15279
+ transition: "transform 0.2s ease",
15280
+ };
15281
+ const expandedContentStyles = {
15282
+ marginTop: "12px",
15283
+ paddingTop: "12px",
15284
+ borderTop: "1px solid var(--bw-border-color)",
15285
+ };
15286
+ const expandedImageContainerStyles = {
15287
+ width: "100%",
15288
+ height: "180px",
15289
+ marginBottom: "12px",
15290
+ borderRadius: "calc(var(--bw-border-radius) - 4px)",
15291
+ overflow: "hidden",
15292
+ backgroundColor: "var(--bw-background-color)",
15293
+ };
15272
15294
  const descriptionStyles = {
15273
15295
  fontSize: "13px",
15274
15296
  color: "var(--bw-text-muted)",
15275
15297
  margin: "0 0 10px 0",
15276
15298
  lineHeight: 1.4,
15277
- display: "-webkit-box",
15278
- WebkitLineClamp: 5,
15279
- WebkitBoxOrient: "vertical",
15280
- overflow: "hidden",
15281
15299
  fontFamily: "var(--bw-font-family)",
15282
15300
  };
15283
15301
  const itemsContainerStyles = {
@@ -15359,6 +15377,8 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
15359
15377
  const { locale } = useLocale();
15360
15378
  const totalPrice = upsell.price * participantCount;
15361
15379
  const isDisabled = !upsell.available;
15380
+ const [isExpanded, setIsExpanded] = React.useState(false);
15381
+ const hasSavings = (upsell.savingsPercent ?? 0) > 0;
15362
15382
  const getCardStyles = () => {
15363
15383
  if (isDisabled)
15364
15384
  return cardDisabledStyles;
@@ -15366,16 +15386,22 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
15366
15386
  return cardSelectedStyles;
15367
15387
  return cardBaseStyles;
15368
15388
  };
15369
- return (jsxRuntime.jsxs("div", { style: getCardStyles(), onClick: !isDisabled ? onSelect : undefined, role: "checkbox", "aria-checked": isSelected, tabIndex: isDisabled ? -1 : 0, onKeyDown: (e) => {
15389
+ const toggleExpanded = () => {
15390
+ setIsExpanded((current) => !current);
15391
+ };
15392
+ return (jsxRuntime.jsxs("div", { style: getCardStyles(), onClick: !isDisabled ? toggleExpanded : undefined, role: "button", "aria-expanded": isExpanded, tabIndex: isDisabled ? -1 : 0, onKeyDown: (e) => {
15370
15393
  if (!isDisabled && (e.key === "Enter" || e.key === " ")) {
15371
15394
  e.preventDefault();
15372
- onSelect();
15395
+ toggleExpanded();
15373
15396
  }
15374
- }, children: [jsxRuntime.jsx("div", { style: checkboxContainerStyles, children: jsxRuntime.jsx("div", { style: isSelected ? checkboxSelectedStyles : checkboxInnerStyles, children: isSelected && (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", style: { width: "16px", height: "16px" }, children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) })) }) }), jsxRuntime.jsx("div", { style: imageContainerStyles, children: upsell.image ? (jsxRuntime.jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsxRuntime.jsx("div", { style: imagePlaceholderStyles, children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "40px", height: "40px", opacity: 0.4 }, children: jsxRuntime.jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [jsxRuntime.jsx("h4", { style: nameStyles, children: upsell.name }), upsell.description && (jsxRuntime.jsx("p", { style: descriptionStyles, children: upsell.description })), upsell.items.length > 0 && (jsxRuntime.jsx("div", { style: itemsContainerStyles, children: upsell.items.map((item, index) => (jsxRuntime.jsxs("span", { style: itemStyles, children: [item.type === "product" ? "📦" : "🎫", " ", item.name, item.quantity > 1 && ` (${item.quantity}x)`] }, index))) })), upsell.suggestedEventInstance && (jsxRuntime.jsxs("div", { style: eventInfoStyles, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-text-color)", fontWeight: 500 }, children: ["\uD83D\uDCC5 ", new Date(upsell.suggestedEventInstance.date).toLocaleDateString(locale === "de" ? "de-DE" : locale === "en" ? "en-US" : locale === "es" ? "es-ES" : locale === "sv" ? "sv-SE" : "pt-PT", {
15397
+ }, children: [jsxRuntime.jsxs("div", { style: previewHeaderStyles, children: [jsxRuntime.jsx("div", { style: previewImageContainerStyles, children: upsell.image ? (jsxRuntime.jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsxRuntime.jsx("div", { style: imagePlaceholderStyles, children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "32px", height: "32px", opacity: 0.4 }, children: jsxRuntime.jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), jsxRuntime.jsxs("div", { style: { minWidth: 0 }, children: [jsxRuntime.jsx("h4", { style: previewNameStyles, children: upsell.name }), jsxRuntime.jsxs("div", { style: previewPriceStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), hasSavings && (jsxRuntime.jsx("div", { style: { ...previewPriceStyles, color: "var(--bw-highlight-color)" }, children: t("upsells.savePercent", { percent: upsell.savingsPercent ?? 0 }) }))] }), jsxRuntime.jsxs("div", { style: headerRightStyles, children: [jsxRuntime.jsx("button", { type: "button", onClick: (event) => {
15398
+ event.stopPropagation();
15399
+ onSelect();
15400
+ }, "aria-label": t("common.extras"), style: { background: "transparent", border: "none", cursor: "pointer", padding: 0 }, disabled: isDisabled, children: jsxRuntime.jsx("div", { style: isSelected ? checkboxSelectedStyles : checkboxInnerStyles, children: isSelected && (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", style: { width: "32px", height: "32px" }, children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) })) }) }), jsxRuntime.jsx("span", { style: { ...chevronStyles, transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)" }, children: "\u25BC" })] })] }), isExpanded && (jsxRuntime.jsxs("div", { style: expandedContentStyles, children: [jsxRuntime.jsx("div", { style: expandedImageContainerStyles, children: upsell.image ? (jsxRuntime.jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsxRuntime.jsx("div", { style: imagePlaceholderStyles, children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "40px", height: "40px", opacity: 0.4 }, children: jsxRuntime.jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), upsell.description && (jsxRuntime.jsx("p", { style: descriptionStyles, children: upsell.description })), upsell.items.length > 0 && (jsxRuntime.jsx("div", { style: itemsContainerStyles, children: upsell.items.map((item, index) => (jsxRuntime.jsxs("span", { style: itemStyles, children: [item.type === "product" ? "📦" : "🎫", " ", item.name, item.quantity > 1 && ` (${item.quantity}x)`] }, index))) })), upsell.suggestedEventInstance && (jsxRuntime.jsxs("div", { style: eventInfoStyles, children: [jsxRuntime.jsxs("span", { style: { color: "var(--bw-text-color)", fontWeight: 500 }, children: ["\uD83D\uDCC5 ", new Date(upsell.suggestedEventInstance.date).toLocaleDateString(locale === "de" ? "de-DE" : locale === "en" ? "en-US" : locale === "es" ? "es-ES" : locale === "sv" ? "sv-SE" : "pt-PT", {
15375
15401
  weekday: "short",
15376
15402
  day: "numeric",
15377
15403
  month: "short",
15378
- })] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxRuntime.jsxs("div", { style: priceContainerStyles, children: [jsxRuntime.jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxRuntime.jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsxRuntime.jsx("div", { style: unavailableOverlayStyles, children: jsxRuntime.jsx("span", { children: upsell.unavailableReason
15404
+ })] }), jsxRuntime.jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] })), jsxRuntime.jsxs("div", { style: priceContainerStyles, children: [jsxRuntime.jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxRuntime.jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] })), hasSavings && (jsxRuntime.jsx("span", { style: priceTotalStyles, children: t("upsells.savePercent", { percent: upsell.savingsPercent ?? 0 }) }))] })] })), isDisabled && (jsxRuntime.jsx("div", { style: unavailableOverlayStyles, children: jsxRuntime.jsx("span", { children: upsell.unavailableReason
15379
15405
  ? formatUnavailableReason(upsell.unavailableReason, t)
15380
15406
  : t("upsells.notAvailable") }) }))] }));
15381
15407
  }
@@ -15394,20 +15420,9 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
15394
15420
  }
15395
15421
  };
15396
15422
  const isSelected = (upsellId) => selectedUpsells.some((s) => s.upsellPackageId === upsellId);
15397
- // Calculate total for selected upsells
15398
- const calculateTotal = () => {
15399
- return selectedUpsells.reduce((total, selection) => {
15400
- const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
15401
- if (upsell) {
15402
- return total + upsell.price * selection.quantity;
15403
- }
15404
- return total;
15405
- }, 0);
15406
- };
15407
- const selectedTotal = calculateTotal();
15408
15423
  const selectedCount = selectedUpsells.length;
15409
15424
  const footerContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: onBack, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), className: buttonClassName, children: t("common.back") }), jsxRuntime.jsx("button", { type: "button", onClick: onContinue, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), className: buttonClassName, children: selectedCount === 0 ? t("button.continueWithout") : t("button.continue") })] }));
15410
- return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsxRuntime.jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsxRuntime.jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsxRuntime.jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: [jsxRuntime.jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
15425
+ return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsxRuntime.jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsxRuntime.jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsxRuntime.jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: jsxRuntime.jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }) }))] }) }));
15411
15426
  }
15412
15427
 
15413
15428
  /**
@@ -15545,6 +15560,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
15545
15560
  // Upsells state
15546
15561
  const [upsells, setUpsells] = React.useState([]);
15547
15562
  const [selectedUpsells, setSelectedUpsells] = React.useState([]);
15563
+ const [bookingPersistedState, setBookingPersistedState] = React.useState(null);
15548
15564
  const [isLoadingUpsells, setIsLoadingUpsells] = React.useState(false);
15549
15565
  const [tempParticipantCount, setTempParticipantCount] = React.useState(1); // Used during upsell step
15550
15566
  // State for upcoming events (next-events view mode)
@@ -16199,6 +16215,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16199
16215
  const handleEventInstanceSelect = async (eventInstance) => {
16200
16216
  trackEvent("event_instance_selected", { eventInstanceId: eventInstance.id, eventInstanceName: eventInstance.name });
16201
16217
  setSelectedEventInstance(eventInstance);
16218
+ setBookingPersistedState(null);
16202
16219
  bookingReturnStep.current = "eventInstances";
16203
16220
  // Set default participant count for upsell calculations
16204
16221
  const defaultParticipantCount = 1;
@@ -16252,6 +16269,21 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16252
16269
  setCurrentStep(bookingReturnStep.current);
16253
16270
  setSelectedEventInstance(null);
16254
16271
  setEventDetails(null);
16272
+ setBookingPersistedState(null);
16273
+ };
16274
+ const handleBackFromBooking = () => {
16275
+ if (upsells.length > 0) {
16276
+ setCurrentStep("upsells");
16277
+ return;
16278
+ }
16279
+ if (isDirectInstanceMode) {
16280
+ setCurrentStep("eventTypes");
16281
+ setSidebarOpen(false);
16282
+ setEventDetails(null);
16283
+ setBookingPersistedState(null);
16284
+ return;
16285
+ }
16286
+ handleBackToEventInstances();
16255
16287
  };
16256
16288
  const handleBookingSuccess = (result) => {
16257
16289
  trackEvent("booking_completed", { paymentIntentId: result.paymentIntent?.id });
@@ -16259,6 +16291,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16259
16291
  setSuccessPaymentId(result.paymentIntent.id);
16260
16292
  setSidebarOpen(false);
16261
16293
  setShouldRenderBookingForm(false);
16294
+ setBookingPersistedState(null);
16262
16295
  config.onSuccess?.(result);
16263
16296
  };
16264
16297
  const handleBookingError = (errorMessage) => {
@@ -16327,6 +16360,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16327
16360
  ? (eventTypes.find((et) => et.id === eventTypeId) ?? selectedEventType)
16328
16361
  : selectedEventType;
16329
16362
  if (resolvedEventType && resolvedEventType !== selectedEventType) {
16363
+ trackEvent("event_type_selected", { eventTypeId: resolvedEventType.id, eventTypeName: resolvedEventType.name });
16330
16364
  setSelectedEventType(resolvedEventType);
16331
16365
  }
16332
16366
  // Check if this is coming from a card preview (eventTypeId was provided)
@@ -16380,7 +16414,9 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16380
16414
  }
16381
16415
  : null;
16382
16416
  if (eventInstance) {
16417
+ trackEvent("event_instance_selected", { eventInstanceId: eventInstance.id, eventInstanceName: eventInstance.name });
16383
16418
  setSelectedEventInstance(eventInstance);
16419
+ setBookingPersistedState(null);
16384
16420
  }
16385
16421
  setError(null);
16386
16422
  // Check for upsells before going to booking (same as handleEventInstanceSelect)
@@ -16544,19 +16580,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16544
16580
  }
16545
16581
  // Main view based on view mode
16546
16582
  if (viewMode === "next-events" && showingPreview) {
16547
- return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
16548
- setCurrentStep("eventTypes");
16549
- setShowingPreview(true);
16550
- setEventDetails(null);
16551
- }, onBackToEventTypes: () => {
16552
- setCurrentStep("eventTypes");
16553
- setShowingPreview(true);
16554
- setEventDetails(null);
16555
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
16556
- setCurrentStep("eventTypes");
16557
- setShowingPreview(true);
16558
- setEventDetails(null);
16559
- }, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16583
+ return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16560
16584
  setIsSuccess(false);
16561
16585
  setCurrentStep("eventTypes");
16562
16586
  setShowingPreview(true);
@@ -16566,6 +16590,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16566
16590
  setShouldRenderBookingForm(false);
16567
16591
  setSelectedUpsells([]);
16568
16592
  setUpsells([]);
16593
+ setBookingPersistedState(null);
16569
16594
  const url = new URL(window.location.href);
16570
16595
  url.searchParams.delete("payment_intent");
16571
16596
  url.searchParams.delete("payment_intent_client_secret");
@@ -16576,19 +16601,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16576
16601
  }, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
16577
16602
  }
16578
16603
  if (viewMode === "specials" && showingPreview) {
16579
- return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
16580
- setCurrentStep("eventTypes");
16581
- setShowingPreview(true);
16582
- setEventDetails(null);
16583
- }, onBackToEventTypes: () => {
16584
- setCurrentStep("eventTypes");
16585
- setShowingPreview(true);
16586
- setEventDetails(null);
16587
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
16588
- setCurrentStep("eventTypes");
16589
- setShowingPreview(true);
16590
- setEventDetails(null);
16591
- }, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16604
+ return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [jsxRuntime.jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16592
16605
  setIsSuccess(false);
16593
16606
  setCurrentStep("eventTypes");
16594
16607
  setShowingPreview(true);
@@ -16598,6 +16611,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16598
16611
  setShouldRenderBookingForm(false);
16599
16612
  setSelectedUpsells([]);
16600
16613
  setUpsells([]);
16614
+ setBookingPersistedState(null);
16601
16615
  }, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsxRuntime.jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
16602
16616
  }
16603
16617
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
@@ -16650,7 +16664,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16650
16664
  setShouldRenderInstanceSelection(true);
16651
16665
  }
16652
16666
  }, children: config.buttonText ||
16653
- (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), onBackToEventTypes: () => setSidebarOpen(false), selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16667
+ (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16654
16668
  setIsSuccess(false);
16655
16669
  setCurrentStep("eventTypes");
16656
16670
  setSidebarOpen(false);
@@ -16682,32 +16696,36 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16682
16696
  // Determine the correct back handlers based on view mode
16683
16697
  const getBackHandlers = () => {
16684
16698
  if (viewMode === "next-events") {
16685
- return {
16686
- onBackToEventInstances: () => {
16687
- setCurrentStep("eventInstances");
16699
+ const backFromBooking = () => {
16700
+ if (upsells.length > 0) {
16701
+ setCurrentStep("upsells");
16688
16702
  setShowingPreview(false);
16689
- setEventDetails(null);
16690
- },
16703
+ return;
16704
+ }
16705
+ setCurrentStep("eventInstances");
16706
+ setShowingPreview(false);
16707
+ setEventDetails(null);
16708
+ setBookingPersistedState(null);
16709
+ };
16710
+ return {
16711
+ onBackToEventInstances: backFromBooking,
16691
16712
  onBackToEventTypes: () => {
16692
16713
  setShowingPreview(true);
16693
16714
  setCurrentStep("eventTypes");
16694
16715
  setEventDetails(null);
16716
+ setBookingPersistedState(null);
16695
16717
  },
16696
- onClose: () => {
16697
- setCurrentStep("eventInstances");
16698
- setShowingPreview(false);
16699
- setEventDetails(null);
16700
- },
16718
+ onClose: backFromBooking,
16701
16719
  };
16702
16720
  }
16703
16721
  return {
16704
- onBackToEventInstances: handleBackToEventInstances,
16722
+ onBackToEventInstances: handleBackFromBooking,
16705
16723
  onBackToEventTypes: handleBackToEventTypes,
16706
- onClose: handleBackToEventInstances,
16724
+ onClose: handleBackFromBooking,
16707
16725
  };
16708
16726
  };
16709
16727
  const backHandlers = getBackHandlers();
16710
- return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: backHandlers.onBackToEventInstances, onBackToEventTypes: backHandlers.onBackToEventTypes, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
16728
+ return (jsxRuntime.jsxs(StyleProvider, { config: config, children: [jsxRuntime.jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsxRuntime.jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsxRuntime.jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsxRuntime.jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsxRuntime.jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
16711
16729
  setIsSuccess(false);
16712
16730
  setCurrentStep("eventTypes");
16713
16731
  setSuccessPaymentId(null);