"use client"; import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { DashboardLayout } from "@/components/layouts/DashboardLayout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/layout/Card"; import { Badge } from "@/components/ui/layout/Badge"; import { Zap, TrendingUp, TrendingDown, Clock, Target, AlertTriangle, CheckCircle, BarChart3, Loader2, } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; import { supabase } from "@/lib/supabase"; import { logError, getUserFriendlyErrorMessage, extractSupabaseErrorInfo } from "@/utils/errorUtils"; interface PerformanceMetric { id: string; website_name: string; website_url: string; lighthouse_score: number; performance_score: number; accessibility_score: number; best_practices_score: number; seo_score: number; first_contentful_paint: number; largest_contentful_paint: number; cumulative_layout_shift: number; total_blocking_time: number; created_at: string; } interface PerformanceSummary { totalWebsites: number; averageScore: number; goodPerformance: number; needsImprovement: number; poor: number; } export default function PerformancePage() { const { userDetails } = useAuth(); const [metrics, setMetrics] = useState([]); const [summary, setSummary] = useState({ totalWebsites: 0, averageScore: 0, goodPerformance: 0, needsImprovement: 0, poor: 0, }); const [loading, setLoading] = useState(true); const [timeRange, setTimeRange] = useState<"7d" | "30d" | "90d">("30d"); useEffect(() => { if (userDetails?.organization_id) { loadPerformanceData(); } }, [userDetails, timeRange]); const loadPerformanceData = async () => { if (!userDetails?.organization_id) return; try { setLoading(true); // Calculate date range const days = timeRange === "7d" ? 7 : timeRange === "30d" ? 30 : 90; const startDate = new Date(); startDate.setDate(startDate.getDate() - days); // Fetch latest performance data for each website const { data: scanData, error } = await supabase .from("scans") .select(` id, lighthouse_score, created_at, scan_results!inner ( category, score, metrics ), pages!inner ( websites!inner ( id, name, base_url, organization_id ) ) `) .eq("pages.websites.organization_id", userDetails.organization_id) .eq("status", "completed") .gte("created_at", startDate.toISOString()) .order("created_at", { ascending: false }); if (error) { const errorInfo = extractSupabaseErrorInfo(error); logError("Error loading performance data", error, { organizationId: userDetails.organization_id, timeRange, startDate: startDate.toISOString(), supabaseError: errorInfo }); // If tables don't exist, set empty metrics if (errorInfo.message?.includes("does not exist") || errorInfo.details?.includes("does not exist")) { setMetrics([]); setSummary({ totalWebsites: 0, averageScore: 0, goodPerformance: 0, needsImprovement: 0, poor: 0, }); return; } throw error; } // Process the data to get latest metrics per website const websiteMetrics = new Map(); scanData?.forEach((scan: any) => { const website = scan.pages.websites; if (!websiteMetrics.has(website.id)) { const results = scan.scan_results || []; websiteMetrics.set(website.id, { id: scan.id, website_name: website.name, website_url: website.base_url, lighthouse_score: scan.lighthouse_score || 0, performance_score: results.find((r: any) => r.category === "performance")?.score || 0, accessibility_score: results.find((r: any) => r.category === "accessibility")?.score || 0, best_practices_score: results.find((r: any) => r.category === "best-practices")?.score || 0, seo_score: results.find((r: any) => r.category === "seo")?.score || 0, first_contentful_paint: results.find((r: any) => r.category === "performance")?.metrics?.first_contentful_paint || 0, largest_contentful_paint: results.find((r: any) => r.category === "performance")?.metrics?.largest_contentful_paint || 0, cumulative_layout_shift: results.find((r: any) => r.category === "performance")?.metrics?.cumulative_layout_shift || 0, total_blocking_time: results.find((r: any) => r.category === "performance")?.metrics?.total_blocking_time || 0, created_at: scan.created_at, }); } }); const metricsArray = Array.from(websiteMetrics.values()); setMetrics(metricsArray); // Calculate summary if (metricsArray.length > 0) { const avgScore = Math.round( metricsArray.reduce((sum, m) => sum + m.lighthouse_score, 0) / metricsArray.length ); const good = metricsArray.filter(m => m.lighthouse_score >= 90).length; const needsImprovement = metricsArray.filter(m => m.lighthouse_score >= 50 && m.lighthouse_score < 90).length; const poor = metricsArray.filter(m => m.lighthouse_score < 50).length; setSummary({ totalWebsites: metricsArray.length, averageScore: avgScore, goodPerformance: good, needsImprovement, poor, }); } } catch (error) { const errorInfo = extractSupabaseErrorInfo(error); logError("Error loading performance data", error, { organizationId: userDetails.organization_id, timeRange, function: "loadPerformanceData", supabaseError: errorInfo }); } finally { setLoading(false); } }; const getScoreColor = (score: number) => { if (score >= 90) return "text-green-600 bg-green-100"; if (score >= 50) return "text-yellow-600 bg-yellow-100"; return "text-red-600 bg-red-100"; }; const getScoreIcon = (score: number) => { if (score >= 90) return ; if (score >= 50) return ; return ; }; if (loading) { return (
); } return (
{/* Header */}

Performance Overview

Monitor and analyze your websites' performance metrics

{/* Summary Cards */}

Total Websites

{summary.totalWebsites}

Average Score

{summary.averageScore}

Good Performance

{summary.goodPerformance}

Needs Improvement

{summary.needsImprovement}

{/* Performance Metrics */}

Website Performance

{metrics.length > 0 ? (
{metrics.map((metric, index) => (

{metric.website_name}

{metric.website_url}

Last scan: {new Date(metric.created_at).toLocaleDateString()}

{getScoreIcon(metric.lighthouse_score)} {metric.lighthouse_score}/100
{metric.performance_score}
Performance
{metric.accessibility_score}
Accessibility
{metric.best_practices_score}
Best Practices
{metric.seo_score}
SEO
{(metric.first_contentful_paint > 0 || metric.largest_contentful_paint > 0) && (
{metric.first_contentful_paint > 0 && (
{(metric.first_contentful_paint / 1000).toFixed(1)}s
FCP
)} {metric.largest_contentful_paint > 0 && (
{(metric.largest_contentful_paint / 1000).toFixed(1)}s
LCP
)} {metric.cumulative_layout_shift > 0 && (
{metric.cumulative_layout_shift.toFixed(3)}
CLS
)} {metric.total_blocking_time > 0 && (
{metric.total_blocking_time}ms
TBT
)}
)}
))}
) : (

No performance data available

Run scans on your websites to see performance metrics here

)}
); }