Enhances dashboard with new metrics and charts

Improves the dashboard with additional metrics and visualizations
to provide a more comprehensive overview of application usage and performance.

Adds new charts, including:
- Word cloud for category analysis
- Geographic map for user distribution (simulated data)
- Response time distribution chart

Refactors existing components for improved clarity and reusability,
including the introduction of a generic `MetricCard` component.

Improves error handling and user feedback during data refresh and
session loading.

Adds recommended VSCode extensions for ESLint and Prettier.
This commit is contained in:
2025-05-22 04:04:50 +02:00
parent 2624bf1378
commit 5317b2aa39
34 changed files with 2122 additions and 172 deletions

View File

@ -0,0 +1,109 @@
"use client";
import { useRef, useEffect } from "react";
import Chart from "chart.js/auto";
import annotationPlugin from "chartjs-plugin-annotation";
Chart.register(annotationPlugin);
interface ResponseTimeDistributionProps {
responseTimes: number[];
targetResponseTime?: number;
}
export default function ResponseTimeDistribution({
responseTimes,
targetResponseTime,
}: ResponseTimeDistributionProps) {
const ref = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
if (!ref.current || !responseTimes.length) return;
const ctx = ref.current.getContext("2d");
if (!ctx) return;
// Create bins for the histogram (0-1s, 1-2s, 2-3s, etc.)
const maxTime = Math.ceil(Math.max(...responseTimes));
const bins = Array(Math.min(maxTime + 1, 10)).fill(0);
// Count responses in each bin
responseTimes.forEach((time) => {
const binIndex = Math.min(Math.floor(time), bins.length - 1);
bins[binIndex]++;
});
// Create labels for each bin
const labels = bins.map((_, i) => {
if (i === bins.length - 1 && bins.length < maxTime + 1) {
return `${i}+ seconds`;
}
return `${i}-${i + 1} seconds`;
});
const chart = new Chart(ctx, {
type: "bar",
data: {
labels,
datasets: [
{
label: "Responses",
data: bins,
backgroundColor: bins.map((_, i) => {
// Green for fast, yellow for medium, red for slow
if (i <= 2) return "rgba(34, 197, 94, 0.7)"; // Green
if (i <= 5) return "rgba(250, 204, 21, 0.7)"; // Yellow
return "rgba(239, 68, 68, 0.7)"; // Red
}),
borderWidth: 1,
},
],
},
options: {
responsive: true,
plugins: {
legend: { display: false },
annotation: targetResponseTime
? {
annotations: {
targetLine: {
type: "line",
yMin: 0,
yMax: Math.max(...bins),
xMin: targetResponseTime,
xMax: targetResponseTime,
borderColor: "rgba(75, 192, 192, 1)",
borderWidth: 2,
label: {
display: true,
content: "Target",
position: "start",
},
},
},
}
: undefined,
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: "Number of Responses",
},
},
x: {
title: {
display: true,
text: "Response Time",
},
},
},
},
});
return () => chart.destroy();
}, [responseTimes, targetResponseTime]);
return <canvas ref={ref} height={180} />;
}