@bigz-app/booking-widget 0.2.3 → 0.3.1

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.
@@ -295,9 +295,9 @@
295
295
  const themes = {
296
296
  // --- Light Themes ---
297
297
  "light-fresh": {
298
- highlight: "oklch(0.65 0.2 190)", // accent-strong
299
- background: "oklch(0.99 0.005 220)", // neutral-strong (background)
300
- surface: "oklch(1 0 0)", // card (pure white)
298
+ highlight: "#00a8a1", // accent-strong
299
+ background: "#f8fdfe", // neutral-strong (background)
300
+ surface: "#ffffff", // card (pure white)
301
301
  text: "#0e7490", // Turquoise 800
302
302
  border: "#bae6fd", // Blue 200
303
303
  success: "#38bdf8", // Blue 400
@@ -9197,7 +9197,7 @@
9197
9197
 
9198
9198
  var reactStripe_umdExports = reactStripe_umd.exports;
9199
9199
 
9200
- const spinner = (borderColor) => (u$2("div", { style: {
9200
+ const spinner$1 = (borderColor) => (u$2("div", { style: {
9201
9201
  width: "auto",
9202
9202
  height: "auto",
9203
9203
  fontSize: "16px",
@@ -9333,7 +9333,7 @@
9333
9333
  if (!isLoading) {
9334
9334
  e.currentTarget.style.backgroundColor = "var(--bw-highlight-color)";
9335
9335
  }
9336
- }, children: isLoading ? (u$2(k$3, { children: [spinner("var(--bw-surface-color)"), " Verarbeite Zahlung..."] })) : (u$2(k$3, { children: [" ", totalAmount <
9336
+ }, children: isLoading ? (u$2(k$3, { children: [spinner$1("var(--bw-surface-color)"), " Verarbeite Zahlung..."] })) : (u$2(k$3, { children: [" ", totalAmount <
9337
9337
  eventDetails.price * formData.participants.filter((p) => p.name.trim()).length
9338
9338
  ? "Anzahlen & buchen"
9339
9339
  : "Jetzt buchen"] })) }), u$2("style", { children: `
@@ -9349,6 +9349,64 @@
9349
9349
  const [paymentIntentId, setPaymentIntentId] = d$1(null);
9350
9350
  const [isCreatingPaymentIntent, setIsCreatingPaymentIntent] = d$1(false);
9351
9351
  const [paymentError, setPaymentError] = d$1(null);
9352
+ // LocalStorage persistence (scoped by organization + event) for paymentIntentId only
9353
+ const storageKey = typeof window !== "undefined"
9354
+ ? `bw_pi_${config?.organizationId}_${config?.eventInstanceId || eventDetails?.id}`
9355
+ : "";
9356
+ const PAYMENT_INTENT_TTL = 24 * 60 * 60 * 1000; // 24 hours
9357
+ function loadPersistedPaymentIntent() {
9358
+ if (typeof window === "undefined" || !storageKey)
9359
+ return null;
9360
+ try {
9361
+ const raw = window.localStorage.getItem(storageKey);
9362
+ if (!raw)
9363
+ return null;
9364
+ const parsed = JSON.parse(raw);
9365
+ if (!parsed?.id || !parsed?.ts)
9366
+ return null;
9367
+ if (Date.now() - parsed.ts > PAYMENT_INTENT_TTL) {
9368
+ window.localStorage.removeItem(storageKey);
9369
+ return null;
9370
+ }
9371
+ return parsed.id;
9372
+ }
9373
+ catch {
9374
+ return null;
9375
+ }
9376
+ }
9377
+ function persistPaymentIntent(id) {
9378
+ if (typeof window === "undefined" || !storageKey || !id)
9379
+ return;
9380
+ try {
9381
+ const payload = { id, ts: Date.now() };
9382
+ window.localStorage.setItem(storageKey, JSON.stringify(payload));
9383
+ }
9384
+ catch { }
9385
+ }
9386
+ function clearPersistedPaymentIntent() {
9387
+ if (typeof window === "undefined" || !storageKey)
9388
+ return;
9389
+ try {
9390
+ window.localStorage.removeItem(storageKey);
9391
+ }
9392
+ catch { }
9393
+ }
9394
+ // On mount (and when scope changes), restore persisted paymentIntentId
9395
+ y$1(() => {
9396
+ if (!paymentIntentId) {
9397
+ const restored = loadPersistedPaymentIntent();
9398
+ if (restored) {
9399
+ setPaymentIntentId(restored);
9400
+ }
9401
+ }
9402
+ // eslint-disable-next-line react-hooks/exhaustive-deps
9403
+ }, [storageKey]);
9404
+ // Persist whenever paymentIntentId changes
9405
+ y$1(() => {
9406
+ if (paymentIntentId) {
9407
+ persistPaymentIntent(paymentIntentId);
9408
+ }
9409
+ }, [paymentIntentId]);
9352
9410
  // Create payment intent when component mounts or when relevant data changes
9353
9411
  y$1(() => {
9354
9412
  const createPaymentIntent = async () => {
@@ -9453,7 +9511,7 @@
9453
9511
  justifyContent: "center",
9454
9512
  padding: "var(--bw-spacing)",
9455
9513
  gap: "8px",
9456
- }, children: [spinner(), u$2("span", { style: {
9514
+ }, children: [spinner$1(), u$2("span", { style: {
9457
9515
  color: "var(--bw-text-muted)",
9458
9516
  fontFamily: "var(--bw-font-family)",
9459
9517
  fontSize: "var(--bw-font-size)",
@@ -9478,10 +9536,16 @@
9478
9536
  clientSecret,
9479
9537
  appearance: stripeAppearance || { theme: "stripe" },
9480
9538
  locale: config.locale || "de",
9481
- }, children: u$2(PaymentFormInner, { config: config, eventDetails: eventDetails, formData: formData, totalAmount: totalAmount, discountCode: discountCode, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, clientSecret: clientSecret }) }));
9539
+ }, children: u$2(PaymentFormInner, { config: config, eventDetails: eventDetails, formData: formData, totalAmount: totalAmount, discountCode: discountCode, onSuccess: (result) => {
9540
+ // Clear persisted PI data on successful payment
9541
+ clearPersistedPaymentIntent();
9542
+ setPaymentIntentId(null);
9543
+ setClientSecret(null);
9544
+ onSuccess(result);
9545
+ }, onError: onError, systemConfig: systemConfig, clientSecret: clientSecret }) }));
9482
9546
  }
9483
9547
 
9484
- function Sidebar({ isOpen, onClose, title, children, width = "400px" }) {
9548
+ function Sidebar({ isOpen, onClose, title, children, width = "450px" }) {
9485
9549
  const [isVisible, setIsVisible] = d$1(false);
9486
9550
  const [isAnimating, setIsAnimating] = d$1(false);
9487
9551
  const themedStyles = useStyles();
@@ -9880,7 +9944,7 @@
9880
9944
  marginBottom: "8px",
9881
9945
  fontFamily: "var(--bw-font-family)",
9882
9946
  };
9883
- return (u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `Buchung - ${eventDetails.name}`, width: "420px", children: u$2("div", { className: "booking-widget-container", style: { padding: "var(--bw-spacing)" }, children: [u$2("div", { style: {
9947
+ return (u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `Buchung - ${eventDetails.name}`, children: u$2("div", { className: "booking-widget-container", style: { padding: "var(--bw-spacing)" }, children: [u$2("div", { style: {
9884
9948
  backgroundColor: "var(--bw-surface-color)",
9885
9949
  border: `1px solid var(--bw-border-color)`,
9886
9950
  backdropFilter: "blur(4px)",
@@ -10098,7 +10162,7 @@
10098
10162
  fontFamily: "var(--bw-font-family)",
10099
10163
  display: "block",
10100
10164
  marginBottom: "8px",
10101
- }, children: "Kommentar (optional)" }), u$2("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: "Zus\u00E4tzliche Anmerkungen zu Ihrer Buchung...", rows: 3, style: {
10165
+ }, children: "Kommentar (optional)" }), u$2("textarea", { id: "booking-comment", ...form.register("comment"), placeholder: "Zus\u00E4tzliche Anmerkungen zur Buchung...", rows: 3, style: {
10102
10166
  width: "100%",
10103
10167
  padding: "12px",
10104
10168
  border: `1px solid var(--bw-border-color)`,
@@ -10293,6 +10357,258 @@
10293
10357
  ` })] }) }));
10294
10358
  }
10295
10359
 
10360
+ /**
10361
+ * Google Ads Conversion Tracking Utility
10362
+ *
10363
+ * This utility handles Google Ads conversion tracking for the booking widget.
10364
+ * It includes consent checking, gtag initialization, and conversion tracking.
10365
+ */
10366
+ /**
10367
+ * Check if Google Consent Mode has granted the necessary permissions for ads tracking
10368
+ * This only checks Google's official consent mode - the proper way to handle Google Ads consent
10369
+ */
10370
+ function checkGoogleConsent() {
10371
+ console.log("[Google Ads Tracking] 🔍 Checking Google consent...");
10372
+ if (typeof window === "undefined") {
10373
+ console.log("[Google Ads Tracking] ❌ Window object not available (SSR context)");
10374
+ return false;
10375
+ }
10376
+ console.log("[Google Ads Tracking] ✅ Window object available");
10377
+ // Check for gtag consent mode
10378
+ if (typeof window.gtag === "function") {
10379
+ console.log("[Google Ads Tracking] ✅ gtag function found");
10380
+ try {
10381
+ // Try to get consent state from Google's consent mode
10382
+ let consentGranted = false;
10383
+ window.gtag("get", (consentState) => {
10384
+ console.log("[Google Ads Tracking] 📋 Consent state received:", consentState);
10385
+ // For Google Ads conversion tracking, we need ad_storage consent
10386
+ consentGranted = consentState.ad_storage === "granted";
10387
+ console.log("[Google Ads Tracking] 🔐 ad_storage consent:", consentState.ad_storage);
10388
+ });
10389
+ console.log("[Google Ads Tracking] 🎯 Final consent result:", consentGranted);
10390
+ return consentGranted;
10391
+ }
10392
+ catch (error) {
10393
+ console.warn("[Google Ads Tracking] ⚠️ Error checking gtag consent:", error);
10394
+ }
10395
+ }
10396
+ else {
10397
+ console.log("[Google Ads Tracking] ❌ gtag function not found");
10398
+ }
10399
+ // If gtag is not available, we assume consent has not been properly configured
10400
+ // The host page should implement Google Consent Mode if they want tracking
10401
+ console.log("[Google Ads Tracking] 🚫 No consent mechanism found, returning false");
10402
+ return false;
10403
+ }
10404
+ /**
10405
+ * Check if gtag is already initialized on the host page
10406
+ */
10407
+ function isGtagInitialized() {
10408
+ console.log("[Google Ads Tracking] 🔍 Checking if gtag is initialized...");
10409
+ if (typeof window === "undefined") {
10410
+ console.log("[Google Ads Tracking] ❌ Window object not available (SSR context)");
10411
+ return false;
10412
+ }
10413
+ console.log("[Google Ads Tracking] ✅ Window object available");
10414
+ // Check if gtag function exists
10415
+ if (typeof window.gtag === "function") {
10416
+ console.log("[Google Ads Tracking] ✅ gtag function exists");
10417
+ return true;
10418
+ }
10419
+ console.log("[Google Ads Tracking] ❌ gtag function not found, checking for scripts...");
10420
+ // Check if Google Analytics or Google Ads scripts are already loaded
10421
+ const scripts = document.querySelectorAll('script[src*="googletagmanager.com"]');
10422
+ console.log("[Google Ads Tracking] 📜 Found", scripts.length, "Google Tag Manager scripts");
10423
+ const isInitialized = scripts.length > 0;
10424
+ console.log("[Google Ads Tracking] 🎯 gtag initialization status:", isInitialized);
10425
+ return isInitialized;
10426
+ }
10427
+ /**
10428
+ * Initialize Google Tag (gtag) if not already present
10429
+ */
10430
+ function initializeGtag(tagId) {
10431
+ console.log("[Google Ads Tracking] 🚀 Starting gtag initialization with tagId:", tagId);
10432
+ return new Promise((resolve, reject) => {
10433
+ if (typeof window === "undefined") {
10434
+ console.log("[Google Ads Tracking] ❌ Window object not available (SSR context)");
10435
+ reject(new Error("Window object not available"));
10436
+ return;
10437
+ }
10438
+ console.log("[Google Ads Tracking] ✅ Window object available");
10439
+ // If gtag is already initialized, just resolve
10440
+ if (isGtagInitialized()) {
10441
+ console.log("[Google Ads Tracking] ⚡ gtag already initialized, skipping setup");
10442
+ resolve();
10443
+ return;
10444
+ }
10445
+ console.log("[Google Ads Tracking] 📦 gtag not found, creating new script element...");
10446
+ try {
10447
+ // Create the gtag script
10448
+ const script = document.createElement("script");
10449
+ script.async = true;
10450
+ script.src = `https://www.googletagmanager.com/gtag/js?id=${tagId}`;
10451
+ console.log("[Google Ads Tracking] 🌐 Script src set to:", script.src);
10452
+ script.onload = () => {
10453
+ console.log("[Google Ads Tracking] 📥 Script loaded successfully, initializing gtag...");
10454
+ // Initialize gtag
10455
+ window.dataLayer = window.dataLayer || [];
10456
+ console.log("[Google Ads Tracking] 📊 dataLayer initialized");
10457
+ window.gtag = (...args) => {
10458
+ window.dataLayer.push(args);
10459
+ };
10460
+ console.log("[Google Ads Tracking] 🔧 gtag function created");
10461
+ // Configure gtag
10462
+ console.log("[Google Ads Tracking] ⚙️ Configuring gtag with privacy settings...");
10463
+ window.gtag("js", new Date());
10464
+ window.gtag("config", tagId, {
10465
+ // Respect consent settings
10466
+ anonymize_ip: true,
10467
+ allow_google_signals: false,
10468
+ allow_ad_personalization_signals: false,
10469
+ });
10470
+ console.log("[Google Ads Tracking] ✅ gtag initialized successfully with tagId:", tagId);
10471
+ resolve();
10472
+ };
10473
+ script.onerror = (error) => {
10474
+ console.error("[Google Ads Tracking] ❌ Failed to load Google Tag script:", error);
10475
+ reject(new Error("Failed to load Google Tag script"));
10476
+ };
10477
+ console.log("[Google Ads Tracking] 📑 Adding script to document head...");
10478
+ // Add script to head
10479
+ document.head.appendChild(script);
10480
+ console.log("[Google Ads Tracking] ✅ Script element appended to head");
10481
+ }
10482
+ catch (error) {
10483
+ console.error("[Google Ads Tracking] ❌ Error during gtag initialization:", error);
10484
+ reject(error);
10485
+ }
10486
+ });
10487
+ }
10488
+ /**
10489
+ * Track a Google Ads conversion
10490
+ */
10491
+ function trackConversion(config) {
10492
+ console.log("[Google Ads Tracking] 🎯 Starting conversion tracking with config:", config);
10493
+ if (typeof window === "undefined") {
10494
+ console.warn("[Google Ads Tracking] ❌ Window object not available");
10495
+ return;
10496
+ }
10497
+ console.log("[Google Ads Tracking] ✅ Window object available");
10498
+ if (!config.tagId || !config.conversionId) {
10499
+ console.warn("[Google Ads Tracking] ❌ Missing tagId or conversionId", {
10500
+ tagId: config.tagId,
10501
+ conversionId: config.conversionId,
10502
+ });
10503
+ return;
10504
+ }
10505
+ console.log("[Google Ads Tracking] ✅ Required config fields present:", {
10506
+ tagId: config.tagId,
10507
+ conversionId: config.conversionId,
10508
+ });
10509
+ if (typeof window.gtag !== "function") {
10510
+ console.warn("[Google Ads Tracking] ❌ gtag function not available");
10511
+ return;
10512
+ }
10513
+ console.log("[Google Ads Tracking] ✅ gtag function is available");
10514
+ try {
10515
+ console.log("[Google Ads Tracking] 🔧 Building conversion data...");
10516
+ const conversionData = {
10517
+ send_to: `${config.tagId}/${config.conversionId}`,
10518
+ };
10519
+ console.log("[Google Ads Tracking] 📋 Base conversion data:", conversionData);
10520
+ // Add optional parameters
10521
+ if (config.conversionValue !== undefined) {
10522
+ conversionData.value = config.conversionValue;
10523
+ console.log("[Google Ads Tracking] 💰 Added conversion value:", config.conversionValue);
10524
+ }
10525
+ if (config.conversionCurrency) {
10526
+ conversionData.currency = config.conversionCurrency;
10527
+ console.log("[Google Ads Tracking] 💱 Added currency:", config.conversionCurrency);
10528
+ }
10529
+ if (config.transactionId) {
10530
+ conversionData.transaction_id = config.transactionId;
10531
+ console.log("[Google Ads Tracking] 🔖 Added transaction ID:", config.transactionId);
10532
+ }
10533
+ console.log("[Google Ads Tracking] 📦 Final conversion data:", conversionData);
10534
+ // Track the conversion
10535
+ console.log("[Google Ads Tracking] 🚀 Sending conversion event to gtag...");
10536
+ window.gtag("event", "conversion", conversionData);
10537
+ console.log("[Google Ads Tracking] ✅ Conversion tracked successfully:", conversionData);
10538
+ }
10539
+ catch (error) {
10540
+ console.error("[Google Ads Tracking] ❌ Error tracking conversion:", error);
10541
+ }
10542
+ }
10543
+ /**
10544
+ * Main function to handle Google Ads conversion tracking
10545
+ * This function checks consent, initializes gtag if needed, and tracks the conversion
10546
+ */
10547
+ async function handleGoogleAdsConversion(config) {
10548
+ console.log("[Google Ads Tracking] 🎬 Starting handleGoogleAdsConversion with config:", config);
10549
+ // Validate config
10550
+ if (!config.tagId || !config.conversionId) {
10551
+ console.log("[Google Ads Tracking] ❌ No tagId or conversionId provided, skipping conversion tracking", { tagId: config.tagId, conversionId: config.conversionId });
10552
+ return;
10553
+ }
10554
+ console.log("[Google Ads Tracking] ✅ Config validation passed");
10555
+ // Check consent first
10556
+ console.log("[Google Ads Tracking] 🔐 Checking consent...");
10557
+ if (!checkGoogleConsent()) {
10558
+ console.log("[Google Ads Tracking] 🚫 Google consent not granted, skipping conversion tracking");
10559
+ return;
10560
+ }
10561
+ console.log("[Google Ads Tracking] ✅ Consent check passed");
10562
+ try {
10563
+ // Initialize gtag if not already present
10564
+ console.log("[Google Ads Tracking] 🔍 Checking if gtag needs initialization...");
10565
+ if (!isGtagInitialized()) {
10566
+ console.log("[Google Ads Tracking] 🚀 Initializing gtag...");
10567
+ await initializeGtag(config.tagId);
10568
+ console.log("[Google Ads Tracking] ✅ gtag initialization completed");
10569
+ }
10570
+ else {
10571
+ console.log("[Google Ads Tracking] ⚡ gtag already initialized, proceeding...");
10572
+ }
10573
+ // Small delay to ensure gtag is ready
10574
+ console.log("[Google Ads Tracking] ⏱️ Adding 100ms delay to ensure gtag is ready...");
10575
+ setTimeout(() => {
10576
+ console.log("[Google Ads Tracking] 🎯 Delay completed, tracking conversion...");
10577
+ trackConversion(config);
10578
+ }, 100);
10579
+ }
10580
+ catch (error) {
10581
+ console.error("[Google Ads Tracking] ❌ Error handling conversion:", error);
10582
+ }
10583
+ }
10584
+ /**
10585
+ * Utility function to get conversion value from booking data
10586
+ */
10587
+ function getConversionValueFromBooking(bookingData) {
10588
+ console.log("[Google Ads Tracking] 💰 Extracting conversion value from booking data:", bookingData);
10589
+ // Try to get the total amount from various possible structures
10590
+ const possiblePaths = [
10591
+ { path: "order.total", value: bookingData?.order?.total },
10592
+ { path: "booking.total", value: bookingData?.booking?.total },
10593
+ { path: "total", value: bookingData?.total },
10594
+ { path: "amount", value: bookingData?.amount },
10595
+ { path: "payment.amount", value: bookingData?.payment?.amount },
10596
+ { path: "stripePaymentIntent.amount", value: bookingData?.stripePaymentIntent?.amount },
10597
+ ];
10598
+ console.log("[Google Ads Tracking] 🔍 Checking possible value paths:", possiblePaths);
10599
+ for (const { path, value } of possiblePaths) {
10600
+ console.log(`[Google Ads Tracking] 📋 Checking path '${path}':`, value);
10601
+ if (typeof value === "number" && value > 0) {
10602
+ // Convert from cents to euros
10603
+ const convertedValue = value / 100;
10604
+ console.log(`[Google Ads Tracking] ✅ Found valid value at '${path}': ${value} cents = ${convertedValue} euros`);
10605
+ return convertedValue;
10606
+ }
10607
+ }
10608
+ console.log("[Google Ads Tracking] ❌ No valid conversion value found in booking data");
10609
+ return undefined;
10610
+ }
10611
+
10296
10612
  const BookingSuccessModal = ({ isOpen, onClose, config, onError, paymentIntentId, }) => {
10297
10613
  const [bookingData, setBookingData] = d$1(null);
10298
10614
  const [eventDetails, setEventDetails] = d$1(null);
@@ -10337,6 +10653,27 @@
10337
10653
  });
10338
10654
  // Set payment status from Stripe data or order status
10339
10655
  setPaymentStatus(data.stripePaymentIntent?.status || data.order.status);
10656
+ // Trigger Google Ads conversion tracking if payment is successful
10657
+ const finalPaymentStatus = data.stripePaymentIntent?.status || data.order.status;
10658
+ if (finalPaymentStatus === "succeeded" &&
10659
+ config.googleAds?.tagId &&
10660
+ config.googleAds?.conversionId) {
10661
+ // Prepare conversion tracking data
10662
+ const conversionValue = config.googleAds.includeValue !== false
10663
+ ? getConversionValueFromBooking(data)
10664
+ : undefined;
10665
+ const transactionId = data.order.id;
10666
+ // Track the conversion
10667
+ handleGoogleAdsConversion({
10668
+ tagId: config.googleAds.tagId,
10669
+ conversionId: config.googleAds.conversionId,
10670
+ conversionValue,
10671
+ conversionCurrency: config.googleAds.conversionCurrency || "EUR",
10672
+ transactionId,
10673
+ }).catch((error) => {
10674
+ console.warn("[BookingSuccessModal] Google Ads conversion tracking failed:", error);
10675
+ });
10676
+ }
10340
10677
  }
10341
10678
  else {
10342
10679
  onError?.(data.error || "Fehler beim Abrufen der Buchungsdaten");
@@ -10726,44 +11063,42 @@
10726
11063
  // Allocation Badge Component
10727
11064
  const AllocationBadge = ({ availableSpots, maxParticipants, }) => {
10728
11065
  const badgeInfo = getAllocationBadgeInfo(availableSpots, maxParticipants);
10729
- if (!badgeInfo)
10730
- return null;
10731
11066
  return (u$2("div", { style: {
10732
- position: "absolute",
10733
- bottom: "4px",
10734
- right: "20px",
10735
- backgroundColor: badgeInfo.backgroundColor,
10736
- color: badgeInfo.textColor,
11067
+ backgroundColor: badgeInfo?.backgroundColor || "transparent",
11068
+ color: badgeInfo?.textColor || "transparent",
10737
11069
  fontSize: "11px",
10738
11070
  fontWeight: "bold",
10739
- padding: "3px 8px",
11071
+ padding: "1px 8px",
11072
+ display: "flex",
11073
+ marginRight: "auto",
11074
+ marginTop: "-24px",
11075
+ marginBottom: "5px",
10740
11076
  borderRadius: "var(--bw-border-radius-small)",
10741
11077
  fontFamily: "var(--bw-font-family)",
10742
- boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
10743
11078
  zIndex: 50,
10744
11079
  whiteSpace: "nowrap",
10745
- }, children: badgeInfo.text }));
11080
+ width: "fit-content",
11081
+ }, children: badgeInfo?.text || " - " }));
10746
11082
  };
