From 945f93f2ecf15041551c1582c6c79f88c7537630 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 12:19:47 +0100
Subject: [PATCH] fix(search) : create modal component

---
 src/app/app.module.ts                         |   2 +
 .../modal-filter/modal-filter.component.html  |  33 ++++
 .../modal-filter/modal-filter.component.scss  | 170 ++++++++++++++++++
 .../modal-filter.component.spec.ts            |  25 +++
 .../modal-filter/modal-filter.component.ts    |  64 +++++++
 .../recherche/recherche.component.ts          |  12 --
 .../components/search/search.component.html   |  49 +----
 .../components/search/search.component.ts     |  80 +++------
 .../structure-list/services/search.service.ts |   6 +-
 .../structure-list.component.ts               |   1 +
 10 files changed, 332 insertions(+), 110 deletions(-)
 create mode 100644 src/app/structure-list/components/modal-filter/modal-filter.component.html
 create mode 100644 src/app/structure-list/components/modal-filter/modal-filter.component.scss
 create mode 100644 src/app/structure-list/components/modal-filter/modal-filter.component.spec.ts
 create mode 100644 src/app/structure-list/components/modal-filter/modal-filter.component.ts
 delete mode 100644 src/app/structure-list/components/recherche/recherche.component.ts

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 4934e7b00..2b3e218eb 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -16,6 +16,7 @@ import { StructureListComponent } from './structure-list/structure-list.componen
 import { CardComponent } from './structure-list/components/card/card.component';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { SearchComponent } from './structure-list/components/search/search.component';
