From 0545c60a014a3a86e44ab3698dff3e7a9c5a703d Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 23 Feb 2021 15:54:12 +0100
Subject: [PATCH] fix(profile) : export logic to new component

---
 src/app/profile/profile.component.html        | 255 +-----------------
 src/app/profile/profile.component.ts          | 228 +---------------
 src/app/profile/profile.module.ts             |   3 +-
 src/app/shared/components/index.ts            |   6 +
 .../modal-options.component.html              |   0
 .../modal-options.component.scss              |   8 +-
 .../modal-options.component.spec.ts           |   0
 .../modal-options/modal-options.component.ts  |   2 +-
 .../structure-options-modal.component.html    | 226 ++++++++++++++++
 .../structure-options-modal.component.scss    |  86 ++++++
 .../structure-options-modal.component.spec.ts |  24 ++
 .../structure-options-modal.component.ts      | 236 ++++++++++++++++
 .../enum/functionTypeModalOptions.enum.ts     |   0
 src/styles.scss                               |   1 +
 14 files changed, 594 insertions(+), 481 deletions(-)
 rename src/app/{profile => shared/components}/modal-options/modal-options.component.html (100%)
 rename src/app/{profile => shared/components}/modal-options/modal-options.component.scss (78%)
 rename src/app/{profile => shared/components}/modal-options/modal-options.component.spec.ts (100%)
 rename src/app/{profile => shared/components}/modal-options/modal-options.component.ts (86%)
 create mode 100644 src/app/shared/components/structure-options-modal/structure-options-modal.component.html
 create mode 100644 src/app/shared/components/structure-options-modal/structure-options-modal.component.scss
 create mode 100644 src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts
 create mode 100644 src/app/shared/components/structure-options-modal/structure-options-modal.component.ts
 rename src/app/{profile => shared}/enum/functionTypeModalOptions.enum.ts (100%)

diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html
index 3ef2c4743..96e8c9734 100644
--- a/src/app/profile/profile.component.html
+++ b/src/app/profile/profile.component.html
@@ -13,26 +13,10 @@
           <span>Identifiant</span>
           <div fxLayout="row" fxLayoutAlign="space-between center">
             <p>{{ userProfile.email }}</p>
-            <nav aria-label="modalOption">
-              <ul>
-                <li>
-                  <button
-                    [ngClass]="{ active: isModalOptsProfile }"
-                    (click)="openModalOptsProfile()"
-                    class="btn-primary transparent"
-                  >
-                    <app-svg-icon [type]="'ico'" [iconColor]="inherit" [icon]="'moreOpts'"></app-svg-icon>
-                  </button>
-                  <ul *ngIf="isModalOptsProfile" class="dropdown">
-                    <app-modal-options
-                      [isModalProfileOpts]="true"
-                      [hasOwners]="false"
-                      (closed)="closeModalOpts($event)"
-                    ></app-modal-options>
-                  </ul>
-                </li>
-              </ul>
-            </nav>
+            <app-structure-options-modal
+              [userProfile]="userProfile"
+              (closed)="ngOnInit()"
+            ></app-structure-options-modal>
           </div>
         </div>
       </div>
@@ -47,26 +31,7 @@
               <a class="structureName" routerLink="/home" [state]="{ data: s.structure }">{{
                 s.structure.structureName
               }}</a>
-              <nav aria-label="modalOption">
-                <ul>
-                  <li>
-                    <button
-                      [ngClass]="{ active: modalOptsStructureIndex == i }"
-                      (click)="openModalOptsStructure(i, s)"
-                      class="btn-primary transparent"
-                    >
-                      <app-svg-icon [type]="'ico'" [iconColor]="inherit" [icon]="'moreOpts'"></app-svg-icon>
-                    </button>
-                    <ul *ngIf="modalOptsStructureIndex == i" class="dropdown">
-                      <app-modal-options
-                        [isModalProfileOpts]="false"
-                        [hasOwners]="currentStructureOwners.owners.length > 0"
-                        (closed)="closeModalOpts($event)"
-                      ></app-modal-options>
-                    </ul>
-                  </li>
-                </ul>
-              </nav>
+              <app-structure-options-modal [structure]="s" (closed)="ngOnInit()"></app-structure-options-modal>
             </div>
             <div fxLayout="column" fxLayoutGap="14px">
               <p class="ownerName" *ngFor="let owner of s.owners">{{ owner.email }}</p>
@@ -99,213 +64,3 @@
     </div>
   </div>
 </div>
