Files
dashboard/components/PerformanceDebug.tsx
T

141 lines
5.6 KiB
TypeScript

import React, { useState, useEffect, useCallback } from 'react';
import { performanceService } from '../services/performanceService.ts';
const PerformanceDebug: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const [metrics, setMetrics] = useState(() => performanceService.getMetrics());
const [apiTimings, setApiTimings] = useState(() => performanceService.getApiTimings());
const [componentTimings, setComponentTimings] = useState(() =>
performanceService.getComponentTimings()
);
const refreshMetrics = useCallback(() => {
setMetrics(performanceService.getMetrics());
setApiTimings(performanceService.getApiTimings());
setComponentTimings(performanceService.getComponentTimings());
}, []);
useEffect(() => {
if (!isOpen) return undefined;
refreshMetrics(); // Refresh immediately on open
const interval = setInterval(refreshMetrics, 2000);
return () => clearInterval(interval);
}, [isOpen, refreshMetrics]);
const formatMs = (value: number | null) => (value === null ? 'N/A' : `${Math.round(value)} ms`);
const formatCls = (value: number | null) => (value === null ? 'N/A' : value.toFixed(4));
if (!isOpen) {
return (
<button
onClick={() => setIsOpen(true)}
className="fixed bottom-6 right-24 bg-indigo-600 text-white w-16 h-16 rounded-full shadow-lg flex items-center justify-center hover:bg-indigo-700 transition-transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 z-40"
aria-label="Open Performance Debug"
>
<i className="fa-solid fa-tachometer-alt-fast text-2xl"></i>
</button>
);
}
return (
<div className="fixed bottom-6 right-6 w-96 bg-white rounded-2xl shadow-2xl z-40 border border-gray-200 transform transition-all text-sm font-sans">
<div className="p-4 border-b flex justify-between items-center bg-gray-50 rounded-t-2xl">
<h3 className="font-bold text-gray-800 flex items-center">
<i className="fa-solid fa-tachometer-alt-fast mr-2 text-indigo-600"></i> Performance Debug
</h3>
<div className="flex items-center gap-2">
<button
onClick={refreshMetrics}
className="text-gray-500 hover:text-indigo-600"
title="Refresh Metrics"
>
<i className="fa-solid fa-sync"></i>
</button>
<button
onClick={() => setIsOpen(false)}
className="text-gray-400 hover:text-gray-600 text-xl"
aria-label="Close"
>
&times;
</button>
</div>
</div>
<div className="p-4 space-y-3 max-h-96 overflow-y-auto">
<div>
<h4 className="font-semibold text-gray-700 mb-1">Core Web Vitals & Loading</h4>
<ul className="space-y-1 pl-2 text-gray-600">
<li className="flex justify-between">
<span>Page Load Time:</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">
{formatMs(metrics.pageLoad)}
</span>
</li>
<li className="flex justify-between">
<span>Time to First Byte (TTFB):</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">{formatMs(metrics.ttfb)}</span>
</li>
<li className="flex justify-between">
<span>First Contentful Paint (FCP):</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">{formatMs(metrics.fcp)}</span>
</li>
<li className="flex justify-between">
<span>Largest Contentful Paint (LCP):</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">{formatMs(metrics.lcp)}</span>
</li>
<li className="flex justify-between">
<span>First Input Delay (FID):</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">{formatMs(metrics.fid)}</span>
</li>
<li className="flex justify-between">
<span>Cumulative Layout Shift (CLS):</span>{' '}
<span className="font-mono bg-gray-100 px-2 rounded">{formatCls(metrics.cls)}</span>
</li>
</ul>
</div>
<div>
<h4 className="font-semibold text-gray-700 mb-1 pt-2 border-t mt-3">
Component Mount Timings
</h4>
<ul className="space-y-1 pl-2 text-gray-600">
{componentTimings.length > 0 ? (
componentTimings.map((timing) => (
<li key={timing.timestamp} className="flex justify-between">
<span>{timing.name}:</span>
<span className="font-mono bg-gray-100 px-2 rounded">
{formatMs(timing.duration)}
</span>
</li>
))
) : (
<li>No components timed yet.</li>
)}
</ul>
</div>
<div>
<h4 className="font-semibold text-gray-700 mb-1 pt-2 border-t mt-3">
API Timings (Last 10)
</h4>
<ul className="space-y-1 pl-2 text-gray-600">
{apiTimings.length > 0 ? (
apiTimings.map((timing) => (
<li key={timing.timestamp} className="flex justify-between">
<span>{timing.name}:</span>
<span className="font-mono bg-gray-100 px-2 rounded">
{formatMs(timing.duration)}
</span>
</li>
))
) : (
<li>No API calls recorded yet.</li>
)}
</ul>
</div>
</div>
</div>
);
};
export default PerformanceDebug;