neuer versuch

This commit is contained in:
Timo Knuth
2026-01-14 14:02:48 +01:00
parent 1747922b29
commit f68b7a331c
53 changed files with 3560 additions and 4397 deletions

View File

@@ -4,10 +4,30 @@ import { useEffect, useState, useRef } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import posthog from 'posthog-js';
export function PostHogProvider({ children }: { children: React.ReactNode }) {
export function PostHogPageView() {
const pathname = usePathname();
const searchParams = useSearchParams();
const [isInitialized, setIsInitialized] = useState(false);
// Track page views
useEffect(() => {
const cookieConsent = localStorage.getItem('cookieConsent');
if (cookieConsent === 'accepted' && pathname) {
let url = window.origin + pathname;
if (searchParams && searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', {
$current_url: url,
});
}
}, [pathname, searchParams]);
return null;
}
export function PostHogProvider({ children }: { children: React.ReactNode }) {
const initializationAttempted = useRef(false);
// Initialize PostHog once
@@ -18,6 +38,9 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
const cookieConsent = localStorage.getItem('cookieConsent');
// Check if we should initialize based on consent
// If not accepted yet, we don't init. CookieBanner deals with setting 'accepted' and reloading or calling init.
// Ideally we should listen to consent changes, but for now matching previous behavior.
if (cookieConsent === 'accepted') {
const apiKey = process.env.NEXT_PUBLIC_POSTHOG_KEY;
const apiHost = process.env.NEXT_PUBLIC_POSTHOG_HOST;
@@ -27,49 +50,24 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
return;
}
// Check if already initialized (using _loaded property)
if (!(posthog as any)._loaded) {
posthog.init(apiKey, {
api_host: apiHost || 'https://us.i.posthog.com',
person_profiles: 'identified_only',
capture_pageview: false, // Manual pageview tracking
capture_pageview: false, // We handle this manually
capture_pageleave: true,
autocapture: true,
respect_dnt: true,
opt_out_capturing_by_default: false,
});
// Enable debug mode in development
if (process.env.NODE_ENV === 'development') {
posthog.debug();
}
// Set initialized immediately after init
setIsInitialized(true);
} else {
setIsInitialized(true); // Already loaded
}
}
// NO cleanup function - PostHog should persist across page navigation
}, []);
// Track page views ONLY after PostHog is initialized
useEffect(() => {
const cookieConsent = localStorage.getItem('cookieConsent');
if (cookieConsent === 'accepted' && pathname && isInitialized) {
let url = window.origin + pathname;
if (searchParams && searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', {
$current_url: url,
});
}
}, [pathname, searchParams, isInitialized]); // Added isInitialized dependency
return <>{children}</>;
}

View File

@@ -3,19 +3,20 @@
import { Suspense } from 'react';
import { ToastContainer } from '@/components/ui/Toast';
import AuthProvider from '@/components/SessionProvider';
import { PostHogProvider } from '@/components/PostHogProvider';
import { PostHogProvider, PostHogPageView } from '@/components/PostHogProvider';
import CookieBanner from '@/components/CookieBanner';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<Suspense fallback={null}>
<PostHogProvider>
<AuthProvider>
{children}
</AuthProvider>
<CookieBanner />
<ToastContainer />
</PostHogProvider>
</Suspense>
<PostHogProvider>
<Suspense fallback={null}>
<PostHogPageView />
</Suspense>
<AuthProvider>
{children}
</AuthProvider>
<CookieBanner />
<ToastContainer />
</PostHogProvider>
);
}

View File

@@ -17,7 +17,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<div className="grid md:grid-cols-4 gap-8">
<div>
<Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity">
<img src="/logo.svg" alt="" className="w-10 h-10" />
<img src="/logo.svg" alt="QR Master Logo" className="w-10 h-10" />
<span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span>
</Link>
<p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}>
@@ -30,6 +30,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<ul className={`space-y-2 ${isDashboard ? 'text-gray-500' : 'text-gray-400'}`}>
<li><Link href="/#features" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.features}</Link></li>
<li><Link href="/#pricing" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.pricing}</Link></li>
<li><Link href="/qr-code-tracking" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>QR Analytics</Link></li>
<li><Link href="/faq" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.faq}</Link></li>
<li><Link href="/blog" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.blog}</Link></li>
</ul>