@bigz-app/booking-widget 0.3.6 → 0.3.9

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.
@@ -6946,7 +6946,7 @@
6946
6946
  // Convert double underscores to HTML underline tags for React Markdown
6947
6947
  return markdown.replace(/__([^_]+)__/g, "<u>$1</u>");
6948
6948
  };
6949
- const IconCheck$1 = ({ size = 16, color = "#10b981" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: u$2("polyline", { points: "20 6 9 17 4 12" }) }));
6949
+ const IconCheck$2 = ({ size = 16, color = "#10b981" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: u$2("polyline", { points: "20 6 9 17 4 12" }) }));
6950
6950
  const IconWave$1 = ({ size = 20, color = "#0ea5e9" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("path", { d: "M2 18c2-2 6-2 8 0s6 2 8 0 6-2 8 0" }), u$2("path", { d: "M2 12c2-2 6-2 8 0s6 2 8 0 6-2 8 0" }), u$2("path", { d: "M2 6c2-2 6-2 8 0s6 2 8 0 6-2 8 0" })] }));
6951
6951
  function EventTypeDetailsDialog({ isOpen, onClose, eventType, onEventTypeSelect, }) {
6952
6952
  if (!isOpen || !eventType)
@@ -6993,7 +6993,7 @@
6993
6993
  fontSize: "16px",
6994
6994
  lineHeight: "1.6",
6995
6995
  color: "var(--bw-text-color)",
6996
- }, children: [u$2("div", { style: { marginTop: "4px", flexShrink: 0 }, children: u$2(IconCheck$1, { size: 16, color: "var(--bw-success-color)" }) }), u$2("span", { children: highlight.trim() })] }, index))) }) }) }))] }), eventType.description && (u$2("div", { style: {
6996
+ }, children: [u$2("div", { style: { marginTop: "4px", flexShrink: 0 }, children: u$2(IconCheck$2, { size: 16, color: "var(--bw-success-color)" }) }), u$2("span", { children: highlight.trim() })] }, index))) }) }) }))] }), eventType.description && (u$2("div", { style: {
6997
6997
  marginBottom: "24px",
6998
6998
  color: "var(--bw-text-muted)",
6999
6999
  fontSize: "16px",
@@ -7302,7 +7302,7 @@
7302
7302
  // Custom minimal SVG icons (Lucide-style)
7303
7303
  const IconClock = ({ size = 16, color = "#10b981" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("circle", { cx: "12", cy: "12", r: "10" }), u$2("polyline", { points: "12 6 12 12 16 14" })] }));
7304
7304
  const IconCalendar = ({ size = 16, color = "#3b82f6" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }), u$2("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), u$2("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), u$2("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
7305
- const IconCheck = ({ size = 16, color = "#10b981" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: u$2("polyline", { points: "20 6 9 17 4 12" }) }));
7305
+ const IconCheck$1 = ({ size = 16, color = "#10b981" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: u$2("polyline", { points: "20 6 9 17 4 12" }) }));
7306
7306
  // Wave icon for booking action
7307
7307
  const IconWave = ({ size = 20, color = "#0ea5e9" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("path", { d: "M2 18c2-2 6-2 8 0s6 2 8 0 6-2 8 0" }), u$2("path", { d: "M2 12c2-2 6-2 8 0s6 2 8 0 6-2 8 0" }), u$2("path", { d: "M2 6c2-2 6-2 8 0s6 2 8 0 6-2 8 0" })] }));
7308
7308
  // Loading skeleton component that matches the actual design
@@ -7766,7 +7766,7 @@
7766
7766
  color: "var(--bw-text-muted)",
7767
7767
  position: "relative",
7768
7768
  maxWidth: "100%",
