import React, { useState, useMemo } from 'react'; import { SchoolData, Student, Payment, Class } from '../types'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, PieChart, Pie, AreaChart, Area, Legend, LineChart, Line } from 'recharts'; import { Users, BookOpen, Wallet, Clock, FileDown, RefreshCw, TrendingUp, UserPlus, CheckCircle2, AlertCircle, Calendar, ChevronRight, Layout } from 'lucide-react'; import { pdfService } from '../services/pdfService'; interface DashboardProps { data: SchoolData; } const Dashboard: React.FC = ({ data }) => { const [isGeneratingPDF, setIsGeneratingPDF] = useState(false); const [dashboardView, setDashboardView] = useState<'standard' | 'detailed'>('standard'); // Basic Stats const activeStudents = useMemo(() => data.students.filter(s => s.status === 'active').length, [data.students]); const totalClasses = useMemo(() => data.classes.length, [data.classes]); const pendingPayments = useMemo(() => data.payments.filter(p => p.status === 'pending').length, [data.payments]); const revenue = useMemo(() => data.payments .filter(p => p.status === 'paid') .reduce((sum, p) => sum + (Number((p as any).valor_pago) || (Number(p.amount) - (Number(p.discount) || 0))), 0), [data.payments]); // Advanced Stats const newStudentsThisMonth = useMemo(() => { const now = new Date(); const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); return data.students.filter(s => new Date(s.registrationDate) >= startOfMonth).length; }, [data.students]); const attendanceRate = useMemo(() => { if (!data.attendance || data.attendance.length === 0) return 0; const presents = data.attendance.filter(a => a.type === 'presence').length; return Math.round((presents / data.attendance.length) * 100); }, [data.attendance]); const averagePaymentValue = useMemo(() => { if (data.payments.length === 0) return 0; const total = data.payments.reduce((sum, p) => sum + p.amount, 0); return Math.round(total / data.payments.length); }, [data.payments]); const aulasARepor = useMemo(() => { if (!data.lessons) return 0; const cancelled = data.lessons.filter(l => l.status === 'cancelled'); return cancelled.filter(c => !data.lessons!.some(l => l.originalLessonId === c.id)).length; }, [data.lessons]); // Chart Data: Class Occupancy const classOccupancy = useMemo(() => data.classes.map(c => ({ name: c.name, students: data.students.filter(s => s.classId === c.id).length, capacity: 20 // Assuming a default capacity })).sort((a, b) => b.students - a.students), [data.classes, data.students]); // Chart Data: Payment Status const paymentStatus = useMemo(() => [ { name: 'Pago', value: data.payments.filter(p => p.status === 'paid').length, color: '#10b981' }, { name: 'Pendente', value: data.payments.filter(p => p.status === 'pending').length, color: '#f59e0b' }, { name: 'Atrasado', value: data.payments.filter(p => p.status === 'overdue').length, color: '#ef4444' }, ], [data.payments]); // Chart Data: Revenue Over Time (Last 6 months) const revenueHistory = useMemo(() => { const months = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']; const now = new Date(); const history = []; for (let i = 5; i >= 0; i--) { const d = new Date(now.getFullYear(), now.getMonth() - i, 1); const monthName = months[d.getMonth()]; const monthPayments = data.payments.filter(p => { const pDate = new Date(p.paidDate || p.dueDate); return pDate.getMonth() === d.getMonth() && pDate.getFullYear() === d.getFullYear() && p.status === 'paid'; }); const monthRevenue = monthPayments.reduce((sum, p) => sum + (Number((p as any).valor_pago) || (Number(p.amount) - (Number(p.discount) || 0))), 0); history.push({ name: monthName, revenue: monthRevenue }); } return history; }, [data.payments]); // Recent Activity const recentActivity = useMemo(() => { const activities = [ ...data.students.slice(-3).map(s => ({ type: 'student', title: 'Novo Aluno', desc: s.name, date: s.registrationDate, icon: UserPlus, color: 'bg-blue-100 text-blue-600' })), ...data.payments.filter(p => p.status === 'paid').slice(-3).map(p => ({ type: 'payment', title: 'Pagamento Recebido', desc: `R$ ${(Number((p as any).valor_pago) || (Number(p.amount) - (Number(p.discount) || 0))).toLocaleString()}`, date: p.paidDate || p.dueDate, icon: CheckCircle2, color: 'bg-emerald-100 text-emerald-600' })) ].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()).slice(0, 5); return activities; }, [data.students, data.payments]); const handleGenerateReport = async () => { setIsGeneratingPDF(true); try { await pdfService.generateFullSchoolReportPDF(data); } catch (error) { console.error('Error generating PDF:', error); } finally { setIsGeneratingPDF(false); } }; const stats = [ { label: 'Alunos Ativos', value: activeStudents, icon: Users, color: 'text-blue-600', bg: 'bg-blue-100', trend: '+12%' }, { label: 'Turmas Ativas', value: totalClasses, icon: BookOpen, color: 'text-indigo-600', bg: 'bg-indigo-100', trend: '+2' }, { label: 'Receita Total', value: `R$ ${revenue.toLocaleString()}`, icon: Wallet, color: 'text-emerald-600', bg: 'bg-emerald-100', trend: '+8.4%' }, { label: 'Taxa de Presença', value: `${attendanceRate}%`, icon: TrendingUp, color: 'text-purple-600', bg: 'bg-purple-100', trend: '+2.1%' }, ]; const secondaryStats = [ { label: 'Aulas a Repor', value: aulasARepor, icon: Calendar, color: 'text-red-600' }, { label: 'Novos Alunos (Mês)', value: newStudentsThisMonth, icon: UserPlus, color: 'text-sky-600' }, { label: 'Pagamentos Pendentes', value: pendingPayments, icon: Clock, color: 'text-amber-600' }, { label: 'Ticket Médio', value: `R$ ${averagePaymentValue}`, icon: Wallet, color: 'text-slate-600' }, ]; return (

Painel Executivo

Visão geral do desempenho da instituição.

{/* Main Stats Grid */}
{stats.map((stat, i) => (
{stat.trend}

{stat.label}

{stat.value}

))}
{/* Secondary Stats Row */}
{secondaryStats.map((stat, i) => (

{stat.label}

{stat.value}

))}
{/* Revenue Area Chart */}

Fluxo de Receita

Últimos 6 meses

+15.2% vs ano anterior
`R$ ${value}`} /> [`R$ ${value.toLocaleString()}`, 'Receita']} />
{/* Payment Status Pie Chart */}

