import 'dart:math'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/services/auth_service.dart'; import '../../../../features/materials/presentation/pages/teacher_materials_page.dart'; import 'dashboard_action_card.dart'; /// Quick access cards for teacher actions class TeacherQuickActionsWidget extends StatefulWidget { const TeacherQuickActionsWidget({super.key}); @override State createState() => _TeacherQuickActionsWidgetState(); } class _TeacherQuickActionsWidgetState extends State { bool _isCreatingClass = false; /// Mesmas dimensões dos cards em "As Minhas Disciplinas". static const double _scrollCardWidth = 200; static const double _scrollRowHeight = 150; static const double _cardMinHeight = 150; static const EdgeInsets _cardPadding = EdgeInsets.all(16); static const double _titleFontSize = 16; static const double _subtitleFontSize = 13; static const double _iconSize = 24; static const double _iconPadding = 10; @override Widget build(BuildContext context) { final cards = [ _buildUploadContentCard(context), _buildCreateClassCard(context), _buildCreateQuizCard(context), _buildViewAnalyticsCard(context), ]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Ações Rápidas', style: TextStyle( color: Theme.of(context).colorScheme.onSurface, fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), SizedBox( height: _scrollRowHeight, child: ListView.separated( scrollDirection: Axis.horizontal, clipBehavior: Clip.none, padding: const EdgeInsets.only(right: 16), itemCount: cards.length, separatorBuilder: (_, __) => const SizedBox(width: 12), itemBuilder: (context, index) => SizedBox(width: _scrollCardWidth, child: cards[index]), ), ), ], ); } Widget _buildUploadContentCard(BuildContext context) { return ClipRRect( borderRadius: BorderRadius.circular(16), child: DashboardActionCard( title: 'Upload Conteúdo', subtitle: 'PDFs, textos, imagens', icon: Icons.upload_file, useGradient: true, minHeight: _cardMinHeight, iconSize: _iconSize, iconPadding: _iconPadding, titleFontSize: _titleFontSize, subtitleFontSize: _subtitleFontSize, padding: _cardPadding, onTap: () => Navigator.push( context, MaterialPageRoute(builder: (_) => const TeacherMaterialsPage()), ), ), ); } Widget _buildCreateQuizCard(BuildContext context) { return ClipRRect( borderRadius: BorderRadius.circular(16), child: DashboardActionCardSurface( title: 'Criar Quiz', subtitle: 'Avaliações interativas', icon: Icons.quiz, minHeight: _cardMinHeight, titleFontSize: _titleFontSize, subtitleFontSize: _subtitleFontSize, iconSize: _iconSize, padding: _cardPadding, onTap: () => context.go('/teacher/quiz/create'), ), ); } Widget _buildViewAnalyticsCard(BuildContext context) { final cs = Theme.of(context).colorScheme; return DashboardActionCardSurface( title: 'Analytics', subtitle: 'Desempenho da disciplina', icon: Icons.analytics, minHeight: _cardMinHeight, titleFontSize: _titleFontSize, subtitleFontSize: _subtitleFontSize, iconSize: _iconSize, padding: _cardPadding, iconColor: cs.primary, leadingWidget: Container( padding: const EdgeInsets.all(_iconPadding), decoration: BoxDecoration( color: cs.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Icon(Icons.analytics, color: cs.primary, size: _iconSize), ), onTap: () => context.go('/teacher/analytics'), ); } Widget _buildCreateClassCard(BuildContext context) { final cs = Theme.of(context).colorScheme; return ClipRRect( borderRadius: BorderRadius.circular(16), child: DashboardActionCardSurface( title: 'Criar Disciplina', subtitle: 'Gerar código de acesso', icon: Icons.school, minHeight: _cardMinHeight, titleFontSize: _titleFontSize, subtitleFontSize: _subtitleFontSize, iconSize: _iconSize, padding: _cardPadding, iconColor: cs.primary, onTapDisabled: _isCreatingClass, onTap: () => _showCreateClassDialog(context), leadingWidget: Container( padding: const EdgeInsets.all(_iconPadding), decoration: BoxDecoration( color: cs.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: _isCreatingClass ? SizedBox( width: _iconSize, height: _iconSize, child: CircularProgressIndicator( strokeWidth: 2, color: cs.primary, ), ) : Icon(Icons.school, color: cs.primary, size: _iconSize), ), ), ); } void _showCreateClassDialog(BuildContext context) { final TextEditingController nameController = TextEditingController(); String? selectedSchoolClassId; List> schoolClasses = []; bool isLoadingClasses = true; // Carregar school_classes antes de mostrar o dialog FirebaseFirestore.instance .collection('school_classes') .where('active', isEqualTo: true) .orderBy('year') .orderBy('section') .get() .then((snapshot) { schoolClasses = snapshot.docs.map((doc) { final data = doc.data(); return {'id': doc.id, 'name': (data['name'] as String? ?? doc.id)}; }).toList(); isLoadingClasses = false; }) .catchError((_) { isLoadingClasses = false; }); showDialog( context: context, builder: (BuildContext dialogContext) { return StatefulBuilder( builder: (context, setDialogState) { // Atualizar estado do dialog quando as classes carregarem if (isLoadingClasses) { Future.delayed(const Duration(milliseconds: 300), () { if (dialogContext.mounted) setDialogState(() {}); }); } return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), title: Text( 'Criar Nova Disciplina', style: TextStyle( color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.bold, ), ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Nome da disciplina:', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 14, ), ), const SizedBox(height: 12), TextField( controller: nameController, decoration: InputDecoration( hintText: 'Ex: Matemática, Física...', filled: true, fillColor: Theme.of( context, ).colorScheme.surfaceContainerHighest, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, width: 2, ), ), ), ), const SizedBox(height: 16), Text( 'Ano letivo:', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 14, ), ), const SizedBox(height: 8), isLoadingClasses ? Row( children: [ SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, color: Theme.of(context).colorScheme.primary, ), ), const SizedBox(width: 10), Text( 'A carregar disciplinas...', style: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, fontSize: 13, ), ), ], ) : DropdownButtonFormField( value: selectedSchoolClassId, isExpanded: true, decoration: InputDecoration( filled: true, fillColor: Theme.of( context, ).colorScheme.surfaceContainerHighest, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, width: 2, ), ), contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10, ), ), hint: Text( 'Seleciona o ano letivo', style: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, ), ), items: schoolClasses .map( (c) => DropdownMenuItem( value: c['id'], child: Text(c['name']!), ), ) .toList(), onChanged: (value) => setDialogState( () => selectedSchoolClassId = value, ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(dialogContext).pop(), child: Text( 'Cancelar', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), ElevatedButton( onPressed: () { final className = nameController.text.trim(); if (className.isNotEmpty) { Navigator.of(dialogContext).pop(); _createClass( className, schoolClassId: selectedSchoolClassId, ); } }, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primary, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text('Criar'), ), ], ); }, ); }, ); } String _generateClassCode() { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; final random = Random(); return String.fromCharCodes( Iterable.generate( 6, (_) => chars.codeUnitAt(random.nextInt(chars.length)), ), ); } Future _createClass(String className, {String? schoolClassId}) async { setState(() { _isCreatingClass = true; }); try { final currentUser = AuthService.currentUser; if (currentUser == null) { throw Exception('Utilizador não autenticado'); } final classCode = _generateClassCode(); final firestore = FirebaseFirestore.instance; final Map classData = { 'name': className, 'teacherId': currentUser.uid, 'code': classCode, 'createdAt': FieldValue.serverTimestamp(), }; if (schoolClassId != null && schoolClassId.isNotEmpty) { classData['schoolClassId'] = schoolClassId; } await firestore.collection('classes').add(classData); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Disciplina "$className" criada com sucesso! Código: $classCode', ), backgroundColor: Theme.of(context).colorScheme.primary, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Erro ao criar disciplina: $e'), backgroundColor: Colors.red, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ); } } finally { setState(() { _isCreatingClass = false; }); } } }