From b4b44cb1b9ed676fa1d8d2ea6c7cbeea0b28f214 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Mon, 13 Apr 2026 13:13:27 +0200 Subject: [PATCH] =?UTF-8?q?feat(inscription-am):=20places=20disponibles,?= =?UTF-8?q?=20UI=20=C3=A9tape=202,=20plafond=20capacit=C3=A9=204=20c=C3=B4?= =?UTF-8?q?t=C3=A9=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - POST /auth/register/am : places_disponibles, enregistrement place_disponible, contrôle ≤ capacité - Formulaire pro AM : places sur la ligne capacité, mobile un champ par ligne, carte desktop plus compacte (espacements, polices, labelFieldSpacing) - Capacité et places validées jusqu’à 4 dans l’app (kAmCapaciteAccueilMax) ; hint NIR « 13 chiffres + clé » - Scripts d’inscription AM (Node + smoke shell) : places_disponibles Made-with: Cursor --- backend/scripts/test-register-am.sh | 1 + backend/src/routes/auth/auth.service.ts | 6 + .../auth/dto/register-am-complet.dto.ts | 11 ++ frontend/lib/models/am_registration_data.dart | 14 +- .../auth/am_register_step2_screen.dart | 2 + .../auth/am_register_step4_screen.dart | 1 + frontend/lib/services/auth_service.dart | 4 + .../lib/widgets/custom_app_text_field.dart | 5 +- frontend/lib/widgets/nir_text_field.dart | 5 +- .../professional_info_form_screen.dart | 180 +++++++++++------- tests/scripts/register-am-dubois-test.mjs | 1 + tests/scripts/register-am-mansouri-test.mjs | 1 + 12 files changed, 163 insertions(+), 68 deletions(-) diff --git a/backend/scripts/test-register-am.sh b/backend/scripts/test-register-am.sh index 5a5b01b..db139a6 100755 --- a/backend/scripts/test-register-am.sh +++ b/backend/scripts/test-register-am.sh @@ -26,6 +26,7 @@ curl -s -w "\n\nHTTP %{http_code}\n" -X POST "$BASE_URL/auth/register/am" \ "nir": "186127500100279", "numero_agrement": "AGR-SMOKE-CURL-001", "capacite_accueil": 3, + "places_disponibles": 2, "acceptation_cgu": true, "acceptation_privacy": true }' diff --git a/backend/src/routes/auth/auth.service.ts b/backend/src/routes/auth/auth.service.ts index 0874aec..55a7b94 100644 --- a/backend/src/routes/auth/auth.service.ts +++ b/backend/src/routes/auth/auth.service.ts @@ -418,6 +418,12 @@ export class AuthService { ); } + if (dto.places_disponibles > dto.capacite_accueil) { + throw new BadRequestException( + 'Le nombre de places disponibles ne peut pas dépasser la capacité d\'accueil.', + ); + } + const nirNormalized = (dto.nir || '').replace(/\s/g, '').toUpperCase(); const nirValidation = validateNir(nirNormalized, { dateNaissance: dto.date_naissance, diff --git a/backend/src/routes/auth/dto/register-am-complet.dto.ts b/backend/src/routes/auth/dto/register-am-complet.dto.ts index 16d0c89..2749cc4 100644 --- a/backend/src/routes/auth/dto/register-am-complet.dto.ts +++ b/backend/src/routes/auth/dto/register-am-complet.dto.ts @@ -138,6 +138,17 @@ export class RegisterAMCompletDto { @Max(10, { message: 'La capacité ne peut pas dépasser 10' }) capacite_accueil: number; + @ApiProperty({ + example: 2, + description: 'Nombre de places libres actuellement (≤ capacité d\'accueil)', + minimum: 0, + maximum: 10, + }) + @IsInt() + @Min(0, { message: 'Les places disponibles ne peuvent pas être négatives' }) + @Max(10, { message: 'Les places disponibles ne peuvent pas dépasser 10' }) + places_disponibles: number; + // ============================================ // ÉTAPE 3 : PRÉSENTATION (Optionnel) // ============================================ diff --git a/frontend/lib/models/am_registration_data.dart b/frontend/lib/models/am_registration_data.dart index 54e2f0c..6bc88e6 100644 --- a/frontend/lib/models/am_registration_data.dart +++ b/frontend/lib/models/am_registration_data.dart @@ -1,5 +1,8 @@ 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 = ''; @@ -27,6 +30,8 @@ class AmRegistrationData extends ChangeNotifier { /// 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; // Step 3: Presentation & CGU String presentationText = ''; @@ -72,6 +77,7 @@ class AmRegistrationData extends ChangeNotifier { String? agrementNumber, DateTime? agreementDate, int? capacity, + int? placesAvailable, }) { this.photoPath = photoPath; this.photoBytes = photoBytes; @@ -85,6 +91,7 @@ class AmRegistrationData extends ChangeNotifier { this.agrementNumber = agrementNumber ?? this.agrementNumber; this.agreementDate = agreementDate ?? this.agreementDate; this.capacity = capacity ?? this.capacity; + this.placesAvailable = placesAvailable ?? this.placesAvailable; notifyListeners(); } @@ -125,7 +132,10 @@ class AmRegistrationData extends ChangeNotifier { agreementDate != null && capacity != null && capacity! >= 1 && - capacity! <= 10; + capacity! <= kAmCapaciteAccueilMax && + placesAvailable != null && + placesAvailable! >= 0 && + placesAvailable! <= capacity!; bool get isStep3Complete => // presentationText is optional as per CDC (message au gestionnaire) @@ -142,7 +152,7 @@ class AmRegistrationData extends ChangeNotifier { '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, ' + 'nir: $nir, agrementNumber: $agrementNumber, agreementDate: $agreementDate, capacity: $capacity, placesAvailable: $placesAvailable, ' 'photoPath (step2): $photoPath, photoConsent (step2): $photoConsent, ' 'presentationText: $presentationText, cguAccepted: $cguAccepted)'; } diff --git a/frontend/lib/screens/auth/am_register_step2_screen.dart b/frontend/lib/screens/auth/am_register_step2_screen.dart index 1eea9ff..2f98b0e 100644 --- a/frontend/lib/screens/auth/am_register_step2_screen.dart +++ b/frontend/lib/screens/auth/am_register_step2_screen.dart @@ -25,6 +25,7 @@ class AmRegisterStep2Screen extends StatelessWidget { agrementNumber: registrationData.agrementNumber, agreementDate: registrationData.agreementDate, capacity: registrationData.capacity, + placesAvailable: registrationData.placesAvailable, ); return ProfessionalInfoFormScreen( @@ -46,6 +47,7 @@ class AmRegisterStep2Screen extends StatelessWidget { agrementNumber: data.agrementNumber, agreementDate: data.agreementDate, capacity: data.capacity, + placesAvailable: data.placesAvailable, ); context.go('/am-register-step3'); }, diff --git a/frontend/lib/screens/auth/am_register_step4_screen.dart b/frontend/lib/screens/auth/am_register_step4_screen.dart index 6e2a350..b49cd8c 100644 --- a/frontend/lib/screens/auth/am_register_step4_screen.dart +++ b/frontend/lib/screens/auth/am_register_step4_screen.dart @@ -206,6 +206,7 @@ class _AmRegisterStep4ScreenState extends State { agrementNumber: data.agrementNumber, agreementDate: data.agreementDate, capacity: data.capacity, + placesAvailable: data.placesAvailable, photoConsent: data.photoConsent, ), onSubmit: (d) {}, diff --git a/frontend/lib/services/auth_service.dart b/frontend/lib/services/auth_service.dart index c2edf66..99d52aa 100644 --- a/frontend/lib/services/auth_service.dart +++ b/frontend/lib/services/auth_service.dart @@ -165,6 +165,9 @@ class AuthService { if (data.agreementDate == null) { throw Exception('La date d\'obtention de l\'agrément est requise.'); } + if (data.placesAvailable == null) { + throw Exception('Le nombre de places disponibles est requis.'); + } String? photoBase64; String? photoFilename; @@ -211,6 +214,7 @@ class AuthService { 'date_agrement': '${data.agreementDate!.year}-${data.agreementDate!.month.toString().padLeft(2, '0')}-${data.agreementDate!.day.toString().padLeft(2, '0')}', 'capacite_accueil': data.capacity ?? 1, + 'places_disponibles': data.placesAvailable!, 'biographie': data.presentationText.isNotEmpty ? data.presentationText : null, 'acceptation_cgu': data.cguAccepted, 'acceptation_privacy': data.cguAccepted, diff --git a/frontend/lib/widgets/custom_app_text_field.dart b/frontend/lib/widgets/custom_app_text_field.dart index dae6364..72d5b84 100644 --- a/frontend/lib/widgets/custom_app_text_field.dart +++ b/frontend/lib/widgets/custom_app_text_field.dart @@ -27,6 +27,8 @@ class CustomAppTextField extends StatefulWidget { final IconData? suffixIcon; final double labelFontSize; final double inputFontSize; + /// Espace vertical entre le libellé et la zone de saisie. + final double labelFieldSpacing; final bool showLabel; final Iterable? autofillHints; final TextInputAction? textInputAction; @@ -56,6 +58,7 @@ class CustomAppTextField extends StatefulWidget { this.suffixIcon, this.labelFontSize = 18.0, this.inputFontSize = 18.0, + this.labelFieldSpacing = 6.0, this.autofillHints, this.textInputAction, this.onFieldSubmitted, @@ -105,7 +108,7 @@ class _CustomAppTextFieldState extends State { fontWeight: FontWeight.w500, ), ), - const SizedBox(height: 6), + SizedBox(height: widget.labelFieldSpacing), ], // Pas de hauteur fixe sur le TextFormField : le message d’erreur du // validateur s’affiche en dessous ; un SizedBox fixe le masquait. diff --git a/frontend/lib/widgets/nir_text_field.dart b/frontend/lib/widgets/nir_text_field.dart index 90d9e29..0e0f951 100644 --- a/frontend/lib/widgets/nir_text_field.dart +++ b/frontend/lib/widgets/nir_text_field.dart @@ -18,12 +18,13 @@ class NirTextField extends StatelessWidget { final bool enabled; final bool readOnly; final CustomAppTextFieldStyle style; + final double labelFieldSpacing; const NirTextField({ super.key, required this.controller, this.labelText = 'N° Sécurité Sociale (NIR)', - this.hintText = '15 caractères dont clé valide (dépt 2A ou 2B si Corse)', + this.hintText = '13 chiffres + clé', this.validator, this.fieldWidth = double.infinity, this.fieldHeight = 53.0, @@ -32,6 +33,7 @@ class NirTextField extends StatelessWidget { this.enabled = true, this.readOnly = false, this.style = CustomAppTextFieldStyle.beige, + this.labelFieldSpacing = 6.0, }); @override @@ -50,6 +52,7 @@ class NirTextField extends StatelessWidget { enabled: enabled, readOnly: readOnly, style: style, + labelFieldSpacing: labelFieldSpacing, ); } } diff --git a/frontend/lib/widgets/professional_info_form_screen.dart b/frontend/lib/widgets/professional_info_form_screen.dart index 72ce73c..811f746 100644 --- a/frontend/lib/widgets/professional_info_form_screen.dart +++ b/frontend/lib/widgets/professional_info_form_screen.dart @@ -7,6 +7,7 @@ import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'dart:math' as math; import 'dart:io'; +import '../models/am_registration_data.dart' show kAmCapaciteAccueilMax; import '../models/card_assets.dart'; import '../config/display_config.dart'; import '../utils/nir_utils.dart'; @@ -34,6 +35,7 @@ class ProfessionalInfoData { /// Date d'obtention de l'agrément (obligatoire, API `date_agrement`). final DateTime? agreementDate; final int? capacity; + final int? placesAvailable; ProfessionalInfoData({ this.photoPath, @@ -48,6 +50,7 @@ class ProfessionalInfoData { this.agrementNumber = '', this.agreementDate, this.capacity, + this.placesAvailable, }); } @@ -94,6 +97,7 @@ class _ProfessionalInfoFormScreenState extends State final _agrementController = TextEditingController(); final _agreementDateController = TextEditingController(); final _capacityController = TextEditingController(); + final _placesAvailableController = TextEditingController(); FocusNode? _birthCityFocus; FocusNode? _birthCountryFocus; @@ -133,6 +137,7 @@ class _ProfessionalInfoFormScreenState extends State ? DateFormat('dd/MM/yyyy').format(data.agreementDate!) : ''; _capacityController.text = data.capacity?.toString() ?? ''; + _placesAvailableController.text = data.placesAvailable?.toString() ?? ''; _photoPathFramework = data.photoPath; _photoFile = data.photoFile; _photoBytes = data.photoBytes; @@ -180,9 +185,20 @@ class _ProfessionalInfoFormScreenState extends State _agrementController.dispose(); _agreementDateController.dispose(); _capacityController.dispose(); + _placesAvailableController.dispose(); super.dispose(); } + String? _validatePlacesAvailable(String? v) { + if (v == null || v.isEmpty) return 'Places disponibles requises'; + final n = int.tryParse(v); + if (n == null || n < 0) return 'Nombre entre 0 et la capacité'; + if (n > kAmCapaciteAccueilMax) return 'Maximum $kAmCapaciteAccueilMax'; + final cap = int.tryParse(_capacityController.text); + if (cap != null && n > cap) return 'Ne peut pas dépasser la capacité'; + return null; + } + Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, @@ -285,6 +301,7 @@ class _ProfessionalInfoFormScreenState extends State agrementNumber: _agrementController.text, agreementDate: _selectedAgreementDate, capacity: int.tryParse(_capacityController.text), + placesAvailable: int.tryParse(_placesAvailableController.text), ); widget.onSubmit(data); @@ -308,7 +325,7 @@ class _ProfessionalInfoFormScreenState extends State ), Center( child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(vertical: 40.0), + padding: EdgeInsets.symmetric(vertical: config.isMobile ? 40.0 : 28.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -329,7 +346,7 @@ class _ProfessionalInfoFormScreenState extends State ), textAlign: TextAlign.center, ), - SizedBox(height: config.isMobile ? 16 : 30), + SizedBox(height: config.isMobile ? 16 : 20), _buildCard(context, config, screenSize), // Boutons mobile sous la carte @@ -400,7 +417,7 @@ class _ProfessionalInfoFormScreenState extends State Container( width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6, padding: EdgeInsets.symmetric( - vertical: config.isMobile ? 20 : (config.isReadonly ? 30 : 50), + vertical: config.isMobile ? 20 : (config.isReadonly ? 24 : 28), horizontal: config.isMobile ? 24 : 50, ), decoration: BoxDecoration( @@ -428,7 +445,7 @@ class _ProfessionalInfoFormScreenState extends State ), textAlign: TextAlign.center, ), - const SizedBox(height: 20), + SizedBox(height: config.isMobile ? 20.0 : 14.0), ], config.isMobile ? _buildMobileFields(context, config) @@ -550,7 +567,7 @@ class _ProfessionalInfoFormScreenState extends State ), ], ), - const SizedBox(height: 18), + const SizedBox(height: 10), // Contenu Expanded( @@ -578,7 +595,7 @@ class _ProfessionalInfoFormScreenState extends State }, ), ), - const SizedBox(height: 10), + const SizedBox(height: 5), AppCustomCheckbox( label: 'J\'accepte l\'utilisation\nde ma photo.', value: _photoConsent, @@ -589,7 +606,7 @@ class _ProfessionalInfoFormScreenState extends State ], ), ), - const SizedBox(width: 32), + const SizedBox(width: 24), // CHAMPS (2/3) - Layout optimisé compact Expanded( @@ -605,7 +622,7 @@ class _ProfessionalInfoFormScreenState extends State Expanded(flex: 3, child: _buildReadonlyField('Ville de naissance', _birthCityController.text)), ], ), - const SizedBox(height: 12), + const SizedBox(height: 5), // Ligne 2 : Pays + NIR Row( @@ -615,7 +632,7 @@ class _ProfessionalInfoFormScreenState extends State Expanded(flex: 3, child: _buildReadonlyField('NIR', _formatNirForDisplay(_nirController.text))), ], ), - const SizedBox(height: 12), + const SizedBox(height: 5), // Ligne 3 : N° agrément + Date d'obtention Row( @@ -634,12 +651,19 @@ class _ProfessionalInfoFormScreenState extends State ), ], ), - const SizedBox(height: 12), + const SizedBox(height: 5), Row( children: [ Expanded( child: _buildReadonlyField('Capacité d\'accueil', _capacityController.text), ), + const SizedBox(width: 16), + Expanded( + child: _buildReadonlyField( + 'Places disponibles', + _placesAvailableController.text, + ), + ), ], ), ], @@ -668,10 +692,10 @@ class _ProfessionalInfoFormScreenState extends State children: [ Text( label, - style: GoogleFonts.merienda(fontSize: 18.0, fontWeight: FontWeight.w600), + style: GoogleFonts.merienda(fontSize: 16.0, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, ), - const SizedBox(height: 4), + const SizedBox(height: 3), Container( width: double.infinity, height: 45.0, // Hauteur réduite pour compacter @@ -685,7 +709,7 @@ class _ProfessionalInfoFormScreenState extends State ), child: Text( value.isNotEmpty ? value : '-', - style: GoogleFonts.merienda(fontSize: 16.0), + style: GoogleFonts.merienda(fontSize: 14.0), overflow: TextOverflow.ellipsis, ), ), @@ -695,7 +719,7 @@ class _ProfessionalInfoFormScreenState extends State /// Layout DESKTOP : Photo à gauche, champs à droite Widget _buildDesktopFields(BuildContext context, DisplayConfig config) { - final double verticalSpacing = config.isReadonly ? 16.0 : 32.0; + final double verticalSpacing = config.isReadonly ? 8.0 : 14.0; return Column( mainAxisSize: MainAxisSize.min, @@ -708,7 +732,7 @@ class _ProfessionalInfoFormScreenState extends State width: 300, child: _buildPhotoSection(context, config), ), - const SizedBox(width: 30), + const SizedBox(width: 22), // Champs à droite Expanded( child: Column( @@ -751,8 +775,9 @@ class _ProfessionalInfoFormScreenState extends State controller: _nirController, fieldWidth: double.infinity, fieldHeight: config.isMobile ? 45.0 : 53.0, - labelFontSize: config.isMobile ? 15.0 : 22.0, - inputFontSize: config.isMobile ? 14.0 : 20.0, + labelFontSize: config.isMobile ? 15.0 : 20.0, + inputFontSize: config.isMobile ? 14.0 : 18.0, + labelFieldSpacing: config.isMobile ? 6.0 : 3.0, ), SizedBox(height: verticalSpacing), Row( @@ -767,7 +792,7 @@ class _ProfessionalInfoFormScreenState extends State validator: (v) => v!.isEmpty ? 'Agrément requis' : null, ), ), - const SizedBox(width: 20), + const SizedBox(width: 14), Expanded( child: _buildField( config: config, @@ -784,19 +809,41 @@ class _ProfessionalInfoFormScreenState extends State ], ), SizedBox(height: verticalSpacing), - _buildField( - config: config, - label: 'Capacité d\'accueil', - controller: _capacityController, - hint: 'De 1 à 10 enfants', - keyboardType: TextInputType.number, - validator: (v) { - if (v == null || v.isEmpty) return 'Capacité requise'; - final n = int.tryParse(v); - if (n == null || n < 1) return 'Entrez un nombre entre 1 et 10'; - if (n > 10) return 'Maximum 10 (plafond agrément)'; - return null; - }, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: _buildField( + config: config, + label: 'Capacité d\'accueil', + controller: _capacityController, + hint: 'De 1 à $kAmCapaciteAccueilMax enfants', + keyboardType: TextInputType.number, + validator: (v) { + if (v == null || v.isEmpty) return 'Capacité requise'; + final n = int.tryParse(v); + if (n == null || n < 1) { + return 'Entrez un nombre entre 1 et $kAmCapaciteAccueilMax'; + } + if (n > kAmCapaciteAccueilMax) { + return 'Maximum $kAmCapaciteAccueilMax'; + } + return null; + }, + ), + ), + const SizedBox(width: 14), + Expanded( + child: _buildField( + config: config, + label: 'Places disponibles', + controller: _placesAvailableController, + hint: 'Entre 0 et la capacité', + keyboardType: TextInputType.number, + validator: _validatePlacesAvailable, + ), + ), + ], ), ], ); @@ -852,49 +899,53 @@ class _ProfessionalInfoFormScreenState extends State ), const SizedBox(height: 12), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: _buildField( - config: config, - label: 'N° d\'agrément', - controller: _agrementController, - hint: 'N° agrément', - validator: (v) => v!.isEmpty ? 'Agrément requis' : null, - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildField( - config: config, - label: 'Date d\'obtention de l\'agrément', - controller: _agreementDateController, - hint: 'JJ/MM/AAAA', - readOnly: true, - onTap: () => _selectAgreementDate(context), - suffixIcon: Icons.calendar_today, - validator: (_) => - _selectedAgreementDate == null ? 'Date d\'obtention requise' : null, - ), - ), - ], + _buildField( + config: config, + label: 'N° d\'agrément', + controller: _agrementController, + hint: 'Votre numéro d\'agrément', + validator: (v) => v!.isEmpty ? 'Agrément requis' : null, + ), + const SizedBox(height: 12), + _buildField( + config: config, + label: 'Date d\'obtention de l\'agrément', + controller: _agreementDateController, + hint: 'JJ/MM/AAAA', + readOnly: true, + onTap: () => _selectAgreementDate(context), + suffixIcon: Icons.calendar_today, + validator: (_) => + _selectedAgreementDate == null ? 'Date d\'obtention requise' : null, ), const SizedBox(height: 12), _buildField( config: config, label: 'Capacité d\'accueil', controller: _capacityController, - hint: 'De 1 à 10 enfants', + hint: 'De 1 à $kAmCapaciteAccueilMax enfants', keyboardType: TextInputType.number, validator: (v) { if (v == null || v.isEmpty) return 'Capacité requise'; final n = int.tryParse(v); - if (n == null || n < 1) return 'Entrez un nombre entre 1 et 10'; - if (n > 10) return 'Maximum 10 (plafond agrément)'; + if (n == null || n < 1) { + return 'Entrez un nombre entre 1 et $kAmCapaciteAccueilMax'; + } + if (n > kAmCapaciteAccueilMax) { + return 'Maximum $kAmCapaciteAccueilMax'; + } return null; }, ), + const SizedBox(height: 12), + _buildField( + config: config, + label: 'Places disponibles', + controller: _placesAvailableController, + hint: 'Entre 0 et la capacité', + keyboardType: TextInputType.number, + validator: _validatePlacesAvailable, + ), ], ); } @@ -918,7 +969,7 @@ class _ProfessionalInfoFormScreenState extends State baseShadowColor: Colors.green.shade300, isMobile: config.isMobile, ), - const SizedBox(height: 10), + SizedBox(height: config.isMobile ? 10.0 : 6.0), AppCustomCheckbox( label: 'J\'accepte l\'utilisation\nde ma photo.', value: _photoConsent, @@ -959,8 +1010,9 @@ class _ProfessionalInfoFormScreenState extends State hintText: hint ?? label, fieldWidth: double.infinity, fieldHeight: config.isMobile ? 45.0 : 53.0, - labelFontSize: config.isMobile ? 15.0 : 22.0, - inputFontSize: config.isMobile ? 14.0 : 20.0, + labelFontSize: config.isMobile ? 15.0 : 20.0, + inputFontSize: config.isMobile ? 14.0 : 18.0, + labelFieldSpacing: config.isMobile ? 6.0 : 3.0, keyboardType: keyboardType ?? TextInputType.text, readOnly: readOnly, onTap: onTap, diff --git a/tests/scripts/register-am-dubois-test.mjs b/tests/scripts/register-am-dubois-test.mjs index 6133645..9cdcd6c 100644 --- a/tests/scripts/register-am-dubois-test.mjs +++ b/tests/scripts/register-am-dubois-test.mjs @@ -61,6 +61,7 @@ try { numero_agrement: 'AGR-2019-095001', date_agrement: '2019-09-01', capacite_accueil: 4, + places_disponibles: 2, biographie: "Assistante maternelle agréée depuis 2019. Née en Corse à Ajaccio. Spécialité bébés 0-18 mois. " + 'Accueil bienveillant et cadre sécurisant. 2 places disponibles.', diff --git a/tests/scripts/register-am-mansouri-test.mjs b/tests/scripts/register-am-mansouri-test.mjs index a359a79..1e52d62 100644 --- a/tests/scripts/register-am-mansouri-test.mjs +++ b/tests/scripts/register-am-mansouri-test.mjs @@ -60,6 +60,7 @@ try { numero_agrement: 'AGR-2017-095002', date_agrement: '2017-06-15', capacite_accueil: 3, + places_disponibles: 1, biographie: "Assistante maternelle expérimentée. Née à l'étranger. Spécialité 1-3 ans. " + 'Accueil à la journée. 1 place disponible.',