+import { ModalFilterComponent } from './structure-list/components/modal-filter/modal-filter.component';
 
 @NgModule({
   declarations: [
@@ -26,6 +27,7 @@ import { SearchComponent } from './structure-list/components/search/search.compo
     StructureListComponent,
     CardComponent,
     SearchComponent,
+    ModalFilterComponent,
   ],
   imports: [
     BrowserModule,
diff --git a/src/app/structure-list/components/modal-filter/modal-filter.component.html b/src/app/structure-list/components/modal-filter/modal-filter.component.html
new file mode 100644
index 000000000..d006c7cac
--- /dev/null
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.html
@@ -0,0 +1,33 @@
+<div *ngIf="modalType" fxLayout="column" fxLayoutAlign="space-between" [ngClass]="['modal', 'modal' + modalType]">
+  <div class="body-wrap">
+    <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
+      <div class="blockFiltre" *ngFor="let c of categories">
+        <h4>{{ c.name }}</h4>
+
+        <ul class="blockLigne">
+          <div fxLayout="row" class="ligneFiltre" fxLayoutAlign="space-between center" *ngFor="let module of c.modules">
+            <li class="checkbox">
+              <div class="checkboxItem">
+                <label>
+                  <input
+                    type="checkbox"
+                    [checked]="getIndex(module.id, c.name) > -1"
+                    [value]="module.id"
+                    (change)="onCheckboxChange($event, c.name)"
+                  />
+                  <span class="customCheck"></span>
+                  <div class="label">{{ module.text }}</div>
+                </label>
+              </div>
+            </li>
+            <span class="nbResult">{{ module.count ? module.count : '0' }}</span>
+          </div>
+        </ul>
+      </div>
+    </div>
+    <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
+      <a (click)="clearFilters()">Effacer</a>
+      <button type="button" (click)="emitFilter(searchForm.value.searchTerm)">Appliquer</button>
+    </div>
+  </div>
+</div>
diff --git a/src/app/structure-list/components/modal-filter/modal-filter.component.scss b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
new file mode 100644
index 000000000..08adc9c1c
--- /dev/null
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -0,0 +1,170 @@
+@import '../../../../assets/scss/icons';
+@import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
+@import '../../../../assets/scss/breakpoint';
+@import '../../../../assets/scss/shapes';
+
+.modalformations {
+  @media #{$desktop} {
+    margin-left: 0;
+  }
+
+  margin-left: 206px;
+}
+.modalplusFiltres {
+  @media #{$desktop} {
+    margin-left: 0;
+  }
+  margin-left: 412px;
+}
+.modal {
+  max-height: 648px;
+  max-width: 754px;
+  width: 94%;
+  border-left: 6.5px solid transparent;
+  border-bottom: 6.5px solid transparent;
+  border-radius: 11px;
+  z-index: 401 !important;
+  position: absolute;
+  border: 1px solid $grey-5;
+  border-radius: 6px;
+  @include background-hash;
+  ::-webkit-scrollbar {
+    width: 10px;
+  }
+  ::-webkit-scrollbar-track {
+    background: $grey-5;
+  }
+  ::-webkit-scrollbar-thumb {
+    background: $grey;
+    border-radius: 6px;
+  }
+  .contentModal {
+    overflow-y: auto;
+    max-width: 1100px;
+    border-bottom: 1px solid $grey;
+    margin-bottom: 10px;
+    max-height: 500px;
+    .blockFiltre {
+      width: 100%;
+      padding: 32px 40px 10px 40px;
+      min-width: 450px;
+    }
+    .blockLigne {
+      padding-left: 0;
+      -moz-column-count: 2;
+      -moz-column-gap: 46px;
+      -webkit-column-count: 2;
+      -webkit-column-gap: 46px;
+      column-count: 2;
+      column-gap: 46px;
+      column-rule: dashed 1px $grey;
+      @media #{$large-phone} {
+        -moz-column-count: 1;
+        -webkit-column-count: 1;
+        column-count: 1;
+      }
+    }
+    .ligneFiltre {
+      padding: 5px 0 5px 0;
+    }
+    h4 {
+      @include cn-bold-14;
+      display: flex;
+      align-items: center;
+      margin-top: 0;
+    }
+    .nbResult {
+      @include cn-regular-14;
+    }
+    label {
+      @include cn-regular-14;
+    }
+  }
+  .footer {
+    margin: 0px 20px 16px 0;
+    a {
+      @include cn-bold-14;
+      display: flex;
+      align-items: center;
+      text-decoration: underline;
+    }
+    height: 32px;
+    button {
+      height: 100%;
+      border: none;
+      cursor: pointer;
+      background-color: $purple;
+      @include cn-bold-14;
+      line-height: 100%;
+      align-items: center;
+      text-align: center;
+      color: $white;
+      padding: 3px 16px 3px 16px;
+      outline: none;
+    }
+  }
+}
+.checkbox {
+  .checkboxItem {
+    /*position: relative;
+    display: inline-grid;
+    align-items: center;
+    grid-template-columns: min-content auto;
+    min-height: 25px;*/
+  }
+  list-style-type: none;
+  input {
+    opacity: 0;
+    display: none;
+    &:checked ~ .customCheck {
+      background-color: $orange-light;
+      border-color: transparent;
+    }
+    &:checked ~ .customCheck:after {
+      display: block;
+    }
+  }
+  label {
+    //display: inline-grid;
+    align-items: center;
+    grid-template-columns: min-content auto;
+    display: inline-grid;
+    cursor: pointer;
+  }
+  .label {
+    padding-left: 8px;
+    @include cn-regular-14;
+  }
+  .customCheck {
+    display: inline-grid;
+    width: 18px;
+    height: 18px;
+    background-color: $white;
+    border: 1px solid $grey;
+    cursor: pointer;
+    position: relative;
+
+    top: 0;
+    left: 0;
+    &:hover {
+      background-color: $grey-5;
+    }
+    &:after {
+      content: '';
+      position: absolute;
+      display: none;
+    }
+    &:after {
+      left: 7px;
+      top: 3px;
+      width: 4px;
+      height: 8px;
+      border: solid $white;
+      border-width: 0 2px 2px 0;
+      transform: rotate(45deg);
+      -webkit-transform: rotate(45deg);
+      -ms-transform: rotate(45deg);
+    }
+  }
+}
diff --git a/src/app/structure-list/components/modal-filter/modal-filter.component.spec.ts b/src/app/structure-list/components/modal-filter/modal-filter.component.spec.ts
new file mode 100644
index 000000000..5228b636c
--- /dev/null
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ModalFilterComponent } from './modal-filter.component';
+
+describe('ModalFilterComponent', () => {
+  let component: ModalFilterComponent;
+  let fixture: ComponentFixture<ModalFilterComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ModalFilterComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ModalFilterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/structure-list/components/modal-filter/modal-filter.component.ts b/src/app/structure-list/components/modal-filter/modal-filter.component.ts
new file mode 100644
index 000000000..3be4344db
--- /dev/null
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.ts
@@ -0,0 +1,64 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { Category } from '../../models/category.model';
+import { Filter } from '../../models/filter.model';
+import { Module } from '../../models/module.model';
+
+@Component({
+  selector: 'app-modal-filter',
+  templateUrl: './modal-filter.component.html',
+  styleUrls: ['./modal-filter.component.scss'],
+})
+export class ModalFilterComponent implements OnInit {
+  constructor(private fb: FormBuilder) {
+    this.searchForm = this.fb.group({
+      searchTerm: '',
+    });
+  }
+  @Input() public modalType: string;
+  @Input() public categories: Category[];
+  @Input() public modules: Module[];
+  @Output() searchEvent = new EventEmitter();
+  // Checkbox variable
+  checkedModules: Module[];
+  // Form search input
+  searchForm: FormGroup;
+  ngOnInit(): void {
+    // Manage checkbox
+    this.checkedModules = this.modules.slice();
+  }
+
+  // Return index of a specific module in array modules
+  public getIndex(id: number, categ: string): number {
+    return this.checkedModules.findIndex((m: Module) => m.id === id && m.text === categ);
+  }
+
+  // Management of the checkbox event (Check / Uncheck)
+  public onCheckboxChange(event, categ: string): void {
+    const checkValue: number = parseInt(event.target.value, 10);
+    if (event.target.checked) {
+      this.checkedModules.push(new Module(checkValue, categ));
+    } else {
+      // Check if the unchecked module is present in the list and remove it
+      if (this.getIndex(checkValue, categ) > -1) {
+        this.checkedModules.splice(this.getIndex(checkValue, categ), 1);
+      }
+    }
+  }
+
+  // Clear only filters in the current modal
+  public clearFilters(): void {
+    this.categories.forEach((categ: Category) => {
+      categ.modules.forEach((module: Module) => {
+        if (this.getIndex(module.id, categ.name) > -1) {
+          this.checkedModules.splice(this.getIndex(module.id, categ.name), 1);
+        }
+      });
+    });
+  }
+
+  // Sends an array containing all filters
+  public emitFilter(): void {
+    this.searchEvent.emit(this.checkedModules);
+  }
+}
diff --git a/src/app/structure-list/components/recherche/recherche.component.ts b/src/app/structure-list/components/recherche/recherche.component.ts
deleted file mode 100644
index 6ccca06c4..000000000
--- a/src/app/structure-list/components/recherche/recherche.component.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Component, OnInit, Input } from '@angular/core';
-
-@Component({
-  selector: 'app-recherche',
-  templateUrl: './recherche.component.html',
-  styleUrls: ['./recherche.component.scss'],
-})
-export class RechercheComponent implements OnInit {
-  constructor() {}
-
-  ngOnInit(): void {}
-}
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 68ef0abfa..8f962c47d 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -49,48 +49,13 @@
       <div class="arrow"></div>
     </button>
   </div>
-  <div
-    *ngIf="modalTypeOpened"
-    fxLayout="column"
-    fxLayoutAlign="space-between"
-    [ngClass]="['modal', 'modal' + modalTypeOpened]"
-  >
-    <div class="body-wrap">
-      <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
-        <div class="blockFiltre" *ngFor="let c of categories">
-          <h4>{{ c.name }}</h4>
-
-          <ul class="blockLigne">
-            <div
-              fxLayout="row"
-              class="ligneFiltre"
-              fxLayoutAlign="space-between center"
-              *ngFor="let module of c.modules"
-            >
-              <li class="checkbox">
-                <div class="checkboxItem">
-                  <label>
-                    <input
-                      type="checkbox"
-                      [checked]="getIndex(module.id, c.name) > -1"
-                      [value]="module.id"
-                      (change)="onCheckboxChange($event, c.name)"
-                    />
-                    <span class="customCheck"></span>
-                    <div class="label">{{ module.text }}</div>
-                  </label>
-                </div>
-              </li>
-              <span class="nbResult">{{ module.count ? module.count : '0' }}</span>
-            </div>
-          </ul>
-        </div>
-      </div>
-      <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
-        <a (click)="clearFilters()">Effacer</a>
-        <button type="button" (click)="applyFilter(searchForm.value.searchTerm)">Appliquer</button>
-      </div>
-    </div>
+  <div *ngIf="modalTypeOpened">
+    <app-modal-filter
+      [modalType]="modalTypeOpened"
+      [categories]="categories"
+      [modules]="checkedModulesFilter"
+      (searchEvent)="fetchResults($event)"
+    ></app-modal-filter>
   </div>
 </div>
 <div class="footerSearchSection" fxLayout="row" fxLayoutAlign="space-between center">
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index aa70de956..c7440073c 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -1,5 +1,4 @@
 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
-import { stringToKeyValue } from '@angular/flex-layout/extended/typings/style/style-transforms';
 import { FormBuilder, FormGroup } from '@angular/forms';
 import { Category } from '../../models/category.model';
 import { Filter } from '../../models/filter.model';
@@ -31,84 +30,57 @@ export class SearchComponent implements OnInit {
   modalTypeOpened: string;
 
   // Checkbox variable
-  checkedModules: Module[];
   checkedModulesFilter: Module[];
 
   ngOnInit(): void {
     // Will store the different categories
     this.categories = [];
 
-    // Manage checkbox
-    this.checkedModules = new Array();
     this.checkedModulesFilter = new Array();
   }
 
-  // Delete when getting back-end
-  private mockApiNumber(nb: number): string {
-    return ('00' + nb).slice(-3);
-  }
-
-  // Open the modal and display the list according to the right filter button
-  public openModal(option: string): void {
-    this.categories = [];
-    if (this.modalTypeOpened !== option) {
-      this.modalTypeOpened = option;
-      this.fakeData(option);
-    } else {
-      this.modalTypeOpened = null;
-    }
-
-    // Init checked list modules
-    this.checkedModules = this.checkedModulesFilter.slice();
-  }
-
   // Sends an array containing all filters
   public applyFilter(term: string): void {
-    this.checkedModulesFilter = this.checkedModules.slice();
-    this.openModal(this.modalTypeOpened);
-    // Send search input filter
-    const filters: Filter[] = [];
+    // Add search input filter
+    let filters: Filter[] = [];
     if (term) {
       filters.push(new Filter('nomDeVotreStructure', term, false));
     }
-
-    // Send checked box filter
+    // Add checked box filter
     this.checkedModulesFilter.forEach((cm) => {
       filters.push(new Filter(this.fromStringToIdExcel(cm.text), this.mockApiNumber(cm.id), false));
     });
+    // Send filters
     this.searchEvent.emit(filters);
   }
 
-  // Management of the checkbox event (Check / Uncheck)
-  public onCheckboxChange(event, categ: string): void {
-    const checkValue: number = parseInt(event.target.value, 10);
-    if (event.target.checked) {
-      this.checkedModules.push(new Module(checkValue, categ));
-    } else {
-      // Check if the unchecked module is present in the list and remove it
-      if (this.getIndex(checkValue, categ) > -1) {
-        this.checkedModules.splice(this.getIndex(checkValue, categ), 1);
-      }
-    }
+  // Delete when getting back-end
+  private mockApiNumber(nb: number): string {
+    return ('00' + nb).slice(-3);
   }
 
-  // Return index of a specific module in array modules
-  public getIndex(id: number, categ: string): number {
-    return this.checkedModules.findIndex((m: Module) => m.id === id && m.text === categ);
+  public fetchResults(checkedModules: Module[]): void {
+    let inputTerm = this.searchForm.get('searchTerm').value;
+
+    // Store checked modules
+    this.checkedModulesFilter = checkedModules;
+
+    // Close modal after receive filters from her.
+    this.openModal(this.modalTypeOpened);
+    inputTerm ? this.applyFilter(inputTerm) : this.applyFilter(null);
   }
 
-  // Clear only filters in the current modal
-  public clearFilters(): void {
-    this.categories.forEach((categ: Category) => {
-      categ.modules.forEach((module: Module) => {
-        if (this.getIndex(module.id, categ.name) > -1) {
-          this.checkedModules.splice(this.getIndex(module.id, categ.name), 1);
-        }
-      });
-    });
+  // Open the modal and display the list according to the right filter button
+  public openModal(option: string): void {
+    this.categories = [];
+    if (this.modalTypeOpened !== option) {
+      this.modalTypeOpened = option;
+      this.fakeData(option);
+    } else {
+      this.modalTypeOpened = null;
+    }
   }
 
-  // Format title of category to id of excel category
   private fromStringToIdExcel(categ: string): string {
     let splitStr = categ.toLowerCase().split(' ');
     for (let i = 1; i < splitStr.length; i++) {
@@ -138,7 +110,7 @@ export class SearchComponent implements OnInit {
     if (option === this.modalType[0]) {
       this.mockService(this.categories, 'Accompagnement des démarches', { name: 'CAF', id: 5 }, 7);
     } else if (option === this.modalType[1]) {
-      this.searchService.getCategories().subscribe((categories: Category[]) => {
+      this.searchService.getCategoriesFormations().subscribe((categories: Category[]) => {
         this.searchService
           .getFakeCounterModule()
           .subscribe((res: { structureCountTab: { id: number; count: number }[] }) => {
diff --git a/src/app/structure-list/services/search.service.ts b/src/app/structure-list/services/search.service.ts
index 4ae64b197..fc3e73583 100644
--- a/src/app/structure-list/services/search.service.ts
+++ b/src/app/structure-list/services/search.service.ts
@@ -11,8 +11,10 @@ import { Module } from '../models/module.model';
 export class SearchService {
   constructor(private http: HttpClient) {}
 
-  public getCategories(): Observable<Category[]> {
-    return this.http.get('/api/Categories').pipe(map((data: any[]) => data.map((item) => new Category(item))));
+  public getCategoriesFormations(): Observable<Category[]> {
+    return this.http
+      .get('/api/CategoriesFormations')
+      .pipe(map((data: any[]) => data.map((item) => new Category(item))));
   }
   public getFakeCounterModule(): Observable<any> {
     return this.http.get('http://localhost:3000/structures/count');
diff --git a/src/app/structure-list/structure-list.component.ts b/src/app/structure-list/structure-list.component.ts
index 5152fa5fb..62fe27456 100644
--- a/src/app/structure-list/structure-list.component.ts
+++ b/src/app/structure-list/structure-list.component.ts
@@ -16,6 +16,7 @@ export class StructureListComponent implements OnInit {
   ngOnInit(): void {}
 
   public fetchResults(filters: Filter[]): void {
+    console.log(filters);
     this.searchEvent.emit(filters);
   }
 }
-- 
GitLab