login_screen.dart 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import '../../models/models.dart';
  4. import '../../themes/themes.dart';
  5. import '../../viewmodels/viewmodels.dart';
  6. import '../../widgets/widgets.dart';
  7. import '../home/home_screen.dart';
  8. class LoginScreen extends StatefulWidget {
  9. const LoginScreen({Key? key}) : super(key: key);
  10. @override
  11. State<LoginScreen> createState() => _LoginScreenState();
  12. }
  13. class _LoginScreenState extends State<LoginScreen> {
  14. final _correo = TextEditingController();
  15. final _contrasena = TextEditingController();
  16. Sucursal? _selectedSucursal;
  17. @override
  18. void dispose() {
  19. super.dispose();
  20. _correo.dispose();
  21. _contrasena.dispose();
  22. }
  23. @override
  24. void initState() {
  25. super.initState();
  26. // Verifica la sesión almacenada
  27. WidgetsBinding.instance.addPostFrameCallback((_) {
  28. final loginViewModel =
  29. Provider.of<LoginViewModel>(context, listen: false);
  30. Provider.of<PermisoViewModel>(context, listen: false)
  31. .sincronizarPermisos();
  32. Provider.of<UsuarioViewModel>(context, listen: false)
  33. .sincronizarUsuarios();
  34. // Verificar la sesión
  35. loginViewModel.checkSession().then((_) {
  36. if (loginViewModel.status == Status.authenticated) {
  37. print("Sesión activa detectada, redirigiendo al HomeScreen.");
  38. Navigator.pushReplacement(
  39. context,
  40. MaterialPageRoute(builder: (context) => const HomeScreen()),
  41. );
  42. } else {
  43. print("No se detectó sesión, mostrando la pantalla de login.");
  44. final sucursalViewModel =
  45. Provider.of<SucursalViewModel>(context, listen: false);
  46. sucursalViewModel.sincronizarSucursales().then((_) {
  47. setState(() {
  48. final sucursales = sucursalViewModel.sucursales;
  49. _selectedSucursal = sucursales.firstWhere(
  50. (sucursal) => sucursal.seleccionado == 1,
  51. orElse: () =>
  52. sucursales.isNotEmpty ? sucursales[0] : Sucursal(),
  53. );
  54. });
  55. });
  56. }
  57. });
  58. });
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. final loginViewModel = Provider.of<LoginViewModel>(context);
  63. // Mostrar la pantalla de carga `Cargando` mientras verifica la sesión
  64. if (loginViewModel.isLoading) {
  65. return const Cargando();
  66. }
  67. final size = MediaQuery.sizeOf(context);
  68. final sucursalViewModel = Provider.of<SucursalViewModel>(context);
  69. final sucursales = sucursalViewModel.sucursales;
  70. final errores = loginViewModel.errores;
  71. return Scaffold(
  72. backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
  73. body: SingleChildScrollView(
  74. child: Padding(
  75. padding: const EdgeInsets.all(8.0),
  76. child: Column(
  77. mainAxisAlignment: MainAxisAlignment.center,
  78. children: [
  79. SizedBox(height: size.width < 1200 ? 20 : 100),
  80. const Image(
  81. image: AssetImage('assets/JoshiLogoHorizontal.png'),
  82. height: 250,
  83. ),
  84. const Text(
  85. 'Inicie sesión para acceder al sistema',
  86. style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
  87. textAlign: TextAlign.center,
  88. ),
  89. const SizedBox(height: 20),
  90. // Campo de correo
  91. SizedBox(
  92. width: size.width < 1200 ? size.width : size.width * .35,
  93. child: Card(
  94. elevation: 5,
  95. shape: RoundedRectangleBorder(
  96. borderRadius: BorderRadius.circular(15)),
  97. child: Padding(
  98. padding: const EdgeInsets.all(15),
  99. child: Column(
  100. children: [
  101. AppDropdownModel<Sucursal>(
  102. etiqueta: 'Seleccione una sucursal',
  103. hint: 'Elija una sucursal',
  104. selectedValue: _selectedSucursal,
  105. onChanged: (Sucursal? newValue) {
  106. setState(() {
  107. _selectedSucursal = newValue;
  108. });
  109. },
  110. items: sucursales.map((Sucursal sucursal) {
  111. return DropdownMenuItem<Sucursal>(
  112. value: sucursal,
  113. child: Text(
  114. sucursal.nombre ?? '',
  115. style: const TextStyle(color: Colors.black),
  116. ),
  117. );
  118. }).toList(),
  119. ),
  120. const SizedBox(height: 5),
  121. AppTextField(
  122. autofillHints: [AutofillHints.username],
  123. prefixIcon: const Icon(Icons.mail),
  124. etiqueta: 'Correo electrónico',
  125. hintText: 'Introduzca su correo electrónico',
  126. errorText: errores?['correo'],
  127. controller: _correo,
  128. keyboardType: TextInputType.emailAddress,
  129. ),
  130. const SizedBox(height: 5),
  131. AppTextField(
  132. prefixIcon: const Icon(Icons.lock),
  133. etiqueta: 'Contraseña',
  134. hintText: 'Introduzca su contraseña',
  135. errorText: errores?['contrasena'],
  136. controller: _contrasena,
  137. obscureText: true,
  138. ),
  139. ],
  140. ),
  141. ),
  142. ),
  143. ),
  144. const SizedBox(height: 20),
  145. // Botón de login
  146. Align(
  147. alignment: Alignment.center,
  148. child: SizedBox(
  149. height: 75,
  150. width: 380,
  151. child: ElevatedButton(
  152. style: ButtonStyle(
  153. shape: MaterialStatePropertyAll(
  154. RoundedRectangleBorder(
  155. borderRadius: BorderRadius.circular(10),
  156. ),
  157. ),
  158. backgroundColor:
  159. MaterialStatePropertyAll(AppTheme.secondary),
  160. ),
  161. onPressed: () async {
  162. await loginViewModel.login(
  163. _correo.text, _contrasena.text);
  164. if (loginViewModel.status == Status.authenticated) {
  165. if (_selectedSucursal != null) {
  166. await sucursalViewModel
  167. .setSelectedSucursal(_selectedSucursal!);
  168. }
  169. Navigator.pushReplacement(
  170. context,
  171. MaterialPageRoute(
  172. builder: (context) => const HomeScreen()),
  173. );
  174. } else {
  175. String mensaje = "";
  176. if (loginViewModel.errores?["correo"] != null) {
  177. mensaje += "\n${loginViewModel.errores!["correo"]}";
  178. }
  179. if (mensaje.isNotEmpty && context.mounted) {
  180. return showDialog(
  181. context: context,
  182. builder: (context) {
  183. return AlertDialog(
  184. title: const Text("Alerta"),
  185. content: Text(mensaje),
  186. actions: [
  187. Row(children: [
  188. Expanded(
  189. child: TextButton(
  190. onPressed: () async {
  191. Navigator.pop(context);
  192. },
  193. child: const Text('Continuar'),
  194. ))
  195. ])
  196. ],
  197. );
  198. },
  199. );
  200. }
  201. }
  202. },
  203. child: const Row(
  204. mainAxisAlignment: MainAxisAlignment.center,
  205. children: [
  206. Text(
  207. 'Iniciar Sesión',
  208. style: TextStyle(fontSize: 18, color: Colors.white),
  209. ),
  210. ],
  211. ),
  212. ),
  213. ),
  214. ),
  215. const SizedBox(height: 20),
  216. ],
  217. ),
  218. ),
  219. ),
  220. );
  221. }
  222. }