'use client'; import { useState, useEffect, useCallback } from 'react'; import { motion } from 'framer-motion'; import { BarChart3, TrendingUp, Eye, Heart, Zap, Globe, Activity, Target, Award, RefreshCw, MousePointer, RotateCcw, Trash2, AlertTriangle } from 'lucide-react'; import { useToast } from '@/components/Toast'; interface AnalyticsData { overview: { totalProjects: number; publishedProjects: number; featuredProjects: number; totalViews: number; avgLighthouse: number; }; projects: Array<{ id: number; title: string; category: string; difficulty: string; views: number; lighthouse: number; published: boolean; featured: boolean; createdAt: string; updatedAt: string; }>; categories: Record; difficulties: Record; performance: { avgLighthouse: number; totalViews: number; }; metrics: { bounceRate: number; avgSessionDuration: number; pagesPerSession: number; newUsers: number; }; } interface AnalyticsDashboardProps { isAuthenticated: boolean; } export function AnalyticsDashboard({ isAuthenticated }: AnalyticsDashboardProps) { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [timeRange, setTimeRange] = useState<'7d' | '30d' | '90d' | '1y'>('30d'); const [showResetModal, setShowResetModal] = useState(false); const [resetType, setResetType] = useState<'analytics' | 'pageviews' | 'interactions' | 'performance' | 'all'>('analytics'); const [resetting, setResetting] = useState(false); const { showSuccess, showError } = useToast(); const fetchAnalyticsData = useCallback(async () => { if (!isAuthenticated) return; try { setLoading(true); setError(null); // Add cache-busting parameter to ensure fresh data after reset const cacheBust = `?nocache=true&t=${Date.now()}`; const [analyticsRes, performanceRes] = await Promise.all([ fetch(`/api/analytics/dashboard${cacheBust}`, { headers: { 'x-admin-request': 'true' } }), fetch(`/api/analytics/performance${cacheBust}`, { headers: { 'x-admin-request': 'true' } }) ]); if (!analyticsRes.ok || !performanceRes.ok) { throw new Error('Failed to fetch analytics data'); } const [analytics, performance] = await Promise.all([ analyticsRes.json(), performanceRes.json() ]); setData({ overview: analytics.overview || { totalProjects: 0, publishedProjects: 0, featuredProjects: 0, totalViews: 0, avgLighthouse: 90 }, projects: analytics.projects || [], categories: analytics.categories || {}, difficulties: analytics.difficulties || {}, performance: { avgLighthouse: performance.avgLighthouse || analytics.overview?.avgLighthouse || 0, totalViews: performance.totalViews || analytics.overview?.totalViews || 0, }, metrics: performance.metrics || analytics.metrics || { bounceRate: 0, avgSessionDuration: 0, pagesPerSession: 0, newUsers: 0 } }); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load analytics'); } finally { setLoading(false); } }, [isAuthenticated]); const resetAnalytics = async () => { if (!isAuthenticated || resetting) return; setResetting(true); setError(null); try { const response = await fetch('/api/analytics/reset', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-admin-request': 'true' }, body: JSON.stringify({ type: resetType }) }); const result = await response.json(); if (response.ok) { showSuccess( 'Analytics Reset', `Successfully reset ${resetType === 'all' ? 'all analytics data' : resetType} data.` ); setShowResetModal(false); // Clear cache and refresh data await fetchAnalyticsData(); } else { const errorMsg = result.error || 'Failed to reset analytics'; setError(errorMsg); showError('Reset Failed', errorMsg); } } catch (err) { const errorMsg = 'Failed to reset analytics. Please try again.'; setError(errorMsg); showError('Reset Failed', errorMsg); console.error('Reset error:', err); } finally { setResetting(false); } }; useEffect(() => { if (isAuthenticated) { fetchAnalyticsData(); } }, [isAuthenticated, fetchAnalyticsData]); const StatCard = ({ title, value, icon: Icon, color, description, tooltip }: { title: string; value: number | string; icon: React.ComponentType<{ className?: string; size?: number }>; color: string; description?: string; tooltip?: string; }) => (

{title}

{description &&

{description}

}

{value}

{tooltip && (
{tooltip}
)}
); const getDifficultyColor = (difficulty: string) => { switch (difficulty) { case 'Beginner': return 'bg-stone-50 text-stone-700 border-stone-200'; case 'Intermediate': return 'bg-stone-100 text-stone-700 border-stone-300'; case 'Advanced': return 'bg-stone-200 text-stone-800 border-stone-400'; case 'Expert': return 'bg-stone-300 text-stone-900 border-stone-500'; default: return 'bg-stone-50 text-stone-600 border-stone-200'; } }; const getCategoryColor = (index: number) => { const colors = [ 'bg-stone-100 text-stone-700', 'bg-stone-200 text-stone-800', 'bg-stone-300 text-stone-900', 'bg-stone-100 text-stone-700', 'bg-stone-200 text-stone-800' ]; return colors[index % colors.length]; }; // Authentication disabled - show analytics directly return (
{/* Header */}

Analytics Dashboard

Portfolio performance and analytics metrics

{/* Time Range Selector */}
{(['7d', '30d', '90d', '1y'] as const).map((range) => ( ))}
{loading && (
Loading analytics data...
)} {error && (
Error: {error}
)} {data && !loading && ( <> {/* Overview Stats */}

Overview

0 ? data.overview.avgLighthouse : 'N/A'} icon={Zap} color="bg-stone-100 text-stone-600" description={data.overview.avgLighthouse > 0 ? "Avg Lighthouse score" : "No performance data yet"} tooltip={data.overview.avgLighthouse > 0 ? "✅ REAL DATA: Average Lighthouse performance score (0-100) calculated from real Web Vitals metrics (LCP, FCP, CLS, FID, TTFB) collected from actual page visits. Only shown when real performance data exists." : "No performance data collected yet. Scores will appear after visitors load your pages and Web Vitals are tracked."} />
{/* Project Performance */}
{/* Top Projects */}

Top Performing Projects

{data.projects .sort((a, b) => b.views - a.views) .slice(0, 5) .map((project, index) => (
#{index + 1}

{project.title}

{project.category}

{project.views.toLocaleString()}

views

✅ REAL DATA: Page views tracked from PageView table for this project. Each visit is automatically recorded.
))}
{/* Categories Distribution */}

Categories

{Object.entries(data.categories).map(([category, count], index) => (
{category}
{count}
))}
{/* Difficulty & Activity */}
{/* Difficulty Distribution */}

Difficulty Levels

{Object.entries(data.difficulties).map(([difficulty, count]) => (

{count}

{difficulty}

))}
{/* Recent Activity */}

Recent Activity

{data.projects .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) .slice(0, 4) .map((project, index) => (

{project.title}

Updated {new Date(project.updatedAt).toLocaleDateString()}

{project.featured && ( Featured )} {project.published ? 'Live' : 'Draft'}
))}
)} {/* Reset Modal */} {showResetModal && (

Reset Analytics Data

This action cannot be undone

Warning:

This will permanently delete the selected analytics data. This action cannot be reversed.

)}
); } export default AnalyticsDashboard;