v4.0.0.3
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { reveal } from '$lib/actions/reveal';
|
||||
import type { BookingContent } from '$lib/types';
|
||||
import { promoteJourney, trackEvent } from '$lib/analytics';
|
||||
import { trackAb, type AbContext } from '$lib/ab';
|
||||
|
||||
type SuccessModalComponentType = typeof import('$lib/components/SuccessModal.svelte').default;
|
||||
@@ -59,6 +60,7 @@
|
||||
let sendClickedAt = 0;
|
||||
let stepChanges = 0;
|
||||
let journey: string[] = [];
|
||||
let trackedFormStart = false;
|
||||
|
||||
let errors: Record<string, string> = {};
|
||||
let submitting = false;
|
||||
@@ -164,6 +166,14 @@
|
||||
|
||||
function noteInteraction() {
|
||||
if (!firstInteractionAt) firstInteractionAt = Date.now();
|
||||
if (!trackedFormStart) {
|
||||
trackedFormStart = true;
|
||||
trackEvent('lead_form_start', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
step: step,
|
||||
page_path: typeof window !== 'undefined' ? window.location.pathname : pagePath || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clearError(field: string) {
|
||||
@@ -175,6 +185,12 @@
|
||||
selectedServices = selectedServices.includes(service)
|
||||
? selectedServices.filter((s) => s !== service)
|
||||
: [...selectedServices, service];
|
||||
trackEvent('service_interest_select', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
selected_service: service,
|
||||
selection_state: selectedServices.includes(service) ? 'removed' : 'added',
|
||||
step
|
||||
});
|
||||
clearError('services');
|
||||
}
|
||||
|
||||
@@ -226,6 +242,11 @@
|
||||
function goNext() {
|
||||
noteInteraction();
|
||||
if (!validateStep(step)) return;
|
||||
trackEvent('lead_form_step_complete', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
step,
|
||||
next_step: step + 1
|
||||
});
|
||||
step += 1;
|
||||
stepChanges += 1;
|
||||
}
|
||||
@@ -233,6 +254,11 @@
|
||||
function goBack() {
|
||||
noteInteraction();
|
||||
if (step > 1) {
|
||||
trackEvent('lead_form_step_back', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
step,
|
||||
previous_step: step - 1
|
||||
});
|
||||
step -= 1;
|
||||
stepChanges += 1;
|
||||
errors = {};
|
||||
@@ -249,6 +275,12 @@
|
||||
sendClickedAt = Date.now();
|
||||
submitErrorDetail = '';
|
||||
showErrorModal = false;
|
||||
trackEvent('lead_form_submit_attempt', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
selected_services: selectedServices.join(' | '),
|
||||
step,
|
||||
step_changes: stepChanges
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/submit', {
|
||||
@@ -287,10 +319,23 @@
|
||||
}
|
||||
|
||||
submitted = true;
|
||||
trackEvent('lead_form_submit_success', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
selected_services: selectedServices.join(' | '),
|
||||
step_changes: stepChanges
|
||||
});
|
||||
// Link the visitor's session_events journey to the submitted email so
|
||||
// the owner can review it from the CP dashboard. Without this call,
|
||||
// session_events expire after 24h. See docs/server-side-analytics.md.
|
||||
promoteJourney(email);
|
||||
if (ab) trackAb({ ...ab, event_type: 'conversion', meta: { surface: 'booking_submit' } });
|
||||
} catch (err: unknown) {
|
||||
submitErrorDetail = err instanceof Error ? err.message : String(err);
|
||||
showErrorModal = true;
|
||||
trackEvent('lead_form_submit_error', {
|
||||
form_name: isCompactContactPage ? 'contact_compact' : 'booking_wizard',
|
||||
error_detail: submitErrorDetail.slice(0, 120)
|
||||
});
|
||||
} finally {
|
||||
submitting = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user