@bigz-app/booking-widget 1.3.2 → 1.3.3
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 +113 -8
- package/dist/booking-widget.js.map +1 -1
- package/dist/components/UniversalBookingWidget.d.ts.map +1 -1
- package/dist/index.cjs +113 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +113 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/utils/analytics.d.ts +17 -0
- package/dist/utils/analytics.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UniversalBookingWidget.d.ts","sourceRoot":"","sources":["../../src/components/UniversalBookingWidget.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UniversalBookingWidget.d.ts","sourceRoot":"","sources":["../../src/components/UniversalBookingWidget.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -15410,6 +15410,88 @@ function UpsellsStep({ upsells, selectedUpsells, participantCount, isLoading, is
|
|
|
15410
15410
|
return (jsxRuntime.jsx(Sidebar, { isOpen: isOpen, onClose: onClose, title: t("upsells.title"), footer: footerContent, children: jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", padding: "16px 16px" }, children: [isLoading && (jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px", padding: "40px 20px", ...textStyles.muted }, children: [spinner(), jsxRuntime.jsx("span", { children: t("upsells.loading") })] })), !isLoading && upsells.length === 0 && (jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "40px 20px", ...textStyles.muted }, children: jsxRuntime.jsx("p", { children: t("upsells.noExtras") }) })), !isLoading && upsells.length > 0 && (jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px", flex: 1, overflowY: "auto", paddingBottom: "16px" }, children: upsells.map((upsell) => (jsxRuntime.jsx(UpsellCard, { upsell: upsell, isSelected: isSelected(upsell.id), participantCount: participantCount, onSelect: () => selectUpsell(upsell.id) }, upsell.id))) })), selectedCount > 0 && (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "16px", paddingBottom: "16px", paddingTop: "16px", borderTop: "1px solid var(--bw-border-color)", fontSize: "14px" }, children: [jsxRuntime.jsx("span", { style: textStyles.muted, children: selectedCount === 1 ? t("upsells.selected", { count: selectedCount }) : t("upsells.selectedPlural", { count: selectedCount }) }), jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: "var(--bw-highlight-color)", fontFamily: "var(--bw-font-family)" }, children: ["+", formatCurrency(selectedTotal)] })] }))] }) }));
|
|
15411
15411
|
}
|
|
15412
15412
|
|
|
15413
|
+
/**
|
|
15414
|
+
* Widget analytics — server-side PostHog tracking via batched sendBeacon.
|
|
15415
|
+
*
|
|
15416
|
+
* Events are buffered locally and flushed every few seconds (or on page
|
|
15417
|
+
* unload) as a single POST to `/api/booking/track`. This avoids extra
|
|
15418
|
+
* network requests on every click while still capturing a complete funnel.
|
|
15419
|
+
*/
|
|
15420
|
+
let buffer = [];
|
|
15421
|
+
let flushTimer = null;
|
|
15422
|
+
let currentApiBaseUrl = "";
|
|
15423
|
+
let currentOrganizationId = "";
|
|
15424
|
+
const FLUSH_INTERVAL_MS = 3000;
|
|
15425
|
+
function flush() {
|
|
15426
|
+
if (buffer.length === 0)
|
|
15427
|
+
return;
|
|
15428
|
+
const payload = JSON.stringify({
|
|
15429
|
+
organizationId: currentOrganizationId,
|
|
15430
|
+
events: buffer,
|
|
15431
|
+
});
|
|
15432
|
+
buffer = [];
|
|
15433
|
+
const url = getApiUrl(currentApiBaseUrl, "/booking/track");
|
|
15434
|
+
// Use fetch with keepalive as primary — works cross-origin with CORS.
|
|
15435
|
+
// sendBeacon silently fails cross-origin with application/json because
|
|
15436
|
+
// it can't do CORS preflight, so we only use it as a text/plain fallback
|
|
15437
|
+
// on page unload when fetch may be aborted.
|
|
15438
|
+
try {
|
|
15439
|
+
void fetch(url, {
|
|
15440
|
+
method: "POST",
|
|
15441
|
+
headers: { "Content-Type": "application/json" },
|
|
15442
|
+
body: payload,
|
|
15443
|
+
keepalive: true,
|
|
15444
|
+
});
|
|
15445
|
+
}
|
|
15446
|
+
catch {
|
|
15447
|
+
// fetch failed (e.g. during page unload) — try sendBeacon with text/plain
|
|
15448
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
15449
|
+
const blob = new Blob([payload], { type: "text/plain" });
|
|
15450
|
+
navigator.sendBeacon(url, blob);
|
|
15451
|
+
}
|
|
15452
|
+
}
|
|
15453
|
+
}
|
|
15454
|
+
function scheduleFlush() {
|
|
15455
|
+
if (flushTimer)
|
|
15456
|
+
return;
|
|
15457
|
+
flushTimer = setTimeout(() => {
|
|
15458
|
+
flushTimer = null;
|
|
15459
|
+
flush();
|
|
15460
|
+
}, FLUSH_INTERVAL_MS);
|
|
15461
|
+
}
|
|
15462
|
+
/**
|
|
15463
|
+
* Initialise the analytics module. Must be called once before `trackEvent`.
|
|
15464
|
+
*/
|
|
15465
|
+
function initAnalytics(apiBaseUrl, organizationId) {
|
|
15466
|
+
currentApiBaseUrl = apiBaseUrl;
|
|
15467
|
+
currentOrganizationId = organizationId;
|
|
15468
|
+
if (typeof window !== "undefined") {
|
|
15469
|
+
window.addEventListener("pagehide", flush);
|
|
15470
|
+
window.addEventListener("visibilitychange", () => {
|
|
15471
|
+
if (document.visibilityState === "hidden")
|
|
15472
|
+
flush();
|
|
15473
|
+
});
|
|
15474
|
+
}
|
|
15475
|
+
}
|
|
15476
|
+
/**
|
|
15477
|
+
* Queue a widget event. Non-blocking, fire-and-forget.
|
|
15478
|
+
*/
|
|
15479
|
+
function trackEvent(event, properties = {}) {
|
|
15480
|
+
if (typeof window === "undefined")
|
|
15481
|
+
return;
|
|
15482
|
+
if (!currentOrganizationId)
|
|
15483
|
+
return;
|
|
15484
|
+
buffer.push({
|
|
15485
|
+
event,
|
|
15486
|
+
properties,
|
|
15487
|
+
domain: window.location.hostname,
|
|
15488
|
+
url: window.location.href,
|
|
15489
|
+
referrer: document.referrer,
|
|
15490
|
+
timestamp: new Date().toISOString(),
|
|
15491
|
+
});
|
|
15492
|
+
scheduleFlush();
|
|
15493
|
+
}
|
|
15494
|
+
|
|
15413
15495
|
// Main widget component
|
|
15414
15496
|
function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onTimezone, }) {
|
|
15415
15497
|
const t = useTranslations();
|
|
@@ -15602,6 +15684,21 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15602
15684
|
setIsLoadingVoucherConfig(false);
|
|
15603
15685
|
}
|
|
15604
15686
|
};
|
|
15687
|
+
// Initialise analytics once on mount
|
|
15688
|
+
const analyticsInitRef = React.useRef(false);
|
|
15689
|
+
React.useEffect(() => {
|
|
15690
|
+
if (!analyticsInitRef.current && config.organizationId) {
|
|
15691
|
+
analyticsInitRef.current = true;
|
|
15692
|
+
initAnalytics(config.apiBaseUrl, config.organizationId);
|
|
15693
|
+
trackEvent("widget_loaded", {
|
|
15694
|
+
viewMode,
|
|
15695
|
+
eventTypeId: config.eventTypeId,
|
|
15696
|
+
categoryId: config.categoryId,
|
|
15697
|
+
eventInstanceId: config.eventInstanceId,
|
|
15698
|
+
isStandaloneVoucherMode,
|
|
15699
|
+
});
|
|
15700
|
+
}
|
|
15701
|
+
}, [config.organizationId, config.apiBaseUrl]);
|
|
15605
15702
|
// Fire widget pageview once when Google Ads config is received from API
|
|
15606
15703
|
const pageviewFiredRef = React.useRef(false);
|
|
15607
15704
|
React.useEffect(() => {
|
|
@@ -15698,6 +15795,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15698
15795
|
});
|
|
15699
15796
|
const voucherData = await voucherResponse.json();
|
|
15700
15797
|
if (voucherResponse.ok && voucherData.voucherResult) {
|
|
15798
|
+
trackEvent("voucher_purchased", { voucherType: voucherData.voucherResult.voucherType, source: "stripe_redirect" });
|
|
15701
15799
|
setVoucherPurchaseResult(voucherData.voucherResult);
|
|
15702
15800
|
setIsSuccess(true);
|
|
15703
15801
|
setSuccessPaymentId(null);
|
|
@@ -15707,6 +15805,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15707
15805
|
catch {
|
|
15708
15806
|
// Fall back to booking success flow if voucher lookup fails.
|
|
15709
15807
|
}
|
|
15808
|
+
trackEvent("booking_completed", { paymentIntentId: stripeReturn.paymentIntent, source: "stripe_redirect" });
|
|
15710
15809
|
setVoucherPurchaseResult(null);
|
|
15711
15810
|
setSuccessPaymentId(stripeReturn.paymentIntent);
|
|
15712
15811
|
setIsSuccess(true);
|
|
@@ -15744,6 +15843,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15744
15843
|
});
|
|
15745
15844
|
const voucherData = await voucherResponse.json();
|
|
15746
15845
|
if (voucherResponse.ok && voucherData.voucherResult) {
|
|
15846
|
+
trackEvent("voucher_purchased", { voucherType: voucherData.voucherResult.voucherType, source: "mollie_redirect" });
|
|
15747
15847
|
setVoucherPurchaseResult(voucherData.voucherResult);
|
|
15748
15848
|
setIsSuccess(true);
|
|
15749
15849
|
setSuccessPaymentId(null);
|
|
@@ -15782,6 +15882,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15782
15882
|
window[globalFlagKey] = true;
|
|
15783
15883
|
const timer = setTimeout(() => {
|
|
15784
15884
|
setShowPromoDialog(true);
|
|
15885
|
+
trackEvent("promo_dialog_shown", { discountCode: config.promo?.discountCode });
|
|
15785
15886
|
}, 1000);
|
|
15786
15887
|
return () => clearTimeout(timer);
|
|
15787
15888
|
}, [config.promo?.enabled, config.promo?.discountCode]);
|
|
@@ -15791,6 +15892,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15791
15892
|
localStorage.setItem(`bigz-promo-${promoId}-shown`, "true");
|
|
15792
15893
|
};
|
|
15793
15894
|
const handlePromoCtaClick = () => {
|
|
15895
|
+
trackEvent("promo_cta_clicked", { discountCode: config.promo?.discountCode });
|
|
15794
15896
|
setShowPromoDialog(false);
|
|
15795
15897
|
const promoId = config.promo?.discountCode || "default";
|
|
15796
15898
|
localStorage.setItem(`bigz-promo-${promoId}-shown`, "true");
|
|
@@ -15825,6 +15927,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
15825
15927
|
}
|
|
15826
15928
|
extractGoogleAdsConfig(data);
|
|
15827
15929
|
setEventTypes(data.eventTypes);
|
|
15930
|
+
trackEvent("event_types_loaded", { count: data.eventTypes.length });
|
|
15828
15931
|
if (isSingleEventTypeMode && data.eventTypes.length === 1) {
|
|
15829
15932
|
setSelectedEventType(data.eventTypes[0]);
|
|
15830
15933
|
await loadEventInstances(data.eventTypes[0].id);
|
|
@@ -16080,6 +16183,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16080
16183
|
}
|
|
16081
16184
|
// Event type selection handlers
|
|
16082
16185
|
const handleEventTypeSelect = async (eventType) => {
|
|
16186
|
+
trackEvent("event_type_selected", { eventTypeId: eventType.id, eventTypeName: eventType.name });
|
|
16083
16187
|
setSelectedEventType(eventType);
|
|
16084
16188
|
setCurrentStep("eventInstances");
|
|
16085
16189
|
setShouldRenderInstanceSelection(true);
|
|
@@ -16093,6 +16197,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16093
16197
|
};
|
|
16094
16198
|
// Event instance selection handlers
|
|
16095
16199
|
const handleEventInstanceSelect = async (eventInstance) => {
|
|
16200
|
+
trackEvent("event_instance_selected", { eventInstanceId: eventInstance.id, eventInstanceName: eventInstance.name });
|
|
16096
16201
|
setSelectedEventInstance(eventInstance);
|
|
16097
16202
|
bookingReturnStep.current = "eventInstances";
|
|
16098
16203
|
// Set default participant count for upsell calculations
|
|
@@ -16105,9 +16210,8 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16105
16210
|
try {
|
|
16106
16211
|
const availableUpsells = await loadUpsells(selectedEventType.id, eventInstance.id, defaultParticipantCount);
|
|
16107
16212
|
if (availableUpsells.length > 0) {
|
|
16108
|
-
|
|
16213
|
+
trackEvent("upsell_step_viewed", { count: availableUpsells.length });
|
|
16109
16214
|
setUpsells(availableUpsells);
|
|
16110
|
-
// Pre-select default-checked upsells
|
|
16111
16215
|
const defaultSelections = availableUpsells
|
|
16112
16216
|
.filter((upsell) => upsell.defaultChecked && upsell.available)
|
|
16113
16217
|
.map((upsell) => ({
|
|
@@ -16117,7 +16221,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16117
16221
|
setSelectedUpsells(defaultSelections);
|
|
16118
16222
|
setCurrentStep("upsells");
|
|
16119
16223
|
setIsLoadingUpsells(false);
|
|
16120
|
-
return;
|
|
16224
|
+
return;
|
|
16121
16225
|
}
|
|
16122
16226
|
}
|
|
16123
16227
|
catch (err) {
|
|
@@ -16127,7 +16231,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16127
16231
|
setIsLoadingUpsells(false);
|
|
16128
16232
|
}
|
|
16129
16233
|
}
|
|
16130
|
-
|
|
16234
|
+
trackEvent("booking_form_opened", { fromUpsells: false });
|
|
16131
16235
|
setCurrentStep("booking");
|
|
16132
16236
|
setShouldRenderBookingForm(true);
|
|
16133
16237
|
setIsLoadingEventDetails(true);
|
|
@@ -16150,6 +16254,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16150
16254
|
setEventDetails(null);
|
|
16151
16255
|
};
|
|
16152
16256
|
const handleBookingSuccess = (result) => {
|
|
16257
|
+
trackEvent("booking_completed", { paymentIntentId: result.paymentIntent?.id });
|
|
16153
16258
|
setIsSuccess(true);
|
|
16154
16259
|
setSuccessPaymentId(result.paymentIntent.id);
|
|
16155
16260
|
setSidebarOpen(false);
|
|
@@ -16165,7 +16270,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16165
16270
|
setSelectedUpsells(selections);
|
|
16166
16271
|
};
|
|
16167
16272
|
const handleUpsellsContinue = async () => {
|
|
16168
|
-
|
|
16273
|
+
trackEvent("booking_form_opened", { fromUpsells: true });
|
|
16169
16274
|
setCurrentStep("booking");
|
|
16170
16275
|
setShouldRenderBookingForm(true);
|
|
16171
16276
|
setIsLoadingEventDetails(true);
|
|
@@ -16185,8 +16290,8 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16185
16290
|
};
|
|
16186
16291
|
// Voucher purchase handlers
|
|
16187
16292
|
const handleVoucherCardClick = async () => {
|
|
16293
|
+
trackEvent("voucher_card_clicked");
|
|
16188
16294
|
setPreselectedVoucherEventTypeId(null);
|
|
16189
|
-
// Ensure voucher config and event types are loaded before opening the form
|
|
16190
16295
|
if (!voucherConfig || voucherEventTypes.length === 0) {
|
|
16191
16296
|
await loadVoucherConfig();
|
|
16192
16297
|
}
|
|
@@ -16205,6 +16310,7 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16205
16310
|
setPreselectedVoucherEventTypeId(null);
|
|
16206
16311
|
};
|
|
16207
16312
|
const handleVoucherSuccess = (result) => {
|
|
16313
|
+
trackEvent("voucher_purchased", { voucherType: result.voucherType });
|
|
16208
16314
|
setVoucherPurchaseResult(result);
|
|
16209
16315
|
setIsVoucherFormOpen(false);
|
|
16210
16316
|
setIsSuccess(true);
|
|
@@ -16287,8 +16393,8 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16287
16393
|
try {
|
|
16288
16394
|
const availableUpsells = await loadUpsells(eventTypeForUpsells.id, eventInstanceId, defaultParticipantCount);
|
|
16289
16395
|
if (availableUpsells.length > 0) {
|
|
16396
|
+
trackEvent("upsell_step_viewed", { count: availableUpsells.length });
|
|
16290
16397
|
setUpsells(availableUpsells);
|
|
16291
|
-
// Pre-select default-checked upsells
|
|
16292
16398
|
const defaultSelections = availableUpsells
|
|
16293
16399
|
.filter((upsell) => upsell.defaultChecked && upsell.available)
|
|
16294
16400
|
.map((upsell) => ({
|
|
@@ -16298,7 +16404,6 @@ function UniversalBookingWidgetInner({ config: baseConfig, onWidgetLanguage, onT
|
|
|
16298
16404
|
setSelectedUpsells(defaultSelections);
|
|
16299
16405
|
setCurrentStep("upsells");
|
|
16300
16406
|
setIsLoadingUpsells(false);
|
|
16301
|
-
// Load event details in background for when user continues past upsells
|
|
16302
16407
|
void loadEventDetails(eventInstanceId);
|
|
16303
16408
|
return;
|
|
16304
16409
|
}
|