Compare commits

..
Author SHA1 Message Date
jmartin aee061f9bd feat(frontend): Ajout champ genre obligatoire + Clean Code Step3
- Ajout champ gender (H/F) dans ChildData avec sélecteur radio
- Correction indicateur étape: 3/5 → 3/6
- Suppression commentaires inutiles et code obsolète
- Suppression print() pour gestion silencieuse des erreurs
- Ajout méthode gender() dans DataGenerator

Ticket #38
2025-12-02 14:43:10 +01:00
Julien Martin 1bbdab03d0 suppression d'un reliquat 2025-05-12 22:47:30 +02:00
Julien Martin 7f78617561 Merge branch 'develop' of https://github.com/MonkeyJLuffy/petitspas into develop 2025-05-12 16:15:29 +02:00
Julien Martin 7707b99773 feat: harmonisation de la taille de police dans les champs de motivation (étape4 et 5) - Ajout du paramètre fontSize au CustomDecoratedTextField - Taille de police fixée à 18px pour une meilleure lisibilité 2025-05-12 16:11:12 +02:00
Julien Martin 760f4feca3 feat(ui): Amélioration des cartes de récapitulatif parents et enfants\n\n- Labes plus grands et espacement augmenté pour les cartes parents\n- Labels plus grands pour les champs enfants\n- Titre enfant intégré et centré dans la carte\n- Image enfant sans cadre blanc, occupant toute la hauteur\n- Bouton de modification bien positionné\n- Affichage des consentements en lecture seule sous la fiche enfant 2025-05-12 13:04:29 +02:00
Julien Martin 03712bd99b feat(ui): Ajout des icônes de croix rouge et grise pour la suppression des cartes enfants 2025-05-12 12:21:05 +02:00
Julien Martin 1496f7f174 refactor(inscription): Refonte complète du processus d'inscription - Modèles etdonnées: Suppression de placeholder_registration_data.dart, ajout de user_registration_data.dart, data_generator.dart et card_assets.dart - Interface utilisateur: Refonte des écrans d'inscription, amélioration des widgets, ajout de cartes colorées - Assets: Ajout de nouvelles cartes colorées - Configuration: Mise à jour de pubspec.yaml et app_router.dart 2025-05-12 12:00:49 +02:00
Julien Martin acb602643a feat: Avancée majeure parcours inscription parent et refactorisation widgets UI
Ce commit comprend plusieurs améliorations significatives :

Inscription Parent - Étape 5 (Récapitulatif) :
- Initialisation de l'écran pour l'étape 5/5 du parcours d'inscription parent.
- Mise en place de la structure de base de l'écran de récapitulatif (titre, fond, bouton de soumission initial, modale de confirmation).
- Intégration de la navigation vers l'étape 5 depuis l'étape 4, incluant le passage (actuellement factice) des données d'inscription.
- Correction des erreurs de navigation et de typage liées à l'introduction de `PlaceholderRegistrationData` pour cette nouvelle étape.

Refactorisation des Widgets UI :
- `CustomAppTextField` :
    - Évolution majeure pour supporter différents styles de fond (beige, lavande, jaune) via un nouvel enum `CustomAppTextFieldStyle`.
    - Les images de fond pour les styles lavande et jaune (`input_field_lavande.png`, `input_field_jaune.png`) ont été renommées et sont maintenant utilisées.
    - Mise à jour de l'écran de login pour utiliser ce `CustomAppTextField` stylisé, remplaçant l'ancien widget privé `_ImageTextField`.
    - Réintégration des paramètres `isRequired`, `enabled`, `readOnly`, `onTap`, et `suffixIcon` qui avaient été omis lors d'une refactorisation précédente, assurant la compatibilité avec l'étape 3.
- `ImageButton` :
    - Extraction du widget privé `_ImageButton` de l'écran de login en un widget public `ImageButton` (dans `widgets/image_button.dart`) pour une réutilisation globale.
    - Mise à jour de l'écran de login pour utiliser ce nouveau widget public.
    - Utilisation du nouveau `ImageButton` pour le bouton "Soumettre ma demande" sur l'écran de l'étape 5.

