Germinal's picture
Upload components/Dashboard.jsx with huggingface_hub
c039555 verified
import { useState, useEffect } from 'react';
import { Bar, Pie, Line } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ArcElement, PointElement, LineElement } from 'chart.js';
import { FiBarChart2, FiPieChart, FiTrendingUp, FiUsers, FiAlertTriangle } from 'react-icons/fi';
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ArcElement, PointElement, LineElement);
export default function Dashboard({ results }) {
const [activeTab, setActiveTab] = useState('overview');
const [chartData, setChartData] = useState(null);
useEffect(() => {
if (results && results.length > 0) {
const statusCounts = results.reduce((acc, agent) => {
acc[agent.status] = (acc[agent.status] || 0) + 1;
return acc;
}, {});
const positionCounts = results.reduce((acc, agent) => {
acc[agent.position] = (acc[agent.position] || 0) + 1;
return acc;
}, {});
setChartData({
status: {
labels: Object.keys(statusCounts),
datasets: [{
label: 'Status dos Agentes',
data: Object.values(statusCounts),
backgroundColor: [
'rgba(16, 185, 129, 0.7)',
'rgba(239, 68, 68, 0.7)',
'rgba(245, 158, 11, 0.7)'
],
borderColor: [
'rgba(16, 185, 129, 1)',
'rgba(239, 68, 68, 1)',
'rgba(245, 158, 11, 1)'
],
borderWidth: 1
}]
},
positions: {
labels: Object.keys(positionCounts),
datasets: [{
label: 'Cargos',
data: Object.values(positionCounts),
backgroundColor: 'rgba(59, 130, 246, 0.7)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 1
}]
},
timeline: {
labels: results.map((_, i) => `Agente ${i+1}`),
datasets: [{
label: 'Análise de Risco',
data: results.map(agent => agent.riskScore || Math.random() * 100),
borderColor: 'rgba(239, 68, 68, 1)',
backgroundColor: 'rgba(239, 68, 68, 0.1)',
tension: 0.4,
fill: true
}]
}
});
}
}, [results]);
if (!results || results.length === 0) {
return (
<div className="bg-gray-50 rounded-lg p-6 text-center">
<FiAlertTriangle className="mx-auto h-12 w-12 text-gray-400 mb-4" />
<p className="text-gray-600">Nenhum dado disponível para exibir no dashboard</p>
</div>
);
}
return (
<div className="bg-white rounded-lg shadow-md p-6">
<div className="border-b border-gray-200 mb-6">
<nav className="-mb-px flex space-x-8" aria-label="Tabs">
{['overview', 'status', 'positions', 'risk'].map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`${
activeTab === tab
? 'border-primary text-primary'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
} whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm`}
>
{tab === 'overview' && <><FiBarChart2 className="inline mr-1" /> Visão Geral</>}
{tab === 'status' && <><FiUsers className="inline mr-1" /> Status</>}
{tab === 'positions' && <><FiPieChart className="inline mr-1" /> Cargos</>}
{tab === 'risk' && <><FiTrendingUp className="inline mr-1" /> Risco</>}
</button>
))}
</nav>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
<div className="bg-blue-50 rounded-lg p-4">
<div className="flex items-center">
<div className="bg-primary rounded-full h-10 w-10 flex items-center justify-center mr-3">
<FiUsers className="text-white" />
</div>
<div>
<p className="text-sm text-gray-600">Total de Agentes</p>
<p className="text-2xl font-bold text-gray-900">{results.length}</p>
</div>
</div>
</div>
<div className="bg-green-50 rounded-lg p-4">
<div className="flex items-center">
<div className="bg-success rounded-full h-10 w-10 flex items-center justify-center mr-3">
<FiUsers className="text-white" />
</div>
<div>
<p className="text-sm text-gray-600">Ativos</p>
<p className="text-2xl font-bold text-gray-900">
{results.filter(r => r.status === 'ativo').length}
</p>
</div>
</div>
</div>
<div className="bg-red-50 rounded-lg p-4">
<div className="flex items-center">
<div className="bg-danger rounded-full h-10 w-10 flex items-center justify-center mr-3">
<FiAlertTriangle className="text-white" />
</div>
<div>
<p className="text-sm text-gray-600">Inativos</p>
<p className="text-2xl font-bold text-gray-900">
{results.filter(r => r.status === 'inativo').length}
</p>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 rounded-lg p-6">
{activeTab === 'overview' && chartData && (
<div className="space-y-6">
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Distribuição por Status</h3>
<div className="h-64">
<Pie
data={chartData.status}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
},
},
/>
</div>
</div>
</div>
)}
{activeTab === 'status' && chartData && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Status dos Agentes</h3>
<div className="h-64">
<Bar
data={chartData.status}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
/>
</div>
</div>
)}
{activeTab === 'positions' && chartData && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Distribuição de Cargos</h3>
<div className="h-64">
<Bar
data={chartData.positions}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
indexAxis: 'y',
/>
</div>
</div>
)}
{activeTab === 'risk' && chartData && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Análise de Risco</h3>
<div className="h-64">
<Line
data={chartData.timeline}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
y: {
beginAtZero: true,
max: 100
}
}
/>
</div>
</div>
)}
</div>
</div>
);
}