Compare commits

..

6 Commits

Author SHA1 Message Date
c934466e47 Merge pull request 'feat(#37): Inscription Parent - Étape 2 (Parent 2)' (#74) from feature/37-frontend-inscription-parent-step2 into master
feat(#37): Inscription Parent - Étape 2 (Parent 2)
2025-12-01 22:36:31 +00:00
90d8fa8669 feat(#37): Inscription Parent - Étape 2 (Parent 2)
Frontend Step2:
- Suppression des champs mot de passe et confirmation
- Correction de l'indicateur d'étape: 2/5 → 2/6
- Améliorations visuelles (mêmes que Step1):
  * Taille des labels: 18 → 22px
  * Taille de police des champs: 18 → 20px
  * Espacement entre champs: 20 → 32px
  * Meilleure répartition verticale avec spaceEvenly

Note: Le champ password est conservé dans le modèle ParentData pour compatibilité
2025-12-01 23:36:02 +01:00
90cdf16709 docs: Correction numérotation tickets et ajout statuts terminés
- Correction numérotation pour correspondre à Gitea (#36-#63)
- Ajout tickets #34 et #35 (réservés)
- Marquage tickets terminés avec :
  * #3, #4, #7 (BDD)
  * #18, #19, #20, #21 (Backend API Parent)
  * #36 (Frontend Step1)
- Correction doublons (#38, #39, #41, #42, #47, #48)
- Renumération tickets Frontend et Tests
2025-12-01 23:28:08 +01:00
bde97c24db Merge pull request 'feat(#36): Inscription Parent - Étape 1 (Parent 1)' (#73) from feature/36-frontend-inscription-parent-step1 into master
feat(#36): Inscription Parent - Étape 1 (Parent 1)
2025-12-01 22:21:02 +00:00
9ae6533b4d feat(#36): Inscription Parent - Étape 1 (Parent 1)
Backend:
- Retrait des champs non-CDC: profession, situation_familiale, date_naissance
- Nettoyage des DTOs RegisterParentCompletDto et RegisterParentDto
- Mise à jour de la logique dans auth.service.ts (inscrireParentComplet et legacy)

Frontend Step1:
- Suppression des champs mot de passe et confirmation
- Correction de l'indicateur d'étape: 1/5 → 1/6
- Améliorations visuelles:
  * Taille des labels: 18 → 22px
  * Taille de police des champs: 18 → 20px
  * Espacement entre champs: 20 → 32px
  * Meilleure répartition verticale avec spaceEvenly

Note: Le champ password est conservé dans le modèle ParentData pour compatibilité avec Step2
2025-12-01 23:19:58 +01:00
579b6cae90 [Backend] API Inscription Parent - REFONTE Workflow 6 etapes (#72)
Co-authored-by: Julien Martin <julien.martin@ptits-pas.fr>
Co-committed-by: Julien Martin <julien.martin@ptits-pas.fr>
2025-12-01 21:43:36 +00:00
6 changed files with 133 additions and 169 deletions

View File

@ -200,16 +200,10 @@ export class AuthService {
adresse: dto.adresse, adresse: dto.adresse,
code_postal: dto.code_postal, code_postal: dto.code_postal,
ville: dto.ville, ville: dto.ville,
profession: dto.profession,
situation_familiale: dto.situation_familiale,
token_creation_mdp: tokenCreationMdp, token_creation_mdp: tokenCreationMdp,
token_creation_mdp_expire_le: tokenExpiration, token_creation_mdp_expire_le: tokenExpiration,
}); });
if (dto.date_naissance) {
parent1.date_naissance = new Date(dto.date_naissance);
}
const savedParent1 = await manager.save(Users, parent1); const savedParent1 = await manager.save(Users, parent1);
// Créer Parent 2 si renseigné // Créer Parent 2 si renseigné
@ -327,16 +321,10 @@ export class AuthService {
adresse: dto.adresse, adresse: dto.adresse,
code_postal: dto.code_postal, code_postal: dto.code_postal,
ville: dto.ville, ville: dto.ville,
profession: dto.profession,
situation_familiale: dto.situation_familiale,
token_creation_mdp: tokenCreationMdp, token_creation_mdp: tokenCreationMdp,
token_creation_mdp_expire_le: dateExpiration, token_creation_mdp_expire_le: dateExpiration,
}); });
if (dto.date_naissance) {
parent1.date_naissance = new Date(dto.date_naissance);
}
const parent1Enregistre = await manager.save(Users, parent1); const parent1Enregistre = await manager.save(Users, parent1);
let parent2Enregistre: Users | null = null; let parent2Enregistre: Users | null = null;

View File

@ -66,22 +66,6 @@ export class RegisterParentCompletDto {
@MaxLength(150) @MaxLength(150)
ville?: string; ville?: string;
@ApiProperty({ example: 'Infirmière', required: false })
@IsOptional()
@IsString()
@MaxLength(150)
profession?: string;
@ApiProperty({ enum: SituationFamilialeType, example: SituationFamilialeType.MARIE, required: false })
@IsOptional()
@IsEnum(SituationFamilialeType)
situation_familiale?: SituationFamilialeType;
@ApiProperty({ example: '1990-04-03', required: false })
@IsOptional()
@IsDateString()
date_naissance?: string;
// ============================================ // ============================================
// ÉTAPE 2 : PARENT 2 / CO-PARENT (Optionnel) // ÉTAPE 2 : PARENT 2 / CO-PARENT (Optionnel)
// ============================================ // ============================================

View File

@ -59,22 +59,6 @@ export class RegisterParentDto {
@MaxLength(150) @MaxLength(150)
ville?: string; ville?: string;
@ApiProperty({ example: 'Infirmière', required: false })
@IsOptional()
@IsString()
@MaxLength(150)
profession?: string;
@ApiProperty({ enum: SituationFamilialeType, example: SituationFamilialeType.MARIE, required: false })
@IsOptional()
@IsEnum(SituationFamilialeType)
situation_familiale?: SituationFamilialeType;
@ApiProperty({ example: '1990-04-03', required: false })
@IsOptional()
@IsDateString()
date_naissance?: string;
// === Informations co-parent (optionnel) === // === Informations co-parent (optionnel) ===
@ApiProperty({ example: 'thomas.martin@ptits-pas.fr', required: false }) @ApiProperty({ example: 'thomas.martin@ptits-pas.fr', required: false })
@IsOptional() @IsOptional()

View File

@ -58,32 +58,34 @@ Ajouter un champ pour stocker la présentation du dossier parent (étape 4 de l'
--- ---
### Ticket #3 : [BDD] Ajout gestion tokens création mot de passe ### Ticket #3 : [BDD] Ajout gestion tokens création mot de passe
**Estimation** : 30min **Estimation** : 30min
**Labels** : `bdd`, `p0-bloquant`, `security` **Labels** : `bdd`, `p0-bloquant`, `security`
**Statut** : ✅ TERMINÉ (Fermé le 2025-11-28)
**Description** : **Description** :
Ajouter les champs nécessaires pour gérer les tokens de création de mot de passe (workflow sans MDP lors inscription). Ajouter les champs nécessaires pour gérer les tokens de création de mot de passe (workflow sans MDP lors inscription).
**Tâches** : **Tâches** :
- [ ] Ajouter `password_reset_token` UUID dans `utilisateurs` - [x] Ajouter `password_reset_token` UUID dans `utilisateurs`
- [ ] Ajouter `password_reset_expires` TIMESTAMPTZ dans `utilisateurs` - [x] Ajouter `password_reset_expires` TIMESTAMPTZ dans `utilisateurs`
- [ ] Créer migration Prisma - [x] Créer migration Prisma
- [ ] Tester migration - [x] Tester migration
--- ---
### Ticket #4 : [BDD] Ajout champ genre obligatoire enfants ### Ticket #4 : [BDD] Ajout champ genre obligatoire enfants
**Estimation** : 30min **Estimation** : 30min
**Labels** : `bdd`, `p0-bloquant`, `cdc` **Labels** : `bdd`, `p0-bloquant`, `cdc`
**Statut** : ✅ TERMINÉ (Fermé le 2025-11-28)
**Description** : **Description** :
Ajouter le champ `genre` obligatoire (H/F) dans la table `enfants`. Ajouter le champ `genre` obligatoire (H/F) dans la table `enfants`.
**Tâches** : **Tâches** :
- [ ] Ajouter `genre` ENUM('H', 'F') NOT NULL dans `enfants` - [x] Ajouter `genre` ENUM('H', 'F') NOT NULL dans `enfants`
- [ ] Créer migration Prisma - [x] Créer migration Prisma
- [ ] Tester migration - [x] Tester migration
--- ---
@ -122,9 +124,10 @@ Créer la table `configuration` pour stocker les paramètres système (SMTP, app
--- ---
### Ticket #7 : [BDD] Tables documents légaux & acceptations ### Ticket #7 : [BDD] Tables documents légaux & acceptations
**Estimation** : 2h **Estimation** : 2h
**Labels** : `bdd`, `p0-bloquant`, `rgpd`, `juridique` **Labels** : `bdd`, `p0-bloquant`, `rgpd`, `juridique`
**Statut** : ✅ TERMINÉ (Fermé le 2025-11-30 - Ticket #68 sur Gitea)
**Description** : **Description** :
Créer les tables pour gérer les versions des documents légaux (CGU/Privacy) et tracer les acceptations utilisateurs. Créer les tables pour gérer les versions des documents légaux (CGU/Privacy) et tracer les acceptations utilisateurs.
@ -334,12 +337,13 @@ Ajouter la gestion du co-parent (Parent 2) dans l'endpoint d'inscription.
--- ---
### Ticket #18 : [Backend] API Inscription Parent (étape 3 - Enfants) ### Ticket #18 : [Backend] API Inscription Parent - REFONTE (Workflow complet 6 étapes) ✅
**Estimation** : 4h **Estimation** : 4h
**Labels** : `backend`, `p2`, `auth`, `cdc`, `upload` **Labels** : `backend`, `p2`, `auth`, `cdc`, `upload`
**Statut** : ✅ TERMINÉ (Fermé le 2025-12-01)
**Description** : **Description** :
Créer l'endpoint pour ajouter des enfants lors de l'inscription parent. Refonte complète de l'API d'inscription parent pour gérer le workflow complet en 6 étapes dans une seule transaction.
**Tâches** : **Tâches** :
- [ ] Endpoint `POST /api/v1/enfants` - [ ] Endpoint `POST /api/v1/enfants`
@ -352,12 +356,13 @@ Créer l'endpoint pour ajouter des enfants lors de l'inscription parent.
--- ---
### Ticket #19 : [Backend] API Inscription Parent (étape 4-6 - Finalisation) ### Ticket #19 : [Backend] API Inscription Parent (étape 2 - Parent 2) ✅
**Estimation** : 2h **Estimation** : 2h
**Labels** : `backend`, `p2`, `auth`, `cdc` **Labels** : `backend`, `p2`, `auth`, `cdc`
**Statut** : ✅ TERMINÉ (Fermé le 2025-12-01)
**Description** : **Description** :
Finaliser l'inscription parent (présentation, CGU, récapitulatif). Gestion du co-parent (Parent 2) dans l'endpoint d'inscription (intégré dans la refonte #18).
**Tâches** : **Tâches** :
- [ ] Enregistrement présentation dossier - [ ] Enregistrement présentation dossier
@ -367,12 +372,13 @@ Finaliser l'inscription parent (présentation, CGU, récapitulatif).
--- ---
### Ticket #20 : [Backend] API Inscription AM (panneau 1 - Identité) ### Ticket #20 : [Backend] API Inscription Parent (étape 3 - Enfants) ✅
**Estimation** : 4h **Estimation** : 4h
**Labels** : `backend`, `p2`, `auth`, `cdc`, `upload` **Labels** : `backend`, `p2`, `auth`, `cdc`, `upload`
**Statut** : ✅ TERMINÉ (Fermé le 2025-12-01)
**Description** : **Description** :
Créer l'endpoint d'inscription Assistante Maternelle (panneau 1/5 : identité). Gestion des enfants dans l'endpoint d'inscription (intégré dans la refonte #18).
**Tâches** : **Tâches** :
- [ ] Endpoint `POST /api/v1/auth/register/am` - [ ] Endpoint `POST /api/v1/auth/register/am`
@ -386,12 +392,13 @@ Créer l'endpoint d'inscription Assistante Maternelle (panneau 1/5 : identité).
--- ---
### Ticket #21 : [Backend] API Inscription AM (panneau 2 - Infos pro) ### Ticket #21 : [Backend] API Inscription Parent (étape 4-6 - Finalisation) ✅
**Estimation** : 3h **Estimation** : 3h
**Labels** : `backend`, `p2`, `auth`, `cdc` **Labels** : `backend`, `p2`, `auth`, `cdc`
**Statut** : ✅ TERMINÉ (Fermé le 2025-12-01)
**Description** : **Description** :
Ajouter les informations professionnelles de l'AM (panneau 2/5). Finalisation de l'inscription parent (présentation, CGU, récapitulatif - intégré dans la refonte #18).
**Tâches** : **Tâches** :
- [ ] Validation NIR (15 chiffres obligatoire) - [ ] Validation NIR (15 chiffres obligatoire)
@ -617,22 +624,33 @@ Créer l'écran de création de gestionnaire (super admin uniquement).
--- ---
### Ticket #34 : [Frontend] Inscription Parent - Étape 1 (Parent 1) ### Ticket #34 : [Réservé - Non utilisé]
---
### Ticket #35 : [Réservé - Non utilisé]
---
### Ticket #36 : [Frontend] Inscription Parent - Étape 1 (Parent 1) ✅
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth`, `cdc` **Labels** : `frontend`, `p3`, `auth`, `cdc`
**Statut** : ✅ TERMINÉ (PR #73 mergée le 2025-12-01)
**Description** : **Description** :
Créer le formulaire d'inscription parent - étape 1/6 (informations Parent 1). Créer le formulaire d'inscription parent - étape 1/6 (informations Parent 1).
**Tâches** : **Tâches** :
- [ ] Formulaire identité Parent 1 - [x] Formulaire identité Parent 1
- [ ] Validation côté client - [x] Validation côté client
- [ ] Pas de champ mot de passe - [x] Pas de champ mot de passe
- [ ] Navigation vers étape 2 - [x] Navigation vers étape 2
- [x] Améliorations visuelles (labels 22px, champs 20px, espacement 32px)
- [x] Correction indicateur étape 1/6
--- ---
### Ticket #35 : [Frontend] Inscription Parent - Étape 2 (Parent 2) ### Ticket #37 : [Frontend] Inscription Parent - Étape 2 (Parent 2)
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth`, `cdc` **Labels** : `frontend`, `p3`, `auth`, `cdc`
@ -644,10 +662,13 @@ Créer le formulaire d'inscription parent - étape 2/6 (informations Parent 2 op
- [ ] Formulaire identité Parent 2 (conditionnel) - [ ] Formulaire identité Parent 2 (conditionnel)
- [ ] Checkbox "Même adresse" - [ ] Checkbox "Même adresse"
- [ ] Navigation vers étape 3 - [ ] Navigation vers étape 3
- [ ] Pas de champ mot de passe
- [ ] Améliorations visuelles (mêmes que Step1)
- [ ] Correction indicateur étape 2/6
--- ---
### Ticket #36 : [Frontend] Inscription Parent - Étape 3 (Enfants) ### Ticket #38 : [Frontend] Inscription Parent - Étape 3 (Enfants)
**Estimation** : 4h **Estimation** : 4h
**Labels** : `frontend`, `p3`, `auth`, `cdc`, `upload` **Labels** : `frontend`, `p3`, `auth`, `cdc`, `upload`
@ -664,7 +685,7 @@ Créer le formulaire d'inscription parent - étape 3/6 (informations enfants).
--- ---
### Ticket #37 : [Frontend] Inscription Parent - Étapes 4-6 (Finalisation) ### Ticket #39 : [Frontend] Inscription Parent - Étapes 4-6 (Finalisation)
**Estimation** : 4h **Estimation** : 4h
**Labels** : `frontend`, `p3`, `auth`, `cdc` **Labels** : `frontend`, `p3`, `auth`, `cdc`
@ -681,7 +702,7 @@ Créer les étapes finales de l'inscription parent (présentation, CGU, récapit
--- ---
### Ticket #38 : [Frontend] Inscription AM - Panneau 1 (Identité) ### Ticket #40 : [Frontend] Inscription AM - Panneau 1 (Identité)
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth`, `cdc`, `upload` **Labels** : `frontend`, `p3`, `auth`, `cdc`, `upload`
@ -697,7 +718,7 @@ Créer le formulaire d'inscription AM - panneau 1/5 (identité).
--- ---
### Ticket #39 : [Frontend] Inscription AM - Panneau 2 (Infos pro) ### Ticket #41 : [Frontend] Inscription AM - Panneau 2 (Infos pro)
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth`, `cdc` **Labels** : `frontend`, `p3`, `auth`, `cdc`
@ -713,7 +734,7 @@ Créer le formulaire d'inscription AM - panneau 2/5 (informations professionnell
--- ---
### Ticket #40 : [Frontend] Inscription AM - Finalisation ### Ticket #42 : [Frontend] Inscription AM - Finalisation
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth`, `cdc` **Labels** : `frontend`, `p3`, `auth`, `cdc`
@ -729,7 +750,7 @@ Créer les étapes finales de l'inscription AM (présentation, CGU, récapitulat
--- ---
### Ticket #41 : [Frontend] Écran Création Mot de Passe ### Ticket #43 : [Frontend] Écran Création Mot de Passe
**Estimation** : 3h **Estimation** : 3h
**Labels** : `frontend`, `p3`, `auth` **Labels** : `frontend`, `p3`, `auth`
@ -746,7 +767,7 @@ Créer l'écran de création de mot de passe (lien reçu par email).
--- ---
### Ticket #42 : [Frontend] Dashboard Gestionnaire - Structure ### Ticket #44 : [Frontend] Dashboard Gestionnaire - Structure
**Estimation** : 2h **Estimation** : 2h
**Labels** : `frontend`, `p3`, `gestionnaire` **Labels** : `frontend`, `p3`, `gestionnaire`
@ -760,7 +781,7 @@ Créer la structure du dashboard gestionnaire avec 2 onglets.
--- ---
### Ticket #43 : [Frontend] Dashboard Gestionnaire - Liste Parents ### Ticket #45 : [Frontend] Dashboard Gestionnaire - Liste Parents
**Estimation** : 4h **Estimation** : 4h
**Labels** : `frontend`, `p3`, `gestionnaire` **Labels** : `frontend`, `p3`, `gestionnaire`
@ -776,7 +797,7 @@ Créer la liste des parents en attente de validation.
--- ---
### Ticket #44 : [Frontend] Dashboard Gestionnaire - Liste AM ### Ticket #46 : [Frontend] Dashboard Gestionnaire - Liste AM
**Estimation** : 4h **Estimation** : 4h
**Labels** : `frontend`, `p3`, `gestionnaire` **Labels** : `frontend`, `p3`, `gestionnaire`
@ -793,7 +814,7 @@ Créer la liste des assistantes maternelles en attente de validation.
--- ---
### Ticket #45 : [Frontend] Écran Changement MDP Obligatoire ### Ticket #47 : [Frontend] Écran Changement MDP Obligatoire
**Estimation** : 2h **Estimation** : 2h
**Labels** : `frontend`, `p3`, `auth`, `security` **Labels** : `frontend`, `p3`, `auth`, `security`
@ -809,7 +830,7 @@ Créer l'écran de changement de mot de passe obligatoire (première connexion g
--- ---
### Ticket #46 : [Frontend] Gestion Erreurs & Messages ### Ticket #48 : [Frontend] Gestion Erreurs & Messages
**Estimation** : 2h **Estimation** : 2h
**Labels** : `frontend`, `p3`, `ux` **Labels** : `frontend`, `p3`, `ux`
@ -823,7 +844,7 @@ Créer un système de gestion des erreurs et messages utilisateur.
--- ---
### Ticket #47 : [Frontend] Écran Gestion Documents Légaux (Admin) ### Ticket #49 : [Frontend] Écran Gestion Documents Légaux (Admin)
**Estimation** : 5h **Estimation** : 5h
**Labels** : `frontend`, `p3`, `juridique`, `admin` **Labels** : `frontend`, `p3`, `juridique`, `admin`
@ -842,7 +863,7 @@ Créer l'écran de gestion des documents légaux (CGU/Privacy) pour l'admin.
--- ---
### Ticket #48 : [Frontend] Affichage dynamique CGU lors inscription ### Ticket #50 : [Frontend] Affichage dynamique CGU lors inscription
**Estimation** : 2h **Estimation** : 2h
**Labels** : `frontend`, `p3`, `juridique` **Labels** : `frontend`, `p3`, `juridique`
@ -856,9 +877,24 @@ Afficher dynamiquement les CGU/Privacy lors de l'inscription (avec numéro de ve
--- ---
### Ticket #51 : [Frontend] Écran Logs Admin (optionnel v1.1)
**Estimation** : 4h
**Labels** : `frontend`, `p3`, `admin`, `logs`
**Description** :
Créer l'écran de consultation des logs système (optionnel pour v1.1).
**Tâches** :
- [ ] Appel API logs
- [ ] Filtres (date, niveau, utilisateur)
- [ ] Pagination
- [ ] Export CSV
---
## 🔵 PRIORITÉ 4 : Tests & Documentation ## 🔵 PRIORITÉ 4 : Tests & Documentation
### Ticket #49 : [Tests] Tests unitaires Backend ### Ticket #52 : [Tests] Tests unitaires Backend
**Estimation** : 8h **Estimation** : 8h
**Labels** : `tests`, `p4`, `backend` **Labels** : `tests`, `p4`, `backend`

View File

@ -22,11 +22,9 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
final _firstNameController = TextEditingController(); final _firstNameController = TextEditingController();
final _phoneController = TextEditingController(); final _phoneController = TextEditingController();
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _passwordController = TextEditingController(); final _addressController = TextEditingController();
final _confirmPasswordController = TextEditingController(); final _postalCodeController = TextEditingController();
final _addressController = TextEditingController(); // Rue seule final _cityController = TextEditingController();
final _postalCodeController = TextEditingController(); // Restauré
final _cityController = TextEditingController(); // Restauré
@override @override
void initState() { void initState() {
@ -48,8 +46,6 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
_lastNameController.text = genLastName; _lastNameController.text = genLastName;
_phoneController.text = DataGenerator.phone(); _phoneController.text = DataGenerator.phone();
_emailController.text = DataGenerator.email(genFirstName, genLastName); _emailController.text = DataGenerator.email(genFirstName, genLastName);
_passwordController.text = DataGenerator.password();
_confirmPasswordController.text = _passwordController.text;
} }
@override @override
@ -58,8 +54,6 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
_firstNameController.dispose(); _firstNameController.dispose();
_phoneController.dispose(); _phoneController.dispose();
_emailController.dispose(); _emailController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
_addressController.dispose(); _addressController.dispose();
_postalCodeController.dispose(); _postalCodeController.dispose();
_cityController.dispose(); _cityController.dispose();
@ -88,9 +82,9 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Indicateur d'étape (à rendre dynamique) // Indicateur d'étape
Text( Text(
'Étape 1/5', 'Étape 1/6',
style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54), style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
@ -121,54 +115,43 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
key: _formKey, key: _formKey,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
const SizedBox(height: 10),
Row( Row(
children: [ children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _lastNameController, labelText: 'Nom', hintText: 'Votre nom de famille', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _lastNameController, labelText: 'Nom', hintText: 'Votre nom de famille', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4% Expanded(flex: 1, child: const SizedBox()),
Expanded(flex: 12, child: CustomAppTextField(controller: _firstNameController, labelText: 'Prénom', hintText: 'Votre prénom', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _firstNameController, labelText: 'Prénom', hintText: 'Votre prénom', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 32),
Row( Row(
children: [ children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _phoneController, labelText: 'Téléphone', keyboardType: TextInputType.phone, hintText: 'Votre numéro de téléphone', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _phoneController, labelText: 'Téléphone', keyboardType: TextInputType.phone, hintText: 'Votre numéro de téléphone', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4% Expanded(flex: 1, child: const SizedBox()),
Expanded(flex: 12, child: CustomAppTextField(controller: _emailController, labelText: 'Email', keyboardType: TextInputType.emailAddress, hintText: 'Votre adresse e-mail', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _emailController, labelText: 'Email', keyboardType: TextInputType.emailAddress, hintText: 'Votre adresse e-mail', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 32),
Row(
children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _passwordController, labelText: 'Mot de passe', obscureText: true, hintText: 'Créez votre mot de passe', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, validator: (value) {
if (value == null || value.isEmpty) return 'Mot de passe requis';
if (value.length < 6) return '6 caractères minimum';
return null;
})),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4%
Expanded(flex: 12, child: CustomAppTextField(controller: _confirmPasswordController, labelText: 'Confirmation', obscureText: true, hintText: 'Confirmez le mot de passe', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, validator: (value) {
if (value == null || value.isEmpty) return 'Confirmation requise';
if (value != _passwordController.text) return 'Ne correspond pas';
return null;
})),
],
),
const SizedBox(height: 20),
CustomAppTextField( CustomAppTextField(
controller: _addressController, controller: _addressController,
labelText: 'Adresse (N° et Rue)', labelText: 'Adresse (N° et Rue)',
hintText: 'Numéro et nom de votre rue', hintText: 'Numéro et nom de votre rue',
style: CustomAppTextFieldStyle.beige, style: CustomAppTextFieldStyle.beige,
fieldWidth: double.infinity, fieldWidth: double.infinity,
labelFontSize: 22.0,
inputFontSize: 20.0,
), ),
const SizedBox(height: 20), const SizedBox(height: 32),
Row( Row(
children: [ children: [
Expanded(flex: 1, child: CustomAppTextField(controller: _postalCodeController, labelText: 'Code Postal', keyboardType: TextInputType.number, hintText: 'Code postal', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 1, child: CustomAppTextField(controller: _postalCodeController, labelText: 'Code Postal', keyboardType: TextInputType.number, hintText: 'Code postal', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded(flex: 4, child: CustomAppTextField(controller: _cityController, labelText: 'Ville', hintText: 'Votre ville', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 4, child: CustomAppTextField(controller: _cityController, labelText: 'Ville', hintText: 'Votre ville', style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 10),
], ],
), ),
), ),
@ -205,12 +188,12 @@ class _ParentRegisterStep1ScreenState extends State<ParentRegisterStep1Screen> {
ParentData( ParentData(
firstName: _firstNameController.text, firstName: _firstNameController.text,
lastName: _lastNameController.text, lastName: _lastNameController.text,
address: _addressController.text, // Rue address: _addressController.text,
postalCode: _postalCodeController.text, // Ajout postalCode: _postalCodeController.text,
city: _cityController.text, // Ajout city: _cityController.text,
phone: _phoneController.text, phone: _phoneController.text,
email: _emailController.text, email: _emailController.text,
password: _passwordController.text, password: '', // Pas de mot de passe à cette étape
) )
); );
Navigator.pushNamed(context, '/parent-register/step2', arguments: _registrationData); Navigator.pushNamed(context, '/parent-register/step2', arguments: _registrationData);

View File

@ -22,16 +22,14 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
bool _addParent2 = true; // Pour le test, on ajoute toujours le parent 2 bool _addParent2 = true; // Pour le test, on ajoute toujours le parent 2
bool _sameAddressAsParent1 = false; // Peut être généré aléatoirement aussi bool _sameAddressAsParent1 = false; // Peut être généré aléatoirement aussi
// Contrôleurs pour les champs du parent 2 (restauration CP et Ville) // Contrôleurs pour les champs du parent 2
final _lastNameController = TextEditingController(); final _lastNameController = TextEditingController();
final _firstNameController = TextEditingController(); final _firstNameController = TextEditingController();
final _phoneController = TextEditingController(); final _phoneController = TextEditingController();
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _passwordController = TextEditingController(); final _addressController = TextEditingController();
final _confirmPasswordController = TextEditingController(); final _postalCodeController = TextEditingController();
final _addressController = TextEditingController(); // Rue seule final _cityController = TextEditingController();
final _postalCodeController = TextEditingController(); // Restauré
final _cityController = TextEditingController(); // Restauré
@override @override
void initState() { void initState() {
@ -49,17 +47,13 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
_lastNameController.text = genLastName; _lastNameController.text = genLastName;
_phoneController.text = DataGenerator.phone(); _phoneController.text = DataGenerator.phone();
_emailController.text = DataGenerator.email(genFirstName, genLastName); _emailController.text = DataGenerator.email(genFirstName, genLastName);
_passwordController.text = DataGenerator.password();
_confirmPasswordController.text = _passwordController.text;
_sameAddressAsParent1 = DataGenerator.boolean(); _sameAddressAsParent1 = DataGenerator.boolean();
if (!_sameAddressAsParent1) { if (!_sameAddressAsParent1) {
// Générer adresse, CP, Ville séparément
_addressController.text = DataGenerator.address(); _addressController.text = DataGenerator.address();
_postalCodeController.text = DataGenerator.postalCode(); _postalCodeController.text = DataGenerator.postalCode();
_cityController.text = DataGenerator.city(); _cityController.text = DataGenerator.city();
} else { } else {
// Vider les champs si même adresse (seront désactivés)
_addressController.clear(); _addressController.clear();
_postalCodeController.clear(); _postalCodeController.clear();
_cityController.clear(); _cityController.clear();
@ -72,8 +66,6 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
_firstNameController.dispose(); _firstNameController.dispose();
_phoneController.dispose(); _phoneController.dispose();
_emailController.dispose(); _emailController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
_addressController.dispose(); _addressController.dispose();
_postalCodeController.dispose(); _postalCodeController.dispose();
_cityController.dispose(); _cityController.dispose();
@ -98,7 +90,7 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text('Étape 2/5', style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54)), Text('Étape 2/6', style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54)),
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
'Informations du Deuxième Parent (Optionnel)', 'Informations du Deuxième Parent (Optionnel)',
@ -117,7 +109,9 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
const SizedBox(height: 10),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -156,40 +150,33 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
]), ]),
), ),
]), ]),
const SizedBox(height: 25), const SizedBox(height: 32),
Row( Row(
children: [ children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _lastNameController, labelText: 'Nom', hintText: 'Nom du parent 2', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _lastNameController, labelText: 'Nom', hintText: 'Nom du parent 2', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4% Expanded(flex: 1, child: const SizedBox()),
Expanded(flex: 12, child: CustomAppTextField(controller: _firstNameController, labelText: 'Prénom', hintText: 'Prénom du parent 2', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _firstNameController, labelText: 'Prénom', hintText: 'Prénom du parent 2', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 32),
Row( Row(
children: [ children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _phoneController, labelText: 'Téléphone', keyboardType: TextInputType.phone, hintText: 'Son téléphone', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _phoneController, labelText: 'Téléphone', keyboardType: TextInputType.phone, hintText: 'Son téléphone', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4% Expanded(flex: 1, child: const SizedBox()),
Expanded(flex: 12, child: CustomAppTextField(controller: _emailController, labelText: 'Email', keyboardType: TextInputType.emailAddress, hintText: 'Son email', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 12, child: CustomAppTextField(controller: _emailController, labelText: 'Email', keyboardType: TextInputType.emailAddress, hintText: 'Son email', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 32),
CustomAppTextField(controller: _addressController, labelText: 'Adresse (N° et Rue)', hintText: 'Son numéro et nom de rue', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0),
const SizedBox(height: 32),
Row( Row(
children: [ children: [
Expanded(flex: 12, child: CustomAppTextField(controller: _passwordController, labelText: 'Mot de passe', obscureText: true, hintText: 'Son mot de passe', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, validator: _addParent2 ? (v) => (v == null || v.isEmpty ? 'Requis' : (v.length < 6 ? '6 car. min' : null)) : null)), Expanded(flex: 1, child: CustomAppTextField(controller: _postalCodeController, labelText: 'Code Postal', keyboardType: TextInputType.number, hintText: 'Son code postal', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
Expanded(flex: 1, child: const SizedBox()), // Espace de 4%
Expanded(flex: 12, child: CustomAppTextField(controller: _confirmPasswordController, labelText: 'Confirmation', obscureText: true, hintText: 'Confirmer mot de passe', enabled: _parent2FieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, validator: _addParent2 ? (v) => (v == null || v.isEmpty ? 'Requis' : (v != _passwordController.text ? 'Différent' : null)) : null)),
],
),
const SizedBox(height: 20),
CustomAppTextField(controller: _addressController, labelText: 'Adresse (N° et Rue)', hintText: 'Son numéro et nom de rue', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity),
const SizedBox(height: 20),
Row(
children: [
Expanded(flex: 1, child: CustomAppTextField(controller: _postalCodeController, labelText: 'Code Postal', keyboardType: TextInputType.number, hintText: 'Son code postal', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded(flex: 4, child: CustomAppTextField(controller: _cityController, labelText: 'Ville', hintText: 'Sa ville', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity)), Expanded(flex: 4, child: CustomAppTextField(controller: _cityController, labelText: 'Ville', hintText: 'Sa ville', enabled: _addressFieldsEnabled, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0)),
], ],
), ),
const SizedBox(height: 10),
], ],
), ),
), ),
@ -225,7 +212,7 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
city: _sameAddressAsParent1 ? _registrationData.parent1.city : _cityController.text, city: _sameAddressAsParent1 ? _registrationData.parent1.city : _cityController.text,
phone: _phoneController.text, phone: _phoneController.text,
email: _emailController.text, email: _emailController.text,
password: _passwordController.text, password: '', // Pas de mot de passe à cette étape
) )
); );
} else { } else {
@ -244,8 +231,10 @@ class _ParentRegisterStep2ScreenState extends State<ParentRegisterStep2Screen> {
void _clearParent2Fields() { void _clearParent2Fields() {
_formKey.currentState?.reset(); _formKey.currentState?.reset();
_lastNameController.clear(); _firstNameController.clear(); _phoneController.clear(); _lastNameController.clear();
_emailController.clear(); _passwordController.clear(); _confirmPasswordController.clear(); _firstNameController.clear();
_phoneController.clear();
_emailController.clear();
_addressController.clear(); _addressController.clear();
_postalCodeController.clear(); _postalCodeController.clear();
_cityController.clear(); _cityController.clear();