Corrections :
- Correction d'une erreur de `RenderFlex overflowed` dans la carte enfant (`_ChildCardWidget`) de l'étape 3 de l'inscription parent, en ajustant les espacements internes.
- Résolution de diverses erreurs de compilation qui sont apparues pendant ces refactorisations.
2025-05-07 17:43:07 +02:00
Julien Martin 0772f83369 feat(auth): amélioration UI et UX étape 4 inscription parent 2025-05-07 17:09:06 +02:00
Julien Martin 42d147c273 feat(auth): Amélioration UI/UX étape 3 inscription enfants
- Corrige le débordement visuel (RenderFlex overflow) dans les cartes enfants.

- Augmente les marges latérales du sélecteur d'enfants pour un meilleur centrage.

- Ajoute un défilement automatique vers la droite lors de l'ajout d'un enfant.

- Intègre une barre de défilement horizontale et un effet de fondu dynamique (fading edges) au sélecteur d'enfants.

- Ajuste le padding vertical dans CustomAppTextField pour un meilleur centrage du hintText.

- Met à jour index.html :

  - Utilise le token {{flutter_service_worker_version}}.

  - Ajoute la balise meta mobile-web-app-capable.

  - Rétablit temporairement loadEntrypoint pour éviter un écran blanc (avertissement de dépréciation en attente de correction).
2025-05-07 10:42:52 +02:00
Julien Martin df56ba11df feat(auth): Amélioration UI et logique inscription parent étape 3
- Ajout du switch "Enfant à naître" et ajustement du champ prénom.

- Amélioration de la gestion de l'affichage des photos (placeholder, kIsWeb).

- Refactorisation des boutons avec HoverReliefWidget.

- Localisation du DatePicker en français.

- Nettoyage de l'intégration (annulée) de image_cropper.

