@bigz-app/booking-widget 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/booking-widget.js +88 -41
  2. package/dist/booking-widget.js.map +1 -1
  3. package/dist/components/UniversalBookingWidget.d.ts +3 -105
  4. package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
  5. package/dist/components/events/EventInstanceSelection.d.ts +3 -1
  6. package/dist/components/events/EventInstanceSelection.d.ts.map +1 -1
  7. package/dist/components/events/EventTypeSelection.d.ts +2 -1
  8. package/dist/components/events/EventTypeSelection.d.ts.map +1 -1
  9. package/dist/components/events/NextEventsPreview.d.ts +1 -1
  10. package/dist/components/events/NextEventsPreview.d.ts.map +1 -1
  11. package/dist/components/events/SpecialsView.d.ts +1 -1
  12. package/dist/components/events/SpecialsView.d.ts.map +1 -1
  13. package/dist/components/events/types.d.ts +42 -0
  14. package/dist/components/events/types.d.ts.map +1 -0
  15. package/dist/components/upsells/UpsellCard.d.ts +1 -1
  16. package/dist/components/upsells/UpsellCard.d.ts.map +1 -1
  17. package/dist/components/upsells/UpsellsStep.d.ts +2 -44
  18. package/dist/components/upsells/UpsellsStep.d.ts.map +1 -1
  19. package/dist/components/upsells/types.d.ts +44 -0
  20. package/dist/components/upsells/types.d.ts.map +1 -0
  21. package/dist/components/voucher/VoucherPurchaseForm.d.ts +2 -15
  22. package/dist/components/voucher/VoucherPurchaseForm.d.ts.map +1 -1
  23. package/dist/components/voucher/types.d.ts +15 -0
  24. package/dist/components/voucher/types.d.ts.map +1 -0
  25. package/dist/config.d.ts +66 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/i18n/locales/es.d.ts.map +1 -1
  28. package/dist/i18n/locales/pt.d.ts.map +1 -1
  29. package/dist/i18n/locales/sv.d.ts.map +1 -1
  30. package/dist/index.cjs +88 -41
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.esm.js +88 -41
  33. package/dist/index.esm.js.map +1 -1
  34. package/dist/styles/StyleProvider.d.ts +1 -1
  35. package/dist/styles/StyleProvider.d.ts.map +1 -1
  36. package/dist/utils.d.ts +1 -1
  37. package/dist/utils.d.ts.map +1 -1
  38. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -721,6 +721,21 @@ const es = {
721
721
  "instances.bestPrice": "¡¡¡mejor precio!!!",
722
722
  "instances.goodPrice": "buen precio",
723
723
  "instances.oclock": "",
724
+ // Lista de espera
725
+ "waitlist.joinCta": "Lista de espera",
726
+ "waitlist.title": "Apuntarse a la lista de espera",
727
+ "waitlist.subtitle": "{{name}} está agotado. Deja tus datos y te contactaremos si se libera un lugar.",
728
+ "waitlist.name": "Nombre",
729
+ "waitlist.email": "Correo electrónico",
730
+ "waitlist.phone": "Teléfono (opcional)",
731
+ "waitlist.requiredFields": "Por favor, introduce tu nombre y correo electrónico.",
732
+ "waitlist.join": "Apuntarse",
733
+ "waitlist.submitting": "Apuntando...",
734
+ "waitlist.cancel": "Cancelar",
735
+ "waitlist.submitError": "Algo salió mal. Por favor, inténtalo de nuevo.",
736
+ "waitlist.successTitle": "¡Estás en la lista!",
737
+ "waitlist.successMessage": "Eres el número {{position}} en la lista de espera. Te contactaremos si se libera un lugar.",
738
+ "waitlist.done": "Listo",
724
739
  // Next events preview
725
740
  "nextEvents.title": "Próximas fechas disponibles",
726
741
  "nextEvents.subtitle": "Selecciona una fecha o consulta todas las fechas disponibles",
@@ -1018,6 +1033,21 @@ const pt = {
1018
1033
  "instances.bestPrice": "melhor preço !!!",
1019
1034
  "instances.goodPrice": "bom preço",
1020
1035
  "instances.oclock": "",
1036
+ // Lista de espera
1037
+ "waitlist.joinCta": "Lista de espera",
1038
+ "waitlist.title": "Entrar na lista de espera",
1039
+ "waitlist.subtitle": "{{name}} está esgotado. Deixe os seus dados e entraremos em contacto se surgir uma vaga.",
1040
+ "waitlist.name": "Nome",
1041
+ "waitlist.email": "E-mail",
1042
+ "waitlist.phone": "Telefone (opcional)",
1043
+ "waitlist.requiredFields": "Por favor, introduza o seu nome e e-mail.",
1044
+ "waitlist.join": "Inscrever-se",
1045
+ "waitlist.submitting": "A inscrever...",
1046
+ "waitlist.cancel": "Cancelar",
1047
+ "waitlist.submitError": "Algo correu mal. Por favor, tente novamente.",
1048
+ "waitlist.successTitle": "Está na lista!",
1049
+ "waitlist.successMessage": "É o número {{position}} na lista de espera. Entraremos em contacto se surgir uma vaga.",
1050
+ "waitlist.done": "Concluído",
1021
1051
  // Next events preview
1022
1052
  "nextEvents.title": "Próximas datas disponíveis",
1023
1053
  "nextEvents.subtitle": "Selecione uma data ou veja todas as datas disponíveis",
@@ -1315,6 +1345,21 @@ const sv = {
1315
1345
  "instances.bestPrice": "bästa pris !!!",
1316
1346
  "instances.goodPrice": "bra pris",
1317
1347
  "instances.oclock": "",
1348
+ // Väntelista
1349
+ "waitlist.joinCta": "Ställ dig i kö",
1350
+ "waitlist.title": "Ställ dig i kö",
1351
+ "waitlist.subtitle": "{{name}} är fullbokat. Lämna dina uppgifter så kontaktar vi dig om en plats blir ledig.",
1352
+ "waitlist.name": "Namn",
1353
+ "waitlist.email": "E-post",
1354
+ "waitlist.phone": "Telefon (valfritt)",
1355
+ "waitlist.requiredFields": "Ange ditt namn och din e-postadress.",
1356
+ "waitlist.join": "Ställ dig i kö",
1357
+ "waitlist.submitting": "Anmäler...",
1358
+ "waitlist.cancel": "Avbryt",
1359
+ "waitlist.submitError": "Något gick fel. Försök igen.",
1360
+ "waitlist.successTitle": "Du står i kön!",
1361
+ "waitlist.successMessage": "Du är nummer {{position}} på väntelistan. Vi hör av oss om en plats blir ledig.",
1362
+ "waitlist.done": "Klar",
1318
1363
  // Next events preview
1319
1364
  "nextEvents.title": "Nästa tillgängliga datum",
1320
1365
  "nextEvents.subtitle": "Välj ett datum eller visa alla tillgängliga datum",
@@ -14392,7 +14437,7 @@ function InfoBadge({ text }) {
14392
14437
  pointerEvents: "none",
14393
14438
  }, children: text }))] }));
