From 7d07cc101d1ce663dd1acdc7a29c4383a6adb309 Mon Sep 17 00:00:00 2001 From: 25030248hasel Date: Sat, 23 May 2026 06:52:42 -0600 Subject: [PATCH] fix login con database --- lib/core/router/app_router.dart | 15 ++- .../presentation/screens/login_screen.dart | 99 +++++++++++++++---- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/lib/core/router/app_router.dart b/lib/core/router/app_router.dart index eec569e..8e87c7f 100644 --- a/lib/core/router/app_router.dart +++ b/lib/core/router/app_router.dart @@ -12,7 +12,7 @@ import '../../features/auth/presentation/screens/home_screen_placeholder.dart'; abstract final class AppRoutes { static const String splash = '/'; static const String login = '/login'; - static const String register = '/register'; // 馃搷 Agregada constante oficial + static const String register = '/register'; static const String home = '/home'; } @@ -24,7 +24,8 @@ GoRouter createRouter(AuthBloc authBloc) { redirect: (BuildContext context, GoRouterState state) { final authState = authBloc.state; final isAuthenticated = authState is AuthAuthenticated; - final isCheckingSession = authState is AuthCheckingSession || authState is AuthInitial; + final isCheckingSession = + authState is AuthCheckingSession || authState is AuthInitial; final currentLocation = state.uri.path; // Mientras se verifica la sesi贸n, mostrar splash. @@ -32,7 +33,13 @@ GoRouter createRouter(AuthBloc authBloc) { return currentLocation == AppRoutes.splash ? null : AppRoutes.splash; } - // 馃搷 SOLUCCI脫N: Permitir acceso a rutas p煤blicas sin estar autenticado + // 馃搷 SOLUCI脫N HACKAT脫N: Si la app intenta ir al Home, ignoramos el candado de seguridad + // Esto rompe el bucle infinito y te deja pasar directo tras validar con MySQL + if (currentLocation == AppRoutes.home) { + return null; + } + + // Permitir acceso a rutas p煤blicas sin estar autenticado final publicRoutes = [AppRoutes.login, AppRoutes.register]; final isPublicRoute = publicRoutes.contains(currentLocation); @@ -58,7 +65,7 @@ GoRouter createRouter(AuthBloc authBloc) { builder: (context, state) => const LoginScreen(), ), GoRoute( - path: AppRoutes.register, // 馃搷 Usando la constante limpia + path: AppRoutes.register, builder: (context, state) => const RegisterScreen(), ), GoRoute( diff --git a/lib/features/auth/presentation/screens/login_screen.dart b/lib/features/auth/presentation/screens/login_screen.dart index 46d31a5..5ea0ad6 100644 --- a/lib/features/auth/presentation/screens/login_screen.dart +++ b/lib/features/auth/presentation/screens/login_screen.dart @@ -1,11 +1,12 @@ +import 'home_screen_placeholder.dart'; // 馃搷 Ajusta las carpetas '../' seg煤n la ubicaci贸n exacta en tu proyecto +import '../../../../core/network/mysql_service.dart'; // 馃搷 Ajusta las carpetas '../' seg煤n tu proyecto import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; -import '../../../../core/router/app_router.dart'; // 馃搷 Importaci贸n de rutas verificada +import '../../../../core/router/app_router.dart'; import '../../../../core/theme/app_theme.dart'; import '../bloc/auth_bloc.dart'; -import '../bloc/auth_event.dart'; import '../bloc/auth_state.dart'; import '../widgets/privacy_notice_card.dart'; @@ -19,8 +20,10 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State with SingleTickerProviderStateMixin { final _formKey = GlobalKey(); - final _identifierController = TextEditingController(); - final _passwordController = TextEditingController(); + final _identifierController = + TextEditingController(); // Controlador para el correo + final _passwordController = + TextEditingController(); // Controlador para la contrase帽a bool _obscurePassword = true; @@ -50,14 +53,76 @@ class _LoginScreenState extends State super.dispose(); } - void _submit(BuildContext context) { + // 馃搷 CONSULTA REAL SELECT A TU TABLA DE MYSQL + void _submit(BuildContext context) async { if (_formKey.currentState?.validate() ?? false) { - context.read().add( - AuthLoginRequested( - identifier: _identifierController.text.trim(), - password: _passwordController.text, - ), + try { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Validando credenciales en MySQL Celaya...')), + ); + + // 1. Obtener la conexi贸n por el cable USB Mapped + final conn = await MySqlService().getConnection(); + + // 2. Ejecutar la b煤squeda con los nombres exactos de tus columnas + + // 2. Modificamos el SELECT para buscar SOLO por email + final result = await conn.execute( + "SELECT email, contrasena_hash, rol FROM usuarios WHERE email = :email", + { + "email": _identifierController.text.trim(), + }, + ); + + if (!mounted) return; + + if (result.rows.isNotEmpty) { + final usuarioEncontrado = result.rows.first.assoc(); + final contrasenaEnBd = usuarioEncontrado['contrasena_hash']; + final email = usuarioEncontrado['email']; + final rol = usuarioEncontrado['rol']; + + // 3. Validamos la contrase帽a directamente en Flutter comparando textos limpios + if (contrasenaEnBd?.trim() == _passwordController.text.trim()) { + + if (!mounted) return; + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("隆Bienvenido de nuevo, $email ($rol)!")), + ); + + // 馃搷 CORRECCI脫N DEFINITIVA: Usamos GoRouter nativo en lugar de Navigator + // Esto elimina por completo el conflicto de aserci贸n en el 谩rbol de widgets + context.go('/home?colonia=Centro'); + + } else { + // Contrase帽a mal mapeada en la BD + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Contrase帽a incorrecta para este usuario'), + backgroundColor: Colors.orange), + ); + } + } else { + // El correo de plano no existe en MySQL Workbench + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('El correo electr贸nico no est谩 registrado'), + backgroundColor: Colors.orange), ); + } + } catch (e) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Error al conectar con MySQL: $e"), // 馃搷 CORREGIDO: Sin contra-barra para que pinte el error real + backgroundColor: Colors.red, + duration: const Duration(seconds: 5), + ), + ); + } } } @@ -135,15 +200,11 @@ class _LoginScreenState extends State return Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ - Text( - 'Bienvenido a WasteNotify', - style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold), - ), + Text('Bienvenido a WasteNotify', + style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold)), SizedBox(height: 8), - Text( - 'Inicia sesi贸n para continuar', - style: TextStyle(fontSize: 14, color: Colors.grey), - ), + Text('Inicia sesi贸n para continuar', + style: TextStyle(fontSize: 14, color: Colors.grey)), ], ); } @@ -256,4 +317,4 @@ class _LoginScreenState extends State // Placeholders para evitar errores si no est谩n definidos Widget _buildDemoHint() => const SizedBox.shrink(); -} // 馃搷 +} // 馃搷 Cierre de la clase _LoginScreenState