import React, { useState } from 'react'; import { SchoolData, Class, Student, Subject, Grade, Period } from '../types'; import { dbService } from '../services/dbService'; import { useDialog } from '../DialogContext'; import { FileText, Plus, Trash2, ChevronRight, Save, GraduationCap, BookOpen, User, X, Search, CheckCircle2, AlertCircle, Calendar, Calculator } from 'lucide-react'; interface ReportCardProps { data: SchoolData; updateData: (newData: Partial) => void; } const ReportCard: React.FC = ({ data, updateData }) => { const { showAlert, showConfirm } = useDialog(); const [selectedClass, setSelectedClass] = useState(null); const [selectedStudent, setSelectedStudent] = useState(null); const [newSubjectName, setNewSubjectName] = useState(''); const [newPeriodName, setNewPeriodName] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [showConfigManager, setShowConfigManager] = useState(false); const [configTab, setConfigTab] = useState<'subjects' | 'periods'>('subjects'); const [studentGrades, setStudentGrades] = useState>>({}); // subjectId -> periodId -> value const subjects = data.subjects || []; const periods = data.periods || []; const grades = data.grades || []; const handleAddSubject = () => { if (!newSubjectName.trim()) { showAlert('Atenção', '⚠️ Por favor, informe o nome da disciplina.', 'warning'); return; } const newSubject: Subject = { id: crypto.randomUUID(), name: newSubjectName.trim() }; const updatedSubjects = [...subjects, newSubject]; updateData({ subjects: updatedSubjects }); dbService.saveData({ ...data, subjects: updatedSubjects }); setNewSubjectName(''); }; const handleAddPeriod = () => { if (!newPeriodName.trim()) { showAlert('Atenção', '⚠️ Por favor, informe o nome do período.', 'warning'); return; } const newPeriod: Period = { id: crypto.randomUUID(), name: newPeriodName.trim() }; const updatedPeriods = [...periods, newPeriod]; updateData({ periods: updatedPeriods }); dbService.saveData({ ...data, periods: updatedPeriods }); setNewPeriodName(''); }; const handleDeleteSubject = (id: string) => { showConfirm( 'Excluir Disciplina', '⚠️ Tem certeza que deseja excluir esta disciplina? Todas as notas vinculadas serão perdidas.', () => { const updatedSubjects = subjects.filter(s => s.id !== id); const updatedGrades = grades.filter(g => g.subjectId !== id); updateData({ subjects: updatedSubjects, grades: updatedGrades }); dbService.saveData({ ...data, subjects: updatedSubjects, grades: updatedGrades }); } ); }; const handleDeletePeriod = (id: string) => { showConfirm( 'Excluir Período', '⚠️ Tem certeza que deseja excluir este período? Todas as notas vinculadas serão perdidas.', () => { const updatedPeriods = periods.filter(p => p.id !== id); const updatedGrades = grades.filter(g => g.period !== id); updateData({ periods: updatedPeriods, grades: updatedGrades }); dbService.saveData({ ...data, periods: updatedPeriods, grades: updatedGrades }); } ); }; const handleOpenStudentGrades = (student: Student) => { setSelectedStudent(student); const initialGrades: Record> = {}; subjects.forEach(subject => { initialGrades[subject.id] = {}; periods.forEach(period => { const existingGrade = grades.find(g => g.studentId === student.id && g.subjectId === subject.id && g.period === period.id); initialGrades[subject.id][period.id] = existingGrade ? existingGrade.value : 0; }); }); setStudentGrades(initialGrades); }; const handleSaveGrades = () => { if (!selectedStudent) return; const newGradesList: Grade[] = [...grades.filter(g => g.studentId !== selectedStudent.id)]; Object.entries(studentGrades).forEach(([subjectId, periodGrades]) => { Object.entries(periodGrades).forEach(([periodId, value]) => { if (value > 0) { newGradesList.push({ id: crypto.randomUUID(), studentId: selectedStudent.id, subjectId, period: periodId, value }); } }); }); updateData({ grades: newGradesList }); dbService.saveData({ ...data, grades: newGradesList }); setSelectedStudent(null); showAlert('Sucesso', '✅ Notas salvas com sucesso!', 'success'); }; const calculateGeneralAverage = () => { let totalSum = 0; let totalCount = 0; Object.values(studentGrades).forEach(subjectPeriods => { const periodValues = Object.values(subjectPeriods).filter((v): v is number => typeof v === 'number' && v > 0); if (periodValues.length > 0) { const subjectSum = periodValues.reduce((a, b) => a + b, 0); const subjectAvg = subjectSum / periodValues.length; totalSum += subjectAvg; totalCount++; } }); return totalCount > 0 ? (totalSum / totalCount).toFixed(2) : '0.00'; }; const getStudentGeneralAverage = (studentId: string) => { const studentGradesList = grades.filter(g => g.studentId === studentId); if (studentGradesList.length === 0) return '0.00'; const subjectAverages: number[] = []; const subjectsWithGrades = new Set(studentGradesList.map(g => g.subjectId)); subjectsWithGrades.forEach(subId => { const subGrades = studentGradesList.filter(g => g.subjectId === subId); const sum = subGrades.reduce((a, b) => a + b.value, 0); subjectAverages.push(sum / subGrades.length); }); if (subjectAverages.length === 0) return '0.00'; const totalSum = subjectAverages.reduce((a, b) => a + b, 0); return (totalSum / subjectAverages.length).toFixed(2); }; const filteredClasses = data.classes.filter(c => (c.name || '').toLowerCase().includes((searchTerm || '').toLowerCase()) ); return (

Boletim Escolar

Gerencie as notas e o desempenho dos alunos.

{showConfigManager ? (

Gerenciar Configurações

{configTab === 'subjects' ? (
setNewSubjectName(e.target.value)} />
{subjects.map(subject => (
{subject.name}
))} {subjects.length === 0 && (
Nenhuma disciplina cadastrada.
)}
) : (
setNewPeriodName(e.target.value)} />
{periods.map(period => (
{period.name}
))} {periods.length === 0 && (
Nenhum período cadastrado.
)}
)}
) : (
{!selectedClass ? ( <>
setSearchTerm(e.target.value)} />
{filteredClasses.map(cls => { const course = data.courses.find(c => c.id === cls.courseId); const studentCount = data.students.filter(s => s.classId === cls.id).length; return (
setSelectedClass(cls)} className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm hover:shadow-xl hover:border-indigo-200 transition-all cursor-pointer group relative overflow-hidden" >

{cls.name}

{course?.name || 'Curso não encontrado'}

{studentCount} Alunos Matriculados
); })}
) : (

{selectedClass.name}

Selecione um aluno para preencher as notas.

{data.students.filter(s => s.classId === selectedClass.id).length} Alunos
{data.students .filter(s => s.classId === selectedClass.id) .sort((a, b) => a.name.localeCompare(b.name)) .map(student => (
{student.photo ? ( {student.name} ) : ( )}
{student.name}
Média Geral = 6 ? 'text-emerald-600' : 'text-red-600'}`}> {getStudentGeneralAverage(student.id)}
))}
)}
)} {/* GRADES MODAL */} {selectedStudent && (

{selectedStudent.name}

Boletim Escolar • {selectedClass?.name}

{subjects.length === 0 || periods.length === 0 ? (

{subjects.length === 0 ? 'Nenhuma disciplina cadastrada.' : 'Nenhum período cadastrado.'} Por favor, complete as configurações primeiro.

) : (
{subjects.map(subject => { // Encontrar provas vinculadas a esta disciplina const linkedExams = (data.exams || []).filter(e => e.subjectId === subject.id && e.status === 'published'); return (

{subject.name}

{linkedExams.length > 0 && (
{linkedExams.length} {linkedExams.length === 1 ? 'Prova' : 'Provas'}
)}
MÉDIA: {(() => { const subjectGrades = studentGrades[subject.id] || {}; const vals = Object.values(subjectGrades).filter((v): v is number => typeof v === 'number' && v > 0); return vals.length > 0 ? (vals.reduce((a, b) => a + b, 0) / vals.length).toFixed(1) : '0.0'; })()}
{periods.map(period => { // Verificar se há uma prova vinculada a esta disciplina+período const linkedExam = (data.exams || []).find(e => e.subjectId === subject.id && e.periodId === period.id && e.status === 'published'); return (
{ const val = parseFloat(e.target.value) || 0; setStudentGrades(prev => ({ ...prev, [subject.id]: { ...prev[subject.id], [period.id]: val } })); }} /> {linkedExam && (

📝 {linkedExam.title}

)}
); })}
); })} {/* General Average Summary */}

Média Geral

Calculada automaticamente com base em todas as disciplinas.

{calculateGeneralAverage()}
)}
)}
); }; export default ReportCard;