@bigz-app/booking-widget 0.3.8 → 0.3.10

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
@@ -12225,6 +12225,282 @@ function NextEventsPreview({ events, onEventSelect, onShowAll, showAllButtonText
12225
12225
  ` })] }));
12226
12226
  }
12227
12227
 
12228
+ function PromoDialog({ onClose, onCtaClick }) {
12229
+ const [copied, setCopied] = useState(false);
12230
+ const [isVisible, setIsVisible] = useState(false);
12231
+ const [portalContainer, setPortalContainer] = useState(null);
12232
+ // Hardcoded Xmas surf school content
12233
+ const discountCode = "X-MAS";
12234
+ // Create portal container on mount to escape stacking context issues
12235
+ useEffect(() => {
12236
+ const container = document.createElement("div");
12237
+ container.id = "bigz-promo-dialog-portal";
12238
+ container.style.position = "relative";
12239
+ container.style.zIndex = "2147483647"; // Maximum z-index value
12240
+ document.body.appendChild(container);
12241
+ setPortalContainer(container);
12242
+ return () => {
12243
+ document.body.removeChild(container);
12244
+ };
12245
+ }, []);
12246
+ // Animate in on mount
12247
+ useEffect(() => {
12248
+ const timer = setTimeout(() => setIsVisible(true), 50);
12249
+ return () => clearTimeout(timer);
12250
+ }, []);
12251
+ const handleCopyCode = async () => {
12252
+ try {
12253
+ await navigator.clipboard.writeText(discountCode);
12254
+ setCopied(true);
12255
+ setTimeout(() => setCopied(false), 2000);
12256
+ }
12257
+ catch (err) {
12258
+ // Fallback for older browsers
12259
+ const textArea = document.createElement("textarea");
12260
+ textArea.value = discountCode;
12261
+ document.body.appendChild(textArea);
12262
+ textArea.select();
12263
+ document.execCommand("copy");
12264
+ document.body.removeChild(textArea);
12265
+ setCopied(true);
12266
+ setTimeout(() => setCopied(false), 2000);
12267
+ }
12268
+ };
12269
+ const handleClose = () => {
12270
+ setIsVisible(false);
12271
+ setTimeout(onClose, 200);
12272
+ };
12273
+ const handleCtaClick = () => {
12274
+ setIsVisible(false);
12275
+ setTimeout(onCtaClick, 200);
12276
+ };
12277
+ // Don't render until portal container is ready
12278
+ if (!portalContainer) {
12279
+ return null;
12280
+ }
12281
+ const dialogContent = (jsxs(Fragment, { children: [jsx("style", { children: `
12282
+ @keyframes promo-wave {
12283
+ 0%, 100% { transform: translateX(0) translateY(0); }
12284
+ 25% { transform: translateX(5px) translateY(-3px); }
12285
+ 50% { transform: translateX(0) translateY(-5px); }
12286
+ 75% { transform: translateX(-5px) translateY(-3px); }
12287
+ }
12288
+ @keyframes promo-float {
12289
+ 0%, 100% { transform: translateY(0); }
12290
+ 50% { transform: translateY(-8px); }
12291
+ }
12292
+ @keyframes promo-shimmer {
12293
+ 0% { background-position: -200% center; }
12294
+ 100% { background-position: 200% center; }
12295
+ }
12296
+ @keyframes promo-sparkle {
12297
+ 0%, 100% { opacity: 0.3; transform: scale(1); }
12298
+ 50% { opacity: 1; transform: scale(1.2); }
12299
+ }
12300
+ @keyframes promo-snow {
12301
+ 0% { transform: translateY(-10px) rotate(0deg); opacity: 0; }
12302
+ 10% { opacity: 1; }
12303
+ 90% { opacity: 1; }
12304
+ 100% { transform: translateY(350px) rotate(360deg); opacity: 0; }
12305
+ }
12306
+ ` }), jsx("div", { onClick: handleClose, style: {
12307
+ position: "fixed",
12308
+ inset: 0,
12309
+ backgroundColor: "rgba(0, 20, 40, 0.85)",
12310
+ backdropFilter: "blur(8px)",
12311
+ zIndex: 60,
12312
+ opacity: isVisible ? 1 : 0,
12313
+ transition: "opacity 300ms ease-out",
12314
+ } }), jsx("div", { style: {
12315
+ position: "fixed",
12316
+ top: "50%",
12317
+ left: "50%",
12318
+ transform: `translate(-50%, -50%) scale(${isVisible ? 1 : 0.9})`,
12319
+ zIndex: 61,
12320
+ width: "92%",
12321
+ maxWidth: "440px",
12322
+ opacity: isVisible ? 1 : 0,
12323
+ transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
12324
+ }, children: jsxs("div", { style: {
12325
+ position: "relative",
12326
+ background: "linear-gradient(165deg, #0c4a6e 0%, #0e7490 40%, #0891b2 100%)",
12327
+ borderRadius: "28px",
12328
+ overflow: "hidden",
12329
+ boxShadow: "0 25px 60px -12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.1), inset 0 1px 0 rgba(255,255,255,0.2)",
12330
+ }, children: [Array.from({ length: 15 }).map((_, i) => (jsx("div", { style: {
12331
+ position: "absolute",
12332
+ left: `${5 + Math.random() * 90}%`,
12333
+ top: "-10px",
12334
+ fontSize: `${10 + Math.random() * 14}px`,
12335
+ color: "white",
12336
+ opacity: 0,
12337
+ animation: `promo-snow ${4 + Math.random() * 3}s linear infinite`,
12338
+ animationDelay: `${Math.random() * 4}s`,
12339
+ pointerEvents: "none",
12340
+ zIndex: 1,
12341
+ }, children: "\u2744" }, i))), jsxs("div", { style: {
12342
+ position: "relative",
12343
+ height: "180px",
12344
+ background: "linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(12,74,110,0.8) 100%)",
12345
+ display: "flex",
12346
+ alignItems: "center",
12347
+ justifyContent: "center",
12348
+ overflow: "hidden",
12349
+ }, children: [jsx("img", { src: "https://images.unsplash.com/photo-1502680390469-be75c86b636f?w=600&q=80", alt: "Surfer at sunset", style: {
12350
+ position: "absolute",
12351
+ inset: 0,
12352
+ width: "100%",
12353
+ height: "100%",
12354
+ objectFit: "cover",
12355
+ opacity: 0.6,
12356
+ } }), jsx("div", { style: {
12357
+ position: "absolute",
12358
+ inset: 0,
12359
+ background: "linear-gradient(180deg, rgba(12,74,110,0.3) 0%, rgba(12,74,110,0.95) 100%)",
12360
+ } }), jsx("div", { style: {
12361
+ position: "relative",
12362
+ zIndex: 2,
12363
+ fontSize: "64px",
12364
+ animation: "promo-float 3s ease-in-out infinite",
12365
+ filter: "drop-shadow(0 8px 16px rgba(0,0,0,0.4))",
12366
+ }, children: "\uD83C\uDFC4\u200D\u2642\uFE0F" }), jsx("div", { style: {
12367
+ position: "absolute",
12368
+ top: "16px",
12369
+ left: "20px",
12370
+ fontSize: "28px",
12371
+ animation: "promo-sparkle 2s ease-in-out infinite",
12372
+ }, children: "\uD83C\uDF84" }), jsx("div", { style: {
12373
+ position: "absolute",
12374
+ top: "20px",
12375
+ right: "20px",
12376
+ fontSize: "24px",
12377
+ animation: "promo-sparkle 2s ease-in-out infinite 0.5s",
12378
+ }, children: "\u2B50" })] }), jsx("button", { onClick: handleClose, style: {
12379
+ position: "absolute",
12380
+ top: "16px",
12381
+ right: "16px",
12382
+ width: "36px",
12383
+ height: "36px",
12384
+ borderRadius: "50%",
12385
+ border: "none",
12386
+ background: "rgba(0, 0, 0, 0.3)",
12387
+ backdropFilter: "blur(4px)",
12388
+ color: "white",
12389
+ fontSize: "22px",
12390
+ cursor: "pointer",
12391
+ display: "flex",
12392
+ alignItems: "center",
12393
+ justifyContent: "center",
12394
+ transition: "all 150ms ease",
12395
+ zIndex: 10,
12396
+ lineHeight: 1,
12397
+ }, onMouseEnter: (e) => {
12398
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.5)";
12399
+ e.currentTarget.style.transform = "scale(1.1)";
12400
+ }, onMouseLeave: (e) => {
12401
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.3)";
12402
+ e.currentTarget.style.transform = "scale(1)";
12403
+ }, children: "\u00D7" }), jsxs("div", { style: { padding: "28px 28px 32px", textAlign: "center", position: "relative", zIndex: 2 }, children: [jsx("h2", { style: {
12404
+ fontSize: "26px",
12405
+ fontWeight: "800",
12406
+ color: "white",
12407
+ marginBottom: "6px",
12408
+ textShadow: "0 2px 8px rgba(0,0,0,0.3)",
12409
+ letterSpacing: "-0.5px",
12410
+ }, children: "Frohe Weihnachten! \uD83C\uDF85" }), jsxs("p", { style: {
12411
+ fontSize: "17px",
12412
+ color: "rgba(255, 255, 255, 0.9)",
12413
+ marginBottom: "20px",
12414
+ lineHeight: 1.5,
12415
+ }, children: ["Schenk dir oder deinen Liebsten", jsx("br", {}), jsx("strong", { style: { color: "#fbbf24" }, children: "10% Rabatt" }), " auf alle Kurse!"] }), jsxs("div", { style: {
12416
+ background: "white",
12417
+ borderRadius: "16px",
12418
+ padding: "18px 20px",
12419
+ marginBottom: "20px",
12420
+ boxShadow: "0 8px 24px rgba(0,0,0,0.15), inset 0 -2px 0 rgba(0,0,0,0.05)",
12421
+ }, children: [jsx("p", { style: {
12422
+ fontSize: "11px",
12423
+ textTransform: "uppercase",
12424
+ letterSpacing: "1.5px",
12425
+ color: "#64748b",
12426
+ marginBottom: "10px",
12427
+ fontWeight: "600",
12428
+ }, children: "Dein Geschenk-Code" }), jsxs("div", { style: {
12429
+ display: "flex",
12430
+ alignItems: "center",
12431
+ justifyContent: "center",
12432
+ gap: "14px",
12433
+ }, children: [jsx("div", { style: {
12434
+ background: "linear-gradient(135deg, #dc2626 0%, #b91c1c 100%)",
12435
+ padding: "10px 20px",
12436
+ borderRadius: "10px",
12437
+ boxShadow: "0 4px 12px rgba(220, 38, 38, 0.3)",
12438
+ }, children: jsx("span", { style: {
12439
+ fontSize: "28px",
12440
+ fontWeight: "900",
12441
+ color: "white",
12442
+ letterSpacing: "6px",
12443
+ textShadow: "0 2px 4px rgba(0,0,0,0.2)",
12444
+ }, children: discountCode }) }), jsx("button", { onClick: handleCopyCode, style: {
12445
+ padding: "12px 16px",
12446
+ borderRadius: "10px",
12447
+ border: "2px solid",
12448
+ borderColor: copied ? "#22c55e" : "#e2e8f0",
12449
+ background: copied ? "#dcfce7" : "#f8fafc",
12450
+ color: copied ? "#15803d" : "#475569",
12451
+ fontSize: "13px",
12452
+ fontWeight: "600",
12453
+ cursor: "pointer",
12454
+ transition: "all 150ms ease",
12455
+ display: "flex",
12456
+ alignItems: "center",
12457
+ gap: "6px",
12458
+ whiteSpace: "nowrap",
12459
+ }, children: copied ? (jsx(Fragment, { children: "\u2713 Kopiert!" })) : (jsxs(Fragment, { children: [jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }), "Kopieren"] })) })] })] }), jsx("div", { style: {
12460
+ display: "flex",
12461
+ justifyContent: "center",
12462
+ gap: "8px",
12463
+ marginBottom: "20px",
12464
+ flexWrap: "wrap",
12465
+ }, children: ["🏄 Surfen", "🪁 Wingen", "🏄‍♀️ SUP", "💨 Windsurfen"].map((activity) => (jsx("span", { style: {
12466
+ background: "rgba(255,255,255,0.15)",
12467
+ backdropFilter: "blur(4px)",
12468
+ padding: "6px 12px",
12469
+ borderRadius: "20px",
12470
+ fontSize: "13px",
12471
+ color: "white",
12472
+ fontWeight: "500",
12473
+ }, children: activity }, activity))) }), jsxs("button", { onClick: handleCtaClick, style: {
12474
+ width: "100%",
12475
+ padding: "18px 24px",
12476
+ borderRadius: "14px",
12477
+ border: "none",
12478
+ background: "linear-gradient(135deg, #f59e0b 0%, #d97706 100%)",
12479
+ color: "white",
12480
+ fontSize: "18px",
12481
+ fontWeight: "700",
12482
+ cursor: "pointer",
12483
+ transition: "all 150ms ease",
12484
+ boxShadow: "0 8px 24px rgba(245, 158, 11, 0.4), inset 0 1px 0 rgba(255,255,255,0.2)",
12485
+ display: "flex",
12486
+ alignItems: "center",
12487
+ justifyContent: "center",
12488
+ gap: "10px",
12489
+ }, onMouseEnter: (e) => {
12490
+ e.currentTarget.style.transform = "translateY(-2px)";
12491
+ e.currentTarget.style.boxShadow = "0 12px 28px rgba(245, 158, 11, 0.5), inset 0 1px 0 rgba(255,255,255,0.2)";
12492
+ }, onMouseLeave: (e) => {
12493
+ e.currentTarget.style.transform = "translateY(0)";
12494
+ e.currentTarget.style.boxShadow = "0 8px 24px rgba(245, 158, 11, 0.4), inset 0 1px 0 rgba(255,255,255,0.2)";
12495
+ }, children: [jsx("span", { style: { animation: "promo-wave 2s ease-in-out infinite" }, children: "\uD83C\uDF81" }), "Jetzt Kurs buchen", jsx("span", { children: "\u2192" })] }), jsx("p", { style: {
12496
+ marginTop: "16px",
12497
+ fontSize: "12px",
12498
+ color: "rgba(255,255,255,0.6)",
12499
+ }, children: "G\u00FCltig f\u00FCr alle Buchungen bis 31. Dezember 2025" })] })] }) })] }));
12500
+ // Use portal to render at document body level, escaping any stacking context
12501
+ return createPortal(dialogContent, portalContainer);
12502
+ }
12503
+
12228
12504
  // Predefined themes & Style Provider have been moved to ../styles/StyleProvider.tsx
12229
12505
  // Main widget component
12230
12506
  function UniversalBookingWidget({ config: baseConfig }) {
@@ -12267,6 +12543,9 @@ function UniversalBookingWidget({ config: baseConfig }) {
12267
12543
  // PERFORMANCE OPTIMIZATION: Lazy component loading
12268
12544
  const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = useState(false);
12269
12545
  const [shouldRenderBookingForm, setShouldRenderBookingForm] = useState(false);
12546
+ // Promo dialog state
12547
+ const [showPromoDialog, setShowPromoDialog] = useState(false);
12548
+ const [widgetContainerRef, setWidgetContainerRef] = useState(null);
12270
12549
  // Determine initial step and load data
12271
12550
  useEffect(() => {
12272
12551
  const initializeWidget = async () => {
@@ -12341,6 +12620,46 @@ function UniversalBookingWidget({ config: baseConfig }) {
12341
12620
  setShouldRenderBookingForm(true);
12342
12621
  }
12343
12622
  }, [currentStep, shouldRenderInstanceSelection, shouldRenderBookingForm]);
12623
+ // Promo dialog: show Xmas promo once per user during holiday season, prevent double-opening across multiple widgets
12624
+ useEffect(() => {
12625
+ // Only show during holiday season (December and January)
12626
+ const now = new Date();
12627
+ const month = now.getMonth(); // 0 = January, 11 = December
12628
+ const isHolidaySeason = month === 11 || month === 0; // December (11) or January (0)
12629
+ if (!isHolidaySeason) {
12630
+ return;
12631
+ }
12632
+ const promoId = "xmas-2024";
12633
+ const storageKey = `bigz-promo-${promoId}-shown`;
12634
+ const globalFlagKey = `__bigzPromoShown_${promoId}`;
12635
+ // Check if already shown in this session (localStorage) or claimed by another widget (global flag)
12636
+ const alreadyShown = localStorage.getItem(storageKey) === "true";
12637
+ const claimedByOtherWidget = window[globalFlagKey] === true;
12638
+ if (alreadyShown || claimedByOtherWidget) {
12639
+ return;
12640
+ }
12641
+ // Claim this promo for this widget instance (prevents other widgets from showing it)
12642
+ window[globalFlagKey] = true;
12643
+ // Show the dialog after a short delay for better UX
12644
+ const timer = setTimeout(() => {
12645
+ setShowPromoDialog(true);
12646
+ }, 1000);
12647
+ return () => clearTimeout(timer);
12648
+ }, []);
12649
+ // Handle promo dialog close
12650
+ const handlePromoDialogClose = () => {
12651
+ setShowPromoDialog(false);
12652
+ localStorage.setItem("bigz-promo-xmas-2024-shown", "true");
12653
+ };
12654
+ // Handle promo dialog CTA click - scroll to widget
12655
+ const handlePromoCtaClick = () => {
12656
+ setShowPromoDialog(false);
12657
+ localStorage.setItem("bigz-promo-xmas-2024-shown", "true");
12658
+ // Scroll to the widget container
12659
+ if (widgetContainerRef) {
12660
+ widgetContainerRef.scrollIntoView({ behavior: "smooth", block: "start" });
12661
+ }
12662
+ };
12344
12663
  const loadEventTypes = async () => {
12345
12664
  const requestBody = {
12346
12665
  organizationId: config.organizationId,
@@ -12740,104 +13059,104 @@ function UniversalBookingWidget({ config: baseConfig }) {
12740
13059
  // Main view based on view mode
12741
13060
  if (viewMode === "next-events" && showingPreview) {
12742
13061
  // Next events preview mode
12743
- return (jsxs(StyleProvider, { config: config, 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: () => {
12744
- setCurrentStep("eventTypes");
12745
- setShowingPreview(true);
12746
- setEventDetails(null);
12747
- }, onBackToEventTypes: () => {
12748
- setCurrentStep("eventTypes");
12749
- setShowingPreview(true);
12750
- setEventDetails(null);
12751
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
12752
- setCurrentStep("eventTypes");
12753
- setShowingPreview(true);
12754
- setEventDetails(null);
12755
- }, systemConfig: systemConfig })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12756
- setIsSuccess(false);
12757
- setCurrentStep("eventTypes");
12758
- setShowingPreview(true);
12759
- // Reset state
12760
- setSuccessPaymentIntentId(null);
12761
- // Reset lazy loading flags
12762
- setShouldRenderInstanceSelection(false);
12763
- setShouldRenderBookingForm(false);
12764
- // Clean up URL to remove Stripe parameters
12765
- const url = new URL(window.location.href);
12766
- url.searchParams.delete("payment_intent");
12767
- url.searchParams.delete("payment_intent_client_secret");
12768
- url.searchParams.delete("redirect_status");
12769
- window.history.replaceState({}, "", url.toString());
12770
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13062
+ 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: () => {
13063
+ setCurrentStep("eventTypes");
13064
+ setShowingPreview(true);
13065
+ setEventDetails(null);
13066
+ }, onBackToEventTypes: () => {
13067
+ setCurrentStep("eventTypes");
13068
+ setShowingPreview(true);
13069
+ setEventDetails(null);
13070
+ }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
13071
+ setCurrentStep("eventTypes");
13072
+ setShowingPreview(true);
13073
+ setEventDetails(null);
13074
+ }, systemConfig: systemConfig })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13075
+ setIsSuccess(false);
13076
+ setCurrentStep("eventTypes");
13077
+ setShowingPreview(true);
13078
+ // Reset state
13079
+ setSuccessPaymentIntentId(null);
13080
+ // Reset lazy loading flags
13081
+ setShouldRenderInstanceSelection(false);
13082
+ setShouldRenderBookingForm(false);
13083
+ // Clean up URL to remove Stripe parameters
13084
+ const url = new URL(window.location.href);
13085
+ url.searchParams.delete("payment_intent");
13086
+ url.searchParams.delete("payment_intent_client_secret");
13087
+ url.searchParams.delete("redirect_status");
13088
+ window.history.replaceState({}, "", url.toString());
13089
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (jsx(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12771
13090
  }
12772
13091
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
12773
13092
  // Show all events for the single event type
12774
- return (jsxs(StyleProvider, { config: config, children: [shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
12775
- setShowingPreview(true);
12776
- setCurrentStep("eventTypes");
12777
- }, isOpen: currentStep === "eventInstances", onClose: () => {
12778
- setShowingPreview(true);
12779
- setCurrentStep("eventTypes");
12780
- }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12781
- setIsSuccess(false);
12782
- setCurrentStep("eventTypes");
12783
- setShowingPreview(true);
12784
- // Reset state
12785
- setSuccessPaymentIntentId(null);
12786
- // Reset lazy loading flags
12787
- setShouldRenderInstanceSelection(false);
12788
- setShouldRenderBookingForm(false);
12789
- // Clean up URL to remove Stripe parameters
12790
- const url = new URL(window.location.href);
12791
- url.searchParams.delete("payment_intent");
12792
- url.searchParams.delete("payment_intent_client_secret");
12793
- url.searchParams.delete("redirect_status");
12794
- window.history.replaceState({}, "", url.toString());
12795
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13093
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
13094
+ setShowingPreview(true);
13095
+ setCurrentStep("eventTypes");
13096
+ }, isOpen: currentStep === "eventInstances", onClose: () => {
13097
+ setShowingPreview(true);
13098
+ setCurrentStep("eventTypes");
13099
+ }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13100
+ setIsSuccess(false);
13101
+ setCurrentStep("eventTypes");
13102
+ setShowingPreview(true);
13103
+ // Reset state
13104
+ setSuccessPaymentIntentId(null);
13105
+ // Reset lazy loading flags
13106
+ setShouldRenderInstanceSelection(false);
13107
+ setShouldRenderBookingForm(false);
13108
+ // Clean up URL to remove Stripe parameters
13109
+ const url = new URL(window.location.href);
13110
+ url.searchParams.delete("payment_intent");
13111
+ url.searchParams.delete("payment_intent_client_secret");
13112
+ url.searchParams.delete("redirect_status");
13113
+ window.history.replaceState({}, "", url.toString());
13114
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (jsx(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12796
13115
  }
12797
13116
  if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
12798
13117
  // Button mode - show button that opens sidebar/booking directly
12799
- return (jsx(StyleProvider, { config: config, children: jsxs("div", { style: {
12800
- display: "flex",
12801
- justifyContent: "center",
12802
- alignItems: "center",
12803
- minHeight: "120px",
12804
- }, children: [jsx("button", { type: "button", style: {
12805
- backgroundColor: "var(--bw-highlight-color)",
12806
- color: "white",
12807
- padding: "16px 32px",
12808
- border: "none",
12809
- borderRadius: "var(--bw-border-radius)",
12810
- fontSize: "18px",
12811
- fontWeight: 600,
12812
- fontFamily: "var(--bw-font-family)",
12813
- boxShadow: "var(--bw-shadow-md)",
12814
- cursor: "pointer",
12815
- }, onClick: () => {
12816
- if (isDirectInstanceMode) {
12817
- setCurrentStep("booking");
12818
- setShouldRenderBookingForm(true);
12819
- }
12820
- else {
12821
- setSidebarOpen(true);
12822
- setShouldRenderInstanceSelection(true);
12823
- }
12824
- }, children: config.buttonText ||
12825
- (isDirectInstanceMode ? "Jetzt buchen" : "Jetzt Termin auswählen") }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen, onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12826
- setIsSuccess(false);
12827
- setCurrentStep("eventTypes");
12828
- setSidebarOpen(false);
12829
- // Reset state
12830
- setSuccessPaymentIntentId(null);
12831
- // Reset lazy loading flags
12832
- setShouldRenderInstanceSelection(false);
12833
- setShouldRenderBookingForm(false);
12834
- // Clean up URL to remove Stripe parameters
12835
- const url = new URL(window.location.href);
12836
- url.searchParams.delete("payment_intent");
12837
- url.searchParams.delete("payment_intent_client_secret");
12838
- url.searchParams.delete("redirect_status");
12839
- window.history.replaceState({}, "", url.toString());
12840
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }) }));
13118
+ return (jsxs(StyleProvider, { config: config, children: [jsxs("div", { ref: setWidgetContainerRef, style: {
13119
+ display: "flex",
13120
+ justifyContent: "center",
13121
+ alignItems: "center",
13122
+ minHeight: "120px",
13123
+ }, children: [jsx("button", { type: "button", style: {
13124
+ backgroundColor: "var(--bw-highlight-color)",
13125
+ color: "white",
13126
+ padding: "16px 32px",
13127
+ border: "none",
13128
+ borderRadius: "var(--bw-border-radius)",
13129
+ fontSize: "18px",
13130
+ fontWeight: 600,
13131
+ fontFamily: "var(--bw-font-family)",
13132
+ boxShadow: "var(--bw-shadow-md)",
13133
+ cursor: "pointer",
13134
+ }, onClick: () => {
13135
+ if (isDirectInstanceMode) {
13136
+ setCurrentStep("booking");
13137
+ setShouldRenderBookingForm(true);
13138
+ }
13139
+ else {
13140
+ setSidebarOpen(true);
13141
+ setShouldRenderInstanceSelection(true);
13142
+ }
13143
+ }, children: config.buttonText ||
13144
+ (isDirectInstanceMode ? "Jetzt buchen" : "Jetzt Termin auswählen") }), shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen, onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13145
+ setIsSuccess(false);
13146
+ setCurrentStep("eventTypes");
13147
+ setSidebarOpen(false);
13148
+ // Reset state
13149
+ setSuccessPaymentIntentId(null);
13150
+ // Reset lazy loading flags
13151
+ setShouldRenderInstanceSelection(false);
13152
+ setShouldRenderBookingForm(false);
13153
+ // Clean up URL to remove Stripe parameters
13154
+ const url = new URL(window.location.href);
13155
+ url.searchParams.delete("payment_intent");
13156
+ url.searchParams.delete("payment_intent_client_secret");
13157
+ url.searchParams.delete("redirect_status");
13158
+ window.history.replaceState({}, "", url.toString());
13159
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (jsx(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12841
13160
  }
12842
13161
  // Cards mode (default) - show event type selection
12843
13162
  const cardsView = (jsx(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
@@ -12870,21 +13189,21 @@ function UniversalBookingWidget({ config: baseConfig }) {
12870
13189
  };
12871
13190
  };
12872
13191
  const backHandlers = getBackHandlers();
12873
- return (jsxs(StyleProvider, { config: config, children: [cardsView, shouldRenderInstanceSelection && (jsx(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12874
- setIsSuccess(false);
12875
- setCurrentStep("eventTypes");
12876
- // Reset state
12877
- setSuccessPaymentIntentId(null);
12878
- // Reset lazy loading flags
12879
- setShouldRenderInstanceSelection(false);
12880
- setShouldRenderBookingForm(false);
12881
- // Clean up URL to remove Stripe parameters
12882
- const url = new URL(window.location.href);
12883
- url.searchParams.delete("payment_intent");
12884
- url.searchParams.delete("payment_intent_client_secret");
12885
- url.searchParams.delete("redirect_status");
12886
- window.history.replaceState({}, "", url.toString());
12887
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13192
+ 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 })), 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 })), jsx(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13193
+ setIsSuccess(false);
13194
+ setCurrentStep("eventTypes");
13195
+ // Reset state
13196
+ setSuccessPaymentIntentId(null);
13197
+ // Reset lazy loading flags
13198
+ setShouldRenderInstanceSelection(false);
13199
+ setShouldRenderBookingForm(false);
13200
+ // Clean up URL to remove Stripe parameters
13201
+ const url = new URL(window.location.href);
13202
+ url.searchParams.delete("payment_intent");
13203
+ url.searchParams.delete("payment_intent_client_secret");
13204
+ url.searchParams.delete("redirect_status");
13205
+ window.history.replaceState({}, "", url.toString());
13206
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (jsx(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12888
13207
  }
12889
13208
 
12890
13209
  // Export init function for vanilla JS usage