2025-01-30 13:18:24 +01:00
|
|
|
"use client";
|
|
|
|
|
|
2025-01-30 13:30:44 +01:00
|
|
|
import React, { useState } from "react";
|
2025-01-30 13:18:24 +01:00
|
|
|
import { Pie } from "react-chartjs-2";
|
|
|
|
|
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
|
2025-01-30 13:38:25 +01:00
|
|
|
import ChartDataLabels from "chartjs-plugin-datalabels";
|
2025-01-30 13:18:24 +01:00
|
|
|
|
2025-01-30 13:38:25 +01:00
|
|
|
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
|
2025-01-30 13:18:24 +01:00
|
|
|
|
|
|
|
|
interface ApplicationChartProps {
|
|
|
|
|
data: { nsapp: string }[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ApplicationChart: React.FC<ApplicationChartProps> = ({ data }) => {
|
2025-01-30 13:30:44 +01:00
|
|
|
const [chartStartIndex, setChartStartIndex] = useState(0);
|
|
|
|
|
|
|
|
|
|
const appCounts: Record<string, number> = {};
|
|
|
|
|
data.forEach((item) => {
|
|
|
|
|
appCounts[item.nsapp] = (appCounts[item.nsapp] || 0) + 1;
|
|
|
|
|
});
|
|
|
|
|
|
2025-01-30 13:38:25 +01:00
|
|
|
const sortedApps = Object.entries(appCounts).sort(([, a], [, b]) => b - a);
|
2025-01-30 13:30:44 +01:00
|
|
|
const chartApps = sortedApps.slice(chartStartIndex, chartStartIndex + 20);
|
|
|
|
|
|
|
|
|
|
const chartData = {
|
|
|
|
|
labels: chartApps.map(([name]) => name),
|
|
|
|
|
datasets: [
|
|
|
|
|
{
|
|
|
|
|
label: "Applications",
|
|
|
|
|
data: chartApps.map(([, count]) => count),
|
|
|
|
|
backgroundColor: [
|
|
|
|
|
"#ff6384",
|
|
|
|
|
"#36a2eb",
|
|
|
|
|
"#ffce56",
|
|
|
|
|
"#4bc0c0",
|
|
|
|
|
"#9966ff",
|
|
|
|
|
"#ff9f40",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
2025-01-30 13:18:24 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
2025-01-30 13:38:25 +01:00
|
|
|
<div className="mt-6 text-center">
|
2025-01-30 13:30:44 +01:00
|
|
|
<div className="w-1/2 mx-auto my-6">
|
2025-01-30 13:38:25 +01:00
|
|
|
<Pie
|
|
|
|
|
data={chartData}
|
|
|
|
|
options={{
|
|
|
|
|
plugins: {
|
|
|
|
|
legend: { display: false },
|
|
|
|
|
datalabels: {
|
|
|
|
|
color: "white",
|
|
|
|
|
font: { weight: "bold" },
|
|
|
|
|
formatter: (value, context) => {
|
|
|
|
|
return context.chart.data.labels?.[context.dataIndex] || "";
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2025-01-30 13:30:44 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex justify-center space-x-4">
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => setChartStartIndex(Math.max(0, chartStartIndex - 20))}
|
|
|
|
|
disabled={chartStartIndex === 0}
|
|
|
|
|
className={`p-2 border rounded ${chartStartIndex === 0 ? "bg-gray-400 cursor-not-allowed" : "bg-blue-500 text-white"}`}
|
|
|
|
|
>
|
2025-01-30 13:38:25 +01:00
|
|
|
◀ Last 20
|
2025-01-30 13:30:44 +01:00
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => setChartStartIndex(chartStartIndex + 20)}
|
|
|
|
|
disabled={chartStartIndex + 20 >= sortedApps.length}
|
|
|
|
|
className={`p-2 border rounded ${chartStartIndex + 20 >= sortedApps.length ? "bg-gray-400 cursor-not-allowed" : "bg-blue-500 text-white"}`}
|
|
|
|
|
>
|
|
|
|
|
Next 20 ▶
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2025-01-30 13:18:24 +01:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ApplicationChart;
|