10747
11083
  // Price Badge Component (for special prices)
10748
11084
  const SpecialPriceBadge = ({ price, yearPrices }) => {
10749
11085
  const badgeInfo = getPriceBadgeInfo(price, yearPrices);
10750
- if (!badgeInfo)
10751
- return null;
10752
11086
  return (u$2("div", { style: {
10753
- position: "absolute",
10754
- bottom: "28px",
10755
- right: "20px",
10756
- backgroundColor: badgeInfo.backgroundColor,
10757
- color: badgeInfo.textColor,
11087
+ backgroundColor: badgeInfo?.backgroundColor || "transparent",
11088
+ color: badgeInfo?.textColor || "transparent",
10758
11089
  fontSize: "11px",
10759
11090
  fontWeight: "bold",
10760
- padding: "3px 8px",
11091
+ padding: "1px 8px",
11092
+ display: "flex",
11093
+ marginLeft: "auto",
11094
+ marginTop: "-20px",
11095
+ marginBottom: "5px",
10761
11096
  borderRadius: "var(--bw-border-radius-small)",
10762
11097
  fontFamily: "var(--bw-font-family)",
10763
- boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
10764
11098
  zIndex: 50,
10765
11099
  whiteSpace: "nowrap",
10766
- }, children: badgeInfo.text }));
11100
+ width: "fit-content",
11101
+ }, children: badgeInfo?.text || " - " }));
10767
11102
  };
