Skip to content

Commit 1c5c34e

Browse files
HyteqHyteq
authored andcommitted
feat: improved performance tab calculation
1 parent f4d5035 commit 1c5c34e

5 files changed

Lines changed: 337 additions & 346 deletions

File tree

apps/dashboard/app/(main)/websites/[id]/_components/tabs/overview-tab.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,8 @@ export function WebsiteOverviewTab({
861861
isLoading={isLoading}
862862
initialPageSize={7}
863863
minHeight={230}
864+
isScrollable
865+
scrollHeight={400}
864866
/>
865867

866868
<DataTable
@@ -870,6 +872,8 @@ export function WebsiteOverviewTab({
870872
isLoading={isLoading}
871873
initialPageSize={7}
872874
minHeight={230}
875+
isScrollable
876+
scrollHeight={400}
873877
/>
874878
</div>
875879

@@ -880,6 +884,8 @@ export function WebsiteOverviewTab({
880884
title="Custom Events"
881885
description="User-defined events and interactions with property breakdowns"
882886
isLoading={isLoading}
887+
isScrollable
888+
scrollHeight={400}
883889
initialPageSize={8}
884890
minHeight={200}
885891
emptyMessage="No custom events tracked yet"
@@ -956,6 +962,8 @@ export function WebsiteOverviewTab({
956962
initialPageSize={8}
957963
minHeight={200}
958964
showSearch={false}
965+
isScrollable
966+
scrollHeight={400}
959967
/>
960968

961969
<DataTable
@@ -967,6 +975,8 @@ export function WebsiteOverviewTab({
967975
initialPageSize={8}
968976
minHeight={200}
969977
showSearch={false}
978+
isScrollable
979+
scrollHeight={400}
970980
/>
971981

972982
<DataTable
@@ -978,6 +988,8 @@ export function WebsiteOverviewTab({
978988
initialPageSize={8}
979989
minHeight={200}
980990
showSearch={false}
991+
isScrollable
992+
scrollHeight={400}
981993
/>
982994
</div>
983995
</div>

apps/dashboard/app/(main)/websites/[id]/_components/tabs/performance-tab.tsx

Lines changed: 47 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,22 @@
22

33
import { useEffect, useMemo, useCallback } from "react";
44
import { Monitor, Smartphone, Zap, MapPin, TrendingUp, TrendingDown, AlertTriangle, CheckCircle } from "lucide-react";
5+
import { Question } from "@phosphor-icons/react";
56
import { DataTable } from "@/components/analytics/data-table";
67
import { useEnhancedPerformanceData } from "@/hooks/use-dynamic-query";
78
import type { FullTabProps } from "../utils/types";
89
import { BrowserIcon, OSIcon } from "@/components/icon";
910
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" };
3021
}
3122

3223
function PerformanceMetricCell({ value, type = 'time' }: { value?: number; type?: 'time' | 'cls' }) {
@@ -72,16 +63,29 @@ function PerformanceSummaryCard({ summary }: { summary: PerformanceSummary }) {
7263
return 'text-red-600';
7364
}, [summary.avgLoadTime]);
7465

66+
const ratingInfo = getPerformanceRating(summary.performanceScore);
67+
7568
return (
7669
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
7770
<div className="p-4 rounded-lg border bg-background">
7871
<div className="flex items-center gap-2 mb-2">
7972
<Zap className="h-4 w-4 text-primary" />
8073
<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>
8184
</div>
8285
<div className={`text-2xl font-bold ${performanceColor}`}>
8386
{summary.performanceScore}/100
8487
</div>
88+
<div className={`text-sm font-medium ${ratingInfo.className}`}>{ratingInfo.rating}</div>
8589
</div>
8690

8791
<div className="p-4 rounded-lg border bg-background">
@@ -136,13 +140,28 @@ const performanceColumns = [
136140
{
137141
id: 'avg_load_time',
138142
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+
146165
];
147166

148167
const createNameColumn = (header: string, iconRenderer?: (name: string) => React.ReactNode, nameFormatter?: (name: string) => string) => ({
@@ -246,36 +265,7 @@ export function WebsitePerformanceTab({
246265

247266
// Optimized performance summary calculation
248267
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);
279269
}, [processedData.pages]);
280270

281271
// Optimized tabs generation with stable references

0 commit comments

Comments
 (0)