-<div *ngIf="editModal" class="modalBackground">
-  <div class="modal" (clickOutside)="closeModalOptsProfile()">
-    <form
-      *ngIf="editModal == typeModalProfile.password"
-      [formGroup]="formPassword"
-      class="contentModal"
-      fxLayout="column"
-      fxLayoutAlign="center start"
-      fxLayoutGap="20px"
-    >
-      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
-        <h2>Changer de mot de passe</h2>
-        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
-      </div>
-      <div class="form-group" fxLayout="column" fxLayoutGap="4px">
-        <label for="oldPassword">Ancien mot de passe</label>
-        <p *ngIf="passwordError" class="special invalid">Votre ancien mot de passe est incorrect.</p>
-        <div fxLayout="row" fxLayoutGap="13px">
-          <input
-            [type]="isShowOldPassword ? 'text' : 'password'"
-            formControlName="oldPassword"
-            class="form-input password"
-            autocomplete="on"
-          />
-          <app-svg-icon
-            (click)="showOldPassword()"
-            [type]="'form'"
-            [iconClass]="'grey'"
-            [icon]="'eyePassword'"
-          ></app-svg-icon>
-          <app-svg-icon *ngIf="passwordError" [type]="'form'" [icon]="'notValidate'"></app-svg-icon>
-        </div>
-      </div>
-      <div class="form-group" fxLayout="column">
-        <label for="password">Nouveau mot de passe</label>
-        <p class="special" [ngClass]="{ invalid: fpass.password.invalid && fpass.password.value }">
-          Le mot de passe doit contenir au minimum : 8 caractères dont un caractère spécial, un caractère en majuscule
-          et un chiffre.
-        </p>
-        <div fxLayout="row" fxLayoutGap="13px">
-          <input
-            [type]="isShowPassword ? 'text' : 'password'"
-            formControlName="password"
-            class="form-input password"
-            autocomplete="on"
-          />
-          <app-svg-icon
-            (click)="showPassword()"
-            [type]="'form'"
-            [iconClass]="'grey'"
-            [icon]="'eyePassword'"
-          ></app-svg-icon>
-          <app-svg-icon *ngIf="fpass.password.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
-          <app-svg-icon
-            *ngIf="fpass.password.invalid && fpass.password.value"
-            [type]="'form'"
-            [icon]="'notValidate'"
-          ></app-svg-icon>
-        </div>
-      </div>
-      <div class="form-group" fxLayout="column">
-        <label for="confirmPassword">Confirmation du mot de passe</label>
-        <div fxLayout="row" fxLayoutGap="13px">
-          <input
-            [type]="isShowConfirmPassword ? 'text' : 'password'"
-            formControlName="confirmPassword"
-            class="form-input password"
-            autocomplete="on"
-          />
-          <app-svg-icon
-            (click)="showConfirmPassword()"
-            [type]="'form'"
-            [iconClass]="'grey'"
-            [icon]="'eyePassword'"
-          ></app-svg-icon>
-          <app-svg-icon
-            *ngIf="fpass.confirmPassword.valid && fpass.password.value"
-            [type]="'form'"
-            [icon]="'validate'"
-          ></app-svg-icon>
-          <app-svg-icon
-            *ngIf="fpass.confirmPassword.invalid && fpass.confirmPassword.value"
-            [type]="'form'"
-            [icon]="'notValidate'"
-          ></app-svg-icon>
-        </div>
-      </div>
-      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
-        <button
-          type="submit"
-          [ngClass]="{ invalid: formPassword.invalid }"
-          class="btn-primary small leave"
-          (click)="submitPassword()"
-        >
-          Valider
-        </button>
-      </div>
-    </form>
-    <form
-      *ngIf="editModal == typeModalProfile.email"
-      [formGroup]="formEmail"
-      class="contentModal"
-      fxLayout="column"
-      fxLayoutAlign="center start"
-    >
-      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
-        <h2>Changer de courriel</h2>
-        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
-      </div>
-      <div class="form-group" fxLayout="column">
-        <label for="email">Nouveau courriel</label>
-        <p class="special invalid" *ngIf="this.fmail.email.hasError('alreadyExist')">L'email est déja utilisé.</p>
-        <div fxLayout="row" fxLayoutGap="13px">
-          <input
-            type="text"
-            formControlName="email"
-            class="form-input"
-            autocomplete="on"
-            (keyup)="verifyEmailAlreadyUsed($event.target.value, this.fmail.email)"
-          />
-          <app-svg-icon *ngIf="fmail.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
-          <app-svg-icon
-            *ngIf="fmail.email.invalid && fmail.email.value"
-            [type]="'form'"
-            [icon]="'notValidate'"
-          ></app-svg-icon>
-        </div>
-      </div>
-      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
-        <button
-          type="submit"
-          [ngClass]="{ invalid: formEmail.invalid }"
-          class="btn-primary small leave"
-          (click)="submitEmail()"
-        >
-          Valider
-        </button>
-      </div>
-    </form>
-    <div
-      *ngIf="editModal == typeModalProfile.deleteAccount"
-      class="contentModal"
-      fxLayout="column"
-      fxLayoutAlign="center start"
-      fxLayoutGap="30px"
-    >
-      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
-        <h2>Supprimer un compte</h2>
-        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
-      </div>
-      <div fxLayout="column" fxLayoutGap="16px">
-        <div class="row removeOwner" *ngFor="let owner of currentStructureOwners.owners" fxLayoutGap="16px">
-          <button class="btn-primary small" (click)="removeOwner(owner.id)">X</button>
-          <span>
-            {{ owner.email }}
-          </span>
-        </div>
-      </div>
-      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
-        <button type="button" class="btn-primary small leave" (click)="closeModalOptsProfile()">Terminer</button>
-      </div>
-    </div>
-    <form
-      *ngIf="editModal == typeModalProfile.addAccount"
-      [formGroup]="formAddAccount"
-      class="contentModal"
-      fxLayout="column"
-      fxLayoutAlign="center start"
-      fxLayoutGap="30px"
-    >
-      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
-        <h2>Ajouter un compte</h2>
-        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
-      </div>
-      <div class="form-group" fxLayout="column">
-        <label for="email">Courriel du compte à ajouter</label>
-        <p *ngIf="ownerAlreadyLinked" class="special invalid">L'email est déjà rattaché à la structure.</p>
-        <div fxLayout="row" fxLayoutGap="13px">
-          <input type="text" formControlName="email" class="form-input" autocomplete="on" />
-          <app-svg-icon *ngIf="fAddAccount.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
-          <app-svg-icon
-            *ngIf="fAddAccount.email.invalid && fAddAccount.email.value"
-            [type]="'form'"
-            [icon]="'notValidate'"
-          ></app-svg-icon>
-        </div>
-      </div>
-      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
-        <button
-          type="submit"
-          [ngClass]="{ invalid: formAddAccount.invalid }"
-          class="btn-primary small leave"
-          (click)="addOwner()"
-        >
-          Envoyer
-        </button>
-      </div>
-    </form>
-  </div>
-</div>
-<app-modal-confirmation
-  [openned]="deleteModalStructureOpenned"
-  [content]="'Voulez-vous vraiment supprimer cette structure ?'"
-  (closed)="deleteStructure($event)"
-></app-modal-confirmation>
-<app-modal-confirmation
-  [openned]="deleteModalAccountOpenned"
-  [content]="'Voulez-vous vraiment supprimer votre compte ?'"
-  (closed)="deleteAccount($event)"
-></app-modal-confirmation>
diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts
index 67cb92574..0b3b1d36c 100644
--- a/src/app/profile/profile.component.ts
+++ b/src/app/profile/profile.component.ts
@@ -1,16 +1,9 @@
 import { Component, OnInit } from '@angular/core';
