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) { if (_isCheckingAccess) { return const Scaffold( backgroundColor: Color(0xFFF8F9FA), body: Center( child: CircularProgressIndicator(color: Color(0xFF82C9BD)), ), ); } if (!_accessGranted) { return Scaffold( backgroundColor: const Color(0xFFF8F9FA), appBar: AppBar( backgroundColor: const Color(0xFF82C9BD), elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.of(context).pop(), ), title: const Text( 'Acesso Negado', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), ), ), body: Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.lock_outline, size: 64, color: Color(0xFF82C9BD), ), const SizedBox(height: 24), const Text( 'Sem permissão', style: TextStyle( color: Color(0xFF2D3748), fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), Text( 'Só podes ver os alunos das tuas próprias turmas.', style: TextStyle(color: Colors.grey[600], fontSize: 14), textAlign: TextAlign.center, ), ], ), ), ), ); } return Scaffold( backgroundColor: const Color(0xFFF8F9FA), appBar: AppBar( backgroundColor: const Color(0xFF82C9BD), elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.of(context).pop(), ), title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.className, style: const TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), const Text( 'Alunos Matriculados', style: TextStyle( color: Colors.white70, fontSize: 13, fontWeight: FontWeight.w300, ), ), ], ), ), 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 const Center( child: CircularProgressIndicator(color: Color(0xFF82C9BD)), ); } if (snapshot.hasError) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 48, color: Colors.grey[400]), const SizedBox(height: 16), Text( 'Erro ao carregar alunos', style: TextStyle(color: Colors.grey[600], fontSize: 16), ), ], ), ); } final enrollments = snapshot.data?.docs ?? []; if (enrollments.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.people_outline, size: 64, color: Colors.grey[300]), const SizedBox(height: 24), Text( 'Nenhum aluno entrou nesta turma ainda.', style: TextStyle(color: Colors.grey[600], fontSize: 16), textAlign: TextAlign.center, ), const SizedBox(height: 8), Padding( padding: const EdgeInsets.symmetric(horizontal: 32.0), child: Text( 'Partilha o código da turma para os alunos se juntarem.', style: TextStyle(color: Colors.grey[500], fontSize: 13), textAlign: TextAlign.center, ), ), ], ), ); } return ListView.builder( padding: const EdgeInsets.all(16.0), itemCount: enrollments.length, 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?; return Container( margin: const EdgeInsets.only(bottom: 12.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16.0), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: ListTile( contentPadding: const EdgeInsets.all(16.0), leading: Container( width: 48, height: 48, decoration: BoxDecoration( color: const Color(0xFF82C9BD).withOpacity(0.1), borderRadius: BorderRadius.circular(12.0), ), child: const Icon( Icons.person, color: Color(0xFF82C9BD), size: 24, ), ), title: Text( studentName, style: const TextStyle( color: Color(0xFF2D3748), fontSize: 16, fontWeight: FontWeight.w600, ), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Text( joinedAt != null ? 'Entrou em ${_formatDate(joinedAt.toDate())}' : 'Data desconhecida', style: TextStyle(color: Colors.grey[600], fontSize: 13), ), ], ), ), ); }, ); }, ), ); } String _formatDate(DateTime date) { return DateFormat('dd/MM/yyyy').format(date); } }