import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:go_router/go_router.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../core/services/auth_service.dart'; import '../../../../core/theme/app_theme_extension.dart'; import '../../../../shared/presentation/widgets/custom_notification.dart'; class SignupPage extends StatefulWidget { final String? selectedRole; const SignupPage({super.key, this.selectedRole}); @override State createState() => _SignupPageState(); } class _SignupPageState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; bool _obscurePassword = true; late String _selectedRole; String? _selectedSchoolClassId; List> _availableClasses = []; bool _isLoadingClasses = false; @override void initState() { super.initState(); // Usar role passado da tela anterior ou default 'student' _selectedRole = widget.selectedRole ?? 'student'; if (_selectedRole == 'student') { _loadAvailableClasses(); } } Future _loadAvailableClasses() async { setState(() => _isLoadingClasses = true); try { final snapshot = await FirebaseFirestore.instance .collection('school_classes') .where('active', isEqualTo: true) .orderBy('year') .orderBy('section') .get(); setState(() { _availableClasses = snapshot.docs.map((doc) { final data = doc.data(); return {'id': doc.id, 'name': (data['name'] as String? ?? doc.id)}; }).toList(); _isLoadingClasses = false; }); } catch (e) { setState(() => _isLoadingClasses = false); } } @override void dispose() { _nameController.dispose(); _emailController.dispose(); _passwordController.dispose(); super.dispose(); } Widget _buildClassSelector(BuildContext context) { if (_isLoadingClasses) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Theme.of(context).colorScheme.primary, ), ), const SizedBox(width: 12), Text( 'A carregar anos letivos...', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 14, ), ), ], ), ); } if (_availableClasses.isEmpty) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Text( 'Nenhum ano letivo disponível. Contacta o teu professor.', style: TextStyle( color: Theme.of(context).colorScheme.error, fontSize: 13, ), ), ); } return DropdownButtonFormField( value: _selectedSchoolClassId, isExpanded: true, decoration: InputDecoration( labelText: 'Ano letivo', labelStyle: TextStyle(color: Theme.of(context).colorScheme.onSurface), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of(context).colorScheme.outline.withOpacity(0.3), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide(color: Theme.of(context).colorScheme.primary), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide(color: Theme.of(context).colorScheme.error), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide(color: Theme.of(context).colorScheme.error), ), filled: true, fillColor: Theme.of(context).brightness == Brightness.dark ? Theme.of(context).colorScheme.surfaceContainerHighest : Theme.of(context).colorScheme.surface, ), style: TextStyle(color: Theme.of(context).colorScheme.onSurface), dropdownColor: Theme.of(context).colorScheme.surface, hint: Text( 'Escolha o seu ano letivo', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), ), items: _availableClasses .map( (c) => DropdownMenuItem( value: c['id'], child: Text(c['name']!), ), ) .toList(), onChanged: (value) => setState(() => _selectedSchoolClassId = value), validator: (value) { if (value == null || value.isEmpty) { return 'Seleciona o teu ano letivo'; } return null; }, ); } Future _handleSignup() async { if (!_formKey.currentState!.validate()) return; setState(() { _isLoading = true; }); try { // Get name, email and password from controllers final name = _nameController.text.trim(); final email = _emailController.text.trim(); final password = _passwordController.text.trim(); print('DEBUG: Iniciando processo de signup para: $email'); print('DEBUG: Nome: $name, Papel: $_selectedRole'); // Attempt signup with Firebase await AuthService.signUpWithEmailAndPassword( email: email, password: password, displayName: name, role: _selectedRole, schoolClassId: _selectedRole == 'student' ? _selectedSchoolClassId : null, ); print('DEBUG: Signup Firebase bem-sucedido, navegando para dashboard'); if (mounted) { setState(() { _isLoading = false; }); // Show success message NotificationHelper.showSuccess( context, message: 'Conta criada com sucesso!', ); // Navigate to appropriate dashboard based on role if (_selectedRole == 'teacher') { context.go('/teacher-dashboard'); } else { context.go('/student-dashboard'); } } } catch (e) { print('DEBUG: Erro no signup: $e'); if (mounted) { setState(() { _isLoading = false; }); // Show error message NotificationHelper.showError( context, message: e.toString().replaceAll('Exception: ', ''), ); } } } @override Widget build(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (!didPop) { context.go('/role-selection'); } }, child: Scaffold( body: Stack( children: [ // Main content Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: Theme.of(context).brightness == Brightness.dark ? AppThemeExtras.of(context).authBackgroundGradient : [ Theme.of(context).colorScheme.background, Theme.of( context, ).colorScheme.primary.withOpacity(0.1), Theme.of( context, ).colorScheme.secondary.withOpacity(0.05), Theme.of(context).colorScheme.background, ], ), ), child: SafeArea( top: false, child: Center( child: SingleChildScrollView( padding: const EdgeInsets.only( left: 24.0, right: 24.0, bottom: 28.0, top: 52.0, ), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 60), // Logo/Title Container( width: double.infinity, height: 84, decoration: const BoxDecoration( color: Color(0xFFF9EEE8), borderRadius: BorderRadius.all( Radius.circular(20), ), ), child: Center( child: SizedBox( width: 140, height: 140, child: ClipRRect( borderRadius: BorderRadius.circular(16), child: Image.asset( 'assets/images/logo.png', fit: BoxFit.cover, ), ), ), ), ).animate().fadeIn( duration: const Duration(milliseconds: 800), ), const SizedBox(height: 40), // Signup form Container( padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( color: Theme.of( context, ).colorScheme.surface.withOpacity(0.9), borderRadius: BorderRadius.circular(16.0), boxShadow: [ BoxShadow( color: Theme.of( context, ).colorScheme.shadow.withOpacity(0.1), blurRadius: 10.0, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Criar Conta', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Theme.of( context, ).colorScheme.onSurface, ), ), const SizedBox(height: 24), // Name field TextFormField( controller: _nameController, keyboardType: TextInputType.name, style: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), decoration: InputDecoration( labelText: 'Primeiro Nome', labelStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), hintStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, ), prefixIcon: Icon( Icons.person, color: Theme.of( context, ).colorScheme.primary, ), border: InputBorder.none, enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.outline.withOpacity(0.3), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.primary, ), ), filled: true, fillColor: Theme.of(context).brightness == Brightness.dark ? Theme.of( context, ).colorScheme.surfaceContainerHighest : Theme.of(context).colorScheme.surface, ), validator: (value) { if (value == null || value.isEmpty) { return 'Nome é obrigatório'; } if (value.length < 2) { return 'Nome muito curto'; } return null; }, ), const SizedBox(height: 16), // Seletor de ano letivo (apenas para alunos) if (_selectedRole == 'student') ...[ _buildClassSelector(context), const SizedBox(height: 16), ], // Email field TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, style: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), decoration: InputDecoration( labelText: 'Email', labelStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), hintStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, ), prefixIcon: Icon( Icons.email, color: Theme.of( context, ).colorScheme.primary, ), border: InputBorder.none, enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.outline.withOpacity(0.3), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.primary, ), ), filled: true, fillColor: Theme.of(context).brightness == Brightness.dark ? Theme.of( context, ).colorScheme.surfaceContainerHighest : Theme.of(context).colorScheme.surface, ), validator: (value) { if (value == null || value.isEmpty) { return 'Email é obrigatório'; } if (!value.contains('@')) { return 'Email inválido'; } return null; }, ), const SizedBox(height: 16), // Password field TextFormField( controller: _passwordController, obscureText: _obscurePassword, style: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), decoration: InputDecoration( labelText: 'Palavra-passe', labelStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurface, ), hintStyle: TextStyle( color: Theme.of( context, ).colorScheme.onSurfaceVariant, ), prefixIcon: Icon( Icons.lock, color: Theme.of( context, ).colorScheme.primary, ), suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, color: Theme.of( context, ).colorScheme.primary, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), border: InputBorder.none, enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.outline.withOpacity(0.3), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), borderSide: BorderSide( color: Theme.of( context, ).colorScheme.primary, ), ), filled: true, fillColor: Theme.of(context).brightness == Brightness.dark ? Theme.of( context, ).colorScheme.surfaceContainerHighest : Theme.of(context).colorScheme.surface, ), validator: (value) { if (value == null || value.isEmpty) { return 'Palavra-passe é obrigatória'; } if (value.length < 6) { return 'Palavra-passe muito curta'; } return null; }, ), const SizedBox(height: 24), // Signup button SizedBox( height: 50, child: ElevatedButton( onPressed: _isLoading ? null : _handleSignup, style: ElevatedButton.styleFrom( backgroundColor: Theme.of( context, ).colorScheme.primary, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 8.0, ), ), elevation: 2, ), child: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( Colors.white, ), ), ) : Text( 'Criar Conta', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(height: 16), // Login link GestureDetector( onTap: () { context.go('/login?role=$_selectedRole'); }, child: Text( 'Já tem conta? Entrar aqui', style: TextStyle( color: Theme.of( context, ).colorScheme.primary, fontWeight: FontWeight.w500, ), ), ), ], ), ).animate().fadeIn( duration: const Duration(milliseconds: 1000), ), const SizedBox(height: 40), ], ), ), ), ), ), ), // Custom back button Positioned( top: 50, left: 16, child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface.withOpacity(0.8), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Theme.of( context, ).colorScheme.shadow.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: IconButton( icon: Icon( Icons.arrow_back, color: Theme.of(context).colorScheme.onSurface, ), onPressed: () => context.go('/role-selection'), ), ), ), ], ), ), ); } }