- Mise à jour de EVOLUTIONS_CDC.md.
2025-05-06 23:44:10 +02:00
Julien Martin bbdacd68aa feat(auth): Supprime l'ancien workflow d'inscription parent et ajoute les assets pour le nouveau workflow 2025-05-05 12:51:32 +02:00
Julien Martin 7f831f363e chore: mise à jour du .gitignore et nettoyage du cache 2025-05-02 21:27:29 +02:00
Julien Martin 009d42ece8 chore: mise à jour du .gitignore et nettoyage des fichiers inutiles 2025-05-02 21:24:28 +02:00
Julien Martin e6d3c41ecc refactor: suppression des fichiers de thème non utilisés 2025-05-02 20:41:00 +02:00
Julien Martin c7ac3d9ebe docs: mise à jour des règles et évolutions du CDC 2025-05-02 19:54:18 +02:00
Julien Martin c8b8ad9318 feat(login): ajout du lien 'Mot de passe oublié ?' dans l'interface de connexion\n\n- Ajout du lien dans la page de connexion\n- Mise à jour du document d'évolution avec les spécifications de récupération de compte\n- Ajustements mineurs dans l'interface 2025-05-02 19:44:52 +02:00
Julien Martin 482040ba55 fix: mise à jour des chemins de l'icône pour utiliser icon.png 2025-05-01 16:51:20 +02:00
Julien Martin 2bcb0b1e54 J'ajoute tout ce que cursor a oublié... 2025-05-01 16:43:03 +02:00
Julien Martin 30e72242a8 style(login): � Ajustement de la mise en page du formulaire de connexion - Alignement des labels et des champs - Ajustement de la taille de police 2025-05-01 16:34:23 +02:00
Julien Martin aaf7070757 feat(login): ✨ Ajoutdes champs de formulaire et du bouton de connexion - Images field_email, field_password et btn_green 2025-04-30 18:38:04 +02:00
Julien Martin f4c211e0dd feat(login): � Refote visuelle du login - Fond paper2 et image river_logo_desktop positionnée à 1/4 de la largeur restante - ✨ Séparation desktop/mobile 2025-04-30 18:26:40 +02:00
Julien Martin 9519fafe3a feat: ajout d'un sélecteur de thèmes avec trois options (P'titsPas, Pastel, Sombre) 2025-04-30 11:01:15 +02:00
Julien Martin 9321430818 feat(init): mise en place initiale de P'titsPas - Documentation: CDC complet, sécifications techniques SSS-001, charte graphique, évolutions - Backend: structure NestJS avec controllers/services/routes, config Prisma - Frontend: app Flutter avec structure MVC, thème et Firebase - Changement de nom: SuperNounou devient P'titsPas 2025-04-30 10:38:47 +02:00
3 changed files with 59 additions and 32 deletions
@@ -28,22 +28,24 @@ class ParentData {
class ChildData { class ChildData {
String firstName; String firstName;
String lastName; String lastName;
String dob; // Date de naissance ou prévisionnelle String dob;
String gender;
bool photoConsent; bool photoConsent;
bool multipleBirth; bool multipleBirth;
bool isUnbornChild; bool isUnbornChild;
File? imageFile; File? imageFile;
CardColorVertical cardColor; // Nouveau champ pour la couleur de la carte CardColorVertical cardColor;
ChildData({ ChildData({
this.firstName = '', this.firstName = '',
this.lastName = '', this.lastName = '',
this.dob = '', this.dob = '',
this.gender = 'F',
this.photoConsent = false, this.photoConsent = false,
this.multipleBirth = false, this.multipleBirth = false,
this.isUnbornChild = false, this.isUnbornChild = false,
this.imageFile, this.imageFile,
required this.cardColor, // Rendre requis dans le constructeur required this.cardColor,
}); });
} }
@@ -1,19 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'dart:math' as math; // Pour la rotation du chevron import 'dart:math' as math;
import 'package:flutter/gestures.dart'; // Pour PointerDeviceKind import 'package:flutter/gestures.dart';
import '../../widgets/hover_relief_widget.dart'; // Import du nouveau widget import '../../widgets/hover_relief_widget.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
// import 'package:image_cropper/image_cropper.dart'; // Supprimé import 'dart:io' show File, Platform;
import 'dart:io' show File, Platform; // Ajout de Platform import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/foundation.dart' show kIsWeb; // Import pour kIsWeb import '../../widgets/custom_app_text_field.dart';
import '../../widgets/custom_app_text_field.dart'; // Import du nouveau widget TextField import '../../widgets/app_custom_checkbox.dart';
import '../../widgets/app_custom_checkbox.dart'; // Import du nouveau widget Checkbox import '../../models/user_registration_data.dart';
import '../../models/user_registration_data.dart'; // Import du modèle de données import '../../utils/data_generator.dart';
import '../../utils/data_generator.dart'; // Import du générateur import '../../models/card_assets.dart';
import '../../models/card_assets.dart'; // Import des enums de cartes
// La classe _ChildFormData est supprimée car on utilise ChildData du modèle
class ParentRegisterStep3Screen extends StatefulWidget { class ParentRegisterStep3Screen extends StatefulWidget {
final UserRegistrationData registrationData; // Accepte les données final UserRegistrationData registrationData; // Accepte les données
@@ -25,16 +22,15 @@ class ParentRegisterStep3Screen extends StatefulWidget {
} }
class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> { class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
late UserRegistrationData _registrationData; // Stocke l'état complet late UserRegistrationData _registrationData;
final ScrollController _scrollController = ScrollController(); // Pour le défilement horizontal final ScrollController _scrollController = ScrollController();
bool _isScrollable = false; bool _isScrollable = false;
bool _showLeftFade = false; bool _showLeftFade = false;
bool _showRightFade = false; bool _showRightFade = false;
static const double _fadeExtent = 0.05; // Pourcentage de fondu static const double _fadeExtent = 0.05;
// Liste ordonnée des couleurs de cartes pour les enfants
static const List<CardColorVertical> _childCardColors = [ static const List<CardColorVertical> _childCardColors = [
CardColorVertical.lavender, // Premier enfant toujours lavande CardColorVertical.lavender,
CardColorVertical.pink, CardColorVertical.pink,
CardColorVertical.peach, CardColorVertical.peach,
CardColorVertical.lime, CardColorVertical.lime,
@@ -43,11 +39,7 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
CardColorVertical.blue, CardColorVertical.blue,
]; ];
// Garder une trace des couleurs déjà utilisées final Set<CardColorVertical> _usedColors = {};
final Set<CardColorVertical> _usedColors = {};
// Utilisation de GlobalKey pour les cartes enfants si validation complexe future
// Map<int, GlobalKey<FormState>> _childFormKeys = {};
@override @override
void initState() { void initState() {
@@ -101,6 +93,7 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
lastName: _registrationData.parent1.lastName, lastName: _registrationData.parent1.lastName,
firstName: DataGenerator.firstName(), firstName: DataGenerator.firstName(),
dob: DataGenerator.dob(isUnborn: isUnborn), dob: DataGenerator.dob(isUnborn: isUnborn),
gender: DataGenerator.gender(),
isUnbornChild: isUnborn, isUnbornChild: isUnborn,
photoConsent: DataGenerator.boolean(), photoConsent: DataGenerator.boolean(),
multipleBirth: DataGenerator.boolean(), multipleBirth: DataGenerator.boolean(),
@@ -138,8 +131,10 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
_registrationData.children[childIndex].imageFile = File(pickedFile.path); _registrationData.children[childIndex].imageFile = File(pickedFile.path);
} }
}); });
} }
} catch (e) { print("Erreur image: $e"); } } catch (e) {
// Gestion silencieuse de l'erreur
}
} }
Future<void> _selectDate(BuildContext context, int childIndex) async { Future<void> _selectDate(BuildContext context, int childIndex) async {
@@ -194,7 +189,7 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text('Étape 3/5', style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54)), Text('Étape 3/6', style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54)),
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
'Informations Enfants', 'Informations Enfants',
@@ -228,18 +223,18 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 20.0), padding: const EdgeInsets.only(right: 20.0),
child: _ChildCardWidget( child: _ChildCardWidget(
key: ValueKey(_registrationData.children[index].hashCode), // Utiliser une clé basée sur les données key: ValueKey(_registrationData.children[index].hashCode),
childData: _registrationData.children[index], childData: _registrationData.children[index],
childIndex: index, childIndex: index,
onPickImage: () => _pickImage(index), onPickImage: () => _pickImage(index),
onDateSelect: () => _selectDate(context, index), onDateSelect: () => _selectDate(context, index),
onFirstNameChanged: (value) => setState(() => _registrationData.children[index].firstName = value), onFirstNameChanged: (value) => setState(() => _registrationData.children[index].firstName = value),
onLastNameChanged: (value) => setState(() => _registrationData.children[index].lastName = value), onLastNameChanged: (value) => setState(() => _registrationData.children[index].lastName = value),
onGenderChanged: (value) => setState(() => _registrationData.children[index].gender = value),
onTogglePhotoConsent: (newValue) => setState(() => _registrationData.children[index].photoConsent = newValue), onTogglePhotoConsent: (newValue) => setState(() => _registrationData.children[index].photoConsent = newValue),
onToggleMultipleBirth: (newValue) => setState(() => _registrationData.children[index].multipleBirth = newValue), onToggleMultipleBirth: (newValue) => setState(() => _registrationData.children[index].multipleBirth = newValue),
onToggleIsUnborn: (newValue) => setState(() { onToggleIsUnborn: (newValue) => setState(() {
_registrationData.children[index].isUnbornChild = newValue; _registrationData.children[index].isUnbornChild = newValue;
// Générer une nouvelle date si on change le statut
_registrationData.children[index].dob = DataGenerator.dob(isUnborn: newValue); _registrationData.children[index].dob = DataGenerator.dob(isUnborn: newValue);
}), }),
onRemove: () => _removeChild(index), onRemove: () => _removeChild(index),
@@ -295,13 +290,14 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
} }
// Widget pour la carte enfant (adapté pour prendre ChildData et des callbacks) // Widget pour la carte enfant (adapté pour prendre ChildData et des callbacks)
class _ChildCardWidget extends StatefulWidget { // Transformé en StatefulWidget pour gérer les contrôleurs internes class _ChildCardWidget extends StatefulWidget {
final ChildData childData; final ChildData childData;
final int childIndex; final int childIndex;
final VoidCallback onPickImage; final VoidCallback onPickImage;
final VoidCallback onDateSelect; final VoidCallback onDateSelect;
final ValueChanged<String> onFirstNameChanged; final ValueChanged<String> onFirstNameChanged;
final ValueChanged<String> onLastNameChanged; final ValueChanged<String> onLastNameChanged;
final ValueChanged<String> onGenderChanged;
final ValueChanged<bool> onTogglePhotoConsent; final ValueChanged<bool> onTogglePhotoConsent;
final ValueChanged<bool> onToggleMultipleBirth; final ValueChanged<bool> onToggleMultipleBirth;
final ValueChanged<bool> onToggleIsUnborn; final ValueChanged<bool> onToggleIsUnborn;
@@ -316,6 +312,7 @@ class _ChildCardWidget extends StatefulWidget { // Transformé en StatefulWidget
required this.onDateSelect, required this.onDateSelect,
required this.onFirstNameChanged, required this.onFirstNameChanged,
required this.onLastNameChanged, required this.onLastNameChanged,
required this.onGenderChanged,
required this.onTogglePhotoConsent, required this.onTogglePhotoConsent,
required this.onToggleMultipleBirth, required this.onToggleMultipleBirth,
required this.onToggleIsUnborn, required this.onToggleIsUnborn,
@@ -436,6 +433,32 @@ class _ChildCardWidgetState extends State<_ChildCardWidget> {
fieldHeight: 55.0 * 1.1, // 60.5 fieldHeight: 55.0 * 1.1, // 60.5
), ),
const SizedBox(height: 9.0 * 1.1), // 9.9 const SizedBox(height: 9.0 * 1.1), // 9.9
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Genre', style: GoogleFonts.merienda(fontSize: 16 * 1.1, fontWeight: FontWeight.w600)),
Row(
children: [
Radio<String>(
value: 'H',
groupValue: widget.childData.gender,
onChanged: (value) => widget.onGenderChanged(value!),
activeColor: Theme.of(context).primaryColor,
),
Text('H', style: GoogleFonts.merienda(fontSize: 16 * 1.1)),
const SizedBox(width: 20),
Radio<String>(
value: 'F',
groupValue: widget.childData.gender,
onChanged: (value) => widget.onGenderChanged(value!),
activeColor: Theme.of(context).primaryColor,
),
Text('F', style: GoogleFonts.merienda(fontSize: 16 * 1.1)),
],
),
],
),
const SizedBox(height: 9.0 * 1.1), // 9.9
CustomAppTextField( CustomAppTextField(
controller: _dobController, controller: _dobController,
labelText: widget.childData.isUnbornChild ? 'Date prévisionnelle de naissance' : 'Date de naissance', labelText: widget.childData.isUnbornChild ? 'Date prévisionnelle de naissance' : 'Date de naissance',
+2
View File
@@ -51,6 +51,8 @@ class DataGenerator {
static bool boolean() => _random.nextBool(); static bool boolean() => _random.nextBool();
static String gender() => _random.nextBool() ? 'H' : 'F';
static String motivation() { static String motivation() {
int count = _random.nextInt(3) + 2; // 2 à 4 phrases int count = _random.nextInt(3) + 2; // 2 à 4 phrases
List<String> chosenSnippets = []; List<String> chosenSnippets = [];