-import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
 import { Router } from '@angular/router';
-import { Structure } from '../models/structure.model';
 import { StructureWithOwners } from '../models/structureWithOwners.model';
-import { TempUser } from '../models/temp-user.model';
 import { User } from '../models/user.model';
 import { AuthService } from '../services/auth.service';
 import { StructureService } from '../services/structure.service';
-import { MustMatch } from '../shared/validator/form';
-import { CustomRegExp } from '../utils/CustomRegExp';
-import { FunctionTypeModalOptions } from './enum/functionTypeModalOptions.enum';
-import { TypeModalProfile } from './enum/TypeModalProfile.enum';
 import { ProfileService } from './services/profile.service';
 
 @Component({
@@ -19,42 +12,14 @@ import { ProfileService } from './services/profile.service';
   styleUrls: ['./profile.component.scss'],
 })
 export class ProfileComponent implements OnInit {
-  // Password profile
-  public formPassword: FormGroup;
-  public isShowOldPassword = false;
-  public isShowPassword = false;
-  public isShowConfirmPassword = false;
-  public changePassword = false;
-  public passwordError = false;
-
-  // Email profile
-  public formEmail: FormGroup;
-  public changeEmail = false;
-
-  // formAddAccount
-  public formAddAccount: FormGroup;
-  public ownerAlreadyLinked = false;
-
-  // Global var
   public userProfile: User;
-  public loading = false;
   public structures: StructureWithOwners[] = [];
-  public editModal: TypeModalProfile;
-  public typeModalProfile = TypeModalProfile;
-
-  // Modal options
-  public modalOptsStructureIndex: number;
-  public isModalOptsProfile = false;
-  public currentStructureOwners: StructureWithOwners;
-  public deleteModalStructureOpenned = false;
-  public deleteModalAccountOpenned = false;
 
   constructor(
-    private authService: AuthService,
-    private formBuilder: FormBuilder,
     private profileService: ProfileService,
     private structureService: StructureService,
-    private router: Router
+    private router: Router,
+    private authService: AuthService
   ) {}
 
   ngOnInit(): void {
@@ -67,198 +32,13 @@ export class ProfileComponent implements OnInit {
         });
       });
     });
-    this.initForm();
-  }
-  public initForm(): void {
-    this.formPassword = this.formBuilder.group(
-      {
-        oldPassword: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
-        password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
-        confirmPassword: [''],
-      },
-      { validator: MustMatch('password', 'confirmPassword') }
-    );
-
-    this.formEmail = this.formBuilder.group({
-      email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]],
-    });
-
-    this.formAddAccount = this.formBuilder.group({
-      email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]],
-    });
-  }
-  // getter for form fields
-  get fpass(): { [key: string]: AbstractControl } {
-    return this.formPassword.controls;
-  }
-
-  // getter for form fields
-  get fmail(): { [key: string]: AbstractControl } {
-    return this.formEmail.controls;
-  }
-
-  get fAddAccount(): { [key: string]: AbstractControl } {
-    return this.formAddAccount.controls;
-  }
-
-  public closeModalOpts(functionType: number): void {
-    switch (functionType) {
-      case FunctionTypeModalOptions.changeEmail:
-        this.editModal = TypeModalProfile.email;
-        break;
-      case FunctionTypeModalOptions.changePassword:
-        this.editModal = TypeModalProfile.password;
-        break;
-      case FunctionTypeModalOptions.deleteAccount:
-        this.toggleDeleteAccountModal();
-        break;
-      case FunctionTypeModalOptions.addUser:
-        this.editModal = TypeModalProfile.addAccount;
-        this.ownerAlreadyLinked = false;
-        break;
-      case FunctionTypeModalOptions.removeUser:
-        this.editModal = TypeModalProfile.deleteAccount;
-        break;
-      case FunctionTypeModalOptions.editStructure:
-        this.router.navigateByUrl('/create-structure', { state: { data: this.currentStructureOwners.structure } });
-        break;
-      case FunctionTypeModalOptions.removeStructure:
-        this.toggleDeleteStructureModal();
-        break;
-      default:
-        break;
-    }
-    this.isModalOptsProfile = false;
-    this.modalOptsStructureIndex = null;
-  }
-
-  // Profile Section
-  public closeModalOptsProfile(): void {
-    this.editModal = null;
-    this.formAddAccount.reset();
-    this.formEmail.reset();
-    this.formPassword.reset();
-  }
-  public submitEmail(): void {
-    // stop here if form is invalid
-    if (this.formEmail.invalid) {
-      return;
-    }
-    this.loading = true;
-    this.profileService.changeEmail(this.formEmail.value.email, this.userProfile.email).subscribe(
-      () => {
-        this.closeModalOptsProfile();
-        this.formEmail.reset();
-        this.loading = false;
-      },
-      (err) => {
-        this.loading = false;
-      }
-    );
-  }
-  public submitPassword(): void {
-    // stop here if form is invalid
-    if (this.formPassword.invalid) {
-      return;
-    }
-    this.loading = true;
-
-    this.profileService.changePassword(this.formPassword.value.password, this.formPassword.value.oldPassword).subscribe(
-      () => {
-        this.closeModalOptsProfile();
-        this.formPassword.reset();
-        this.loading = false;
-        this.passwordError = false;
-      },
-      (error) => {
-        this.passwordError = true;
-        this.loading = false;
-      }
-    );
-  }
-  public openModalOptsProfile(): void {
-    this.isModalOptsProfile = true;
-  }
-  public showOldPassword(): void {
-    this.isShowOldPassword = !this.isShowOldPassword;
-  }
-  public showPassword(): void {
-    this.isShowPassword = !this.isShowPassword;
-  }
-  public showConfirmPassword(): void {
-    this.isShowConfirmPassword = !this.isShowConfirmPassword;
-  }
-  public logout(): void {
-    this.authService.logout();
-  }
-  public deleteAccount(shouldDelete: boolean): void {
-    this.toggleDeleteAccountModal();
-    if (shouldDelete) {
-      this.profileService.deleteProfile().subscribe(() => {
-        this.logout();
-      });
-    }
   }
 
