From 60fa0c8e41df9c82e5d6957dd752e4c210c4c9c8 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Tue, 16 Feb 2021 12:07:38 +0100 Subject: [PATCH] feat: add registration form from email --- src/app/app-routing.module.ts | 9 ++ src/app/app.module.ts | 2 + src/app/form/form.component.ts | 108 ++++++++++++++++++------ src/app/models/temp-user.model.ts | 7 ++ src/app/resolvers/temp-user.resolver.ts | 22 +++++ src/app/services/temp-user.service.ts | 16 ++++ 6 files changed, 137 insertions(+), 27 deletions(-) create mode 100644 src/app/models/temp-user.model.ts create mode 100644 src/app/resolvers/temp-user.resolver.ts create mode 100644 src/app/services/temp-user.service.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 993557771..9f29fd079 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -11,6 +11,7 @@ import { LegalNoticeComponent } from './legal-notice/legal-notice.component'; import { ProfileComponent } from './profile/profile.component'; import { ResetEmailComponent } from './reset-email/reset-email.component'; import { ResetPasswordComponent } from './reset-password/reset-password.component'; +import { TempUserResolver } from './resolvers/temp-user.resolver'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureListComponent } from './structure-list/structure-list.component'; import { UserVerificationComponent } from './user-verification/user-verification.component'; @@ -49,6 +50,14 @@ const routes: Routes = [ path: 'users/verify/:id', component: UserVerificationComponent, }, + { + path: 'register', + component: FormComponent, + canDeactivate: [DeactivateGuard], + resolve: { + user: TempUserResolver, + }, + }, { path: 'change-email/:id', component: ResetEmailComponent, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 76b6da88f..25507d5d2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -30,6 +30,7 @@ import { AdminModule } from './admin/admin.module'; import { AdminGuard } from './guards/admin.guard'; import { DeactivateGuard } from './guards/deactivate.guard'; import { FooterFormComponent } from './form/footer-form/footer-form.component'; +import { TempUserResolver } from './resolvers/temp-user.resolver'; @NgModule({ declarations: [ @@ -59,6 +60,7 @@ import { FooterFormComponent } from './form/footer-form/footer-form.component'; AuthGuard, AdminGuard, DeactivateGuard, + TempUserResolver, ], bootstrap: [AppComponent], }) diff --git a/src/app/form/form.component.ts b/src/app/form/form.component.ts index a09015170..a5547fc23 100644 --- a/src/app/form/form.component.ts +++ b/src/app/form/form.component.ts @@ -18,6 +18,7 @@ import { AuthService } from '../services/auth.service'; import { first } from 'rxjs/operators'; import { Regex } from '../shared/enum/regex.enum'; import { PageTypeEnum } from './pageType.enum'; +import { TempUserService } from '../services/temp-user.service'; const { DateTime } = require('luxon'); @Component({ selector: 'app-structureForm', @@ -42,6 +43,7 @@ export class FormComponent implements OnInit { public trainingCategories: { category: Category; openned: boolean }[] = []; public pageTypeEnum = PageTypeEnum; public claimStructure: Structure = null; + public linkedStructureId: Array<string> = null; // Page and progress var public currentPage = 0; @@ -67,6 +69,7 @@ export class FormComponent implements OnInit { public showMenu = false; public isEditMode = false; public isClaimMode = false; + public isAccountMode = false; public isLoading = false; public isWifiChoosen = false; @@ -75,7 +78,9 @@ export class FormComponent implements OnInit { private searchService: SearchService, private profileService: ProfileService, private authService: AuthService, - private router: Router + private tempUserService: TempUserService, + private router: Router, + private route: ActivatedRoute ) {} async ngOnInit(): Promise<void> { @@ -98,6 +103,16 @@ export class FormComponent implements OnInit { } else { this.initForm(new Structure()); } + // Handle account creation when pre-register + this.route.data.subscribe((data) => { + if (data.user) { + this.isAccountMode = true; + this.createAccountForm(data.user.email, data.user.name, data.user.surname); + this.linkedStructureId = data.user.pendingStructuresLink; + this.setValidationsForm(); + this.currentPage = PageTypeEnum.accountInfo; + } + }); } async setCategories(): Promise<void> { @@ -162,13 +177,16 @@ export class FormComponent implements OnInit { this.setValidationsForm(); } - private createAccountForm(): void { + private createAccountForm(email?: string, name?: string, surname?: string): void { this.accountForm = new FormGroup( { - email: new FormControl('', [Validators.required, Validators.pattern(Regex.email)]), //NOSONAR - name: new FormControl('', [Validators.required, Validators.pattern(Regex.textWithoutNumber)]), //NOSONAR - surname: new FormControl('', [Validators.required, Validators.pattern(Regex.textWithoutNumber)]), //NOSONAR - phone: new FormControl('', [Validators.required, Validators.pattern(Regex.phone)]), //NOSONAR + email: new FormControl(email ? email : '', [Validators.required, Validators.pattern(Regex.email)]), + name: new FormControl(name ? name : '', [Validators.required, Validators.pattern(Regex.textWithoutNumber)]), + surname: new FormControl(surname ? surname : '', [ + Validators.required, + Validators.pattern(Regex.textWithoutNumber), + ]), + phone: new FormControl('', [Validators.required, Validators.pattern(Regex.phone)]), password: new FormControl('', [ Validators.required, Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})/), //NOSONAR @@ -192,19 +210,13 @@ export class FormComponent implements OnInit { street: new FormControl(structure.address.street, Validators.required), commune: new FormControl(structure.address.commune, Validators.required), }), - contactMail: new FormControl(structure.contactMail, [ - Validators.required, - Validators.pattern(Regex.email), //NOSONAR - ]), - contactPhone: new FormControl(structure.contactPhone, [ - Validators.required, - Validators.pattern(Regex.phone), //NOSONAR - ]), - website: new FormControl(structure.website, Validators.pattern(Regex.website)), //NOSONAR - facebook: new FormControl(structure.facebook, Validators.pattern(Regex.facebook)), //NOSONAR - twitter: new FormControl(structure.twitter, Validators.pattern(Regex.twitter)), //NOSONAR - instagram: new FormControl(structure.instagram, Validators.pattern(Regex.instagram)), //NOSONAR - linkedin: new FormControl(structure.linkedin, Validators.pattern(Regex.linkedIn)), //NOSONAR + contactMail: new FormControl(structure.contactMail, [Validators.required, Validators.pattern(Regex.email)]), + contactPhone: new FormControl(structure.contactPhone, [Validators.required, Validators.pattern(Regex.phone)]), + website: new FormControl(structure.website, Validators.pattern(Regex.website)), + facebook: new FormControl(structure.facebook, Validators.pattern(Regex.facebook)), + twitter: new FormControl(structure.twitter, Validators.pattern(Regex.twitter)), + instagram: new FormControl(structure.instagram, Validators.pattern(Regex.instagram)), + linkedin: new FormControl(structure.linkedin, Validators.pattern(Regex.linkedIn)), hours: new FormGroup({}), pmrAccess: new FormControl(structure.pmrAccess, Validators.required), exceptionalClosures: new FormControl(structure.exceptionalClosures), @@ -222,24 +234,24 @@ export class FormComponent implements OnInit { digitalCultureSecurity: this.loadArrayForCheckbox(structure.digitalCultureSecurity, false), nbComputers: new FormControl( structure.equipmentsAndServices.includes('ordinateurs') ? structure.nbComputers : 1, - [Validators.required, Validators.pattern(Regex.noNullNumber)] //NOSONAR + [Validators.required, Validators.pattern(Regex.noNullNumber)] ), nbPrinters: new FormControl(structure.equipmentsAndServices.includes('imprimantes') ? structure.nbPrinters : 1, [ Validators.required, - Validators.pattern(Regex.noNullNumber), //NOSONAR + Validators.pattern(Regex.noNullNumber), ]), nbTablets: new FormControl(structure.equipmentsAndServices.includes('tablettes') ? structure.nbTablets : 1, [ Validators.required, - Validators.pattern(Regex.noNullNumber), //NOSONAR + Validators.pattern(Regex.noNullNumber), ]), nbNumericTerminal: new FormControl( structure.equipmentsAndServices.includes('bornesNumeriques') ? structure.nbNumericTerminal : 1, - [Validators.required, Validators.pattern(Regex.noNullNumber)] //NOSONAR - ), - nbScanners: new FormControl( - structure.equipmentsAndServices.includes('scanners') ? structure.nbScanners : 1, - [Validators.required, Validators.pattern(Regex.noNullNumber)] //NOSONAR + [Validators.required, Validators.pattern(Regex.noNullNumber)] ), + nbScanners: new FormControl(structure.equipmentsAndServices.includes('scanners') ? structure.nbScanners : 1, [ + Validators.required, + Validators.pattern(Regex.noNullNumber), + ]), freeWorkShop: new FormControl(structure.freeWorkShop, Validators.required), }); return form; @@ -398,6 +410,21 @@ export class FormComponent implements OnInit { }; this.pagesValidation[PageTypeEnum.cgu] = { valid: this.userAcceptSavedDate }; this.updatePageValid(); + } else if (this.isAccountMode) { + this.pagesValidation[PageTypeEnum.accountInfo] = { + valid: + this.accountForm.get('surname').valid && + this.accountForm.get('name').valid && + this.accountForm.get('phone').valid, + }; + this.pagesValidation[PageTypeEnum.accountCredentials] = { + valid: + this.accountForm.get('email').valid && + this.accountForm.get('password').valid && + this.accountForm.get('confirmPassword').valid, + }; + this.pagesValidation[PageTypeEnum.cgu] = { valid: this.userAcceptSavedDate }; + this.updatePageValid(); } else { this.pagesValidation[PageTypeEnum.summary] = { valid: true }; this.pagesValidation[PageTypeEnum.info] = { valid: true }; @@ -544,6 +571,31 @@ export class FormComponent implements OnInit { this.progressStatus += 25; } + /** + * Page algo for create account case + */ + public nextPageAccount(): void { + if (this.currentPage == this.nbPagesForm - 1) { + const user = new User(this.accountForm.value); + // Create user with structure + user.structuresLink = this.linkedStructureId; + this.authService.register(user).subscribe(() => { + this.progressStatus = 100; + }); + } + + if (this.currentPage == PageTypeEnum.accountInfo) { + this.currentPage = PageTypeEnum.accountCredentials; + this.updatePageValid(); + } else if (this.currentPage == PageTypeEnum.accountCredentials) { + this.currentPage = PageTypeEnum.cgu; + this.updatePageValid(); + } else if (this.currentPage == PageTypeEnum.cgu) { + this.currentPage = this.nbPagesForm; + } + + this.progressStatus += 25; + } /** * Page algo for claim structure case @@ -566,6 +618,8 @@ export class FormComponent implements OnInit { public nextPage(): void { if (this.isClaimMode) { this.nextPageClaim(); + } else if (this.isAccountMode) { + this.nextPageAccount(); } else { // Check if user already connected to skip accountForm pages. if (this.currentPage == PageTypeEnum.info && this.profile) { diff --git a/src/app/models/temp-user.model.ts b/src/app/models/temp-user.model.ts new file mode 100644 index 000000000..5a487980f --- /dev/null +++ b/src/app/models/temp-user.model.ts @@ -0,0 +1,7 @@ +export class TempUser { + _id: string; + email: string; + name: string; + surname: string; + pendingStructuresLink: string[]; +} diff --git a/src/app/resolvers/temp-user.resolver.ts b/src/app/resolvers/temp-user.resolver.ts new file mode 100644 index 000000000..2ae604aa6 --- /dev/null +++ b/src/app/resolvers/temp-user.resolver.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import { map, catchError } from 'rxjs/operators'; +import { TempUser } from '../models/temp-user.model'; +import { TempUserService } from '../services/temp-user.service'; + +@Injectable() +export class TempUserResolver implements Resolve<TempUser> { + constructor(private tempUserService: TempUserService, private router: Router) {} + + resolve(route: ActivatedRouteSnapshot): Observable<TempUser> { + const userId = route.queryParams.id; + return this.tempUserService.getUser(userId).pipe( + map((res) => res), + catchError(() => { + this.router.navigate(['/home']); + return new Observable<TempUser>(); + }) + ); + } +} diff --git a/src/app/services/temp-user.service.ts b/src/app/services/temp-user.service.ts new file mode 100644 index 000000000..4dd2b4524 --- /dev/null +++ b/src/app/services/temp-user.service.ts @@ -0,0 +1,16 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { TempUser } from '../models/temp-user.model'; + +@Injectable({ + providedIn: 'root', +}) +export class TempUserService { + private readonly baseUrl = 'api/temp-user'; + constructor(private http: HttpClient) {} + + public getUser(id: string): Observable<TempUser> { + return this.http.get<TempUser>(`${this.baseUrl}/${id}`); + } +} -- GitLab