petitspas/frontend/lib/models/am_registration_data.dart
Julien Martin 671da71752 feat(#112): reprise après refus via lien e-mail (/reprise?token=)
Branche le flux front : chargement du dossier, session reprise, wizards
parent/AM préremplis et resoumission via reprise-resoumettre.

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

206 lines
7.2 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/foundation.dart';
/// Accueil simultané : plafond légal courant en France pour une AM agréée (enfants de moins de 3 ans).
const int kAmCapaciteAccueilMax = 4;
class AmRegistrationData extends ChangeNotifier {
// Step 1: Identity Info
String firstName = '';
String lastName = '';
String streetAddress = ''; // Nouveau pour N° et Rue
String postalCode = ''; // Nouveau
String city = ''; // Nouveau
String phone = '';
String email = '';
String password = '';
// String? photoPath; // Déplacé ou géré à l'étape 2
// bool photoConsent = false; // Déplacé ou géré à l'étape 2
// Step 2: Professional Info
String? photoPath; // Chemin fichier local (hors web) si pas doctets en mémoire
Uint8List? photoBytes; // Galerie / web (ImagePicker)
String? photoFilename; // Nom pour lAPI (ex. image.jpg)
bool photoConsent = false; // Ajouté pour l'étape 2
DateTime? dateOfBirth;
String birthCity = ''; // Nouveau
String birthCountry = ''; // Nouveau
// String placeOfBirth = ''; // Remplacé par birthCity et birthCountry
String nir = ''; // Numéro de Sécurité Sociale
String agrementNumber = ''; // Numéro d'agrément
/// Date d'obtention de l'agrément — obligatoire (API `date_agrement`).
DateTime? agreementDate;
int? capacity; // Number of children the AM can look after
/// Places libres actuellement (0 ≤ valeur ≤ capacité) — API `places_disponibles`.
int? placesAvailable;
/// Photo déjà en base lors d'une reprise (#112) — sert pour l'affichage et `photo_url` API.
String? repriseExistingPhotoUrl;
// Step 3: Presentation & CGU
String presentationText = '';
bool cguAccepted = false;
// --- Methods to update data and notify listeners ---
void updateIdentityInfo({
String? firstName,
String? lastName,
String? streetAddress, // Modifié
String? postalCode, // Nouveau
String? city, // Nouveau
String? phone,
String? email,
String? password,
}) {
this.firstName = firstName ?? this.firstName;
this.lastName = lastName ?? this.lastName;
this.streetAddress = streetAddress ?? this.streetAddress; // Modifié
this.postalCode = postalCode ?? this.postalCode; // Nouveau
this.city = city ?? this.city; // Nouveau
this.phone = phone ?? this.phone;
this.email = email ?? this.email;
this.password = password ?? this.password;
// if (photoPath != null || this.photoPath != null) { // Supprimé de l'étape 1
// this.photoPath = photoPath;
// }
// this.photoConsent = photoConsent ?? this.photoConsent; // Supprimé de l'étape 1
notifyListeners();
}
void updateProfessionalInfo({
String? photoPath,
Uint8List? photoBytes,
String? photoFilename,
bool? photoConsent,
DateTime? dateOfBirth,
String? birthCity, // Nouveau
String? birthCountry, // Nouveau
// String? placeOfBirth, // Remplacé
String? nir,
String? agrementNumber,
DateTime? agreementDate,
int? capacity,
int? placesAvailable,
}) {
this.photoPath = photoPath;
this.photoBytes = photoBytes;
this.photoFilename = photoFilename;
this.photoConsent = photoConsent ?? this.photoConsent;
this.dateOfBirth = dateOfBirth ?? this.dateOfBirth;
this.birthCity = birthCity ?? this.birthCity; // Nouveau
this.birthCountry = birthCountry ?? this.birthCountry; // Nouveau
// this.placeOfBirth = placeOfBirth ?? this.placeOfBirth; // Remplacé
this.nir = nir ?? this.nir;
this.agrementNumber = agrementNumber ?? this.agrementNumber;
this.agreementDate = agreementDate ?? this.agreementDate;
this.capacity = capacity ?? this.capacity;
this.placesAvailable = placesAvailable ?? this.placesAvailable;
notifyListeners();
}
void updatePresentationAndCgu({
String? presentationText,
bool? cguAccepted,
}) {
this.presentationText = presentationText ?? this.presentationText;
this.cguAccepted = cguAccepted ?? this.cguAccepted;
notifyListeners();
}
/// Reprise après refus (#112).
void resetForReprise({
required String firstName,
required String lastName,
required String phone,
required String email,
required String streetAddress,
required String postalCode,
required String city,
String? existingPhotoUrl,
}) {
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
this.email = email;
this.streetAddress = streetAddress;
this.postalCode = postalCode;
this.city = city;
password = '';
repriseExistingPhotoUrl = existingPhotoUrl;
photoPath = existingPhotoUrl;
photoBytes = null;
photoFilename = null;
photoConsent = false;
dateOfBirth = null;
birthCity = '';
birthCountry = '';
nir = '';
agrementNumber = '';
agreementDate = null;
capacity = null;
placesAvailable = null;
presentationText = '';
cguAccepted = false;
notifyListeners();
}
// --- Getters for validation or display ---
bool get isStep1Complete =>
firstName.trim().length >= 2 &&
lastName.trim().length >= 2 &&
streetAddress.isNotEmpty &&
postalCode.isNotEmpty &&
city.isNotEmpty &&
phone.isNotEmpty &&
email.isNotEmpty;
// password n'est pas requis à l'inscription (défini après validation par lien email)
/// Photo réelle (pas seulement un placeholder asset).
bool get _hasUserPhoto =>
(photoBytes != null && photoBytes!.isNotEmpty) ||
(repriseExistingPhotoUrl != null &&
repriseExistingPhotoUrl!.trim().isNotEmpty) ||
(photoPath != null &&
photoPath!.isNotEmpty &&
!photoPath!.startsWith('assets/'));
bool get isStep2Complete =>
_hasUserPhoto &&
photoConsent == true &&
dateOfBirth != null &&
birthCity.trim().length >= 2 &&
birthCountry.trim().length >= 2 &&
nir.isNotEmpty &&
agrementNumber.isNotEmpty &&
agreementDate != null &&
capacity != null &&
capacity! >= 1 &&
capacity! <= kAmCapaciteAccueilMax &&
placesAvailable != null &&
placesAvailable! >= 0 &&
placesAvailable! <= capacity!;
bool get isStep3Complete =>
// presentationText is optional as per CDC (message au gestionnaire)
cguAccepted;
bool get isRegistrationComplete =>
isStep1Complete && isStep2Complete && isStep3Complete;
/// Reprise (#112) : champs renvoyés par PATCH reprise-resoumettre.
bool get isRepriseSubmitReady => isStep1Complete && cguAccepted;
@override
String toString() {
return 'AmRegistrationData('
'firstName: $firstName, lastName: $lastName, '
'streetAddress: $streetAddress, postalCode: $postalCode, city: $city, '
'phone: $phone, email: $email, '
// 'photoPath: $photoPath, photoConsent: $photoConsent, ' // Commenté car déplacé/modifié
'dateOfBirth: $dateOfBirth, birthCity: $birthCity, birthCountry: $birthCountry, '
'nir: $nir, agrementNumber: $agrementNumber, agreementDate: $agreementDate, capacity: $capacity, placesAvailable: $placesAvailable, '
'photoPath (step2): $photoPath, photoConsent (step2): $photoConsent, '
'presentationText: $presentationText, cguAccepted: $cguAccepted)';
}
}