feat(inscription): email accusé réception, photos enfants, formulaires identité

- Backend: mail après inscription parent avec n° dossier, UPLOAD_PHOTOS_DIR, réponse API
- Frontend: imageBytes + payload photo, utils email/code postal/téléphone, champs dédiés
- Formulaires admin, login (focus), personal_info, child_card, custom_app_text_field

Made-with: Cursor
This commit is contained in:
2026-03-31 00:04:38 +02:00
parent 110240b682
commit bf05b1d7d7
20 changed files with 1148 additions and 273 deletions
@@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'dart:math' as math; // Pour la rotation du chevron
import 'package:image_picker/image_picker.dart';
import 'dart:io' show File;
import 'package:flutter/foundation.dart' show kIsWeb;
import '../../widgets/hover_relief_widget.dart';
import '../../widgets/child_card_widget.dart';
import '../../widgets/custom_navigation_button.dart';
@@ -152,10 +153,19 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
if (pickedFile != null) {
if (childIndex < registrationData.children.length) {
final oldChild = registrationData.children[childIndex];
final updatedChild = oldChild.copyWith(imageFile: File(pickedFile.path));
final bytes = await pickedFile.readAsBytes();
if (bytes.isEmpty) return;
File? file;
if (!kIsWeb) {
try {
final f = File(pickedFile.path);
if (await f.exists()) file = f;
} catch (_) {}
}
final updatedChild = oldChild.copyWith(imageBytes: bytes, imageFile: file);
registrationData.updateChild(childIndex, updatedChild);
}
}
}
} catch (e) { print("Erreur image: $e"); }
}
@@ -285,13 +295,14 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
// Générer les cartes enfants
for (int index = 0; index < registrationData.children.length; index++) ...[
ChildCardWidget(
key: ValueKey(registrationData.children[index].hashCode),
key: ValueKey('parent_register_child_$index'),
childData: registrationData.children[index],
childIndex: index,
onPickImage: () => _pickImage(index, registrationData),
onClearImage: () => setState(() {
final c = registrationData.children[index];
registrationData.updateChild(index, c.copyWith(imageFile: null));
registrationData.updateChild(
index, c.copyWith(imageFile: null, imageBytes: null));
}),
onDateSelect: () => _selectDate(context, index, registrationData),
onFirstNameChanged: (value) => setState(() {
@@ -392,13 +403,14 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
return Padding(
padding: const EdgeInsets.only(right: 20.0),
child: ChildCardWidget(
key: ValueKey(registrationData.children[index].hashCode), // Utiliser une clé basée sur les données
key: ValueKey('parent_register_child_$index'),
childData: registrationData.children[index],
childIndex: index,
onPickImage: () => _pickImage(index, registrationData),
onClearImage: () => setState(() {
final c = registrationData.children[index];
registrationData.updateChild(index, c.copyWith(imageFile: null));
registrationData.updateChild(
index, c.copyWith(imageFile: null, imageBytes: null));
}),
onDateSelect: () => _selectDate(context, index, registrationData),
onFirstNameChanged: (value) => setState(() {