Files
LearnIT/lib/features/analytics/presentation/pages/analytics_page.dart

359 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:go_router/go_router.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../../../../core/theme/app_theme_extension.dart';
import '../../../../core/services/auth_service.dart';
import '../../../../core/services/gamification_service.dart';
import '../../../../core/models/class_stats.dart';
import '../../../../core/models/achievement.dart';
import '../widgets/class_analytics_card.dart';
import '../widgets/class_ranking_widget.dart';
import '../widgets/create_achievement_dialog.dart';
/// Analytics page for teachers with class breakdowns and rankings
class AnalyticsPage extends StatefulWidget {
const AnalyticsPage({super.key});
@override
State<AnalyticsPage> createState() => _AnalyticsPageState();
}
class _AnalyticsPageState extends State<AnalyticsPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
List<ClassStats> _classStats = [];
bool _loading = true;
String? _selectedClassId;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
_loadClassStats();
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
Future<void> _loadClassStats() async {
try {
final user = AuthService.currentUser;
if (user == null) return;
// Obter disciplinas do professor
final classesSnapshot = await FirebaseFirestore.instance
.collection('classes')
.where('teacherId', isEqualTo: user.uid)
.get();
final classStatsList = <ClassStats>[];
for (final classDoc in classesSnapshot.docs) {
final classId = classDoc.id;
// Forçar atualização para obter dados mais recentes
final stats = await GamificationService.getClassStats(
classId,
forceRefresh: true,
);
if (stats != null) {
classStatsList.add(stats);
}
}
if (mounted) {
setState(() {
_classStats = classStatsList;
_loading = false;
});
}
} catch (e) {
print('Error loading class stats: $e');
if (mounted) {
setState(() {
_loading = false;
});
}
}
}
@override
Widget build(BuildContext context) {
final themeExtras = AppThemeExtras.of(context);
final cs = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: cs.surface,
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: themeExtras.dashboardBackgroundGradient,
stops: themeExtras.dashboardGradientStops,
),
),
child: SafeArea(
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.all(24),
child: Column(
children: [
Row(
children: [
IconButton(
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () => context.go('/teacher-dashboard'),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Analytics',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
'Acompanhe o desempenho das disciplinas',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.8),
fontSize: 16,
),
),
],
),
),
IconButton(
icon: const Icon(Icons.add, color: Colors.white),
onPressed: _showCreateAchievementDialog,
tooltip: 'Criar Conquista',
),
],
),
const SizedBox(height: 20),
TabBar(
controller: _tabController,
labelColor: Colors.white,
unselectedLabelColor: Colors.white.withValues(alpha: 0.7),
indicatorColor: Colors.white,
indicatorWeight: 2,
tabs: const [
Tab(text: 'Disciplinas'),
Tab(text: 'Rankings'),
],
),
],
),
),
// Content
Expanded(
child: TabBarView(
controller: _tabController,
children: [_buildClassesTab(), _buildRankingsTab()],
),
),
],
),
),
),
);
}
Widget _buildClassesTab() {
if (_loading) {
return const Center(
child: CircularProgressIndicator(color: Colors.white),
);
}
if (_classStats.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.analytics_outlined,
size: 64,
color: Colors.white.withValues(alpha: 0.5),
),
const SizedBox(height: 16),
Text(
'Nenhuma disciplina encontrada',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.7),
fontSize: 18,
),
),
const SizedBox(height: 8),
Text(
'Crie disciplinas para ver as analytics aqui',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.5),
fontSize: 14,
),
),
],
),
);
}
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Overview Cards
Row(
children: [
Expanded(
child: _buildOverviewCard(
'Total de Alunos',
'${_classStats.fold(0, (sum, stats) => sum + stats.totalStudents)}',
Icons.people,
Colors.blue,
),
),
const SizedBox(width: 12),
Expanded(
child: _buildOverviewCard(
'Alunos Ativos',
'${_classStats.fold(0, (sum, stats) => sum + stats.activeStudents)}',
Icons.trending_up,
Colors.green,
),
),
],
),
const SizedBox(height: 20),
// Class Cards
..._classStats.map(
(stats) => Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ClassAnalyticsCard(
classStats: stats,
onTap: () => _showClassRanking(stats),
),
),
),
],
),
);
}
Widget _buildRankingsTab() {
if (_selectedClassId == null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.leaderboard,
size: 64,
color: Colors.white.withValues(alpha: 0.5),
),
const SizedBox(height: 16),
Text(
'Selecione uma disciplina',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.7),
fontSize: 18,
),
),
const SizedBox(height: 8),
Text(
'Clique em uma disciplina na aba "Disciplinas" para ver o ranking',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.5),
fontSize: 14,
),
),
],
),
);
}
return ClassRankingWidget(classId: _selectedClassId!);
}
Widget _buildOverviewCard(
String title,
String value,
IconData icon,
Color color,
) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.white.withValues(alpha: 0.2)),
),
child: Column(
children: [
Icon(icon, color: color, size: 32),
const SizedBox(height: 12),
Text(
value,
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
title,
style: TextStyle(
color: Colors.white.withValues(alpha: 0.8),
fontSize: 14,
),
textAlign: TextAlign.center,
),
],
),
).animate().scale(duration: 600.ms, curve: Curves.elasticOut);
}
void _showClassRanking(ClassStats stats) {
setState(() {
_selectedClassId = stats.classId;
});
_tabController.animateTo(1); // Mudar para aba de rankings
}
void _showCreateAchievementDialog() {
showDialog(
context: context,
builder: (context) => CreateAchievementDialog(
onAchievementCreated: (achievement) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Conquista "${achievement.name}" criada com sucesso!',
),
backgroundColor: Colors.green,
),
);
},
),
);
}
}