- Routes /forgot-password et /reset-password (distinct de /create-password). - AuthService : POST forgot-password (réponse neutre côté UX) et reset-password. - Login : lien « Mot de passe oublié ? » vers la demande de réinitialisation. Made-with: Cursor
159 lines
5.6 KiB
Dart
159 lines
5.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:google_fonts/google_fonts.dart';
|
||
|
||
import '../../services/auth_service.dart';
|
||
import '../../utils/email_utils.dart';
|
||
import '../../widgets/image_button.dart';
|
||
|
||
/// Demande de lien de réinitialisation (ticket #127).
|
||
class ForgotPasswordScreen extends StatefulWidget {
|
||
const ForgotPasswordScreen({super.key});
|
||
|
||
@override
|
||
State<ForgotPasswordScreen> createState() => _ForgotPasswordScreenState();
|
||
}
|
||
|
||
class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
final _emailCtrl = TextEditingController();
|
||
|
||
bool _submitting = false;
|
||
String? _fieldError;
|
||
|
||
@override
|
||
void dispose() {
|
||
_emailCtrl.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
String? _validateEmail(String? value) {
|
||
return validateEmail(value, allowEmpty: false);
|
||
}
|
||
|
||
Future<void> _submit() async {
|
||
if (_submitting) return;
|
||
setState(() => _fieldError = null);
|
||
if (!(_formKey.currentState?.validate() ?? false)) return;
|
||
|
||
setState(() => _submitting = true);
|
||
try {
|
||
await AuthService.requestForgotPassword(_emailCtrl.text);
|
||
if (!mounted) return;
|
||
setState(() => _submitting = false);
|
||
await showDialog<void>(
|
||
context: context,
|
||
builder: (ctx) => AlertDialog(
|
||
title: Text('Demande enregistrée', style: GoogleFonts.merienda(fontWeight: FontWeight.w700)),
|
||
content: Text(
|
||
'Si un compte correspond à cette adresse, vous recevrez un e-mail '
|
||
'avec un lien pour réinitialiser votre mot de passe.',
|
||
style: GoogleFonts.merienda(),
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.of(ctx).pop(),
|
||
child: Text('OK', style: GoogleFonts.merienda(color: const Color(0xFF2D6A4F))),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
if (mounted) context.go('/login');
|
||
} catch (e) {
|
||
if (!mounted) return;
|
||
setState(() {
|
||
_submitting = false;
|
||
_fieldError = e.toString().replaceAll('Exception: ', '');
|
||
});
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
body: Container(
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('assets/images/paper2.png'),
|
||
fit: BoxFit.cover,
|
||
repeat: ImageRepeat.repeat,
|
||
),
|
||
),
|
||
child: Center(
|
||
child: ConstrainedBox(
|
||
constraints: const BoxConstraints(maxWidth: 520),
|
||
child: Card(
|
||
color: const Color(0xF4FFFFFF),
|
||
margin: const EdgeInsets.all(24),
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(24),
|
||
child: Form(
|
||
key: _formKey,
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: [
|
||
Text(
|
||
'Mot de passe oublié',
|
||
style: GoogleFonts.merienda(fontSize: 28, fontWeight: FontWeight.w700),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
const SizedBox(height: 12),
|
||
Text(
|
||
'Indiquez l’adresse e-mail de votre compte. Nous vous enverrons un lien si elle est reconnue.',
|
||
style: GoogleFonts.merienda(fontSize: 14, color: Colors.black87),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
const SizedBox(height: 20),
|
||
TextFormField(
|
||
controller: _emailCtrl,
|
||
keyboardType: TextInputType.emailAddress,
|
||
autocorrect: false,
|
||
validator: _validateEmail,
|
||
decoration: const InputDecoration(
|
||
labelText: 'E-mail',
|
||
border: OutlineInputBorder(),
|
||
),
|
||
),
|
||
if (_fieldError != null) ...[
|
||
const SizedBox(height: 12),
|
||
Text(
|
||
_fieldError!,
|
||
style: GoogleFonts.merienda(color: Colors.red.shade700, fontSize: 13),
|
||
),
|
||
],
|
||
const SizedBox(height: 20),
|
||
_submitting
|
||
? const Center(child: CircularProgressIndicator())
|
||
: ImageButton(
|
||
bg: 'assets/images/bg_green.png',
|
||
width: double.infinity,
|
||
height: 44,
|
||
text: 'Envoyer le lien',
|
||
textColor: const Color(0xFF2D6A4F),
|
||
onPressed: _submit,
|
||
),
|
||
const SizedBox(height: 12),
|
||
TextButton(
|
||
onPressed: () => context.go('/login'),
|
||
child: Text(
|
||
'Retour à la connexion',
|
||
style: GoogleFonts.merienda(
|
||
color: const Color(0xFF2D6A4F),
|
||
decoration: TextDecoration.underline,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|