@bigz-app/booking-widget 1.4.5 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/booking-widget.js +710 -112
- package/dist/booking-widget.js.map +1 -1
- package/dist/components/UniversalBookingWidget.d.ts +21 -105
- package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
- package/dist/components/booking/MolliePaymentForm.d.ts +11 -1
- package/dist/components/booking/MolliePaymentForm.d.ts.map +1 -1
- package/dist/components/booking/StripePaymentForm.d.ts +11 -1
- package/dist/components/booking/StripePaymentForm.d.ts.map +1 -1
- package/dist/components/events/EventInstanceSelection.d.ts +3 -1
- package/dist/components/events/EventInstanceSelection.d.ts.map +1 -1
- package/dist/components/events/EventTypeSelection.d.ts +17 -1
- package/dist/components/events/EventTypeSelection.d.ts.map +1 -1
- package/dist/components/events/FreeformSelection.d.ts +49 -0
- package/dist/components/events/FreeformSelection.d.ts.map +1 -0
- package/dist/components/events/NextEventsPreview.d.ts +1 -1
- package/dist/components/events/NextEventsPreview.d.ts.map +1 -1
- package/dist/components/events/SpecialsView.d.ts +1 -1
- package/dist/components/events/SpecialsView.d.ts.map +1 -1
- package/dist/components/events/index.d.ts +1 -0
- package/dist/components/events/index.d.ts.map +1 -1
- package/dist/components/events/types.d.ts +42 -0
- package/dist/components/events/types.d.ts.map +1 -0
- package/dist/components/upsells/UpsellCard.d.ts +1 -1
- package/dist/components/upsells/UpsellCard.d.ts.map +1 -1
- package/dist/components/upsells/UpsellsStep.d.ts +2 -44
- package/dist/components/upsells/UpsellsStep.d.ts.map +1 -1
- package/dist/components/upsells/types.d.ts +44 -0
- package/dist/components/upsells/types.d.ts.map +1 -0
- package/dist/components/voucher/VoucherIntegration.d.ts +3 -2
- package/dist/components/voucher/VoucherIntegration.d.ts.map +1 -1
- package/dist/components/voucher/VoucherPurchaseForm.d.ts +9 -16
- package/dist/components/voucher/VoucherPurchaseForm.d.ts.map +1 -1
- package/dist/components/voucher/index.d.ts +1 -1
- package/dist/components/voucher/index.d.ts.map +1 -1
- package/dist/components/voucher/types.d.ts +15 -0
- package/dist/components/voucher/types.d.ts.map +1 -0
- package/dist/components/voucher/useVoucherConfig.d.ts +6 -0
- package/dist/components/voucher/useVoucherConfig.d.ts.map +1 -1
- package/dist/config.d.ts +66 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/index.cjs +710 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +710 -112
- package/dist/index.esm.js.map +1 -1
- package/dist/styles/StyleProvider.d.ts +1 -1
- package/dist/styles/StyleProvider.d.ts.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/booking-widget.js
CHANGED
|
@@ -207,6 +207,10 @@
|
|
|
207
207
|
"booking.stepUpsells": "Extras",
|
|
208
208
|
"booking.stepDetails": "Angaben",
|
|
209
209
|
"booking.stepPayment": "Zahlung",
|
|
210
|
+
"booking.steps": "{{count}} Schritt(e)",
|
|
211
|
+
"booking.freeformUnitsAvailable": "{{count}} Einheiten verfuegbar",
|
|
212
|
+
"booking.freeformNotAvailable": "Das gewaehlte Zeitfenster ist nicht verfuegbar",
|
|
213
|
+
"booking.freeformMissingConfig": "Die Freeform-Konfiguration fuer diesen Event-Typ fehlt.",
|
|
210
214
|
// Booking summary
|
|
211
215
|
"summary.title": "Buchungszusammenfassung",
|
|
212
216
|
"summary.subtotal": "Zwischensumme:",
|
|
@@ -262,6 +266,13 @@
|
|
|
262
266
|
"voucher.monetaryTypeDesc": "Beliebigen Betrag wählen",
|
|
263
267
|
"voucher.eventType": "Erlebnisgutschein",
|
|
264
268
|
"voucher.eventTypeDesc": "Für ein bestimmtes Erlebnis",
|
|
269
|
+
"voucher.categoryType": "Kategoriegutschein",
|
|
270
|
+
"voucher.categoryTypeDesc": "Für ein beliebiges Erlebnis einer Kategorie",
|
|
271
|
+
"voucher.categoryVoucher": "Kategoriegutschein",
|
|
272
|
+
"voucher.selectCategory": "Kategorie wählen",
|
|
273
|
+
"voucher.categoryLabel": "Kategorie",
|
|
274
|
+
"voucher.selectCategoryPlaceholder": "Kategorie auswählen...",
|
|
275
|
+
"voucher.categoryAmount": "Gutscheinwert",
|
|
265
276
|
"voucher.selectAmount": "Betrag wählen",
|
|
266
277
|
"voucher.customAmount": "Oder eigenen Betrag eingeben",
|
|
267
278
|
"voucher.amountRange": "Betrag muss zwischen {{min}} und {{max}} liegen",
|
|
@@ -515,6 +526,10 @@
|
|
|
515
526
|
"booking.stepUpsells": "Extras",
|
|
516
527
|
"booking.stepDetails": "Details",
|
|
517
528
|
"booking.stepPayment": "Payment",
|
|
529
|
+
"booking.steps": "{{count}} step(s)",
|
|
530
|
+
"booking.freeformUnitsAvailable": "{{count}} units available",
|
|
531
|
+
"booking.freeformNotAvailable": "Selected window is not available",
|
|
532
|
+
"booking.freeformMissingConfig": "Missing freeform configuration for this event type.",
|
|
518
533
|
// Booking summary
|
|
519
534
|
"summary.title": "Booking Summary",
|
|
520
535
|
"summary.subtotal": "Subtotal:",
|
|
@@ -570,6 +585,13 @@
|
|
|
570
585
|
"voucher.monetaryTypeDesc": "Choose any amount",
|
|
571
586
|
"voucher.eventType": "Event Voucher",
|
|
572
587
|
"voucher.eventTypeDesc": "For a specific experience",
|
|
588
|
+
"voucher.categoryType": "Category Voucher",
|
|
589
|
+
"voucher.categoryTypeDesc": "For any experience in a category",
|
|
590
|
+
"voucher.categoryVoucher": "Category Voucher",
|
|
591
|
+
"voucher.selectCategory": "Select Category",
|
|
592
|
+
"voucher.categoryLabel": "Category",
|
|
593
|
+
"voucher.selectCategoryPlaceholder": "Choose a category...",
|
|
594
|
+
"voucher.categoryAmount": "Voucher Value",
|
|
573
595
|
"voucher.selectAmount": "Select Amount",
|
|
574
596
|
"voucher.customAmount": "Or enter custom amount",
|
|
575
597
|
"voucher.amountRange": "Amount must be between {{min}} and {{max}}",
|
|
@@ -757,6 +779,21 @@
|
|
|
757
779
|
"instances.bestPrice": "¡¡¡mejor precio!!!",
|
|
758
780
|
"instances.goodPrice": "buen precio",
|
|
759
781
|
"instances.oclock": "",
|
|
782
|
+
// Lista de espera
|
|
783
|
+
"waitlist.joinCta": "Lista de espera",
|
|
784
|
+
"waitlist.title": "Apuntarse a la lista de espera",
|
|
785
|
+
"waitlist.subtitle": "{{name}} está agotado. Deja tus datos y te contactaremos si se libera un lugar.",
|
|
786
|
+
"waitlist.name": "Nombre",
|
|
787
|
+
"waitlist.email": "Correo electrónico",
|
|
788
|
+
"waitlist.phone": "Teléfono (opcional)",
|
|
789
|
+
"waitlist.requiredFields": "Por favor, introduce tu nombre y correo electrónico.",
|
|
790
|
+
"waitlist.join": "Apuntarse",
|
|
791
|
+
"waitlist.submitting": "Apuntando...",
|
|
792
|
+
"waitlist.cancel": "Cancelar",
|
|
793
|
+
"waitlist.submitError": "Algo salió mal. Por favor, inténtalo de nuevo.",
|
|
794
|
+
"waitlist.successTitle": "¡Estás en la lista!",
|
|
795
|
+
"waitlist.successMessage": "Eres el número {{position}} en la lista de espera. Te contactaremos si se libera un lugar.",
|
|
796
|
+
"waitlist.done": "Listo",
|
|
760
797
|
// Next events preview
|
|
761
798
|
"nextEvents.title": "Próximas fechas disponibles",
|
|
762
799
|
"nextEvents.subtitle": "Selecciona una fecha o consulta todas las fechas disponibles",
|
|
@@ -860,6 +897,13 @@
|
|
|
860
897
|
"voucher.monetaryTypeDesc": "Elige cualquier cantidad",
|
|
861
898
|
"voucher.eventType": "Vale de experiencia",
|
|
862
899
|
"voucher.eventTypeDesc": "Para una experiencia específica",
|
|
900
|
+
"voucher.categoryType": "Vale de categoría",
|
|
901
|
+
"voucher.categoryTypeDesc": "Para cualquier experiencia de una categoría",
|
|
902
|
+
"voucher.categoryVoucher": "Vale de categoría",
|
|
903
|
+
"voucher.selectCategory": "Seleccionar categoría",
|
|
904
|
+
"voucher.categoryLabel": "Categoría",
|
|
905
|
+
"voucher.selectCategoryPlaceholder": "Elige una categoría...",
|
|
906
|
+
"voucher.categoryAmount": "Valor del vale",
|
|
863
907
|
"voucher.selectAmount": "Selecciona el importe",
|
|
864
908
|
"voucher.customAmount": "O introduce un importe personalizado",
|
|
865
909
|
"voucher.amountRange": "El importe debe estar entre {{min}} y {{max}}",
|
|
@@ -1047,6 +1091,21 @@
|
|
|
1047
1091
|
"instances.bestPrice": "melhor preço !!!",
|
|
1048
1092
|
"instances.goodPrice": "bom preço",
|
|
1049
1093
|
"instances.oclock": "",
|
|
1094
|
+
// Lista de espera
|
|
1095
|
+
"waitlist.joinCta": "Lista de espera",
|
|
1096
|
+
"waitlist.title": "Entrar na lista de espera",
|
|
1097
|
+
"waitlist.subtitle": "{{name}} está esgotado. Deixe os seus dados e entraremos em contacto se surgir uma vaga.",
|
|
1098
|
+
"waitlist.name": "Nome",
|
|
1099
|
+
"waitlist.email": "E-mail",
|
|
1100
|
+
"waitlist.phone": "Telefone (opcional)",
|
|
1101
|
+
"waitlist.requiredFields": "Por favor, introduza o seu nome e e-mail.",
|
|
1102
|
+
"waitlist.join": "Inscrever-se",
|
|
1103
|
+
"waitlist.submitting": "A inscrever...",
|
|
1104
|
+
"waitlist.cancel": "Cancelar",
|
|
1105
|
+
"waitlist.submitError": "Algo correu mal. Por favor, tente novamente.",
|
|
1106
|
+
"waitlist.successTitle": "Está na lista!",
|
|
1107
|
+
"waitlist.successMessage": "É o número {{position}} na lista de espera. Entraremos em contacto se surgir uma vaga.",
|
|
1108
|
+
"waitlist.done": "Concluído",
|
|
1050
1109
|
// Next events preview
|
|
1051
1110
|
"nextEvents.title": "Próximas datas disponíveis",
|
|
1052
1111
|
"nextEvents.subtitle": "Selecione uma data ou veja todas as datas disponíveis",
|
|
@@ -1150,6 +1209,13 @@
|
|
|
1150
1209
|
"voucher.monetaryTypeDesc": "Escolha qualquer quantia",
|
|
1151
1210
|
"voucher.eventType": "Vale de experiência",
|
|
1152
1211
|
"voucher.eventTypeDesc": "Para uma experiência específica",
|
|
1212
|
+
"voucher.categoryType": "Vale de categoria",
|
|
1213
|
+
"voucher.categoryTypeDesc": "Para qualquer experiência de uma categoria",
|
|
1214
|
+
"voucher.categoryVoucher": "Vale de categoria",
|
|
1215
|
+
"voucher.selectCategory": "Selecionar categoria",
|
|
1216
|
+
"voucher.categoryLabel": "Categoria",
|
|
1217
|
+
"voucher.selectCategoryPlaceholder": "Escolha uma categoria...",
|
|
1218
|
+
"voucher.categoryAmount": "Valor do vale",
|
|
1153
1219
|
"voucher.selectAmount": "Selecione o valor",
|
|
1154
1220
|
"voucher.customAmount": "Ou introduza um valor personalizado",
|
|
1155
1221
|
"voucher.amountRange": "O valor deve estar entre {{min}} e {{max}}",
|
|
@@ -1337,6 +1403,21 @@
|
|
|
1337
1403
|
"instances.bestPrice": "bästa pris !!!",
|
|
1338
1404
|
"instances.goodPrice": "bra pris",
|
|
1339
1405
|
"instances.oclock": "",
|
|
1406
|
+
// Väntelista
|
|
1407
|
+
"waitlist.joinCta": "Ställ dig i kö",
|
|
1408
|
+
"waitlist.title": "Ställ dig i kö",
|
|
1409
|
+
"waitlist.subtitle": "{{name}} är fullbokat. Lämna dina uppgifter så kontaktar vi dig om en plats blir ledig.",
|
|
1410
|
+
"waitlist.name": "Namn",
|
|
1411
|
+
"waitlist.email": "E-post",
|
|
1412
|
+
"waitlist.phone": "Telefon (valfritt)",
|
|
1413
|
+
"waitlist.requiredFields": "Ange ditt namn och din e-postadress.",
|
|
1414
|
+
"waitlist.join": "Ställ dig i kö",
|
|
1415
|
+
"waitlist.submitting": "Anmäler...",
|
|
1416
|
+
"waitlist.cancel": "Avbryt",
|
|
1417
|
+
"waitlist.submitError": "Något gick fel. Försök igen.",
|
|
1418
|
+
"waitlist.successTitle": "Du står i kön!",
|
|
1419
|
+
"waitlist.successMessage": "Du är nummer {{position}} på väntelistan. Vi hör av oss om en plats blir ledig.",
|
|
1420
|
+
"waitlist.done": "Klar",
|
|
1340
1421
|
// Next events preview
|
|
1341
1422
|
"nextEvents.title": "Nästa tillgängliga datum",
|
|
1342
1423
|
"nextEvents.subtitle": "Välj ett datum eller visa alla tillgängliga datum",
|
|
@@ -1440,6 +1521,13 @@
|
|
|
1440
1521
|
"voucher.monetaryTypeDesc": "Välj valfritt belopp",
|
|
1441
1522
|
"voucher.eventType": "Upplevelsebevis",
|
|
1442
1523
|
"voucher.eventTypeDesc": "För en specifik upplevelse",
|
|
1524
|
+
"voucher.categoryType": "Kategoripresent",
|
|
1525
|
+
"voucher.categoryTypeDesc": "För alla upplevelser i en kategori",
|
|
1526
|
+
"voucher.categoryVoucher": "Kategoripresent",
|
|
1527
|
+
"voucher.selectCategory": "Välj kategori",
|
|
1528
|
+
"voucher.categoryLabel": "Kategori",
|
|
1529
|
+
"voucher.selectCategoryPlaceholder": "Välj en kategori...",
|
|
1530
|
+
"voucher.categoryAmount": "Presentkortsvärde",
|
|
1443
1531
|
"voucher.selectAmount": "Välj belopp",
|
|
1444
1532
|
"voucher.customAmount": "Eller ange eget belopp",
|
|
1445
1533
|
"voucher.amountRange": "Beloppet måste vara mellan {{min}} och {{max}}",
|
|
@@ -6478,7 +6566,7 @@
|
|
|
6478
6566
|
document.head.appendChild(script);
|
|
6479
6567
|
});
|
|
6480
6568
|
}
|
|
6481
|
-
function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess: _onSuccess, onError, upsellSelections = [], mollieProfileId, mollieTestmode, }) {
|
|
6569
|
+
function MolliePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess: _onSuccess, onError, upsellSelections = [], mollieProfileId, mollieTestmode, freeformSelection, }) {
|
|
6482
6570
|
const t = useTranslations();
|
|
6483
6571
|
const { locale } = useLocale();
|
|
6484
6572
|
const [isLoading, setIsLoading] = d$1(false);
|
|
@@ -6492,7 +6580,9 @@
|
|
|
6492
6580
|
const cardFormRef = A$2(null);
|
|
6493
6581
|
const cardContainerRef = A$2(null);
|
|
6494
6582
|
const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
|
|
6495
|
-
const isFullyCoveredByGiftCards =
|
|
6583
|
+
const isFullyCoveredByGiftCards = freeformSelection
|
|
6584
|
+
? false
|
|
6585
|
+
: isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
|
|
6496
6586
|
const isCreditCard = selectedMethod === "creditcard";
|
|
6497
6587
|
y$1(() => {
|
|
6498
6588
|
if (isFullyCoveredByGiftCards)
|
|
@@ -6602,6 +6692,9 @@
|
|
|
6602
6692
|
return (u$2(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: _onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
6603
6693
|
}
|
|
6604
6694
|
const validateBeforePayment = () => {
|
|
6695
|
+
if (freeformSelection) {
|
|
6696
|
+
return null;
|
|
6697
|
+
}
|
|
6605
6698
|
const participantCount = formData.participants.filter((p) => p.name?.trim()).length;
|
|
6606
6699
|
const availableSpots = eventDetails.availableSpots || 0;
|
|
6607
6700
|
if (participantCount > availableSpots) {
|
|
@@ -6613,21 +6706,41 @@
|
|
|
6613
6706
|
return null;
|
|
6614
6707
|
};
|
|
6615
6708
|
const buildRequestData = (cardToken) => ({
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6709
|
+
...(freeformSelection
|
|
6710
|
+
? {
|
|
6711
|
+
eventTypeId: freeformSelection.eventTypeId,
|
|
6712
|
+
organizationId: config.organizationId,
|
|
6713
|
+
start: freeformSelection.start,
|
|
6714
|
+
end: freeformSelection.end,
|
|
6715
|
+
requestedUnits: freeformSelection.requestedUnits,
|
|
6716
|
+
amount: Math.round(totalAmount),
|
|
6717
|
+
currency: "EUR",
|
|
6718
|
+
customerName: freeformSelection.customerName.trim(),
|
|
6719
|
+
customerEmail: freeformSelection.customerEmail.trim(),
|
|
6720
|
+
customerPhone: freeformSelection.customerPhone?.trim(),
|
|
6721
|
+
comment: freeformSelection.comment?.trim(),
|
|
6722
|
+
locale,
|
|
6723
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6724
|
+
...(cardToken && { cardToken }),
|
|
6725
|
+
...(selectedMethod && !cardToken && { method: selectedMethod }),
|
|
6726
|
+
}
|
|
6727
|
+
: {
|
|
6728
|
+
eventInstanceId: config.eventInstanceId || eventDetails.id,
|
|
6729
|
+
organizationId: config.organizationId,
|
|
6730
|
+
amount: Math.round(totalAmount),
|
|
6731
|
+
currency: "EUR",
|
|
6732
|
+
participants: formData.participants.filter((p) => p.name?.trim()),
|
|
6733
|
+
discountCode: discountCode?.code,
|
|
6734
|
+
giftCardCodes: giftCards?.map((gc) => gc.code) || [],
|
|
6735
|
+
customerName: formData.customerName?.trim(),
|
|
6736
|
+
customerEmail: formData.customerEmail?.trim(),
|
|
6737
|
+
customerPhone: formData.customerPhone?.trim(),
|
|
6738
|
+
comment: formData.comment?.trim(),
|
|
6739
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
6740
|
+
...(cardToken && { cardToken }),
|
|
6741
|
+
...(selectedMethod && !cardToken && { method: selectedMethod }),
|
|
6742
|
+
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
6743
|
+
}),
|
|
6631
6744
|
});
|
|
6632
6745
|
const handleCardPayment = async () => {
|
|
6633
6746
|
if (!mollieRef.current)
|
|
@@ -6645,7 +6758,9 @@
|
|
|
6645
6758
|
setPaymentError(tokenError?.message || t("error.createPayment"));
|
|
6646
6759
|
return;
|
|
6647
6760
|
}
|
|
6648
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl,
|
|
6761
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, freeformSelection
|
|
6762
|
+
? "/booking/create-freeform-mollie-payment"
|
|
6763
|
+
: "/booking/create-mollie-payment"), {
|
|
6649
6764
|
method: "POST",
|
|
6650
6765
|
headers: createApiHeaders(config, locale),
|
|
6651
6766
|
body: JSON.stringify(createRequestBody(config, buildRequestData(token))),
|
|
@@ -6681,7 +6796,9 @@
|
|
|
6681
6796
|
setPaymentError(validationError);
|
|
6682
6797
|
return;
|
|
6683
6798
|
}
|
|
6684
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl,
|
|
6799
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, freeformSelection
|
|
6800
|
+
? "/booking/create-freeform-mollie-payment"
|
|
6801
|
+
: "/booking/create-mollie-payment"), {
|
|
6685
6802
|
method: "POST",
|
|
6686
6803
|
headers: createApiHeaders(config, locale),
|
|
6687
6804
|
body: JSON.stringify(createRequestBody(config, buildRequestData())),
|
|
@@ -6709,7 +6826,7 @@
|
|
|
6709
6826
|
? t("button.processingPayment")
|
|
6710
6827
|
: selectedMethodData
|
|
6711
6828
|
? t("payment.payWithMethod", { method: selectedMethodData.description })
|
|
6712
|
-
: totalAmount < eventDetails.price * formData.participants.filter((p) => p.name?.trim()).length
|
|
6829
|
+
: !freeformSelection && totalAmount < eventDetails.price * formData.participants.filter((p) => p.name?.trim()).length
|
|
6713
6830
|
? t("button.depositAndBook")
|
|
6714
6831
|
: t("button.bookNow");
|
|
6715
6832
|
const isPayDisabled = isLoading || !selectedMethod || (isCreditCard && !isMollieReady);
|
|
@@ -7016,12 +7133,18 @@
|
|
|
7016
7133
|
};
|
|
7017
7134
|
|
|
7018
7135
|
// Inner component that uses the Stripe hooks
|
|
7019
|
-
function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onError, }) {
|
|
7136
|
+
function PaymentFormInner({ eventDetails, formData, totalAmount, onSuccess, onError, freeformSelection, }) {
|
|
7020
7137
|
const t = useTranslations();
|
|
7021
|
-
const
|
|
7022
|
-
const
|
|
7023
|
-
|
|
7138
|
+
const isFreeform = Boolean(freeformSelection);
|
|
7139
|
+
const participantCount = isFreeform
|
|
7140
|
+
? 1
|
|
7141
|
+
: formData.participants.filter((p) => p.name.trim()).length;
|
|
7142
|
+
const fullAmount = isFreeform ? totalAmount : eventDetails.price * participantCount;
|
|
7143
|
+
const submitLabel = !isFreeform && totalAmount < fullAmount ? t("button.depositAndBook") : t("button.bookNow");
|
|
7024
7144
|
return (u$2(StripeElementsPaymentForm, { onValidate: () => {
|
|
7145
|
+
if (isFreeform) {
|
|
7146
|
+
return null;
|
|
7147
|
+
}
|
|
7025
7148
|
const availableSpots = eventDetails.availableSpots || 0;
|
|
7026
7149
|
if (participantCount > availableSpots) {
|
|
7027
7150
|
return t("payment.tooManyParticipants", { count: participantCount, available: availableSpots });
|
|
@@ -7043,7 +7166,7 @@
|
|
|
7043
7166
|
},
|
|
7044
7167
|
}, submitContent: u$2(k$3, { children: submitLabel }), loadingContent: u$2(k$3, { children: [spinner("var(--bw-surface-color)"), " ", t("button.processingPayment")] }) }));
|
|
7045
7168
|
}
|
|
7046
|
-
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripeAppearance, upsellSelections = [], }) {
|
|
7169
|
+
function StripePaymentForm({ config, eventDetails, formData, totalAmount, discountCode, giftCards, onSuccess, onError, systemConfig, stripeAppearance, upsellSelections = [], freeformSelection, }) {
|
|
7047
7170
|
const t = useTranslations();
|
|
7048
7171
|
const { locale } = useLocale();
|
|
7049
7172
|
const [clientSecret, setClientSecret] = d$1(null);
|
|
@@ -7063,7 +7186,9 @@
|
|
|
7063
7186
|
return loadStripe(systemConfig.stripePublishableKey, stripeOptions);
|
|
7064
7187
|
}, [systemConfig?.stripePublishableKey, systemConfig?.connectedAccountId, locale]);
|
|
7065
7188
|
const storageKey = typeof window !== "undefined"
|
|
7066
|
-
?
|
|
7189
|
+
? freeformSelection
|
|
7190
|
+
? `bw_pi_freeform_${config?.organizationId}_${freeformSelection.eventTypeId}_${freeformSelection.start}_${freeformSelection.end}_${freeformSelection.requestedUnits}`
|
|
7191
|
+
: `bw_pi_${config?.organizationId}_${config?.eventInstanceId || eventDetails?.id}`
|
|
7067
7192
|
: "";
|
|
7068
7193
|
const PAYMENT_INTENT_TTL = 24 * 60 * 60 * 1000;
|
|
7069
7194
|
function loadPersistedPaymentIntent() {
|
|
@@ -7118,48 +7243,82 @@
|
|
|
7118
7243
|
}, [paymentIntentId]);
|
|
7119
7244
|
y$1(() => {
|
|
7120
7245
|
const createStripePayment = async () => {
|
|
7121
|
-
if (!systemConfig || !eventDetails
|
|
7246
|
+
if (!systemConfig || !eventDetails) {
|
|
7247
|
+
return;
|
|
7248
|
+
}
|
|
7249
|
+
if (freeformSelection) {
|
|
7250
|
+
if (!freeformSelection.customerEmail?.trim() ||
|
|
7251
|
+
!freeformSelection.customerName?.trim() ||
|
|
7252
|
+
!freeformSelection.start ||
|
|
7253
|
+
!freeformSelection.end) {
|
|
7254
|
+
return;
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
else if (!formData.participants?.length) {
|
|
7122
7258
|
return;
|
|
7123
7259
|
}
|
|
7124
7260
|
const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
|
|
7125
|
-
if (
|
|
7261
|
+
if (!freeformSelection &&
|
|
7262
|
+
(participantCount === 0 || !formData.customerEmail?.trim() || !formData.customerName?.trim())) {
|
|
7126
7263
|
return;
|
|
7127
7264
|
}
|
|
7128
7265
|
setIsCreatingPaymentIntent(true);
|
|
7129
7266
|
setPaymentError(null);
|
|
7130
7267
|
try {
|
|
7131
|
-
const
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7268
|
+
const endpoint = freeformSelection
|
|
7269
|
+
? "/booking/create-freeform-stripe-payment"
|
|
7270
|
+
: "/booking/create-stripe-payment";
|
|
7271
|
+
const requestData = freeformSelection
|
|
7272
|
+
? {
|
|
7273
|
+
eventTypeId: freeformSelection.eventTypeId,
|
|
7274
|
+
organizationId: config.organizationId,
|
|
7275
|
+
start: freeformSelection.start,
|
|
7276
|
+
end: freeformSelection.end,
|
|
7277
|
+
requestedUnits: freeformSelection.requestedUnits,
|
|
7278
|
+
amount: Math.round(totalAmount),
|
|
7279
|
+
currency: "eur",
|
|
7280
|
+
customerName: freeformSelection.customerName.trim(),
|
|
7281
|
+
customerEmail: freeformSelection.customerEmail.trim(),
|
|
7282
|
+
customerPhone: freeformSelection.customerPhone?.trim(),
|
|
7283
|
+
comment: freeformSelection.comment?.trim(),
|
|
7284
|
+
locale,
|
|
7285
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
7286
|
+
...(paymentIntentId && { paymentIntentId }),
|
|
7287
|
+
}
|
|
7288
|
+
: {
|
|
7289
|
+
eventInstanceId: config.eventInstanceId || eventDetails.id,
|
|
7290
|
+
organizationId: config.organizationId,
|
|
7291
|
+
amount: Math.round(totalAmount),
|
|
7292
|
+
currency: "eur",
|
|
7293
|
+
participants: formData.participants.filter((p) => p.name?.trim()),
|
|
7294
|
+
discountCode: discountCode?.code,
|
|
7295
|
+
giftCardCodes: giftCards?.map((gc) => gc.code) || [],
|
|
7296
|
+
customerName: formData.customerName?.trim(),
|
|
7297
|
+
customerEmail: formData.customerEmail?.trim(),
|
|
7298
|
+
customerPhone: formData.customerPhone?.trim(),
|
|
7299
|
+
comment: formData.comment?.trim(),
|
|
7300
|
+
...(config.partnerContractId && { partnerContractId: config.partnerContractId }),
|
|
7301
|
+
...(paymentIntentId && { paymentIntentId }),
|
|
7302
|
+
...(upsellSelections && upsellSelections.length > 0 && { upsellSelections }),
|
|
7303
|
+
};
|
|
7150
7304
|
if (!requestData.organizationId) {
|
|
7151
7305
|
throw new Error("Organization ID is required");
|
|
7152
7306
|
}
|
|
7153
|
-
if (
|
|
7307
|
+
if (requestData.amount === undefined || requestData.amount < 0) {
|
|
7154
7308
|
throw new Error("Valid amount is required");
|
|
7155
7309
|
}
|
|
7156
|
-
if (!requestData
|
|
7310
|
+
if (!freeformSelection && "eventInstanceId" in requestData && !requestData.eventInstanceId) {
|
|
7311
|
+
throw new Error("Event instance ID is required");
|
|
7312
|
+
}
|
|
7313
|
+
if (!freeformSelection &&
|
|
7314
|
+
"participants" in requestData &&
|
|
7315
|
+
(!requestData.participants || requestData.participants.length === 0)) {
|
|
7157
7316
|
throw new Error("At least one participant is required");
|
|
7158
7317
|
}
|
|
7159
7318
|
if (!requestData.customerEmail) {
|
|
7160
7319
|
throw new Error("Customer email is required");
|
|
7161
7320
|
}
|
|
7162
|
-
const response = await fetch(getApiUrl(config.apiBaseUrl,
|
|
7321
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, endpoint), {
|
|
7163
7322
|
method: "POST",
|
|
7164
7323
|
headers: createApiHeaders(config, locale),
|
|
7165
7324
|
body: JSON.stringify(createRequestBody(config, requestData)),
|
|
@@ -7204,9 +7363,13 @@
|
|
|
7204
7363
|
giftCards,
|
|
7205
7364
|
config,
|
|
7206
7365
|
upsellSelections,
|
|
7366
|
+
freeformSelection,
|
|
7367
|
+
locale,
|
|
7207
7368
|
]);
|
|
7208
7369
|
const participantCount = formData.participants?.filter((p) => p.name?.trim()).length || 0;
|
|
7209
|
-
const isFullyCoveredByGiftCards =
|
|
7370
|
+
const isFullyCoveredByGiftCards = freeformSelection
|
|
7371
|
+
? false
|
|
7372
|
+
: isGiftCardFullyCovered(giftCards, eventDetails?.price || 0, participantCount, discountCode?.discountAmount || 0);
|
|
7210
7373
|
if (isFullyCoveredByGiftCards && totalAmount <= 0) {
|
|
7211
7374
|
return (u$2(GiftCardOnlyBooking, { config: config, eventDetails: eventDetails, formData: formData, discountCode: discountCode, giftCards: giftCards, onSuccess: onSuccess, onError: onError, upsellSelections: upsellSelections }));
|
|
7212
7375
|
}
|
|
@@ -7245,7 +7408,7 @@
|
|
|
7245
7408
|
setPaymentIntentId(null);
|
|
7246
7409
|
setClientSecret(null);
|
|
7247
7410
|
onSuccess(result);
|
|
7248
|
-
}, onError: onError }) }));
|
|
7411
|
+
}, onError: onError, ...(freeformSelection ? { freeformSelection } : {}) }) }));
|
|
7249
7412
|
}
|
|
7250
7413
|
|
|
7251
7414
|
const HOLD_DURATION_SECONDS = 15 * 60;
|
|
@@ -13505,20 +13668,22 @@
|
|
|
13505
13668
|
const labelStyles = formStyles.label;
|
|
13506
13669
|
const inputStyles = formStyles.input;
|
|
13507
13670
|
const errorTextStyles = formStyles.error;
|
|
13508
|
-
function VoucherPurchaseForm({ config, voucherConfig, eventTypes, isOpen, onClose, onSuccess, onError, systemConfig, preselectedEventTypeId, isLoadingEventTypes = false, }) {
|
|
13671
|
+
function VoucherPurchaseForm({ config, voucherConfig, eventTypes, categories, isOpen, onClose, onSuccess, onError, systemConfig, preselectedEventTypeId, isLoadingEventTypes = false, }) {
|
|
13509
13672
|
const t = useTranslations();
|
|
13510
13673
|
const { locale } = useLocale();
|
|
13511
13674
|
const paymentProvider = systemConfig?.paymentProvider ?? "stripe";
|
|
13512
13675
|
// Form state
|
|
13513
|
-
// Show voucher type selection if both monetary and event vouchers are allowed
|
|
13514
|
-
// The event type selection will handle the case when no event types are available
|
|
13515
13676
|
const canUseMonetaryVoucherType = voucherConfig.allowMonetaryVouchers !== false;
|
|
13516
13677
|
const canUseEventVoucherType = voucherConfig.allowEventVouchers;
|
|
13517
|
-
const
|
|
13678
|
+
const canUseCategoryVoucherType = canUseEventVoucherType && categories.length > 0;
|
|
13679
|
+
const availableTypeCount = [canUseMonetaryVoucherType, canUseEventVoucherType, canUseCategoryVoucherType].filter(Boolean).length;
|
|
13680
|
+
const showVoucherTypeSelection = availableTypeCount > 1 && !isLoadingEventTypes;
|
|
13518
13681
|
const [voucherType, setVoucherType] = d$1(canUseMonetaryVoucherType ? "monetary" : "event");
|
|
13519
13682
|
const [monetaryAmount, setMonetaryAmount] = d$1(voucherConfig.monetaryPresets[2] || 10000);
|
|
13520
13683
|
const [selectedEventTypeId, setSelectedEventTypeId] = d$1(null);
|
|
13521
13684
|
const [eventQuantity, setEventQuantity] = d$1(1);
|
|
13685
|
+
const [selectedCategoryId, setSelectedCategoryId] = d$1(null);
|
|
13686
|
+
const [categoryAmount, setCategoryAmount] = d$1(10000);
|
|
13522
13687
|
const [recipientName, setRecipientName] = d$1("");
|
|
13523
13688
|
const [message, setMessage] = d$1("");
|
|
13524
13689
|
const [customerName, setCustomerName] = d$1("");
|
|
@@ -13578,6 +13743,9 @@
|
|
|
13578
13743
|
if (voucherType === "monetary") {
|
|
13579
13744
|
return monetaryAmount;
|
|
13580
13745
|
}
|
|
13746
|
+
else if (voucherType === "category") {
|
|
13747
|
+
return categoryAmount;
|
|
13748
|
+
}
|
|
13581
13749
|
else {
|
|
13582
13750
|
const eventType = eventTypes.find((et) => et.id === selectedEventTypeId);
|
|
13583
13751
|
if (eventType) {
|
|
@@ -13585,7 +13753,7 @@
|
|
|
13585
13753
|
}
|
|
13586
13754
|
return 0;
|
|
13587
13755
|
}
|
|
13588
|
-
}, [voucherType, monetaryAmount, selectedEventTypeId, eventQuantity, eventTypes]);
|
|
13756
|
+
}, [voucherType, monetaryAmount, selectedEventTypeId, eventQuantity, eventTypes, categoryAmount]);
|
|
13589
13757
|
const selectedEventType = T$2(() => {
|
|
13590
13758
|
return eventTypes.find((et) => et.id === selectedEventTypeId);
|
|
13591
13759
|
}, [eventTypes, selectedEventTypeId]);
|
|
@@ -13594,6 +13762,8 @@
|
|
|
13594
13762
|
voucherType,
|
|
13595
13763
|
selectedEventTypeId,
|
|
13596
13764
|
eventQuantity,
|
|
13765
|
+
selectedCategoryId,
|
|
13766
|
+
categoryAmount,
|
|
13597
13767
|
recipientName: recipientName.trim(),
|
|
13598
13768
|
message: message.trim(),
|
|
13599
13769
|
customerName: customerName.trim(),
|
|
@@ -13603,6 +13773,8 @@
|
|
|
13603
13773
|
voucherType,
|
|
13604
13774
|
selectedEventTypeId,
|
|
13605
13775
|
eventQuantity,
|
|
13776
|
+
selectedCategoryId,
|
|
13777
|
+
categoryAmount,
|
|
13606
13778
|
recipientName,
|
|
13607
13779
|
message,
|
|
13608
13780
|
customerName,
|
|
@@ -13621,24 +13793,37 @@
|
|
|
13621
13793
|
return false;
|
|
13622
13794
|
if (voucherType === "event" && !selectedEventTypeId)
|
|
13623
13795
|
return false;
|
|
13796
|
+
if (voucherType === "category" && !selectedCategoryId)
|
|
13797
|
+
return false;
|
|
13624
13798
|
return true;
|
|
13625
|
-
}, [customerName, customerEmail, acceptTerms, totalAmount,
|
|
13799
|
+
}, [customerName, customerEmail, acceptTerms, totalAmount, voucherType, selectedEventTypeId, selectedCategoryId]);
|
|
13626
13800
|
const defaultMonetaryAmount = T$2(() => voucherConfig.monetaryPresets[2] || voucherConfig.monetaryPresets[0] || 1000, [voucherConfig.monetaryPresets]);
|
|
13627
13801
|
const handleVoucherTypeChange = q$2((nextType) => {
|
|
13628
13802
|
setVoucherType(nextType);
|
|
13629
13803
|
setPaymentError(null);
|
|
13630
13804
|
if (nextType === "event") {
|
|
13631
|
-
// Keep voucher type mutually exclusive: entering event flow resets amount selection state.
|
|
13632
13805
|
setMonetaryAmount(defaultMonetaryAmount);
|
|
13806
|
+
setSelectedCategoryId(null);
|
|
13807
|
+
setCategoryAmount(10000);
|
|
13633
13808
|
if (eventTypes.length === 1) {
|
|
13634
13809
|
setSelectedEventTypeId(eventTypes[0]?.id ?? null);
|
|
13635
13810
|
}
|
|
13636
13811
|
return;
|
|
13637
13812
|
}
|
|
13638
|
-
|
|
13813
|
+
if (nextType === "category") {
|
|
13814
|
+
setMonetaryAmount(defaultMonetaryAmount);
|
|
13815
|
+
setSelectedEventTypeId(null);
|
|
13816
|
+
setEventQuantity(1);
|
|
13817
|
+
if (categories.length === 1) {
|
|
13818
|
+
setSelectedCategoryId(categories[0]?.id ?? null);
|
|
13819
|
+
}
|
|
13820
|
+
return;
|
|
13821
|
+
}
|
|
13639
13822
|
setSelectedEventTypeId(null);
|
|
13640
13823
|
setEventQuantity(1);
|
|
13641
|
-
|
|
13824
|
+
setSelectedCategoryId(null);
|
|
13825
|
+
setCategoryAmount(10000);
|
|
13826
|
+
}, [defaultMonetaryAmount, eventTypes, categories]);
|
|
13642
13827
|
y$1(() => {
|
|
13643
13828
|
if (!canUseMonetaryVoucherType && voucherType === "monetary") {
|
|
13644
13829
|
setVoucherType("event");
|
|
@@ -13679,9 +13864,12 @@
|
|
|
13679
13864
|
organizationId: config.organizationId,
|
|
13680
13865
|
amount: totalAmount,
|
|
13681
13866
|
currency: "eur",
|
|
13682
|
-
voucherType,
|
|
13683
|
-
monetaryValue: voucherType === "monetary" ? totalAmount
|
|
13867
|
+
voucherType: voucherType === "category" ? "monetary" : voucherType,
|
|
13868
|
+
monetaryValue: voucherType === "monetary" ? totalAmount
|
|
13869
|
+
: voucherType === "category" ? categoryAmount
|
|
13870
|
+
: undefined,
|
|
13684
13871
|
eventTypeId: voucherType === "event" ? selectedEventTypeId : undefined,
|
|
13872
|
+
eventCategoryId: voucherType === "category" ? selectedCategoryId : undefined,
|
|
13685
13873
|
eventAmount: voucherType === "event" ? eventQuantity : undefined,
|
|
13686
13874
|
recipientName: recipientName.trim() || undefined,
|
|
13687
13875
|
message: message.trim() || undefined,
|
|
@@ -13872,7 +14060,30 @@
|
|
|
13872
14060
|
fontSize: "13px",
|
|
13873
14061
|
color: "var(--bw-text-muted)",
|
|
13874
14062
|
marginTop: "4px",
|
|
13875
|
-
}, children: t("voucher.eventTypeDesc") })] }))
|
|
14063
|
+
}, children: t("voucher.eventTypeDesc") })] })), canUseCategoryVoucherType && (u$2("button", { type: "button", onClick: () => handleVoucherTypeChange("category"), style: {
|
|
14064
|
+
flex: 1,
|
|
14065
|
+
padding: "16px",
|
|
14066
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14067
|
+
border: voucherType === "category"
|
|
14068
|
+
? "2px solid var(--bw-highlight-color)"
|
|
14069
|
+
: "1px solid var(--bw-border-color)",
|
|
14070
|
+
backgroundColor: voucherType === "category"
|
|
14071
|
+
? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
|
|
14072
|
+
: "var(--bw-surface-color)",
|
|
14073
|
+
cursor: "pointer",
|
|
14074
|
+
fontFamily: "var(--bw-font-family)",
|
|
14075
|
+
transition: "all 0.2s ease",
|
|
14076
|
+
textAlign: "center",
|
|
14077
|
+
}, children: [u$2("div", { style: {
|
|
14078
|
+
fontWeight: 600,
|
|
14079
|
+
color: voucherType === "category"
|
|
14080
|
+
? "var(--bw-highlight-color)"
|
|
14081
|
+
: "var(--bw-text-color)",
|
|
14082
|
+
}, children: t("voucher.categoryType") }), u$2("div", { style: {
|
|
14083
|
+
fontSize: "13px",
|
|
14084
|
+
color: "var(--bw-text-muted)",
|
|
14085
|
+
marginTop: "4px",
|
|
14086
|
+
}, children: t("voucher.categoryTypeDesc") })] }))] })] })), voucherType === "monetary" && (u$2("div", { style: cardStyles, children: [u$2("h2", { style: sectionHeaderStyles, children: t("voucher.selectAmount") }), u$2("div", { style: {
|
|
13876
14087
|
display: "grid",
|
|
13877
14088
|
gridTemplateColumns: "repeat(3, 1fr)",
|
|
13878
14089
|
gap: "8px",
|
|
@@ -13927,7 +14138,50 @@
|
|
|
13927
14138
|
fontSize: "18px",
|
|
13928
14139
|
color: "var(--bw-highlight-color)",
|
|
13929
14140
|
fontFamily: "var(--bw-font-family)",
|
|
13930
|
-
}, children: formatCurrency(totalAmount) })] }) }))] })), u$2("div", { style: cardStyles, children: [u$2("h2", { style: sectionHeaderStyles, children: t("voucher.
|
|
14141
|
+
}, children: formatCurrency(totalAmount) })] }) }))] })), voucherType === "category" && (u$2("div", { style: cardStyles, children: [u$2("h2", { style: sectionHeaderStyles, children: t("voucher.selectCategory") }), u$2("div", { style: { marginTop: "12px" }, children: u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [u$2("div", { children: [u$2("label", { htmlFor: "category-select", style: labelStyles, children: t("voucher.categoryLabel") }), u$2("select", { id: "category-select", value: selectedCategoryId || "", onChange: (e) => setSelectedCategoryId(e.target.value ? Number(e.target.value) : null), disabled: categories.length === 1, style: {
|
|
14142
|
+
...inputStyles,
|
|
14143
|
+
cursor: categories.length === 1 ? "not-allowed" : "pointer",
|
|
14144
|
+
}, children: [categories.length > 1 && (u$2("option", { value: "", children: t("voucher.selectCategoryPlaceholder") })), categories.map((cat) => (u$2("option", { value: cat.id, children: cat.name }, cat.id)))] })] }), selectedCategoryId && (u$2("div", { children: [u$2("label", { htmlFor: "category-amount", style: labelStyles, children: t("voucher.categoryAmount") }), u$2("div", { style: {
|
|
14145
|
+
display: "grid",
|
|
14146
|
+
gridTemplateColumns: "repeat(3, 1fr)",
|
|
14147
|
+
gap: "8px",
|
|
14148
|
+
marginTop: "4px",
|
|
14149
|
+
}, children: voucherConfig.monetaryPresets.map((preset) => (u$2("button", { type: "button", onClick: () => setCategoryAmount(preset), style: {
|
|
14150
|
+
padding: "10px",
|
|
14151
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14152
|
+
border: categoryAmount === preset
|
|
14153
|
+
? "2px solid var(--bw-highlight-color)"
|
|
14154
|
+
: "1px solid var(--bw-border-color)",
|
|
14155
|
+
backgroundColor: categoryAmount === preset
|
|
14156
|
+
? "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)"
|
|
14157
|
+
: "var(--bw-surface-color)",
|
|
14158
|
+
cursor: "pointer",
|
|
14159
|
+
fontFamily: "var(--bw-font-family)",
|
|
14160
|
+
fontWeight: 600,
|
|
14161
|
+
fontSize: "14px",
|
|
14162
|
+
color: categoryAmount === preset
|
|
14163
|
+
? "var(--bw-highlight-color)"
|
|
14164
|
+
: "var(--bw-text-color)",
|
|
14165
|
+
transition: "all 0.2s ease",
|
|
14166
|
+
}, children: formatCurrency(preset) }, preset))) })] }))] }) }), selectedCategoryId && categoryAmount > 0 && (u$2("div", { style: {
|
|
14167
|
+
marginTop: "16px",
|
|
14168
|
+
padding: "12px",
|
|
14169
|
+
backgroundColor: "rgba(var(--bw-highlight-color-rgb, 0, 177, 170), 0.1)",
|
|
14170
|
+
borderRadius: "var(--bw-border-radius)",
|
|
14171
|
+
border: "1px solid var(--bw-highlight-color)",
|
|
14172
|
+
}, children: u$2("div", { style: {
|
|
14173
|
+
display: "flex",
|
|
14174
|
+
justifyContent: "space-between",
|
|
14175
|
+
alignItems: "center",
|
|
14176
|
+
}, children: [u$2("span", { style: {
|
|
14177
|
+
color: "var(--bw-text-color)",
|
|
14178
|
+
fontFamily: "var(--bw-font-family)",
|
|
14179
|
+
}, children: categories.find((c) => c.id === selectedCategoryId)?.name }), u$2("span", { style: {
|
|
14180
|
+
fontWeight: 700,
|
|
14181
|
+
fontSize: "18px",
|
|
14182
|
+
color: "var(--bw-highlight-color)",
|
|
14183
|
+
fontFamily: "var(--bw-font-family)",
|
|
14184
|
+
}, children: formatCurrency(categoryAmount) })] }) }))] })), u$2("div", { style: cardStyles, children: [u$2("h2", { style: sectionHeaderStyles, children: t("voucher.recipientSection") }), u$2("p", { style: {
|
|
13931
14185
|
fontSize: "13px",
|
|
13932
14186
|
color: "var(--bw-text-muted)",
|
|
13933
14187
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -13960,7 +14214,9 @@
|
|
|
13960
14214
|
fontFamily: "var(--bw-font-family)",
|
|
13961
14215
|
}, children: voucherType === "monetary"
|
|
13962
14216
|
? t("voucher.monetaryVoucher")
|
|
13963
|
-
:
|
|
14217
|
+
: voucherType === "category"
|
|
14218
|
+
? categories.find((c) => c.id === selectedCategoryId)?.name || t("voucher.categoryVoucher")
|
|
14219
|
+
: `${eventQuantity}x ${selectedEventType?.name || t("voucher.eventVoucher")}` }), recipientName && (u$2("div", { style: {
|
|
13964
14220
|
fontSize: "13px",
|
|
13965
14221
|
color: "var(--bw-text-muted)",
|
|
13966
14222
|
fontFamily: "var(--bw-font-family)",
|
|
@@ -14236,7 +14492,7 @@
|
|
|
14236
14492
|
}, children: t("voucher.buyAsGift") })] }));
|
|
14237
14493
|
}
|
|
14238
14494
|
|
|
14239
|
-
function VoucherIntegration({ config, voucherConfig, eventTypes, systemConfig, isFormOpen, isLoadingConfig, preselectedEventTypeId, voucherPurchaseResult, isSuccess, showStandaloneCard, onCardClick, onFormClose, onSuccess, onError, onSuccessModalClose, }) {
|
|
14495
|
+
function VoucherIntegration({ config, voucherConfig, eventTypes, categories, systemConfig, isFormOpen, isLoadingConfig, preselectedEventTypeId, voucherPurchaseResult, isSuccess, showStandaloneCard, onCardClick, onFormClose, onSuccess, onError, onSuccessModalClose, }) {
|
|
14240
14496
|
if (!voucherConfig?.enabled) {
|
|
14241
14497
|
return null;
|
|
14242
14498
|
}
|
|
@@ -14247,7 +14503,7 @@
|
|
|
14247
14503
|
justifyContent: "center",
|
|
14248
14504
|
}, children: u$2(VoucherPurchaseCard, { config: voucherConfig, minEventPrice: eventTypes.length > 0
|
|
14249
14505
|
? Math.min(...eventTypes.map((et) => et.maxPrice))
|
|
14250
|
-
: undefined, fallbackImages: eventTypes.flatMap((eventType) => eventType.images || []), onClick: onCardClick, standalone: true }) }) })), u$2(VoucherPurchaseForm, { config: config, voucherConfig: voucherConfig, eventTypes: eventTypes, isOpen: isFormOpen, onClose: onFormClose, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, preselectedEventTypeId: preselectedEventTypeId, isLoadingEventTypes: isLoadingConfig }), isSuccess && voucherPurchaseResult && (u$2(VoucherSuccessModal, { isOpen: true, onClose: onSuccessModalClose, result: voucherPurchaseResult }))] }));
|
|
14506
|
+
: undefined, fallbackImages: eventTypes.flatMap((eventType) => eventType.images || []), onClick: onCardClick, standalone: true }) }) })), u$2(VoucherPurchaseForm, { config: config, voucherConfig: voucherConfig, eventTypes: eventTypes, categories: categories, isOpen: isFormOpen, onClose: onFormClose, onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, preselectedEventTypeId: preselectedEventTypeId, isLoadingEventTypes: isLoadingConfig }), isSuccess && voucherPurchaseResult && (u$2(VoucherSuccessModal, { isOpen: true, onClose: onSuccessModalClose, result: voucherPurchaseResult }))] }));
|
|
14251
14507
|
}
|
|
14252
14508
|
|
|
14253
14509
|
// Helper function to preprocess markdown for underline support
|
|
@@ -14307,7 +14563,7 @@
|
|
|
14307
14563
|
pointerEvents: "none",
|
|
14308
14564
|
}, children: text }))] }));
|
|
14309
14565
|
}
|
|
14310
|
-
function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview, isLoading = false, skeletonCount = 4, showVoucherAttachment = false, onVoucherClick, }) {
|
|
14566
|
+
function EventTypeSelection({ eventTypes, onEventTypeSelect, onInstancePreview, isLoading = false, skeletonCount = 4, showVoucherAttachment = false, onVoucherClick, showImages = true, }) {
|
|
14311
14567
|
const t = useTranslations();
|
|
14312
14568
|
const { locale } = useLocale();
|
|
14313
14569
|
const timezone = useTimezone();
|
|
@@ -14386,6 +14642,18 @@
|
|
|
14386
14642
|
gridAutoRows: "1fr",
|
|
14387
14643
|
}, children: eventTypes.map((eventType) => {
|
|
14388
14644
|
const isAvailable = eventType.hasAvailableInstances;
|
|
14645
|
+
const hasImage = showImages && eventType.images && eventType.images.length > 0;
|
|
14646
|
+
const availabilityBadge = (u$2("div", { style: {
|
|
14647
|
+
padding: "4px 8px",
|
|
14648
|
+
borderRadius: "var(--bw-border-radius-small)",
|
|
14649
|
+
fontSize: "12px",
|
|
14650
|
+
fontWeight: 600,
|
|
14651
|
+
color: "#ffffff",
|
|
14652
|
+
fontFamily: "var(--bw-font-family)",
|
|
14653
|
+
backgroundColor: isAvailable
|
|
14654
|
+
? "var(--bw-success-color)"
|
|
14655
|
+
: "var(--bw-error-color)",
|
|
14656
|
+
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }));
|
|
14389
14657
|
return (u$2("div", { className: "event-type-card", style: {
|
|
14390
14658
|
position: "relative",
|
|
14391
14659
|
backgroundColor: "var(--bw-surface-color)",
|
|
@@ -14397,17 +14665,7 @@
|
|
|
14397
14665
|
fontFamily: "var(--bw-font-family)",
|
|
14398
14666
|
cursor: isAvailable ? "pointer" : "not-allowed",
|
|
14399
14667
|
opacity: isAvailable ? 1 : 0.6,
|
|
14400
|
-
}, onClick: () => isAvailable && onEventTypeSelect(eventType), children: [u$2("div", { style: { position: "absolute", top: "16px", right: "16px", zIndex: 10 }, children: u$2("div", { style: {
|
|
14401
|
-
padding: "4px 8px",
|
|
14402
|
-
borderRadius: "var(--bw-border-radius-small)",
|
|
14403
|
-
fontSize: "12px",
|
|
14404
|
-
fontWeight: 600,
|
|
14405
|
-
color: "#ffffff",
|
|
14406
|
-
fontFamily: "var(--bw-font-family)",
|
|
14407
|
-
backgroundColor: isAvailable
|
|
14408
|
-
? "var(--bw-success-color)"
|
|
14409
|
-
: "var(--bw-error-color)",
|
|
14410
|
-
}, children: isAvailable ? t("events.spotsAvailable") : t("events.soldOut") }) }), eventType.images && eventType.images.length > 0 && (u$2(k$3, { children: [u$2("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: u$2("div", { style: {
|
|
14668
|
+
}, onClick: () => isAvailable && onEventTypeSelect(eventType), children: [hasImage && (u$2("div", { style: { position: "absolute", top: "16px", right: "16px", zIndex: 10 }, children: availabilityBadge })), hasImage && (u$2(k$3, { children: [u$2("div", { style: { position: "absolute", top: "16px", left: "16px", zIndex: 10 }, children: u$2("div", { style: {
|
|
14411
14669
|
fontSize: "13px",
|
|
14412
14670
|
color: "var(--bw-surface-color)",
|
|
14413
14671
|
fontWeight: 600,
|
|
@@ -14421,7 +14679,7 @@
|
|
|
14421
14679
|
flexDirection: "column",
|
|
14422
14680
|
justifyContent: "space-between",
|
|
14423
14681
|
height: "540px",
|
|
14424
|
-
}, children: [u$2("div", { children: [u$2("h2", { className: "event-type-title", style: {
|
|
14682
|
+
}, children: [u$2("div", { children: [!hasImage && (u$2("div", { style: { display: "flex", justifyContent: "flex-end", margin: "0 0 8px 0" }, children: availabilityBadge })), u$2("h2", { className: "event-type-title", style: {
|
|
14425
14683
|
fontSize: "clamp(1.1rem, 2.5vw, 24px)",
|
|
14426
14684
|
fontWeight: 700,
|
|
14427
14685
|
color: "var(--bw-text-color)",
|
|
@@ -14693,16 +14951,16 @@
|
|
|
14693
14951
|
}
|
|
14694
14952
|
|
|
14695
14953
|
const getAllocationBadgeInfo = (availableSpots, maxParticipants, t) => {
|
|
14696
|
-
|
|
14697
|
-
if (availabilityRatio >= 0.6)
|
|
14698
|
-
return null;
|
|
14699
|
-
if (availabilityRatio === 0) {
|
|
14954
|
+
if (maxParticipants <= 0 || availableSpots <= 0) {
|
|
14700
14955
|
return {
|
|
14701
14956
|
text: t("events.soldOut"),
|
|
14702
14957
|
backgroundColor: "#7f1d1d",
|
|
14703
14958
|
textColor: "#fca5a5",
|
|
14704
14959
|
};
|
|
14705
14960
|
}
|
|
14961
|
+
const availabilityRatio = availableSpots / maxParticipants;
|
|
14962
|
+
if (availabilityRatio >= 0.6)
|
|
14963
|
+
return null;
|
|
14706
14964
|
if (availabilityRatio <= 0.3) {
|
|
14707
14965
|
return {
|
|
14708
14966
|
text: t("instances.almostSoldOut"),
|
|
@@ -14816,7 +15074,7 @@
|
|
|
14816
15074
|
boxShadow: displayInfo ? "0 2px 4px rgba(0, 0, 0, 0.2)" : "none",
|
|
14817
15075
|
}, children: formatCurrency(price) }));
|
|
14818
15076
|
};
|
|
14819
|
-
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, }) {
|
|
15077
|
+
function EventInstanceSelection({ eventInstances, selectedEventType, onEventInstanceSelect, onBackToEventTypes, isOpen, onClose, isLoadingEventInstances = false, isLoadingEventDetails = false, hasUpsellsStep = false, apiBaseUrl, organizationId, waitlistEnabled = false, }) {
|
|
14820
15078
|
const t = useTranslations();
|
|
14821
15079
|
const { locale } = useLocale();
|
|
14822
15080
|
const timezone = useTimezone();
|
|
@@ -15001,12 +15259,13 @@
|
|
|
15001
15259
|
? "0 2px 4px rgba(0, 0, 0, 0.2)"
|
|
15002
15260
|
: undefined,
|
|
15003
15261
|
}, children: `${t("common.from")} ${formatCurrency(minPrice)}` }), isOpen: openGroups.has(key), onToggle: () => toggleGroup(key), children: u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px", paddingTop: "12px" }, children: events.map((event) => {
|
|
15004
|
-
const availableSpots = event.
|
|
15005
|
-
const isFullyBooked = availableSpots === 0;
|
|
15262
|
+
const availableSpots = event.availableSpots;
|
|
15006
15263
|
const startDate = new Date(event.startTime);
|
|
15007
15264
|
const isPastEvent = today.toISOString() >= startDate.toISOString();
|
|
15008
|
-
const
|
|
15009
|
-
const
|
|
15265
|
+
const isUnavailable = availableSpots <= 0 || !event.bookingOpen;
|
|
15266
|
+
const isDisabled = isUnavailable || isPastEvent;
|
|
15267
|
+
const canWaitlist = waitlistEnabled &&
|
|
15268
|
+
isUnavailable &&
|
|
15010
15269
|
!isPastEvent &&
|
|
15011
15270
|
!!apiBaseUrl &&
|
|
15012
15271
|
!!organizationId;
|
|
@@ -15043,7 +15302,7 @@
|
|
|
15043
15302
|
color: "var(--bw-highlight-color)",
|
|
15044
15303
|
opacity: 0.8,
|
|
15045
15304
|
fontSize: "32px",
|
|
15046
|
-
}, children: spinner() }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.maxParticipants, t: t }), u$2("div", { style: {
|
|
15305
|
+
}, children: spinner() }) })), u$2(SpecialPriceBadge, { price: event.price, yearPrices: yearPrices, t: t }), u$2(AllocationBadge, { availableSpots: availableSpots, maxParticipants: event.effectiveMaxParticipants ?? event.maxParticipants, t: t }), u$2("div", { style: {
|
|
15047
15306
|
display: "flex",
|
|
15048
15307
|
justifyContent: "space-between",
|
|
15049
15308
|
width: "100%",
|
|
@@ -15220,18 +15479,19 @@
|
|
|
15220
15479
|
margin: "0 auto",
|
|
15221
15480
|
padding: "12px 16px",
|
|
15222
15481
|
fontFamily: "var(--bw-font-family)",
|
|
15223
|
-
}, children: [u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginBottom: "10px" }, children: events
|
|
15224
|
-
|
|
15225
|
-
const isFullyBooked = availableSpots === 0;
|
|
15482
|
+
}, children: [u$2("div", { style: { display: "flex", flexDirection: "column", gap: "12px", marginBottom: "10px" }, children: events
|
|
15483
|
+
.filter((event) => {
|
|
15226
15484
|
const startDate = new Date(event.startTime);
|
|
15227
15485
|
const isPastEvent = today.toISOString() >= startDate.toISOString();
|
|
15228
|
-
|
|
15229
|
-
|
|
15486
|
+
return !isPastEvent && event.availableSpots > 0 && event.bookingOpen;
|
|
15487
|
+
})
|
|
15488
|
+
.map((event) => {
|
|
15489
|
+
const availableSpots = event.availableSpots;
|
|
15490
|
+
const startDate = new Date(event.startTime);
|
|
15230
15491
|
const allocationBadge = (() => {
|
|
15492
|
+
const availabilityRatio = availableSpots / event.maxParticipants;
|
|
15231
15493
|
if (availabilityRatio >= 0.6)
|
|
15232
15494
|
return null;
|
|
15233
|
-
if (availabilityRatio === 0)
|
|
15234
|
-
return { text: t("events.soldOut"), backgroundColor: "#7f1d1d", textColor: "#fca5a5" };
|
|
15235
15495
|
if (availabilityRatio <= 0.3)
|
|
15236
15496
|
return { text: t("instances.almostSoldOut"), backgroundColor: "#7f1d1d", textColor: "#fca5a5" };
|
|
15237
15497
|
return { text: t("instances.popularDate"), backgroundColor: "#b45309", textColor: "#fbbf24" };
|
|
@@ -15245,13 +15505,9 @@
|
|
|
15245
15505
|
padding: "16px 10px",
|
|
15246
15506
|
transition: "all 0.2s ease",
|
|
15247
15507
|
fontFamily: "var(--bw-font-family)",
|
|
15248
|
-
|
|
15249
|
-
filter: isDisabled ? "grayscale(40%)" : "none",
|
|
15250
|
-
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
15508
|
+
cursor: "pointer",
|
|
15251
15509
|
}, onClick: () => {
|
|
15252
|
-
|
|
15253
|
-
handleEventSelect(event.id);
|
|
15254
|
-
}
|
|
15510
|
+
handleEventSelect(event.id);
|
|
15255
15511
|
}, children: [selectedEventInstanceId === event.id && isLoadingEventDetails && (u$2("div", { style: {
|
|
15256
15512
|
position: "absolute",
|
|
15257
15513
|
inset: 0,
|
|
@@ -15506,7 +15762,7 @@
|
|
|
15506
15762
|
alignItems: "center",
|
|
15507
15763
|
backgroundColor: "var(--bw-background-color)",
|
|
15508
15764
|
}, children: [u$2("span", { style: { fontSize: "12px", color: "var(--bw-text-muted)" }, children: isFullyBooked
|
|
15509
|
-
? t("
|
|
15765
|
+
? t("events.soldOut")
|
|
15510
15766
|
: t("specials.spotsLeft").replace("{{count}}", String(special.availableSpots)) }), u$2("span", { style: {
|
|
15511
15767
|
fontSize: "13px",
|
|
15512
15768
|
fontWeight: 600,
|
|
@@ -15515,6 +15771,312 @@
|
|
|
15515
15771
|
}) })] }));
|
|
15516
15772
|
}
|
|
15517
15773
|
|
|
15774
|
+
function toMinutesForUnit(unit) {
|
|
15775
|
+
switch (unit.toLowerCase()) {
|
|
15776
|
+
case "minute":
|
|
15777
|
+
case "minutes":
|
|
15778
|
+
return 1;
|
|
15779
|
+
case "hour":
|
|
15780
|
+
case "hours":
|
|
15781
|
+
return 60;
|
|
15782
|
+
case "day":
|
|
15783
|
+
case "days":
|
|
15784
|
+
return 24 * 60;
|
|
15785
|
+
default:
|
|
15786
|
+
return 1;
|
|
15787
|
+
}
|
|
15788
|
+
}
|
|
15789
|
+
// --- Timezone helpers ------------------------------------------------------
|
|
15790
|
+
// The booking is evaluated server-side against the organization's local
|
|
15791
|
+
// operating hours. The customer's browser may be in a different timezone, so we
|
|
15792
|
+
// interpret the datetime-local field as a wall-clock time in the ORG timezone
|
|
15793
|
+
// (not the browser's) and convert to a UTC instant for the API.
|
|
15794
|
+
function getTzParts(date, timeZone) {
|
|
15795
|
+
const dtf = new Intl.DateTimeFormat("en-CA", {
|
|
15796
|
+
timeZone,
|
|
15797
|
+
hour12: false,
|
|
15798
|
+
year: "numeric",
|
|
15799
|
+
month: "2-digit",
|
|
15800
|
+
day: "2-digit",
|
|
15801
|
+
hour: "2-digit",
|
|
15802
|
+
minute: "2-digit",
|
|
15803
|
+
second: "2-digit",
|
|
15804
|
+
});
|
|
15805
|
+
const parts = {};
|
|
15806
|
+
for (const part of dtf.formatToParts(date)) {
|
|
15807
|
+
if (part.type !== "literal")
|
|
15808
|
+
parts[part.type] = part.value;
|
|
15809
|
+
}
|
|
15810
|
+
return parts;
|
|
15811
|
+
}
|
|
15812
|
+
function tzOffsetMs(utcMs, timeZone) {
|
|
15813
|
+
const p = getTzParts(new Date(utcMs), timeZone);
|
|
15814
|
+
const hour = p.hour === "24" ? "00" : p.hour;
|
|
15815
|
+
const asLocalUtc = Date.UTC(Number(p.year), Number(p.month) - 1, Number(p.day), Number(hour), Number(p.minute), Number(p.second));
|
|
15816
|
+
return asLocalUtc - utcMs;
|
|
15817
|
+
}
|
|
15818
|
+
/** Convert an org-tz wall-clock string ("YYYY-MM-DDTHH:mm") to a UTC instant. */
|
|
15819
|
+
function zonedWallTimeToUtc(wallTime, timeZone) {
|
|
15820
|
+
const [datePart, timePart] = wallTime.split("T");
|
|
15821
|
+
if (!datePart || !timePart)
|
|
15822
|
+
return new Date(NaN);
|
|
15823
|
+
const [y, mo, d] = datePart.split("-").map(Number);
|
|
15824
|
+
const [h, mi] = timePart.split(":").map(Number);
|
|
15825
|
+
const naiveUtc = Date.UTC(y, (mo ?? 1) - 1, d, h ?? 0, mi ?? 0);
|
|
15826
|
+
// Single-pass offset correction (good enough outside the ~1h DST fold).
|
|
15827
|
+
const offset = tzOffsetMs(naiveUtc, timeZone);
|
|
15828
|
+
return new Date(naiveUtc - offset);
|
|
15829
|
+
}
|
|
15830
|
+
/** Render a UTC instant as an org-tz datetime-local input value. */
|
|
15831
|
+
function utcToZonedInputValue(date, timeZone) {
|
|
15832
|
+
const p = getTzParts(date, timeZone);
|
|
15833
|
+
const hour = p.hour === "24" ? "00" : p.hour;
|
|
15834
|
+
return `${p.year}-${p.month}-${p.day}T${hour}:${p.minute}`;
|
|
15835
|
+
}
|
|
15836
|
+
/** Format a UTC instant for display in the org timezone. */
|
|
15837
|
+
function formatInTimeZone(date, timeZone, locale) {
|
|
15838
|
+
return new Intl.DateTimeFormat(locale, {
|
|
15839
|
+
timeZone,
|
|
15840
|
+
dateStyle: "medium",
|
|
15841
|
+
timeStyle: "short",
|
|
15842
|
+
}).format(date);
|
|
15843
|
+
}
|
|
15844
|
+
function calculateTieredPrice(durationUnits, config) {
|
|
15845
|
+
const tiers = [...(config.tiers ?? [])]
|
|
15846
|
+
.filter((tier) => tier.unitCount > 0 && tier.price >= 0)
|
|
15847
|
+
.sort((a, b) => b.unitCount - a.unitCount);
|
|
15848
|
+
if (tiers.length === 0) {
|
|
15849
|
+
return 0;
|
|
15850
|
+
}
|
|
15851
|
+
let total = 0;
|
|
15852
|
+
let remaining = durationUnits;
|
|
15853
|
+
for (const tier of tiers) {
|
|
15854
|
+
const count = Math.floor(remaining / tier.unitCount);
|
|
15855
|
+
if (count <= 0)
|
|
15856
|
+
continue;
|
|
15857
|
+
total += count * tier.price;
|
|
15858
|
+
remaining -= count * tier.unitCount;
|
|
15859
|
+
}
|
|
15860
|
+
if (remaining > 0) {
|
|
15861
|
+
if (typeof config.perUnitPrice === "number") {
|
|
15862
|
+
total += remaining * config.perUnitPrice;
|
|
15863
|
+
}
|
|
15864
|
+
else {
|
|
15865
|
+
total += tiers[tiers.length - 1]?.price ?? 0;
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15868
|
+
return total;
|
|
15869
|
+
}
|
|
15870
|
+
function FreeformSelection({ config, eventType, systemConfig, isOpen, onClose, onSuccess, onError, }) {
|
|
15871
|
+
const t = useTranslations();
|
|
15872
|
+
const { locale } = useLocale();
|
|
15873
|
+
const freeformConfig = eventType.freeformConfig;
|
|
15874
|
+
const timeZone = eventType.organizationTimezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
15875
|
+
const isNamedResource = eventType.resourceKind === "named";
|
|
15876
|
+
const maxUnits = isNamedResource ? 1 : Math.max(1, eventType.resourceQuantity ?? 1);
|
|
15877
|
+
const now = T$2(() => {
|
|
15878
|
+
const next = new Date();
|
|
15879
|
+
next.setMinutes(next.getMinutes() + 30, 0, 0);
|
|
15880
|
+
return next;
|
|
15881
|
+
}, []);
|
|
15882
|
+
const [startInput, setStartInput] = d$1(utcToZonedInputValue(now, timeZone));
|
|
15883
|
+
const [duration, setDuration] = d$1(Math.max(1, freeformConfig?.minDuration ?? 1));
|
|
15884
|
+
const [requestedUnits, setRequestedUnits] = d$1(1);
|
|
15885
|
+
const [customerName, setCustomerName] = d$1("");
|
|
15886
|
+
const [customerEmail, setCustomerEmail] = d$1("");
|
|
15887
|
+
const [customerPhone, setCustomerPhone] = d$1("");
|
|
15888
|
+
const [comment, setComment] = d$1("");
|
|
15889
|
+
const [acceptTerms, setAcceptTerms] = d$1(false);
|
|
15890
|
+
const [checkoutStep, setCheckoutStep] = d$1("details");
|
|
15891
|
+
const [availability, setAvailability] = d$1(null);
|
|
15892
|
+
const [availabilityError, setAvailabilityError] = d$1(null);
|
|
15893
|
+
const [isCheckingAvailability, setIsCheckingAvailability] = d$1(false);
|
|
15894
|
+
y$1(() => {
|
|
15895
|
+
if (!isOpen)
|
|
15896
|
+
return;
|
|
15897
|
+
setCheckoutStep("details");
|
|
15898
|
+
}, [isOpen]);
|
|
15899
|
+
y$1(() => {
|
|
15900
|
+
if (!freeformConfig)
|
|
15901
|
+
return;
|
|
15902
|
+
setDuration(Math.max(1, freeformConfig.minDuration));
|
|
15903
|
+
setRequestedUnits(1);
|
|
15904
|
+
setAvailability(null);
|
|
15905
|
+
setAvailabilityError(null);
|
|
15906
|
+
}, [freeformConfig?.resourceId]);
|
|
15907
|
+
const unitMinutes = toMinutesForUnit(freeformConfig?.unit ?? "hour");
|
|
15908
|
+
const startDate = T$2(() => zonedWallTimeToUtc(startInput, timeZone), [startInput, timeZone]);
|
|
15909
|
+
const endDate = T$2(() => new Date(startDate.getTime() + duration * unitMinutes * 60000), [duration, startDate, unitMinutes]);
|
|
15910
|
+
y$1(() => {
|
|
15911
|
+
if (!isOpen || !freeformConfig)
|
|
15912
|
+
return;
|
|
15913
|
+
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime()))
|
|
15914
|
+
return;
|
|
15915
|
+
const timer = setTimeout(async () => {
|
|
15916
|
+
setIsCheckingAvailability(true);
|
|
15917
|
+
setAvailabilityError(null);
|
|
15918
|
+
try {
|
|
15919
|
+
const response = await fetch(getApiUrl(config.apiBaseUrl, "/booking/freeform-availability"), {
|
|
15920
|
+
method: "POST",
|
|
15921
|
+
headers: createApiHeaders(config, locale),
|
|
15922
|
+
body: JSON.stringify(createRequestBody(config, {
|
|
15923
|
+
eventTypeId: eventType.id,
|
|
15924
|
+
requestedUnits,
|
|
15925
|
+
start: startDate.toISOString(),
|
|
15926
|
+
end: endDate.toISOString(),
|
|
15927
|
+
})),
|
|
15928
|
+
});
|
|
15929
|
+
const data = await response.json();
|
|
15930
|
+
if (!response.ok) {
|
|
15931
|
+
setAvailability(null);
|
|
15932
|
+
setAvailabilityError(data.error || t("error.loadBookingData"));
|
|
15933
|
+
return;
|
|
15934
|
+
}
|
|
15935
|
+
setAvailability({
|
|
15936
|
+
available: Boolean(data.available),
|
|
15937
|
+
freeUnits: Number(data.freeUnits ?? 0),
|
|
15938
|
+
capacityUnits: Number(data.capacityUnits ?? 0),
|
|
15939
|
+
usedUnits: Number(data.usedUnits ?? 0),
|
|
15940
|
+
reservationUsedUnits: Number(data.reservationUsedUnits ?? 0),
|
|
15941
|
+
blockUsedUnits: Number(data.blockUsedUnits ?? 0),
|
|
15942
|
+
durationUnits: Number(data.durationUnits ?? 0),
|
|
15943
|
+
roundedDurationMinutes: Number(data.roundedDurationMinutes ?? 0),
|
|
15944
|
+
});
|
|
15945
|
+
}
|
|
15946
|
+
catch (_error) {
|
|
15947
|
+
setAvailability(null);
|
|
15948
|
+
setAvailabilityError(t("error.loadBookingData"));
|
|
15949
|
+
}
|
|
15950
|
+
finally {
|
|
15951
|
+
setIsCheckingAvailability(false);
|
|
15952
|
+
}
|
|
15953
|
+
}, 350);
|
|
15954
|
+
return () => clearTimeout(timer);
|
|
15955
|
+
}, [
|
|
15956
|
+
config,
|
|
15957
|
+
endDate,
|
|
15958
|
+
eventType.id,
|
|
15959
|
+
freeformConfig,
|
|
15960
|
+
isOpen,
|
|
15961
|
+
locale,
|
|
15962
|
+
requestedUnits,
|
|
15963
|
+
startDate,
|
|
15964
|
+
t,
|
|
15965
|
+
]);
|
|
15966
|
+
const billedDurationUnits = availability?.durationUnits ?? Math.max(1, Math.ceil(duration / Math.max(1, freeformConfig?.stepDuration ?? 1)));
|
|
15967
|
+
const basePrice = T$2(() => {
|
|
15968
|
+
if (!freeformConfig)
|
|
15969
|
+
return 0;
|
|
15970
|
+
if (freeformConfig.pricingModel === "perUnit") {
|
|
15971
|
+
return (freeformConfig.perUnitPrice ?? 0) * billedDurationUnits;
|
|
15972
|
+
}
|
|
15973
|
+
return calculateTieredPrice(billedDurationUnits, freeformConfig);
|
|
15974
|
+
}, [billedDurationUnits, freeformConfig]);
|
|
15975
|
+
const totalPrice = Math.max(0, basePrice * requestedUnits);
|
|
15976
|
+
const canContinueToPayment = !!freeformConfig &&
|
|
15977
|
+
customerName.trim().length >= 2 &&
|
|
15978
|
+
customerEmail.trim().length > 3 &&
|
|
15979
|
+
acceptTerms &&
|
|
15980
|
+
!!availability?.available &&
|
|
15981
|
+
!isCheckingAvailability;
|
|
15982
|
+
const freeformSelection = T$2(() => ({
|
|
15983
|
+
eventTypeId: eventType.id,
|
|
15984
|
+
start: startDate.toISOString(),
|
|
15985
|
+
end: endDate.toISOString(),
|
|
15986
|
+
requestedUnits,
|
|
15987
|
+
customerName: customerName.trim(),
|
|
15988
|
+
customerEmail: customerEmail.trim(),
|
|
15989
|
+
customerPhone: customerPhone.trim(),
|
|
15990
|
+
comment: comment.trim(),
|
|
15991
|
+
}), [
|
|
15992
|
+
comment,
|
|
15993
|
+
customerEmail,
|
|
15994
|
+
customerName,
|
|
15995
|
+
customerPhone,
|
|
15996
|
+
endDate,
|
|
15997
|
+
eventType.id,
|
|
15998
|
+
requestedUnits,
|
|
15999
|
+
startDate,
|
|
16000
|
+
]);
|
|
16001
|
+
const paymentFormData = T$2(() => ({
|
|
16002
|
+
customerName: customerName.trim(),
|
|
16003
|
+
customerEmail: customerEmail.trim(),
|
|
16004
|
+
customerPhone: customerPhone.trim(),
|
|
16005
|
+
participants: [{ name: customerName.trim() || customerEmail.trim(), level: undefined }],
|
|
16006
|
+
comment: comment.trim(),
|
|
16007
|
+
}), [comment, customerEmail, customerName, customerPhone]);
|
|
16008
|
+
const eventDetailsForPayment = T$2(() => ({
|
|
16009
|
+
id: eventType.id,
|
|
16010
|
+
name: eventType.name,
|
|
16011
|
+
startTime: startDate.toISOString(),
|
|
16012
|
+
endTime: endDate.toISOString(),
|
|
16013
|
+
price: basePrice,
|
|
16014
|
+
maxParticipants: availability?.capacityUnits ?? requestedUnits,
|
|
16015
|
+
participantCount: 0,
|
|
16016
|
+
availableSpots: availability?.freeUnits ?? requestedUnits,
|
|
16017
|
+
durationDays: 1,
|
|
16018
|
+
durationPerDay: availability?.roundedDurationMinutes ?? duration * unitMinutes,
|
|
16019
|
+
images: eventType.images ?? [],
|
|
16020
|
+
category: eventType.category,
|
|
16021
|
+
organization: {
|
|
16022
|
+
id: config.organizationId,
|
|
16023
|
+
name: "",
|
|
16024
|
+
},
|
|
16025
|
+
bookingOpen: availability?.available ?? false,
|
|
16026
|
+
}), [
|
|
16027
|
+
availability?.available,
|
|
16028
|
+
availability?.capacityUnits,
|
|
16029
|
+
availability?.freeUnits,
|
|
16030
|
+
availability?.roundedDurationMinutes,
|
|
16031
|
+
basePrice,
|
|
16032
|
+
config.organizationId,
|
|
16033
|
+
duration,
|
|
16034
|
+
endDate,
|
|
16035
|
+
eventType.category,
|
|
16036
|
+
eventType.id,
|
|
16037
|
+
eventType.images,
|
|
16038
|
+
eventType.name,
|
|
16039
|
+
requestedUnits,
|
|
16040
|
+
startDate,
|
|
16041
|
+
unitMinutes,
|
|
16042
|
+
]);
|
|
16043
|
+
const footer = (u$2("div", { style: { width: "100%", display: "flex", gap: "12px" }, children: [u$2("button", { type: "button", onClick: () => {
|
|
16044
|
+
if (checkoutStep === "payment") {
|
|
16045
|
+
setCheckoutStep("details");
|
|
16046
|
+
}
|
|
16047
|
+
else {
|
|
16048
|
+
onClose();
|
|
16049
|
+
}
|
|
16050
|
+
}, style: {
|
|
16051
|
+
flex: 1,
|
|
16052
|
+
padding: "12px 16px",
|
|
16053
|
+
border: "1px solid var(--bw-border-color)",
|
|
16054
|
+
borderRadius: "var(--bw-border-radius)",
|
|
16055
|
+
backgroundColor: "var(--bw-surface-color)",
|
|
16056
|
+
color: "var(--bw-text-color)",
|
|
16057
|
+
fontFamily: "var(--bw-font-family)",
|
|
16058
|
+
fontWeight: 600,
|
|
16059
|
+
cursor: "pointer",
|
|
16060
|
+
}, children: checkoutStep === "payment" ? t("button.backToDetails") : t("common.back") }), checkoutStep === "details" && (u$2("button", { type: "button", onClick: () => setCheckoutStep("payment"), disabled: !canContinueToPayment, style: {
|
|
16061
|
+
flex: 1,
|
|
16062
|
+
padding: "12px 16px",
|
|
16063
|
+
border: "none",
|
|
16064
|
+
borderRadius: "var(--bw-border-radius)",
|
|
16065
|
+
backgroundColor: "var(--bw-highlight-color)",
|
|
16066
|
+
color: "var(--bw-button-text-color, #ffffff)",
|
|
16067
|
+
fontFamily: "var(--bw-font-family)",
|
|
16068
|
+
fontWeight: 700,
|
|
16069
|
+
cursor: canContinueToPayment ? "pointer" : "not-allowed",
|
|
16070
|
+
opacity: canContinueToPayment ? 1 : 0.6,
|
|
16071
|
+
}, children: t("button.continueToPayment") }))] }));
|
|
16072
|
+
if (!freeformConfig) {
|
|
16073
|
+
return (u$2(Sidebar, { isOpen: isOpen, onClose: onClose, title: eventType.name, children: u$2("div", { style: { padding: "16px", color: "var(--bw-error-color)", fontFamily: "var(--bw-font-family)" }, children: t("booking.freeformMissingConfig") }) }));
|
|
16074
|
+
}
|
|
16075
|
+
return (u$2(Sidebar, { isOpen: isOpen, onClose: onClose, title: eventType.name, footer: footer, children: u$2("div", { style: { padding: "16px", display: "flex", flexDirection: "column", gap: "16px" }, children: checkoutStep === "details" ? (u$2(k$3, { children: [u$2("div", { style: { border: "1px solid var(--bw-border-color)", borderRadius: "var(--bw-border-radius)", padding: "14px", backgroundColor: "var(--bw-surface-color)" }, children: [u$2("h3", { style: { margin: "0 0 12px 0", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-color)" }, children: t("booking.eventDetails") }), u$2("div", { style: { display: "grid", gap: "10px" }, children: [u$2("label", { style: { display: "grid", gap: "6px", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-muted)" }, children: [t("booking.date"), u$2("input", { type: "datetime-local", value: startInput, onChange: (event) => setStartInput(event.target.value), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } })] }), u$2("label", { style: { display: "grid", gap: "6px", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-muted)" }, children: [t("booking.duration"), u$2("input", { type: "number", min: freeformConfig.minDuration, max: freeformConfig.maxDuration, step: freeformConfig.stepDuration, value: duration, onChange: (event) => setDuration(Number(event.target.value)), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } })] }), !isNamedResource && (u$2("label", { style: { display: "grid", gap: "6px", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-muted)" }, children: [t("voucher.quantity"), u$2("input", { type: "number", min: 1, max: maxUnits, value: requestedUnits, onChange: (event) => setRequestedUnits(Math.min(maxUnits, Math.max(1, Number(event.target.value)))), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } })] }))] }), u$2("div", { style: { marginTop: "12px", fontSize: "13px", color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: [formatInTimeZone(startDate, timeZone, locale), " - ", formatInTimeZone(endDate, timeZone, locale), eventType.organizationTimezone ? ` (${timeZone})` : ""] }), isCheckingAvailability && (u$2("div", { style: { marginTop: "8px", fontSize: "13px", color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)" }, children: t("common.loading") })), availabilityError && (u$2("div", { style: { marginTop: "8px", fontSize: "13px", color: "var(--bw-error-color)", fontFamily: "var(--bw-font-family)" }, children: availabilityError })), !availabilityError && availability && (u$2("div", { style: { marginTop: "8px", fontSize: "13px", color: availability.available ? "var(--bw-success-color)" : "var(--bw-error-color)", fontFamily: "var(--bw-font-family)" }, children: availability.available
|
|
16076
|
+
? t("booking.freeformUnitsAvailable", { count: availability.freeUnits })
|
|
16077
|
+
: t("booking.freeformNotAvailable") }))] }), u$2("div", { style: { border: "1px solid var(--bw-border-color)", borderRadius: "var(--bw-border-radius)", padding: "14px", backgroundColor: "var(--bw-surface-color)" }, children: [u$2("h3", { style: { margin: "0 0 12px 0", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-color)" }, children: t("booking.contactInfo") }), u$2("div", { style: { display: "grid", gap: "10px" }, children: [u$2("input", { type: "text", placeholder: t("booking.namePlaceholder"), value: customerName, onChange: (event) => setCustomerName(event.target.value), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } }), u$2("input", { type: "email", placeholder: t("booking.emailPlaceholder"), value: customerEmail, onChange: (event) => setCustomerEmail(event.target.value), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } }), u$2("input", { type: "tel", placeholder: t("booking.phonePlaceholder"), value: customerPhone, onChange: (event) => setCustomerPhone(event.target.value), style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)" } }), u$2("textarea", { placeholder: t("booking.commentPlaceholder"), value: comment, onChange: (event) => setComment(event.target.value), rows: 3, style: { padding: "10px", borderRadius: "var(--bw-border-radius-small)", border: "1px solid var(--bw-border-color)", backgroundColor: "var(--bw-background-color)", color: "var(--bw-text-color)", resize: "vertical" } }), u$2("label", { style: { display: "flex", alignItems: "center", gap: "8px", fontFamily: "var(--bw-font-family)", fontSize: "13px", color: "var(--bw-text-muted)" }, children: [u$2("input", { type: "checkbox", checked: acceptTerms, onChange: (event) => setAcceptTerms(event.target.checked) }), t("booking.acceptTerms"), " ", t("booking.terms")] })] })] }), u$2("div", { style: { border: "1px solid var(--bw-border-color)", borderRadius: "var(--bw-border-radius)", padding: "14px", backgroundColor: "var(--bw-surface-color)" }, children: [u$2("h3", { style: { margin: "0 0 12px 0", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-color)" }, children: t("summary.title") }), u$2("div", { style: { display: "flex", justifyContent: "space-between", color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)", fontSize: "14px" }, children: [u$2("span", { children: t("booking.duration") }), u$2("span", { children: t("booking.steps", { count: billedDurationUnits }) })] }), u$2("div", { style: { display: "flex", justifyContent: "space-between", color: "var(--bw-text-muted)", fontFamily: "var(--bw-font-family)", fontSize: "14px", marginTop: "6px" }, children: [u$2("span", { children: t("booking.price") }), u$2("span", { children: [formatCurrency(basePrice), " x ", requestedUnits] })] }), u$2("div", { style: { display: "flex", justifyContent: "space-between", color: "var(--bw-text-color)", fontFamily: "var(--bw-font-family)", fontSize: "20px", fontWeight: 700, marginTop: "10px" }, children: [u$2("span", { children: t("summary.totalAmount") }), u$2("span", { children: formatCurrency(totalPrice) })] })] })] })) : (u$2(k$3, { children: [u$2(HoldCountdown, {}), u$2("div", { style: { border: "1px solid var(--bw-border-color)", borderRadius: "var(--bw-border-radius)", padding: "14px", backgroundColor: "var(--bw-surface-color)" }, children: [u$2("h3", { style: { margin: "0 0 12px 0", fontFamily: "var(--bw-font-family)", color: "var(--bw-text-color)" }, children: t("summary.payment") }), !systemConfig?.paymentProvider && (u$2("p", { style: { margin: 0, color: "var(--bw-error-color)", fontFamily: "var(--bw-font-family)" }, children: t("booking.paymentUnavailable") })), systemConfig?.paymentProvider === "mollie" && (u$2(MolliePaymentForm, { config: config, eventDetails: eventDetailsForPayment, formData: paymentFormData, totalAmount: totalPrice, discountCode: null, giftCards: [], onSuccess: onSuccess, onError: onError, mollieProfileId: systemConfig?.mollieProfileId, mollieTestmode: systemConfig?.mollieTestmode, freeformSelection: freeformSelection })), systemConfig?.paymentProvider === "stripe" && (u$2(StripePaymentForm, { config: config, eventDetails: eventDetailsForPayment, formData: paymentFormData, totalAmount: totalPrice, discountCode: null, giftCards: [], onSuccess: onSuccess, onError: onError, systemConfig: systemConfig, freeformSelection: freeformSelection }))] })] })) }) }));
|
|
16078
|
+
}
|
|
16079
|
+
|
|
15518
16080
|
const getThemeConfig = (theme = "generic") => {
|
|
15519
16081
|
switch (theme) {
|
|
15520
16082
|
case "christmas":
|
|
@@ -16149,12 +16711,14 @@
|
|
|
16149
16711
|
const [isSuccess, setIsSuccess] = d$1(false);
|
|
16150
16712
|
const [successPaymentId, setSuccessPaymentId] = d$1(null);
|
|
16151
16713
|
const [systemConfig, setSystemConfig] = d$1(null);
|
|
16714
|
+
const [waitlistEnabled, setWaitlistEnabled] = d$1(false);
|
|
16152
16715
|
// When true, loadEventInstances skips the single-instance auto-select (used by handleShowAllEvents)
|
|
16153
16716
|
const skipInstanceAutoSelectRef = A$2(false);
|
|
16154
16717
|
// PERFORMANCE OPTIMIZATION: Lazy component loading
|
|
16155
16718
|
const [shouldRenderInstanceSelection, setShouldRenderInstanceSelection] = d$1(false);
|
|
16156
16719
|
const [shouldRenderUpsells, setShouldRenderUpsells] = d$1(false);
|
|
16157
16720
|
const [shouldRenderBookingForm, setShouldRenderBookingForm] = d$1(false);
|
|
16721
|
+
const [shouldRenderFreeformSelection, setShouldRenderFreeformSelection] = d$1(false);
|
|
16158
16722
|
// Google Ads config (received from API, set once from the first API response)
|
|
16159
16723
|
const [googleAdsConfig, setGoogleAdsConfig] = d$1(null);
|
|
16160
16724
|
const extractGoogleAdsConfig = (data) => {
|
|
@@ -16168,6 +16732,7 @@
|
|
|
16168
16732
|
// Voucher purchase state
|
|
16169
16733
|
const [voucherConfig, setVoucherConfig] = d$1(null);
|
|
16170
16734
|
const [voucherEventTypes, setVoucherEventTypes] = d$1([]);
|
|
16735
|
+
const [voucherCategories, setVoucherCategories] = d$1([]);
|
|
16171
16736
|
const [isLoadingVoucherConfig, setIsLoadingVoucherConfig] = d$1(false);
|
|
16172
16737
|
const [isVoucherFormOpen, setIsVoucherFormOpen] = d$1(false);
|
|
16173
16738
|
const [voucherPurchaseResult, setVoucherPurchaseResult] = d$1(null);
|
|
@@ -16247,6 +16812,7 @@
|
|
|
16247
16812
|
setVoucherConfig(mergedConfig);
|
|
16248
16813
|
extractGoogleAdsConfig(data);
|
|
16249
16814
|
setVoucherEventTypes(data.eventTypes || []);
|
|
16815
|
+
setVoucherCategories(data.categories || []);
|
|
16250
16816
|
// Set system config for payment processing
|
|
16251
16817
|
if (data.paymentProvider) {
|
|
16252
16818
|
setSystemConfig({
|
|
@@ -16275,7 +16841,7 @@
|
|
|
16275
16841
|
if (!analyticsInitRef.current && config.organizationId) {
|
|
16276
16842
|
analyticsInitRef.current = true;
|
|
16277
16843
|
initAnalytics(config.apiBaseUrl, config.organizationId, {
|
|
16278
|
-
partnerContractId: config.partnerContractId,
|
|
16844
|
+
...(config.partnerContractId ? { partnerContractId: config.partnerContractId } : {}),
|
|
16279
16845
|
});
|
|
16280
16846
|
trackEvent("widget_loaded", {
|
|
16281
16847
|
viewMode,
|
|
@@ -16639,6 +17205,7 @@
|
|
|
16639
17205
|
}
|
|
16640
17206
|
extractGoogleAdsConfig(data);
|
|
16641
17207
|
setEventInstances(data.eventInstances);
|
|
17208
|
+
setWaitlistEnabled(data.waitlistEnabled ?? false);
|
|
16642
17209
|
if (data.paymentProvider) {
|
|
16643
17210
|
setSystemConfig({
|
|
16644
17211
|
paymentProvider: data.paymentProvider,
|
|
@@ -16754,6 +17321,18 @@
|
|
|
16754
17321
|
const handleEventTypeSelect = async (eventType) => {
|
|
16755
17322
|
trackEvent("event_type_selected", { eventTypeId: eventType.id, eventTypeName: eventType.name });
|
|
16756
17323
|
setSelectedEventType(eventType);
|
|
17324
|
+
if (eventType.bookingMode === "freeform") {
|
|
17325
|
+
setCurrentStep("freeform");
|
|
17326
|
+
setShouldRenderFreeformSelection(true);
|
|
17327
|
+
setIsLoadingEventInstances(true);
|
|
17328
|
+
try {
|
|
17329
|
+
await loadEventInstances(eventType.id);
|
|
17330
|
+
}
|
|
17331
|
+
finally {
|
|
17332
|
+
setIsLoadingEventInstances(false);
|
|
17333
|
+
}
|
|
17334
|
+
return;
|
|
17335
|
+
}
|
|
16757
17336
|
setCurrentStep("eventInstances");
|
|
16758
17337
|
setShouldRenderInstanceSelection(true);
|
|
16759
17338
|
setIsLoadingEventInstances(true);
|
|
@@ -16844,6 +17423,7 @@
|
|
|
16844
17423
|
setSuccessPaymentId(result.paymentIntent.id);
|
|
16845
17424
|
setSidebarOpen(false);
|
|
16846
17425
|
setShouldRenderBookingForm(false);
|
|
17426
|
+
setShouldRenderFreeformSelection(false);
|
|
16847
17427
|
setBookingPersistedState(null);
|
|
16848
17428
|
config.onSuccess?.(result);
|
|
16849
17429
|
};
|
|
@@ -17159,6 +17739,7 @@
|
|
|
17159
17739
|
setShouldRenderInstanceSelection(false);
|
|
17160
17740
|
setShouldRenderUpsells(false);
|
|
17161
17741
|
setShouldRenderBookingForm(false);
|
|
17742
|
+
setShouldRenderFreeformSelection(false);
|
|
17162
17743
|
setSelectedUpsells([]);
|
|
17163
17744
|
setUpsells([]);
|
|
17164
17745
|
setBookingPersistedState(null);
|
|
@@ -17180,6 +17761,7 @@
|
|
|
17180
17761
|
setShouldRenderInstanceSelection(false);
|
|
17181
17762
|
setShouldRenderUpsells(false);
|
|
17182
17763
|
setShouldRenderBookingForm(false);
|
|
17764
|
+
setShouldRenderFreeformSelection(false);
|
|
17183
17765
|
setSelectedUpsells([]);
|
|
17184
17766
|
setUpsells([]);
|
|
17185
17767
|
setBookingPersistedState(null);
|
|
@@ -17192,13 +17774,14 @@
|
|
|
17192
17774
|
}, isOpen: currentStep === "eventInstances", onClose: () => {
|
|
17193
17775
|
setShowingPreview(true);
|
|
17194
17776
|
setCurrentStep("eventTypes");
|
|
17195
|
-
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
17777
|
+
}, isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
17196
17778
|
setIsSuccess(false);
|
|
17197
17779
|
setCurrentStep("eventTypes");
|
|
17198
17780
|
setShowingPreview(true);
|
|
17199
17781
|
setSuccessPaymentId(null);
|
|
17200
17782
|
setShouldRenderInstanceSelection(false);
|
|
17201
17783
|
setShouldRenderBookingForm(false);
|
|
17784
|
+
setShouldRenderFreeformSelection(false);
|
|
17202
17785
|
const url = new URL(window.location.href);
|
|
17203
17786
|
url.searchParams.delete("payment_intent");
|
|
17204
17787
|
url.searchParams.delete("payment_intent_client_secret");
|
|
@@ -17242,13 +17825,23 @@
|
|
|
17242
17825
|
setCurrentStep("booking");
|
|
17243
17826
|
setShouldRenderBookingForm(true);
|
|
17244
17827
|
}
|
|
17828
|
+
else if (selectedEventType?.bookingMode === "freeform") {
|
|
17829
|
+
setCurrentStep("freeform");
|
|
17830
|
+
setShouldRenderFreeformSelection(true);
|
|
17831
|
+
}
|
|
17245
17832
|
else {
|
|
17246
17833
|
setCurrentStep("eventInstances");
|
|
17247
17834
|
setSidebarOpen(true);
|
|
17248
17835
|
setShouldRenderInstanceSelection(true);
|
|
17249
17836
|
}
|
|
17250
17837
|
}, children: [isButtonBusy && u$2(Spinner, { size: 20, borderColor: "var(--bw-button-text-color, #ffffff)" }), config.buttonText ||
|
|
17251
|
-
(isDirectInstanceMode
|
|
17838
|
+
(isDirectInstanceMode || selectedEventType?.bookingMode === "freeform"
|
|
17839
|
+
? t("button.bookNow")
|
|
17840
|
+
: t("button.viewDates"))] }), shouldRenderInstanceSelection && (u$2(EventInstanceSelection, { eventInstances: eventInstances, selectedEventType: selectedEventType, onEventInstanceSelect: handleEventInstanceSelect, onBackToEventTypes: () => setSidebarOpen(false), isOpen: sidebarOpen && currentStep === "eventInstances", onClose: () => setSidebarOpen(false), isLoadingEventInstances: isLoadingEventInstances, isLoadingEventDetails: isLoadingEventDetails, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (u$2(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: handleBackFromBooking, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (u$2(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
|
|
17841
|
+
setCurrentStep("eventTypes");
|
|
17842
|
+
setSidebarOpen(false);
|
|
17843
|
+
setShouldRenderFreeformSelection(false);
|
|
17844
|
+
}, onSuccess: handleBookingSuccess, onError: handleBookingError, systemConfig: systemConfig })), u$2(BookingSuccessModal, { isOpen: isSuccess, onClose: () => {
|
|
17252
17845
|
setIsSuccess(false);
|
|
17253
17846
|
setCurrentStep("eventTypes");
|
|
17254
17847
|
setSidebarOpen(false);
|
|
@@ -17256,6 +17849,7 @@
|
|
|
17256
17849
|
setShouldRenderInstanceSelection(false);
|
|
17257
17850
|
setShouldRenderUpsells(false);
|
|
17258
17851
|
setShouldRenderBookingForm(false);
|
|
17852
|
+
setShouldRenderFreeformSelection(false);
|
|
17259
17853
|
setSelectedUpsells([]);
|
|
17260
17854
|
setUpsells([]);
|
|
17261
17855
|
const url = new URL(window.location.href);
|
|
@@ -17268,7 +17862,7 @@
|
|
|
17268
17862
|
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId })] }), showPromoDialog && config.promo && (u$2(PromoDialog, { config: config.promo, onClose: handlePromoDialogClose, onCtaClick: handlePromoCtaClick }))] }));
|
|
17269
17863
|
}
|
|
17270
17864
|
// Cards mode (default) - show event type selection with optional voucher card
|
|
17271
|
-
const cardsView = (u$2(k$3, { children: [hasEventSelection && (u$2(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, onInstancePreview: (instanceId, eventTypeId) => void handleUpcomingEventSelect(instanceId, eventTypeId), isLoading: isLoading, skeletonCount: getSkeletonCount(), showVoucherAttachment: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled && !isStandaloneVoucherMode), onVoucherClick: handleVoucherAttachmentClick })), isStandaloneVoucherMode && (u$2(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, systemConfig: systemConfig, isFormOpen: false, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: null, voucherPurchaseResult: null, isSuccess: false, showStandaloneCard: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled), onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => { } })), isStandaloneVoucherMode && isLoading && !voucherConfig && (u$2("div", { style: { padding: "24px", textAlign: "center" }, children: u$2("div", { style: {
|
|
17865
|
+
const cardsView = (u$2(k$3, { children: [hasEventSelection && (u$2(EventTypeSelection, { eventTypes: eventTypes, onEventTypeSelect: handleEventTypeSelect, onInstancePreview: (instanceId, eventTypeId) => void handleUpcomingEventSelect(instanceId, eventTypeId), isLoading: isLoading, skeletonCount: getSkeletonCount(), showVoucherAttachment: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled && !isStandaloneVoucherMode), onVoucherClick: handleVoucherAttachmentClick, showImages: config.showEventImages !== false })), isStandaloneVoucherMode && (u$2(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, categories: voucherCategories, systemConfig: systemConfig, isFormOpen: false, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: null, voucherPurchaseResult: null, isSuccess: false, showStandaloneCard: Boolean(voucherConfig?.enabled && voucherCardIntegrationEnabled), onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => { } })), isStandaloneVoucherMode && isLoading && !voucherConfig && (u$2("div", { style: { padding: "24px", textAlign: "center" }, children: u$2("div", { style: {
|
|
17272
17866
|
display: "inline-block",
|
|
17273
17867
|
width: "32px",
|
|
17274
17868
|
height: "32px",
|
|
@@ -17309,13 +17903,17 @@
|
|
|
17309
17903
|
};
|
|
17310
17904
|
};
|
|
17311
17905
|
const backHandlers = getBackHandlers();
|
|
17312
|
-
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, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (u$2(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), u$2(
|
|
17906
|
+
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, hasUpsellsStep: hasUpsellsFlowStep, apiBaseUrl: config.apiBaseUrl, organizationId: config.organizationId, waitlistEnabled: waitlistEnabled })), shouldRenderUpsells && (u$2(UpsellsStep, { upsells: upsells, selectedUpsells: selectedUpsells, participantCount: tempParticipantCount, isLoading: isLoadingUpsells, isOpen: currentStep === "upsells", onClose: () => setCurrentStep("eventInstances"), onSelect: handleUpsellsSelect, onContinue: handleUpsellsContinue, onBack: handleUpsellsBack })), shouldRenderBookingForm && eventDetails && (u$2(BookingForm, { config: config, eventDetails: eventDetails, onSuccess: handleBookingSuccess, onError: handleBookingError, isOpen: currentStep === "booking" && !!eventDetails, onClose: backHandlers.onClose, systemConfig: systemConfig, selectedUpsells: selectedUpsells, upsells: upsells, persistedState: bookingPersistedState, onPersistedStateChange: setBookingPersistedState })), shouldRenderFreeformSelection && selectedEventType?.bookingMode === "freeform" && (u$2(FreeformSelection, { config: config, eventType: selectedEventType, isOpen: currentStep === "freeform", onClose: () => {
|
|
17907
|
+
setCurrentStep("eventTypes");
|
|
17908
|
+
setShouldRenderFreeformSelection(false);
|
|
17909
|
+
}, onSuccess: handleBookingSuccess, onError: handleBookingError, systemConfig: systemConfig })), u$2(BookingSuccessModal, { isOpen: isSuccess && !voucherPurchaseResult, onClose: () => {
|
|
17313
17910
|
setIsSuccess(false);
|
|
17314
17911
|
setCurrentStep("eventTypes");
|
|
17315
17912
|
setSuccessPaymentId(null);
|
|
17316
17913
|
setShouldRenderInstanceSelection(false);
|
|
17317
17914
|
setShouldRenderUpsells(false);
|
|
17318
17915
|
setShouldRenderBookingForm(false);
|
|
17916
|
+
setShouldRenderFreeformSelection(false);
|
|
17319
17917
|
setSelectedUpsells([]);
|
|
17320
17918
|
setUpsells([]);
|
|
17321
17919
|
const url = new URL(window.location.href);
|
|
@@ -17325,7 +17923,7 @@
|
|
|
17325
17923
|
url.searchParams.delete("mollie_payment_id");
|
|
17326
17924
|
url.searchParams.delete("mollie_status");
|
|
17327
17925
|
window.history.replaceState({}, "", url.toString());
|
|
17328
|
-
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId }), u$2(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, systemConfig: systemConfig, isFormOpen: isVoucherFormOpen, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: preselectedVoucherEventTypeId, voucherPurchaseResult: voucherPurchaseResult, isSuccess: isSuccess, showStandaloneCard: false, onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => {
|
|
17926
|
+
}, config: config, googleAdsConfig: googleAdsConfig, onError: setError, paymentIntentId: successPaymentId }), u$2(VoucherIntegration, { config: config, voucherConfig: voucherConfig, eventTypes: voucherEventTypes, categories: voucherCategories, systemConfig: systemConfig, isFormOpen: isVoucherFormOpen, isLoadingConfig: isLoadingVoucherConfig, preselectedEventTypeId: preselectedVoucherEventTypeId, voucherPurchaseResult: voucherPurchaseResult, isSuccess: isSuccess, showStandaloneCard: false, onCardClick: handleVoucherCardClick, onFormClose: handleVoucherFormClose, onSuccess: handleVoucherSuccess, onError: handleVoucherError, onSuccessModalClose: () => {
|
|
17329
17927
|
setIsSuccess(false);
|
|
17330
17928
|
setVoucherPurchaseResult(null);
|
|
17331
17929
|
const url = new URL(window.location.href);
|
|
@@ -17378,7 +17976,7 @@
|
|
|
17378
17976
|
}
|
|
17379
17977
|
}
|
|
17380
17978
|
|
|
17381
|
-
var css_248z = ".booking-widget-container{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;color:var(--bw-text-color,#1e293b);direction:ltr;display:block;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;position:relative;text-align:left}.booking-widget-container *,.booking-widget-container :after,.booking-widget-container :before{box-sizing:border-box;margin:0;padding:0}.booking-widget-container input,.booking-widget-container select,.booking-widget-container textarea{font-family:inherit;font-size:inherit;line-height:inherit}.booking-widget-container button{background:none;border:none;cursor:pointer;font-family:inherit;font-size:inherit}.booking-widget-container a{color:inherit;text-decoration:none}.booking-widget-container img{display:block;height:auto;max-width:100%;vertical-align:middle}.booking-widget-container ol,.booking-widget-container ul{list-style:none}.booking-widget-container h1,.booking-widget-container h2,.booking-widget-container h3,.booking-widget-container h4,.booking-widget-container h5,.booking-widget-container h6{font-size:inherit;font-weight:inherit}#booking-widget-portal{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);direction:ltr;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;text-align:left}#booking-widget-portal *,#booking-widget-portal :after,#booking-widget-portal :before{box-sizing:border-box}#booking-widget-portal-root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);line-height:1.5}:root{--bw-highlight-color:#00b1aa;--bw-highlight-color-rgb:0,177,170;--bw-background-color:#f8fdfe;--bw-surface-color:#fff;--bw-text-color:#0e7490;--bw-text-muted:rgba(14,116,144,.7);--bw-border-color:#bae6fd;--bw-success-color:#38bdf8;--bw-warning-color:#fbbf24;--bw-error-color:#f43f5e;--bw-border-radius:18px;--bw-border-radius-small:calc(var(--bw-border-radius)*0.8);--bw-spacing:16px;--bw-spacing-large:24px;--bw-font-family:\"Inter\",system-ui,sans-serif;--bw-font-size:14px;--bw-font-size-large:18px;--bw-font-size-small:12px;--bw-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);--bw-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--bw-highlight-muted:rgba(0,177,170,.1);--bw-highlight-subtle:rgba(0,177,170,.05);--bw-text-subtle:rgba(14,116,144,.4)}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-out{0%{opacity:1}to{opacity:0}}@keyframes slide-in-right{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes slide-out-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(100%)}}@keyframes slide-in-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.animate-spin{animation:spin 1s linear infinite}.animate-shimmer{animation:shimmer 2s infinite}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-in-up{animation:slide-in-up .3s ease-out}.animate-scale-in{animation:scale-in .2s ease-out}.skeleton-shimmer{overflow:hidden;position:relative}.skeleton-shimmer:after{animation:shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.3),transparent);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.bw-btn{letter-spacing:var(--bw-letter-spacing,normal);text-transform:var(--bw-text-transform,none);transition:all .2s ease!important}.bw-btn:hover:not(:disabled):not([disabled]){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-btn:active:not(:disabled):not([disabled]){box-shadow:0 2px 4px rgba(0,0,0,.1)}.bw-btn-primary:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);filter:brightness(1.1)}.bw-btn-secondary:hover:not(:disabled):not([disabled]){background-color:var(--bw-surface-color);border-color:var(--bw-highlight-color);color:var(--bw-highlight-color)}.bw-btn-ghost:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-muted)}.bw-btn-outline:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);color:var(--bw-button-text-color,#fff)}.bw-btn:disabled,.bw-btn[disabled]{cursor:not-allowed!important;opacity:.5!important}button[class*=bw-btn],button[style*=transition]{transition:all .2s ease!important}button[data-variant=primary]:hover:not(:disabled),button[style*=\"--bw-highlight-color\"]:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);filter:brightness(1.1);transform:translateY(-1px)}button[data-variant=secondary]:hover:not(:disabled){border-color:var(--bw-highlight-color)!important;color:var(--bw-highlight-color)!important}button[data-variant=ghost]:hover:not(:disabled){background-color:var(--bw-highlight-muted)!important}button[data-variant=outline]:hover:not(:disabled){background-color:var(--bw-highlight-color)!important;color:var(--bw-button-text-color,#fff)!important}.bw-button-hover:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.bw-button-hover:active:not(:disabled){box-shadow:0 2px 4px rgba(0,0,0,.1);transform:translateY(0)}@media (max-width:768px){.sidebar-mobile{border-radius:0!important;max-width:100%!important;width:100%!important}}@media (max-width:600px){.event-type-list{gap:12px!important;padding:8px!important}.event-type-card{flex:1 1 100%!important;max-width:100%!important;padding:0!important}.event-type-img{height:160px!important}.event-type-title{font-size:1.1rem!important}.event-type-desc{font-size:.8rem!important;max-height:100px!important;min-height:100px!important}.event-type-content{padding:16px 24px!important}}.event-type-markdown{overflow:visible!important}.event-type-markdown p{color:var(--bw-text-muted);font-family:var(--bw-font-family);line-height:1.6;margin:0 0 8px}.event-type-markdown p:last-child{margin-bottom:0}.event-type-markdown h2{font-size:18px!important;font-weight:700!important;margin:12px 0 6px!important}.event-type-markdown h2,.event-type-markdown h3{color:var(--bw-text-color)!important;line-height:1.3!important}.event-type-markdown h3{font-size:16px!important;font-weight:600!important;margin:10px 0 4px!important}.event-type-markdown strong{color:var(--bw-text-color);font-weight:600}.event-type-markdown em{font-style:italic}.event-type-markdown u{text-decoration:underline}.event-type-markdown ul{list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ul li{color:var(--bw-text-muted)!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ul li:before{color:var(--bw-text-color)!important;content:\"•\"!important;font-weight:700!important;left:-16px!important;position:absolute!important;top:0!important}.event-type-markdown ol{counter-reset:list-counter!important;list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ol li{color:var(--bw-text-muted)!important;counter-increment:list-counter!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ol li:before{color:var(--bw-text-color)!important;content:counter(list-counter) \".\"!important;font-weight:700!important;left:-20px!important;position:absolute!important;top:0!important}.event-type-markdown blockquote{border-left:2px solid var(--bw-border-color);color:var(--bw-text-muted);font-style:italic;margin:4px 0;padding-left:12px}.event-type-markdown a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{color:var(--bw-text-color);font-weight:600;margin-bottom:.5em}.markdown-content h1{font-size:1.5em}.markdown-content h2{font-size:1.25em}.markdown-content h3{font-size:1.1em}.markdown-content p{line-height:1.6;margin-bottom:1em}.markdown-content ol,.markdown-content ul{margin-bottom:1em;padding-left:1.5em}.markdown-content ul{list-style-type:disc}.markdown-content ol{list-style-type:decimal}.markdown-content li{margin-bottom:.25em}.markdown-content a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content a:hover{opacity:.8}.markdown-content strong{font-weight:600}.markdown-content em{font-style:italic}.markdown-content code{background:var(--bw-highlight-subtle);border-radius:4px;font-family:monospace;font-size:.9em;padding:.125em .25em}.markdown-content blockquote{border-left:3px solid var(--bw-highlight-color);color:var(--bw-text-muted);margin:1em 0;padding-left:1em}.print-only{display:none}.print-hidden{display:block}@media print{.print-only{display:block}.print-hidden{display:none!important}.print-booking-header{border-bottom:2px solid #000;display:block;margin-bottom:24px;padding-bottom:16px;text-align:center}.print-booking-header h1{font-size:24px;margin:0 0 8px}.print-booking-header .subtitle{color:#666;font-size:14px}.print-booking-card{border:1px solid #ccc;border-radius:8px;margin-bottom:16px;padding:16px;page-break-inside:avoid}.print-section-title{border-bottom:1px solid #ddd;display:block;font-size:16px;font-weight:600;margin-bottom:12px;padding-bottom:8px}.print-detail-grid{display:grid;gap:12px;grid-template-columns:1fr 1fr}.print-detail-item{margin-bottom:8px}.print-detail-label{color:#666;font-size:12px;margin-bottom:4px}.print-detail-value{font-size:14px;font-weight:600}.print-status-badge{border-radius:9999px;display:inline-block;font-size:12px;font-weight:600;padding:4px 12px}.print-status-paid{background-color:#dcfce7;color:#166534;display:inline-block}.print-participant{align-items:center;background-color:#f9fafb;border-radius:4px;display:flex;justify-content:space-between;margin-bottom:8px;padding:8px}.print-participant-name{font-weight:600}.print-participant-age{color:#666;font-size:12px}.print-payment-summary{display:block}.print-payment-row{border-bottom:1px solid #eee;display:flex;justify-content:space-between;padding:4px 0}.print-payment-row:last-child{border-bottom:none;font-weight:600}.print-footer{border-top:1px solid #ddd;color:#666;display:block;font-size:12px;margin-top:24px;padding-top:16px;text-align:center}.print-footer p{margin:4px 0}}";
|
|
17979
|
+
var css_248z = ".booking-widget-container{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;color:var(--bw-text-color,#1e293b);direction:ltr;display:block;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;position:relative;text-align:left}.booking-widget-container *,.booking-widget-container :after,.booking-widget-container :before{box-sizing:border-box;margin:0;padding:0}.booking-widget-container input,.booking-widget-container select,.booking-widget-container textarea{font-family:inherit;font-size:inherit;line-height:inherit}.booking-widget-container button{background:none;border:none;cursor:pointer;font-family:inherit;font-size:inherit}.booking-widget-container a{color:inherit;text-decoration:none}.booking-widget-container img{display:block;height:auto;max-width:100%;vertical-align:middle}.booking-widget-container ol,.booking-widget-container ul{list-style:none}.booking-widget-container h1,.booking-widget-container h2,.booking-widget-container h3,.booking-widget-container h4,.booking-widget-container h5,.booking-widget-container h6{font-size:inherit;font-weight:inherit}#booking-widget-portal{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);direction:ltr;font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);isolation:isolate;line-height:1.5;text-align:left}#booking-widget-portal *,#booking-widget-portal :after,#booking-widget-portal :before{box-sizing:border-box}#booking-widget-portal-root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--bw-text-color,#1e293b);font-family:var(--bw-font-family,system-ui,-apple-system,sans-serif);font-size:var(--bw-font-size,14px);line-height:1.5}:root{--bw-highlight-color:#00b1aa;--bw-highlight-color-rgb:0,177,170;--bw-background-color:#f8fdfe;--bw-surface-color:#fff;--bw-text-color:#0e7490;--bw-text-muted:rgba(14,116,144,.7);--bw-border-color:#bae6fd;--bw-success-color:#38bdf8;--bw-warning-color:#fbbf24;--bw-error-color:#f43f5e;--bw-border-radius:18px;--bw-border-radius-small:calc(var(--bw-border-radius)*0.8);--bw-spacing:16px;--bw-spacing-large:24px;--bw-font-family:\"Inter\",system-ui,sans-serif;--bw-font-size:14px;--bw-font-size-large:18px;--bw-font-size-small:12px;--bw-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);--bw-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--bw-highlight-muted:rgba(0,177,170,.1);--bw-highlight-subtle:rgba(0,177,170,.05);--bw-text-subtle:rgba(14,116,144,.4)}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-out{0%{opacity:1}to{opacity:0}}@keyframes slide-in-right{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes slide-out-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(100%)}}@keyframes slide-in-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes scale-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.animate-spin{animation:spin 1s linear infinite}.animate-shimmer{animation:shimmer 2s infinite}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-in-up{animation:slide-in-up .3s ease-out}.animate-scale-in{animation:scale-in .2s ease-out}.skeleton-shimmer{overflow:hidden;position:relative}.skeleton-shimmer:after{animation:shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.3),transparent);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.booking-widget-container .bw-btn{letter-spacing:var(--bw-letter-spacing,normal);text-transform:var(--bw-text-transform,none);transition:all .2s ease!important}.booking-widget-container .bw-btn:hover:not(:disabled):not([disabled]){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.booking-widget-container .bw-btn:active:not(:disabled):not([disabled]){box-shadow:0 2px 4px rgba(0,0,0,.1)}.booking-widget-container .bw-btn-primary:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);filter:brightness(1.1)}.booking-widget-container .bw-btn-secondary:hover:not(:disabled):not([disabled]){background-color:var(--bw-surface-color);border-color:var(--bw-highlight-color);color:var(--bw-highlight-color)}.booking-widget-container .bw-btn-ghost:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-muted)}.booking-widget-container .bw-btn-outline:hover:not(:disabled):not([disabled]){background-color:var(--bw-highlight-color);color:var(--bw-button-text-color,#fff)}.booking-widget-container .bw-btn:disabled,.booking-widget-container .bw-btn[disabled]{cursor:not-allowed!important;opacity:.5!important}.booking-widget-container button[class*=bw-btn],.booking-widget-container button[style*=transition]{transition:all .2s ease!important}.booking-widget-container button[data-variant=primary]:hover:not(:disabled),.booking-widget-container button[style*=\"--bw-highlight-color\"]:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);filter:brightness(1.1);transform:translateY(-1px)}.booking-widget-container button[data-variant=secondary]:hover:not(:disabled){border-color:var(--bw-highlight-color)!important;color:var(--bw-highlight-color)!important}.booking-widget-container button[data-variant=ghost]:hover:not(:disabled){background-color:var(--bw-highlight-muted)!important}.booking-widget-container button[data-variant=outline]:hover:not(:disabled){background-color:var(--bw-highlight-color)!important;color:var(--bw-button-text-color,#fff)!important}.booking-widget-container .bw-button-hover:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.booking-widget-container .bw-button-hover:active:not(:disabled){box-shadow:0 2px 4px rgba(0,0,0,.1);transform:translateY(0)}@media (max-width:768px){.sidebar-mobile{border-radius:0!important;max-width:100%!important;width:100%!important}}@media (max-width:600px){.event-type-list{gap:12px!important;padding:8px!important}.event-type-card{flex:1 1 100%!important;max-width:100%!important;padding:0!important}.event-type-img{height:160px!important}.event-type-title{font-size:1.1rem!important}.event-type-desc{font-size:.8rem!important;max-height:100px!important;min-height:100px!important}.event-type-content{padding:16px 24px!important}}.event-type-markdown{overflow:visible!important}.event-type-markdown p{color:var(--bw-text-muted);font-family:var(--bw-font-family);line-height:1.6;margin:0 0 8px}.event-type-markdown p:last-child{margin-bottom:0}.event-type-markdown h2{font-size:18px!important;font-weight:700!important;margin:12px 0 6px!important}.event-type-markdown h2,.event-type-markdown h3{color:var(--bw-text-color)!important;line-height:1.3!important}.event-type-markdown h3{font-size:16px!important;font-weight:600!important;margin:10px 0 4px!important}.event-type-markdown strong{color:var(--bw-text-color);font-weight:600}.event-type-markdown em{font-style:italic}.event-type-markdown u{text-decoration:underline}.event-type-markdown ul{list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ul li{color:var(--bw-text-muted)!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ul li:before{color:var(--bw-text-color)!important;content:\"•\"!important;font-weight:700!important;left:-16px!important;position:absolute!important;top:0!important}.event-type-markdown ol{counter-reset:list-counter!important;list-style:none!important;margin:6px 0!important;padding:0 0 0 24px!important;position:relative!important}.event-type-markdown ol li{color:var(--bw-text-muted)!important;counter-increment:list-counter!important;font-family:var(--bw-font-family)!important;margin-bottom:2px!important;padding-left:0!important;position:relative!important}.event-type-markdown ol li:before{color:var(--bw-text-color)!important;content:counter(list-counter) \".\"!important;font-weight:700!important;left:-20px!important;position:absolute!important;top:0!important}.event-type-markdown blockquote{border-left:2px solid var(--bw-border-color);color:var(--bw-text-muted);font-style:italic;margin:4px 0;padding-left:12px}.event-type-markdown a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{color:var(--bw-text-color);font-weight:600;margin-bottom:.5em}.markdown-content h1{font-size:1.5em}.markdown-content h2{font-size:1.25em}.markdown-content h3{font-size:1.1em}.markdown-content p{line-height:1.6;margin-bottom:1em}.markdown-content ol,.markdown-content ul{margin-bottom:1em;padding-left:1.5em}.markdown-content ul{list-style-type:disc}.markdown-content ol{list-style-type:decimal}.markdown-content li{margin-bottom:.25em}.markdown-content a{color:var(--bw-highlight-color);text-decoration:underline}.markdown-content a:hover{opacity:.8}.markdown-content strong{font-weight:600}.markdown-content em{font-style:italic}.markdown-content code{background:var(--bw-highlight-subtle);border-radius:4px;font-family:monospace;font-size:.9em;padding:.125em .25em}.markdown-content blockquote{border-left:3px solid var(--bw-highlight-color);color:var(--bw-text-muted);margin:1em 0;padding-left:1em}.print-only{display:none}.print-hidden{display:block}@media print{.print-only{display:block}.print-hidden{display:none!important}.print-booking-header{border-bottom:2px solid #000;display:block;margin-bottom:24px;padding-bottom:16px;text-align:center}.print-booking-header h1{font-size:24px;margin:0 0 8px}.print-booking-header .subtitle{color:#666;font-size:14px}.print-booking-card{border:1px solid #ccc;border-radius:8px;margin-bottom:16px;padding:16px;page-break-inside:avoid}.print-section-title{border-bottom:1px solid #ddd;display:block;font-size:16px;font-weight:600;margin-bottom:12px;padding-bottom:8px}.print-detail-grid{display:grid;gap:12px;grid-template-columns:1fr 1fr}.print-detail-item{margin-bottom:8px}.print-detail-label{color:#666;font-size:12px;margin-bottom:4px}.print-detail-value{font-size:14px;font-weight:600}.print-status-badge{border-radius:9999px;display:inline-block;font-size:12px;font-weight:600;padding:4px 12px}.print-status-paid{background-color:#dcfce7;color:#166534;display:inline-block}.print-participant{align-items:center;background-color:#f9fafb;border-radius:4px;display:flex;justify-content:space-between;margin-bottom:8px;padding:8px}.print-participant-name{font-weight:600}.print-participant-age{color:#666;font-size:12px}.print-payment-summary{display:block}.print-payment-row{border-bottom:1px solid #eee;display:flex;justify-content:space-between;padding:4px 0}.print-payment-row:last-child{border-bottom:none;font-weight:600}.print-footer{border-top:1px solid #ddd;color:#666;display:block;font-size:12px;margin-top:24px;padding-top:16px;text-align:center}.print-footer p{margin:4px 0}}";
|
|
17382
17980
|
styleInject(css_248z);
|
|
17383
17981
|
|
|
17384
17982
|
// Export init function for vanilla JS usage with Preact
|