10768
11103
  // Price Display Component (with special price styling)
10769
11104
  const PriceDisplay = ({ price, yearPrices }) => {
@@ -10776,13 +11111,27 @@
10776
11111
  fontSize: "var(--bw-font-size-medium)",
10777
11112
  fontWeight: "600",
10778
11113
  padding: "3px 8px",
10779
- marginTop: "-3px",
10780
11114
  borderRadius: "var(--bw-border-radius-small)",
10781
11115
  fontFamily: "var(--bw-font-family)",
10782
11116
  border: displayInfo ? "none" : "1px solid var(--bw-border-color)",
10783
11117
  boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
10784
11118
  }, children: formatCurrency(price) }));
10785
11119
  };
11120
+ const spinner = (borderColor) => (u$2("div", { style: {
11121
+ width: "auto",
11122
+ height: "auto",
11123
+ fontSize: "16px",
11124
+ color: "var(--bw-text-color)",
11125
+ animation: "spin 1s linear infinite",
11126
+ display: "flex",
11127
+ justifyContent: "center",
11128
+ alignItems: "center",
11129
+ }, children: u$2("div", { style: {
11130
+ width: "16px",
11131
+ height: "16px",
11132
+ border: `3px dotted ${"var(--bw-highlight-color)"}`,
11133
+ borderRadius: "50%",
11134
+ } }) }));
10786
11135
  function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, }) {
10787
11136
  const [selectedEventInstanceId, setSelectedEventInstanceId] = d$1(null);
10788
11137
  const [openMonths, setOpenMonths] = d$1(new Set());
@@ -10859,7 +11208,6 @@
10859
11208
  .bw-accordion-trigger,
10860
11209
  .bw-event-instance-card {
10861
11210
  position: relative;
10862
- overflow: hidden;
10863
11211
  }
10864
11212
 
10865
11213
  .bw-accordion-trigger::before,
@@ -10908,14 +11256,11 @@
10908
11256
  height: 32px !important;
10909
11257
  font-size: 1rem !important;
10910
11258
  }
