Files
hidalyx-drluiscastro/lib/features/auth/presentation/widgets/login_form_widget.dart
T
2026-09-21 16:33:51 -04:00

185 lines
6.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import '../../../../core/theme/app_colors.dart';
import '../store/auth_store.dart';
class LoginFormWidget extends StatefulWidget {
final AuthStore store;
final VoidCallback onLoginSuccess;
const LoginFormWidget({
super.key,
required this.store,
required this.onLoginSuccess,
});
@override
State<LoginFormWidget> createState() => _LoginFormWidgetState();
}
class _LoginFormWidgetState extends State<LoginFormWidget> {
final _formKey = GlobalKey<FormBuilderState>();
Future<void> _submit() async {
if (_formKey.currentState?.saveAndValidate() ?? false) {
final values = _formKey.currentState!.value;
final email = values['email'] as String;
final password = values['password'] as String;
final success = await widget.store.login(
email: email,
password: password,
);
if (success && mounted) {
widget.onLoginSuccess();
}
}
}
@override
Widget build(BuildContext context) {
return Observer(
builder: (_) {
return FormBuilder(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Mensaje de Error si existe
if (widget.store.errorMessage != null) ...[
Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
color: AppColors.error.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: AppColors.error.withValues(alpha: 0.3)),
),
child: Row(
children: [
const Icon(Icons.error_outline_rounded, color: AppColors.error, size: 20),
const SizedBox(width: 10),
Expanded(
child: Text(
widget.store.errorMessage!,
style: const TextStyle(
color: AppColors.error,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
const SizedBox(height: 16),
],
// Campo Email
const Text(
'Correo Electrónico',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
),
const SizedBox(height: 6),
FormBuilderTextField(
name: 'email',
initialValue: '[email protected]',
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
decoration: const InputDecoration(
hintText: '[email protected]',
prefixIcon: Icon(Icons.mail_outline_rounded, color: AppColors.textMuted, size: 20),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(errorText: 'El correo electrónico es requerido'),
FormBuilderValidators.email(errorText: 'Ingrese un correo electrónico válido'),
]),
),
const SizedBox(height: 16),
// Campo Contraseña
const Text(
'Contraseña',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
),
const SizedBox(height: 6),
FormBuilderTextField(
name: 'password',
initialValue: 'LUIS',
obscureText: !widget.store.isPasswordVisible,
textInputAction: TextInputAction.done,
onSubmitted: (_) => _submit(),
decoration: InputDecoration(
hintText: 'Ingrese su contraseña',
prefixIcon: const Icon(Icons.lock_outline_rounded, color: AppColors.textMuted, size: 20),
suffixIcon: IconButton(
icon: Icon(
widget.store.isPasswordVisible
? Icons.visibility_off_outlined
: Icons.visibility_outlined,
color: AppColors.textMuted,
size: 20,
),
onPressed: widget.store.togglePasswordVisibility,
),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(errorText: 'La contraseña es requerida'),
]),
),
const SizedBox(height: 24),
// Botón de Inicio de Sesión
ElevatedButton(
onPressed: widget.store.isLoading ? null : _submit,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
),
child: widget.store.isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.login_rounded, size: 18),
SizedBox(width: 8),
Text(
'Ingresar al Consultorio',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
],
),
),
],
),
);
},
);
}
}