[#101] [Frontend] Inscription parent — API, soumission et validation
Squash merge de develop vers master. Livrables principaux (ticket #101 et mise au point associée) : - Branchement du formulaire d'inscription parent sur POST /api/v1/auth/register/parent - Payload DTO (parents, enfants, photos base64, CGU) et services Auth - Parcours gestionnaire : cartes dossiers, wizard validation famille, images authentifiées - Scripts d'inscription test (Martin, Durand/Rousseau, Lecomte) ; .gitignore .cursor/ Inclut également les ajustements develop fusionnés dans ce lot (inscription AM, champs relais, etc.). Closes #101 Made-with: Cursor
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:p_tits_pas/models/user.dart';
|
||||
|
||||
/// Réponse unifiée GET /dossiers/:numeroDossier. Ticket #119, #107.
|
||||
@@ -107,7 +108,12 @@ class DossierFamille {
|
||||
numeroDossier: json['numero_dossier']?.toString(),
|
||||
parents: parentsList,
|
||||
enfants: enfantsList,
|
||||
presentation: (json['texte_motivation'] ?? json['presentation'])?.toString(),
|
||||
presentation: (json['texte_motivation'] ??
|
||||
json['presentation'] ??
|
||||
json['presentation_dossier'] ??
|
||||
json['texteMotivation'] ??
|
||||
json['presentationDossier'])
|
||||
?.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -151,7 +157,7 @@ class ParentDossier {
|
||||
|
||||
factory ParentDossier.fromJson(Map<String, dynamic> json) {
|
||||
return ParentDossier(
|
||||
id: json['id']?.toString() ?? '',
|
||||
id: json['user_id']?.toString() ?? json['id']?.toString() ?? '',
|
||||
email: json['email']?.toString() ?? '',
|
||||
prenom: json['prenom']?.toString(),
|
||||
nom: json['nom']?.toString(),
|
||||
@@ -194,7 +200,27 @@ class EnfantDossier {
|
||||
|
||||
String get fullName => '${firstName ?? ''} ${lastName ?? ''}'.trim();
|
||||
|
||||
static String? _optionalPhotoUrl(dynamic v) {
|
||||
if (v == null) return null;
|
||||
if (v is String) {
|
||||
final s = v.trim();
|
||||
return s.isEmpty ? null : s;
|
||||
}
|
||||
final s = v.toString().trim();
|
||||
return s.isEmpty ? null : s;
|
||||
}
|
||||
|
||||
factory EnfantDossier.fromJson(Map<String, dynamic> json) {
|
||||
final rawPhoto = json['photo_url'] ?? json['photoUrl'];
|
||||
final resolvedPhoto = _optionalPhotoUrl(rawPhoto);
|
||||
if (kDebugMode) {
|
||||
debugPrint(
|
||||
'[PetitsPas/dossier] EnfantDossier.fromJson id=${json['id']} '
|
||||
'prénom=${json['first_name'] ?? json['prenom']} | '
|
||||
'photo_url brute=$rawPhoto (${rawPhoto?.runtimeType}) → '
|
||||
'résolu=${resolvedPhoto ?? "∅"}',
|
||||
);
|
||||
}
|
||||
return EnfantDossier(
|
||||
id: json['id']?.toString() ?? '',
|
||||
firstName: (json['first_name'] ?? json['prenom'])?.toString(),
|
||||
@@ -203,8 +229,9 @@ class EnfantDossier {
|
||||
gender: (json['gender'] ?? json['genre'])?.toString(),
|
||||
status: json['status']?.toString(),
|
||||
dueDate: json['due_date']?.toString(),
|
||||
photoUrl: json['photo_url']?.toString(),
|
||||
consentPhoto: json['consent_photo'] == true,
|
||||
photoUrl: resolvedPhoto,
|
||||
consentPhoto:
|
||||
json['consent_photo'] == true || json['consentPhoto'] == true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:io'; // Pour File
|
||||
import '../models/card_assets.dart'; // Import de l'enum CardColorVertical
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
// import 'package:p_tits_pas/models/child.dart'; // Commenté car fichier non trouvé
|
||||
|
||||
class ParentData {
|
||||
@@ -29,25 +28,61 @@ class ParentData {
|
||||
}
|
||||
|
||||
class ChildData {
|
||||
static const Object _unsetImage = Object();
|
||||
static const Object _unsetImageBytes = Object();
|
||||
|
||||
String firstName;
|
||||
String lastName;
|
||||
String dob; // Date de naissance ou prévisionnelle
|
||||
/// Valeurs API : `H`, `F`, `Autre` (GenreType backend). Vide tant que non choisi.
|
||||
String genre;
|
||||
bool photoConsent;
|
||||
bool multipleBirth;
|
||||
bool isUnbornChild;
|
||||
File? imageFile;
|
||||
/// Octets de la photo (fiable à l’envoi API ; [imageFile] peut être absent sur le web).
|
||||
Uint8List? imageBytes;
|
||||
CardColorVertical cardColor; // Nouveau champ pour la couleur de la carte
|
||||
|
||||
ChildData({
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.dob = '',
|
||||
this.genre = '',
|
||||
this.photoConsent = false,
|
||||
this.multipleBirth = false,
|
||||
this.isUnbornChild = false,
|
||||
this.imageFile,
|
||||
this.imageBytes,
|
||||
required this.cardColor, // Rendre requis dans le constructeur
|
||||
});
|
||||
|
||||
ChildData copyWith({
|
||||
String? firstName,
|
||||
String? lastName,
|
||||
String? dob,
|
||||
String? genre,
|
||||
bool? photoConsent,
|
||||
bool? multipleBirth,
|
||||
bool? isUnbornChild,
|
||||
Object? imageFile = _unsetImage,
|
||||
Object? imageBytes = _unsetImageBytes,
|
||||
CardColorVertical? cardColor,
|
||||
}) {
|
||||
return ChildData(
|
||||
firstName: firstName ?? this.firstName,
|
||||
lastName: lastName ?? this.lastName,
|
||||
dob: dob ?? this.dob,
|
||||
genre: genre ?? this.genre,
|
||||
photoConsent: photoConsent ?? this.photoConsent,
|
||||
multipleBirth: multipleBirth ?? this.multipleBirth,
|
||||
isUnbornChild: isUnbornChild ?? this.isUnbornChild,
|
||||
imageFile: identical(imageFile, _unsetImage) ? this.imageFile : imageFile as File?,
|
||||
imageBytes:
|
||||
identical(imageBytes, _unsetImageBytes) ? this.imageBytes : imageBytes as Uint8List?,
|
||||
cardColor: cardColor ?? this.cardColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Nouvelle classe pour les détails bancaires
|
||||
|
||||
Reference in New Issue
Block a user