-  // Structure section
-  public openModalOptsStructure(index: number, s: StructureWithOwners): void {
-    this.modalOptsStructureIndex = index;
-    this.currentStructureOwners = s;
-  }
   public addStructure(): void {
     this.router.navigateByUrl('/create-structure');
   }
-  private toggleDeleteStructureModal(): void {
-    this.deleteModalStructureOpenned = !this.deleteModalStructureOpenned;
-  }
-  private toggleDeleteAccountModal(): void {
-    this.deleteModalAccountOpenned = !this.deleteModalAccountOpenned;
-  }
 
-  public deleteStructure(shouldDelete: boolean): void {
-    this.toggleDeleteStructureModal();
-    if (shouldDelete) {
-      this.structureService.delete(this.currentStructureOwners.structure._id).subscribe((structure: Structure) => {
-        this.ngOnInit();
-      });
-    }
-  }
-
-  public verifyEmailAlreadyUsed(inputEmail, formControl: FormControl): void {
-    if (formControl.valid) {
-      this.profileService.isEmailAlreadyUsed(inputEmail).subscribe((isExist) => {
-        if (isExist) {
-          formControl.setErrors({ alreadyExist: true });
-        }
-      });
-    }
-  }
-  public removeOwner(owner: string): void {
-    this.structureService.removeOwnerFromStructure(owner, this.currentStructureOwners.structure._id).subscribe(() => {
-      this.currentStructureOwners.owners = this.currentStructureOwners.owners.filter((o) => o.id !== owner);
-      if (this.currentStructureOwners.owners.length == 0) {
-        this.closeModalOptsProfile();
-      }
-    });
-  }
-  public addOwner(): void {
-    // stop here if form is invalid
-    if (this.formAddAccount.invalid) {
-      return;
-    }
-    this.loading = true;
-    const user = new TempUser();
-    user.email = this.fAddAccount.email.value;
-    this.structureService.addOwnerToStructure(user, this.currentStructureOwners.structure._id).subscribe(
-      () => {
-        this.closeModalOptsProfile();
-        this.formAddAccount.reset();
-        this.loading = false;
-      },
-      (err) => {
-        this.ownerAlreadyLinked = true;
-        this.loading = false;
-      }
-    );
+  public logout(): void {
+    this.authService.logout();
   }
 }
diff --git a/src/app/profile/profile.module.ts b/src/app/profile/profile.module.ts
index adf5fb74c..a9427003f 100644
--- a/src/app/profile/profile.module.ts
+++ b/src/app/profile/profile.module.ts
@@ -3,11 +3,10 @@ import { ProfileComponent } from './profile.component';
 import { SharedModule } from '../shared/shared.module';
 import { CommonModule } from '@angular/common';
 import { BrowserModule } from '@angular/platform-browser';
-import { ModalOptionsComponent } from './modal-options/modal-options.component';
 
 @NgModule({
   imports: [CommonModule, BrowserModule, SharedModule],
-  declarations: [ProfileComponent, ModalOptionsComponent],
+  declarations: [ProfileComponent],
   exports: [ProfileComponent],
 })
 export class ProfileModule {}
diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts
index 4fecd7be0..9cad91820 100644
--- a/src/app/shared/components/index.ts
+++ b/src/app/shared/components/index.ts
@@ -12,6 +12,8 @@ import { HourPickerComponent } from './hour-picker/hour-picker.component';
 import { CopyPasteComponent } from './hour-picker/copy-paste/copy-paste.component';
 import { RadioFormComponent } from './radio-form/radio-form.component';
 import { ModalConfirmationComponent } from './modal-confirmation/modal-confirmation.component';