14394
14439
  }
14395
- function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview, isLoading = false, skeletonCount = 4, showVoucherAttachment = false, onVoucherClick, }) {
14440
+ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview, isLoading = false, skeletonCount = 4, showVoucherAttachment = false, onVoucherClick, showImages = true, }) {
14396
14441
  const t = useTranslations();
14397
14442
  const { locale } = useLocale();
14398
14443
  const timezone = useTimezone();
@@ -14471,6 +14516,18 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
14471
14516
  gridAutoRows: "1fr",
14472
14517
  }, children: eventTypes.map((eventType) => {
14473
14518
  const isAvailable = eventType.hasAvailableInstances;
14519
+ const hasImage = showImages && eventType.images && eventType.images.length > 0;
14520
+ const availabilityBadge = (jsx("div", { style: {
14521
+ padding: "4px 8px",
14522
+ borderRadius: "var(--bw-border-radius-small)",
14523
+ fontSize: "12px",
14524
+ fontWeight: 600,
14525
+ color: "#ffffff",
14526
+ fontFamily: "var(--bw-font-family)",
14527
+ backgroundColor: isAvailable
14528
+ ? "var(--bw-success-color)"
14529
+ : "var(--bw-error-color)",
14530
+ }, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }));
14474
14531
  return (jsxs("div", { className: "event-type-card", style: {
14475
14532
  position: "relative",
14476
14533
  backgroundColor: "var(--bw-surface-color)",
@@ -14482,17 +14539,7 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
14482
14539
  fontFamily: "var(--bw-font-family)",
14483
14540
  cursor: isAvailable ? "pointer" : "not-allowed",
14484
14541
  opacity: isAvailable ? 1 : 0.6,
14485
- }, onClick: () => isAvailable && onEventTypeSelect(eventType), children: [jsx("div", { style: { position: "absolute", top: "16px", right: "16px", zIndex: 10 }, children: jsx("div", { style: {
14486
- padding: "4px 8px",
14487
- borderRadius: "var(--bw-border-radius-small)",
14488
- fontSize: "12px",
14489
- fontWeight: 600,
14490
- color: "#ffffff",
14491
- fontFamily: "var(--bw-font-family)",
14492
- backgroundColor: isAvailable
14493
- ? "var(--bw-success-color)"
14494
- : "var(--bw-error-color)",
14495
- }, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), eventType.images && eventType.images.length > 0 && (jsxs(Fragment, { children: [jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsx("div", { style: {
14542
+ }, onClick: () => isAvailable && onEventTypeSelect(eventType), children: [hasImage && (jsx("div", { style: { position: "absolute", top: "16px", right: "16px", zIndex: 10 }, children: availabilityBadge })), hasImage && (jsxs(Fragment, { children: [jsx("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: jsx("div", { style: {
14496
14543
  fontSize: "13px",
14497
14544
  color: "var(--bw-surface-color)",
14498
14545
  fontWeight: 600,
@@ -14506,7 +14553,7 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview,
14506
14553
  flexDirection: "column",
14507
14554
  justifyContent: "space-between",
14508
14555
  height: "540px",
14509
- }, children: [jsxs("div", { children: [jsx("h2", { className: "event-type-title", style: {
14556
+ }, children: [jsxs("div", { children: [!hasImage && (jsx("div", { style: { display: "flex", justifyContent: "flex-end", margin: "0 0 8px 0" }, children: availabilityBadge })), jsx("h2", { className: "event-type-title", style: {
14510
14557
  fontSize: "clamp(1.1rem, 2.5vw, 24px)",
14511
14558
  fontWeight: 700,
14512
14559
  color: "var(--bw-text-color)",
@@ -14778,16 +14825,16 @@ function WaitlistDialog({ apiBaseUrl, organizationId, eventInstanceId, eventName
14778
14825
  }
14779
14826
 
14780
14827
  const getAllocationBadgeInfo = (availableSpots, maxParticipants, t) => {
14781
- const availabilityRatio = availableSpots / maxParticipants;
14782
- if (availabilityRatio >= 0.6)
14783
- return null;
14784
- if (availabilityRatio === 0) {
14828
+ if (maxParticipants <= 0 || availableSpots <= 0) {
14785
14829
  return {
14786
14830
  text: t("events.soldOut"),
14787
14831
  backgroundColor: "#7f1d1d",
14788
14832
  textColor: "#fca5a5",
14789
14833
  };
14790
14834
  }
14835
+ const availabilityRatio = availableSpots / maxParticipants;
14836
+ if (availabilityRatio >= 0.6)
14837
+ return null;
14791
14838
  if (availabilityRatio <= 0.3) {
14792
14839
  return {
14793
14840
  text: t("instances.almostSoldOut"),
@@ -14901,7 +14948,7 @@ const PriceDisplay = ({ price, yearPrices, t }) => {
14901
14948
  boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
14902
14949
  }, children: formatCurrency(price) }));
14903
14950
  };
14904
- function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, }) {
14951
+ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, waitlistEnabled = false, }) {
14905
14952
  const t = useTranslations();
14906
14953
  const { locale } = useLocale();
14907
14954
  const timezone = useTimezone();
@@ -15086,12 +15133,13 @@ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInst
15086
15133
  ? "0 2px 4px rgba(0, 0, 0, 0.2)"
15087
15134
  : undefined,
15088
15135
  }, children: `${t("common.from")} ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", paddingTop: "12px" }, children: events.map((event) => {
15089
- const availableSpots = event.maxParticipants - event.participantCount;
15090
- const isFullyBooked = availableSpots === 0;
15136
+ const availableSpots = event.availableSpots;
15091
15137
  const startDate = new Date(event.startTime);
15092
15138
  const isPastEvent = today.toISOString() >= startDate.toISOString();
15093
- const isDisabled = isFullyBooked || isPastEvent || !event.bookingOpen;
15094
- const canWaitlist = isFullyBooked &&
15139
+ const isUnavailable = availableSpots <= 0 || !event.bookingOpen;
15140
+ const isDisabled = isUnavailable || isPastEvent;
15141
+ const canWaitlist = waitlistEnabled &&
15142
+ isUnavailable &&
15095
15143
  !isPastEvent &&
15096
15144
  !!apiBaseUrl &&
15097
15145
  !!organizationId;
@@ -15128,7 +15176,7 @@ function EventInstanceSelection({ eventInstances, selectedEventType, onEventInst
15128
15176
  color: "var(--bw-highlight-color)",
15129
15177
  opacity: 0.8,
15130
15178
  fontSize: "32px",
15131
- }, children: spinner() }) })), jsx(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), jsx(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants, t: t }), jsxs("div", { style: {
15179
+ }, children: spinner() }) })), jsx(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), jsx(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.effectiveMaxParticipants ?? event.maxParticipants, t: t }), jsxs("div", { style: {
15132
15180
  display: "flex",
15133
15181
  justifyContent: "space-between",
15134
15182
  width: "100%",
@@ -15305,18 +15353,19 @@ function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText
15305
15353
  margin: "0 auto",
15306
15354
  padding: "12px 16px",
15307
15355
  fontFamily: "var(--bw-font-family)",
15308
- }, children: [jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginBottom: "10px" }, children: events.map((event) => {
15309
- const availableSpots = event.maxParticipants - event.participantCount;
15310
- const isFullyBooked = availableSpots === 0;
15356
+ }, children: [jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginBottom: "10px" }, children: events
15357
+ .filter((event) => {
15311
15358
  const startDate = new Date(event.startTime);
15312
15359
  const isPastEvent = today.toISOString() >= startDate.toISOString();
15313
- const isDisabled = isFullyBooked || isPastEvent || !event.bookingOpen;
15314
- const availabilityRatio = availableSpots / event.maxParticipants;
15360
+ return !isPastEvent && event.availableSpots > 0 && event.bookingOpen;
15361
+ })
15362
+ .map((event) => {
15363
+ const availableSpots = event.availableSpots;
15364
+ const startDate = new Date(event.startTime);
15315
15365
  const allocationBadge = (() => {
15366
+ const availabilityRatio = availableSpots / event.maxParticipants;
15316
15367
  if (availabilityRatio >= 0.6)
15317
15368
  return null;
15318
- if (availabilityRatio === 0)
15319
- return { text: t("events.soldOut"), backgroundColor: "#7f1d1d", textColor: "#fca5a5" };
15320
15369
  if (availabilityRatio <= 0.3)
15321
15370
  return { text: t("instances.almostSoldOut"), backgroundColor: "#7f1d1d", textColor: "#fca5a5" };
15322
15371
  return { text: t("instances.popularDate"), backgroundColor: "#b45309", textColor: "#fbbf24" };
@@ -15330,13 +15379,9 @@ function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText
15330
15379
  padding: "16px 10px",
15331
15380
  transition: "all 0.2s ease",
15332
15381
  fontFamily: "var(--bw-font-family)",
15333
- opacity: isDisabled ? 0.3 : 1,
15334
- filter: isDisabled ? "grayscale(40%)" : "none",
15335
- cursor: isDisabled ? "not-allowed" : "pointer",
15382
+ cursor: "pointer",
15336
15383
  }, onClick: () => {
15337
- if (!isDisabled) {
15338
- handleEventSelect(event.id);
15339
- }
15384
+ handleEventSelect(event.id);
15340
15385
  }, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (jsx("div", { style: {
15341
15386
  position: "absolute",
15342
15387
  inset: 0,
@@ -15591,7 +15636,7 @@ function SpecialsView({ specials, onEventSelect, isLoading = false, showSavingsA
15591
15636
  alignItems: "center",
15592
15637
  backgroundColor: "var(--bw-background-color)",
15593
15638
  }, children: [jsx("span", { style: { fontSize: "12px", color: "var(--bw-text-muted)" }, children: isFullyBooked
15594
- ? t("common.fullyBooked")
15639
+ ? t("events.soldOut")
15595
15640
  : t("specials.spotsLeft").replace("{{count}}", String(special.availableSpots)) }), jsxs("span", { style: {
15596
15641
  fontSize: "13px",
15597
15642
  fontWeight: 600,
@@ -16540,6 +16585,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
16540
16585
  const [isSuccess, setIsSuccess] = useState(false);
16541
16586
  const [successPaymentId, setSuccessPaymentId] = useState(null);
16542
16587
  const [systemConfig, setSystemConfig] = useState(null);
16588
+ const [waitlistEnabled, setWaitlistEnabled] = useState(false);
16543
16589
  // When true, loadEventInstances skips the single-instance auto-select (used by handleShowAllEvents)
16544
16590
  const skipInstanceAutoSelectRef = useRef(false);
16545
16591
  // PERFORMANCE OPTIMIZATION: Lazy component loading
@@ -17033,6 +17079,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
17033
17079
  }
17034
17080
  extractGoogleAdsConfig(data);
17035
17081
  setEventInstances(data.eventInstances);
17082
+ setWaitlistEnabled(data.waitlistEnabled ?? false);
17036
17083
  if (data.paymentProvider) {
17037
17084
  setSystemConfig({
17038
17085
  paymentProvider: data.paymentProvider,
@@ -17601,7 +17648,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
17601
17648
  }, isOpen: currentStep === "eventInstances", onClose: () => {
17602
17649
  setShowingPreview(true);
17603
17650
  setCurrentStep("eventTypes");
17604
- }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
17651
+ }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
17605
17652
  setIsSuccess(false);
17606
17653
  setCurrentStep("eventTypes");
17607
17654
  setShowingPreview(true);
@@ -17664,7 +17711,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
17664
17711
  }, children: [isButtonBusy && jsx(Spinner, { size: 20, borderColor: "var(--bw-button-text-color, #ffffff)" }), config.buttonText ||
17665
17712
  (isDirectInstanceMode || selectedEventType?.bookingMode === "freeform"
17666
17713
  ? t("button.bookNow")
17667
- : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), 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, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (jsx(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
17714
+ : t("button.viewDates"))] }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), 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, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (jsx(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
17668
17715
  setCurrentStep("eventTypes");
17669
17716
  setSidebarOpen(false);
17670
17717
  setShouldRenderFreeformSelection(false);
@@ -17689,7 +17736,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
17689
17736
  }, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (jsx(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
17690
17737
  }
17691
17738
  // Cards mode (default) - show event type selection with optional voucher card
17692
- const cardsView = (jsxs(Fragment, { children: [hasEventSelection && (jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, onInstancePreview: (instanceId, eventTypeId) => void handleUpcomingEventSelect(instanceId, eventTypeId), isLoading: isLoading, skeletonCount: getSkeletonCount(), showVoucherAttachment: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled && !isStandaloneVoucherMode), onVoucherClick: handleVoucherAttachmentClick })), isStandaloneVoucherMode && (jsx(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, categories: voucherCategories, systemConfig: systemConfig, isFormOpen: false, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: null, voucherPurchaseResult: null, isSuccess: false, showStandaloneCard: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled), onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => { } })), isStandaloneVoucherMode && isLoading && !voucherConfig && (jsx("div", { style: { padding: "24px", textAlign: "center" }, children: jsx("div", { style: {
17739
+ const cardsView = (jsxs(Fragment, { children: [hasEventSelection && (jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, onInstancePreview: (instanceId, eventTypeId) => void handleUpcomingEventSelect(instanceId, eventTypeId), isLoading: isLoading, skeletonCount: getSkeletonCount(), showVoucherAttachment: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled && !isStandaloneVoucherMode), onVoucherClick: handleVoucherAttachmentClick, showImages: config.showEventImages !== false })), isStandaloneVoucherMode && (jsx(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, categories: voucherCategories, systemConfig: systemConfig, isFormOpen: false, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: null, voucherPurchaseResult: null, isSuccess: false, showStandaloneCard: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled), onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => { } })), isStandaloneVoucherMode && isLoading && !voucherConfig && (jsx("div", { style: { padding: "24px", textAlign: "center" }, children: jsx("div", { style: {
17693
17740
  display: "inline-block",
17694
17741
  width: "32px",
17695
17742
  height: "32px",
@@ -17730,7 +17777,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
17730
17777
  };
17731
17778
  };
17732
17779
  const backHandlers = getBackHandlers();
17733
- 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, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), 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, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (jsx(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
17780
+ 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, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), 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, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (jsx(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
17734
17781
  setCurrentStep("eventTypes");
17735
17782
  setShouldRenderFreeformSelection(false);
17736
17783
  }, onSuccess: handleBookingSuccess, onError: handleBookingError, systemConfig: systemConfig })), jsx(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {