@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.esm.js CHANGED
@@ -225,6 +225,8 @@ const de$1 = {
225
225
  "button.depositAndBook": "Anzahlen & buchen",
226
226
  "button.continueWithout": "Weiter ohne Extras",
227
227
  "button.continue": "Weiter",
228
+ "button.continueToPayment": "Weiter zur Zahlung",
229
+ "button.backToDetails": "Zurück zu den Angaben",
228
230
  "button.addExtras": "Extras hinzufügen",
229
231
  // Event types
230
232
  "events.noEventsAvailable": "Keine Veranstaltungen verfügbar",
@@ -417,6 +419,8 @@ const de$1 = {
417
419
  "upsells.noExtras": "Keine Extras für diese Buchung verfügbar.",
418
420
  "upsells.selected": "{{count}} Extra ausgewählt",
419
421
  "upsells.selectedPlural": "{{count}} Extras ausgewählt",
422
+ "upsells.savePercent": "{{percent}}% sparen",
423
+ "booking.paymentUnavailable": "Online-Zahlung ist für diese Buchung nicht verfügbar. Bitte kontaktiere uns, um die Reservierung abzuschließen.",
420
424
  "upsells.spotsFree": "{{count}} Plätze frei",
421
425
  "upsells.notAvailable": "Nicht verfügbar",
422
426
  "upsells.reason.outOfStock": "{{productName}} ist nicht auf Lager",
@@ -501,6 +505,8 @@ const en = {
501
505
  "button.depositAndBook": "Pay deposit & book",
502
506
  "button.continueWithout": "Continue without extras",
503
507
  "button.continue": "Continue",
508
+ "button.continueToPayment": "Continue to payment",
509
+ "button.backToDetails": "Back to details",
504
510
  "button.addExtras": "Add extras",
505
511
  // Event types
506
512
  "events.noEventsAvailable": "No events available",
@@ -693,6 +699,8 @@ const en = {
693
699
  "upsells.noExtras": "No extras available for this booking.",
694
700
  "upsells.selected": "{{count}} extra selected",
695
701
  "upsells.selectedPlural": "{{count}} extras selected",
702
+ "upsells.savePercent": "Save {{percent}}%",
703
+ "booking.paymentUnavailable": "Online payment is not available for this booking. Please contact us to complete your reservation.",
696
704
  "upsells.spotsFree": "{{count}} spots available",
697
705
  "upsells.notAvailable": "Not available",
698
706
  "upsells.reason.outOfStock": "{{productName}} is out of stock",
@@ -777,6 +785,8 @@ const es = {
777
785
  "button.depositAndBook": "Pagar depósito y reservar",
778
786
  "button.continueWithout": "Continuar sin extras",
779
787
  "button.continue": "Continuar",
788
+ "button.continueToPayment": "Continuar al pago",
789
+ "button.backToDetails": "Volver a los datos",
780
790
  "button.addExtras": "Añadir extras",
781
791
  // Event types
782
792
  "events.noEventsAvailable": "No hay eventos disponibles",
@@ -969,6 +979,8 @@ const es = {
969
979
  "upsells.noExtras": "No hay extras disponibles para esta reserva.",
970
980
  "upsells.selected": "{{count}} extra seleccionado",
971
981
  "upsells.selectedPlural": "{{count}} extras seleccionados",
982
+ "upsells.savePercent": "Ahorra {{percent}}%",
983
+ "booking.paymentUnavailable": "El pago en línea no está disponible para esta reserva. Contáctanos para completarla.",
972
984
  "upsells.spotsFree": "{{count}} plazas disponibles",
973
985
  "upsells.notAvailable": "No disponible",
974
986
  "upsells.reason.outOfStock": "{{productName}} está agotado",
@@ -1053,6 +1065,8 @@ const pt = {
1053
1065
  "button.depositAndBook": "Pagar sinal e reservar",
1054
1066
  "button.continueWithout": "Continuar sem extras",
1055
1067
  "button.continue": "Continuar",
1068
+ "button.continueToPayment": "Continuar para pagamento",
1069
+ "button.backToDetails": "Voltar aos dados",
1056
1070
  "button.addExtras": "Adicionar extras",
1057
1071
  // Event types
1058
1072
  "events.noEventsAvailable": "Sem eventos disponíveis",
@@ -1245,6 +1259,8 @@ const pt = {
1245
1259
  "upsells.noExtras": "Sem extras disponíveis para esta reserva.",
1246
1260
  "upsells.selected": "{{count}} extra selecionado",
1247
1261
  "upsells.selectedPlural": "{{count}} extras selecionados",
1262
+ "upsells.savePercent": "Poupa {{percent}}%",
1263
+ "booking.paymentUnavailable": "O pagamento online não está disponível para esta reserva. Contacta-nos para concluir a reserva.",
1248
1264
  "upsells.spotsFree": "{{count}} lugares disponíveis",
1249
1265
  "upsells.notAvailable": "Não disponível",
1250
1266
  "upsells.reason.outOfStock": "{{productName}} está esgotado",
@@ -1329,6 +1345,8 @@ const sv = {
1329
1345
  "button.depositAndBook": "Betala handpenning & boka",
1330
1346
  "button.continueWithout": "Fortsätt utan tillägg",
1331
1347
  "button.continue": "Fortsätt",
1348
+ "button.continueToPayment": "Fortsätt till betalning",
1349
+ "button.backToDetails": "Tillbaka till uppgifter",
1332
1350
  "button.addExtras": "Lägg till tillägg",
1333
1351
  // Event types
1334
1352
  "events.noEventsAvailable": "Inga evenemang tillgängliga",
@@ -1521,6 +1539,8 @@ const sv = {
1521
1539
  "upsells.noExtras": "Inga tillägg tillgängliga för denna bokning.",
1522
1540
  "upsells.selected": "{{count}} tillägg valt",
1523
1541
  "upsells.selectedPlural": "{{count}} tillägg valda",
1542
+ "upsells.savePercent": "Spara {{percent}}%",
1543
+ "booking.paymentUnavailable": "Onlinebetalning är inte tillgänglig för denna bokning. Kontakta oss för att slutföra bokningen.",
1524
1544
  "upsells.spotsFree": "{{count}} platser lediga",
1525
1545
  "upsells.notAvailable": "Inte tillgängligt",
1526
1546
  "upsells.reason.outOfStock": "{{productName}} är slut i lager",
@@ -11453,7 +11473,7 @@ const sectionHeaderStyles$1 = sectionStyles.header;
11453
11473
  const labelStyles$1 = formStyles.label;
11454
11474
  const inputStyles$1 = formStyles.input;
11455
11475
  const errorTextStyles$1 = formStyles.error;
11456
- function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError, onBackToEventInstances, onBackToEventTypes, selectedEventType, selectedEventInstance, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], }) {
11476
+ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError, isOpen, onClose, systemConfig, selectedUpsells = [], upsells = [], persistedState = null, onPersistedStateChange, }) {
11457
11477
  const t$1 = useTranslations();
11458
11478
  const { locale } = useLocale();
11459
11479
  const timezone = useTimezone();
@@ -11465,15 +11485,16 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11465
11485
  const raw = Math.round((baseAmount * basisPoints) / 10000);
11466
11486
  return round ? roundDiscountUp(raw) : raw;
11467
11487
  };
11468
- const [appliedVouchers, setAppliedVouchers] = useState([]);
11469
- const paymentSectionRef = useRef(null);
11488
+ const [appliedVouchers, setAppliedVouchers] = useState(() => persistedState?.appliedVouchers ?? []);
11489
+ const [checkoutStep, setCheckoutStep] = useState(() => persistedState?.checkoutStep ?? "details");
11470
11490
  // Payment option: "deposit" or "full" - only relevant when deposit is available
11471
- const [paymentOption, setPaymentOption] = useState("deposit");
11491
+ const [paymentOption, setPaymentOption] = useState(() => persistedState?.paymentOption ?? "deposit");
11472
11492
  // Per-participant upsell selections: participantIndex -> array of upsell package IDs
11473
- const [participantUpsells, setParticipantUpsells] = useState({});
11493
+ const [participantUpsells, setParticipantUpsells] = useState(() => persistedState?.participantUpsells ?? {});
11494
+ const wasOpenRef = useRef(false);
11474
11495
  const form = useForm({
11475
11496
  resolver: t(createBookingFormSchema(t$1, participantFieldsConfig)),
11476
- defaultValues: {
11497
+ defaultValues: persistedState?.formData ?? {
11477
11498
  customerName: "",
11478
11499
  customerEmail: "",
11479
11500
  customerPhone: "",
@@ -11483,6 +11504,28 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11483
11504
  acceptTerms: false,
11484
11505
  },
11485
11506
  });
11507
+ const persistState = useCallback(() => {
11508
+ onPersistedStateChange?.({
11509
+ formData: form.getValues(),
11510
+ checkoutStep,
11511
+ paymentOption,
11512
+ appliedVouchers,
11513
+ participantUpsells,
11514
+ });
11515
+ }, [onPersistedStateChange, form, checkoutStep, paymentOption, appliedVouchers, participantUpsells]);
11516
+ useEffect(() => {
11517
+ if (isOpen && !wasOpenRef.current && persistedState) {
11518
+ form.reset(persistedState.formData);
11519
+ setCheckoutStep(persistedState.checkoutStep);
11520
+ setPaymentOption(persistedState.paymentOption);
11521
+ setAppliedVouchers(persistedState.appliedVouchers);
11522
+ setParticipantUpsells(persistedState.participantUpsells);
11523
+ }
11524
+ if (!isOpen && wasOpenRef.current) {
11525
+ persistState();
11526
+ }
11527
+ wasOpenRef.current = isOpen;
11528
+ }, [isOpen, persistedState, form, persistState]);
11486
11529
  const watchedParticipants = form.watch("participants");
11487
11530
  const participantCount = watchedParticipants.length;
11488
11531
  const watchedCustomerName = form.watch("customerName");
@@ -11607,6 +11650,18 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11607
11650
  }), [watchedCustomerName, watchedCustomerEmail, watchedCustomerPhone, watchedParticipants, watchedComment]);
11608
11651
  const appliedDiscountCode = appliedVouchers.find((v) => v.type === "discount");
11609
11652
  const appliedGiftCards = appliedVouchers.filter((v) => v.type === "giftCard");
11653
+ const discountCodeProp = appliedDiscountCode
11654
+ ? {
11655
+ id: appliedDiscountCode.id,
11656
+ code: appliedDiscountCode.code,
11657
+ description: appliedDiscountCode.description || undefined,
11658
+ type: appliedDiscountCode.discountType || "percentage",
11659
+ value: appliedDiscountCode.discountValue || 0,
11660
+ discountAmount: appliedDiscountCode.discountAmount,
11661
+ newTotal: appliedDiscountCode.newTotal,
11662
+ }
11663
+ : null;
11664
+ const hasPaymentProvider = Boolean(stripePromise || systemConfig?.paymentProvider === "mollie");
11610
11665
  const handleVoucherValidated = useCallback((voucher, _error) => {
11611
11666
  if (voucher) {
11612
11667
  setAppliedVouchers((prev) => [...prev, voucher]);
@@ -11718,19 +11773,12 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11718
11773
  });
11719
11774
  }, [config]);
11720
11775
  const handleClose = () => {
11776
+ persistState();
11777
+ setCheckoutStep("details");
11721
11778
  onClose();
11722
- if (selectedEventInstance && selectedEventType) {
11723
- onBackToEventInstances?.();
11724
- }
11725
- else if (selectedEventType) {
11726
- onBackToEventTypes?.();
11727
- }
11728
- };
11729
- const scrollToPayment = () => {
11730
- paymentSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
11731
11779
  };
11732
11780
  // Footer navigation
11733
- const footerContent = (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: handleClose, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), children: t$1("common.back") }), jsx("button", { type: "button", onClick: scrollToPayment, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: t$1("button.toPayment") })] }));
11781
+ const footerContent = (jsxs(Fragment, { children: [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" && (jsx("button", { type: "button", onClick: () => setCheckoutStep("payment"), disabled: !isReadyForPayment() || !hasPaymentProvider, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), children: t$1("button.continueToPayment") }))] }));
11734
11782
  if (!eventDetails.bookingOpen) {
11735
11783
  return (jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.notPossible"), children: jsx("div", { style: {
11736
11784
  display: "flex",
@@ -11747,264 +11795,211 @@ function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError,
11747
11795
  fontFamily: "var(--bw-font-family)",
11748
11796
  }, children: t$1("booking.notPossible") }), jsx("p", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.notPossibleMessage") })] }) }) }));
11749
11797
  }
11750
- return (jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.title", { name: eventDetails.name }), footer: footerContent, children: jsxs("div", { className: "booking-widget-container", style: { padding: "16px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.eventDetails") }), jsxs("div", { style: {
11751
- display: "grid",
11752
- gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11753
- gap: "12px",
11754
- fontSize: "14px",
11755
- }, children: [jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxs("span", { style: {
11756
- color: "var(--bw-text-muted)",
11757
- fontFamily: "var(--bw-font-family)",
11758
- display: "flex",
11759
- alignItems: "center",
11760
- gap: "4px",
11761
- }, children: [jsx(IconCalendar, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.date")] }), jsxs("span", { style: {
11762
- color: "var(--bw-text-color)",
11763
- fontWeight: 500,
11764
- fontFamily: "var(--bw-font-family)",
11765
- }, children: [formatEventDate(eventDetails.startTime, timezone, locale), " \u2022 ", formatTime(eventDetails.startTime, timezone, locale)] })] }), jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxs("span", { style: {
11766
- color: "var(--bw-text-muted)",
11767
- fontFamily: "var(--bw-font-family)",
11768
- display: "flex",
11769
- alignItems: "center",
11770
- gap: "4px",
11771
- }, children: [jsx(IconClock, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.duration")] }), jsxs("span", { style: {
11772
- color: "var(--bw-text-color)",
11773
- fontWeight: 500,
11774
- fontFamily: "var(--bw-font-family)",
11775
- }, children: [eventDetails.durationDays, " ", eventDetails.durationDays > 1 ? t$1("common.days") : t$1("common.day")] })] }), jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxs("span", { style: {
11776
- color: "var(--bw-text-muted)",
11777
- fontFamily: "var(--bw-font-family)",
11798
+ return (jsx(Sidebar, { isOpen: isOpen, onClose: handleClose, title: t$1("booking.title", { name: eventDetails.name }), footer: footerContent, children: jsxs("div", { className: "booking-widget-container", style: { padding: "16px" }, children: [checkoutStep === "details" && (jsxs(Fragment, { children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.eventDetails") }), jsxs("div", { style: {
11799
+ display: "grid",
11800
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11801
+ gap: "12px",
11802
+ fontSize: "14px",
11803
+ }, children: [jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxs("span", { style: {
11804
+ color: "var(--bw-text-muted)",
11805
+ fontFamily: "var(--bw-font-family)",
11806
+ display: "flex",
11807
+ alignItems: "center",
11808
+ gap: "4px",
11809
+ }, children: [jsx(IconCalendar, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.date")] }), jsxs("span", { style: {
11810
+ color: "var(--bw-text-color)",
11811
+ fontWeight: 500,
11812
+ fontFamily: "var(--bw-font-family)",
11813
+ }, children: [formatEventDate(eventDetails.startTime, timezone, locale), " \u2022 ", formatTime(eventDetails.startTime, timezone, locale)] })] }), jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [jsxs("span", { style: {
11814
+ color: "var(--bw-text-muted)",
11815
+ fontFamily: "var(--bw-font-family)",
11816
+ display: "flex",
11817
+ alignItems: "center",
11818
+ gap: "4px",
11819
+ }, children: [jsx(IconClock, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.duration")] }), jsxs("span", { style: {
11820
+ color: "var(--bw-text-color)",
11821
+ fontWeight: 500,
11822
+ fontFamily: "var(--bw-font-family)",
11823
+ }, children: [eventDetails.durationDays, " ", eventDetails.durationDays > 1 ? t$1("common.days") : t$1("common.day")] })] }), jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [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: [jsx(IconMoney, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.price")] }), jsxs("span", { style: {
11830
+ color: "var(--bw-text-color)",
11831
+ fontWeight: 500,
11832
+ fontFamily: "var(--bw-font-family)",
11833
+ }, children: [formatCurrency(eventDetails.price), " ", t$1("common.perPerson")] })] })] })] }), jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.contactInfo") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxs("div", { style: {
11834
+ display: "grid",
11835
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11836
+ gap: "16px",
11837
+ }, children: [jsxs("div", { children: [jsx("label", { htmlFor: "customerName", style: labelStyles$1, children: t$1("booking.name") }), jsx("input", { id: "customerName", ...form.register("customerName"), type: "text", style: inputStyles$1, placeholder: t$1("booking.namePlaceholder") }), customerNameError && (jsx("p", { style: errorTextStyles$1, children: customerNameError.message }))] }), jsxs("div", { children: [jsx("label", { htmlFor: "customerEmail", style: labelStyles$1, children: t$1("booking.email") }), jsx("input", { id: "customerEmail", ...form.register("customerEmail"), type: "email", style: inputStyles$1, placeholder: t$1("booking.emailPlaceholder") }), customerEmailError && (jsx("p", { style: errorTextStyles$1, children: customerEmailError.message }))] })] }), jsxs("div", { children: [jsx("label", { htmlFor: "customerPhone", style: labelStyles$1, children: t$1("booking.phone") }), jsx("input", { id: "customerPhone", ...form.register("customerPhone"), type: "tel", style: inputStyles$1, placeholder: t$1("booking.phonePlaceholder") })] }), jsxs("div", { style: { marginTop: "10px", border: "1px solid var(--bw-border-color)", padding: "16px", borderRadius: "var(--bw-border-radius)" }, children: [jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsx("input", { id: "acceptTerms", ...form.register("acceptTerms"), type: "checkbox", style: formStyles.checkbox }), jsxs("label", { htmlFor: "acceptTerms", style: {
11838
+ fontSize: "14px",
11839
+ color: "var(--bw-text-muted)",
11840
+ fontFamily: "var(--bw-font-family)",
11841
+ maxWidth: "calc(100% - 32px)",
11842
+ overflowWrap: "break-word",
11843
+ cursor: "pointer",
11844
+ }, children: [t$1("booking.acceptTerms"), " ", 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 && (jsx("p", { style: { ...errorTextStyles$1, marginTop: "8px" }, children: form.formState.errors.acceptTerms.message }))] })] })] }), jsxs("div", { style: cardStyles$1, children: [jsx("div", { style: {
11778
11845
  display: "flex",
11846
+ justifyContent: "space-between",
11779
11847
  alignItems: "center",
11780
- gap: "4px",
11781
- }, children: [jsx(IconMoney, { size: 20, color: "var(--bw-highlight-color)" }), " ", t$1("booking.price")] }), jsxs("span", { style: {
11782
- color: "var(--bw-text-color)",
11783
- fontWeight: 500,
11784
- fontFamily: "var(--bw-font-family)",
11785
- }, children: [formatCurrency(eventDetails.price), " ", t$1("common.perPerson")] })] })] })] }), jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: sectionHeaderStyles$1, children: t$1("booking.contactInfo") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "16px" }, children: [jsxs("div", { style: {
11786
- display: "grid",
11787
- gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
11788
- gap: "16px",
11789
- }, children: [jsxs("div", { children: [jsx("label", { htmlFor: "customerName", style: labelStyles$1, children: t$1("booking.name") }), jsx("input", { id: "customerName", ...form.register("customerName"), type: "text", style: inputStyles$1, placeholder: t$1("booking.namePlaceholder") }), customerNameError && (jsx("p", { style: errorTextStyles$1, children: customerNameError.message }))] }), jsxs("div", { children: [jsx("label", { htmlFor: "customerEmail", style: labelStyles$1, children: t$1("booking.email") }), jsx("input", { id: "customerEmail", ...form.register("customerEmail"), type: "email", style: inputStyles$1, placeholder: t$1("booking.emailPlaceholder") }), customerEmailError && (jsx("p", { style: errorTextStyles$1, children: customerEmailError.message }))] })] }), jsxs("div", { children: [jsx("label", { htmlFor: "customerPhone", style: labelStyles$1, children: t$1("booking.phone") }), jsx("input", { id: "customerPhone", ...form.register("customerPhone"), type: "tel", style: inputStyles$1, placeholder: t$1("booking.phonePlaceholder") })] }), jsxs("div", { style: { marginTop: "10px", border: "1px solid var(--bw-border-color)", padding: "16px", borderRadius: "var(--bw-border-radius)" }, children: [jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsx("input", { id: "acceptTerms", ...form.register("acceptTerms"), type: "checkbox", style: formStyles.checkbox }), jsxs("label", { htmlFor: "acceptTerms", style: {
11848
+ marginBottom: "16px",
11849
+ }, children: jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: 0 }, children: t$1("booking.participants") }) }), jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [watchedParticipants.map((_, index) => (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [participantFieldsConfig.name.enabled && (jsxs("div", { style: { flex: 1 }, children: [jsx("label", { htmlFor: `participant-name-${index}`, style: labelStyles$1, children: t$1("booking.participantName") }), 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 && (jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.name?.message }))] })), participantFieldsConfig.age.enabled && (jsxs("div", { style: { width: "80px" }, children: [jsx("label", { htmlFor: `participant-age-${index}`, style: labelStyles$1, children: t$1("booking.participantAge") }), jsx("input", { id: `participant-age-${index}`, ...form.register(`participants.${index}.age`, {
11850
+ setValueAs: (value) => {
11851
+ if (value === "" || value === null || value === undefined) {
11852
+ return undefined;
11853
+ }
11854
+ const num = Number(value);
11855
+ return Number.isNaN(num) ? undefined : num;
11856
+ },
11857
+ }), type: "number", min: "0", max: "120", style: inputStyles$1, placeholder: "25" })] })), watchedParticipants.length > 1 && (jsxs("div", { children: [jsx("label", { style: { ...labelStyles$1, visibility: "hidden" }, children: "\u00A0" }), jsx("button", { type: "button", onClick: () => removeParticipant(index), style: {
11858
+ color: "var(--bw-error-color)",
11859
+ backgroundColor: "var(--bw-surface-color)",
11860
+ border: "1px solid var(--bw-border-color)",
11861
+ borderRadius: "50%",
11862
+ width: "36px",
11863
+ height: "36px",
11864
+ display: "flex",
11865
+ alignItems: "center",
11866
+ justifyContent: "center",
11867
+ cursor: "pointer",
11868
+ transition: "all 0.2s ease",
11869
+ fontSize: "24px",
11870
+ fontWeight: 700,
11871
+ fontFamily: "var(--bw-font-family)",
11872
+ padding: 0,
11873
+ }, children: "\u00D7" })] }))] }), participantFieldsConfig.level.enabled && (jsxs("div", { style: { minWidth: "140px" }, children: [jsx("label", { htmlFor: `participant-level-${index}`, style: labelStyles$1, children: t$1("booking.participantLevel") }), jsxs("select", { id: `participant-level-${index}`, ...form.register(`participants.${index}.level`), style: inputStyles$1, children: [jsx("option", { value: "", children: t$1("booking.participantLevelPlaceholder") }), participantLevelOptions.map((level) => (jsx("option", { value: level, children: t$1(`level.${level}`) }, level)))] }), form.formState.errors.participants?.[index]?.level && (jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.level?.message }))] })), upsells.length > 0 && (jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11874
+ const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11875
+ return (jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11876
+ }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsx("div", { style: {
11877
+ display: "flex",
11878
+ flexDirection: "column",
11879
+ alignItems: "center",
11880
+ marginTop: "12px",
11881
+ }, children: jsx("button", { type: "button", onClick: addParticipant, style: {
11882
+ color: "#ffffff",
11883
+ fontSize: "14px",
11884
+ fontWeight: 600,
11885
+ padding: "8px 16px",
11886
+ borderRadius: "var(--bw-border-radius)",
11887
+ backgroundColor: "var(--bw-highlight-color)",
11888
+ border: "1px solid var(--bw-highlight-color)",
11889
+ cursor: "pointer",
11890
+ transition: "all 0.2s ease",
11891
+ marginBottom: "4px",
11892
+ fontFamily: "var(--bw-font-family)",
11893
+ boxShadow: "0 2px 8px 0 var(--bw-highlight-color)",
11894
+ }, children: t$1("booking.addParticipant", { number: watchedParticipants.length + 1 }) }) })) : (jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.maxSpotsReached", { count: eventDetails.availableSpots }) }))] })] }), jsx(VoucherInput, { config: config, orderValue: baseTotal, eventInstanceId: eventDetails?.id, customerEmail: watchedCustomerEmail, onVoucherValidated: handleVoucherValidated, appliedVouchers: appliedVouchers, onRemoveVoucher: handleRemoveVoucher, disabled: !eventDetails }), jsxs("div", { style: cardStyles$1, children: [jsx("label", { htmlFor: "booking-comment", style: labelStyles$1, children: t$1("booking.comment") }), jsx("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: t$1("booking.commentPlaceholder"), rows: 3, style: {
11895
+ ...inputStyles$1,
11896
+ resize: "vertical",
11897
+ minHeight: "80px",
11898
+ } })] })] })] })), checkoutStep === "payment" && (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxs("div", { style: {
11899
+ color: "var(--bw-text-color)",
11900
+ fontWeight: 500,
11901
+ fontFamily: "var(--bw-font-family)",
11902
+ }, children: [jsxs("span", { style: { fontWeight: 200 }, children: [watchedParticipants.length > 1 ? watchedParticipants.length : 1, " x "] }), " ", formatCurrency(eventDetails.price)] })] }), upsellsTotal > 0 && (jsxs("div", { style: { marginTop: "8px", paddingTop: "8px", borderTop: "1px dashed var(--bw-border-color)" }, children: [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) => {
11903
+ // Count how many participants have this upsell selected
11904
+ const countWithUpsell = watchedParticipants.filter((_, idx) => (participantUpsells[idx] || []).includes(upsell.id)).length;
11905
+ if (countWithUpsell === 0)
11906
+ return null;
11907
+ const upsellLineTotal = upsell.price * countWithUpsell;
11908
+ return (jsx("div", { style: { display: "flex", flexDirection: "column", gap: "2px", fontSize: "13px" }, children: jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }) }, upsell.id));
11909
+ })] })), appliedVouchers.length > 0 && (jsxs(Fragment, { children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), jsx("span", { style: {
11910
+ fontFamily: "var(--bw-font-family)",
11911
+ color: totalDiscount > 0 ? "var(--bw-text-muted)" : "var(--bw-text-muted)",
11912
+ textDecoration: totalDiscount > 0 ? "line-through" : "none",
11913
+ }, children: formatCurrency(baseTotal) })] }), appliedDiscountCode && (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: {
11914
+ color: "var(--bw-success-color)",
11915
+ fontFamily: "var(--bw-font-family)",
11790
11916
  fontSize: "14px",
11917
+ }, children: t$1("summary.discount", { code: appliedDiscountCode.code }) }), jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(appliedDiscountCode.discountAmount)] })] })), appliedGiftCards.map((giftCard) => (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: {
11918
+ color: "var(--bw-success-color)",
11919
+ fontFamily: "var(--bw-font-family)",
11920
+ fontSize: "14px",
11921
+ }, children: t$1("summary.giftCard", { code: giftCard.code }) }), jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(giftCard.balanceToUse || giftCard.discountAmount)] })] }, giftCard.code)))] })), jsxs("div", { style: {
11922
+ borderTop: "1px solid var(--bw-border-color)",
11923
+ paddingTop: "12px",
11924
+ }, children: [hasDepositOption && (jsxs("div", { style: {
11925
+ display: "flex",
11926
+ justifyContent: "space-between",
11927
+ alignItems: "center",
11928
+ fontSize: "14px",
11929
+ marginBottom: "12px",
11930
+ }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.totalAmount") }), jsx("span", { style: {
11791
11931
  color: "var(--bw-text-muted)",
11792
11932
  fontFamily: "var(--bw-font-family)",
11793
- maxWidth: "calc(100% - 32px)",
11794
- overflowWrap: "break-word",
11933
+ fontWeight: 500,
11934
+ }, children: formatCurrency(totalAmount) })] })), hasDepositOption && (jsxs("div", { style: {
11935
+ display: "flex",
11936
+ gap: "8px",
11937
+ marginBottom: "16px",
11938
+ }, children: [jsxs("button", { type: "button", onClick: () => setPaymentOption("deposit"), style: {
11939
+ flex: 1,
11940
+ padding: "12px",
11941
+ borderRadius: "var(--bw-border-radius)",
11942
+ border: paymentOption === "deposit"
11943
+ ? "2px solid var(--bw-highlight-color)"
11944
+ : "1px solid var(--bw-border-color)",
11945
+ backgroundColor: paymentOption === "deposit"
11946
+ ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11947
+ : "var(--bw-surface-color)",
11795
11948
  cursor: "pointer",
11796
- }, children: [t$1("booking.acceptTerms"), " ", 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 && (jsx("p", { style: { ...errorTextStyles$1, marginTop: "8px" }, children: form.formState.errors.acceptTerms.message }))] })] })] }), jsxs("div", { style: cardStyles$1, children: [jsx("div", { style: {
11797
- display: "flex",
11798
- justifyContent: "space-between",
11799
- alignItems: "center",
11800
- marginBottom: "16px",
11801
- }, children: jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: 0 }, children: t$1("booking.participants") }) }), jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [watchedParticipants.map((_, index) => (jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [participantFieldsConfig.name.enabled && (jsxs("div", { style: { flex: 1 }, children: [jsx("label", { htmlFor: `participant-name-${index}`, style: labelStyles$1, children: t$1("booking.participantName") }), 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 && (jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.name?.message }))] })), participantFieldsConfig.age.enabled && (jsxs("div", { style: { width: "80px" }, children: [jsx("label", { htmlFor: `participant-age-${index}`, style: labelStyles$1, children: t$1("booking.participantAge") }), jsx("input", { id: `participant-age-${index}`, ...form.register(`participants.${index}.age`, {
11802
- setValueAs: (value) => {
11803
- if (value === "" || value === null || value === undefined) {
11804
- return undefined;
11805
- }
11806
- const num = Number(value);
11807
- return Number.isNaN(num) ? undefined : num;
11808
- },
11809
- }), type: "number", min: "0", max: "120", style: inputStyles$1, placeholder: "25" })] })), watchedParticipants.length > 1 && (jsxs("div", { children: [jsx("label", { style: { ...labelStyles$1, visibility: "hidden" }, children: "\u00A0" }), jsx("button", { type: "button", onClick: () => removeParticipant(index), style: {
11810
- color: "var(--bw-error-color)",
11811
- backgroundColor: "var(--bw-surface-color)",
11812
- border: "1px solid var(--bw-border-color)",
11813
- borderRadius: "50%",
11814
- width: "36px",
11815
- height: "36px",
11816
- display: "flex",
11817
- alignItems: "center",
11818
- justifyContent: "center",
11819
- cursor: "pointer",
11820
- transition: "all 0.2s ease",
11821
- fontSize: "24px",
11949
+ fontFamily: "var(--bw-font-family)",
11950
+ transition: "all 0.2s ease",
11951
+ }, children: [jsx("div", { style: {
11952
+ fontSize: "13px",
11953
+ color: "var(--bw-text-muted)",
11954
+ marginBottom: "4px",
11955
+ }, children: t$1("summary.deposit") }), jsx("div", { style: {
11956
+ fontSize: "18px",
11822
11957
  fontWeight: 700,
11823
- fontFamily: "var(--bw-font-family)",
11824
- padding: 0,
11825
- }, children: "\u00D7" })] }))] }), participantFieldsConfig.level.enabled && (jsxs("div", { style: { minWidth: "140px" }, children: [jsx("label", { htmlFor: `participant-level-${index}`, style: labelStyles$1, children: t$1("booking.participantLevel") }), jsxs("select", { id: `participant-level-${index}`, ...form.register(`participants.${index}.level`), style: inputStyles$1, children: [jsx("option", { value: "", children: t$1("booking.participantLevelPlaceholder") }), participantLevelOptions.map((level) => (jsx("option", { value: level, children: t$1(`level.${level}`) }, level)))] }), form.formState.errors.participants?.[index]?.level && (jsx("p", { style: errorTextStyles$1, children: form.formState.errors.participants[index]?.level?.message }))] })), upsells.length > 0 && (jsx("div", { style: participantUpsellStyles.container, children: upsells.map((upsell) => {
11826
- const isSelected = (participantUpsells[index] || []).includes(upsell.id);
11827
- return (jsxs("label", { htmlFor: `upsell-${index}-${upsell.id}`, style: isSelected ? participantUpsellStyles.labelSelected : participantUpsellStyles.label, children: [jsx("input", { id: `upsell-${index}-${upsell.id}`, type: "checkbox", style: participantUpsellStyles.checkbox, checked: isSelected, onChange: () => toggleParticipantUpsell(index, upsell.id) }), jsx("span", { style: { fontWeight: 500 }, children: upsell.name }), jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: ["(+", formatCurrency(upsell.price), ")"] })] }, upsell.id));
11828
- }) }))] }, index))), watchedParticipants.length < eventDetails.availableSpots ? (jsx("div", { style: {
11829
- display: "flex",
11830
- flexDirection: "column",
11831
- alignItems: "center",
11832
- marginTop: "12px",
11833
- }, children: jsx("button", { type: "button", onClick: addParticipant, style: {
11834
- color: "#ffffff",
11835
- fontSize: "14px",
11836
- fontWeight: 600,
11837
- padding: "8px 16px",
11838
- borderRadius: "var(--bw-border-radius)",
11839
- backgroundColor: "var(--bw-highlight-color)",
11840
- border: "1px solid var(--bw-highlight-color)",
11841
- cursor: "pointer",
11842
- transition: "all 0.2s ease",
11843
- marginBottom: "4px",
11844
- fontFamily: "var(--bw-font-family)",
11845
- boxShadow: "0 2px 8px 0 var(--bw-highlight-color)",
11846
- }, children: t$1("booking.addParticipant", { number: watchedParticipants.length + 1 }) }) })) : (jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.maxSpotsReached", { count: eventDetails.availableSpots }) }))] })] }), jsx(VoucherInput, { config: config, orderValue: baseTotal, eventInstanceId: eventDetails?.id, customerEmail: watchedCustomerEmail, onVoucherValidated: handleVoucherValidated, appliedVouchers: appliedVouchers, onRemoveVoucher: handleRemoveVoucher, disabled: !eventDetails }), jsxs("div", { style: cardStyles$1, children: [jsx("label", { htmlFor: "booking-comment", style: labelStyles$1, children: t$1("booking.comment") }), jsx("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: t$1("booking.commentPlaceholder"), rows: 3, style: {
11847
- ...inputStyles$1,
11848
- resize: "vertical",
11849
- minHeight: "80px",
11850
- } })] }), jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "24px" }, children: [jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1, marginBottom: "16px" }, children: t$1("summary.title") }), jsxs("div", { style: { marginTop: "10px", display: "flex", flexDirection: "column", gap: "12px" }, children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("booking.price") }), jsxs("div", { style: {
11851
- color: "var(--bw-text-color)",
11852
- fontWeight: 500,
11958
+ color: paymentOption === "deposit"
11959
+ ? "var(--bw-highlight-color)"
11960
+ : "var(--bw-text-color)",
11961
+ }, children: formatCurrency(depositAmount) })] }), jsxs("button", { type: "button", onClick: () => setPaymentOption("full"), style: {
11962
+ flex: 1,
11963
+ padding: "12px",
11964
+ borderRadius: "var(--bw-border-radius)",
11965
+ border: paymentOption === "full"
11966
+ ? "2px solid var(--bw-highlight-color)"
11967
+ : "1px solid var(--bw-border-color)",
11968
+ backgroundColor: paymentOption === "full"
11969
+ ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11970
+ : "var(--bw-surface-color)",
11971
+ cursor: "pointer",
11853
11972
  fontFamily: "var(--bw-font-family)",
11854
- }, children: [jsxs("span", { style: { fontWeight: 200 }, children: [watchedParticipants.length > 1 ? watchedParticipants.length : 1, " x "] }), " ", formatCurrency(eventDetails.price)] })] }), upsellsTotal > 0 && (jsxs("div", { style: { marginTop: "8px", paddingTop: "8px", borderTop: "1px dashed var(--bw-border-color)" }, children: [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) => {
11855
- // Count how many participants have this upsell selected
11856
- const countWithUpsell = watchedParticipants.filter((_, idx) => (participantUpsells[idx] || []).includes(upsell.id)).length;
11857
- if (countWithUpsell === 0)
11858
- return null;
11859
- const upsellLineTotal = upsell.price * countWithUpsell;
11860
- return (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "13px" }, children: [jsxs("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+ ", upsell.name, " (", countWithUpsell, "\u00D7)"] }), jsx("span", { style: { color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: formatCurrency(upsellLineTotal) })] }, upsell.id));
11861
- })] })), appliedVouchers.length > 0 && (jsxs(Fragment, { children: [jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.subtotal") }), jsx("span", { style: {
11862
- fontFamily: "var(--bw-font-family)",
11863
- color: totalDiscount > 0 ? "var(--bw-text-muted)" : "var(--bw-text-muted)",
11864
- textDecoration: totalDiscount > 0 ? "line-through" : "none",
11865
- }, children: formatCurrency(baseTotal) })] }), appliedDiscountCode && (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: {
11866
- color: "var(--bw-success-color)",
11867
- fontFamily: "var(--bw-font-family)",
11868
- fontSize: "14px",
11869
- }, children: t$1("summary.discount", { code: appliedDiscountCode.code }) }), jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(appliedDiscountCode.discountAmount)] })] })), appliedGiftCards.map((giftCard) => (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [jsx("span", { style: {
11870
- color: "var(--bw-success-color)",
11871
- fontFamily: "var(--bw-font-family)",
11872
- fontSize: "14px",
11873
- }, children: t$1("summary.giftCard", { code: giftCard.code }) }), jsxs("span", { style: { color: "var(--bw-success-color)", fontFamily: "var(--bw-font-family)" }, children: ["-", formatCurrency(giftCard.balanceToUse || giftCard.discountAmount)] })] }, giftCard.code)))] })), jsxs("div", { style: {
11874
- borderTop: "1px solid var(--bw-border-color)",
11875
- paddingTop: "12px",
11876
- }, children: [hasDepositOption && (jsxs("div", { style: {
11877
- display: "flex",
11878
- gap: "8px",
11879
- marginBottom: "16px",
11880
- }, children: [jsxs("button", { type: "button", onClick: () => setPaymentOption("deposit"), style: {
11881
- flex: 1,
11882
- padding: "12px",
11883
- borderRadius: "var(--bw-border-radius)",
11884
- border: paymentOption === "deposit"
11885
- ? "2px solid var(--bw-highlight-color)"
11886
- : "1px solid var(--bw-border-color)",
11887
- backgroundColor: paymentOption === "deposit"
11888
- ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11889
- : "var(--bw-surface-color)",
11890
- cursor: "pointer",
11891
- fontFamily: "var(--bw-font-family)",
11892
- transition: "all 0.2s ease",
11893
- }, children: [jsx("div", { style: {
11894
- fontSize: "13px",
11895
- color: "var(--bw-text-muted)",
11896
- marginBottom: "4px",
11897
- }, children: t$1("summary.deposit") }), jsx("div", { style: {
11898
- fontSize: "18px",
11899
- fontWeight: 700,
11900
- color: paymentOption === "deposit"
11901
- ? "var(--bw-highlight-color)"
11902
- : "var(--bw-text-color)",
11903
- }, children: formatCurrency(depositAmount) })] }), jsxs("button", { type: "button", onClick: () => setPaymentOption("full"), style: {
11904
- flex: 1,
11905
- padding: "12px",
11906
- borderRadius: "var(--bw-border-radius)",
11907
- border: paymentOption === "full"
11908
- ? "2px solid var(--bw-highlight-color)"
11909
- : "1px solid var(--bw-border-color)",
11910
- backgroundColor: paymentOption === "full"
11911
- ? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
11912
- : "var(--bw-surface-color)",
11913
- cursor: "pointer",
11914
- fontFamily: "var(--bw-font-family)",
11915
- transition: "all 0.2s ease",
11916
- }, children: [jsx("div", { style: {
11917
- fontSize: "13px",
11918
- color: "var(--bw-text-muted)",
11919
- marginBottom: "4px",
11920
- }, children: t$1("summary.payFull") }), jsx("div", { style: {
11921
- fontSize: "18px",
11922
- fontWeight: 700,
11923
- color: paymentOption === "full"
11924
- ? "var(--bw-highlight-color)"
11925
- : "var(--bw-text-color)",
11926
- }, children: formatCurrency(totalAmount) })] })] })), hasDepositOption && paymentOption === "deposit" && (jsxs("div", { style: {
11927
- display: "flex",
11928
- justifyContent: "space-between",
11929
- alignItems: "center",
11930
- fontSize: "14px",
11931
- marginBottom: "8px",
11932
- }, children: [jsx("span", { style: { color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t$1("summary.totalAmount") }), jsx("span", { style: {
11973
+ transition: "all 0.2s ease",
11974
+ }, children: [jsx("div", { style: {
11975
+ fontSize: "13px",
11933
11976
  color: "var(--bw-text-muted)",
11934
- fontFamily: "var(--bw-font-family)",
11935
- fontWeight: 500,
11936
- }, children: formatCurrency(totalAmount) })] })), jsxs("div", { style: {
11937
- display: "flex",
11938
- justifyContent: "space-between",
11939
- alignItems: "center",
11940
- fontSize: "18px",
11941
- fontWeight: 600,
11942
- }, children: [jsx("span", { style: { color: "var(--bw-text-color)", fontFamily: "var(--bw-font-family)" }, children: hasDepositOption && paymentOption === "deposit"
11943
- ? t$1("summary.payToday")
11944
- : t$1("summary.totalAmount") }), jsx("span", { style: {
11945
- color: "var(--bw-highlight-color)",
11946
- fontFamily: "var(--bw-font-family)",
11977
+ marginBottom: "4px",
11978
+ }, children: t$1("summary.payFull") }), jsx("div", { style: {
11979
+ fontSize: "18px",
11947
11980
  fontWeight: 700,
11948
- }, children: formatCurrency(paymentAmount) })] }), hasDepositOption && paymentOption === "deposit" && (jsx("div", { style: {
11949
- fontSize: "12px",
11950
- color: "var(--bw-text-muted)",
11981
+ color: paymentOption === "full"
11982
+ ? "var(--bw-highlight-color)"
11983
+ : "var(--bw-text-color)",
11984
+ }, children: formatCurrency(totalAmount) })] })] })), jsxs("div", { style: {
11985
+ display: "flex",
11986
+ justifyContent: "space-between",
11987
+ alignItems: "center",
11988
+ fontSize: "18px",
11989
+ fontWeight: 600,
11990
+ }, children: [jsx("span", { style: { color: "var(--bw-text-color)", fontFamily: "var(--bw-font-family)" }, children: hasDepositOption && paymentOption === "deposit"
11991
+ ? t$1("summary.payToday")
11992
+ : t$1("summary.totalAmount") }), jsx("span", { style: {
11993
+ color: "var(--bw-highlight-color)",
11951
11994
  fontFamily: "var(--bw-font-family)",
11952
- marginTop: "8px",
11953
- textAlign: "right",
11954
- }, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), jsx("div", { ref: paymentSectionRef, children: (stripePromise || systemConfig?.paymentProvider === "mollie") &&
11955
- (() => {
11956
- if (!isReadyForPayment()) {
11957
- const participantsWithNames = watchedParticipants.filter((p) => p.name?.trim()).length;
11958
- const totalParticipantRows = watchedParticipants.length;
11959
- const participantsWithoutNames = totalParticipantRows - participantsWithNames;
11960
- const missing = [];
11961
- if (participantFieldsConfig.name.required) {
11962
- if (participantsWithNames === 0) {
11963
- missing.push(t$1("payment.needParticipant"));
11964
- }
11965
- else if (participantsWithoutNames > 0) {
11966
- missing.push(t$1("payment.needAllNames", { count: totalParticipantRows }));
11967
- }
11968
- }
11969
- if (participantsWithNames > (eventDetails?.availableSpots || 0)) {
11970
- missing.push(t$1("payment.reduceParticipants", { count: eventDetails?.availableSpots || 0 }));
11971
- }
11972
- if (!watchedCustomerName || watchedCustomerName.trim().length < 2 || customerNameError) {
11973
- missing.push(t$1("payment.needValidName"));
11974
- }
11975
- if (!watchedCustomerEmail || watchedCustomerEmail.trim().length === 0 || customerEmailError) {
11976
- missing.push(t$1("payment.needValidEmail"));
11977
- }
11978
- if (!watchedAcceptTerms) {
11979
- missing.push(t$1("payment.needAcceptTerms"));
11980
- }
11981
- const message = missing.length > 0
11982
- ? t$1("payment.missingFields", { fields: missing.join(", ") })
11983
- : t$1("payment.fillRequired");
11984
- return (jsx("div", { style: {
11985
- ...cardStyles$1,
11986
- border: "1px solid var(--bw-warning-color)",
11987
- color: "var(--bw-warning-color)",
11995
+ fontWeight: 700,
11996
+ }, children: formatCurrency(paymentAmount) })] }), hasDepositOption && paymentOption === "deposit" && (jsx("div", { style: {
11997
+ fontSize: "12px",
11998
+ color: "var(--bw-text-muted)",
11988
11999
  fontFamily: "var(--bw-font-family)",
11989
- textAlign: "center",
11990
- }, children: message }));
11991
- }
11992
- const discountCodeProp = appliedDiscountCode
11993
- ? {
11994
- id: appliedDiscountCode.id,
11995
- code: appliedDiscountCode.code,
11996
- description: appliedDiscountCode.description || undefined,
11997
- type: appliedDiscountCode.discountType || "percentage",
11998
- value: appliedDiscountCode.discountValue || 0,
11999
- discountAmount: appliedDiscountCode.discountAmount,
12000
- newTotal: appliedDiscountCode.newTotal,
12001
- }
12002
- : null;
12003
- if (systemConfig?.paymentProvider === "mollie") {
12004
- return (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] }));
12005
- }
12006
- return (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] }));
12007
- })() })] })] })] }) }));
12000
+ marginTop: "8px",
12001
+ textAlign: "right",
12002
+ }, children: t$1("summary.remainingOnSite", { amount: formatCurrency(totalAmount - depositAmount) }) }))] })] })] }), !hasPaymentProvider && (jsx("div", { style: cardStyles$1, children: jsx("p", { style: { ...errorTextStyles$1, margin: 0 }, children: t$1("booking.paymentUnavailable") }) })), hasPaymentProvider && (systemConfig?.paymentProvider === "mollie" ? (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(MolliePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, upsellSelections: aggregatedUpsellSelections(), mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode })] })) : (jsxs("div", { style: cardStyles$1, children: [jsx("h2", { style: { ...sectionHeaderStyles$1 }, children: t$1("summary.payment") }), jsx(StripePaymentForm, { config: config, eventDetails: eventDetails, formData: paymentFormData, totalAmount: paymentAmount, discountCode: discountCodeProp, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig ?? null, stripePromise: stripePromise, stripeAppearance: stripeAppearance, upsellSelections: aggregatedUpsellSelections() })] })))] }))] }) }));
12008
12003
  }