+import { StructureOptionsModalComponent } from './structure-options-modal/structure-options-modal.component';
+import { ModalOptionsComponent } from './modal-options/modal-options.component';
 
 // tslint:disable-next-line: max-line-length
 export {
@@ -29,6 +31,8 @@ export {
   CopyPasteComponent,
   RadioFormComponent,
   ModalConfirmationComponent,
+  StructureOptionsModalComponent,
+  ModalOptionsComponent,
 };
 
 // tslint:disable-next-line:variable-name
@@ -47,4 +51,6 @@ export const SharedComponents = [
   CopyPasteComponent,
   RadioFormComponent,
   ModalConfirmationComponent,
+  StructureOptionsModalComponent,
+  ModalOptionsComponent,
 ];
diff --git a/src/app/profile/modal-options/modal-options.component.html b/src/app/shared/components/modal-options/modal-options.component.html
similarity index 100%
rename from src/app/profile/modal-options/modal-options.component.html
rename to src/app/shared/components/modal-options/modal-options.component.html
diff --git a/src/app/profile/modal-options/modal-options.component.scss b/src/app/shared/components/modal-options/modal-options.component.scss
similarity index 78%
rename from src/app/profile/modal-options/modal-options.component.scss
rename to src/app/shared/components/modal-options/modal-options.component.scss
index 907e3f944..33159ef26 100644
--- a/src/app/profile/modal-options/modal-options.component.scss
+++ b/src/app/shared/components/modal-options/modal-options.component.scss
@@ -1,7 +1,7 @@
-@import '../../../assets/scss/color';
-@import '../../../assets/scss/typography';
-@import '../../../assets/scss/shapes';
-@import '../../../assets/scss/z-index';
+@import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
+@import '../../../../assets/scss/shapes';
+@import '../../../../assets/scss/z-index';
 
 .modalOptions {
   width: 300px;
diff --git a/src/app/profile/modal-options/modal-options.component.spec.ts b/src/app/shared/components/modal-options/modal-options.component.spec.ts
similarity index 100%
rename from src/app/profile/modal-options/modal-options.component.spec.ts
rename to src/app/shared/components/modal-options/modal-options.component.spec.ts
diff --git a/src/app/profile/modal-options/modal-options.component.ts b/src/app/shared/components/modal-options/modal-options.component.ts
similarity index 86%
rename from src/app/profile/modal-options/modal-options.component.ts
rename to src/app/shared/components/modal-options/modal-options.component.ts
index e9eb32e28..1fa03b1ed 100644
--- a/src/app/profile/modal-options/modal-options.component.ts
+++ b/src/app/shared/components/modal-options/modal-options.component.ts
@@ -1,5 +1,5 @@
 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { FunctionTypeModalOptions } from '../enum/functionTypeModalOptions.enum';
+import { FunctionTypeModalOptions } from '../../enum/functionTypeModalOptions.enum';
 
 @Component({
   selector: 'app-modal-options',
diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.html b/src/app/shared/components/structure-options-modal/structure-options-modal.component.html
new file mode 100644
index 000000000..1857d0baa
--- /dev/null
+++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.html
@@ -0,0 +1,226 @@
+<nav aria-label="modalOption">
+  <ul>
+    <li>
+      <button [ngClass]="{ active: active }" (click)="openModalOpts()" class="btn-primary transparent">
+        <app-svg-icon [type]="'ico'" [iconColor]="'inherit'" [icon]="'moreOpts'"></app-svg-icon>
+      </button>
+      <ul *ngIf="showModalOption" class="dropdown">
+        <app-modal-options
+          [isModalProfileOpts]="!structure"
+          [hasOwners]="structure && structure.owners.length > 0"
+          (closed)="closeModalOpts($event)"
+        ></app-modal-options>
+      </ul>
+    </li>
+  </ul>
+</nav>
+<div *ngIf="editModal" class="modalBackground">
+  <div class="modal" (clickOutside)="closeModalOptsProfile()">
+    <form
+      *ngIf="editModal == typeModalProfile.password"
+      [formGroup]="formPassword"
+      class="contentModal"
+      fxLayout="column"
+      fxLayoutAlign="center start"
+      fxLayoutGap="20px"
+    >
+      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
+        <h2>Changer de mot de passe</h2>
+        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
+      </div>
+      <div class="form-group" fxLayout="column" fxLayoutGap="4px">
+        <label for="oldPassword">Ancien mot de passe</label>
+        <p *ngIf="passwordError" class="special invalid">Votre ancien mot de passe est incorrect.</p>
+        <div fxLayout="row" fxLayoutGap="13px">
+          <input
+            [type]="isShowOldPassword ? 'text' : 'password'"
+            formControlName="oldPassword"
+            class="form-input password"
+            autocomplete="on"
+          />
+          <app-svg-icon
+            (click)="showOldPassword()"
+            [type]="'form'"
+            [iconClass]="'grey'"
+            [icon]="'eyePassword'"
+          ></app-svg-icon>
+          <app-svg-icon *ngIf="passwordError" [type]="'form'" [icon]="'notValidate'"></app-svg-icon>
+        </div>
+      </div>
+      <div class="form-group" fxLayout="column">
+        <label for="password">Nouveau mot de passe</label>
+        <p class="special" [ngClass]="{ invalid: fpass.password.invalid && fpass.password.value }">
+          Le mot de passe doit contenir au minimum : 8 caractères dont un caractère spécial, un caractère en majuscule
+          et un chiffre.
+        </p>
+        <div fxLayout="row" fxLayoutGap="13px">
+          <input
+            [type]="isShowPassword ? 'text' : 'password'"
+            formControlName="password"
+            class="form-input password"
+            autocomplete="on"
+          />
+          <app-svg-icon
+            (click)="showPassword()"
+            [type]="'form'"
+            [iconClass]="'grey'"
+            [icon]="'eyePassword'"
+          ></app-svg-icon>
+          <app-svg-icon *ngIf="fpass.password.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
+          <app-svg-icon
+            *ngIf="fpass.password.invalid && fpass.password.value"
+            [type]="'form'"
+            [icon]="'notValidate'"
+          ></app-svg-icon>
+        </div>
+      </div>
+      <div class="form-group" fxLayout="column">
+        <label for="confirmPassword">Confirmation du mot de passe</label>
+        <div fxLayout="row" fxLayoutGap="13px">
+          <input
+            [type]="isShowConfirmPassword ? 'text' : 'password'"
+            formControlName="confirmPassword"
+            class="form-input password"
+            autocomplete="on"
+          />
+          <app-svg-icon
+            (click)="showConfirmPassword()"
+            [type]="'form'"
+            [iconClass]="'grey'"
+            [icon]="'eyePassword'"
+          ></app-svg-icon>
+          <app-svg-icon
+            *ngIf="fpass.confirmPassword.valid && fpass.password.value"
+            [type]="'form'"
+            [icon]="'validate'"
+          ></app-svg-icon>
+          <app-svg-icon
+            *ngIf="fpass.confirmPassword.invalid && fpass.confirmPassword.value"
+            [type]="'form'"
+            [icon]="'notValidate'"
+          ></app-svg-icon>
+        </div>
+      </div>
+      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
+        <button
+          type="submit"
+          [ngClass]="{ invalid: formPassword.invalid }"
+          class="btn-primary small leave"
+          (click)="submitPassword()"
+        >
+          Valider
+        </button>
+      </div>
+    </form>
+    <form
+      *ngIf="editModal == typeModalProfile.email"
+      [formGroup]="formEmail"
+      class="contentModal"
+      fxLayout="column"
+      fxLayoutAlign="center start"
+    >
+      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
+        <h2>Changer de courriel</h2>
+        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
+      </div>
+      <div class="form-group" fxLayout="column">
+        <label for="email">Nouveau courriel</label>
+        <p class="special invalid" *ngIf="this.fmail.email.hasError('alreadyExist')">L'email est déja utilisé.</p>
+        <div fxLayout="row" fxLayoutGap="13px">
+          <input
+            type="text"
+            formControlName="email"
+            class="form-input"
+            autocomplete="on"
+            (keyup)="verifyEmailAlreadyUsed($event.target.value, this.fmail.email)"
+          />
+          <app-svg-icon *ngIf="fmail.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
+          <app-svg-icon
+            *ngIf="fmail.email.invalid && fmail.email.value"
+            [type]="'form'"
+            [icon]="'notValidate'"
+          ></app-svg-icon>
+        </div>
+      </div>
+      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
+        <button
+          type="submit"
+          [ngClass]="{ invalid: formEmail.invalid }"
+          class="btn-primary small leave"
+          (click)="submitEmail()"
+        >
+          Valider
+        </button>
+      </div>
+    </form>
+    <div
+      *ngIf="editModal == typeModalProfile.deleteAccount"
+      class="contentModal"
+      fxLayout="column"
+      fxLayoutAlign="center start"
+      fxLayoutGap="30px"
+    >
+      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
+        <h2>Supprimer un compte</h2>
+        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
+      </div>
+      <div fxLayout="column" fxLayoutGap="16px">
+        <div class="row removeOwner" *ngFor="let owner of structure.owners" fxLayoutGap="16px">
+          <button class="btn-primary small" (click)="removeOwner(owner.id)">X</button>
+          <span>
+            {{ owner.email }}
+          </span>
+        </div>
+      </div>
+      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
+        <button type="button" class="btn-primary small leave" (click)="closeModalOptsProfile()">Terminer</button>
+      </div>
+    </div>
+    <form
+      *ngIf="editModal == typeModalProfile.addAccount"
+      [formGroup]="formAddAccount"
+      class="contentModal"
+      fxLayout="column"
+      fxLayoutAlign="center start"
+      fxLayoutGap="30px"
+    >
+      <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center">
+        <h2>Ajouter un compte</h2>
+        <div class="ico-close-details" (click)="closeModalOptsProfile()"></div>
+      </div>
+      <div class="form-group" fxLayout="column">
+        <label for="email">Courriel du compte à ajouter</label>
+        <p *ngIf="ownerAlreadyLinked" class="special invalid">L'email est déjà rattaché à la structure.</p>
+        <div fxLayout="row" fxLayoutGap="13px">
+          <input type="text" formControlName="email" class="form-input" autocomplete="on" />
+          <app-svg-icon *ngIf="fAddAccount.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon>
+          <app-svg-icon
+            *ngIf="fAddAccount.email.invalid && fAddAccount.email.value"
+            [type]="'form'"
+            [icon]="'notValidate'"
+          ></app-svg-icon>
+        </div>
+      </div>
+      <div class="footerModal" fxLayout="row" fxLayoutAlign="center center">
+        <button
+          type="submit"
+          [ngClass]="{ invalid: formAddAccount.invalid }"
+          class="btn-primary small leave"
+          (click)="addOwner()"
+        >
+          Envoyer
+        </button>
+      </div>
+    </form>
+  </div>
+</div>
+<app-modal-confirmation
+  [openned]="deleteModalStructureOpenned"
+  [content]="'Voulez-vous vraiment supprimer cette structure ?'"
+  (closed)="deleteStructure($event)"
+></app-modal-confirmation>
+<app-modal-confirmation
+  [openned]="deleteModalAccountOpenned"
+  [content]="'Voulez-vous vraiment supprimer votre compte ?'"
+  (closed)="deleteAccount($event)"
+></app-modal-confirmation>
diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss b/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss
new file mode 100644
index 000000000..6edbfaaaf
--- /dev/null
+++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss
@@ -0,0 +1,86 @@
+@import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
+
+ul {
+  list-style: none;
+  margin: 0;
+  padding-left: 0;
+}
+
+li {
+  fill: $secondary-color;
+  color: $black;
+  display: block;
+  float: left;
+  position: relative;
+  text-decoration: none;
+  button {
+    width: 40px;
+    fill: $secondary-color;
+    &.active {
+      background-color: $secondary-color;
+      fill: $white;
+      border-color: $secondary-color;
+    }
+    &:hover {
+      background-color: $secondary-color;
+      fill: $white;
+      border-color: $secondary-color;
+    }
+  }
+}
+
+ul li ul {
+  position: absolute;
+  display: block;
+  margin-left: -268px;
+  margin-top: 7px;
+}
+
+button {
+  &.transparent {
+    background: none;
+    border: 1px solid $grey-4;
+    border-radius: 6px;
+  }
+}
+.contentModal {
+  padding: 35px 34px 18px 54px !important;
+  .headerModal {
+    width: 100%;
+  }
+  p {
+    &.special {
+      margin: 8px 0;
+      @include cn-regular-14;
+      color: $grey-3;
+      &.invalid {
+        color: $orange-warning;
+      }
+    }
+  }
+  .removeOwner {
+    button {
+      width: 40px;
+      background-color: $red-default;
+    }
+    span {
+      @include cn-bold-18;
+    }
+  }
+  button {
+    &.invalid {
+      opacity: 0.4;
+    }
+  }
+  .form-group {
+    width: 100%;
+    padding-right: 40px;
+    input {
+      width: 100%;
+    }
+  }
+  .ico-close-details {
+    min-width: 40px;
+  }
+}
diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts b/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts
new file mode 100644
index 000000000..3ffffb034
--- /dev/null
+++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts
@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StructureOptionsModalComponent } from './structure-options-modal.component';
+
+describe('StructureOptionsModalComponent', () => {
+  let component: StructureOptionsModalComponent;
+  let fixture: ComponentFixture<StructureOptionsModalComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [StructureOptionsModalComponent],
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(StructureOptionsModalComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts b/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts
new file mode 100644
index 000000000..2ae893c84
--- /dev/null
+++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts
@@ -0,0 +1,236 @@
+import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
+import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { StructureWithOwners } from '../../../models/structureWithOwners.model';
+import { TempUser } from '../../../models/temp-user.model';
+import { User } from '../../../models/user.model';
+import { TypeModalProfile } from '../../../profile/enum/TypeModalProfile.enum';
+import { ProfileService } from '../../../profile/services/profile.service';
+import { AuthService } from '../../../services/auth.service';
+import { StructureService } from '../../../services/structure.service';
+import { CustomRegExp } from '../../../utils/CustomRegExp';
+import { FunctionTypeModalOptions } from '../../enum/functionTypeModalOptions.enum';
+import { MustMatch } from '../../validator/form';
+
+@Component({
+  selector: 'app-structure-options-modal',
+  templateUrl: './structure-options-modal.component.html',
+  styleUrls: ['./structure-options-modal.component.scss'],
+})
+export class StructureOptionsModalComponent implements OnInit {
+  // Global var
+  @Input() public structure?: StructureWithOwners;
+  @Input() public userProfile?: User;
+  @Output() closed = new EventEmitter();
+  public active: boolean;
+
+  // Password profile
+  public formPassword: FormGroup;
+  public isShowOldPassword = false;
+  public isShowPassword = false;
+  public isShowConfirmPassword = false;
+  public passwordError = false;
+
+  // AddAccount
+  public formAddAccount: FormGroup;
+  public ownerAlreadyLinked = false;
+
+  // Email profile
+  public formEmail: FormGroup;
+  public changeEmail = false;
+
+  // Modal var
+  public editModal: TypeModalProfile;
+  public deleteModalAccountOpenned = false;
+  public deleteModalStructureOpenned = false;
+  public showModalOption = false;
+  public typeModalProfile = TypeModalProfile;
+
+  constructor(
+    private router: Router,
+    private formBuilder: FormBuilder,
+    private profileService: ProfileService,
+    private authService: AuthService,
+    private structureService: StructureService
+  ) {}
+
+  ngOnInit(): void {
+    this.formPassword = this.formBuilder.group(
+      {
+        oldPassword: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
+        password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
+        confirmPassword: [''],
+      },
+      { validator: MustMatch('password', 'confirmPassword') }
+    );
+    this.formEmail = this.formBuilder.group({
+      email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]],
+    });
+    this.formAddAccount = this.formBuilder.group({
+      email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]],
+    });
+  }
+
+  public openModalOpts(): void {
+    this.showModalOption = true;
+    this.active = true;
+  }
+
+  // getter for form fields
+  get fmail(): { [key: string]: AbstractControl } {
+    return this.formEmail.controls;
+  }
+
+  // getter for form fields
+  get fAddAccount(): { [key: string]: AbstractControl } {
+    return this.formAddAccount.controls;
+  }
+
+  // getter for form fields
+  get fpass(): { [key: string]: AbstractControl } {
+    return this.formPassword.controls;
+  }
+
+  public showOldPassword(): void {
+    this.isShowOldPassword = !this.isShowOldPassword;
+  }
+  public showPassword(): void {
+    this.isShowPassword = !this.isShowPassword;
+  }
+  public showConfirmPassword(): void {
+    this.isShowConfirmPassword = !this.isShowConfirmPassword;
+  }
+
+  public closeModalOpts(functionType: number): void {
+    switch (functionType) {
+      case FunctionTypeModalOptions.changeEmail:
+        this.editModal = TypeModalProfile.email;
+        break;
+      case FunctionTypeModalOptions.changePassword:
+        this.editModal = TypeModalProfile.password;
+        break;
+      case FunctionTypeModalOptions.deleteAccount:
+        this.toggleDeleteAccountModal();
+        break;
+      case FunctionTypeModalOptions.addUser:
+        this.editModal = TypeModalProfile.addAccount;
+        this.ownerAlreadyLinked = false;
+        break;
+      case FunctionTypeModalOptions.removeUser:
+        this.editModal = TypeModalProfile.deleteAccount;
+        break;
+      case FunctionTypeModalOptions.editStructure:
+        this.router.navigateByUrl('/create-structure', { state: { data: this.structure.structure } });
+        break;
+      case FunctionTypeModalOptions.removeStructure:
+        this.toggleDeleteStructureModal();
+        break;
+      default:
+        break;
+    }
+    this.showModalOption = false;
+    this.active = false;
+  }
+
+  // Profile Section
+  public closeModalOptsProfile(): void {
+    this.editModal = null;
+    //this.formAddAccount.reset();
+    this.formEmail.reset();
+    this.formPassword.reset();
+  }
+
+  private toggleDeleteAccountModal(): void {
+    this.deleteModalAccountOpenned = !this.deleteModalAccountOpenned;
+  }
+  private toggleDeleteStructureModal(): void {
+    this.deleteModalStructureOpenned = !this.deleteModalStructureOpenned;
+  }
+
+  public deleteAccount(shouldDelete: boolean): void {
+    this.toggleDeleteAccountModal();
+    if (shouldDelete) {
+      this.profileService.deleteProfile().subscribe(() => {
+        this.logout();
+      });
+    }
+  }
+
+  public deleteStructure(shouldDelete: boolean): void {
+    this.toggleDeleteStructureModal();
+    if (shouldDelete) {
+      this.structureService.delete(this.structure.structure._id).subscribe(() => {
+        this.closed.emit('');
+      });
+    }
+  }
+
+  public logout(): void {
+    this.authService.logout();
+  }
+
+  public submitPassword(): void {
+    // stop here if form is invalid
+    if (this.formPassword.invalid) {
+      return;
+    }
+    this.profileService.changePassword(this.formPassword.value.password, this.formPassword.value.oldPassword).subscribe(
+      () => {
+        this.closeModalOptsProfile();
+        this.formPassword.reset();
+        this.passwordError = false;
+      },
+      (error) => {
+        this.passwordError = true;
+      }
+    );
+  }
+
+  public addOwner(): void {
+    // stop here if form is invalid
+    if (this.formAddAccount.invalid) {
+      return;
+    }
+    const user = new TempUser();
+    user.email = this.fAddAccount.email.value;
+    this.structureService.addOwnerToStructure(user, this.structure.structure._id).subscribe(
+      () => {
+        this.closeModalOptsProfile();
+        this.formAddAccount.reset();
+      },
+      (err) => {
+        this.ownerAlreadyLinked = true;
+      }
+    );
+  }
+
+  public removeOwner(owner: string): void {
+    this.structureService.removeOwnerFromStructure(owner, this.structure.structure._id).subscribe(() => {
+      this.structure.owners = this.structure.owners.filter((o) => o.id !== owner);
+      if (this.structure.owners.length == 0) {
+        this.closeModalOptsProfile();
+      }
+    });
+  }
+
+  public verifyEmailAlreadyUsed(inputEmail, formControl: FormControl): void {
+    if (formControl.valid) {
+      this.profileService.isEmailAlreadyUsed(inputEmail).subscribe((isExist) => {
+        if (isExist) {
+          formControl.setErrors({ alreadyExist: true });
+        }
+      });
+    }
+  }
+
+  public submitEmail(): void {
+    // stop here if form is invalid
+    if (this.formEmail.invalid) {
+      return;
+    }
+    this.profileService.changeEmail(this.formEmail.value.email, this.userProfile.email).subscribe(() => {
+      this.closeModalOptsProfile();
+      this.formEmail.reset();
+    });
+  }
+}
diff --git a/src/app/profile/enum/functionTypeModalOptions.enum.ts b/src/app/shared/enum/functionTypeModalOptions.enum.ts
similarity index 100%
rename from src/app/profile/enum/functionTypeModalOptions.enum.ts
rename to src/app/shared/enum/functionTypeModalOptions.enum.ts
diff --git a/src/styles.scss b/src/styles.scss
index b49b24295..c1f107ae1 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -193,6 +193,7 @@ button {
   position: absolute;
   content: '';
   top: 0;
+  left: 0;
   background-color: $modal-background;
   .modal {
     max-height: 90%;
-- 
GitLab