10911
- .bw-event-instance-title {
10912
- font-size: 1rem !important;
10913
- }
10914
11259
  .bw-event-instance-price {
10915
11260
  font-size: 1.1rem !important;
10916
11261
  }
10917
11262
  }
10918
- ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `${selectedEventType?.name} Terminauswahl`, width: "500px", children: u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
11263
+ ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `${selectedEventType?.name} Terminauswahl`, children: u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
10919
11264
  display: "flex",
10920
11265
  flexDirection: "column",
10921
11266
  gap: "20px",
@@ -11017,13 +11362,7 @@
11017
11362
  height: "20px",
11018
11363
  backgroundColor: "var(--bw-border-color)",
11019
11364
  borderRadius: "8px",
11020
- } })] }), eventIdx === 0 && (u$2("div", { style: {
11021
- width: "90%",
11022
- height: "12px",
11023
- backgroundColor: "var(--bw-border-color)",
11024
- borderRadius: "4px",
11025
- marginTop: "8px",
11026
- } }))] }, eventIdx))) })] }, idx))) }) }) })] }));
11365
+ } })] })] }, eventIdx))) })] }, idx))) }) }) })] }));
11027
11366
  }
11028
11367
  // Show empty state only if not loading and no event instances
11029
11368
  if (eventInstances.length === 0) {
@@ -11032,7 +11371,6 @@
11032
11371
  .bw-accordion-trigger,
11033
11372
  .bw-event-instance-card {
11034
11373
  position: relative;
11035
- overflow: hidden;
11036
11374
  }
11037
11375
 
11038
11376
  .bw-accordion-trigger::before,
@@ -11081,9 +11419,6 @@
11081
11419
  height: 32px !important;
11082
11420
  font-size: 1rem !important;
11083
11421
  }
