Posthog behoben
This commit is contained in:
parent
8c5e2fa58e
commit
18f92c4285
|
|
@ -132,6 +132,48 @@ export default function DashboardPage() {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Track Google OAuth login/signup
|
||||||
|
useEffect(() => {
|
||||||
|
const authMethod = searchParams.get('authMethod');
|
||||||
|
const isNewUser = searchParams.get('isNewUser') === 'true';
|
||||||
|
|
||||||
|
if (authMethod === 'google') {
|
||||||
|
const trackGoogleAuth = async () => {
|
||||||
|
try {
|
||||||
|
// Fetch user data from API (cookie-based auth)
|
||||||
|
const response = await fetch('/api/user');
|
||||||
|
if (!response.ok) return;
|
||||||
|
|
||||||
|
const user = await response.json();
|
||||||
|
|
||||||
|
// Store in localStorage for consistency
|
||||||
|
localStorage.setItem('user', JSON.stringify(user));
|
||||||
|
|
||||||
|
const { identifyUser, trackEvent } = await import('@/components/PostHogProvider');
|
||||||
|
identifyUser(user.id, {
|
||||||
|
email: user.email,
|
||||||
|
name: user.name,
|
||||||
|
plan: user.plan || 'FREE',
|
||||||
|
provider: 'google',
|
||||||
|
});
|
||||||
|
|
||||||
|
trackEvent(isNewUser ? 'user_signup' : 'user_login', {
|
||||||
|
method: 'google',
|
||||||
|
email: user.email,
|
||||||
|
isNewUser,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up URL params
|
||||||
|
router.replace('/dashboard');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PostHog tracking error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trackGoogleAuth();
|
||||||
|
}
|
||||||
|
}, [searchParams, router]);
|
||||||
|
|
||||||
// Check for successful payment and verify session
|
// Check for successful payment and verify session
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const success = searchParams.get('success');
|
const success = searchParams.get('success');
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,16 @@ export default function AppLayout({
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
|
||||||
const handleSignOut = () => {
|
const handleSignOut = async () => {
|
||||||
|
// Track logout event before clearing data
|
||||||
|
try {
|
||||||
|
const { trackEvent, resetUser } = await import('@/components/PostHogProvider');
|
||||||
|
trackEvent('user_logout');
|
||||||
|
resetUser(); // Reset PostHog user session
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PostHog tracking error:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear all cookies
|
// Clear all cookies
|
||||||
document.cookie.split(";").forEach(c => {
|
document.cookie.split(";").forEach(c => {
|
||||||
document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
|
document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,22 @@ export default function LoginPage() {
|
||||||
// Store user in localStorage for client-side
|
// Store user in localStorage for client-side
|
||||||
localStorage.setItem('user', JSON.stringify(data.user));
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||||||
|
|
||||||
|
// Track successful login with PostHog
|
||||||
|
try {
|
||||||
|
const { identifyUser, trackEvent } = await import('@/components/PostHogProvider');
|
||||||
|
identifyUser(data.user.id, {
|
||||||
|
email: data.user.email,
|
||||||
|
name: data.user.name,
|
||||||
|
plan: data.user.plan || 'FREE',
|
||||||
|
});
|
||||||
|
trackEvent('user_login', {
|
||||||
|
method: 'email',
|
||||||
|
email: data.user.email,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PostHog tracking error:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for redirect parameter
|
// Check for redirect parameter
|
||||||
const redirectUrl = searchParams.get('redirect') || '/dashboard';
|
const redirectUrl = searchParams.get('redirect') || '/dashboard';
|
||||||
router.push(redirectUrl);
|
router.push(redirectUrl);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,23 @@ export default function SignupPage() {
|
||||||
// Store user in localStorage for client-side
|
// Store user in localStorage for client-side
|
||||||
localStorage.setItem('user', JSON.stringify(data.user));
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||||||
|
|
||||||
|
// Track successful signup with PostHog
|
||||||
|
try {
|
||||||
|
const { identifyUser, trackEvent } = await import('@/components/PostHogProvider');
|
||||||
|
identifyUser(data.user.id, {
|
||||||
|
email: data.user.email,
|
||||||
|
name: data.user.name,
|
||||||
|
plan: data.user.plan || 'FREE',
|
||||||
|
signupMethod: 'email',
|
||||||
|
});
|
||||||
|
trackEvent('user_signup', {
|
||||||
|
method: 'email',
|
||||||
|
email: data.user.email,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PostHog tracking error:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Redirect to dashboard
|
// Redirect to dashboard
|
||||||
router.push('/dashboard');
|
router.push('/dashboard');
|
||||||
router.refresh();
|
router.refresh();
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,8 @@ export async function GET(request: NextRequest) {
|
||||||
where: { email: userInfo.email },
|
where: { email: userInfo.email },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isNewUser = !user;
|
||||||
|
|
||||||
// Create user if they don't exist
|
// Create user if they don't exist
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = await db.user.create({
|
user = await db.user.create({
|
||||||
|
|
@ -148,8 +150,12 @@ export async function GET(request: NextRequest) {
|
||||||
// Set authentication cookie
|
// Set authentication cookie
|
||||||
cookies().set('userId', user.id, getAuthCookieOptions());
|
cookies().set('userId', user.id, getAuthCookieOptions());
|
||||||
|
|
||||||
// Redirect to dashboard
|
// Redirect to dashboard with tracking params
|
||||||
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_APP_URL}/dashboard`);
|
const redirectUrl = new URL(`${process.env.NEXT_PUBLIC_APP_URL}/dashboard`);
|
||||||
|
redirectUrl.searchParams.set('authMethod', 'google');
|
||||||
|
redirectUrl.searchParams.set('isNewUser', isNewUser.toString());
|
||||||
|
|
||||||
|
return NextResponse.redirect(redirectUrl.toString());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Google OAuth error:', error);
|
console.error('Google OAuth error:', error);
|
||||||
return NextResponse.redirect(
|
return NextResponse.redirect(
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ export async function POST(request: NextRequest) {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
plan: 'FREE',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export async function POST(request: NextRequest) {
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
user: { id: user.id, email: user.email, name: user.name }
|
user: { id: user.id, email: user.email, name: user.name, plan: user.plan || 'FREE' }
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
console.error('Login error:', error);
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,74 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { usePathname, useSearchParams } from 'next/navigation';
|
import { usePathname, useSearchParams } from 'next/navigation';
|
||||||
import posthog from 'posthog-js';
|
import posthog from 'posthog-js';
|
||||||
|
|
||||||
export function PostHogProvider({ children }: { children: React.ReactNode }) {
|
export function PostHogProvider({ children }: { children: React.ReactNode }) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
|
const initializationAttempted = useRef(false);
|
||||||
|
|
||||||
|
// Initialize PostHog once
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check if user has consented to analytics cookies
|
// Prevent double initialization in React Strict Mode
|
||||||
|
if (initializationAttempted.current) return;
|
||||||
|
initializationAttempted.current = true;
|
||||||
|
|
||||||
const cookieConsent = localStorage.getItem('cookieConsent');
|
const cookieConsent = localStorage.getItem('cookieConsent');
|
||||||
|
|
||||||
// Only initialize PostHog if user has accepted cookies
|
|
||||||
if (cookieConsent === 'accepted') {
|
if (cookieConsent === 'accepted') {
|
||||||
posthog.init('phc_97JBJVVQlqqiZuTVRHuBnnG9HasOv3GSsdeVjossizJ', {
|
const apiKey = process.env.NEXT_PUBLIC_POSTHOG_KEY;
|
||||||
api_host: 'https://us.i.posthog.com',
|
const apiHost = process.env.NEXT_PUBLIC_POSTHOG_HOST;
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
console.warn('PostHog API key not configured');
|
||||||
|
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',
|
person_profiles: 'identified_only',
|
||||||
capture_pageview: false, // We'll capture manually
|
capture_pageview: false, // Manual pageview tracking
|
||||||
capture_pageleave: true,
|
capture_pageleave: true,
|
||||||
autocapture: true,
|
autocapture: true,
|
||||||
// Privacy-friendly settings
|
|
||||||
respect_dnt: true,
|
respect_dnt: true,
|
||||||
opt_out_capturing_by_default: false,
|
opt_out_capturing_by_default: false,
|
||||||
loaded: (posthog) => {
|
});
|
||||||
|
|
||||||
|
// Enable debug mode in development
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
posthog.debug();
|
posthog.debug();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
// Set initialized immediately after init
|
||||||
|
setIsInitialized(true);
|
||||||
|
} else {
|
||||||
|
setIsInitialized(true); // Already loaded
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup on unmount
|
// NO cleanup function - PostHog should persist across page navigation
|
||||||
return () => {
|
|
||||||
if (cookieConsent === 'accepted') {
|
|
||||||
posthog.opt_out_capturing();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Track page views
|
// Track page views ONLY after PostHog is initialized
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const cookieConsent = localStorage.getItem('cookieConsent');
|
const cookieConsent = localStorage.getItem('cookieConsent');
|
||||||
|
|
||||||
if (cookieConsent === 'accepted' && pathname) {
|
if (cookieConsent === 'accepted' && pathname && isInitialized) {
|
||||||
let url = window.origin + pathname;
|
let url = window.origin + pathname;
|
||||||
if (searchParams && searchParams.toString()) {
|
if (searchParams && searchParams.toString()) {
|
||||||
url = url + `?${searchParams.toString()}`;
|
url = url + `?${searchParams.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture('$pageview', {
|
posthog.capture('$pageview', {
|
||||||
$current_url: url,
|
$current_url: url,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [pathname, searchParams]);
|
}, [pathname, searchParams, isInitialized]); // Added isInitialized dependency
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +78,7 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
|
||||||
*/
|
*/
|
||||||
export function identifyUser(userId: string, traits?: Record<string, any>) {
|
export function identifyUser(userId: string, traits?: Record<string, any>) {
|
||||||
const cookieConsent = localStorage.getItem('cookieConsent');
|
const cookieConsent = localStorage.getItem('cookieConsent');
|
||||||
if (cookieConsent === 'accepted') {
|
if (cookieConsent === 'accepted' && (posthog as any)._loaded) {
|
||||||
posthog.identify(userId, traits);
|
posthog.identify(userId, traits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +88,7 @@ export function identifyUser(userId: string, traits?: Record<string, any>) {
|
||||||
*/
|
*/
|
||||||
export function trackEvent(eventName: string, properties?: Record<string, any>) {
|
export function trackEvent(eventName: string, properties?: Record<string, any>) {
|
||||||
const cookieConsent = localStorage.getItem('cookieConsent');
|
const cookieConsent = localStorage.getItem('cookieConsent');
|
||||||
if (cookieConsent === 'accepted') {
|
if (cookieConsent === 'accepted' && (posthog as any)._loaded) {
|
||||||
posthog.capture(eventName, properties);
|
posthog.capture(eventName, properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +98,7 @@ export function trackEvent(eventName: string, properties?: Record<string, any>)
|
||||||
*/
|
*/
|
||||||
export function resetUser() {
|
export function resetUser() {
|
||||||
const cookieConsent = localStorage.getItem('cookieConsent');
|
const cookieConsent = localStorage.getItem('cookieConsent');
|
||||||
if (cookieConsent === 'accepted') {
|
if (cookieConsent === 'accepted' && (posthog as any)._loaded) {
|
||||||
posthog.reset();
|
posthog.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue