diff --git a/src/components/configurator/WizardContainer.tsx b/src/components/configurator/WizardContainer.tsx index d4c574c..50ae1b0 100644 --- a/src/components/configurator/WizardContainer.tsx +++ b/src/components/configurator/WizardContainer.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { useLocale, useTranslations } from 'next-intl'; import { AnimatePresence, motion } from 'framer-motion'; +import { trackEvent } from '@/lib/analytics'; import StepServices from './StepServices'; import StepDetails from './StepDetails'; import StepContact from './StepContact'; @@ -90,7 +91,11 @@ export default function WizardContainer() { const goNext = () => { setDirection(1); - setCurrentStep((prev) => Math.min(prev + 1, 4) as 1 | 2 | 3 | 4); + setCurrentStep((prev) => { + const next = Math.min(prev + 1, 4) as 1 | 2 | 3 | 4; + trackEvent('configurator_step_completed', { step: prev }); + return next; + }); }; const goBack = () => { @@ -131,6 +136,10 @@ export default function WizardContainer() { setDirection(1); setIsGenerating(false); setCurrentStep(4); + trackEvent('configurator_brief_generated', { + services: formData.services.join(','), + ai_enabled: formData.aiEnabled, + }); } catch { setSubmitError(t('errors.network')); setIsGenerating(false); diff --git a/src/components/sections/Discovery.tsx b/src/components/sections/Discovery.tsx index 0f95114..f7edec8 100644 --- a/src/components/sections/Discovery.tsx +++ b/src/components/sections/Discovery.tsx @@ -5,6 +5,7 @@ import { useLocale, useTranslations } from 'next-intl'; import { motion, AnimatePresence } from 'framer-motion'; import { MessageCircle } from 'lucide-react'; import { revealVariants, staggerContainer, viewportOnce } from '@/lib/animations'; +import { trackEvent } from '@/lib/analytics'; import VoiceAgentProvider from '@/components/configurator/VoiceAgentProvider'; import VoiceAgent from '@/components/configurator/VoiceAgent'; import StepComplete from '@/components/configurator/StepComplete'; @@ -36,6 +37,7 @@ export default function Discovery() { const handleOpen = () => { setIsOpen(true); + trackEvent('voice_agent_started'); // Scroll to panel after it renders requestAnimationFrame(() => { panelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }); @@ -44,6 +46,7 @@ export default function Discovery() { const handleComplete = (brief: string, formData: WizardFormData) => { setCompleted({ brief, formData }); + trackEvent('voice_agent_brief_generated'); }; const handleReset = () => { diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts new file mode 100644 index 0000000..d4d146c --- /dev/null +++ b/src/lib/analytics.ts @@ -0,0 +1,12 @@ +/** + * Send a custom event to Google Analytics 4. + * Safe to call anywhere — silently no-ops if gtag isn't loaded. + */ +export function trackEvent( + eventName: string, + params?: Record, +) { + if (typeof window !== 'undefined' && typeof window.gtag === 'function') { + window.gtag('event', eventName, params) + } +} diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 0000000..f53cb7e --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,3 @@ +interface Window { + gtag?: (...args: unknown[]) => void +}