@@ -16,12 +16,14 @@ class StudentDetailViewModel extends ChangeNotifier {
1616 late UserModel student;
1717 List <EnrollmentModel > _enrollments = [];
1818 final Map <String , Map <String , List <EvidenceModel >>> _groupedEvidences = {};
19+ Map <String , String > _subjectsToTakeStatus = {}; // <-- NUEVO
1920
2021 // --- GETTERS ---
2122 bool get isLoading => _isLoading;
2223 String ? get errorMessage => _errorMessage;
2324 List <EnrollmentModel > get enrollments => _enrollments;
2425 Map <String , Map <String , List <EvidenceModel >>> get groupedEvidences => _groupedEvidences;
26+ Map <String , String > get subjectsToTakeStatus => _subjectsToTakeStatus; // <-- NUEVO
2527
2628 final String studentId;
2729
@@ -40,65 +42,78 @@ class StudentDetailViewModel extends ChangeNotifier {
4042 notifyListeners ();
4143
4244 try {
43- // 0. Obtener usuario actual y sus academias
4445 final currentUser = await _authRepo.getCurrentUserData ();
45- // SI EL USUARIO NO TIENE ACADEMIAS, SE TRATARÁ COMO LISTA VACÍA, NO LANZARÁ ERROR
4646 final userAcademies = currentUser? .academies ?? [];
4747
48- // 1. Recargar datos del alumno
4948 final studentDoc = await _db.collection ('users' ).doc (studentId).get ();
5049 if (studentDoc.exists) {
5150 student = UserModel .fromMap (studentDoc.data ()! , studentDoc.id);
5251 } else {
5352 throw Exception ("No se pudo encontrar al estudiante." );
5453 }
5554
56- // Si el usuario no tiene academias, no hay nada que mostrar.
57- if (userAcademies.isEmpty) {
58- _enrollments = [];
59- _groupedEvidences.clear ();
60- _isLoading = false ;
61- notifyListeners ();
62- return ;
55+ // Cargar todas las inscripciones del alumno para la lógica de materias
56+ final allEnrollmentsSnapshot = await _db.collection ('enrollments' ).where ('uid' , isEqualTo: studentId).get ();
57+ final allEnrollments = allEnrollmentsSnapshot.docs.map ((doc) => EnrollmentModel .fromMap (doc.data (), doc.id)).toList ();
58+ final enrolledSubjectsMap = { for (var e in allEnrollments) e.subject.trim ().toLowerCase () : e.status };
59+
60+ // --- LÓGICA DE MATERIAS POR CURSAR (NUEVO) ---
61+ List <String > relevantSubjectsToTake = [];
62+ if (currentUser? .role == 'jefe_academia' ) {
63+ if (userAcademies.isNotEmpty) {
64+ final academySubjectsSnapshot = await _db.collection ('subjects' ).where ('academy' , whereIn: userAcademies).get ();
65+ final academySubjectNames = academySubjectsSnapshot.docs.map ((d) => (d.data ()['name' ] as String ).trim ().toLowerCase ()).toSet ();
66+ relevantSubjectsToTake = student.subjectsToTake.where ((s) => academySubjectNames.contains (s.trim ().toLowerCase ())).toList ();
67+ }
68+ } else {
69+ relevantSubjectsToTake = student.subjectsToTake;
6370 }
6471
65- // 2. Cargar inscripciones (Materias) FILTRADAS por las academias del usuario
66- final enrollmentsSnapshot = await _db
67- .collection ('enrollments' )
68- .where ('uid' , isEqualTo: studentId)
69- .where ('academy' , whereIn: userAcademies)
70- .get ();
71- _enrollments = enrollmentsSnapshot.docs.map ((doc) => EnrollmentModel .fromMap (doc.data (), doc.id)).toList ();
72-
73- // 3. Crear un set de nombres de materias desde las inscripciones ya filtradas.
74- final enrolledSubjectNames = _enrollments.map ((e) => e.subject.trim ().toLowerCase ()).toSet ();
75-
76- // 4. Cargar TODAS las evidencias del alumno
77- final evidencesSnapshot = await _db
78- .collection ('evidencias' )
79- .where ('uid' , isEqualTo: studentId)
80- .get ();
81-
82- // 5. Limpiar y llenar las evidencias aplicando el filtro por NOMBRE de materia
83- _groupedEvidences.clear ();
84- for (var doc in evidencesSnapshot.docs) {
85- final evidence = EvidenceModel .fromMap (doc.data (), doc.id);
86-
87- // FILTRO CLAVE: Comprobar si la materia de la evidencia está en las materias inscritas (y filtradas por academia).
88- if (enrolledSubjectNames.contains (evidence.subject.trim ().toLowerCase ())) {
89- final subject = evidence.subject;
90- _groupedEvidences.putIfAbsent (subject, () => {
91- 'pending' : [],
92- 'approved' : [],
93- 'rejected' : [],
94- });
95-
96- switch (evidence.status) {
97- case 'APROBADA' : _groupedEvidences[subject]! ['approved' ]! .add (evidence); break ;
98- case 'RECHAZADA' : _groupedEvidences[subject]! ['rejected' ]! .add (evidence); break ;
99- default : _groupedEvidences[subject]! ['pending' ]! .add (evidence); break ;
72+ _subjectsToTakeStatus = {};
73+ for (String subjectName in relevantSubjectsToTake) {
74+ final subjectNameLower = subjectName.trim ().toLowerCase ();
75+ if (enrolledSubjectsMap.containsKey (subjectNameLower)) {
76+ _subjectsToTakeStatus[subjectName] = enrolledSubjectsMap[subjectNameLower]! ;
77+ } else {
78+ _subjectsToTakeStatus[subjectName] = 'PENDIENTE' ;
79+ }
80+ }
81+ // --- FIN LÓGICA DE MATERIAS POR CURSAR ---
82+
83+ // Filtrar inscripciones y evidencias solo si es jefe de academia
84+ if (currentUser? .role == 'jefe_academia' ) {
85+ _enrollments = allEnrollments.where ((e) => userAcademies.contains (e.academy)).toList ();
86+ final academySubjectNames = _enrollments.map ((e) => e.subject.trim ().toLowerCase ()).toSet ();
87+
88+ final evidencesSnapshot = await _db.collection ('evidencias' ).where ('uid' , isEqualTo: studentId).get ();
89+ _groupedEvidences.clear ();
90+ for (var doc in evidencesSnapshot.docs) {
91+ final evidence = EvidenceModel .fromMap (doc.data (), doc.id);
92+ if (academySubjectNames.contains (evidence.subject.trim ().toLowerCase ())) {
93+ final subject = evidence.subject;
94+ _groupedEvidences.putIfAbsent (subject, () => {'pending' : [], 'approved' : [], 'rejected' : []});
95+ switch (evidence.status) {
96+ case 'APROBADA' : _groupedEvidences[subject]! ['approved' ]! .add (evidence); break ;
97+ case 'RECHAZADA' : _groupedEvidences[subject]! ['rejected' ]! .add (evidence); break ;
98+ default : _groupedEvidences[subject]! ['pending' ]! .add (evidence); break ;
99+ }
100100 }
101101 }
102+ } else {
103+ // Para admin/tutorias, mostrar todo
104+ _enrollments = allEnrollments;
105+ final evidencesSnapshot = await _db.collection ('evidencias' ).where ('uid' , isEqualTo: studentId).get ();
106+ _groupedEvidences.clear ();
107+ for (var doc in evidencesSnapshot.docs) {
108+ final evidence = EvidenceModel .fromMap (doc.data (), doc.id);
109+ final subject = evidence.subject;
110+ _groupedEvidences.putIfAbsent (subject, () => {'pending' : [], 'approved' : [], 'rejected' : []});
111+ switch (evidence.status) {
112+ case 'APROBADA' : _groupedEvidences[subject]! ['approved' ]! .add (evidence); break ;
113+ case 'RECHAZADA' : _groupedEvidences[subject]! ['rejected' ]! .add (evidence); break ;
114+ default : _groupedEvidences[subject]! ['pending' ]! .add (evidence); break ;
115+ }
116+ }
102117 }
103118
104119 } catch (e) {
@@ -109,27 +124,16 @@ class StudentDetailViewModel extends ChangeNotifier {
109124 }
110125 }
111126
112-
113- Future <String ?> reviewEvidence ({
114- required String evidenceId,
115- required bool isApproved,
116- String ? feedback,
117- }) async {
127+ Future <String ?> reviewEvidence ({ required String evidenceId, required bool isApproved, String ? feedback }) async {
118128 if (! isApproved && (feedback == null || feedback.trim ().isEmpty)) {
119129 return "El motivo del rechazo es obligatorio." ;
120130 }
121-
122131 _isLoading = true ;
123132 _errorMessage = null ;
124133 notifyListeners ();
125-
126134 try {
127- await _authRepo.reviewEvidence (
128- evidenceId: evidenceId,
129- newStatus: isApproved ? 'APROBADA' : 'RECHAZADA' ,
130- feedback: feedback
131- );
132- await loadStudentData (); // Recargar para actualizar la vista
135+ await _authRepo.reviewEvidence (evidenceId: evidenceId, newStatus: isApproved ? 'APROBADA' : 'RECHAZADA' , feedback: feedback);
136+ await loadStudentData ();
133137 return null ;
134138 } catch (e) {
135139 _errorMessage = e.toString ();
@@ -139,29 +143,16 @@ class StudentDetailViewModel extends ChangeNotifier {
139143 }
140144 }
141145
142- Future <String ?> assignSubjectGrade ({
143- required String enrollmentId,
144- required String gradeInput,
145- required bool isAccredited,
146- }) async {
146+ Future <String ?> assignSubjectGrade ({ required String enrollmentId, required String gradeInput, required bool isAccredited }) async {
147147 final grade = double .tryParse (gradeInput);
148148 if (grade == null || grade < 0 || grade > 10 ) {
149149 return "Ingresa una calificación válida (0-10)" ;
150150 }
151-
152151 _isLoading = true ;
153152 notifyListeners ();
154-
155153 try {
156- await _authRepo.assignSubjectGrade (
157- studentId: student.id,
158- enrollmentId: enrollmentId,
159- finalGrade: grade,
160- status: isAccredited ? 'ACREDITADO' : 'NO_ACREDITADO' ,
161- );
162-
154+ await _authRepo.assignSubjectGrade (studentId: student.id, enrollmentId: enrollmentId, finalGrade: grade, status: isAccredited ? 'ACREDITADO' : 'NO_ACREDITADO' );
163155 await loadStudentData ();
164-
165156 return null ;
166157 } catch (e) {
167158 return e.toString ().replaceAll ("Exception: " , "" );
0 commit comments