Skip to content

Commit 5efa6fd

Browse files
committed
✨ feat: Se agregó la visualizacion de materias por cursar del alumno
1 parent d316955 commit 5efa6fd

2 files changed

Lines changed: 129 additions & 128 deletions

File tree

lib/features/dashboard/viewmodels/student_detail_viewmodel.dart

Lines changed: 65 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)