'use client'; import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { BarChart3, TrendingUp, Eye, Heart, Zap, Users, Clock, Globe, Activity, Target, Award, RefreshCw, Calendar, MousePointer, Monitor, RotateCcw, Trash2, AlertTriangle } from 'lucide-react'; interface AnalyticsData { overview: { totalProjects: number; publishedProjects: number; featuredProjects: number; totalViews: number; totalLikes: number; totalShares: number; avgLighthouse: number; }; projects: Array<{ id: number; title: string; category: string; difficulty: string; views: number; likes: number; shares: number; lighthouse: number; published: boolean; featured: boolean; createdAt: string; updatedAt: string; }>; categories: Record; difficulties: Record; performance: { avgLighthouse: number; totalViews: number; totalLikes: number; totalShares: 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 fetchAnalyticsData = async () => { if (!isAuthenticated) return; try { setLoading(true); setError(null); const [analyticsRes, performanceRes] = await Promise.all([ fetch('/api/analytics/dashboard', { headers: { 'x-admin-request': 'true' } }), fetch('/api/analytics/performance', { 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, totalLikes: 0, totalShares: 0, avgLighthouse: 90 }, projects: analytics.projects || [], categories: analytics.categories || {}, difficulties: analytics.difficulties || {}, performance: performance.performance || { avgLighthouse: 90, totalViews: 0, totalLikes: 0, totalShares: 0 }, metrics: performance.metrics || { bounceRate: 35, avgSessionDuration: 180, pagesPerSession: 2.5, newUsers: 0 } }); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load analytics'); } finally { setLoading(false); } }; const resetAnalytics = async () => { if (!isAuthenticated || resetting) return; setResetting(true); try { const response = await fetch('/api/analytics/reset', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-admin-request': 'true' }, body: JSON.stringify({ type: resetType }) }); if (response.ok) { await fetchAnalyticsData(); // Refresh data setShowResetModal(false); } else { const errorData = await response.json(); setError(errorData.error || 'Failed to reset analytics'); } } catch (err) { setError('Failed to reset analytics'); console.error('Reset error:', err); } finally { setResetting(false); } }; useEffect(() => { if (isAuthenticated) { fetchAnalyticsData(); } }, [isAuthenticated, timeRange]); const StatCard = ({ title, value, icon: Icon, color, trend, trendValue, description }: { title: string; value: number | string; icon: React.ComponentType<{ className?: string; size?: number }>; color: string; trend?: 'up' | 'down' | 'neutral'; trendValue?: string; description?: string; }) => (

{title}

{description &&

{description}

}

{value}

{trend && trendValue && (
{trendValue}
)}
); const getDifficultyColor = (difficulty: string) => { switch (difficulty) { case 'Beginner': return 'bg-green-500/30 text-green-400 border-green-500/40'; case 'Intermediate': return 'bg-yellow-500/30 text-yellow-400 border-yellow-500/40'; case 'Advanced': return 'bg-orange-500/30 text-orange-400 border-orange-500/40'; case 'Expert': return 'bg-red-500/30 text-red-400 border-red-500/40'; default: return 'bg-gray-500/30 text-gray-400 border-gray-500/40'; } }; const getCategoryColor = (index: number) => { const colors = [ 'bg-blue-500/30 text-blue-400', 'bg-purple-500/30 text-purple-400', 'bg-green-500/30 text-green-400', 'bg-pink-500/30 text-pink-400', 'bg-indigo-500/30 text-indigo-400' ]; return colors[index % colors.length]; }; if (!isAuthenticated) { return (

Authentication Required

Please log in to view analytics data

); } return (
{/* Header */}

Analytics Dashboard

Portfolio performance and user engagement metrics

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

Overview

{/* 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

))}
{/* Categories Distribution */}

Categories

{Object.entries(data.categories).map(([category, count], index) => (
{category}
{count}
))}
{/* Difficulty & Engagement */}
{/* 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;