Spaces:
Build error
Build error
| 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> | |
| ); | |
| } |