@bigz-app/booking-widget 0.1.21 → 0.1.23

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
@@ -6984,17 +6984,18 @@ function EventTypeDetailsDialog({ isOpen, onClose, eventType, onEventTypeSelect,
6984
6984
  backgroundColor: "var(--bw-background-color)",
6985
6985
  borderRadius: "var(--bw-border-radius)",
6986
6986
  border: `1px solid var(--bw-border-color)`,
6987
- }, children: [jsxs("div", { children: [jsx("div", { style: {
6988
- fontSize: "14px",
6989
- color: "var(--bw-text-muted)",
6987
+ }, children: [jsxs("div", { children: [jsx("div", { className: "bw-event-type-price", style: {
6988
+ fontWeight: "700",
6989
+ color: "var(--bw-text-color)",
6990
6990
  fontFamily: "var(--bw-font-family)",
6991
- marginBottom: "4px",
6992
- }, children: "Preis ab" }), jsx("div", { style: {
6993
- fontSize: "32px",
6991
+ textAlign: "left",
6992
+ }, children: eventType.groupedDurations && jsx("span", { children: eventType.groupedDurations }) }), jsx("div", { className: "bw-event-type-price", style: {
6993
+ fontSize: "clamp(1.72rem, 4vw, 32px)",
6994
6994
  fontWeight: "700",
6995
6995
  color: "var(--bw-text-color)",
6996
6996
  fontFamily: "var(--bw-font-family)",
6997
- }, children: formatCurrency(eventType.basePrice) })] }), isAvailable && (jsxs("button", { onClick: handleBookingClick, style: {
6997
+ textAlign: "right",
6998
+ }, children: jsxs("span", { children: ["ab ", formatCurrency(eventType.minPrice)] }) })] }), isAvailable && (jsxs("button", { onClick: handleBookingClick, style: {
6998
6999
  backgroundColor: "var(--bw-highlight-color)",
6999
7000
  color: "white",
7000
7001
  padding: "14px 28px",
@@ -7569,10 +7570,10 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, isLoading = false,
7569
7570
  e.currentTarget.style.color = "var(--bw-highlight-color)";
7570
7571
  e.currentTarget.style.transform = "translateY(0)";
7571
7572
  }, children: [jsx("span", { style: { fontSize: "16px" }, children: "\uD83D\uDD04" }), "Seite neu laden"] })] }) })) : (jsx("div", { className: "bw-event-type-list", style: { padding: "0px 0px" }, children: jsx("div", { style: {
7572
- display: "flex",
7573
- flexWrap: "wrap",
7574
- justifyContent: "center",
7573
+ display: "grid",
7574
+ gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))",
7575
7575
  gap: "24px",
7576
+ gridAutoRows: "1fr",
7576
7577
  }, children: eventTypes.map((eventType) => {
7577
7578
  const isAvailable = eventType.hasAvailableInstances;
7578
7579
  return (jsxs("div", { className: "bw-event-type-card", style: {
@@ -7580,16 +7581,11 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, isLoading = false,
7580
7581
  backgroundColor: "var(--bw-surface-color)",
7581
7582
  border: `1px solid var(--bw-border-color)`,
7582
7583
  borderRadius: "var(--bw-border-radius)",
7583
- overflow: "hidden",
7584
7584
  transition: "all 0.3s ease",
7585
7585
  cursor: isAvailable ? "pointer" : "not-allowed",
7586
7586
  opacity: isAvailable ? 1 : 0.6,
7587
7587
  boxShadow: "var(--bw-shadow-md)",
7588
7588
  fontFamily: "var(--bw-font-family)",
7589
- maxWidth: "500px",
7590
- flex: "1 1 350px",
7591
- display: "flex",
7592
- flexDirection: "column",
7593
7589
  }, onClick: () => isAvailable && onEventTypeSelect(eventType), onMouseEnter: (e) => {
7594
7590
  if (isAvailable) {
7595
7591
  e.currentTarget.style.boxShadow = "var(--bw-shadow-lg)";
@@ -7616,7 +7612,12 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, isLoading = false,
7616
7612
  padding: "3px 8px",
7617
7613
  borderRadius: "var(--bw-border-radius)",
7618
7614
  fontFamily: "var(--bw-font-family)",
7619
- }, children: eventType.category.name }) }), jsx("div", { className: "bw-event-type-img", style: { position: "relative", width: "100%", height: "300px" }, children: jsx(ImageCarousel, { images: eventType.images, eventName: eventType.name }) }), jsxs("div", { className: "bw-event-type-content", style: { padding: "12px 18px" }, children: [jsx("h2", { className: "bw-event-type-title", style: {
7615
+ }, children: eventType.category.name }) }), jsx("div", { className: "bw-event-type-img", style: { position: "relative", width: "100%", height: "300px" }, children: jsx(ImageCarousel, { images: eventType.images, eventName: eventType.name }) }), jsxs("div", { className: "bw-event-type-content", style: {
7616
+ padding: "12px 18px",
7617
+ display: "flex",
7618
+ flexDirection: "column",
7619
+ justifyContent: "space-between",
7620
+ }, children: [jsx("h2", { className: "bw-event-type-title", style: {
7620
7621
  fontSize: "clamp(1.1rem, 2.5vw, 24px)",
7621
7622
  fontWeight: "700",
7622
7623
  color: "var(--bw-text-color)",
@@ -7669,9 +7670,7 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, isLoading = false,
7669
7670
  overflow: "hidden",
7670
7671
  whiteSpace: "nowrap",
7671
7672
  flex: "1",
7672
- }, children: highlight.trim() })] }, index))) }) })) : (
7673
- // Fallback to description with React Markdown
7674
- eventType.description && (jsx("div", { className: "bw-event-type-desc", style: {
7673
+ }, children: highlight.trim() })] }, index))) }) })) : eventType.description ? (jsx("div", { className: "bw-event-type-desc", style: {
7675
7674
  color: "var(--bw-text-muted)",
7676
7675
  fontSize: "clamp(0.95rem, 2vw, 16px)",
7677
7676
  lineHeight: "1.6",
@@ -7688,13 +7687,30 @@ function EventTypeSelection({ eventTypes, onEventTypeSelect, isLoading = false,
7688
7687
  overflow: "hidden",
7689
7688
  }, children: Markdown({
7690
7689
  children: preprocessMarkdown(eventType.description),
7691
- }) }) }))) }), jsxs("div", { children: [jsx("div", { className: "bw-event-type-price", style: {
7690
+ }) }) })) : (jsx("div", { className: "bw-event-type-desc", style: {
7691
+ color: "var(--bw-text-muted)",
7692
+ fontSize: "clamp(0.95rem, 2vw, 16px)",
7693
+ lineHeight: "1.6",
7694
+ fontFamily: "var(--bw-font-family)",
7695
+ margin: "10px 0 10px 0",
7696
+ minHeight: "128px",
7697
+ maxHeight: "128px",
7698
+ overflow: "hidden",
7699
+ textAlign: "left",
7700
+ }, children: "\u00A0" })) }), jsxs("div", { children: [jsx("div", { className: "bw-event-type-price", style: {
7701
+ fontWeight: "700",
7702
+ color: "var(--bw-text-color)",
7703
+ fontFamily: "var(--bw-font-family)",
7704
+ textAlign: "right",
7705
+ }, children: eventType.groupedDurations.length > 1 ? (jsx("span", { children: eventType.groupedDurations })) : (jsx("span", { children: eventType.cheapestDurationPerDay % 60 === 0
7706
+ ? `${eventType.cheapestDurationPerDay / 60} Stunde${eventType.cheapestDurationPerDay / 60 > 1 ? "n" : ""}`
7707
+ : `${eventType.cheapestDurationPerDay} Minuten` })) }), jsx("div", { className: "bw-event-type-price", style: {
7692
7708
  fontSize: "clamp(1.72rem, 4vw, 32px)",
7693
7709
  fontWeight: "700",
7694
7710
  color: "var(--bw-text-color)",
7695
7711
  fontFamily: "var(--bw-font-family)",
7696
7712
  textAlign: "right",
7697
- }, children: formatCurrency(eventType.basePrice) }), " "] }), jsxs("div", { style: {
7713
+ }, children: jsxs("span", { children: ["ab ", formatCurrency(eventType.minPrice)] }) })] }), jsxs("div", { style: {
7698
7714
  display: "flex",
7699
7715
  justifyContent: "flex-end",
7700
7716
  alignItems: "center",
@@ -9094,14 +9110,39 @@ function PaymentFormInner({ config, eventDetails, formData, totalAmount, discoun
9094
9110
  return;
9095
9111
  }
9096
9112
  // First, confirm the payment with Stripe
9113
+ const confirmParams = {
9114
+ return_url: "https://bigz.surfschule-zingst.de/booking/success",
9115
+ };
9116
+ // Ensure return_url is properly formatted and doesn't contain fragment identifiers
9117
+ try {
9118
+ const url = new URL(confirmParams.return_url);
9119
+ // Remove any fragment identifiers that might cause issues
9120
+ url.hash = "";
9121
+ confirmParams.return_url = url.toString();
9122
+ }
9123
+ catch (e) {
9124
+ console.warn("[PAYMENT_FORM] Invalid return_url, using fallback:", confirmParams.return_url);
9125
+ // Fallback to current origin if URL parsing fails
9126
+ confirmParams.return_url = window.location.origin + window.location.pathname;
9127
+ }
9128
+ console.log("[PAYMENT_FORM] Confirming payment with params:", {
9129
+ paymentIntentId: clientSecret.split("_secret_")[0],
9130
+ return_url: confirmParams.return_url,
9131
+ redirect: "if_required",
9132
+ });
9097
9133
  const { error, paymentIntent } = await stripe.confirmPayment({
9098
9134
  elements,
9099
- confirmParams: {
9100
- return_url: window.location.href,
9101
- },
9135
+ confirmParams,
9102
9136
  redirect: "if_required",
9103
9137
  });
9104
9138
  if (error) {
9139
+ console.error("[PAYMENT_FORM] Payment confirmation error:", {
9140
+ type: error.type,
9141
+ code: error.code,
9142
+ message: error.message,
9143
+ decline_code: error.decline_code,
9144
+ payment_intent: error.payment_intent,
9145
+ });
9105
9146
  if (error.type === "card_error" || error.type === "validation_error") {
9106
9147
  setPaymentError(error.message || "Zahlungsfehler");
9107
9148
  }
@@ -9298,16 +9339,41 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
9298
9339
  const endpoint = isConnectMode
9299
9340
  ? "/booking/create-payment-intent"
9300
9341
  : "/booking-proxy/create-payment-intent";
9301
- // Build request data
9342
+ // Build request data with validation
9302
9343
  const requestData = {
9303
9344
  eventInstanceId: config.eventInstanceId || eventDetails.id,
9304
9345
  organizationId: config.organizationId, // Required for payment intent creation
9305
- amount: totalAmount,
9346
+ amount: Math.round(totalAmount), // Ensure integer (should already be in cents)
9306
9347
  currency: "eur",
9307
- participants: formData.participants.filter((p) => p.name.trim()),
9348
+ participants: formData.participants.filter((p) => p.name?.trim()),
9308
9349
  discountCode: discountCode?.code,
9309
- customerEmail: formData.customerEmail,
9350
+ customerEmail: formData.customerEmail?.trim(),
9310
9351
  };
9352
+ // Validate required fields
9353
+ if (!requestData.eventInstanceId) {
9354
+ throw new Error("Event instance ID is required");
9355
+ }
9356
+ if (!requestData.organizationId) {
9357
+ throw new Error("Organization ID is required");
9358
+ }
9359
+ if (!requestData.amount || requestData.amount <= 0) {
9360
+ throw new Error("Valid amount is required");
9361
+ }
9362
+ if (!requestData.participants || requestData.participants.length === 0) {
9363
+ throw new Error("At least one participant is required");
9364
+ }
9365
+ if (!requestData.customerEmail) {
9366
+ throw new Error("Customer email is required");
9367
+ }
9368
+ console.log("[PAYMENT_FORM] Creating payment intent:", {
9369
+ endpoint,
9370
+ mode: isConnectMode ? "connect" : "apikey",
9371
+ amount: requestData.amount,
9372
+ currency: requestData.currency,
9373
+ participantCount: requestData.participants.length,
9374
+ organizationId: requestData.organizationId,
9375
+ eventInstanceId: requestData.eventInstanceId,
9376
+ });
9311
9377
  // Add mode-specific fields
9312
9378
  if (!isConnectMode) {
9313
9379
  // ApiKey mode needs additional fields
@@ -9323,14 +9389,25 @@ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode
9323
9389
  });
9324
9390
  const data = await response.json();
9325
9391
  if (response.ok) {
9392
+ console.log("[PAYMENT_FORM] Payment intent created successfully:", {
9393
+ hasClientSecret: !!data.clientSecret,
9394
+ clientSecretPrefix: `${data.clientSecret?.substring(0, 20)}...`,
9395
+ });
9326
9396
  setClientSecret(data.clientSecret);
9327
9397
  }
9328
9398
  else {
9399
+ console.error("[PAYMENT_FORM] Payment intent creation failed:", {
9400
+ status: response.status,
9401
+ error: data.error,
9402
+ details: data.details,
9403
+ requestData: { ...requestData, customerEmail: "[redacted]" },
9404
+ });
9329
9405
  setPaymentError(data.error || "Fehler beim Erstellen der Zahlungsabsicht");
9330
9406
  }
9331
9407
  }
9332
9408
  catch (err) {
9333
- setPaymentError("Fehler beim Erstellen der Zahlungsabsicht");
9409
+ console.error("[PAYMENT_FORM] Payment intent creation error:", err);
9410
+ setPaymentError(err.message || "Fehler beim Erstellen der Zahlungsabsicht");
9334
9411
  }
9335
9412
  finally {
9336
9413
  setIsCreatingPaymentIntent(false);
@@ -11593,6 +11670,25 @@ function UniversalBookingWidget({ config: baseConfig }) {
11593
11670
  if (data.connectedAccountId) {
11594
11671
  stripeOptions.stripeAccount = data.connectedAccountId;
11595
11672
  }
11673
+ // Add options to prevent sandbox warnings in vanilla JS environments
11674
+ if (typeof window !== "undefined" && window.document) {
11675
+ // Check if we're in a potential iframe or restricted environment
11676
+ try {
11677
+ // Test if we can access parent window (this will throw in sandbox)
11678
+ const hasParentAccess = window.parent === window || window.parent.location.href;
11679
+ // Add apiVersion to ensure compatibility
11680
+ stripeOptions.apiVersion = "2025-02-24.acacia";
11681
+ // For vanilla JS builds, explicitly set betas to empty array to avoid issues
11682
+ if (!stripeOptions.betas) {
11683
+ stripeOptions.betas = [];
11684
+ }
11685
+ }
11686
+ catch (e) {
11687
+ // We're likely in a sandboxed environment, add specific options
11688
+ console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
11689
+ stripeOptions.betas = [];
11690
+ }
11691
+ }
11596
11692
  setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
11597
11693
  }
11598
11694
  // If only one instance, skip to booking
@@ -11634,6 +11730,25 @@ function UniversalBookingWidget({ config: baseConfig }) {
11634
11730
  if (data.connectedAccountId) {
11635
11731
  stripeOptions.stripeAccount = data.connectedAccountId;
11636
11732
  }
11733
+ // Add options to prevent sandbox warnings in vanilla JS environments
11734
+ if (typeof window !== "undefined" && window.document) {
11735
+ // Check if we're in a potential iframe or restricted environment
11736
+ try {
11737
+ // Test if we can access parent window (this will throw in sandbox)
11738
+ const hasParentAccess = window.parent === window || window.parent.location.href;
11739
+ // Add apiVersion to ensure compatibility
11740
+ stripeOptions.apiVersion = "2025-02-24.acacia";
11741
+ // For vanilla JS builds, explicitly set betas to empty array to avoid issues
11742
+ if (!stripeOptions.betas) {
11743
+ stripeOptions.betas = [];
11744
+ }
11745
+ }
11746
+ catch (e) {
11747
+ // We're likely in a sandboxed environment, add specific options
11748
+ console.warn("[WIDGET] Detected restricted environment, adjusting Stripe options");
11749
+ stripeOptions.betas = [];
11750
+ }
11751
+ }
11637
11752
  setStripePromise(loadStripe(data.stripePublishableKey, stripeOptions));
11638
11753
  }
11639
11754
  }