11084
- .bw-event-instance-title {
11085
- font-size: 1rem !important;
11086
- }
11087
11422
  .bw-event-instance-price {
11088
11423
  font-size: 1.1rem !important;
11089
11424
  }
@@ -11114,7 +11449,6 @@
11114
11449
  .bw-accordion-trigger,
11115
11450
  .bw-event-instance-card {
11116
11451
  position: relative;
11117
- overflow: hidden;
11118
11452
  }
11119
11453
 
11120
11454
  .bw-accordion-trigger::before,
@@ -11163,14 +11497,11 @@
11163
11497
  height: 32px !important;
11164
11498
  font-size: 1rem !important;
11165
11499
  }
11166
- .bw-event-instance-title {
11167
- font-size: 1rem !important;
11168
- }
11169
11500
  .bw-event-instance-price {
11170
11501
  font-size: 1.1rem !important;
11171
11502
  }
11172
11503
  }
11173
- ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `Terminauswahl - ${selectedEventType?.name || "Event"}`, width: "500px", children: u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
11504
+ ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `Terminauswahl - ${selectedEventType?.name || "Event"}`, children: u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
11174
11505
  display: "flex",
11175
11506
  flexDirection: "column",
11176
11507
  gap: "20px",
@@ -11245,7 +11576,7 @@
11245
11576
  color: "var(--bw-highlight-color-muted, rgba(59, 130, 246, 0.8))",
