'use client'; import React, { useState, useEffect } from 'react'; import { useRouter, useParams } from 'next/navigation'; import SelectChoice from '@/components/Form/SelectChoice'; import Attendance from '@/components/Grades/Attendance'; import GradesStatsCircle from '@/components/Grades/GradesStatsCircle'; import GradesDomainBarChart from '@/components/Grades/GradesDomainBarChart'; import { EvaluationStudentView } from '@/components/Evaluation'; import Button from '@/components/Form/Button'; import logger from '@/utils/logger'; import { FE_ADMIN_GRADES_STUDENT_COMPETENCIES_URL, BASE_URL } from '@/utils/Url'; import { fetchStudents, fetchStudentCompetencies, fetchAbsences, editAbsences, deleteAbsences, } from '@/app/actions/subscriptionAction'; import { fetchEvaluations, fetchStudentEvaluations, updateStudentEvaluation, } from '@/app/actions/schoolAction'; import { useEstablishment } from '@/context/EstablishmentContext'; import { useClasses } from '@/context/ClassesContext'; import { Award, ArrowLeft, BookOpen } from 'lucide-react'; import dayjs from 'dayjs'; import { useCsrfToken } from '@/context/CsrfContext'; function getPeriodString(selectedPeriod, frequency) { const year = dayjs().month() >= 8 ? dayjs().year() : dayjs().year() - 1; const nextYear = (year + 1).toString(); const schoolYear = `${year}-${nextYear}`; if (frequency === 1) return `T${selectedPeriod}_${schoolYear}`; if (frequency === 2) return `S${selectedPeriod}_${schoolYear}`; if (frequency === 3) return `A_${schoolYear}`; return ''; } export default function StudentGradesPage() { const router = useRouter(); const params = useParams(); const studentId = Number(params.studentId); const csrfToken = useCsrfToken(); const { selectedEstablishmentId, selectedEstablishmentEvaluationFrequency } = useEstablishment(); const { getNiveauLabel } = useClasses(); const [student, setStudent] = useState(null); const [studentCompetencies, setStudentCompetencies] = useState(null); const [grades, setGrades] = useState({}); const [selectedPeriod, setSelectedPeriod] = useState(null); const [allAbsences, setAllAbsences] = useState([]); // Evaluation states const [evaluations, setEvaluations] = useState([]); const [studentEvaluationsData, setStudentEvaluationsData] = useState([]); const getPeriods = () => { if (selectedEstablishmentEvaluationFrequency === 1) { return [ { label: 'Trimestre 1', value: 1, start: '09-01', end: '12-31' }, { label: 'Trimestre 2', value: 2, start: '01-01', end: '03-31' }, { label: 'Trimestre 3', value: 3, start: '04-01', end: '07-15' }, ]; } if (selectedEstablishmentEvaluationFrequency === 2) { return [ { label: 'Semestre 1', value: 1, start: '09-01', end: '01-31' }, { label: 'Semestre 2', value: 2, start: '02-01', end: '07-15' }, ]; } if (selectedEstablishmentEvaluationFrequency === 3) { return [{ label: 'Année', value: 1, start: '09-01', end: '07-15' }]; } return []; }; // Load student info useEffect(() => { if (selectedEstablishmentId) { fetchStudents(selectedEstablishmentId, null, 5) .then((students) => { const found = students.find((s) => s.id === studentId); setStudent(found || null); }) .catch((error) => logger.error('Error fetching students:', error)); } }, [selectedEstablishmentId, studentId]); // Auto-select current period useEffect(() => { const periods = getPeriods(); const today = dayjs(); const current = periods.find((p) => { const start = dayjs(`${today.year()}-${p.start}`); const end = dayjs(`${today.year()}-${p.end}`); return ( today.isAfter(start.subtract(1, 'day')) && today.isBefore(end.add(1, 'day')) ); }); setSelectedPeriod(current ? current.value : null); }, [selectedEstablishmentEvaluationFrequency]); // Load competencies useEffect(() => { if (studentId && selectedPeriod) { const periodString = getPeriodString( selectedPeriod, selectedEstablishmentEvaluationFrequency ); fetchStudentCompetencies(studentId, periodString) .then((data) => { setStudentCompetencies(data); if (data && data.data) { const initialGrades = {}; data.data.forEach((domaine) => { domaine.categories.forEach((cat) => { cat.competences.forEach((comp) => { initialGrades[comp.competence_id] = comp.score ?? 0; }); }); }); setGrades(initialGrades); } }) .catch((error) => logger.error('Error fetching studentCompetencies:', error) ); } else { setGrades({}); setStudentCompetencies(null); } }, [studentId, selectedPeriod]); // Load absences useEffect(() => { if (selectedEstablishmentId) { fetchAbsences(selectedEstablishmentId) .then((data) => setAllAbsences(data)) .catch((error) => logger.error('Erreur lors du fetch des absences:', error) ); } }, [selectedEstablishmentId]); // Load evaluations for the student useEffect(() => { if (student?.associated_class_id && selectedPeriod && selectedEstablishmentId) { const periodString = getPeriodString( selectedPeriod, selectedEstablishmentEvaluationFrequency ); // Load evaluations for the class fetchEvaluations(selectedEstablishmentId, student.associated_class_id, periodString) .then((data) => setEvaluations(data)) .catch((error) => logger.error('Erreur lors du fetch des évaluations:', error)); // Load student's evaluation scores fetchStudentEvaluations(studentId, null, periodString, null) .then((data) => setStudentEvaluationsData(data)) .catch((error) => logger.error('Erreur lors du fetch des notes:', error)); } }, [student, selectedPeriod, selectedEstablishmentId]); const absences = React.useMemo(() => { return allAbsences .filter((a) => a.student === studentId) .map((a) => ({ id: a.id, date: a.day, type: [2, 1].includes(a.reason) ? 'Absence' : 'Retard', reason: a.reason, justified: [1, 3].includes(a.reason), moment: a.moment, commentaire: a.commentaire, })); }, [allAbsences, studentId]); const handleToggleJustify = (absence) => { const newReason = absence.type === 'Absence' ? absence.justified ? 2 : 1 : absence.justified ? 4 : 3; editAbsences(absence.id, { ...absence, reason: newReason }, csrfToken) .then(() => { setAllAbsences((prev) => prev.map((a) => a.id === absence.id ? { ...a, reason: newReason } : a ) ); }) .catch((e) => logger.error('Erreur lors du changement de justification', e)); }; const handleDeleteAbsence = (absence) => { return deleteAbsences(absence.id, csrfToken) .then(() => { setAllAbsences((prev) => prev.filter((a) => a.id !== absence.id)); }) .catch((e) => logger.error("Erreur lors de la suppression de l'absence", e) ); }; const handleUpdateGrade = async (studentEvalId, data) => { try { await updateStudentEvaluation(studentEvalId, data, csrfToken); // Reload student evaluations const periodString = getPeriodString(selectedPeriod, selectedEstablishmentEvaluationFrequency); const updatedData = await fetchStudentEvaluations(studentId, null, periodString, null); setStudentEvaluationsData(updatedData); } catch (error) { logger.error('Erreur lors de la modification de la note:', error); } }; return (