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