diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..f7d4a644f1a97947833a2b3002a059072ac15458 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "C:\\Users\\feliv\\anaconda3\\python.exe" +} \ No newline at end of file diff --git a/src/app/members/account/edit-data/edit-data.component.ts b/src/app/members/account/edit-data/edit-data.component.ts index 1a6260dab4240bed6e3dc7419b32f18d386336cd..72fb64411fe9640846c75ff3a0c50abb3d667270 100644 --- a/src/app/members/account/edit-data/edit-data.component.ts +++ b/src/app/members/account/edit-data/edit-data.component.ts @@ -98,7 +98,6 @@ export class EditDataComponent implements OnInit { personalPhone:[this.personalData.personalPhone,Validators.pattern("^([0-9]{2}[]?){5}$")], parentsPhone:[this.personalData.parentsPhone,Validators.pattern("^([0-9]{2}[]?){5}$")], - parentsEmail:[this.personalData.parentsEmail,Validators.email], school:this.personalData.school, grade:this.personalData.grade, diff --git a/src/app/signup/core/customValidationModule.ts b/src/app/signup/core/customValidationModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..88be80ef2135470dd5b9b3fd6eec932a0c570d5b --- /dev/null +++ b/src/app/signup/core/customValidationModule.ts @@ -0,0 +1,45 @@ +import { FormGroup, FormControl, FormGroupDirective, NgForm, ValidatorFn } from '@angular/forms'; +import { ErrorStateMatcher } from '@angular/material'; + +//from https://obsessiveprogrammer.com/validating-confirmation-fields-in-angular-reactive-forms-with-angular-material/ + +/** + * Custom validator functions for reactive form validation + */ +export class CustomValidators { + /** + * Validates that child controls in the form group are equal + */ + static childrenEqual: ValidatorFn = (formGroup: FormGroup) => { + const [firstControlName, ...otherControlNames] = Object.keys(formGroup.controls || {}); + const isValid = otherControlNames.every(controlName => formGroup.get(controlName).value === formGroup.get(firstControlName).value); + return isValid ? null : { childrenNotEqual: true }; + } +} + +/** + * Custom ErrorStateMatcher which returns true (error exists) when the parent form group is invalid and the control has been touched + */ +export class ConfirmValidParentMatcher implements ErrorStateMatcher { + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + return control.parent.invalid && control.touched; + } +} + +/** +* Collection of reusable RegExps +*/ +// export const regExps: { [key: string]: RegExp } = { +// password: /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{7,15}$/ +// }; + +/** + * Collection of reusable error messages + */ +export const errorMessages: { [key: string]: string } = { + fullName: 'Full name must be between 1 and 128 characters', + email: 'La forme de l\'adresse email doit être valide (username@domain)', + confirmEmail: 'Les adresses email doivent être identiques', + // password: 'Password must be between 7 and 15 characters, and contain at least one number and special character', + confirmPassword: 'Les mots de passe doivent être identiques' +}; \ No newline at end of file diff --git a/src/app/signup/core/index.ts b/src/app/signup/core/index.ts index dbcc0f66bb1c8b7aaa99783d11c58cd70ec1a3e7..87667362fa92fa1613bd141b5235dd70d8f66502 100644 --- a/src/app/signup/core/index.ts +++ b/src/app/signup/core/index.ts @@ -2,5 +2,4 @@ export * from './registration.model'; export * from './registration.service'; export * from './personnalData.model'; export * from './personnalData.service'; -export * from './password.matcher'; -// commentaire \ No newline at end of file + diff --git a/src/app/signup/core/password.matcher.ts b/src/app/signup/core/password.matcher.ts deleted file mode 100644 index 8d9f40ed61fbbfc2adf88f6fdd2ad071e1681abe..0000000000000000000000000000000000000000 --- a/src/app/signup/core/password.matcher.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; -import { ErrorStateMatcher } from '@angular/material'; - -// From: https://stackoverflow.com/a/51606362 -export class PasswordErrorStateMatcher implements ErrorStateMatcher { - isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const invalidParent = !!(control && control.parent && control.parent.invalid && control.parent.dirty); - return (control && control.dirty && invalidParent); - } -} diff --git a/src/app/signup/student-signup/student-signup.component.html b/src/app/signup/student-signup/student-signup.component.html index 31e460d98d2eb944c214c92d8d263b7074be2824..adfec04b0b25894e2d2807a4ff752f06c3ed3fed 100644 --- a/src/app/signup/student-signup/student-signup.component.html +++ b/src/app/signup/student-signup/student-signup.component.html @@ -1,29 +1,38 @@ <app-form-page> - <form [formGroup]="formGroup" (ngSubmit)="submit()"> + <!-- <form [formGroup]="formGroup" (ngSubmit)="submit()"> --> - <h1>Inscription</h1> + <!-- <h1>Inscription</h1> <p> Bienvenue ! Procédons à ton inscription sur l'espace lycéens. - </p> + </p> --> - <!-- First name --> - <mat-form-field class="full-width"> + <!-- First name --> + <!-- <mat-form-field class="full-width"> <input matInput type="text" formControlName="firstName" placeholder="Prénom" required> - </mat-form-field> + </mat-form-field> --> - <!-- Last name --> - <mat-form-field class="full-width"> + <!-- Last name --> + <!-- <mat-form-field class="full-width"> <input matInput type="text" formControlName="lastName" placeholder="Nom" required> - </mat-form-field> + </mat-form-field> --> - <!-- Email --> - <mat-form-field class="full-width"> + <!-- Email --> + <!-- <mat-form-field class="full-width"> <input matInput type="email" formControlName="email" placeholder="Adresse email" required> <mat-hint> Elle te servira d'identifiant de connexion. </mat-hint> + </mat-form-field> --> + + <!-- Confirm Email --> + <!-- <mat-form-field class="full-width"> + <input matInput type="email" formControlName="emailConfirm" placeholder="Confirmer l'adresse email" + [errorStateMatcher]="emailMatcher"> + <mat-error *ngIf="formGroup.hasError('emailsDifferent')"> + Les adresses emails doivent être identiques. + </mat-error> </mat-form-field> <mat-form-field class="full-width"> @@ -36,17 +45,17 @@ <p> Il ne te reste plus qu'à choisir un mot de passe. :-) - </p> - - <!-- Password --> - <mat-form-field class="full-width"> + </p> --> + + <!-- Password --> + <!-- <mat-form-field class="full-width"> <input matInput type="password" formControlName="password" placeholder="Mot de passe" required> - </mat-form-field> + </mat-form-field> --> - <!-- Confirm password --> - <mat-form-field class="full-width"> + <!-- Confirm password --> + <!-- <mat-form-field class="full-width"> <input matInput type="password" formControlName="passwordConfirm" placeholder="Confirmer le mot de passe" - [errorStateMatcher]="matcher"> + [errorStateMatcher]="passwordMatcher"> <mat-error *ngIf="formGroup.hasError('passwordsDifferent')"> Les mots de passe doivent être identiques. </mat-error> @@ -60,9 +69,93 @@ </div> <p class="text-center">{{error}}</p> + <p class="text-center"> + J'ai déjà un compte ! <a routerLink="/connexion">Me connecter</a> + </p> --> + <!-- </form> --> + + <form [formGroup]="formGroup" novalidate> + + <h1>Inscription</h1> + + <p> + Bienvenue ! Procédons à ton inscription sur l'espace lycéens. + </p> + + <!-- First name --> + <mat-form-field class="full-width"> + <input matInput type="text" formControlName="firstName" placeholder="Prénom" required> + </mat-form-field> + + <!-- Last name --> + <mat-form-field class="full-width"> + <input matInput type="text" formControlName="lastName" placeholder="Nom" required> + </mat-form-field> + + <!-- Email --> + <div formGroupName="emailGroup"> + <mat-form-field class="full-width"> + <input matInput placeholder="Adresse email *" type="email" formControlName="email"> + <mat-hint> + Elle te servira d'identifiant de connexion. + </mat-hint> + <mat-error> + {{errors.email}} + </mat-error> + </mat-form-field> + + <br /> + + <mat-form-field class="full-width"> + <input matInput placeholder="Confirmer l'adresse email" type="email" formControlName="confirmEmail" + [errorStateMatcher]="confirmValidParentMatcher"> + <mat-error> + {{errors.confirmEmail}} + </mat-error> + </mat-form-field> + </div> + + + <mat-form-field class="full-width"> + <input matInput type="tel" formControlName="phoneNumber" placeholder="Numéro de téléphone" required> + <mat-hint> + Il nous permettra de te contacter en cas de nécessité. + </mat-hint> + </mat-form-field> + + <p> + Il ne te reste plus qu'à choisir un mot de passe. :-) + </p> + + <!-- Password --> + <div formGroupName="passwordGroup"> + <mat-form-field class="full-width"> + <input matInput placeholder="Mot de passe *" type="password" formControlName="password"> + <mat-error> + {{errors.password}} + </mat-error> + </mat-form-field> + + <br /> + + <mat-form-field class="full-width"> + <input matInput placeholder="Confirmer le mot de passe" type="password" formControlName="confirmPassword" + [errorStateMatcher]="confirmValidParentMatcher"> + <mat-error> + {{errors.confirmPassword}} + </mat-error> + </mat-form-field> + </div> + + <div class="text-center"> + <button mat-raised-button color="primary" [disabled]="!formGroup.valid || loading">M'inscrire + <app-load-spinner *ngIf="loading" [block]="false"></app-load-spinner> + </button> + </div> <p class="text-center"> J'ai déjà un compte ! <a routerLink="/connexion">Me connecter</a> </p> + </form> </app-form-page> diff --git a/src/app/signup/student-signup/student-signup.component.ts b/src/app/signup/student-signup/student-signup.component.ts index 398a968772ff0e1f237e32c0925fa3e8d572544e..3b3585952e82ad353b64997c8bcda7663f5a8299 100644 --- a/src/app/signup/student-signup/student-signup.component.ts +++ b/src/app/signup/student-signup/student-signup.component.ts @@ -2,9 +2,10 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { MatSnackBar } from '@angular/material'; -import { Observable } from 'rxjs'; +// import { Observable } from 'rxjs'; import { tap, mergeMap } from 'rxjs/operators'; -import { Registration, RegistrationService, PasswordErrorStateMatcher,PersonnalData,PersonnalDataService } from '../core'; +import { Registration, RegistrationService, PersonnalData, PersonnalDataService } from '../core'; +import { CustomValidators, ConfirmValidParentMatcher, errorMessages } from '../core/customValidationModule'; import { AuthService } from 'app/core'; @@ -13,109 +14,266 @@ import { AuthService } from 'app/core'; templateUrl: './student-signup.component.html', styleUrls: ['./student-signup.component.scss'] }) +// export class StudentSignupComponent implements OnInit { + +// registration: Registration; +// personnalData: PersonnalData +// formGroup: FormGroup; +// error: String; +// loading = false; +// public showPersonnalDataForm = false; +// public zipPattern = new RegExp(/^\d{5}(?:\d{2})?$/) +// public possibleParentsStatus = [ +// { id: "maried", name: "Mariés" }, +// { id: "divorced", name: "Divorcés" }, +// { id: "cohabitation", name: "En concubinage" }, +// { id: "monoparental", name: "Famille monoparentale" } +// ] + +// public possibleParentsActivities = [ +// { id: "farmer", name: "Agriculteur" }, +// { id: "artisan", name: "Artisan, commerçant, chef d'entreprise" }, +// { id: "executive", name: "Cadre, profession intellectuelle supérieure" }, +// { id: "teacher", name: "Enseignant et assimilé" }, +// { id: "intermediate", name: "Profession intermédiaire" }, +// { id: "employee", name: "Employé" }, +// { id: "worker", name: "Ouvrier" }, +// { id: "retreated", name: "Retraité" }, +// { id: "inactive", name: "Inactif" }, +// { id: "other", name: "Autre" } +// ] + +// public possibleScholarships = [ +// { id: "echelon1", name: "Oui, échelon 1" }, +// { id: "echelon2", name: "Oui, échelon 2" }, +// { id: "echelon3", name: "Oui, échelon 3" }, +// { id: "echelon4", name: "Oui, échelon 4" }, +// { id: "echelon5", name: "Oui, échelon 5" }, +// { id: "echelon6", name: "Oui, échelon 6" }, +// { id: "no", name: "Non" }, +// ] + +// passwordMatcher = new PasswordErrorStateMatcher(); +// emailMatcher = new EmailErrorStateMatcher(); + +// constructor( +// private registrationService: RegistrationService, +// private personnalDataService: PersonnalDataService, +// private formBuilder: FormBuilder, +// private router: Router, +// private auth: AuthService, +// private snackBar: MatSnackBar, + +// ) { } + +// ngOnInit() { +// this.createForm(); +// } + +// createForm() { + +// this.formGroup = this.formBuilder.group({ +// firstName: '', +// lastName: '', +// email: ['', Validators.email], +// emailConfirm: '', +// phoneNumber: '', +// gender: '', +// adressNumber: '', +// street: '', +// zipCode: ['', Validators.pattern(this.zipPattern)], +// city: '', +// personnalPhone: '', +// parentsPhone: '', +// parentsEmail: ['', Validators.email], +// school: '', +// grade: '', +// section: '', +// specialTeaching: '', +// scholarship: '', +// fatherActivity: '', +// motherActivity: '', +// parentsStatus: '', +// dependantsNumber: '', +// password: '', +// passwordConfirm: '', +// agree: [false, Validators.required], +// filledForm: false, +// acceptedConditions: false, +// }, { validator: (group) => this.checkPasswords(group) && this.checkEmails(group) }) +// console.log(this.formGroup.value.agree) +// } + +// private checkPasswords(group: FormGroup): null | any { +// const password = group.controls.password.value; +// const passwordConfirm = group.controls.passwordConfirm.value; +// return password === passwordConfirm ? null : { passwordsDifferent: true }; +// } +// private checkEmails(group: FormGroup): null | any { +// const email = group.controls.email.value; +// const emailConfirm = group.controls.emailConfirm.value; +// return email === emailConfirm ? null : { emailsDifferent: true }; +// } + +// toggleShowPersonnalDataForm() { +// this.showPersonnalDataForm = !this.showPersonnalDataForm; +// } +// submit() { +// this.loading = true; +// const { email, firstName, lastName, phoneNumber } = this.formGroup.value +// //const {gender,adressNumber,street,zipCode,city,personnalPhone,parentsPhone,parentsEmail,school,grade,section,specialTeaching,scholarship,fatherActivity,motherActivity,parentsStatus,dependantsNumber} = this.formGroup.value; +// const registration: Registration = { email, firstName, lastName, phoneNumber }; +// // const personnalData: PersonnalData = {gender,adressNumber,street,zipCode,city,personnalPhone,parentsPhone,parentsEmail,school,grade,section,specialTeaching,scholarship,fatherActivity,motherActivity,parentsStatus,dependantsNumber}; + +// const password: string = this.formGroup.controls.password.value; +// this.registrationService.create(registration, password).pipe( +// mergeMap(() => this.auth.login(registration.email, password)), +// tap(() => this.snackBar.open( +// `Ton compte a été créé ! Tu es maintenant connecté.`, +// 'OK', +// { duration: 3000 }, +// )), +// tap(() => this.error = ""), +// tap(() => this.loading = false), +// tap(() => { +// setTimeout(() => { +// this.router.navigate(['./membres']) + +// }, 3000) +// }) + +// ).subscribe( +// () => { }, +// (error) => { + + +// this.loading = false + +// if (error.error.email) { +// this.error = "Erreur, cet email est déjà utilisé !" +// } +// } +// ); +// // this.personnalDataService.create(personnalData).pipe( +// // tap(() => this.loading = false), +// // tap(() => this.router.navigate(['/'])), +// // ).subscribe( +// // () => {}, +// // (error) => this.loading = false, +// // ); +// } +// } + export class StudentSignupComponent implements OnInit { registration: Registration; - personnalData: PersonnalData + personnalData: PersonnalData; formGroup: FormGroup; error: String; loading = false; public showPersonnalDataForm = false; public zipPattern = new RegExp(/^\d{5}(?:\d{2})?$/) public possibleParentsStatus = [ - {id:"maried",name:"Mariés"}, - {id:"divorced",name:"Divorcés"}, - {id:"cohabitation",name:"En concubinage"}, - {id:"monoparental",name:"Famille monoparentale"} + { id: "maried", name: "Mariés" }, + { id: "divorced", name: "Divorcés" }, + { id: "cohabitation", name: "En concubinage" }, + { id: "monoparental", name: "Famille monoparentale" } ] public possibleParentsActivities = [ - {id:"farmer",name:"Agriculteur"}, - {id:"artisan",name:"Artisan, commerçant, chef d'entreprise"}, - {id:"executive",name:"Cadre, profession intellectuelle supérieure"}, - {id:"teacher",name:"Enseignant et assimilé"}, - {id:"intermediate",name:"Profession intermédiaire"}, - {id:"employee",name:"Employé"}, - {id:"worker",name:"Ouvrier"}, - {id:"retreated",name:"Retraité"}, - {id:"inactive",name:"Inactif"}, - {id:"other",name:"Autre"} + { id: "farmer", name: "Agriculteur" }, + { id: "artisan", name: "Artisan, commerçant, chef d'entreprise" }, + { id: "executive", name: "Cadre, profession intellectuelle supérieure" }, + { id: "teacher", name: "Enseignant et assimilé" }, + { id: "intermediate", name: "Profession intermédiaire" }, + { id: "employee", name: "Employé" }, + { id: "worker", name: "Ouvrier" }, + { id: "retreated", name: "Retraité" }, + { id: "inactive", name: "Inactif" }, + { id: "other", name: "Autre" } ] public possibleScholarships = [ - {id:"echelon1",name:"Oui, échelon 1"}, - {id:"echelon2",name:"Oui, échelon 2"}, - {id:"echelon3",name:"Oui, échelon 3"}, - {id:"echelon4",name:"Oui, échelon 4"}, - {id:"echelon5",name:"Oui, échelon 5"}, - {id:"echelon6",name:"Oui, échelon 6"}, - {id:"no",name:"Non"}, + { id: "echelon1", name: "Oui, échelon 1" }, + { id: "echelon2", name: "Oui, échelon 2" }, + { id: "echelon3", name: "Oui, échelon 3" }, + { id: "echelon4", name: "Oui, échelon 4" }, + { id: "echelon5", name: "Oui, échelon 5" }, + { id: "echelon6", name: "Oui, échelon 6" }, + { id: "no", name: "Non" }, ] + confirmValidParentMatcher = new ConfirmValidParentMatcher(); //ajouté - matcher = new PasswordErrorStateMatcher(); + errors = errorMessages; //ajouté constructor( private registrationService: RegistrationService, - private personnalDataService : PersonnalDataService, + // private personnalDataService: PersonnalDataService, private formBuilder: FormBuilder, private router: Router, private auth: AuthService, private snackBar: MatSnackBar, - - ) { } + + ) { + } ngOnInit() { this.createForm(); } createForm() { - this.formGroup = this.formBuilder.group({ firstName: '', lastName: '', - email: ['', Validators.email], + emailGroup: this.formBuilder.group({ + email: ['', [ + Validators.required, + Validators.email + ]], + confirmEmail: ['', Validators.required] + }, { validator: CustomValidators.childrenEqual }), phoneNumber: '', - gender:'', - adressNumber:'', - street:'', - zipCode:['',Validators.pattern(this.zipPattern)], - city:'', - personnalPhone:'', - parentsPhone:'', - parentsEmail:['',Validators.email], - school:'', - grade:'', - section:'', - specialTeaching:'', - scholarship:'', - fatherActivity:'', - motherActivity:'', - parentsStatus:'', - dependantsNumber:'', - password: '', - passwordConfirm: '', + gender: '', + adressNumber: '', + street: '', + zipCode: ['', Validators.pattern(this.zipPattern)], + city: '', + personnalPhone: '', + parentsPhone: '', + parentsEmail: ['', Validators.email], + school: '', + grade: '', + section: '', + specialTeaching: '', + scholarship: '', + fatherActivity: '', + motherActivity: '', + parentsStatus: '', + dependantsNumber: '', + passwordGroup: this.formBuilder.group({ + password: ['', [ + Validators.required, + // Validators.pattern(regExps.password) /si l'on veut ajouter une condition au mdp (en définissant regExps dans ../core/customValidationModule.ts) + ]], + confirmPassword: ['', Validators.required] + }, { validator: CustomValidators.childrenEqual }), agree: [false, Validators.required], filledForm: false, acceptedConditions: false, - }, { validator: (group) => this.checkPasswords(group)},) - console.log(this.formGroup.value.agree) + }); } - private checkPasswords(group: FormGroup): null | any { - const password = group.controls.password.value; - const passwordConfirm = group.controls.passwordConfirm.value; - return password === passwordConfirm ? null : { passwordsDifferent: true }; - } - toggleShowPersonnalDataForm(){ + //dernières lignes ajoutées (jusqu'au register): + toggleShowPersonnalDataForm() { this.showPersonnalDataForm = !this.showPersonnalDataForm; } submit() { this.loading = true; - const {email,firstName,lastName,phoneNumber} = this.formGroup.value + const { email, firstName, lastName, phoneNumber } = this.formGroup.value //const {gender,adressNumber,street,zipCode,city,personnalPhone,parentsPhone,parentsEmail,school,grade,section,specialTeaching,scholarship,fatherActivity,motherActivity,parentsStatus,dependantsNumber} = this.formGroup.value; - const registration: Registration = {email,firstName,lastName,phoneNumber}; - // const personnalData: PersonnalData = {gender,adressNumber,street,zipCode,city,personnalPhone,parentsPhone,parentsEmail,school,grade,section,specialTeaching,scholarship,fatherActivity,motherActivity,parentsStatus,dependantsNumber}; - + const registration: Registration = { email, firstName, lastName, phoneNumber }; + // const personnalData: PersonnalData = {gender,adressNumber,street,zipCode,city,personnalPhone,parentsPhone,parentsEmail,school,grade,section,specialTeaching,scholarship,fatherActivity,motherActivity,parentsStatus,dependantsNumber}; + const password: string = this.formGroup.controls.password.value; this.registrationService.create(registration, password).pipe( mergeMap(() => this.auth.login(registration.email, password)), @@ -124,32 +282,39 @@ export class StudentSignupComponent implements OnInit { 'OK', { duration: 3000 }, )), - tap(()=> this.error = ""), + + tap(() => this.error = ""), tap(() => this.loading = false), tap(() => { - setTimeout(()=>{ + setTimeout(() => { this.router.navigate(['./membres']) - - },3000)}) - + + }, 3000) + }) + ).subscribe( - () => {}, - (error) => { - + () => { }, + (error) => { + - this.loading=false - - if(error.error.email){ + this.loading = false + + if (error.error.email) { this.error = "Erreur, cet email est déjà utilisé !" } - } + } + ); // this.personnalDataService.create(personnalData).pipe( // tap(() => this.loading = false), // tap(() => this.router.navigate(['/'])), // ).subscribe( - // () => {}, + // () => { }, // (error) => this.loading = false, // ); } + + register(): void { + // API call to register your user + } //ajouté (inutile?) }