12009
12004
 
12010
12005
  /**
@@ -15171,12 +15166,11 @@ function PromoDialog({ config, onClose, onCtaClick }) {
15171
15166
  return createPortal(dialogContent, portalContainer);
15172
15167
  }
15173
15168
 
15174
- // Upsell card styles
15175
15169
  const cardBaseStyles = {
15176
15170
  position: "relative",
15177
15171
  display: "flex",
15178
15172
  flexDirection: "column",
15179
- padding: "16px",
15173
+ padding: "12px",
15180
15174
  backgroundColor: "var(--bw-surface-color)",
15181
15175
  borderWidth: "2px",
15182
15176
  borderStyle: "solid",
@@ -15196,19 +15190,13 @@ const cardDisabledStyles = {
15196
15190
  opacity: 0.6,
15197
15191
  cursor: "not-allowed",
15198
15192
  };
15199
- const checkboxContainerStyles = {
15200
- position: "absolute",
15201
- bottom: "12px",
15202
- left: "12px",
15203
- zIndex: 1,
15204
- };
15205
15193
  const checkboxInnerStyles = {
15206
- width: "24px",
15207
- height: "24px",
15194
+ width: "48px",
15195
+ height: "48px",
15208
15196
  borderWidth: "2px",
15209
15197
  borderStyle: "solid",
15210
15198
  borderColor: "var(--bw-border-color)",
15211
- borderRadius: "6px",
15199
+ borderRadius: "12px",
15212
15200
  display: "flex",
15213
15201
  alignItems: "center",
15214
15202
  justifyContent: "center",
@@ -15220,13 +15208,13 @@ const checkboxSelectedStyles = {
15220
15208
  borderColor: "var(--bw-highlight-color)",
15221
15209
  backgroundColor: "var(--bw-highlight-color)",
15222
15210
  };
15223
- const imageContainerStyles = {
15224
- width: "100%",
15225
- height: "120px",
15226
- marginBottom: "12px",
15211
+ const previewImageContainerStyles = {
15212
+ width: "56px",
15213
+ height: "56px",
15227
15214
  borderRadius: "calc(var(--bw-border-radius) - 4px)",
15228
15215
  overflow: "hidden",
15229
15216
  backgroundColor: "var(--bw-background-color)",
15217
+ flexShrink: 0,
15230
15218
  };
15231
15219
  const imageStyles = {
15232
15220
  width: "100%",
@@ -15241,23 +15229,53 @@ const imagePlaceholderStyles = {
15241
15229
  justifyContent: "center",
15242
15230
  color: "var(--bw-text-muted)",
15243
15231
  };
15244
- const nameStyles = {
15232
+ const previewNameStyles = {
15245
15233
  fontSize: "16px",
15246
15234
  fontWeight: 600,
15247
15235
  color: "var(--bw-text-color)",
15248
- margin: "0 0 6px 0",
15249
- paddingRight: "36px",
15236
+ margin: 0,
15237
+ fontFamily: "var(--bw-font-family)",
15238
+ };
15239
+ const previewHeaderStyles = {
15240
+ display: "flex",
15241
+ alignItems: "center",
15242
+ gap: "10px",
15243
+ };
15244
+ const previewPriceStyles = {
15245
+ fontSize: "13px",
15246
+ color: "var(--bw-text-muted)",
15247
+ marginTop: "2px",
15250
15248
  fontFamily: "var(--bw-font-family)",
15251
15249
  };
15250
+ const headerRightStyles = {
15251
+ marginLeft: "auto",
15252
+ display: "flex",
15253
+ alignItems: "center",
15254
+ gap: "8px",
15255
+ };
15256
+ const chevronStyles = {
15257
+ fontSize: "12px",
15258
+ color: "var(--bw-text-muted)",
15259
+ transition: "transform 0.2s ease",
15260
+ };
15261
+ const expandedContentStyles = {
15262
+ marginTop: "12px",
15263
+ paddingTop: "12px",
15264
+ borderTop: "1px solid var(--bw-border-color)",
15265
+ };
15266
+ const expandedImageContainerStyles = {
15267
+ width: "100%",
15268
+ height: "180px",
15269
+ marginBottom: "12px",
15270
+ borderRadius: "calc(var(--bw-border-radius) - 4px)",
15271
+ overflow: "hidden",
15272
+ backgroundColor: "var(--bw-background-color)",
15273
+ };
15252
15274
  const descriptionStyles = {
15253
15275
  fontSize: "13px",
15254
15276
  color: "var(--bw-text-muted)",
15255
15277
  margin: "0 0 10px 0",
15256
15278
  lineHeight: 1.4,
15257
- display: "-webkit-box",
15258
- WebkitLineClamp: 5,
15259
- WebkitBoxOrient: "vertical",
15260
- overflow: "hidden",
15261
15279
  fontFamily: "var(--bw-font-family)",
15262
15280
  };
15263
15281
  const itemsContainerStyles = {
@@ -15339,6 +15357,8 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
15339
15357
  const { locale } = useLocale();
15340
15358
  const totalPrice = upsell.price * participantCount;
15341
15359
  const isDisabled = !upsell.available;
15360
+ const [isExpanded, setIsExpanded] = useState(false);
15361
+ const hasSavings = (upsell.savingsPercent ?? 0) > 0;
15342
15362
  const getCardStyles = () => {
15343
15363
  if (isDisabled)
15344
15364
  return cardDisabledStyles;
@@ -15346,16 +15366,22 @@ function UpsellCard({ upsell, isSelected, participantCount, onSelect, }) {
15346
15366
  return cardSelectedStyles;
15347
15367
  return cardBaseStyles;
15348
15368
  };
15349
- return (jsxs("div", { style: getCardStyles(), onClick: !isDisabled ? onSelect : undefined, role: "checkbox", "aria-checked": isSelected, tabIndex: isDisabled ? -1 : 0, onKeyDown: (e) => {
15369
+ const toggleExpanded = () => {
15370
+ setIsExpanded((current) => !current);
15371
+ };
15372
+ return (jsxs("div", { style: getCardStyles(), onClick: !isDisabled ? toggleExpanded : undefined, role: "button", "aria-expanded": isExpanded, tabIndex: isDisabled ? -1 : 0, onKeyDown: (e) => {
15350
15373
  if (!isDisabled && (e.key === "Enter" || e.key === " ")) {
15351
15374
  e.preventDefault();
15352
- onSelect();
15375
+ toggleExpanded();
15353
15376
  }
15354
- }, children: [jsx("div", { style: checkboxContainerStyles, children: jsx("div", { style: isSelected ? checkboxSelectedStyles : checkboxInnerStyles, children: isSelected && (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", style: { width: "16px", height: "16px" }, children: jsx("polyline", { points: "20 6 9 17 4 12" }) })) }) }), jsx("div", { style: imageContainerStyles, children: upsell.image ? (jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsx("div", { style: imagePlaceholderStyles, children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "40px", height: "40px", opacity: 0.4 }, children: jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), jsxs("div", { style: { flex: 1 }, children: [jsx("h4", { style: nameStyles, children: upsell.name }), upsell.description && (jsx("p", { style: descriptionStyles, children: upsell.description })), upsell.items.length > 0 && (jsx("div", { style: itemsContainerStyles, children: upsell.items.map((item, index) => (jsxs("span", { style: itemStyles, children: [item.type === "product" ? "📦" : "🎫", " ", item.name, item.quantity > 1 && ` (${item.quantity}x)`] }, index))) })), upsell.suggestedEventInstance && (jsxs("div", { style: eventInfoStyles, children: [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", {
15377
+ }, children: [jsxs("div", { style: previewHeaderStyles, children: [jsx("div", { style: previewImageContainerStyles, children: upsell.image ? (jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsx("div", { style: imagePlaceholderStyles, children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "32px", height: "32px", opacity: 0.4 }, children: jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), jsxs("div", { style: { minWidth: 0 }, children: [jsx("h4", { style: previewNameStyles, children: upsell.name }), jsxs("div", { style: previewPriceStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), hasSavings && (jsx("div", { style: { ...previewPriceStyles, color: "var(--bw-highlight-color)" }, children: t("upsells.savePercent", { percent: upsell.savingsPercent ?? 0 }) }))] }), jsxs("div", { style: headerRightStyles, children: [jsx("button", { type: "button", onClick: (event) => {
15378
+ event.stopPropagation();
15379
+ onSelect();
15380
+ }, "aria-label": t("common.extras"), style: { background: "transparent", border: "none", cursor: "pointer", padding: 0 }, disabled: isDisabled, children: jsx("div", { style: isSelected ? checkboxSelectedStyles : checkboxInnerStyles, children: isSelected && (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", style: { width: "32px", height: "32px" }, children: jsx("polyline", { points: "20 6 9 17 4 12" }) })) }) }), jsx("span", { style: { ...chevronStyles, transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)" }, children: "\u25BC" })] })] }), isExpanded && (jsxs("div", { style: expandedContentStyles, children: [jsx("div", { style: expandedImageContainerStyles, children: upsell.image ? (jsx("img", { src: upsell.image, alt: upsell.name, style: imageStyles })) : (jsx("div", { style: imagePlaceholderStyles, children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", style: { width: "40px", height: "40px", opacity: 0.4 }, children: jsx("path", { d: "M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" }) }) })) }), upsell.description && (jsx("p", { style: descriptionStyles, children: upsell.description })), upsell.items.length > 0 && (jsx("div", { style: itemsContainerStyles, children: upsell.items.map((item, index) => (jsxs("span", { style: itemStyles, children: [item.type === "product" ? "📦" : "🎫", " ", item.name, item.quantity > 1 && ` (${item.quantity}x)`] }, index))) })), upsell.suggestedEventInstance && (jsxs("div", { style: eventInfoStyles, children: [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", {
15355
15381
  weekday: "short",
15356
15382
  day: "numeric",
15357
15383
  month: "short",
15358
- })] }), jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] }))] }), jsxs("div", { style: priceContainerStyles, children: [jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] }))] }), isDisabled && (jsx("div", { style: unavailableOverlayStyles, children: jsx("span", { children: upsell.unavailableReason
15384
+ })] }), jsx("span", { style: { color: "var(--bw-text-muted)" }, children: t("upsells.spotsFree", { count: upsell.suggestedEventInstance.availableSpots }) })] })), jsxs("div", { style: priceContainerStyles, children: [jsxs("span", { style: pricePerPersonStyles, children: [formatCurrency(upsell.price), "/", t("common.perPerson")] }), participantCount > 1 && (jsxs("span", { style: priceTotalStyles, children: ["= ", formatCurrency(totalPrice)] })), hasSavings && (jsx("span", { style: priceTotalStyles, children: t("upsells.savePercent", { percent: upsell.savingsPercent ?? 0 }) }))] })] })), isDisabled && (jsx("div", { style: unavailableOverlayStyles, children: jsx("span", { children: upsell.unavailableReason
15359
15385
  ? formatUnavailableReason(upsell.unavailableReason, t)
15360
15386
  : t("upsells.notAvailable") }) }))] }));
15361
15387
  }
@@ -15374,20 +15400,9 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
15374
15400
  }
15375
15401
  };
15376
15402
  const isSelected = (upsellId) => selectedUpsells.some((s) => s.upsellPackageId === upsellId);
15377
- // Calculate total for selected upsells
15378
- const calculateTotal = () => {
15379
- return selectedUpsells.reduce((total, selection) => {
15380
- const upsell = upsells.find((u) => u.id === selection.upsellPackageId);
15381
- if (upsell) {
15382
- return total + upsell.price * selection.quantity;
15383
- }
15384
- return total;
15385
- }, 0);
15386
- };
15387
- const selectedTotal = calculateTotal();
15388
15403
  const selectedCount = selectedUpsells.length;
15389
15404
  const footerContent = (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: onBack, style: mergeStyles(buttonStyles.secondary, buttonStyles.fullWidth), className: buttonClassName, children: t("common.back") }), jsx("button", { type: "button", onClick: onContinue, style: mergeStyles(buttonStyles.primary, buttonStyles.fullWidth), className: buttonClassName, children: selectedCount === 0 ? t("button.continueWithout") : t("button.continue") })] }));
15390
- return (jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: [jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
15405
+ return (jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsx("div", { style: { display: "flex", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }) }))] }) }));
15391
15406
  }
15392
15407
 
15393
15408
  /**
@@ -15525,6 +15540,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
15525
15540
  // Upsells state
15526
15541
  const [upsells, setUpsells] = useState([]);
15527
15542
  const [selectedUpsells, setSelectedUpsells] = useState([]);
15543
+ const [bookingPersistedState, setBookingPersistedState] = useState(null);
15528
15544
  const [isLoadingUpsells, setIsLoadingUpsells] = useState(false);
15529
15545
  const [tempParticipantCount, setTempParticipantCount] = useState(1); // Used during upsell step
15530
15546
  // State for upcoming events (next-events view mode)
@@ -16179,6 +16195,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16179
16195
  const handleEventInstanceSelect = async (eventInstance) => {
16180
16196
  trackEvent("event_instance_selected", { eventInstanceId: eventInstance.id, eventInstanceName: eventInstance.name });
16181
16197
  setSelectedEventInstance(eventInstance);
16198
+ setBookingPersistedState(null);
16182
16199
  bookingReturnStep.current = "eventInstances";
16183
16200
  // Set default participant count for upsell calculations
16184
16201
  const defaultParticipantCount = 1;
@@ -16232,6 +16249,21 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16232
16249
  setCurrentStep(bookingReturnStep.current);
16233
16250
  setSelectedEventInstance(null);
16234
16251
  setEventDetails(null);
16252
+ setBookingPersistedState(null);
16253
+ };
16254
+ const handleBackFromBooking = () => {
16255
+ if (upsells.length > 0) {
16256
+ setCurrentStep("upsells");
16257
+ return;
16258
+ }
16259
+ if (isDirectInstanceMode) {
16260
+ setCurrentStep("eventTypes");
16261
+ setSidebarOpen(false);
16262
+ setEventDetails(null);
16263
+ setBookingPersistedState(null);
16264
+ return;
16265
+ }
16266
+ handleBackToEventInstances();
16235
16267
  };
16236
16268
  const handleBookingSuccess = (result) => {
16237
16269
  trackEvent("booking_completed", { paymentIntentId: result.paymentIntent?.id });
@@ -16239,6 +16271,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16239
16271
  setSuccessPaymentId(result.paymentIntent.id);
16240
16272
  setSidebarOpen(false);
16241
16273
  setShouldRenderBookingForm(false);
16274
+ setBookingPersistedState(null);
16242
16275
  config.onSuccess?.(result);
16243
16276
  };
16244
16277
  const handleBookingError = (errorMessage) => {
@@ -16307,6 +16340,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16307
16340
  ? (eventTypes.find((et) => et.id === eventTypeId) ?? selectedEventType)
16308
16341
  : selectedEventType;
16309
16342
  if (resolvedEventType && resolvedEventType !== selectedEventType) {
16343
+ trackEvent("event_type_selected", { eventTypeId: resolvedEventType.id, eventTypeName: resolvedEventType.name });
16310
16344
  setSelectedEventType(resolvedEventType);
16311
16345
  }
16312
16346
  // Check if this is coming from a card preview (eventTypeId was provided)
@@ -16360,7 +16394,9 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16360
16394
  }
16361
16395
  : null;
16362
16396
  if (eventInstance) {
16397
+ trackEvent("event_instance_selected", { eventInstanceId: eventInstance.id, eventInstanceName: eventInstance.name });
16363
16398
  setSelectedEventInstance(eventInstance);
16399
+ setBookingPersistedState(null);
16364
16400
  }
16365
16401
  setError(null);
16366
16402
  // Check for upsells before going to booking (same as handleEventInstanceSelect)
@@ -16524,19 +16560,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16524
16560
  }
16525
16561
  // Main view based on view mode
16526
16562
  if (viewMode === "next-events" && showingPreview) {
16527
- return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
16528
- setCurrentStep("eventTypes");
16529
- setShowingPreview(true);
16530
- setEventDetails(null);
16531
- }, onBackToEventTypes: () => {
16532
- setCurrentStep("eventTypes");
16533
- setShowingPreview(true);
16534
- setEventDetails(null);
16535
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
16536
- setCurrentStep("eventTypes");
16537
- setShowingPreview(true);
16538
- setEventDetails(null);
16539
- }, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16563
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16540
16564
  setIsSuccess(false);
16541
16565
  setCurrentStep("eventTypes");
16542
16566
  setShowingPreview(true);
@@ -16546,6 +16570,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16546
16570
  setShouldRenderBookingForm(false);
16547
16571
  setSelectedUpsells([]);
16548
16572
  setUpsells([]);
16573
+ setBookingPersistedState(null);
16549
16574
  const url = new URL(window.location.href);
16550
16575
  url.searchParams.delete("payment_intent");
16551
16576
  url.searchParams.delete("payment_intent_client_secret");
@@ -16556,19 +16581,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16556
16581
  }, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
16557
16582
  }
16558
16583
  if (viewMode === "specials" && showingPreview) {
16559
- return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
16560
- setCurrentStep("eventTypes");
16561
- setShowingPreview(true);
16562
- setEventDetails(null);
16563
- }, onBackToEventTypes: () => {
16564
- setCurrentStep("eventTypes");
16565
- setShowingPreview(true);
16566
- setEventDetails(null);
16567
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
16568
- setCurrentStep("eventTypes");
16569
- setShowingPreview(true);
16570
- setEventDetails(null);
16571
- }, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16584
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [jsx(SpecialsView, { specials: specials, onEventSelect: handleUpcomingEventSelect, isLoading: isLoadingSpecials, showSavingsAmount: config.specialsSettings?.showSavingsAmount ?? true, showSavingsPercent: config.specialsSettings?.showSavingsPercent ?? false, emptyStateText: config.specialsSettings?.emptyStateText }), shouldRenderBookingForm && eventDetails && (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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16572
16585
  setIsSuccess(false);
16573
16586
  setCurrentStep("eventTypes");
16574
16587
  setShowingPreview(true);
@@ -16578,6 +16591,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16578
16591
  setShouldRenderBookingForm(false);
16579
16592
  setSelectedUpsells([]);
16580
16593
  setUpsells([]);
16594
+ setBookingPersistedState(null);
16581
16595
  }, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
16582
16596
  }
16583
16597
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
@@ -16630,7 +16644,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16630
16644
  setShouldRenderInstanceSelection(true);
16631
16645
  }
16632
16646
  }, children: config.buttonText ||
16633
- (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), onBackToEventTypes: () => setSidebarOpen(false), selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => setCurrentStep(isDirectInstanceMode ? "eventTypes" : "eventInstances"), systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16647
+ (isDirectInstanceMode ? t("button.bookNow") : t("button.selectDate")) }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
16634
16648
  setIsSuccess(false);
16635
16649
  setCurrentStep("eventTypes");
16636
16650
  setSidebarOpen(false);
@@ -16662,32 +16676,36 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16662
16676
  // Determine the correct back handlers based on view mode
16663
16677
  const getBackHandlers = () => {
16664
16678
  if (viewMode === "next-events") {
16665
- return {
16666
- onBackToEventInstances: () => {
16667
- setCurrentStep("eventInstances");
16679
+ const backFromBooking = () => {
16680
+ if (upsells.length > 0) {
16681
+ setCurrentStep("upsells");
16668
16682
  setShowingPreview(false);
16669
- setEventDetails(null);
16670
- },
16683
+ return;
16684
+ }
16685
+ setCurrentStep("eventInstances");
16686
+ setShowingPreview(false);
16687
+ setEventDetails(null);
16688
+ setBookingPersistedState(null);
16689
+ };
16690
+ return {
16691
+ onBackToEventInstances: backFromBooking,
16671
16692
  onBackToEventTypes: () => {
16672
16693
  setShowingPreview(true);
16673
16694
  setCurrentStep("eventTypes");
16674
16695
  setEventDetails(null);
16696
+ setBookingPersistedState(null);
16675
16697
  },
16676
- onClose: () => {
16677
- setCurrentStep("eventInstances");
16678
- setShowingPreview(false);
16679
- setEventDetails(null);
16680
- },
16698
+ onClose: backFromBooking,
16681
16699
  };
16682
16700
  }
16683
16701
  return {
16684
- onBackToEventInstances: handleBackToEventInstances,
16702
+ onBackToEventInstances: handleBackFromBooking,
16685
16703
  onBackToEventTypes: handleBackToEventTypes,
16686
- onClose: handleBackToEventInstances,
16704
+ onClose: handleBackFromBooking,
16687
16705
  };
16688
16706
  };
16689
16707
  const backHandlers = getBackHandlers();
16690
- return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: backHandlers.onBackToEventInstances, onBackToEventTypes: backHandlers.onBackToEventTypes, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells })), jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
16708
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderUpsells && (jsx(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (jsx(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
16691
16709
  setIsSuccess(false);
16692
16710
  setCurrentStep("eventTypes");
16693
16711
  setSuccessPaymentId(null);