Status Financeiro

Distribuição de pagamentos

{data.payments.length > 0 ? ( <> {paymentStatus.map((entry, index) => ( ))}
{data.payments.length} Total
) : (
Sem dados
)}
{paymentStatus.map((item, i) => (
{item.name}
{item.value}
))}
{/* Class Occupancy Bar Chart */}

Ocupação das Turmas

Alunos por turma

{classOccupancy.length > 0 ? ( {classOccupancy.map((entry, index) => ( ))} ) : (
Sem turmas
)}
{/* Recent Activity Feed */}

Atividade Recente

{recentActivity.length > 0 ? ( recentActivity.map((activity, i) => (
{i !== recentActivity.length - 1 && (
)}

{activity.title}

{new Date(activity.date).toLocaleDateString('pt-BR', {day: '2-digit', month: 'short'})}

{activity.desc}

)) ) : (
Nenhuma atividade recente
)}
{/* Detailed View Expansion */} {dashboardView === 'detailed' && (

Distribuição por Gênero

s.gender === 'M').length }, { name: 'Feminino', value: data.students.filter(s => s.gender === 'F').length }, { name: 'Outro', value: data.students.filter(s => s.gender === 'O').length }, ]} cx="50%" cy="50%" outerRadius={60} dataKey="value" label >

Alunos por Status

s.status === 'active').length }, { name: 'Inativo', value: data.students.filter(s => s.status === 'inactive').length }, { name: 'Trancado', value: data.students.filter(s => s.status === 'suspended').length }, ]}>
)}
); }; export default Dashboard;