7769
- }, children: [u$2("div", { style: { marginTop: "4px", flexShrink: 0 }, children: u$2(IconCheck, { size: 16, color: "var(--bw-success-color)" }) }), u$2("span", { style: {
7769
+ }, children: [u$2("div", { style: { marginTop: "4px", flexShrink: 0 }, children: u$2(IconCheck$1, { size: 16, color: "var(--bw-success-color)" }) }), u$2("span", { style: {
7770
7770
  textOverflow: "ellipsis",
7771
7771
  overflow: "hidden",
7772
7772
  whiteSpace: "nowrap",
@@ -9196,6 +9196,110 @@
9196
9196
 
9197
9197
  var reactStripe_umdExports = reactStripe_umd.exports;
9198
9198
 
9199
+ // Component for bookings fully covered by gift cards (no Stripe payment needed)
9200
+ function GiftCardOnlyBooking({ config, eventDetails, formData, discountCode, giftCards, onSuccess, onError, }) {
9201
+ const [isLoading, setIsLoading] = d$1(false);
9202
+ const [error, setError] = d$1(null);
9203
+ const handleBooking = async () => {
9204
+ setIsLoading(true);
9205
+ setError(null);
9206
+ try {
9207
+ // Create booking directly without Stripe payment
9208
+ const requestData = {
9209
+ eventInstanceId: config.eventInstanceId || eventDetails.id,
9210
+ organizationId: config.organizationId,
9211
+ participants: formData.participants.filter((p) => p.name?.trim()),
9212
+ discountCode: discountCode?.code,
9213
+ giftCardCodes: giftCards.map((gc) => gc.code),
9214
+ customerName: formData.customerName?.trim(),
9215
+ customerEmail: formData.customerEmail?.trim(),
9216
+ customerPhone: formData.customerPhone?.trim(),
9217
+ comment: formData.comment?.trim(),
9218
+ paymentMethod: "gift_card",
9219
+ };
9220
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/create-gift-card-booking"), {
9221
+ method: "POST",
9222
+ headers: createApiHeaders(config),
9223
+ body: JSON.stringify(createRequestBody(config, requestData)),
9224
+ });
9225
+ const data = await response.json();
9226
+ if (response.ok) {
9227
+ onSuccess({
9228
+ booking: data.booking,
9229
+ order: data.order,
9230
+ giftCardRedemptions: data.giftCardRedemptions,
9231
+ });
9232
+ }
9233
+ else {
9234
+ setError(data.error || "Fehler beim Erstellen der Buchung");
9235
+ onError(data.error || "Fehler beim Erstellen der Buchung");
9236
+ }
9237
+ }
9238
+ catch (err) {
9239
+ setError(err.message || "Fehler beim Erstellen der Buchung");
9240
+ onError(err.message || "Fehler beim Erstellen der Buchung");
9241
+ }
9242
+ finally {
9243
+ setIsLoading(false);
9244
+ }
9245
+ };
9246
+ const totalGiftCardAmount = giftCards.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0);
9247
+ return (u$2("div", { style: { display: "flex", flexDirection: "column", gap: "var(--bw-spacing)" }, children: [u$2("div", { style: {
9248
+ backgroundColor: "var(--bw-success-color)15",
9249
+ border: "1px solid var(--bw-success-color)40",
9250
+ borderRadius: "var(--bw-border-radius)",
9251
+ padding: "var(--bw-spacing)",
9252
+ }, children: [u$2("div", { style: {
9253
+ display: "flex",
9254
+ alignItems: "center",
9255
+ gap: "8px",
9256
+ marginBottom: "8px",
9257
+ color: "var(--bw-success-color)",
9258
+ fontFamily: "var(--bw-font-family)",
9259
+ fontWeight: "600",
9260
+ }, children: "\uD83C\uDF81 Vollst\u00E4ndig durch Gutschein(e) gedeckt" }), u$2("div", { style: {
9261
+ fontSize: "var(--bw-font-size)",
9262
+ color: "var(--bw-text-muted)",
9263
+ fontFamily: "var(--bw-font-family)",
9264
+ }, children: ["Gutschein-Guthaben: ", formatCurrency(totalGiftCardAmount)] })] }), error && (u$2("div", { style: {
9265
+ backgroundColor: "var(--bw-error-color)15",
9266
+ border: "1px solid var(--bw-error-color)40",
9267
+ borderRadius: "var(--bw-border-radius)",
9268
+ padding: "var(--bw-spacing)",
9269
+ color: "var(--bw-error-color)",
9270
+ fontSize: "var(--bw-font-size)",
9271
+ fontFamily: "var(--bw-font-family)",
9272
+ }, children: ["\u26A0\uFE0F ", error] })), u$2("button", { type: "button", onClick: handleBooking, disabled: isLoading, style: {
9273
+ width: "100%",
9274
+ padding: "12px 24px",
9275
+ backgroundColor: "var(--bw-highlight-color)",
9276
+ color: "#fff",
9277
+ border: "none",
9278
+ borderRadius: "var(--bw-border-radius)",
9279
+ fontSize: "var(--bw-font-size)",
9280
+ fontWeight: "600",
9281
+ cursor: isLoading ? "not-allowed" : "pointer",
9282
+ opacity: isLoading ? 0.6 : 1,
9283
+ transition: "all 0.2s ease",
9284
+ fontFamily: "var(--bw-font-family)",
9285
+ display: "flex",
9286
+ alignItems: "center",
9287
+ justifyContent: "center",
9288
+ gap: "8px",
9289
+ }, children: isLoading ? (u$2(k$3, { children: [u$2("div", { style: {
9290
+ width: "16px",
9291
+ height: "16px",
9292
+ border: "2px solid #fff",
9293
+ borderTopColor: "transparent",
9294
+ borderRadius: "50%",
9295
+ animation: "spin 1s linear infinite",
9296
+ } }), "Buchung wird erstellt..."] })) : ("Mit Gutschein buchen") }), u$2("style", { children: `
9297
+ @keyframes spin {
9298
+ from { transform: rotate(0deg); }
9299
+ to { transform: rotate(360deg); }
9300
+ }
9301
+ ` })] }));
9302
+ }
9199
9303
  const spinner$1 = (borderColor) => (u$2("div", { style: {
9200
9304
  width: "auto",
9201
9305
  height: "auto",
@@ -9212,7 +9316,7 @@
9212
9316
  borderRadius: "50%",
9213
9317
  } }) }));
9214
9318
  // Inner component that uses the Stripe hooks
9215
- function PaymentFormInner({ config, eventDetails, formData, totalAmount, discountCode, onSuccess, onError, }) {
9319
+ function PaymentFormInner({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, }) {
9216
9320
  const stripe = reactStripe_umdExports.useStripe();
9217
9321
  const elements = reactStripe_umdExports.useElements();
9218
9322
  const [isLoading, setIsLoading] = d$1(false);
@@ -9343,7 +9447,7 @@
9343
9447
  ` })] }));
9344
9448
  }
9345
9449
  // Main PaymentForm component that handles payment intent creation and Elements wrapper
9346
- function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, }) {
9450
+ function PaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripePromise, stripeAppearance, }) {
9347
9451
  const [clientSecret, setClientSecret] = d$1(null);
9348
9452
  const [paymentIntentId, setPaymentIntentId] = d$1(null);
9349
9453
  const [isCreatingPaymentIntent, setIsCreatingPaymentIntent] = d$1(false);
@@ -9439,6 +9543,7 @@
9439
9543
  currency: "eur",
9440
9544
  participants: formData.participants.filter((p) => p.name?.trim()),
9441
9545
  discountCode: discountCode?.code,
9546
+ giftCardCodes: giftCards?.map((gc) => gc.code) || [],
9442
9547
  customerName: formData.customerName?.trim(),
9443
9548
  customerEmail: formData.customerEmail?.trim(),
9444
9549
  customerPhone: formData.customerPhone?.trim(),
@@ -9500,8 +9605,21 @@
9500
9605
  formData.customerName,
9501
9606
  totalAmount,
9502
9607
  discountCode,
9608
+ giftCards,
9503
9609
  config,
9504
9610
  ]);
9611
+ // Calculate total gift card coverage
9612
+ const totalGiftCardAmount = giftCards?.reduce((sum, gc) => sum + (gc.balanceToUse || gc.discountAmount || 0), 0) || 0;
9613
+ const baseTotal = eventDetails?.price
9614
+ ? eventDetails.price * (formData.participants?.filter((p) => p.name?.trim()).length || 0)
9615
+ : 0;
9616
+ const discountAmount = discountCode?.discountAmount || 0;
9617
+ const amountAfterDiscount = Math.max(0, baseTotal - discountAmount);
9618
+ const isFullyCoveredByGiftCards = totalGiftCardAmount >= amountAfterDiscount && amountAfterDiscount > 0;
9619
+ // If gift cards fully cover the payment, show a simplified booking button
9620
+ if (isFullyCoveredByGiftCards && totalAmount <= 0) {
9621
+ return (u$2(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards || [], onSuccess: onSuccess, onError: onError }));
9622
+ }
9505
9623
  // Show loading state while creating payment intent
9506
9624
  if (isCreatingPaymentIntent || !clientSecret) {
9507
9625
  return (u$2("div", { style: {
@@ -9535,7 +9653,7 @@
9535
9653
  clientSecret,
9536
9654
  appearance: stripeAppearance || { theme: "stripe" },
9537
9655
  locale: config.locale || "de",
9538
- }, children: u$2(PaymentFormInner, { config: config, eventDetails: eventDetails, formData: formData, totalAmount: totalAmount, discountCode: discountCode, onSuccess: (result) => {
9656
+ }, children: u$2(PaymentFormInner, { config: config, eventDetails: eventDetails, formData: formData, totalAmount: totalAmount, discountCode: discountCode, giftCards: giftCards, onSuccess: (result) => {
9539
9657
  // Clear persisted PI data on successful payment
9540
9658
  clearPersistedPaymentIntent();
9541
9659
  setPaymentIntentId(null);
@@ -9740,6 +9858,222 @@
9740
9858
  }, children: children }))] }));
9741
9859
  }
9742
9860
 
9861
+ // Icons
9862
+ const IconTicket = ({ size = 20, color = "currentColor" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("path", { d: "M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z" }), u$2("path", { d: "M13 5v2" }), u$2("path", { d: "M13 17v2" }), u$2("path", { d: "M13 11v2" })] }));
9863
+ const IconGift = ({ size = 20, color = "currentColor" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("rect", { x: "3", y: "8", width: "18", height: "4", rx: "1" }), u$2("path", { d: "M12 8v13" }), u$2("path", { d: "M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7" }), u$2("path", { d: "M7.5 8a2.5 2.5 0 0 1 0-5A4.8 8 0 0 1 12 8a4.8 8 0 0 1 4.5-5 2.5 2.5 0 0 1 0 5" })] }));
9864
+ const IconCheck = ({ size = 16, color = "currentColor" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: u$2("polyline", { points: "20 6 9 17 4 12" }) }));
9865
+ const IconX = ({ size = 16, color = "currentColor" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), u$2("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
9866
+ const IconSpinner = ({ size = 16, color = "currentColor" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "spin 1s linear infinite" }, children: u$2("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }));
9867
+ function VoucherInput({ config, orderValue, eventInstanceId, customerEmail, onVoucherValidated, appliedVouchers, onRemoveVoucher, disabled = false, }) {
9868
+ const [inputValue, setInputValue] = d$1("");
9869
+ const [isLoading, setIsLoading] = d$1(false);
9870
+ const [error, setError] = d$1(null);
9871
+ const [isExpanded, setIsExpanded] = d$1(false);
9872
+ // Check if a discount code is already applied (only one allowed)
9873
+ const hasDiscountCode = appliedVouchers.some((v) => v.type === "discount");
9874
+ const validateVoucher = q$2(async (code) => {
9875
+ if (!code.trim()) {
9876
+ setError(null);
9877
+ return;
9878
+ }
9879
+ // Check if code is already applied
9880
+ if (appliedVouchers.some((v) => v.code.toUpperCase() === code.toUpperCase())) {
9881
+ setError("Dieser Code wurde bereits angewendet");
9882
+ return;
9883
+ }
9884
+ setIsLoading(true);
9885
+ setError(null);
9886
+ try {
9887
+ const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/validate-voucher"), {
9888
+ method: "POST",
9889
+ headers: createApiHeaders(config),
9890
+ body: JSON.stringify(createRequestBody(config, {
9891
+ code: code.trim(),
9892
+ orderValue: orderValue,
9893
+ eventInstanceId: eventInstanceId,
9894
+ customerEmail: customerEmail,
9895
+ })),
9896
+ });
9897
+ const data = await response.json();
9898
+ if (data.valid && data.voucher) {
9899
+ // Check if trying to add a second discount code
9900
+ if (data.voucher.type === "discount" && hasDiscountCode) {
9901
+ setError("Es kann nur ein Rabattcode verwendet werden");
9902
+ onVoucherValidated(null, "Es kann nur ein Rabattcode verwendet werden");
9903
+ return;
9904
+ }
9905
+ onVoucherValidated(data.voucher);
9906
+ setInputValue("");
9907
+ setError(null);
9908
+ }
9909
+ else {
9910
+ setError(data.error || "Code nicht gefunden oder ungültig");
9911
+ onVoucherValidated(null, data.error);
9912
+ }
9913
+ }
9914
+ catch (err) {
9915
+ const errorMsg = "Fehler beim Validieren des Codes";
9916
+ setError(errorMsg);
9917
+ onVoucherValidated(null, errorMsg);
9918
+ }
9919
+ finally {
9920
+ setIsLoading(false);
9921
+ }
9922
+ }, [
9923
+ config,
9924
+ orderValue,
9925
+ eventInstanceId,
9926
+ customerEmail,
9927
+ appliedVouchers,
9928
+ hasDiscountCode,
9929
+ onVoucherValidated,
9930
+ ]);
9931
+ const handleSubmit = () => {
9932
+ if (inputValue.trim() && !isLoading && !disabled) {
9933
+ validateVoucher(inputValue);
9934
+ }
9935
+ };
9936
+ const handleKeyDown = (e) => {
9937
+ if (e.key === "Enter") {
9938
+ e.preventDefault();
9939
+ if (inputValue.trim() && !isLoading && !disabled) {
9940
+ validateVoucher(inputValue);
9941
+ }
9942
+ }
9943
+ };
9944
+ const inputStyle = {
9945
+ flex: 1,
9946
+ padding: "10px 12px",
9947
+ backgroundColor: "var(--bw-background-color)",
9948
+ border: "1px solid var(--bw-border-color)",
9949
+ borderRadius: "var(--bw-border-radius)",
9950
+ color: "var(--bw-text-color)",
9951
+ fontSize: "var(--bw-font-size)",
9952
+ fontFamily: "var(--bw-font-family)",
9953
+ outline: "none",
9954
+ transition: "all 0.2s ease",
9955
+ textTransform: "uppercase",
9956
+ };
9957
+ const buttonStyle = {
9958
+ padding: "10px 16px",
9959
+ backgroundColor: "var(--bw-highlight-color)",
9960
+ border: "none",
9961
+ borderRadius: "var(--bw-border-radius)",
9962
+ color: "#fff",
9963
+ fontSize: "var(--bw-font-size)",
9964
+ fontFamily: "var(--bw-font-family)",
9965
+ fontWeight: "600",
9966
+ cursor: disabled || isLoading ? "not-allowed" : "pointer",
9967
+ opacity: disabled || isLoading ? 0.6 : 1,
9968
+ transition: "all 0.2s ease",
9969
+ display: "flex",
9970
+ alignItems: "center",
9971
+ justifyContent: "center",
9972
+ gap: "6px",
9973
+ minWidth: "100px",
9974
+ };
9975
+ const appliedVoucherStyle = {
9976
+ display: "flex",
9977
+ alignItems: "center",
9978
+ justifyContent: "space-between",
9979
+ padding: "10px 12px",
9980
+ backgroundColor: "var(--bw-surface-color)",
9981
+ border: "1px solid var(--bw-border-color)",
9982
+ borderRadius: "var(--bw-border-radius)",
9983
+ marginBottom: "8px",
9984
+ };
9985
+ const removeButtonStyle = {
9986
+ background: "none",
9987
+ border: "none",
9988
+ padding: "4px",
9989
+ cursor: "pointer",
9990
+ color: "var(--bw-error-color)",
9991
+ display: "flex",
9992
+ alignItems: "center",
9993
+ justifyContent: "center",
9994
+ borderRadius: "50%",
9995
+ transition: "background-color 0.2s ease",
9996
+ };
9997
+ return (u$2("div", { style: {
9998
+ backgroundColor: "var(--bw-surface-color)",
9999
+ border: "1px solid var(--bw-border-color)",
10000
+ borderRadius: "var(--bw-border-radius)",
10001
+ overflow: "hidden",
10002
+ }, children: [u$2("button", { type: "button", onClick: () => setIsExpanded(!isExpanded), style: {
10003
+ width: "100%",
10004
+ padding: "var(--bw-spacing)",
10005
+ backgroundColor: "transparent",
10006
+ border: "none",
10007
+ cursor: "pointer",
10008
+ display: "flex",
10009
+ alignItems: "center",
10010
+ justifyContent: "space-between",
10011
+ color: "var(--bw-text-color)",
10012
+ fontFamily: "var(--bw-font-family)",
10013
+ fontSize: "var(--bw-font-size)",
10014
+ fontWeight: "500",
10015
+ }, children: [u$2("span", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [u$2(IconTicket, { size: 18, color: "var(--bw-highlight-color)" }), "Rabattcode oder Gutschein", appliedVouchers.length > 0 && (u$2("span", { style: {
10016
+ backgroundColor: "var(--bw-highlight-color)",
10017
+ color: "#fff",
10018
+ padding: "2px 8px",
10019
+ borderRadius: "12px",
10020
+ fontSize: "12px",
10021
+ fontWeight: "600",
10022
+ }, children: appliedVouchers.length }))] }), u$2("span", { style: {
10023
+ transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
10024
+ transition: "transform 0.2s ease",
10025
+ }, children: "\u25BC" })] }), isExpanded && (u$2("div", { style: { padding: "0 var(--bw-spacing) var(--bw-spacing)" }, children: [appliedVouchers.length > 0 && (u$2("div", { style: { marginBottom: "12px" }, children: appliedVouchers.map((voucher) => (u$2("div", { style: appliedVoucherStyle, children: [u$2("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [voucher.type === "discount" ? (u$2(IconTicket, { size: 18, color: "var(--bw-success-color)" })) : (u$2(IconGift, { size: 18, color: "var(--bw-success-color)" })), u$2("div", { children: [u$2("div", { style: {
10026
+ fontFamily: "var(--bw-font-family)",
10027
+ fontSize: "var(--bw-font-size)",
10028
+ fontWeight: "600",
10029
+ color: "var(--bw-text-color)",
10030
+ display: "flex",
10031
+ alignItems: "center",
10032
+ gap: "6px",
10033
+ }, children: [u$2("span", { style: { fontFamily: "monospace" }, children: voucher.code }), u$2(IconCheck, { size: 14, color: "var(--bw-success-color)" })] }), u$2("div", { style: {
10034
+ fontFamily: "var(--bw-font-family)",
10035
+ fontSize: "12px",
10036
+ color: "var(--bw-success-color)",
10037
+ }, children: [voucher.type === "discount"
10038
+ ? `−${formatCurrency(voucher.discountAmount)} Rabatt`
10039
+ : `−${formatCurrency(voucher.balanceToUse || voucher.discountAmount)} Gutschein`, voucher.type === "giftCard" &&
10040
+ voucher.remainingBalance !== undefined &&
10041
+ voucher.remainingBalance > 0 && (u$2("span", { style: { color: "var(--bw-text-muted)", marginLeft: "8px" }, children: ["(Rest: ", formatCurrency(voucher.remainingBalance), ")"] }))] })] })] }), u$2("button", { type: "button", onClick: () => onRemoveVoucher(voucher.code), style: removeButtonStyle, title: "Entfernen", children: u$2(IconX, { size: 16 }) })] }, voucher.code))) })), u$2("div", { style: { display: "flex", gap: "8px" }, children: [u$2("input", { type: "text", value: inputValue, onChange: (e) => {
10042
+ setInputValue(e.target.value.toUpperCase());
10043
+ setError(null);
10044
+ }, onKeyDown: handleKeyDown, placeholder: hasDiscountCode
10045
+ ? "Gutscheincode eingeben..."
10046
+ : "Rabatt- oder Gutscheincode eingeben...", style: inputStyle, disabled: disabled || isLoading, onFocus: (e) => {
10047
+ e.target.style.borderColor = "var(--bw-highlight-color)";
10048
+ e.target.style.boxShadow = "0 0 0 2px var(--bw-highlight-color)33";
10049
+ }, onBlur: (e) => {
10050
+ e.target.style.borderColor = "var(--bw-border-color)";
10051
+ e.target.style.boxShadow = "none";
10052
+ } }), u$2("button", { type: "button", onClick: handleSubmit, style: buttonStyle, disabled: disabled || isLoading || !inputValue.trim(), children: isLoading ? (u$2(IconSpinner, { size: 16, color: "#fff" })) : (u$2(k$3, { children: [u$2(IconCheck, { size: 16 }), "Einl\u00F6sen"] })) })] }), error && (u$2("div", { style: {
10053
+ marginTop: "8px",
10054
+ padding: "8px 12px",
10055
+ backgroundColor: "var(--bw-error-color)15",
10056
+ border: "1px solid var(--bw-error-color)40",
10057
+ borderRadius: "var(--bw-border-radius)",
10058
+ color: "var(--bw-error-color)",
10059
+ fontSize: "var(--bw-font-size)",
10060
+ fontFamily: "var(--bw-font-family)",
10061
+ display: "flex",
10062
+ alignItems: "center",
10063
+ gap: "8px",
10064
+ }, children: [u$2(IconX, { size: 16 }), error] })), hasDiscountCode && (u$2("div", { style: {
10065
+ marginTop: "8px",
10066
+ fontSize: "12px",
10067
+ color: "var(--bw-text-muted)",
10068
+ fontFamily: "var(--bw-font-family)",
10069
+ }, children: "\uD83D\uDCA1 Es wurde bereits ein Rabattcode angewendet. Du kannst weitere Gutscheine hinzuf\u00FCgen." }))] })), u$2("style", { children: `
10070
+ @keyframes spin {
10071
+ from { transform: rotate(0deg); }
10072
+ to { transform: rotate(360deg); }
10073
+ }
10074
+ ` })] }));
10075
+ }
10076
+
9743
10077
  // Form schemas
9744
10078
  const participantSchema = objectType({
9745
10079
  name: stringType().min(1, "Name ist erforderlich"),
@@ -9759,6 +10093,10 @@
9759
10093
  const IconWarning = ({ size = 48, color = "var(--bw-error-color)" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("circle", { cx: "12", cy: "12", r: "10" }), u$2("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), u$2("circle", { cx: "12", cy: "16", r: "1" })] }));
9760
10094
  const IconMoney = ({ size = 20, color = "var(--bw-text-muted)" }) => (u$2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [u$2("rect", { x: "2", y: "6", width: "20", height: "12", rx: "2" }), u$2("circle", { cx: "12", cy: "12", r: "4" }), u$2("line", { x1: "2", y1: "10", x2: "2", y2: "14" }), u$2("line", { x1: "22", y1: "10", x2: "22", y2: "14" })] }));
9761
10095
  function BookingForm({ config, eventDetails, stripePromise, onSuccess, onError, onBackToEventInstances, onBackToEventTypes, selectedEventType, selectedEventInstance, isOpen, onClose, systemConfig, }) {
10096
+ // New voucher system - supports multiple gift cards + one discount code
10097
+ const [appliedVouchers, setAppliedVouchers] = d$1([]);
10098
+ const [voucherError, setVoucherError] = d$1(null);
10099
+ // Legacy state for backward compatibility
9762
10100
  const [discountCode, setDiscountCode] = d$1(null);
9763
10101
  const [discountLoading, setDiscountLoading] = d$1(false);
9764
10102
  const [discountError, setDiscountError] = d$1(null);
@@ -9772,28 +10110,66 @@
9772
10110
  },
9773
10111
  });
9774
10112
  const watchedParticipants = form.watch("participants");
9775
- const watchedDiscountCode = form.watch("discountCode");
10113
+ form.watch("discountCode");
9776
10114
  const watchedCustomerName = form.watch("customerName");
9777
10115
  const watchedCustomerEmail = form.watch("customerEmail");
9778
10116
  const customerNameError = form.formState.errors.customerName;
9779
10117
  const customerEmailError = form.formState.errors.customerEmail;
9780
10118
  const watchedAcceptTerms = form.watch("acceptTerms");
9781
- // Calculate total amount and deposit amount
9782
- const calculateTotal = () => {
10119
+ // Calculate base total before any discounts
10120
+ const calculateBaseTotal = q$2(() => {
9783
10121
  if (!eventDetails)
9784
10122
  return 0;
9785
- const baseTotal = eventDetails.price * watchedParticipants.filter((p) => p.name.trim()).length;
9786
- return discountCode ? discountCode.newTotal : baseTotal;
9787
- };
10123
+ return eventDetails.price * watchedParticipants.filter((p) => p.name.trim()).length;
10124
+ }, [eventDetails, watchedParticipants]);
10125
+ // Calculate total discount from all applied vouchers
10126
+ const calculateTotalDiscount = q$2(() => {
10127
+ return appliedVouchers.reduce((total, voucher) => {
10128
+ if (voucher.type === "discount") {
10129
+ return total + voucher.discountAmount;
10130
+ }
10131
+ else if (voucher.type === "giftCard") {
10132
+ return total + (voucher.balanceToUse || voucher.discountAmount);
10133
+ }
10134
+ return total;
10135
+ }, 0);
10136
+ }, [appliedVouchers]);
10137
+ // Calculate total amount after discounts
10138
+ const calculateTotal = q$2(() => {
10139
+ const baseTotal = calculateBaseTotal();
10140
+ const totalDiscount = calculateTotalDiscount();
10141
+ return Math.max(0, baseTotal - totalDiscount);
10142
+ }, [calculateBaseTotal, calculateTotalDiscount]);
9788
10143
  const calculateDeposit = () => {
9789
10144
  if (!eventDetails || !eventDetails.deposit)
9790
10145
  return 0;
9791
10146
  const participantCount = watchedParticipants.filter((p) => p.name.trim()).length;
9792
10147
  return eventDetails.deposit * participantCount;
9793
10148
  };
10149
+ const baseTotal = calculateBaseTotal();
10150
+ const totalDiscount = calculateTotalDiscount();
9794
10151
  const totalAmount = calculateTotal();
9795
10152
  const depositAmount = calculateDeposit();
9796
- const paymentAmount = depositAmount > 0 ? depositAmount : totalAmount;
10153
+ // If there's a deposit, we pay the deposit; otherwise we pay the total after discounts
10154
+ const paymentAmount = depositAmount > 0 ? Math.max(0, depositAmount - totalDiscount) : totalAmount;
10155
+ // Get discount code for legacy compatibility
10156
+ const appliedDiscountCode = appliedVouchers.find((v) => v.type === "discount");
10157
+ // Get gift cards
10158
+ const appliedGiftCards = appliedVouchers.filter((v) => v.type === "giftCard");
10159
+ // Voucher handlers
10160
+ const handleVoucherValidated = q$2((voucher, error) => {
10161
+ if (error) {
10162
+ setVoucherError(error);
10163
+ return;
10164
+ }
10165
+ if (voucher) {
10166
+ setAppliedVouchers((prev) => [...prev, voucher]);
10167
+ setVoucherError(null);
10168
+ }
10169
+ }, []);
10170
+ const handleRemoveVoucher = q$2((code) => {
10171
+ setAppliedVouchers((prev) => prev.filter((v) => v.code !== code));
10172
+ }, []);
9797
10173
  // Form validation helper
9798
10174
  const isFormValid = () => {
9799
10175
  const participantCount = watchedParticipants.filter((p) => p.name.trim()).length;
@@ -9807,48 +10183,51 @@
9807
10183
  const hasAcceptedTerms = watchedAcceptTerms === true;
9808
10184
  return validParticipants && participantsWithinLimit && hasName && hasEmail && hasAcceptedTerms;
9809
10185
  };
9810
- // Validate discount codes
10186
+ // Re-validate vouchers when participant count changes (affects order value)
9811
10187
  y$1(() => {
9812
- const validateDiscountCode = async (code) => {
9813
- if (!code.trim() || !eventDetails) {
9814
- setDiscountCode(null);
9815
- setDiscountError(null);
9816
- return;
9817
- }
9818
- setDiscountLoading(true);
9819
- setDiscountError(null);
9820
- try {
9821
- const baseTotal = eventDetails.price * watchedParticipants.filter((p) => p.name.trim()).length;
9822
- const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/validate-discount"), {
9823
- method: "POST",
9824
- headers: createApiHeaders(config),
9825
- body: JSON.stringify(createRequestBody(config, {
9826
- code: code.trim(),
9827
- orderValue: baseTotal,
9828
- })),
9829
- });
9830
- const data = await response.json();
9831
- if (data.valid) {
9832
- setDiscountCode(data.discountCode);
10188
+ // When participants change, we need to recalculate voucher amounts
10189
+ // For now, we'll clear vouchers if the order value changes significantly
10190
+ // In a production app, you might want to re-validate each voucher
10191
+ if (appliedVouchers.length > 0) {
10192
+ // Recalculate discount amounts based on new order value
10193
+ const newBaseTotal = eventDetails?.price
10194
+ ? eventDetails.price * watchedParticipants.filter((p) => p.name.trim()).length
10195
+ : 0;
10196
+ // Update voucher amounts (simplified - in production, re-validate via API)
10197
+ setAppliedVouchers((prev) => prev.map((voucher) => {
10198
+ if (voucher.type === "discount") {
10199
+ let newDiscountAmount = 0;
10200
+ if (voucher.discountType === "percentage") {
10201
+ newDiscountAmount = Math.round((newBaseTotal * (voucher.discountValue || 0)) / 10000);
10202
+ }
10203
+ else {
10204
+ newDiscountAmount = voucher.discountValue || 0;
10205
+ }
10206
+ newDiscountAmount = Math.min(newDiscountAmount, newBaseTotal);
10207
+ return {
10208
+ ...voucher,
10209
+ discountAmount: newDiscountAmount,
10210
+ newTotal: newBaseTotal - newDiscountAmount,
10211
+ };
9833
10212
  }
9834
- else {
9835
- setDiscountCode(null);
9836
- setDiscountError(data.error);
10213
+ else if (voucher.type === "giftCard") {
10214
+ // Gift card balance stays the same, but amount to use might change
10215
+ const remainingAfterDiscount = newBaseTotal -
10216
+ prev
10217
+ .filter((v) => v.type === "discount")
10218
+ .reduce((sum, v) => sum + v.discountAmount, 0);
10219
+ const balanceToUse = Math.min(voucher.currentBalance || 0, Math.max(0, remainingAfterDiscount));
10220
+ return {
10221
+ ...voucher,
10222
+ balanceToUse,
10223
+ remainingBalance: (voucher.currentBalance || 0) - balanceToUse,
10224
+ discountAmount: balanceToUse,
10225
+ };
9837
10226
  }
9838
- }
9839
- catch (err) {
9840
- setDiscountError("Fehler beim Validieren des Rabattcodes");
9841
- setDiscountCode(null);
9842
- }
9843
- finally {
9844
- setDiscountLoading(false);
9845
- }
9846
- };
9847
- const timer = setTimeout(() => {
9848
- validateDiscountCode(watchedDiscountCode || "");
9849
- }, 500);
9850
- return () => clearTimeout(timer);
9851
- }, [watchedDiscountCode, watchedParticipants, eventDetails, config]);
10227
+ return voucher;
10228
+ }));
10229
+ }
10230
+ }, [watchedParticipants, eventDetails]);
9852
10231
  // Helper functions
9853
10232
  const addParticipant = () => {
9854
10233
  const currentParticipants = form.getValues("participants");
@@ -10003,7 +10382,7 @@
10003
10382
  color: "var(--bw-text-color)",
10004
10383
  fontWeight: "500",
10005
10384
  fontFamily: "var(--bw-font-family)",
10006
- }, children: [formatCurrency(eventDetails.price), " pro Person"] })] })] })] }), u$2("div", { style: { display: "flex", flexDirection: "column", gap: "var(--bw-spacing-large)" }, children: [u$2("form", { style: { display: "flex", flexDirection: "column", gap: "var(--bw-spacing-large)" }, children: [u$2("div", { style: {
10385
+ }, children: [formatCurrency(eventDetails.price), " pro Person"] })] })] })] }), u$2("div", { style: { display: "flex", flexDirection: "column", gap: "var(--bw-spacing-large)" }, children: [u$2("div", { style: { display: "flex", flexDirection: "column", gap: "var(--bw-spacing-large)" }, children: [u$2("div", { style: {
10007
10386
  backgroundColor: "var(--bw-surface-color)",
10008
10387
  border: `1px solid var(--bw-border-color)`,
10009
10388
  backdropFilter: "blur(4px)",
@@ -10148,7 +10527,7 @@
10148
10527
  color: "var(--bw-error-color)",
10149
10528
  fontSize: "var(--bw-font-size)",
10150
10529
  fontFamily: "var(--bw-font-family)",
10151
- }, children: ["Maximal ", eventDetails.availableSpots, " Pl\u00E4tze verf\u00FCgbar."] }))] })] }), u$2("div", { style: {
10530
+ }, children: ["Maximal ", eventDetails.availableSpots, " Pl\u00E4tze verf\u00FCgbar."] }))] })] }), u$2(VoucherInput, { config: config, orderValue: baseTotal, eventInstanceId: eventDetails?.id, customerEmail: watchedCustomerEmail, onVoucherValidated: handleVoucherValidated, appliedVouchers: appliedVouchers, onRemoveVoucher: handleRemoveVoucher, disabled: !eventDetails }), u$2("div", { style: {
10152
10531
  backgroundColor: "var(--bw-surface-color)",
10153
10532
  border: `1px solid var(--bw-border-color)`,
10154
10533
  backdropFilter: "blur(4px)",
@@ -10247,7 +10626,7 @@
10247
10626
  color: "var(--bw-text-color)",
10248
10627
  fontWeight: "500",
10249
10628
  fontFamily: "var(--bw-font-family)",
10250
- }, children: formatCurrency(eventDetails.deposit || 0) })] })), discountCode && (u$2(k$3, { children: [u$2("div", { style: {
10629
+ }, children: formatCurrency(eventDetails.deposit || 0) })] })), appliedVouchers.length > 0 && (u$2(k$3, { children: [u$2("div", { style: {
10251
10630
  display: "flex",
10252
10631
  justifyContent: "space-between",
10253
10632
  alignItems: "center",
@@ -10256,20 +10635,31 @@
10256
10635
  fontFamily: "var(--bw-font-family)",
10257
10636
  }, children: "Zwischensumme:" }), u$2("span", { style: {
10258
10637
  color: "var(--bw-text-muted)",
10259
- textDecoration: "line-through",
10638
+ textDecoration: totalDiscount > 0 ? "line-through" : "none",
10639
+ fontFamily: "var(--bw-font-family)",
10640
+ }, children: formatCurrency(baseTotal) })] }), appliedDiscountCode && (u$2("div", { style: {
10641
+ display: "flex",
10642
+ justifyContent: "space-between",
10643
+ alignItems: "center",
10644
+ }, children: [u$2("span", { style: {
10645
+ color: "var(--bw-success-color)",
10260
10646
  fontFamily: "var(--bw-font-family)",
10261
- }, children: formatCurrency(eventDetails.price *
10262
- watchedParticipants.filter((p) => p.name.trim()).length) })] }), u$2("div", { style: {
10647
+ fontSize: "var(--bw-font-size)",
10648
+ }, children: ["Rabatt (", appliedDiscountCode.code, "):"] }), u$2("span", { style: {
10649
+ color: "var(--bw-success-color)",
10650
+ fontFamily: "var(--bw-font-family)",
10651
+ }, children: ["-", formatCurrency(appliedDiscountCode.discountAmount)] })] })), appliedGiftCards.map((giftCard) => (u$2("div", { style: {
10263
10652
  display: "flex",
10264
10653
  justifyContent: "space-between",
10265
10654
  alignItems: "center",
10266
10655
  }, children: [u$2("span", { style: {
10267
10656
  color: "var(--bw-success-color)",
10268
10657
  fontFamily: "var(--bw-font-family)",
10269
- }, children: "Rabatt:" }), u$2("span", { style: {
10658
+ fontSize: "var(--bw-font-size)",
10659
+ }, children: ["Gutschein (", giftCard.code, "):"] }), u$2("span", { style: {
10270
10660
  color: "var(--bw-success-color)",
10271
10661
  fontFamily: "var(--bw-font-family)",
10272
- }, children: ["-", formatCurrency(discountCode.discountAmount)] })] })] })), u$2("div", { style: {
10662
+ }, children: ["-", formatCurrency(giftCard.balanceToUse || giftCard.discountAmount)] })] }, giftCard.code)))] })), u$2("div", { style: {
10273
10663
  borderTop: `1px solid var(--bw-border-color)`,
10274
10664
  paddingTop: "12px",
10275
10665
  }, children: [depositAmount > 0 && (u$2("div", { style: {
@@ -10342,7 +10732,15 @@
10342
10732
  fontFamily: "var(--bw-font-family)",
10343
10733
  borderBottom: "2px solid var(--bw-highlight-color)",
10344
10734
  paddingBottom: 4,
10345
- }, children: "Zahlung" }), u$2(PaymentForm, { config: config, eventDetails: eventDetails, formData: form.getValues(), totalAmount: paymentAmount, discountCode: discountCode, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, stripePromise: stripePromise, stripeAppearance: stripeAppearance })] }));
10735
+ }, children: "Zahlung" }), u$2(PaymentForm, { config: config, eventDetails: eventDetails, formData: form.getValues(), totalAmount: paymentAmount, discountCode: appliedDiscountCode ? {
10736
+ id: appliedDiscountCode.id,
10737
+ code: appliedDiscountCode.code,
10738
+ description: appliedDiscountCode.description || undefined,
10739
+ type: appliedDiscountCode.discountType || "percentage",
10740
+ value: appliedDiscountCode.discountValue || 0,
10741
+ discountAmount: appliedDiscountCode.discountAmount,
10742
+ newTotal: appliedDiscountCode.newTotal,
10743
+ } : null, giftCards: appliedGiftCards, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, stripePromise: stripePromise, stripeAppearance: stripeAppearance })] }));
10346
10744
  })()] })] }), u$2("style", { children: `
10347
10745
  .booking-widget-container *,
10348
10746
  .booking-widget-container *::before,
@@ -11369,137 +11767,155 @@
11369
11767
  font-size: 1.1rem !important;
11370
11768
  }
11371
11769
  }
11372
- ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: "Termin-Auswahl", children: [u$2("p", { className: "bw-event-instance-title", children: selectedEventType?.name }), u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
11373
- display: "flex",
11374
- flexDirection: "column",
11375
- gap: "20px",
11376
- }, children: monthYearGroups.map(({ key, label, events, minPrice }) => {
11377
- const monthPriceDisplayInfo = getMonthPriceDisplayInfo(minPrice);
11378
- return (u$2(Accordion, { title: label, priceInfo: u$2("div", { style: {
11379
- fontSize: "1rem",
11380
- backgroundColor: monthPriceDisplayInfo
11381
- ? monthPriceDisplayInfo.backgroundColor
11382
- : "#14532d",
11383
- color: monthPriceDisplayInfo ? monthPriceDisplayInfo.textColor : "#4ade80",
11384
- fontWeight: 500,
11385
- marginLeft: "auto",
11386
- padding: "4px 8px",
11387
- borderRadius: "var(--bw-border-radius-small)",
11388
- border: monthPriceDisplayInfo ? "none" : undefined,
11389
- boxShadow: monthPriceDisplayInfo
11390
- ? "0 2px 4px rgba(0, 0, 0, 0.2)"
11391
- : undefined,
11392
- }, children: `ab ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: u$2("div", { style: {
11393
- display: "flex",
11394
- flexDirection: "column",
11395
- gap: "12px",
11396
- paddingTop: "12px",
11397
- }, children: events.map((event) => {
11398
- const availableSpots = event.maxParticipants - event.participantCount;
11399
- const isFullyBooked = availableSpots === 0;
11400
- const startDate = new Date(event.startTime);
11401
- const isPastEvent = today.toISOString() >= startDate.toISOString();
11402
- return (u$2("div", { className: "bw-event-instance-card", style: {
11403
- position: "relative",
11404
- cursor: !isFullyBooked && !isPastEvent && event.bookingOpen
11405
- ? "pointer"
11406
- : "not-allowed",
11407
- border: "1px solid var(--bw-border-color)",
11408
- backgroundColor: "var(--bw-surface-color)",
11409
- borderRadius: "var(--bw-border-radius)",
11410
- padding: "16px 20px",
11411
- transition: "all 0.2s ease",
11412
- opacity: isFullyBooked || isPastEvent ? 0.3 : 1,
11413
- filter: isFullyBooked || isPastEvent ? "grayscale(40%)" : "none",
11414
- fontFamily: "var(--bw-font-family)",
11415
- }, onClick: () => {
11416
- if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11417
- handleEventInstanceSelect(event);
11418
- }
11419
- }, onMouseEnter: (e) => {
11420
- if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11421
- e.currentTarget.style.transform = "scale(1.02)";
11422
- e.currentTarget.style.backgroundColor =
11423
- "var(--bw-surface-muted, rgba(59, 130, 246, 0.1))";
11424
- }
11425
- }, onMouseLeave: (e) => {
11426
- if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11427
- e.currentTarget.style.transform = "scale(1)";
11428
- e.currentTarget.style.backgroundColor = "var(--bw-surface-color)";
11429
- }
11430
- }, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (u$2("div", { style: {
11431
- position: "absolute",
11432
- top: 0,
11433
- left: 0,
11434
- width: "100%",
11435
- height: "100%",
11436
- backgroundColor: "var(--bw-overlay-color, rgba(15, 23, 42, 0.8))",
11437
- borderRadius: "var(--bw-border-radius)",
11438
- display: "flex",
11439
- alignItems: "center",
11440
- justifyContent: "center",
11441
- }, children: u$2("div", { style: {
11442
- width: "32px",
11443
- height: "32px",
11444
- color: "var(--bw-highlight-color-muted, rgba(59, 130, 246, 0.8))",
11445
- animation: "spin 1s linear infinite",
11446
- fontSize: "32px",
11447
- }, children: spinner() }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants }), u$2("div", { style: {
11448
- display: "flex",
11449
- justifyContent: "space-between",
11450
- width: "100%",
11451
- alignItems: "start",
11452
- gap: "12px",
11453
- marginBottom: "4px",
11454
- }, children: [u$2("div", { style: { display: "flex", alignItems: "start", gap: "12px" }, children: [u$2("div", { className: "bw-event-instance-datebox", style: {
11455
- fontSize: "var(--bw-font-size)",
11456
- transition: "all 0.2s ease",
11457
- borderRadius: "var(--bw-border-radius-small)",
11458
- borderTop: `4px solid var(--bw-border-color)`,
11459
- border: "1px solid var(--bw-border-color)",
11460
- width: "40px",
11461
- height: "40px",
11462
- display: "flex",
11463
- alignItems: "center",
11464
- justifyContent: "center",
11465
- fontWeight: "bold",
11466
- color: "var(--bw-text-color)",
11467
- backgroundColor: "var(--bw-background-color)",
11468
- }, children: startDate.getDate() }), u$2("div", { style: {
11469
- fontSize: "var(--bw-font-size)",
11470
- color: "var(--bw-text-color)",
11471
- display: "flex",
11472
- flexDirection: "column",
11473
- alignItems: "start",
11474
- justifyContent: "start",
11475
- lineHeight: "1.2",
11476
- }, 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) !==
11477
- 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) ===
11478
- 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: {
11479
- fontSize: "12px",
11480
- fontWeight: 400,
11481
- color: "var(--bw-text-muted)",
11482
- marginLeft: "6px",
11483
- background: "var(--bw-background-muted)",
11484
- whiteSpace: "nowrap",
11485
- }, children: [event.durationDays, " Tag", event.durationDays > 1 ? "e" : ""] })] }), u$2("div", { className: "bw-event-instance-price", style: {
11486
- textAlign: "right",
11487
- display: "flex",
11488
- flexDirection: "column",
11489
- alignItems: "end",
11490
- }, children: u$2(PriceDisplay, { price: event.price, yearPrices: yearPrices }) })] }), event.name !== selectedEventType?.name && (u$2("h4", { className: "bw-event-instance-title", style: {
11491
- fontSize: "var(--bw-font-size)",
11492
- fontWeight: "600",
11493
- color: "var(--bw-text-color)",
11494
- lineHeight: "1.25",
11495
- margin: "0 0 2px 0",
11496
- display: "flex",
11497
- alignItems: "center",
11498
- gap: "8px",
11499
- maxWidth: "230px",
11500
- }, children: event.name }))] }, event.id));
11501
- }) }) }, key));
11502
- }) }) })] })] }));
11770
+ ` }), u$2(Sidebar, { isOpen: isOpen, onClose: handleClose, title: `${selectedEventType?.name}`, children: u$2("div", { className: "bw-event-instance-list", style: { padding: "24px" }, children: u$2("div", { style: {
11771
+ display: "flex",
11772
+ flexDirection: "column",
11773
+ gap: "20px",
11774
+ }, children: monthYearGroups.map(({ key, label, events, minPrice, year }, idx) => {
11775
+ const monthPriceDisplayInfo = getMonthPriceDisplayInfo(minPrice);
11776
+ return (u$2(k$3, { children: [idx > 0 && monthYearGroups[idx - 1].year !== year && (u$2("div", { style: {
11777
+ height: 1,
11778
+ backgroundColor: "var(--bw-border-color)",
11779
+ margin: "4px 0",
11780
+ } })), u$2(Accordion, { title: label, priceInfo: u$2("div", { style: {
11781
+ fontSize: "1rem",
11782
+ backgroundColor: monthPriceDisplayInfo
11783
+ ? monthPriceDisplayInfo.backgroundColor
11784
+ : "#14532d",
11785
+ color: monthPriceDisplayInfo
11786
+ ? monthPriceDisplayInfo.textColor
11787
+ : "#4ade80",
11788
+ fontWeight: 500,
11789
+ marginLeft: "auto",
11790
+ padding: "4px 8px",
11791
+ borderRadius: "var(--bw-border-radius-small)",
11792
+ border: monthPriceDisplayInfo ? "none" : undefined,
11793
+ boxShadow: monthPriceDisplayInfo
11794
+ ? "0 2px 4px rgba(0, 0, 0, 0.2)"
11795
+ : undefined,
11796
+ }, children: `ab ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: u$2("div", { style: {
11797
+ display: "flex",
11798
+ flexDirection: "column",
11799
+ gap: "12px",
11800
+ paddingTop: "12px",
11801
+ }, children: events.map((event) => {
11802
+ const availableSpots = event.maxParticipants - event.participantCount;
11803
+ const isFullyBooked = availableSpots === 0;
11804
+ const startDate = new Date(event.startTime);
11805
+ const isPastEvent = today.toISOString() >= startDate.toISOString();
11806
+ return (u$2("div", { className: "bw-event-instance-card", style: {
11807
+ position: "relative",
11808
+ cursor: !isFullyBooked && !isPastEvent && event.bookingOpen
11809
+ ? "pointer"
11810
+ : "not-allowed",
11811
+ border: "1px solid var(--bw-border-color)",
11812
+ backgroundColor: "var(--bw-surface-color)",
11813
+ borderRadius: "var(--bw-border-radius)",
11814
+ padding: "16px 20px",
11815
+ transition: "all 0.2s ease",
11816
+ opacity: isFullyBooked || isPastEvent ? 0.3 : 1,
11817
+ filter: isFullyBooked || isPastEvent ? "grayscale(40%)" : "none",
11818
+ fontFamily: "var(--bw-font-family)",
11819
+ }, onClick: () => {
11820
+ if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11821
+ handleEventInstanceSelect(event);
11822
+ }
11823
+ }, onMouseEnter: (e) => {
11824
+ if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11825
+ e.currentTarget.style.transform = "scale(1.02)";
11826
+ e.currentTarget.style.backgroundColor =
11827
+ "var(--bw-surface-muted, rgba(59, 130, 246, 0.1))";
11828
+ }
11829
+ }, onMouseLeave: (e) => {
11830
+ if (!isFullyBooked && !isPastEvent && event.bookingOpen) {
11831
+ e.currentTarget.style.transform = "scale(1)";
11832
+ e.currentTarget.style.backgroundColor = "var(--bw-surface-color)";
11833
+ }
11834
+ }, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (u$2("div", { style: {
11835
+ position: "absolute",
11836
+ top: 0,
11837
+ left: 0,
11838
+ width: "100%",
11839
+ height: "100%",
11840
+ backgroundColor: "var(--bw-overlay-color, rgba(15, 23, 42, 0.8))",
11841
+ borderRadius: "var(--bw-border-radius)",
11842
+ display: "flex",
11843
+ alignItems: "center",
11844
+ justifyContent: "center",
11845
+ }, children: u$2("div", { style: {
11846
+ width: "32px",
11847
+ height: "32px",
11848
+ color: "var(--bw-highlight-color-muted, rgba(59, 130, 246, 0.8))",
11849
+ animation: "spin 1s linear infinite",
11850
+ fontSize: "32px",
11851
+ }, children: spinner() }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants }), u$2("div", { style: {
11852
+ display: "flex",
11853
+ justifyContent: "space-between",
11854
+ width: "100%",
11855
+ alignItems: "start",
11856
+ gap: "12px",
11857
+ marginBottom: "4px",
11858
+ }, children: [u$2("div", { style: { display: "flex", alignItems: "start", gap: "12px" }, children: [u$2("div", { className: "bw-event-instance-datebox", style: {
11859
+ fontSize: "var(--bw-font-size)",
11860
+ transition: "all 0.2s ease",
11861
+ borderRadius: "var(--bw-border-radius-small)",
11862
+ borderTop: `4px solid var(--bw-border-color)`,
11863
+ border: "1px solid var(--bw-border-color)",
11864
+ width: "40px",
11865
+ height: "40px",
11866
+ display: "flex",
11867
+ alignItems: "center",
11868
+ justifyContent: "center",
11869
+ fontWeight: "bold",
11870
+ color: "var(--bw-text-color)",
11871
+ backgroundColor: "var(--bw-background-color)",
11872
+ }, children: startDate.getDate() }), u$2("div", { style: {
11873
+ fontSize: "var(--bw-font-size)",
11874
+ color: "var(--bw-text-color)",
11875
+ display: "flex",
11876
+ flexDirection: "column",
11877
+ alignItems: "start",
11878
+ justifyContent: "start",
11879
+ lineHeight: "1.2",
11880
+ }, 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) !==
11881
+ formatWeekday(event.endTime) && (u$2(k$3, { children: [u$2("span", { style: {
11882
+ color: "var(--bw-text-muted)",
11883
+ fontSize: "14px",
11884
+ }, 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) ===
11885
+ formatWeekday(event.endTime) ? (u$2(k$3, { children: [u$2("span", { style: {
11886
+ color: "var(--bw-text-muted)",
11887
+ fontSize: "14px",
11888
+ }, children: formatTime(event.startTime) }), u$2("span", { style: {
11889
+ color: "var(--bw-text-muted)",
11890
+ fontSize: "14px",
11891
+ }, children: " - " }), u$2("span", { style: {
11892
+ color: "var(--bw-text-muted)",
11893
+ fontSize: "14px",
11894
+ }, children: formatTime(event.endTime) })] })) : (u$2("span", { style: { color: "var(--bw-text-muted)", fontSize: "14px" }, children: [formatTime(event.startTime), " Uhr"] })) })] }), u$2("span", { style: {
11895
+ fontSize: "12px",
11896
+ fontWeight: 400,
11897
+ color: "var(--bw-text-muted)",
11898
+ marginLeft: "6px",
11899
+ background: "var(--bw-background-muted)",
11900
+ whiteSpace: "nowrap",
11901
+ }, children: [event.durationDays, " Tag", event.durationDays > 1 ? "e" : ""] })] }), u$2("div", { className: "bw-event-instance-price", style: {
11902
+ textAlign: "right",
11903
+ display: "flex",
11904
+ flexDirection: "column",
11905
+ alignItems: "end",
11906
+ }, children: u$2(PriceDisplay, { price: event.price, yearPrices: yearPrices }) })] }), event.name !== selectedEventType?.name && (u$2("h4", { className: "bw-event-instance-title", style: {
11907
+ fontSize: "var(--bw-font-size)",
11908
+ fontWeight: "600",
11909
+ color: "var(--bw-text-color)",
11910
+ lineHeight: "1.25",
11911
+ margin: "0 0 2px 0",
11912
+ display: "flex",
11913
+ alignItems: "center",
11914
+ gap: "8px",
11915
+ maxWidth: "230px",
11916
+ }, children: event.name }))] }, event.id));
11917
+ }) }) })] }, key));
11918
+ }) }) }) })] }));
11503
11919
  }
11504
11920
 
11505
11921
  // Loading skeleton component for NextEventsPreview
@@ -11894,6 +12310,263 @@
11894
12310
  ` })] }));
11895
12311
  }
11896
12312
 
12313
+ function PromoDialog({ onClose, onCtaClick }) {
12314
+ const [copied, setCopied] = d$1(false);
12315
+ const [isVisible, setIsVisible] = d$1(false);
12316
+ // Hardcoded Xmas surf school content
12317
+ const discountCode = "X-MAS";
12318
+ // Animate in on mount
12319
+ y$1(() => {
12320
+ const timer = setTimeout(() => setIsVisible(true), 50);
12321
+ return () => clearTimeout(timer);
12322
+ }, []);
12323
+ const handleCopyCode = async () => {
12324
+ try {
12325
+ await navigator.clipboard.writeText(discountCode);
12326
+ setCopied(true);
12327
+ setTimeout(() => setCopied(false), 2000);
12328
+ }
12329
+ catch (err) {
12330
+ // Fallback for older browsers
12331
+ const textArea = document.createElement("textarea");
12332
+ textArea.value = discountCode;
12333
+ document.body.appendChild(textArea);
12334
+ textArea.select();
12335
+ document.execCommand("copy");
12336
+ document.body.removeChild(textArea);
12337
+ setCopied(true);
12338
+ setTimeout(() => setCopied(false), 2000);
12339
+ }
12340
+ };
12341
+ const handleClose = () => {
12342
+ setIsVisible(false);
12343
+ setTimeout(onClose, 200);
12344
+ };
12345
+ const handleCtaClick = () => {
12346
+ setIsVisible(false);
12347
+ setTimeout(onCtaClick, 200);
12348
+ };
12349
+ return (u$2(k$3, { children: [u$2("style", { children: `
12350
+ @keyframes promo-wave {
12351
+ 0%, 100% { transform: translateX(0) translateY(0); }
12352
+ 25% { transform: translateX(5px) translateY(-3px); }
12353
+ 50% { transform: translateX(0) translateY(-5px); }
12354
+ 75% { transform: translateX(-5px) translateY(-3px); }
12355
+ }
12356
+ @keyframes promo-float {
12357
+ 0%, 100% { transform: translateY(0); }
12358
+ 50% { transform: translateY(-8px); }
12359
+ }
12360
+ @keyframes promo-shimmer {
12361
+ 0% { background-position: -200% center; }
12362
+ 100% { background-position: 200% center; }
12363
+ }
12364
+ @keyframes promo-sparkle {
12365
+ 0%, 100% { opacity: 0.3; transform: scale(1); }
12366
+ 50% { opacity: 1; transform: scale(1.2); }
12367
+ }
12368
+ @keyframes promo-snow {
12369
+ 0% { transform: translateY(-10px) rotate(0deg); opacity: 0; }
12370
+ 10% { opacity: 1; }
12371
+ 90% { opacity: 1; }
12372
+ 100% { transform: translateY(350px) rotate(360deg); opacity: 0; }
12373
+ }
12374
+ ` }), u$2("div", { onClick: handleClose, style: {
12375
+ position: "fixed",
12376
+ inset: 0,
12377
+ backgroundColor: "rgba(0, 20, 40, 0.85)",
12378
+ backdropFilter: "blur(8px)",
12379
+ zIndex: 9998,
12380
+ opacity: isVisible ? 1 : 0,
12381
+ transition: "opacity 300ms ease-out",
12382
+ } }), u$2("div", { style: {
12383
+ position: "fixed",
12384
+ top: "50%",
12385
+ left: "50%",
12386
+ transform: `translate(-50%, -50%) scale(${isVisible ? 1 : 0.9})`,
12387
+ zIndex: 9999,
12388
+ width: "92%",
12389
+ maxWidth: "440px",
12390
+ opacity: isVisible ? 1 : 0,
12391
+ transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
12392
+ }, children: u$2("div", { style: {
12393
+ position: "relative",
12394
+ background: "linear-gradient(165deg, #0c4a6e 0%, #0e7490 40%, #0891b2 100%)",
12395
+ borderRadius: "28px",
12396
+ overflow: "hidden",
12397
+ 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)",
12398
+ }, children: [Array.from({ length: 15 }).map((_, i) => (u$2("div", { style: {
12399
+ position: "absolute",
12400
+ left: `${5 + Math.random() * 90}%`,
12401
+ top: "-10px",
12402
+ fontSize: `${10 + Math.random() * 14}px`,
12403
+ color: "white",
12404
+ opacity: 0,
12405
+ animation: `promo-snow ${4 + Math.random() * 3}s linear infinite`,
12406
+ animationDelay: `${Math.random() * 4}s`,
12407
+ pointerEvents: "none",
12408
+ zIndex: 1,
12409
+ }, children: "\u2744" }, i))), u$2("div", { style: {
12410
+ position: "relative",
12411
+ height: "180px",
12412
+ background: "linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(12,74,110,0.8) 100%)",
12413
+ display: "flex",
12414
+ alignItems: "center",
12415
+ justifyContent: "center",
12416
+ overflow: "hidden",
12417
+ }, children: [u$2("img", { src: "https://images.unsplash.com/photo-1502680390469-be75c86b636f?w=600&q=80", alt: "Surfer at sunset", style: {
12418
+ position: "absolute",
12419
+ inset: 0,
12420
+ width: "100%",
12421
+ height: "100%",
12422
+ objectFit: "cover",
12423
+ opacity: 0.6,
12424
+ } }), u$2("div", { style: {
12425
+ position: "absolute",
12426
+ inset: 0,
12427
+ background: "linear-gradient(180deg, rgba(12,74,110,0.3) 0%, rgba(12,74,110,0.95) 100%)",
12428
+ } }), u$2("div", { style: {
12429
+ position: "relative",
12430
+ zIndex: 2,
12431
+ fontSize: "64px",
12432
+ animation: "promo-float 3s ease-in-out infinite",
12433
+ filter: "drop-shadow(0 8px 16px rgba(0,0,0,0.4))",
12434
+ }, children: "\uD83C\uDFC4\u200D\u2642\uFE0F" }), u$2("div", { style: {
12435
+ position: "absolute",
12436
+ top: "16px",
12437
+ left: "20px",
12438
+ fontSize: "28px",
12439
+ animation: "promo-sparkle 2s ease-in-out infinite",
12440
+ }, children: "\uD83C\uDF84" }), u$2("div", { style: {
12441
+ position: "absolute",
12442
+ top: "20px",
12443
+ right: "20px",
12444
+ fontSize: "24px",
12445
+ animation: "promo-sparkle 2s ease-in-out infinite 0.5s",
12446
+ }, children: "\u2B50" })] }), u$2("button", { onClick: handleClose, style: {
12447
+ position: "absolute",
12448
+ top: "16px",
12449
+ right: "16px",
12450
+ width: "36px",
12451
+ height: "36px",
12452
+ borderRadius: "50%",
12453
+ border: "none",
12454
+ background: "rgba(0, 0, 0, 0.3)",
12455
+ backdropFilter: "blur(4px)",
12456
+ color: "white",
12457
+ fontSize: "22px",
12458
+ cursor: "pointer",
12459
+ display: "flex",
12460
+ alignItems: "center",
12461
+ justifyContent: "center",
12462
+ transition: "all 150ms ease",
12463
+ zIndex: 10,
12464
+ lineHeight: 1,
12465
+ }, onMouseEnter: (e) => {
12466
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.5)";
12467
+ e.currentTarget.style.transform = "scale(1.1)";
12468
+ }, onMouseLeave: (e) => {
12469
+ e.currentTarget.style.background = "rgba(0, 0, 0, 0.3)";
12470
+ e.currentTarget.style.transform = "scale(1)";
12471
+ }, children: "\u00D7" }), u$2("div", { style: { padding: "28px 28px 32px", textAlign: "center", position: "relative", zIndex: 2 }, children: [u$2("h2", { style: {
12472
+ fontSize: "26px",
12473
+ fontWeight: "800",
12474
+ color: "white",
12475
+ marginBottom: "6px",
12476
+ textShadow: "0 2px 8px rgba(0,0,0,0.3)",
12477
+ letterSpacing: "-0.5px",
12478
+ }, children: "Frohe Weihnachten! \uD83C\uDF85" }), u$2("p", { style: {
12479
+ fontSize: "17px",
12480
+ color: "rgba(255, 255, 255, 0.9)",
12481
+ marginBottom: "20px",
12482
+ lineHeight: 1.5,
12483
+ }, children: ["Schenk dir oder deinen Liebsten", u$2("br", {}), u$2("strong", { style: { color: "#fbbf24" }, children: "10% Rabatt" }), " auf alle Kurse!"] }), u$2("div", { style: {
12484
+ background: "white",
12485
+ borderRadius: "16px",
12486
+ padding: "18px 20px",
12487
+ marginBottom: "20px",
12488
+ boxShadow: "0 8px 24px rgba(0,0,0,0.15), inset 0 -2px 0 rgba(0,0,0,0.05)",
12489
+ }, children: [u$2("p", { style: {
12490
+ fontSize: "11px",
12491
+ textTransform: "uppercase",
12492
+ letterSpacing: "1.5px",
12493
+ color: "#64748b",
12494
+ marginBottom: "10px",
12495
+ fontWeight: "600",
12496
+ }, children: "Dein Geschenk-Code" }), u$2("div", { style: {
12497
+ display: "flex",
12498
+ alignItems: "center",
12499
+ justifyContent: "center",
12500
+ gap: "14px",
12501
+ }, children: [u$2("div", { style: {
12502
+ background: "linear-gradient(135deg, #dc2626 0%, #b91c1c 100%)",
12503
+ padding: "10px 20px",
12504
+ borderRadius: "10px",
12505
+ boxShadow: "0 4px 12px rgba(220, 38, 38, 0.3)",
12506
+ }, children: u$2("span", { style: {
12507
+ fontSize: "28px",
12508
+ fontWeight: "900",
12509
+ color: "white",
12510
+ letterSpacing: "6px",
12511
+ textShadow: "0 2px 4px rgba(0,0,0,0.2)",
12512
+ }, children: discountCode }) }), u$2("button", { onClick: handleCopyCode, style: {
12513
+ padding: "12px 16px",
12514
+ borderRadius: "10px",
12515
+ border: "2px solid",
12516
+ borderColor: copied ? "#22c55e" : "#e2e8f0",
12517
+ background: copied ? "#dcfce7" : "#f8fafc",
12518
+ color: copied ? "#15803d" : "#475569",
12519
+ fontSize: "13px",
12520
+ fontWeight: "600",
12521
+ cursor: "pointer",
12522
+ transition: "all 150ms ease",
12523
+ display: "flex",
12524
+ alignItems: "center",
12525
+ gap: "6px",
12526
+ whiteSpace: "nowrap",
12527
+ }, children: copied ? (u$2(k$3, { children: "\u2713 Kopiert!" })) : (u$2(k$3, { children: [u$2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [u$2("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), u$2("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }), "Kopieren"] })) })] })] }), u$2("div", { style: {
12528
+ display: "flex",
12529
+ justifyContent: "center",
12530
+ gap: "8px",
12531
+ marginBottom: "20px",
12532
+ flexWrap: "wrap",
12533
+ }, children: ["🏄 Surfen", "🪁 Wingen", "🏄‍♀️ SUP", "💨 Windsurfen"].map((activity) => (u$2("span", { style: {
12534
+ background: "rgba(255,255,255,0.15)",
12535
+ backdropFilter: "blur(4px)",
12536
+ padding: "6px 12px",
12537
+ borderRadius: "20px",
12538
+ fontSize: "13px",
12539
+ color: "white",
12540
+ fontWeight: "500",
12541
+ }, children: activity }, activity))) }), u$2("button", { onClick: handleCtaClick, style: {
12542
+ width: "100%",
12543
+ padding: "18px 24px",
12544
+ borderRadius: "14px",
12545
+ border: "none",
12546
+ background: "linear-gradient(135deg, #f59e0b 0%, #d97706 100%)",
12547
+ color: "white",
12548
+ fontSize: "18px",
12549
+ fontWeight: "700",
12550
+ cursor: "pointer",
12551
+ transition: "all 150ms ease",
12552
+ boxShadow: "0 8px 24px rgba(245, 158, 11, 0.4), inset 0 1px 0 rgba(255,255,255,0.2)",
12553
+ display: "flex",
12554
+ alignItems: "center",
12555
+ justifyContent: "center",
12556
+ gap: "10px",
12557
+ }, onMouseEnter: (e) => {
12558
+ e.currentTarget.style.transform = "translateY(-2px)";
12559
+ e.currentTarget.style.boxShadow = "0 12px 28px rgba(245, 158, 11, 0.5), inset 0 1px 0 rgba(255,255,255,0.2)";
12560
+ }, onMouseLeave: (e) => {
12561
+ e.currentTarget.style.transform = "translateY(0)";
12562
+ e.currentTarget.style.boxShadow = "0 8px 24px rgba(245, 158, 11, 0.4), inset 0 1px 0 rgba(255,255,255,0.2)";
12563
+ }, children: [u$2("span", { style: { animation: "promo-wave 2s ease-in-out infinite" }, children: "\uD83C\uDF81" }), "Jetzt Kurs buchen", u$2("span", { children: "\u2192" })] }), u$2("p", { style: {
12564
+ marginTop: "16px",
12565
+ fontSize: "12px",
12566
+ color: "rgba(255,255,255,0.6)",
12567
+ }, children: "G\u00FCltig f\u00FCr alle Buchungen bis 31. Dezember 2025" })] })] }) })] }));
12568
+ }
12569
+
11897
12570
  // Predefined themes & Style Provider have been moved to ../styles/StyleProvider.tsx
11898
12571
  // Main widget component
11899
12572
  function UniversalBookingWidget({ config: baseConfig }) {
@@ -11936,6 +12609,9 @@
11936
12609
  // PERFORMANCE OPTIMIZATION: Lazy component loading
11937
12610
  const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = d$1(false);
11938
12611
  const [shouldRenderBookingForm, setShouldRenderBookingForm] = d$1(false);
12612
+ // Promo dialog state
12613
+ const [showPromoDialog, setShowPromoDialog] = d$1(false);
12614
+ const [widgetContainerRef, setWidgetContainerRef] = d$1(null);
11939
12615
  // Determine initial step and load data
11940
12616
  y$1(() => {
11941
12617
  const initializeWidget = async () => {
@@ -12010,6 +12686,46 @@
12010
12686
  setShouldRenderBookingForm(true);
12011
12687
  }
12012
12688
  }, [currentStep, shouldRenderInstanceSelection, shouldRenderBookingForm]);
12689
+ // Promo dialog: show Xmas promo once per user during holiday season, prevent double-opening across multiple widgets
12690
+ y$1(() => {
12691
+ // Only show during holiday season (December and January)
12692
+ const now = new Date();
12693
+ const month = now.getMonth(); // 0 = January, 11 = December
12694
+ const isHolidaySeason = month === 11 || month === 0; // December (11) or January (0)
12695
+ if (!isHolidaySeason) {
12696
+ return;
12697
+ }
12698
+ const promoId = "xmas-2024";
12699
+ const storageKey = `bigz-promo-${promoId}-shown`;
12700
+ const globalFlagKey = `__bigzPromoShown_${promoId}`;
12701
+ // Check if already shown in this session (localStorage) or claimed by another widget (global flag)
12702
+ const alreadyShown = localStorage.getItem(storageKey) === "true";
12703
+ const claimedByOtherWidget = window[globalFlagKey] === true;
12704
+ if (alreadyShown || claimedByOtherWidget) {
12705
+ return;
12706
+ }
12707
+ // Claim this promo for this widget instance (prevents other widgets from showing it)
12708
+ window[globalFlagKey] = true;
12709
+ // Show the dialog after a short delay for better UX
12710
+ const timer = setTimeout(() => {
12711
+ setShowPromoDialog(true);
12712
+ }, 1000);
12713
+ return () => clearTimeout(timer);
12714
+ }, []);
12715
+ // Handle promo dialog close
12716
+ const handlePromoDialogClose = () => {
12717
+ setShowPromoDialog(false);
12718
+ localStorage.setItem("bigz-promo-xmas-2024-shown", "true");
12719
+ };
12720
+ // Handle promo dialog CTA click - scroll to widget
12721
+ const handlePromoCtaClick = () => {
12722
+ setShowPromoDialog(false);
12723
+ localStorage.setItem("bigz-promo-xmas-2024-shown", "true");
12724
+ // Scroll to the widget container
12725
+ if (widgetContainerRef) {
12726
+ widgetContainerRef.scrollIntoView({ behavior: "smooth", block: "start" });
12727
+ }
12728
+ };
12013
12729
  const loadEventTypes = async () => {
12014
12730
  const requestBody = {
12015
12731
  organizationId: config.organizationId,
@@ -12409,104 +13125,104 @@
12409
13125
  // Main view based on view mode
12410
13126
  if (viewMode === "next-events" && showingPreview) {
12411
13127
  // Next events preview mode
12412
- return (u$2(StyleProvider, { config: config, children: [u$2(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (u$2(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
12413
- setCurrentStep("eventTypes");
12414
- setShowingPreview(true);
12415
- setEventDetails(null);
12416
- }, onBackToEventTypes: () => {
12417
- setCurrentStep("eventTypes");
12418
- setShowingPreview(true);
12419
- setEventDetails(null);
12420
- }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
12421
- setCurrentStep("eventTypes");
12422
- setShowingPreview(true);
12423
- setEventDetails(null);
12424
- }, systemConfig: systemConfig })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12425
- setIsSuccess(false);
12426
- setCurrentStep("eventTypes");
12427
- setShowingPreview(true);
12428
- // Reset state
12429
- setSuccessPaymentIntentId(null);
12430
- // Reset lazy loading flags
12431
- setShouldRenderInstanceSelection(false);
12432
- setShouldRenderBookingForm(false);
12433
- // Clean up URL to remove Stripe parameters
12434
- const url = new URL(window.location.href);
12435
- url.searchParams.delete("payment_intent");
12436
- url.searchParams.delete("payment_intent_client_secret");
12437
- url.searchParams.delete("redirect_status");
12438
- window.history.replaceState({}, "", url.toString());
12439
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13128
+ return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [u$2(NextEventsPreview, { events: upcomingEvents, onEventSelect: handleUpcomingEventSelect, onShowAll: handleShowAllEvents, showAllButtonText: nextEventsSettings.showAllButtonText, showAllButton: nextEventsSettings.showAllButton, isLoadingEventDetails: isLoadingEventDetails, isLoadingShowAll: isLoadingShowAll, isLoading: isLoading }), shouldRenderBookingForm && eventDetails && (u$2(BookingForm, { config: config, eventDetails: eventDetails, stripePromise: stripePromise, onSuccess: handleBookingSuccess, onError: handleBookingError, onBackToEventInstances: () => {
13129
+ setCurrentStep("eventTypes");
13130
+ setShowingPreview(true);
13131
+ setEventDetails(null);
13132
+ }, onBackToEventTypes: () => {
13133
+ setCurrentStep("eventTypes");
13134
+ setShowingPreview(true);
13135
+ setEventDetails(null);
13136
+ }, selectedEventType: selectedEventType, selectedEventInstance: selectedEventInstance, isOpen: currentStep === "booking" && !!eventDetails, onClose: () => {
13137
+ setCurrentStep("eventTypes");
13138
+ setShowingPreview(true);
13139
+ setEventDetails(null);
13140
+ }, systemConfig: systemConfig })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13141
+ setIsSuccess(false);
13142
+ setCurrentStep("eventTypes");
13143
+ setShowingPreview(true);
13144
+ // Reset state
13145
+ setSuccessPaymentIntentId(null);
13146
+ // Reset lazy loading flags
13147
+ setShouldRenderInstanceSelection(false);
13148
+ setShouldRenderBookingForm(false);
13149
+ // Clean up URL to remove Stripe parameters
13150
+ const url = new URL(window.location.href);
13151
+ url.searchParams.delete("payment_intent");
13152
+ url.searchParams.delete("payment_intent_client_secret");
13153
+ url.searchParams.delete("redirect_status");
13154
+ window.history.replaceState({}, "", url.toString());
13155
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (u$2(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12440
13156
  }
12441
13157
  if (viewMode === "next-events" && !showingPreview && currentStep === "eventInstances") {
12442
13158
  // Show all events for the single event type
12443
- return (u$2(StyleProvider, { config: config, children: [shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
12444
- setShowingPreview(true);
12445
- setCurrentStep("eventTypes");
12446
- }, isOpen: currentStep === "eventInstances", onClose: () => {
12447
- setShowingPreview(true);
12448
- setCurrentStep("eventTypes");
12449
- }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12450
- setIsSuccess(false);
12451
- setCurrentStep("eventTypes");
12452
- setShowingPreview(true);
12453
- // Reset state
12454
- setSuccessPaymentIntentId(null);
12455
- // Reset lazy loading flags
12456
- setShouldRenderInstanceSelection(false);
12457
- setShouldRenderBookingForm(false);
12458
- // Clean up URL to remove Stripe parameters
12459
- const url = new URL(window.location.href);
12460
- url.searchParams.delete("payment_intent");
12461
- url.searchParams.delete("payment_intent_client_secret");
12462
- url.searchParams.delete("redirect_status");
12463
- window.history.replaceState({}, "", url.toString());
12464
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13159
+ return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => {
13160
+ setShowingPreview(true);
13161
+ setCurrentStep("eventTypes");
13162
+ }, isOpen: currentStep === "eventInstances", onClose: () => {
13163
+ setShowingPreview(true);
13164
+ setCurrentStep("eventTypes");
13165
+ }, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13166
+ setIsSuccess(false);
13167
+ setCurrentStep("eventTypes");
13168
+ setShowingPreview(true);
13169
+ // Reset state
13170
+ setSuccessPaymentIntentId(null);
13171
+ // Reset lazy loading flags
13172
+ setShouldRenderInstanceSelection(false);
13173
+ setShouldRenderBookingForm(false);
13174
+ // Clean up URL to remove Stripe parameters
13175
+ const url = new URL(window.location.href);
13176
+ url.searchParams.delete("payment_intent");
13177
+ url.searchParams.delete("payment_intent_client_secret");
13178
+ url.searchParams.delete("redirect_status");
13179
+ window.history.replaceState({}, "", url.toString());
13180
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (u$2(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12465
13181
  }
12466
13182
  if (viewMode === "button" && (isSingleEventTypeMode || isDirectInstanceMode)) {
12467
13183
  // Button mode - show button that opens sidebar/booking directly
12468
- return (u$2(StyleProvider, { config: config, children: u$2("div", { style: {
12469
- display: "flex",
12470
- justifyContent: "center",
12471
- alignItems: "center",
12472
- minHeight: "120px",
12473
- }, children: [u$2("button", { type: "button", style: {
12474
- backgroundColor: "var(--bw-highlight-color)",
12475
- color: "white",
12476
- padding: "16px 32px",
12477
- border: "none",
12478
- borderRadius: "var(--bw-border-radius)",
12479
- fontSize: "18px",
12480
- fontWeight: 600,
12481
- fontFamily: "var(--bw-font-family)",
12482
- boxShadow: "var(--bw-shadow-md)",
12483
- cursor: "pointer",
12484
- }, onClick: () => {
12485
- if (isDirectInstanceMode) {
12486
- setCurrentStep("booking");
12487
- setShouldRenderBookingForm(true);
12488
- }
12489
- else {
12490
- setSidebarOpen(true);
12491
- setShouldRenderInstanceSelection(true);
12492
- }
12493
- }, children: config.buttonText ||
12494
- (isDirectInstanceMode ? "Jetzt buchen" : "Jetzt Termin auswählen") }), shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen, onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12495
- setIsSuccess(false);
12496
- setCurrentStep("eventTypes");
12497
- setSidebarOpen(false);
12498
- // Reset state
12499
- setSuccessPaymentIntentId(null);
12500
- // Reset lazy loading flags
12501
- setShouldRenderInstanceSelection(false);
12502
- setShouldRenderBookingForm(false);
12503
- // Clean up URL to remove Stripe parameters
12504
- const url = new URL(window.location.href);
12505
- url.searchParams.delete("payment_intent");
12506
- url.searchParams.delete("payment_intent_client_secret");
12507
- url.searchParams.delete("redirect_status");
12508
- window.history.replaceState({}, "", url.toString());
12509
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }) }));
13184
+ return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, style: {
13185
+ display: "flex",
13186
+ justifyContent: "center",
13187
+ alignItems: "center",
13188
+ minHeight: "120px",
13189
+ }, children: [u$2("button", { type: "button", style: {
13190
+ backgroundColor: "var(--bw-highlight-color)",
13191
+ color: "white",
13192
+ padding: "16px 32px",
13193
+ border: "none",
13194
+ borderRadius: "var(--bw-border-radius)",
13195
+ fontSize: "18px",
13196
+ fontWeight: 600,
13197
+ fontFamily: "var(--bw-font-family)",
13198
+ boxShadow: "var(--bw-shadow-md)",
13199
+ cursor: "pointer",
13200
+ }, onClick: () => {
13201
+ if (isDirectInstanceMode) {
13202
+ setCurrentStep("booking");
13203
+ setShouldRenderBookingForm(true);
13204
+ }
13205
+ else {
13206
+ setSidebarOpen(true);
13207
+ setShouldRenderInstanceSelection(true);
13208
+ }
13209
+ }, children: config.buttonText ||
13210
+ (isDirectInstanceMode ? "Jetzt buchen" : "Jetzt Termin auswählen") }), shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen, onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13211
+ setIsSuccess(false);
13212
+ setCurrentStep("eventTypes");
13213
+ setSidebarOpen(false);
13214
+ // Reset state
13215
+ setSuccessPaymentIntentId(null);
13216
+ // Reset lazy loading flags
13217
+ setShouldRenderInstanceSelection(false);
13218
+ setShouldRenderBookingForm(false);
13219
+ // Clean up URL to remove Stripe parameters
13220
+ const url = new URL(window.location.href);
13221
+ url.searchParams.delete("payment_intent");
13222
+ url.searchParams.delete("payment_intent_client_secret");
13223
+ url.searchParams.delete("redirect_status");
13224
+ window.history.replaceState({}, "", url.toString());
13225
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (u$2(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12510
13226
  }
12511
13227
  // Cards mode (default) - show event type selection
12512
13228
  const cardsView = (u$2(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, isLoading: isLoading, skeletonCount: getSkeletonCount() }));
@@ -12539,21 +13255,21 @@
12539
13255
  };
12540
13256
  };
12541
13257
  const backHandlers = getBackHandlers();
12542
- return (u$2(StyleProvider, { config: config, children: [cardsView, shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
12543
- setIsSuccess(false);
12544
- setCurrentStep("eventTypes");
12545
- // Reset state
12546
- setSuccessPaymentIntentId(null);
12547
- // Reset lazy loading flags
12548
- setShouldRenderInstanceSelection(false);
12549
- setShouldRenderBookingForm(false);
12550
- // Clean up URL to remove Stripe parameters
12551
- const url = new URL(window.location.href);
12552
- url.searchParams.delete("payment_intent");
12553
- url.searchParams.delete("payment_intent_client_secret");
12554
- url.searchParams.delete("redirect_status");
12555
- window.history.replaceState({}, "", url.toString());
12556
- }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }));
13258
+ return (u$2(StyleProvider, { config: config, children: [u$2("div", { ref: setWidgetContainerRef, children: [cardsView, shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: handleBackToEventTypes, isOpen: currentStep === "eventInstances", onClose: handleBackToEventTypes, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails })), shouldRenderBookingForm && eventDetails && (u$2(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 })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
13259
+ setIsSuccess(false);
13260
+ setCurrentStep("eventTypes");
13261
+ // Reset state
13262
+ setSuccessPaymentIntentId(null);
13263
+ // Reset lazy loading flags
13264
+ setShouldRenderInstanceSelection(false);
13265
+ setShouldRenderBookingForm(false);
13266
+ // Clean up URL to remove Stripe parameters
13267
+ const url = new URL(window.location.href);
13268
+ url.searchParams.delete("payment_intent");
13269
+ url.searchParams.delete("payment_intent_client_secret");
13270
+ url.searchParams.delete("redirect_status");
13271
+ window.history.replaceState({}, "", url.toString());
13272
+ }, config: config, onError: setError, paymentIntentId: successPaymentIntentId })] }), showPromoDialog && (u$2(PromoDialog, { onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
12557
13273
  }
12558
13274
 
12559
13275
  // Export init function for vanilla JS usage with Preact