import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../../../../core/services/auth_service.dart'; /// Página para visualizar os alunos de uma turma específica class ClassStudentsPage extends StatefulWidget { final String classId; final String className; const ClassStudentsPage({ super.key, required this.classId, required this.className, }); @override State createState() => _ClassStudentsPageState(); } class _ClassStudentsPageState extends State { bool _isCheckingAccess = true; bool _accessGranted = false; @override void initState() { super.initState(); _verifyOwnership(); } Future _verifyOwnership() async { final currentUser = AuthService.currentUser; if (currentUser == null) { setState(() { _isCheckingAccess = false; _accessGranted = false; }); return; } final role = await AuthService.getUserRole(currentUser.uid); if (role != 'teacher') { setState(() { _isCheckingAccess = false; _accessGranted = false; }); return; } final classDoc = await FirebaseFirestore.instance .collection('classes') .doc(widget.classId) .get(); final teacherId = classDoc.data()?['teacherId'] as String?; setState(() { _isCheckingAccess = false; _accessGranted = classDoc.exists && teacherId == currentUser.uid; }); } @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; if (_isCheckingAccess) { return Scaffold( backgroundColor: cs.surface, body: Center(child: CircularProgressIndicator(color: cs.primary)), ); } if (!_accessGranted) { return Scaffold( backgroundColor: cs.surface, appBar: AppBar( backgroundColor: cs.surface, foregroundColor: cs.onSurface, elevation: 0, title: const Text('Acesso Negado'), ), body: Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.lock_outline, size: 64, color: cs.primary), const SizedBox(height: 24), Text( 'Sem permissão', style: TextStyle( color: cs.onSurface, fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), Text( 'Só podes ver os alunos das tuas próprias turmas.', style: TextStyle(color: cs.onSurfaceVariant, fontSize: 14), textAlign: TextAlign.center, ), ], ), ), ), ); } return Scaffold( backgroundColor: cs.surface, appBar: AppBar( backgroundColor: cs.surface, foregroundColor: cs.onSurface, elevation: 0, title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.className, style: TextStyle( color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.bold, ), ), Text( 'Alunos Matriculados', style: TextStyle( color: cs.onSurfaceVariant, fontSize: 13, fontWeight: FontWeight.w400, ), ), ], ), ), body: StreamBuilder( stream: FirebaseFirestore.instance .collection('enrollments') .where('classId', isEqualTo: widget.classId) .orderBy('joinedAt', descending: true) .snapshots(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator(color: cs.primary)); } if (snapshot.hasError) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 48, color: cs.onSurfaceVariant, ), const SizedBox(height: 16), Text( 'Erro ao carregar alunos', style: TextStyle(color: cs.onSurfaceVariant, fontSize: 16), ), ], ), ); } final enrollments = snapshot.data?.docs ?? []; if (enrollments.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.people_outline, size: 64, color: cs.onSurfaceVariant.withValues(alpha: 0.4), ), const SizedBox(height: 24), Text( 'Nenhum aluno entrou nesta turma ainda.', style: TextStyle( color: cs.onSurfaceVariant, fontSize: 16, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Partilha o código da turma para os alunos se juntarem.', style: TextStyle( color: cs.onSurfaceVariant.withValues(alpha: 0.7), fontSize: 13, ), textAlign: TextAlign.center, ), ], ), ), ); } return ListView.separated( padding: const EdgeInsets.all(16), itemCount: enrollments.length, separatorBuilder: (_, __) => const SizedBox(height: 12), itemBuilder: (context, index) { final enrollment = enrollments[index].data() as Map; final studentName = enrollment['studentName'] as String? ?? 'Aluno sem nome'; final joinedAt = enrollment['joinedAt'] as Timestamp?; final enrollmentId = enrollments[index].id; return Container( decoration: BoxDecoration( color: cs.surface, borderRadius: BorderRadius.circular(16), border: Border.all(color: cs.outline.withValues(alpha: 0.15)), boxShadow: [ BoxShadow( color: cs.shadow.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), leading: Container( width: 48, height: 48, decoration: BoxDecoration( color: cs.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Icon(Icons.person, color: cs.primary, size: 24), ), title: Text( studentName, style: TextStyle( color: cs.onSurface, fontSize: 15, fontWeight: FontWeight.w600, ), ), subtitle: Padding( padding: const EdgeInsets.only(top: 4), child: Text( joinedAt != null ? 'Entrou em ${_formatDate(joinedAt.toDate())}' : 'Data desconhecida', style: TextStyle( color: cs.onSurfaceVariant, fontSize: 13, ), ), ), trailing: IconButton( icon: Icon(Icons.delete_outline, color: cs.error), onPressed: () => _showRemoveStudentDialog( context, enrollmentId, studentName, ), tooltip: 'Remover aluno', ), ), ); }, ); }, ), ); } String _formatDate(DateTime date) { return DateFormat('dd/MM/yyyy').format(date); } Future _showRemoveStudentDialog( BuildContext context, String enrollmentId, String studentName, ) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Remover Aluno'), content: Text( 'Tem a certeza que deseja remover $studentName desta turma?', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancelar'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), style: TextButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, ), child: const Text('Remover'), ), ], ), ); if (confirmed == true && context.mounted) { try { await FirebaseFirestore.instance .collection('enrollments') .doc(enrollmentId) .delete(); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ Icon(Icons.check_circle, color: Colors.white), const SizedBox(width: 12), const Text('Aluno removido com sucesso'), ], ), backgroundColor: Colors.green, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), duration: const Duration(seconds: 3), ), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ Icon(Icons.error_outline, color: Colors.white), const SizedBox(width: 12), Text('Erro ao remover aluno: $e'), ], ), backgroundColor: Colors.red, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), duration: const Duration(seconds: 4), ), ); } } } } }