petitspas/frontend/lib/widgets/auth/reprise_identify_dialog.dart
Julien Martin b99745e0fe feat(#112): reprise après refus — dossier complet, email resoumission
- GET/PATCH reprise-dossier enrichis (parents, enfants, motivation, fiche AM)
- Front: lien mail, modale identify login, wizards préremplis, PATCH complet
- Email accusé resoumission aux parents avec n° de dossier
- Fixes préremplissage AM (dates, places, ValueKey étape 2)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 19:19:55 +02:00

169 lines
5.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../services/auth_service.dart';
import '../../utils/email_utils.dart';
import '../custom_app_text_field.dart';
/// Modale login : numéro de dossier + e-mail → token reprise (#112).
class RepriseIdentifyDialog extends StatefulWidget {
final String? initialEmail;
const RepriseIdentifyDialog({super.key, this.initialEmail});
@override
State<RepriseIdentifyDialog> createState() => _RepriseIdentifyDialogState();
}
class _RepriseIdentifyDialogState extends State<RepriseIdentifyDialog> {
final _formKey = GlobalKey<FormState>();
late final TextEditingController _numeroCtrl;
late final TextEditingController _emailCtrl;
bool _loading = false;
String? _error;
@override
void initState() {
super.initState();
_numeroCtrl = TextEditingController();
_emailCtrl = TextEditingController(text: widget.initialEmail ?? '');
}
@override
void dispose() {
_numeroCtrl.dispose();
_emailCtrl.dispose();
super.dispose();
}
String? _validateNumero(String? value) {
final v = value?.trim() ?? '';
if (v.isEmpty) {
return 'Indiquez votre numéro de dossier.';
}
return null;
}
String? _validateEmail(String? value) {
final v = value?.trim() ?? '';
if (v.isEmpty) {
return 'Indiquez votre adresse e-mail.';
}
if (!isValidEmailFormat(v)) {
return 'Ladresse e-mail nest pas valide.';
}
return null;
}
Future<void> _submit() async {
if (_loading) return;
setState(() => _error = null);
if (!(_formKey.currentState?.validate() ?? false)) return;
setState(() => _loading = true);
try {
final token = await AuthService.identifyReprise(
numeroDossier: _numeroCtrl.text,
email: _emailCtrl.text,
);
if (!mounted) return;
Navigator.of(context).pop(token);
} catch (e) {
if (!mounted) return;
setState(() {
_loading = false;
_error = e is Exception
? e.toString().replaceFirst('Exception: ', '')
: 'Impossible de retrouver votre dossier.';
});
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
'Reprendre mon dossier',
style: GoogleFonts.merienda(fontWeight: FontWeight.bold),
),
content: SizedBox(
width: 420,
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Saisissez le numéro de dossier et le-mail utilisés lors '
'de linscription (dossier refusé en attente de correction).',
style: GoogleFonts.merienda(fontSize: 13),
),
const SizedBox(height: 16),
CustomAppTextField(
controller: _numeroCtrl,
labelText: 'Numéro de dossier',
hintText: 'Ex. 2026-000021',
textInputAction: TextInputAction.next,
validator: _validateNumero,
style: CustomAppTextFieldStyle.lavande,
fieldHeight: 48,
fieldWidth: double.infinity,
),
const SizedBox(height: 12),
CustomAppTextField(
controller: _emailCtrl,
labelText: 'E-mail',
hintText: 'Votre adresse e-mail',
keyboardType: TextInputType.emailAddress,
autocorrect: false,
enableSuggestions: false,
inputFormatters: const [EmailMaxLengthFormatter()],
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) => _submit(),
validator: _validateEmail,
style: CustomAppTextFieldStyle.lavande,
fieldHeight: 48,
fieldWidth: double.infinity,
),
if (_error != null) ...[
const SizedBox(height: 12),
Text(
_error!,
style: GoogleFonts.merienda(
fontSize: 12,
color: Colors.red.shade700,
),
),
],
],
),
),
),
actions: [
TextButton(
onPressed: _loading ? null : () => Navigator.of(context).pop(),
child: Text('Annuler', style: GoogleFonts.merienda()),
),
TextButton(
onPressed: _loading ? null : _submit,
child: _loading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Text(
'Continuer',
style: GoogleFonts.merienda(
fontWeight: FontWeight.bold,
color: const Color(0xFF2D6A4F),
),
),
),
],
);
}
}