11246
11577
  animation: "spin 1s linear infinite",
11247
11578
  fontSize: "32px",
11248
- }, children: "\u27F3" }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants }), u$2("div", { style: {
11579
+ }, children: spinner() }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants }), u$2("div", { style: {
11249
11580
  display: "flex",
11250
11581
  justifyContent: "space-between",
11251
11582
  width: "100%",
@@ -11274,12 +11605,21 @@
11274
11605
  alignItems: "start",
11275
11606
  justifyContent: "start",
11276
11607
  lineHeight: "1.2",
11277
- }, children: [u$2("span", { className: "bw-event-instance-title", style: { fontWeight: "600", marginBottom: "2px" }, children: formatWeekday(event.startTime) }), u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.startTime) })] })] }), u$2("div", { className: "bw-event-instance-price", style: {
11608
+ }, children: [u$2("div", { children: [u$2("span", { className: "bw-event-instance-title", style: { fontWeight: "600", marginBottom: "2px" }, children: formatWeekday(event.startTime) }), formatWeekday(event.startTime) !==
11609
+ formatWeekday(event.endTime) && (u$2(k$3, { children: [u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), u$2("span", { className: "bw-event-instance-title", style: { fontWeight: "600", marginBottom: "2px" }, children: formatWeekday(event.endTime) })] }))] }), u$2("div", { children: formatWeekday(event.startTime) ===
11610
+ formatWeekday(event.endTime) ? (u$2(k$3, { children: [u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.startTime) }), u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: " - " }), u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: formatTime(event.endTime) })] })) : (u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: [formatTime(event.startTime), " Uhr"] })) })] }), u$2("span", { style: {
11611
+ fontSize: "12px",
11612
+ fontWeight: 400,
11613
+ color: "var(--bw-text-muted)",
11614
+ marginLeft: "6px",
11615
+ background: "var(--bw-background-muted)",
11616
+ whiteSpace: "nowrap",
11617
+ }, children: [event.durationDays, " Tag", event.durationDays > 1 ? "e" : ""] })] }), u$2("div", { className: "bw-event-instance-price", style: {
11278
11618
  textAlign: "right",
11279
11619
  display: "flex",
11280
11620
  flexDirection: "column",
11281
11621
  alignItems: "end",
11282
- }, children: u$2(PriceDisplay, { price: event.price, yearPrices: yearPrices }) })] }), u$2("h4", { className: "bw-event-instance-title", style: {
11622
+ }, children: u$2(PriceDisplay, { price: event.price, yearPrices: yearPrices }) })] }), event.name !== selectedEventType?.name && (u$2("h4", { className: "bw-event-instance-title", style: {
11283
11623
  fontSize: "var(--bw-font-size)",
11284
11624
  fontWeight: "600",
11285
11625
  color: "var(--bw-text-color)",
@@ -11288,26 +11628,8 @@
11288
11628
  display: "flex",
11289
11629
  alignItems: "center",
11290
11630
  gap: "8px",
11291
- }, children: [event.name, u$2("span", { style: {
11292
- fontSize: "12px",
11293
- fontWeight: 400,
11294
- color: "var(--bw-text-muted)",
11295
- marginLeft: "6px",
11296
- background: "var(--bw-background-muted)",
11297
- borderRadius: "8px",
11298
- padding: "2px 8px",
11299
- whiteSpace: "nowrap",
11300
- }, children: [event.durationDays, " Tag", event.durationDays > 1 ? "e" : ""] })] }), event.notes && (u$2("p", { style: {
11301
- fontSize: "12px",
11302
- color: "var(--bw-text-muted)",
11303
- marginTop: "8px",
11304
- display: "-webkit-box",
11305
- WebkitBoxOrient: "vertical",
11306
- WebkitLineClamp: 2,
11307
- overflow: "hidden",
11308
- margin: "0",
11309
- lineHeight: "1.3",
11310
- }, children: event.notes }))] }, event.id));
11631
+ maxWidth: "230px",
11632
+ }, children: event.name }))] }, event.id));
11311
11633
  }) }) }, month));
11312
11634
  }) }) }) })] }));
11313
11635
  }
@@ -11948,7 +12270,6 @@
11948
12270
  body: JSON.stringify(requestBody),
11949
12271
  });
11950
12272
  const data = await response.json();
11951
- console.log("Event details response:", { status: response.status, data }); // Debug log
11952
12273
  if (response.ok) {
11953
12274
  setEventDetails(data.eventDetails);
11954
12275
  // Store system configuration for PaymentForm