|
2 | 2 |
|
3 | 3 | import { useEffect, useMemo, useCallback } from "react"; |
4 | 4 | import { Monitor, Smartphone, Zap, MapPin, TrendingUp, TrendingDown, AlertTriangle, CheckCircle } from "lucide-react"; |
| 5 | +import { Question } from "@phosphor-icons/react"; |
5 | 6 | import { DataTable } from "@/components/analytics/data-table"; |
6 | 7 | import { useEnhancedPerformanceData } from "@/hooks/use-dynamic-query"; |
7 | 8 | import type { FullTabProps } from "../utils/types"; |
8 | 9 | import { BrowserIcon, OSIcon } from "@/components/icon"; |
9 | 10 | import { CountryFlag } from "@/components/analytics/icons/CountryFlag"; |
10 | | - |
11 | | -interface PerformanceEntry { |
12 | | - name: string; |
13 | | - visitors: number; |
14 | | - avg_load_time: number; |
15 | | - avg_ttfb?: number; |
16 | | - avg_dom_ready_time?: number; |
17 | | - avg_render_time?: number; |
18 | | - avg_fcp?: number; |
19 | | - avg_lcp?: number; |
20 | | - avg_cls?: number; |
21 | | - _uniqueKey?: string; |
22 | | -} |
23 | | - |
24 | | -interface PerformanceSummary { |
25 | | - avgLoadTime: number; |
26 | | - fastPages: number; |
27 | | - slowPages: number; |
28 | | - totalPages: number; |
29 | | - performanceScore: number; |
| 11 | +import { calculatePerformanceSummary } from "@/lib/performance-utils"; |
| 12 | +import type { PerformanceEntry, PerformanceSummary } from "@/types/performance"; |
| 13 | +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; |
| 14 | + |
| 15 | +function getPerformanceRating(score: number): { rating: string; className: string } { |
| 16 | + if (score >= 90) return { rating: "Excellent", className: "text-green-500" }; |
| 17 | + if (score >= 70) return { rating: "Good", className: "text-green-500" }; |
| 18 | + if (score >= 50) return { rating: "Moderate", className: "text-yellow-500" }; |
| 19 | + if (score >= 30) return { rating: "Poor", className: "text-orange-500" }; |
| 20 | + return { rating: "Very Poor", className: "text-red-500" }; |
30 | 21 | } |
31 | 22 |
|
32 | 23 | function PerformanceMetricCell({ value, type = 'time' }: { value?: number; type?: 'time' | 'cls' }) { |
@@ -72,16 +63,29 @@ function PerformanceSummaryCard({ summary }: { summary: PerformanceSummary }) { |
72 | 63 | return 'text-red-600'; |
73 | 64 | }, [summary.avgLoadTime]); |
74 | 65 |
|
| 66 | + const ratingInfo = getPerformanceRating(summary.performanceScore); |
| 67 | + |
75 | 68 | return ( |
76 | 69 | <div className="grid grid-cols-2 md:grid-cols-4 gap-4"> |
77 | 70 | <div className="p-4 rounded-lg border bg-background"> |
78 | 71 | <div className="flex items-center gap-2 mb-2"> |
79 | 72 | <Zap className="h-4 w-4 text-primary" /> |
80 | 73 | <span className="text-sm font-medium text-muted-foreground">Performance Score</span> |
| 74 | + <TooltipProvider> |
| 75 | + <Tooltip> |
| 76 | + <TooltipTrigger> |
| 77 | + <Question className="h-3 w-3 text-muted-foreground" /> |
| 78 | + </TooltipTrigger> |
| 79 | + <TooltipContent> |
| 80 | + <p>A weighted score based on page load times and visitor counts.</p> |
| 81 | + </TooltipContent> |
| 82 | + </Tooltip> |
| 83 | + </TooltipProvider> |
81 | 84 | </div> |
82 | 85 | <div className={`text-2xl font-bold ${performanceColor}`}> |
83 | 86 | {summary.performanceScore}/100 |
84 | 87 | </div> |
| 88 | + <div className={`text-sm font-medium ${ratingInfo.className}`}>{ratingInfo.rating}</div> |
85 | 89 | </div> |
86 | 90 |
|
87 | 91 | <div className="p-4 rounded-lg border bg-background"> |
@@ -136,13 +140,28 @@ const performanceColumns = [ |
136 | 140 | { |
137 | 141 | id: 'avg_load_time', |
138 | 142 | accessorKey: 'avg_load_time', |
139 | | - header: 'Avg Load Time', |
140 | | - cell: ({ getValue }: any) => { |
141 | | - const value = getValue() as number; |
142 | | - if (!value) return '0ms'; |
143 | | - return value < 1000 ? `${Math.round(value)}ms` : `${(value / 1000).toFixed(1)}s`; |
144 | | - } |
145 | | - } |
| 143 | + header: 'Load Time', |
| 144 | + cell: ({ row }: any) => <PerformanceMetricCell value={row.original.avg_load_time} /> |
| 145 | + }, |
| 146 | + { |
| 147 | + id: 'avg_ttfb', |
| 148 | + accessorKey: 'avg_ttfb', |
| 149 | + header: 'TTFB', |
| 150 | + cell: ({ row }: any) => <PerformanceMetricCell value={row.original.avg_ttfb} /> |
| 151 | + }, |
| 152 | + { |
| 153 | + id: 'avg_dom_ready_time', |
| 154 | + accessorKey: 'avg_dom_ready_time', |
| 155 | + header: 'DOM Ready', |
| 156 | + cell: ({ row }: any) => <PerformanceMetricCell value={row.original.avg_dom_ready_time} /> |
| 157 | + }, |
| 158 | + { |
| 159 | + id: 'avg_render_time', |
| 160 | + accessorKey: 'avg_render_time', |
| 161 | + header: 'Render Time', |
| 162 | + cell: ({ row }: any) => <PerformanceMetricCell value={row.original.avg_render_time} /> |
| 163 | + }, |
| 164 | + |
146 | 165 | ]; |
147 | 166 |
|
148 | 167 | const createNameColumn = (header: string, iconRenderer?: (name: string) => React.ReactNode, nameFormatter?: (name: string) => string) => ({ |
@@ -246,36 +265,7 @@ export function WebsitePerformanceTab({ |
246 | 265 |
|
247 | 266 | // Optimized performance summary calculation |
248 | 267 | const performanceSummary = useMemo((): PerformanceSummary => { |
249 | | - const pages = processedData.pages; |
250 | | - if (!pages.length) { |
251 | | - return { avgLoadTime: 0, fastPages: 0, slowPages: 0, totalPages: 0, performanceScore: 0 }; |
252 | | - } |
253 | | - |
254 | | - // Single pass calculation |
255 | | - let totalLoadTime = 0; |
256 | | - let fastPages = 0; |
257 | | - let slowPages = 0; |
258 | | - |
259 | | - for (const page of pages) { |
260 | | - totalLoadTime += page.avg_load_time; |
261 | | - if (page.avg_load_time < 1000) fastPages++; |
262 | | - else if (page.avg_load_time > 3000) slowPages++; |
263 | | - } |
264 | | - |
265 | | - const avgLoadTime = totalLoadTime / pages.length; |
266 | | - const fastPercentage = fastPages / pages.length; |
267 | | - const slowPercentage = slowPages / pages.length; |
268 | | - const performanceScore = Math.max(0, Math.min(100, |
269 | | - Math.round((fastPercentage * 100) - (slowPercentage * 50)) |
270 | | - )); |
271 | | - |
272 | | - return { |
273 | | - avgLoadTime, |
274 | | - fastPages, |
275 | | - slowPages, |
276 | | - totalPages: pages.length, |
277 | | - performanceScore |
278 | | - }; |
| 268 | + return calculatePerformanceSummary(processedData.pages); |
279 | 269 | }, [processedData.pages]); |
280 | 270 |
|
281 | 271 | // Optimized tabs generation with stable references |
|
0 commit comments