hooks in config/services.php/.env.example, and updated wizard steps/controllers to store session payloads, attach packages, and surface localized success/error states. - Retooled payment handling for both Stripe and PayPal, adding richer status management in CheckoutController/ PayPalController, fallback flows in the wizard’s PaymentStep.tsx, and fresh feature tests for intent creation, webhooks, and the wizard CTA. - Introduced a consent-aware Matomo analytics stack: new consent context, cookie-banner UI, useAnalytics/ useCtaExperiment hooks, and MatomoTracker component, then instrumented marketing pages (Home, Packages, Checkout) with localized copy and experiment tracking. - Polished package presentation across marketing UIs by centralizing formatting in PresentsPackages, surfacing localized description tables/placeholders, tuning badges/layouts, and syncing guest/marketing translations. - Expanded docs & reference material (docs/prp/*, TODOs, public gallery overview) and added a Playwright smoke test for the hero CTA while reconciling outstanding checklist items.
59 lines
1.5 KiB
TypeScript
59 lines
1.5 KiB
TypeScript
import { useState, useMemo, useEffect, useCallback } from 'react';
|
|
import { useAnalytics } from '@/hooks/useAnalytics';
|
|
|
|
type CtaVariant = 'gradient' | 'neutral';
|
|
|
|
const STORAGE_KEY = 'marketing_cta_variant_v1';
|
|
|
|
function determineVariant(): CtaVariant {
|
|
if (typeof window === 'undefined') {
|
|
return 'gradient';
|
|
}
|
|
|
|
const stored = window.localStorage.getItem(STORAGE_KEY);
|
|
if (stored === 'gradient' || stored === 'neutral') {
|
|
return stored;
|
|
}
|
|
|
|
const assigned: CtaVariant = Math.random() < 0.5 ? 'gradient' : 'neutral';
|
|
try {
|
|
window.localStorage.setItem(STORAGE_KEY, assigned);
|
|
} catch (error) {
|
|
// localStorage may be unavailable; ignore and fallback to the assigned variant in memory
|
|
console.warn('Unable to persist CTA variant assignment', error);
|
|
}
|
|
return assigned;
|
|
}
|
|
|
|
export function useCtaExperiment(placement: string) {
|
|
const { trackEvent } = useAnalytics();
|
|
const [variant] = useState<CtaVariant>(() => determineVariant());
|
|
|
|
const trackingLabel = useMemo(() => `${placement}:${variant}`, [placement, variant]);
|
|
|
|
useEffect(() => {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
trackEvent({
|
|
category: 'marketing_experiment',
|
|
action: 'cta_impression',
|
|
name: trackingLabel,
|
|
});
|
|
}, [trackEvent, trackingLabel]);
|
|
|
|
const trackClick = useCallback(() => {
|
|
trackEvent({
|
|
category: 'marketing_experiment',
|
|
action: 'cta_click',
|
|
name: trackingLabel,
|
|
});
|
|
}, [trackEvent, trackingLabel]);
|
|
|
|
return {
|
|
variant,
|
|
trackClick,
|
|
};
|
|
}
|