From d5b012236c287f47c085bbec1b38ea6c8629fd0b Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 8 Oct 2020 10:31:10 +0200
Subject: [PATCH 01/50] init

---
 src/app/app.module.ts                         |  3 ++-
 src/app/home/home.component.html              |  2 +-
 .../components/card/card.component.html       |  1 +
 .../components/card/card.component.scss       |  0
 .../components/card/card.component.spec.ts    | 25 +++++++++++++++++++
 .../components/card/card.component.ts         | 15 +++++++++++
 .../recherche/recherche.component.html        |  1 +
 .../recherche/recherche.component.scss        |  0
 .../recherche/recherche.component.spec.ts     | 25 +++++++++++++++++++
 .../recherche/recherche.component.ts          | 15 +++++++++++
 .../services/structure.service.spec.ts        | 16 ++++++++++++
 .../structure/services/structure.service.ts   |  9 +++++++
 src/app/structure/structure.component.html    |  2 ++
 src/app/structure/structure.component.scss    |  0
 src/app/structure/structure.component.spec.ts | 25 +++++++++++++++++++
 src/app/structure/structure.component.ts      | 15 +++++++++++
 src/app/structure/structure.module.ts         | 12 +++++++++
 17 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 src/app/structure/components/card/card.component.html
 create mode 100644 src/app/structure/components/card/card.component.scss
 create mode 100644 src/app/structure/components/card/card.component.spec.ts
 create mode 100644 src/app/structure/components/card/card.component.ts
 create mode 100644 src/app/structure/components/recherche/recherche.component.html
 create mode 100644 src/app/structure/components/recherche/recherche.component.scss
 create mode 100644 src/app/structure/components/recherche/recherche.component.spec.ts
 create mode 100644 src/app/structure/components/recherche/recherche.component.ts
 create mode 100644 src/app/structure/services/structure.service.spec.ts
 create mode 100644 src/app/structure/services/structure.service.ts
 create mode 100644 src/app/structure/structure.component.html
 create mode 100644 src/app/structure/structure.component.scss
 create mode 100644 src/app/structure/structure.component.spec.ts
 create mode 100644 src/app/structure/structure.component.ts
 create mode 100644 src/app/structure/structure.module.ts

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 4ad3e8861..9d221fe1a 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -11,10 +11,11 @@ import { StructureListComponent } from './structure-list/structure-list.componen
 import { FooterComponent } from './footer/footer.component';
 import { HeaderComponent } from './header/header.component';
 import { SharedModule } from './shared/shared.module';
+import { StructureModule } from './structure/structure.module';
 
 @NgModule({
   declarations: [AppComponent, HeaderComponent, FooterComponent, HomeComponent, StructureListComponent],
-  imports: [BrowserModule, AppRoutingModule, FlexLayoutModule, SharedModule],
+  imports: [BrowserModule, AppRoutingModule, FlexLayoutModule, SharedModule, StructureModule],
   providers: [{ provide: LOCALE_ID, useValue: 'fr' }, CustomBreakPointsProvider],
   bootstrap: [AppComponent],
 })
diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html
index 4f2ba48bc..a1abb68dc 100644
--- a/src/app/home/home.component.html
+++ b/src/app/home/home.component.html
@@ -1,5 +1,5 @@
 <div class="content-container">
   <div class="section-container">
-    <p>Home works!</p>
+    <app-structure></app-structure>
   </div>
 </div>
diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
new file mode 100644
index 000000000..8071bfcce
--- /dev/null
+++ b/src/app/structure/components/card/card.component.html
@@ -0,0 +1 @@
+<p>card wsdorks!</p>
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure/components/card/card.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/structure/components/card/card.component.spec.ts b/src/app/structure/components/card/card.component.spec.ts
new file mode 100644
index 000000000..3093fd5a3
--- /dev/null
+++ b/src/app/structure/components/card/card.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CardComponent } from './card.component';
+
+describe('CardComponent', () => {
+  let component: CardComponent;
+  let fixture: ComponentFixture<CardComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ CardComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CardComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
new file mode 100644
index 000000000..07a9ab07e
--- /dev/null
+++ b/src/app/structure/components/card/card.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-card',
+  templateUrl: './card.component.html',
+  styleUrls: ['./card.component.scss']
+})
+export class CardComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
new file mode 100644
index 000000000..63c7b1a72
--- /dev/null
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -0,0 +1 @@
+<p>recherche works!</p>
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/structure/components/recherche/recherche.component.spec.ts b/src/app/structure/components/recherche/recherche.component.spec.ts
new file mode 100644
index 000000000..e38e4d4e8
--- /dev/null
+++ b/src/app/structure/components/recherche/recherche.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RechercheComponent } from './recherche.component';
+
+describe('RechercheComponent', () => {
+  let component: RechercheComponent;
+  let fixture: ComponentFixture<RechercheComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ RechercheComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(RechercheComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
new file mode 100644
index 000000000..b37a52c87
--- /dev/null
+++ b/src/app/structure/components/recherche/recherche.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } 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/services/structure.service.spec.ts b/src/app/structure/services/structure.service.spec.ts
new file mode 100644
index 000000000..d44ef8feb
--- /dev/null
+++ b/src/app/structure/services/structure.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { StructureService } from './structure.service';
+
+describe('StructureService', () => {
+  let service: StructureService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(StructureService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
new file mode 100644
index 000000000..8a09d6adb
--- /dev/null
+++ b/src/app/structure/services/structure.service.ts
@@ -0,0 +1,9 @@
+import { Injectable } from '@angular/core';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class StructureService {
+
+  constructor() { }
+}
diff --git a/src/app/structure/structure.component.html b/src/app/structure/structure.component.html
new file mode 100644
index 000000000..8688da6ce
--- /dev/null
+++ b/src/app/structure/structure.component.html
@@ -0,0 +1,2 @@
+<app-card></app-card>
+<app-recherche></app-recherche>
diff --git a/src/app/structure/structure.component.scss b/src/app/structure/structure.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/structure/structure.component.spec.ts b/src/app/structure/structure.component.spec.ts
new file mode 100644
index 000000000..47da9d53d
--- /dev/null
+++ b/src/app/structure/structure.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StructureComponent } from './structure.component';
+
+describe('StructureComponent', () => {
+  let component: StructureComponent;
+  let fixture: ComponentFixture<StructureComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ StructureComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(StructureComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/structure/structure.component.ts b/src/app/structure/structure.component.ts
new file mode 100644
index 000000000..c74423ddc
--- /dev/null
+++ b/src/app/structure/structure.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-structure',
+  templateUrl: './structure.component.html',
+  styleUrls: ['./structure.component.scss']
+})
+export class StructureComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/src/app/structure/structure.module.ts b/src/app/structure/structure.module.ts
new file mode 100644
index 000000000..902f040cd
--- /dev/null
+++ b/src/app/structure/structure.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { StructureComponent } from './structure.component';
+import { CardComponent } from './components/card/card.component';
+import { RechercheComponent } from './components/recherche/recherche.component';
+
+@NgModule({
+  declarations: [StructureComponent, CardComponent, RechercheComponent],
+  imports: [CommonModule],
+  exports: [StructureComponent],
+})
+export class StructureModule {}
-- 
GitLab


From 960ae5df57c60ef44f486d077078fe1876092163 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 8 Oct 2020 10:47:14 +0200
Subject: [PATCH 02/50] feat(api): Mise en place d'une solution mock

---
 angular.json                                  |    3 +-
 api/db.json                                   |   58 +
 api/routes.json                               |    3 +
 package-lock.json                             | 1195 ++++++++++++++---
 package.json                                  |    4 +-
 proxy.conf.json                               |    5 +
 .../components/card/card.component.html       |   18 +-
 .../components/card/card.component.scss       |   22 +
 .../components/card/card.component.ts         |   17 +-
 src/app/structure/models/structure.model.ts   |   27 +
 src/app/structure/structure.component.html    |    2 +-
 src/app/structure/structure.module.ts         |    3 +-
 12 files changed, 1187 insertions(+), 170 deletions(-)
 create mode 100644 api/db.json
 create mode 100644 api/routes.json
 create mode 100644 proxy.conf.json
 create mode 100644 src/app/structure/models/structure.model.ts

diff --git a/angular.json b/angular.json
index 79beada28..1761772a3 100644
--- a/angular.json
+++ b/angular.json
@@ -74,7 +74,8 @@
         "serve": {
           "builder": "@angular-devkit/build-angular:dev-server",
           "options": {
-            "browserTarget": "pamn:build"
+            "browserTarget": "pamn:build",
+            "proxyConfig": "proxy.conf.json"
           },
           "configurations": {
             "production": {
diff --git a/api/db.json b/api/db.json
new file mode 100644
index 000000000..e41fd2d32
--- /dev/null
+++ b/api/db.json
@@ -0,0 +1,58 @@
+{
+  "structure": [
+    {
+      "id": "26-28",
+      "created_on": "22/09/2020 16:01",
+      "last_modif": "22/09/2020 16:01",
+      "owner": "-",
+      "status": "Un établissement principal (siège social)",
+      "nom": "Labit",
+      "type_structure": "MDM",
+      "description": "Ouvert à toute heure",
+      "num": "12",
+      "voie": "27838 Avenue Lacassagne",
+      "telephone": "0134257645",
+      "courriel": "coop.labit@gmail.com",
+      "site_web": "",
+      "facebook": "",
+      "twitter": "",
+      "instagram": "",
+      "civilite_contact": "Madame",
+      "nom_contact": "Labit",
+      "prenom_contact": "Valentine",
+      "email_contact": "coop.labit@gmail.com",
+      "fonction_contact": "Président de l'association",
+      "pmr": true,
+      "je_fais_a_la_place_de_lusager": true,
+      "accompagnement_aux_demarches": ["Pôle Emploi", "CPAM", "Impôts", "Logement"],
+      "wifi": true
+    },
+    {
+      "id": "26-10",
+      "created_on": "03/09/2020 14:14",
+      "last_modif": "03/09/2020 14:15",
+      "owner": "Marlène Simondant",
+      "status": "Un établissement principal (siège social)",
+      "nom": "fgh",
+      "type_structure": "Bibliothèque",
+      "description": "",
+      "num": "",
+      "voie": "26061 13ème Rue Cité Berliet",
+      "telephone": "0659856235",
+      "courriel": "test@test.te",
+      "site_web": "",
+      "facebook": "",
+      "twitter": "",
+      "instagram": "",
+      "civilite_contact": "",
+      "nom_contact": "dh",
+      "prenom_contact": "fxh",
+      "email_contact": "test@test.te",
+      "fonction_contact": "Bénévole",
+      "pmr": false,
+      "je_fais_a_la_place_de_lusager": false,
+      "accompagnement_aux_demarches": ["CPAM"],
+      "wifi": false
+    }
+  ]
+}
diff --git a/api/routes.json b/api/routes.json
new file mode 100644
index 000000000..6a7af55fa
--- /dev/null
+++ b/api/routes.json
@@ -0,0 +1,3 @@
+{
+  "/api/*": "/$1"
+}
diff --git a/package-lock.json b/package-lock.json
index 3cc3d6852..b09f84a5a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1967,6 +1967,19 @@
         "semver-intersect": "1.4.0"
       }
     },
+    "@sindresorhus/is": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+      "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ=="
+    },
+    "@szmarczak/http-timer": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+      "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+      "requires": {
+        "defer-to-connect": "^1.0.1"
+      }
+    },
     "@types/color-name": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -2278,7 +2291,6 @@
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
       "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
-      "dev": true,
       "requires": {
         "mime-types": "~2.1.24",
         "negotiator": "0.6.2"
@@ -2413,6 +2425,14 @@
       "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
       "dev": true
     },
+    "ansi-align": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
+      "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==",
+      "requires": {
+        "string-width": "^3.0.0"
+      }
+    },
     "ansi-colors": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
@@ -2839,6 +2859,14 @@
       "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
       "dev": true
     },
+    "basic-auth": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
     "batch": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -2906,7 +2934,6 @@
       "version": "1.19.0",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
       "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
-      "dev": true,
       "requires": {
         "bytes": "3.1.0",
         "content-type": "~1.0.4",
@@ -2923,14 +2950,12 @@
         "bytes": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
+          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
         },
         "debug": {
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
           "requires": {
             "ms": "2.0.0"
           }
@@ -2939,7 +2964,6 @@
           "version": "0.4.24",
           "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
           "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
           "requires": {
             "safer-buffer": ">= 2.1.2 < 3"
           }
@@ -2947,8 +2971,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
         }
       }
     },
@@ -2972,6 +2995,109 @@
       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
       "dev": true
     },
+    "boxen": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
+      "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==",
+      "requires": {
+        "ansi-align": "^3.0.0",
+        "camelcase": "^5.3.1",
+        "chalk": "^3.0.0",
+        "cli-boxes": "^2.2.0",
+        "string-width": "^4.1.0",
+        "term-size": "^2.1.0",
+        "type-fest": "^0.8.1",
+        "widest-line": "^3.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
+        }
+      }
+    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3168,8 +3294,7 @@
     "bytes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
-      "dev": true
+      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
     },
     "cacache": {
       "version": "15.0.5",
@@ -3221,6 +3346,45 @@
         "unset-value": "^1.0.0"
       }
     },
+    "cacheable-request": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
+      "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
+      "requires": {
+        "clone-response": "^1.0.2",
+        "get-stream": "^5.1.0",
+        "http-cache-semantics": "^4.0.0",
+        "keyv": "^3.0.0",
+        "lowercase-keys": "^2.0.0",
+        "normalize-url": "^4.1.0",
+        "responselike": "^1.0.2"
+      },
+      "dependencies": {
+        "get-stream": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+          "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "http-cache-semantics": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
+          "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
+        },
+        "lowercase-keys": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+          "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
+        },
+        "normalize-url": {
+          "version": "4.5.0",
+          "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
+          "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ=="
+        }
+      }
+    },
     "caller-callsite": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
@@ -3362,6 +3526,11 @@
         }
       }
     },
+    "ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+    },
     "cipher-base": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -3407,6 +3576,11 @@
       "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
       "dev": true
     },
+    "cli-boxes": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+      "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw=="
+    },
     "cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -3462,6 +3636,14 @@
       "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
       "dev": true
     },
+    "clone-response": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+      "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+      "requires": {
+        "mimic-response": "^1.0.0"
+      }
+    },
     "coa": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
@@ -3646,7 +3828,6 @@
       "version": "2.0.18",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
       "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
-      "dev": true,
       "requires": {
         "mime-db": ">= 1.43.0 < 2"
       }
@@ -3655,7 +3836,6 @@
       "version": "1.7.4",
       "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
       "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
-      "dev": true,
       "requires": {
         "accepts": "~1.3.5",
         "bytes": "3.0.0",
@@ -3670,7 +3850,6 @@
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
           "requires": {
             "ms": "2.0.0"
           }
@@ -3678,8 +3857,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
         }
       }
     },
@@ -3701,6 +3879,34 @@
         "typedarray": "^0.0.6"
       }
     },
+    "configstore": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
+      "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
+      "requires": {
+        "dot-prop": "^5.2.0",
+        "graceful-fs": "^4.1.2",
+        "make-dir": "^3.0.0",
+        "unique-string": "^2.0.0",
+        "write-file-atomic": "^3.0.0",
+        "xdg-basedir": "^4.0.0"
+      },
+      "dependencies": {
+        "make-dir": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+          "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+          "requires": {
+            "semver": "^6.0.0"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        }
+      }
+    },
     "connect": {
       "version": "3.7.0",
       "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
@@ -3736,6 +3942,11 @@
       "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
       "dev": true
     },
+    "connect-pause": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/connect-pause/-/connect-pause-0.1.1.tgz",
+      "integrity": "sha1-smmyu4Ldsaw9tQmcD7WCq6mfs3o="
+    },
     "console-browserify": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
@@ -3752,7 +3963,6 @@
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
       "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
-      "dev": true,
       "requires": {
         "safe-buffer": "5.1.2"
       }
@@ -3760,8 +3970,7 @@
     "content-type": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
-      "dev": true
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
     },
     "conventional-changelog": {
       "version": "3.1.23",
@@ -4040,14 +4249,12 @@
     "cookie": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
-      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
-      "dev": true
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
     },
     "cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
-      "dev": true
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
     },
     "copy-concurrently": {
       "version": "1.0.5",
@@ -4140,6 +4347,15 @@
       "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
       "dev": true
     },
+    "cors": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+      "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+      "requires": {
+        "object-assign": "^4",
+        "vary": "^1"
+      }
+    },
     "cosmiconfig": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
@@ -4237,6 +4453,11 @@
         "randomfill": "^1.0.3"
       }
     },
+    "crypto-random-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+      "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
+    },
     "css": {
       "version": "2.2.4",
       "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
@@ -4561,7 +4782,6 @@
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
       "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
-      "dev": true,
       "requires": {
         "ms": "2.1.2"
       }
@@ -4575,8 +4795,7 @@
     "decamelize": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
-      "dev": true
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
     },
     "decamelize-keys": {
       "version": "1.1.0",
@@ -4602,6 +4821,14 @@
       "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
       "dev": true
     },
+    "decompress-response": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+      "requires": {
+        "mimic-response": "^1.0.0"
+      }
+    },
     "deep-equal": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -4616,6 +4843,11 @@
         "regexp.prototype.flags": "^1.2.0"
       }
     },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+    },
     "default-gateway": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
@@ -4643,6 +4875,11 @@
         }
       }
     },
+    "defer-to-connect": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+      "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ=="
+    },
     "define-properties": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -4764,8 +5001,7 @@
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
-      "dev": true
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
     },
     "dependency-graph": {
       "version": "0.7.2",
@@ -4786,8 +5022,7 @@
     "destroy": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
-      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
-      "dev": true
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
     },
     "detect-indent": {
       "version": "6.0.0",
@@ -4938,7 +5173,6 @@
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
       "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
-      "dev": true,
       "requires": {
         "is-obj": "^2.0.0"
       }
@@ -4953,6 +5187,11 @@
         "minimatch": "^3.0.4"
       }
     },
+    "duplexer3": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+    },
     "duplexify": {
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -4978,8 +5217,7 @@
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
-      "dev": true
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
     "electron-to-chromium": {
       "version": "1.3.573",
@@ -5013,8 +5251,7 @@
     "emoji-regex": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-      "dev": true
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
     },
     "emojis-list": {
       "version": "3.0.0",
@@ -5025,8 +5262,7 @@
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
-      "dev": true
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
     },
     "encoding": {
       "version": "0.1.13",
@@ -5041,7 +5277,6 @@
       "version": "1.4.4",
       "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
       "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
-      "dev": true,
       "requires": {
         "once": "^1.4.0"
       }
@@ -5182,6 +5417,15 @@
         "is-arrayish": "^0.2.1"
       }
     },
+    "errorhandler": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz",
+      "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==",
+      "requires": {
+        "accepts": "~1.3.7",
+        "escape-html": "~1.0.3"
+      }
+    },
     "es-abstract": {
       "version": "1.18.0-next.0",
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz",
@@ -5266,11 +5510,15 @@
       "integrity": "sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig==",
       "dev": true
     },
+    "escape-goat": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
+      "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q=="
+    },
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
-      "dev": true
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
     },
     "escape-string-regexp": {
       "version": "1.0.5",
@@ -5326,8 +5574,7 @@
     "etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
-      "dev": true
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
     },
     "eventemitter3": {
       "version": "4.0.7",
@@ -5435,7 +5682,6 @@
       "version": "4.17.1",
       "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
       "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
-      "dev": true,
       "requires": {
         "accepts": "~1.3.7",
         "array-flatten": "1.1.1",
@@ -5472,14 +5718,12 @@
         "array-flatten": {
           "version": "1.1.1",
           "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-          "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
-          "dev": true
+          "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
         },
         "debug": {
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
           "requires": {
             "ms": "2.0.0"
           }
@@ -5487,8 +5731,31 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
+    "express-urlrewrite": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/express-urlrewrite/-/express-urlrewrite-1.3.0.tgz",
+      "integrity": "sha512-xy3WZqA9EIfb51FkL1R0EqW91Z8lMi9ohp/WrNxKukvQulybqvh7+OsGiw9JOD51NrGsSuWi2hqOv7GW+DGz1w==",
+      "requires": {
+        "debug": "*",
+        "path-to-regexp": "^1.0.3"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "path-to-regexp": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+          "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+          "requires": {
+            "isarray": "0.0.1"
+          }
         }
       }
     },
@@ -5717,7 +5984,6 @@
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
       "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
-      "dev": true,
       "requires": {
         "debug": "2.6.9",
         "encodeurl": "~1.0.2",
@@ -5732,7 +5998,6 @@
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
           "requires": {
             "ms": "2.0.0"
           }
@@ -5740,8 +6005,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
         }
       }
     },
@@ -5873,8 +6137,7 @@
     "forwarded": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
-      "dev": true
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
     },
     "fragment-cache": {
       "version": "0.2.1",
@@ -5888,8 +6151,7 @@
     "fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
-      "dev": true
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
     },
     "from2": {
       "version": "2.3.0",
@@ -5976,8 +6238,7 @@
     "get-caller-file": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "dev": true
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
     },
     "get-pkg-repo": {
       "version": "1.4.0",
@@ -6141,7 +6402,6 @@
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
       "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
-      "dev": true,
       "requires": {
         "pump": "^3.0.0"
       }
@@ -6328,6 +6588,14 @@
         "is-glob": "^4.0.1"
       }
     },
+    "global-dirs": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
+      "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
+      "requires": {
+        "ini": "^1.3.5"
+      }
+    },
     "globals": {
       "version": "11.12.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -6348,11 +6616,28 @@
         "slash": "^3.0.0"
       }
     },
+    "got": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
+      "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
+      "requires": {
+        "@sindresorhus/is": "^0.14.0",
+        "@szmarczak/http-timer": "^1.1.2",
+        "cacheable-request": "^6.0.0",
+        "decompress-response": "^3.3.0",
+        "duplexer3": "^0.1.4",
+        "get-stream": "^4.1.0",
+        "lowercase-keys": "^1.0.1",
+        "mimic-response": "^1.0.1",
+        "p-cancelable": "^1.0.0",
+        "to-readable-stream": "^1.0.0",
+        "url-parse-lax": "^3.0.0"
+      }
+    },
     "graceful-fs": {
       "version": "4.2.4",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
-      "dev": true
+      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
     },
     "handle-thing": {
       "version": "2.0.1",
@@ -6508,6 +6793,11 @@
         }
       }
     },
+    "has-yarn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+      "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw=="
+    },
     "hash-base": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
@@ -6632,7 +6922,6 @@
       "version": "1.7.2",
       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
       "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
-      "dev": true,
       "requires": {
         "depd": "~1.1.2",
         "inherits": "2.0.3",
@@ -6644,8 +6933,7 @@
         "inherits": {
           "version": "2.0.3",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
         }
       }
     },
@@ -6937,6 +7225,11 @@
         "resolve-from": "^3.0.0"
       }
     },
+    "import-lazy": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+      "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM="
+    },
     "import-local": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
@@ -6950,8 +7243,7 @@
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-      "dev": true
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
     },
     "indent-string": {
       "version": "4.0.0",
@@ -6996,8 +7288,7 @@
     "ini": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
-      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
-      "dev": true
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
     },
     "inquirer": {
       "version": "7.3.3",
@@ -7150,8 +7441,7 @@
     "ipaddr.js": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
-      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
-      "dev": true
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
     },
     "is-absolute-url": {
       "version": "2.1.0",
@@ -7212,6 +7502,14 @@
       "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
       "dev": true
     },
+    "is-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "requires": {
+        "ci-info": "^2.0.0"
+      }
+    },
     "is-color-stop": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
@@ -7304,8 +7602,7 @@
     "is-fullwidth-code-point": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-      "dev": true
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
     },
     "is-glob": {
       "version": "4.0.1",
@@ -7316,6 +7613,22 @@
         "is-extglob": "^2.1.1"
       }
     },
+    "is-installed-globally": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz",
+      "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==",
+      "requires": {
+        "global-dirs": "^2.0.1",
+        "is-path-inside": "^3.0.1"
+      },
+      "dependencies": {
+        "is-path-inside": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
+          "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg=="
+        }
+      }
+    },
     "is-interactive": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
@@ -7328,6 +7641,11 @@
       "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
       "dev": true
     },
+    "is-npm": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz",
+      "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig=="
+    },
     "is-number": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -7337,8 +7655,7 @@
     "is-obj": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
-      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
-      "dev": true
+      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
     },
     "is-path-cwd": {
       "version": "2.2.0",
@@ -7379,6 +7696,11 @@
         "isobject": "^3.0.1"
       }
     },
+    "is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+    },
     "is-regex": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
@@ -7430,8 +7752,7 @@
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
-      "dev": true
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
     },
     "is-utf8": {
       "version": "0.2.1",
@@ -7454,6 +7775,11 @@
         "is-docker": "^2.0.0"
       }
     },
+    "is-yarn-global": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+      "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw=="
+    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -7667,6 +7993,11 @@
         }
       }
     },
+    "jju": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+      "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -7695,6 +8026,11 @@
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
       "dev": true
     },
+    "json-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+      "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg="
+    },
     "json-parse-better-errors": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -7707,6 +8043,14 @@
       "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
       "dev": true
     },
+    "json-parse-helpfulerror": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz",
+      "integrity": "sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w=",
+      "requires": {
+        "jju": "^1.1.0"
+      }
+    },
     "json-schema": {
       "version": "0.2.3",
       "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
@@ -7719,6 +8063,193 @@
       "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
       "dev": true
     },
+    "json-server": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/json-server/-/json-server-0.16.2.tgz",
+      "integrity": "sha512-USmSODvmBvt9Z7M3e4AHGHzLBcFlNkQMVOOqtB/h/k79JQI4saPcWniYvD5zf0kE3oGNR9VJzcHKzT8fZ9kEtw==",
+      "requires": {
+        "body-parser": "^1.19.0",
+        "chalk": "^3.0.0",
+        "compression": "^1.7.4",
+        "connect-pause": "^0.1.1",
+        "cors": "^2.8.5",
+        "errorhandler": "^1.5.1",
+        "express": "^4.17.1",
+        "express-urlrewrite": "^1.2.0",
+        "json-parse-helpfulerror": "^1.0.3",
+        "lodash": "^4.17.15",
+        "lodash-id": "^0.14.0",
+        "lowdb": "^1.0.0",
+        "method-override": "^3.0.0",
+        "morgan": "^1.9.1",
+        "nanoid": "^2.1.11",
+        "please-upgrade-node": "^3.2.0",
+        "pluralize": "^8.0.0",
+        "server-destroy": "^1.0.1",
+        "update-notifier": "^4.0.0",
+        "yargs": "^15.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "yargs": {
+          "version": "15.4.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^18.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "18.1.3",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
     "json-stringify-safe": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -8040,6 +8571,14 @@
         "source-map-support": "^0.5.5"
       }
     },
+    "keyv": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+      "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+      "requires": {
+        "json-buffer": "3.0.0"
+      }
+    },
     "killable": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@@ -8058,6 +8597,14 @@
       "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==",
       "dev": true
     },
+    "latest-version": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
+      "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
+      "requires": {
+        "package-json": "^6.3.0"
+      }
+    },
     "less": {
       "version": "3.12.2",
       "resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz",
@@ -8201,8 +8748,12 @@
     "lodash": {
       "version": "4.17.20",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
-      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
-      "dev": true
+      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+    },
+    "lodash-id": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/lodash-id/-/lodash-id-0.14.0.tgz",
+      "integrity": "sha1-uvSJNOVDobXWNG+MhGmLGoyAOJY="
     },
     "lodash._reinterpolate": {
       "version": "3.0.0",
@@ -8358,6 +8909,30 @@
         "signal-exit": "^3.0.0"
       }
     },
+    "lowdb": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz",
+      "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==",
+      "requires": {
+        "graceful-fs": "^4.1.3",
+        "is-promise": "^2.1.0",
+        "lodash": "4",
+        "pify": "^3.0.0",
+        "steno": "^0.4.1"
+      },
+      "dependencies": {
+        "pify": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+          "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+        }
+      }
+    },
+    "lowercase-keys": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+      "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+    },
     "lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -8524,8 +9099,7 @@
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
-      "dev": true
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
     },
     "memory-fs": {
       "version": "0.5.0",
@@ -8668,8 +9242,7 @@
     "merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
-      "dev": true
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
     },
     "merge-source-map": {
       "version": "1.1.0",
@@ -8700,11 +9273,36 @@
       "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
       "dev": true
     },
+    "method-override": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz",
+      "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==",
+      "requires": {
+        "debug": "3.1.0",
+        "methods": "~1.1.2",
+        "parseurl": "~1.3.2",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
     "methods": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
-      "dev": true
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
     },
     "micromatch": {
       "version": "4.0.2",
@@ -8737,20 +9335,17 @@
     "mime": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-      "dev": true
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
     },
     "mime-db": {
       "version": "1.44.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
-      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
-      "dev": true
+      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
     },
     "mime-types": {
       "version": "2.1.27",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
       "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
-      "dev": true,
       "requires": {
         "mime-db": "1.44.0"
       }
@@ -8761,6 +9356,11 @@
       "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
       "dev": true
     },
+    "mimic-response": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+      "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
+    },
     "min-indent": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -8848,8 +9448,7 @@
     "minimist": {
       "version": "1.2.5",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-      "dev": true
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
     },
     "minimist-options": {
       "version": "4.1.0",
@@ -8962,6 +9561,38 @@
       "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
       "dev": true
     },
+    "morgan": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+      "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+      "requires": {
+        "basic-auth": "~2.0.1",
+        "debug": "2.6.9",
+        "depd": "~2.0.0",
+        "on-finished": "~2.3.0",
+        "on-headers": "~1.0.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
     "move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -8990,8 +9621,7 @@
     "ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-      "dev": true
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "multicast-dns": {
       "version": "6.2.3",
@@ -9015,6 +9645,11 @@
       "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
+    "nanoid": {
+      "version": "2.1.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
+      "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
+    },
     "nanomatch": {
       "version": "1.2.13",
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -9044,8 +9679,7 @@
     "negotiator": {
       "version": "0.6.2",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
-      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
-      "dev": true
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
     },
     "neo-async": {
       "version": "2.6.2",
@@ -9350,8 +9984,7 @@
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
     "object-component": {
       "version": "0.0.3",
@@ -9543,7 +10176,6 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
       "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
-      "dev": true,
       "requires": {
         "ee-first": "1.1.1"
       }
@@ -9551,14 +10183,12 @@
     "on-headers": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
-      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
-      "dev": true
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
     },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -9719,6 +10349,11 @@
         "os-tmpdir": "^1.0.0"
       }
     },
+    "p-cancelable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
+      "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw=="
+    },
     "p-finally": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@@ -9729,7 +10364,6 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
       "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-      "dev": true,
       "requires": {
         "p-try": "^2.0.0"
       }
@@ -9764,8 +10398,25 @@
     "p-try": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+    },
+    "package-json": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
+      "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
+      "requires": {
+        "got": "^9.6.0",
+        "registry-auth-token": "^4.0.0",
+        "registry-url": "^5.0.0",
+        "semver": "^6.2.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        }
+      }
     },
     "pacote": {
       "version": "9.5.12",
@@ -10029,8 +10680,7 @@
     "parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-      "dev": true
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
     },
     "pascalcase": {
       "version": "0.1.1",
@@ -10083,8 +10733,7 @@
     "path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
-      "dev": true
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
     },
     "path-type": {
       "version": "4.0.0",
@@ -10147,6 +10796,19 @@
         "find-up": "^3.0.0"
       }
     },
+    "please-upgrade-node": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+      "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+      "requires": {
+        "semver-compare": "^1.0.0"
+      }
+    },
+    "pluralize": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+      "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="
+    },
     "pnp-webpack-plugin": {
       "version": "1.6.4",
       "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz",
@@ -11227,7 +11889,6 @@
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
       "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
-      "dev": true,
       "requires": {
         "forwarded": "~0.1.2",
         "ipaddr.js": "1.9.1"
@@ -11271,7 +11932,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
       "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-      "dev": true,
       "requires": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.1"
@@ -11306,6 +11966,14 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
+    "pupa": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
+      "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
+      "requires": {
+        "escape-goat": "^2.0.0"
+      }
+    },
     "q": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -11321,8 +11989,7 @@
     "qs": {
       "version": "6.7.0",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-      "dev": true
+      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
     },
     "query-string": {
       "version": "4.3.4",
@@ -11380,14 +12047,12 @@
     "range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-      "dev": true
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
     },
     "raw-body": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
       "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
-      "dev": true,
       "requires": {
         "bytes": "3.1.0",
         "http-errors": "1.7.2",
@@ -11398,14 +12063,12 @@
         "bytes": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
+          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
         },
         "iconv-lite": {
           "version": "0.4.24",
           "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
           "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
           "requires": {
             "safer-buffer": ">= 2.1.2 < 3"
           }
@@ -11422,6 +12085,17 @@
         "schema-utils": "^2.6.5"
       }
     },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      }
+    },
     "read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -11715,6 +12389,22 @@
         "unicode-match-property-value-ecmascript": "^1.2.0"
       }
     },
+    "registry-auth-token": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz",
+      "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==",
+      "requires": {
+        "rc": "^1.2.8"
+      }
+    },
+    "registry-url": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+      "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+      "requires": {
+        "rc": "^1.2.8"
+      }
+    },
     "regjsgen": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
@@ -11804,14 +12494,12 @@
     "require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
     },
     "require-main-filename": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-      "dev": true
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
     },
     "requires-port": {
       "version": "1.0.0",
@@ -11927,6 +12615,14 @@
         }
       }
     },
+    "responselike": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+      "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+      "requires": {
+        "lowercase-keys": "^1.0.0"
+      }
+    },
     "restore-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -12064,8 +12760,7 @@
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
     "safe-regex": {
       "version": "1.1.0",
@@ -12079,8 +12774,7 @@
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "sass": {
       "version": "1.26.10",
@@ -12183,6 +12877,26 @@
       "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
       "dev": true
     },
+    "semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
+    },
+    "semver-diff": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+      "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+      "requires": {
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        }
+      }
+    },
     "semver-dsl": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
@@ -12221,7 +12935,6 @@
       "version": "0.17.1",
       "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
       "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
-      "dev": true,
       "requires": {
         "debug": "2.6.9",
         "depd": "~1.1.2",
@@ -12242,7 +12955,6 @@
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
           "requires": {
             "ms": "2.0.0"
           },
@@ -12250,16 +12962,14 @@
             "ms": {
               "version": "2.0.0",
               "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-              "dev": true
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
             }
           }
         },
         "ms": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
         }
       }
     },
@@ -12332,7 +13042,6 @@
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
       "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
-      "dev": true,
       "requires": {
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
@@ -12340,11 +13049,15 @@
         "send": "0.17.1"
       }
     },
+    "server-destroy": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
+      "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0="
+    },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-      "dev": true
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
     },
     "set-immediate-shim": {
       "version": "1.0.1",
@@ -12384,8 +13097,7 @@
     "setprototypeof": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
-      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
-      "dev": true
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
     },
     "sha.js": {
       "version": "2.4.11",
@@ -12426,8 +13138,7 @@
     "signal-exit": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
-      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
-      "dev": true
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
     },
     "simple-swizzle": {
       "version": "0.2.2",
@@ -13234,8 +13945,15 @@
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
-      "dev": true
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+    },
+    "steno": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz",
+      "integrity": "sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=",
+      "requires": {
+        "graceful-fs": "^4.1.3"
+      }
     },
     "stream-browserify": {
       "version": "2.0.2",
@@ -13316,7 +14034,6 @@
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
       "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-      "dev": true,
       "requires": {
         "emoji-regex": "^7.0.1",
         "is-fullwidth-code-point": "^2.0.0",
@@ -13326,14 +14043,12 @@
         "ansi-regex": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
         },
         "strip-ansi": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
           "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
           "requires": {
             "ansi-regex": "^4.1.0"
           }
@@ -13450,6 +14165,11 @@
         "min-indent": "^1.0.0"
       }
     },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+    },
     "style-loader": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz",
@@ -13626,6 +14346,11 @@
         }
       }
     },
+    "term-size": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
+      "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw=="
+    },
     "terser": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
@@ -13769,6 +14494,11 @@
         }
       }
     },
+    "to-readable-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+      "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q=="
+    },
     "to-regex": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
@@ -13793,8 +14523,7 @@
     "toidentifier": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
-      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
-      "dev": true
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
     },
     "tough-cookie": {
       "version": "2.5.0",
@@ -13946,7 +14675,6 @@
       "version": "1.6.18",
       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
       "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-      "dev": true,
       "requires": {
         "media-typer": "0.3.0",
         "mime-types": "~2.1.24"
@@ -13958,6 +14686,14 @@
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
       "dev": true
     },
+    "typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "requires": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
     "typescript": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz",
@@ -14047,6 +14783,14 @@
         "imurmurhash": "^0.1.4"
       }
     },
+    "unique-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+      "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+      "requires": {
+        "crypto-random-string": "^2.0.0"
+      }
+    },
     "universal-analytics": {
       "version": "0.4.23",
       "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.23.tgz",
@@ -14067,8 +14811,7 @@
     "unpipe": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
-      "dev": true
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
     },
     "unquote": {
       "version": "1.1.1",
@@ -14122,6 +14865,71 @@
       "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
       "dev": true
     },
+    "update-notifier": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
+      "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==",
+      "requires": {
+        "boxen": "^4.2.0",
+        "chalk": "^3.0.0",
+        "configstore": "^5.0.1",
+        "has-yarn": "^2.1.0",
+        "import-lazy": "^2.1.0",
+        "is-ci": "^2.0.0",
+        "is-installed-globally": "^0.3.1",
+        "is-npm": "^4.0.0",
+        "is-yarn-global": "^0.3.0",
+        "latest-version": "^5.0.0",
+        "pupa": "^2.0.1",
+        "semver-diff": "^3.1.1",
+        "xdg-basedir": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "uri-js": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
@@ -14165,6 +14973,21 @@
         "requires-port": "^1.0.0"
       }
     },
+    "url-parse-lax": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+      "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+      "requires": {
+        "prepend-http": "^2.0.0"
+      },
+      "dependencies": {
+        "prepend-http": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+          "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc="
+        }
+      }
+    },
     "use": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -14239,8 +15062,7 @@
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
-      "dev": true
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
     },
     "uuid": {
       "version": "3.4.0",
@@ -14270,8 +15092,7 @@
     "vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
-      "dev": true
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
     },
     "vendors": {
       "version": "1.0.4",
@@ -15264,8 +16085,50 @@
     "which-module": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-      "dev": true
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+    },
+    "widest-line": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+      "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+      "requires": {
+        "string-width": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        }
+      }
     },
     "wordwrap": {
       "version": "1.0.0",
@@ -15344,8 +16207,18 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "requires": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
     },
     "ws": {
       "version": "6.2.1",
@@ -15356,6 +16229,11 @@
         "async-limiter": "~1.0.0"
       }
     },
+    "xdg-basedir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+      "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="
+    },
     "xml2js": {
       "version": "0.4.23",
       "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
@@ -15387,8 +16265,7 @@
     "y18n": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-      "dev": true
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
     },
     "yallist": {
       "version": "4.0.0",
diff --git a/package.json b/package.json
index 5a8956c0f..97ef23241 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,8 @@
     "lint": "ng lint",
     "e2e": "ng e2e",
     "release": "standard-version",
-    "translate": "ng xi18n --output-path src/locale --out-file messages.en.xlf"
+    "translate": "ng xi18n --output-path src/locale --out-file messages.en.xlf",
+    "api": "json-server api/db.json --routes api/routes.json --no-cors=true"
   },
   "private": true,
   "dependencies": {
@@ -24,6 +25,7 @@
     "@angular/platform-browser": "~10.1.3",
     "@angular/platform-browser-dynamic": "~10.1.3",
     "@angular/router": "~10.1.3",
+    "json-server": "^0.16.2",
     "rxjs": "~6.6.0",
     "tslib": "^2.0.0",
     "zone.js": "~0.10.2"
diff --git a/proxy.conf.json b/proxy.conf.json
new file mode 100644
index 000000000..c394a84fb
--- /dev/null
+++ b/proxy.conf.json
@@ -0,0 +1,5 @@
+{
+  "/api": {
+    "target": "http://localhost:3000"
+  }
+}
diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index 8071bfcce..db49c0aef 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -1 +1,17 @@
-<p>card wsdorks!</p>
+<span class="divider"></span>
+<span class="nbStructuresLabel">140 structures</span>
+
+<div class="structure">
+  <span class="typeStructure">Bibliothèque</span>
+  <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
+    <span class="nomStructure">Nom de la structure</span>
+    <div class="distanceStructure">
+      <span>|-----| 63 m</span>
+    </div>
+  </div>
+  <br />
+  <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="1vw">
+    <span class="dot"></span>
+    <span>Ouvert actuellement</span>
+  </div>
+</div>
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure/components/card/card.component.scss
index e69de29bb..18648a329 100644
--- a/src/app/structure/components/card/card.component.scss
+++ b/src/app/structure/components/card/card.component.scss
@@ -0,0 +1,22 @@
+.nbStructuresLabel {
+  color: #828282;
+  padding: 10px;
+  font-size: 14px;
+}
+.structure {
+  padding: 12px 0 12px 0;
+  border-bottom: 1px dashed #bdbdbd;
+  .typeStructure {
+    color: #828282;
+  }
+  .headerStructure {
+    .nomStructure {
+      font-weight: bold;
+      color: #594d59;
+      font-size: 22px;
+    }
+  }
+  &:last-child {
+    border-bottom: none;
+  }
+}
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
index 07a9ab07e..57820f6a3 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure/components/card/card.component.ts
@@ -1,15 +1,20 @@
 import { Component, OnInit } from '@angular/core';
+import { Structure } from '../../models/structure.model';
 
 @Component({
   selector: 'app-card',
   templateUrl: './card.component.html',
-  styleUrls: ['./card.component.scss']
+  styleUrls: ['./card.component.scss'],
 })
 export class CardComponent implements OnInit {
+  structure: Structure[] = [];
+  servicesProposes: any = [
+    { val: 'CAF', text: 'Droits à la CAF' },
+    { val: 'Pôle Emploi', text: 'Droits à Pôle Emploi' },
+    { val: 'Impôts', text: 'Droits aux Impots' },
+    { val: 'CPAM', text: 'Droits à la CPAM (AMELI)' },
+  ];
+  constructor() {}
 
-  constructor() { }
-
-  ngOnInit(): void {
-  }
-
+  ngOnInit(): void {}
 }
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
new file mode 100644
index 000000000..bf0a5b70a
--- /dev/null
+++ b/src/app/structure/models/structure.model.ts
@@ -0,0 +1,27 @@
+export class Structure {
+  id: string;
+  created_on: string;
+  last_modif: string;
+  owner: string;
+  status: string;
+  nom: string;
+  type_structure: string;
+  description: string;
+  num: string;
+  voie: string;
+  telephone: string;
+  courriel: string;
+  site_web: string;
+  facebook: string;
+  twitter: string;
+  instagram: string;
+  civilite_contact: string;
+  nom_contact: string;
+  prenom_contact: string;
+  email_contact: string;
+  fonction_contact: string;
+  pmr: boolean;
+  je_fais_a_la_place_de_lusager: boolean;
+  accompagnement_aux_demarches: string[];
+  wifi: boolean;
+}
diff --git a/src/app/structure/structure.component.html b/src/app/structure/structure.component.html
index 8688da6ce..a6dbe19b7 100644
--- a/src/app/structure/structure.component.html
+++ b/src/app/structure/structure.component.html
@@ -1,2 +1,2 @@
-<app-card></app-card>
 <app-recherche></app-recherche>
+<app-card></app-card>
diff --git a/src/app/structure/structure.module.ts b/src/app/structure/structure.module.ts
index 902f040cd..027e62301 100644
--- a/src/app/structure/structure.module.ts
+++ b/src/app/structure/structure.module.ts
@@ -3,10 +3,11 @@ import { CommonModule } from '@angular/common';
 import { StructureComponent } from './structure.component';
 import { CardComponent } from './components/card/card.component';
 import { RechercheComponent } from './components/recherche/recherche.component';
+import { HttpClientModule } from '@angular/common/http';
 
 @NgModule({
   declarations: [StructureComponent, CardComponent, RechercheComponent],
-  imports: [CommonModule],
+  imports: [CommonModule, HttpClientModule],
   exports: [StructureComponent],
 })
 export class StructureModule {}
-- 
GitLab


From f0ec840d63e785d9128024875f9b1b0c553cfbf8 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 9 Oct 2020 14:05:02 +0200
Subject: [PATCH 03/50] feat(card): ajout template + logique structures

---
 .gitignore                                    |   3 +
 package-lock.json                             |   5 +
 package.json                                  |   1 +
 .../components/card/card.component.html       |  28 ++--
 .../components/card/card.component.scss       |  46 +++++-
 .../components/card/card.component.ts         |  19 +--
 src/app/structure/models/structure.model.ts   |  47 ++++--
 .../structure/services/structure.service.ts   | 139 +++++++++++++++++-
 src/app/structure/structure.module.ts         |   3 +-
 src/assets/scss/_icons.scss                   |  14 ++
 10 files changed, 260 insertions(+), 45 deletions(-)

diff --git a/.gitignore b/.gitignore
index 86d943a9b..b1b6bcc81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,3 +44,6 @@ testem.log
 # System Files
 .DS_Store
 Thumbs.db
+
+# apiMock
+api/db.json
diff --git a/package-lock.json b/package-lock.json
index b09f84a5a..da8384e00 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8942,6 +8942,11 @@
         "yallist": "^4.0.0"
       }
     },
+    "luxon": {
+      "version": "1.25.0",
+      "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.25.0.tgz",
+      "integrity": "sha512-hEgLurSH8kQRjY6i4YLey+mcKVAWXbDNlZRmM6AgWDJ1cY3atl8Ztf5wEY7VBReFbmGnwQPz7KYJblL8B2k0jQ=="
+    },
     "magic-string": {
       "version": "0.25.7",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
diff --git a/package.json b/package.json
index 97ef23241..fe8dccab6 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
     "@angular/platform-browser-dynamic": "~10.1.3",
     "@angular/router": "~10.1.3",
     "json-server": "^0.16.2",
+    "luxon": "^1.25.0",
     "rxjs": "~6.6.0",
     "tslib": "^2.0.0",
     "zone.js": "~0.10.2"
diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index db49c0aef..e2443b8c8 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -1,17 +1,25 @@
-<span class="divider"></span>
-<span class="nbStructuresLabel">140 structures</span>
+<span class="nbStructuresLabel">{{ structures.length }} structures</span>
+<div class="structure" fxLayout="column" *ngFor="let structure of structures">
+  <span class="nomStructure">{{ structure.nom }}</span>
 
-<div class="structure">
-  <span class="typeStructure">Bibliothèque</span>
   <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
-    <span class="nomStructure">Nom de la structure</span>
-    <div class="distanceStructure">
-      <span>|-----| 63 m</span>
-    </div>
+    <span class="typeStructure">{{ structure.type_de_structure }}</span>
+    <span class="distanceStructure">|-| 63 m</span>
   </div>
   <br />
   <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="1vw">
-    <span class="dot"></span>
-    <span>Ouvert actuellement</span>
+    <div *ngIf="structure.estOuvert; else closed">
+      <span class="ico-dot-available"></span>
+      <span> Ouvert actuellement</span>
+    </div>
+    <ng-template #closed>
+      <span class="ico-dot-unavailable"></span>
+      <span *ngIf="structure.ouvreLe.jour; else noTime">
+        Fermé - Ouvre {{ structure.ouvreLe.jour }} à {{ structure.ouvreLe.horaire }}</span
+      >
+    </ng-template>
   </div>
 </div>
+<ng-template #noTime>
+  <span> Fermé - Aucun horaire disponible</span>
+</ng-template>
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure/components/card/card.component.scss
index 18648a329..f3f374801 100644
--- a/src/app/structure/components/card/card.component.scss
+++ b/src/app/structure/components/card/card.component.scss
@@ -1,22 +1,52 @@
+@import '../../../../assets/scss/icons';
 .nbStructuresLabel {
   color: #828282;
-  padding: 10px;
-  font-size: 14px;
+  font-family: Trebuchet MS;
+  font-style: normal;
+  font-weight: normal;
+  font-size: 16px;
+  line-height: 19px;
+  display: flex;
+  align-items: center;
 }
 .structure {
   padding: 12px 0 12px 0;
   border-bottom: 1px dashed #bdbdbd;
   .typeStructure {
     color: #828282;
+    font-family: Times New Roman;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 16px;
+    line-height: 100%;
   }
-  .headerStructure {
-    .nomStructure {
-      font-weight: bold;
-      color: #594d59;
-      font-size: 22px;
-    }
+  .nomStructure {
+    padding-top: 13px;
+    color: #594d59;
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: bold;
+    font-size: 20px;
+    line-height: 103%;
+    padding-bottom: 5px;
+  }
+  .distanceStructure {
+    font-family: Times New Roman;
+    font-style: normal;
+    font-size: 16px;
+    line-height: 103%;
+    color: #594d59;
   }
   &:last-child {
     border-bottom: none;
   }
 }
+.statusStructure {
+  span {
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 15px;
+    line-height: 103%;
+  }
+}
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
index 57820f6a3..093bdde33 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure/components/card/card.component.ts
@@ -1,5 +1,6 @@
 import { Component, OnInit } from '@angular/core';
 import { Structure } from '../../models/structure.model';
+import { StructureService } from '../../services/structure.service';
 
 @Component({
   selector: 'app-card',
@@ -7,14 +8,14 @@ import { Structure } from '../../models/structure.model';
   styleUrls: ['./card.component.scss'],
 })
 export class CardComponent implements OnInit {
-  structure: Structure[] = [];
-  servicesProposes: any = [
-    { val: 'CAF', text: 'Droits à la CAF' },
-    { val: 'Pôle Emploi', text: 'Droits à Pôle Emploi' },
-    { val: 'Impôts', text: 'Droits aux Impots' },
-    { val: 'CPAM', text: 'Droits à la CPAM (AMELI)' },
-  ];
-  constructor() {}
+  structures: Structure[] = [];
+  constructor(private _structureService: StructureService) {}
 
-  ngOnInit(): void {}
+  ngOnInit(): void {
+    this._structureService.recupererStructures().subscribe((structures: Structure[]) => {
+      structures.forEach((s: Structure) => {
+        this.structures.push(this._structureService.majOuvertureStructure(s));
+      });
+    });
+  }
 }
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
index bf0a5b70a..d64b5b3ad 100644
--- a/src/app/structure/models/structure.model.ts
+++ b/src/app/structure/models/structure.model.ts
@@ -1,13 +1,13 @@
 export class Structure {
-  id: string;
-  created_on: string;
-  last_modif: string;
-  owner: string;
-  status: string;
-  nom: string;
-  type_structure: string;
+  numero: string;
+  date_de_creation: string;
+  derniere_modification: string;
+  nom_de_lusager: string;
+  votre_structure_est_elle: string;
+  nom_de_votre_structure: string;
+  type_de_structure: string;
   description: string;
-  num: string;
+  n: string;
   voie: string;
   telephone: string;
   courriel: string;
@@ -15,13 +15,30 @@ export class Structure {
   facebook: string;
   twitter: string;
   instagram: string;
-  civilite_contact: string;
-  nom_contact: string;
-  prenom_contact: string;
+  civilite: string;
+  nom: string;
+  prenom: string;
   email_contact: string;
-  fonction_contact: string;
-  pmr: boolean;
-  je_fais_a_la_place_de_lusager: boolean;
-  accompagnement_aux_demarches: string[];
+  fonction: string;
+  accessibilite_personnes_a_mobilite_reduite_pmr: boolean;
+  jaccompagne_les_usagers_dans_leurs_demarches_en_ligne: boolean;
+  accompagnement_des_demarches: string[];
   wifi: boolean;
+  horaires: horaireStructure;
+  estOuvert: boolean;
+  ouvreLe: { jour: string; horaire: string };
+}
+
+export class horaireStructure {
+  lundi: Jour;
+  mardi: Jour;
+  mercredi: Jour;
+  jeudi: Jour;
+  vendredi: Jour;
+  samedi: Jour;
+  dimanche: Jour;
+}
+export class Jour {
+  open: boolean;
+  time: [{ openning: number; closing: number }];
 }
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
index 8a09d6adb..a72138d7e 100644
--- a/src/app/structure/services/structure.service.ts
+++ b/src/app/structure/services/structure.service.ts
@@ -1,9 +1,144 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
+import { Jour, Structure } from '../models/structure.model';
+const { DateTime } = require('luxon');
 
 @Injectable({
-  providedIn: 'root'
+  providedIn: 'root',
 })
 export class StructureService {
+  constructor(private http: HttpClient) {}
 
-  constructor() { }
+  recupererStructures() {
+    return this.http.get('/api/Structures');
+  }
+
+  majOuvertureStructure(structure: Structure) {
+    //Récupère le jour de la semaine.
+    var dt = DateTime.local();
+    var jourSemaine: number = dt.weekday;
+
+    //Vérifie si les minutes commencent par zéro pour éviter la suppression.
+    var now: number;
+    if (dt.minute.toString().length != 1) {
+      now = parseInt('' + dt.hour + dt.minute, 10);
+    } else {
+      now = parseInt('' + dt.hour + 0 + dt.minute, 10);
+    }
+
+    //Récupérer les horaires d'une structure en fonction de son jour pour indiquer si elle est ouverte.
+    var horaireStructure: Jour = this.recupererHoraire(structure, jourSemaine);
+    structure.estOuvert = false;
+    if (horaireStructure.open) {
+      horaireStructure.time.forEach((periode) => {
+        if (this.comparerHoraire(periode.openning, periode.closing, now)) {
+          structure.estOuvert = true;
+        }
+      });
+    }
+    structure.ouvreLe = this.recupererProchaineOuverture(structure, jourSemaine, jourSemaine, now);
+
+    return structure;
+  }
+
+  //Récupère les horaires d'une structure en fonction du jour de la semaine
+  recupererHoraire(structure: Structure, jourActuel: number) {
+    switch (jourActuel) {
+      case 1:
+        return structure.horaires.lundi;
+      case 2:
+        return structure.horaires.mardi;
+      case 3:
+        return structure.horaires.mercredi;
+      case 4:
+        return structure.horaires.jeudi;
+      case 5:
+        return structure.horaires.vendredi;
+      case 6:
+        return structure.horaires.samedi;
+      case 7:
+        return structure.horaires.dimanche;
+    }
+  }
+  //Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
+  comparerHoraire(heureDeb: number, heureFin: number, heureActuelle: number) {
+    return heureActuelle >= heureDeb && heureActuelle <= heureFin;
+  }
+
+  recupererProchaineOuverture(s: Structure, j: number, baseJour: number, baseHeure: number) {
+    //Récupérer horaire du jour en cours
+    var horaires = this.recupererHoraire(s, j);
+    //Condition pour stopper la récursion (Si le jour du compteur est égal au jour en cours)
+    if (j + 1 != baseJour) {
+      if (horaires.open) {
+        //Vérifie si le compteur correspond au jour en cours pour éviter de proposer
+        //les horaires déjà passés.
+        if (j != baseJour) {
+          var jourOuverture = null;
+          horaires.time.every((periode) => {
+            if (periode.openning) {
+              jourOuverture = { jour: this.numberToDay(j), horaire: this.numberToHour(periode.openning) };
+              return false;
+            }
+            return true;
+          });
+          //Si pas de période trouvée, on réitère.
+          if (!jourOuverture) {
+            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+          }
+          return jourOuverture;
+        } else {
+          var jourOuverture = null;
+          horaires.time.every((periode) => {
+            if (periode.openning >= baseHeure) {
+              jourOuverture = { jour: ' ', horaire: this.numberToHour(periode.openning) };
+              return false;
+            }
+            return true;
+          });
+          //Si pas de période trouvée, on réitère.
+          if (!jourOuverture) {
+            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+          }
+          return jourOuverture;
+        }
+      } else {
+        //Si le jour est égal à Dimanche, on le positionne sur Lundi.
+        if (j != 7) {
+          return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+        }
+        return this.recupererProchaineOuverture(s, 1, baseJour, baseHeure);
+      }
+    }
+    return 'Aucun horaire disponible';
+  }
+
+  numberToDay(n: number) {
+    switch (n) {
+      case 1:
+        return 'lundi';
+      case 2:
+        return 'mardi';
+      case 3:
+        return 'mercredi';
+      case 4:
+        return 'jeudi';
+      case 5:
+        return 'vendredi';
+      case 6:
+        return 'samedi';
+      case 7:
+        return 'dimanche';
+    }
+  }
+
+  numberToHour(n: number) {
+    if (n.toString().length == 3) {
+      var tabNum = n.toString().match(/.{1,1}/g);
+      return tabNum[0] + 'h' + tabNum[1] + tabNum[2];
+    } else if (n.toString().length == 4) {
+      var tabNum = n.toString().match(/.{1,2}/g);
+      return tabNum[0] + 'h' + tabNum[1];
+    }
+  }
 }
diff --git a/src/app/structure/structure.module.ts b/src/app/structure/structure.module.ts
index 027e62301..335604aef 100644
--- a/src/app/structure/structure.module.ts
+++ b/src/app/structure/structure.module.ts
@@ -4,10 +4,11 @@ import { StructureComponent } from './structure.component';
 import { CardComponent } from './components/card/card.component';
 import { RechercheComponent } from './components/recherche/recherche.component';
 import { HttpClientModule } from '@angular/common/http';
+import { FlexLayoutModule } from '@angular/flex-layout';
 
 @NgModule({
   declarations: [StructureComponent, CardComponent, RechercheComponent],
-  imports: [CommonModule, HttpClientModule],
+  imports: [CommonModule, HttpClientModule, FlexLayoutModule],
   exports: [StructureComponent],
 })
 export class StructureModule {}
diff --git a/src/assets/scss/_icons.scss b/src/assets/scss/_icons.scss
index b1dcb9ac7..a44fae8f2 100644
--- a/src/assets/scss/_icons.scss
+++ b/src/assets/scss/_icons.scss
@@ -64,3 +64,17 @@
     background: $orange;
   }
 }
+.ico-dot-available {
+  height: 12px;
+  width: 12px;
+  background-color: #41c29c;
+  border-radius: 50%;
+  display: inline-block;
+}
+.ico-dot-unavailable {
+  height: 12px;
+  width: 12px;
+  background-color: #b7b7b7;
+  border-radius: 50%;
+  display: inline-block;
+}
-- 
GitLab


From 2cd65e469fe4fe12ff8000ed6e330b34fb09d07e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20BRISON?=
 <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 9 Oct 2020 14:10:29 +0200
Subject: [PATCH 04/50] Delete db.json

---
 api/db.json | 58 -----------------------------------------------------
 1 file changed, 58 deletions(-)
 delete mode 100644 api/db.json

diff --git a/api/db.json b/api/db.json
deleted file mode 100644
index e41fd2d32..000000000
--- a/api/db.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
-  "structure": [
-    {
-      "id": "26-28",
-      "created_on": "22/09/2020 16:01",
-      "last_modif": "22/09/2020 16:01",
-      "owner": "-",
-      "status": "Un établissement principal (siège social)",
-      "nom": "Labit",
-      "type_structure": "MDM",
-      "description": "Ouvert à toute heure",
-      "num": "12",
-      "voie": "27838 Avenue Lacassagne",
-      "telephone": "0134257645",
-      "courriel": "coop.labit@gmail.com",
-      "site_web": "",
-      "facebook": "",
-      "twitter": "",
-      "instagram": "",
-      "civilite_contact": "Madame",
-      "nom_contact": "Labit",
-      "prenom_contact": "Valentine",
-      "email_contact": "coop.labit@gmail.com",
-      "fonction_contact": "Président de l'association",
-      "pmr": true,
-      "je_fais_a_la_place_de_lusager": true,
-      "accompagnement_aux_demarches": ["Pôle Emploi", "CPAM", "Impôts", "Logement"],
-      "wifi": true
-    },
-    {
-      "id": "26-10",
-      "created_on": "03/09/2020 14:14",
-      "last_modif": "03/09/2020 14:15",
-      "owner": "Marlène Simondant",
-      "status": "Un établissement principal (siège social)",
-      "nom": "fgh",
-      "type_structure": "Bibliothèque",
-      "description": "",
-      "num": "",
-      "voie": "26061 13ème Rue Cité Berliet",
-      "telephone": "0659856235",
-      "courriel": "test@test.te",
-      "site_web": "",
-      "facebook": "",
-      "twitter": "",
-      "instagram": "",
-      "civilite_contact": "",
-      "nom_contact": "dh",
-      "prenom_contact": "fxh",
-      "email_contact": "test@test.te",
-      "fonction_contact": "Bénévole",
-      "pmr": false,
-      "je_fais_a_la_place_de_lusager": false,
-      "accompagnement_aux_demarches": ["CPAM"],
-      "wifi": false
-    }
-  ]
-}
-- 
GitLab


From c9686d31d0b03b57e3e43a0458a9830b03441991 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 9 Oct 2020 15:00:31 +0200
Subject: [PATCH 05/50] fix(test) : add type 'node' for jasmine test + fix
 import test

---
 src/app/app.component.spec.ts                      | 12 ++++--------
 src/app/header/header.component.spec.ts            |  7 ++++---
 .../components/card/card.component.spec.ts         |  8 ++++----
 .../structure/services/structure.service.spec.ts   |  5 ++++-
 tsconfig.spec.json                                 | 14 +++-----------
 5 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts
index f8649a882..3ccaf52ed 100644
--- a/src/app/app.component.spec.ts
+++ b/src/app/app.component.spec.ts
@@ -5,12 +5,8 @@ import { AppComponent } from './app.component';
 describe('AppComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      imports: [
-        RouterTestingModule
-      ],
-      declarations: [
-        AppComponent
-      ],
+      imports: [RouterTestingModule],
+      declarations: [AppComponent],
     }).compileComponents();
   });
 
@@ -26,10 +22,10 @@ describe('AppComponent', () => {
     expect(app.title).toEqual('pamn');
   });
 
-  it('should render title', () => {
+  /*it('should render title', () => {
     const fixture = TestBed.createComponent(AppComponent);
     fixture.detectChanges();
     const compiled = fixture.nativeElement;
     expect(compiled.querySelector('.content span').textContent).toContain('pamn app is running!');
-  });
+  });*/
 });
diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts
index 381e8e80c..6e760707f 100644
--- a/src/app/header/header.component.spec.ts
+++ b/src/app/header/header.component.spec.ts
@@ -1,4 +1,5 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
 
 import { HeaderComponent } from './header.component';
 
@@ -8,9 +9,9 @@ describe('HeaderComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ HeaderComponent ]
-    })
-    .compileComponents();
+      imports: [RouterTestingModule],
+      declarations: [HeaderComponent],
+    }).compileComponents();
   });
 
   beforeEach(() => {
diff --git a/src/app/structure/components/card/card.component.spec.ts b/src/app/structure/components/card/card.component.spec.ts
index 3093fd5a3..c0787da7b 100644
--- a/src/app/structure/components/card/card.component.spec.ts
+++ b/src/app/structure/components/card/card.component.spec.ts
@@ -1,16 +1,16 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
 import { CardComponent } from './card.component';
-
+import { HttpClientModule } from '@angular/common/http';
 describe('CardComponent', () => {
   let component: CardComponent;
   let fixture: ComponentFixture<CardComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ CardComponent ]
-    })
-    .compileComponents();
+      imports: [HttpClientModule],
+      declarations: [CardComponent],
+    }).compileComponents();
   });
 
   beforeEach(() => {
diff --git a/src/app/structure/services/structure.service.spec.ts b/src/app/structure/services/structure.service.spec.ts
index d44ef8feb..8048236e0 100644
--- a/src/app/structure/services/structure.service.spec.ts
+++ b/src/app/structure/services/structure.service.spec.ts
@@ -1,3 +1,4 @@
+import { HttpClientModule } from '@angular/common/http';
 import { TestBed } from '@angular/core/testing';
 
 import { StructureService } from './structure.service';
@@ -6,7 +7,9 @@ describe('StructureService', () => {
   let service: StructureService;
 
   beforeEach(() => {
-    TestBed.configureTestingModule({});
+    TestBed.configureTestingModule({
+      imports: [HttpClientModule],
+    });
     service = TestBed.inject(StructureService);
   });
 
diff --git a/tsconfig.spec.json b/tsconfig.spec.json
index 092345b02..6c31866e9 100644
--- a/tsconfig.spec.json
+++ b/tsconfig.spec.json
@@ -3,16 +3,8 @@
   "extends": "./tsconfig.json",
   "compilerOptions": {
     "outDir": "./out-tsc/spec",
-    "types": [
-      "jasmine"
-    ]
+    "types": ["jasmine", "node"]
   },
-  "files": [
-    "src/test.ts",
-    "src/polyfills.ts"
-  ],
-  "include": [
-    "src/**/*.spec.ts",
-    "src/**/*.d.ts"
-  ]
+  "files": ["src/test.ts", "src/polyfills.ts"],
+  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
 }
-- 
GitLab


From e15e5dc6ea5d7a97ade2d21ddd2b20fcb557d100 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 9 Oct 2020 17:40:17 +0200
Subject: [PATCH 06/50] fix(test) : add test functions + fix model

---
 src/app/structure/models/structure.model.ts   |   2 +-
 .../services/structure.service.spec.ts        | 171 +++++++++++++++++-
 .../structure/services/structure.service.ts   |  20 +-
 3 files changed, 182 insertions(+), 11 deletions(-)

diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
index d64b5b3ad..5617a7948 100644
--- a/src/app/structure/models/structure.model.ts
+++ b/src/app/structure/models/structure.model.ts
@@ -40,5 +40,5 @@ export class horaireStructure {
 }
 export class Jour {
   open: boolean;
-  time: [{ openning: number; closing: number }];
+  time: { openning: number; closing: number }[];
 }
diff --git a/src/app/structure/services/structure.service.spec.ts b/src/app/structure/services/structure.service.spec.ts
index 8048236e0..e4f26a5ac 100644
--- a/src/app/structure/services/structure.service.spec.ts
+++ b/src/app/structure/services/structure.service.spec.ts
@@ -1,19 +1,174 @@
-import { HttpClientModule } from '@angular/common/http';
-import { TestBed } from '@angular/core/testing';
-
+import { HttpClient, HttpClientModule } from '@angular/common/http';
+import { inject, TestBed } from '@angular/core/testing';
+import { horaireStructure, Jour, Structure } from '../models/structure.model';
 import { StructureService } from './structure.service';
+const { DateTime } = require('luxon');
 
 describe('StructureService', () => {
-  let service: StructureService;
-
   beforeEach(() => {
     TestBed.configureTestingModule({
       imports: [HttpClientModule],
     });
-    service = TestBed.inject(StructureService);
   });
+  let _structureService: StructureService;
+  beforeEach(inject([StructureService], (_s: StructureService) => {
+    _structureService = _s;
+  }));
+  it('should return an hour string', () => {
+    const result = _structureService.numberToHour(928);
+    expect(result).toBe('9h28');
+  });
+
+  it('should return a day string', () => {
+    const result = _structureService.numberToDay(1);
+    expect(result).toBe('lundi');
+  });
+  it('should return null', () => {
+    const result = _structureService.numberToDay(8);
+    expect(result).toBeNull();
+  });
+
+  it('Comparer Horaire : should return true', () => {
+    const result = _structureService.comparerHoraire(830, 1200, 900);
+    expect(result).toBeTrue();
+  });
+
+  it('Comparer Horaire : should return false', () => {
+    const result = _structureService.comparerHoraire(830, 1200, 800);
+    expect(result).toBeFalse();
+  });
+
+  it('Recuperer Horaire : should return an object (Jour)', () => {
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 800, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.mardi = new Jour();
+    s.horaires.mardi.open = true;
+    s.horaires.mardi.time = horaire;
+    const jour: Jour = new Jour();
+    jour.open = true;
+    jour.time = horaire;
+    const result = _structureService.recupererHoraire(s, 2);
+    expect(result).toEqual(jour);
+  });
+
+  it('Recuperer Horaire : should return undefined', () => {
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 800, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.lundi.open = true;
+    s.horaires.lundi.time = horaire;
+    const jour: Jour = new Jour();
+    jour.open = true;
+    jour.time = horaire;
+    const result = _structureService.recupererHoraire(s, 2);
+    expect(result).toBeUndefined();
+  });
+
+  it('Recuperer Horaire : should return null', () => {
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 800, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.mardi = new Jour();
+    s.horaires.mardi.open = true;
+    s.horaires.mardi.time = horaire;
+    const result = _structureService.recupererHoraire(s, 8);
+    expect(result).toBeNull();
+  });
+
+  it('Recuperer Prochaine Ouverture : should return an object ({Jour/Horaire})', () => {
+    //Init structure
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 805, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
+    s.horaires.mardi.open = true;
+    s.horaires.mardi.time = horaire;
+
+    //Init sur vendredi à 14h00
+    const result = _structureService.recupererProchaineOuverture(s, 5, 5, 1400);
+    expect(result).toEqual({ jour: 'mardi', horaire: '8h05' });
+  });
+
+  it('Recuperer Prochaine Ouverture dans la journée : should return an object ({Jour/Horaire})', () => {
+    //Init structure
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 805, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
+    s.horaires.mardi.open = true;
+    s.horaires.mardi.time = horaire;
+
+    //Init sur mardi à 12h06
+    const result = _structureService.recupererProchaineOuverture(s, 2, 2, 1206);
+    expect(result).toEqual({ jour: ' ', horaire: '14h00' });
+  });
+
+  it('Recuperer Prochaine Ouverture pour la semaine prochaine sur le même jour : should return an object ({Jour/Horaire})', () => {
+    //Init structure
+    const s: Structure = new Structure();
+    var horaire = [
+      { openning: 805, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
+    s.horaires.mardi.open = true;
+    s.horaires.mardi.time = horaire;
+
+    //Init sur mardi à 15h15
+    const result = _structureService.recupererProchaineOuverture(s, 2, 2, 1515);
+    expect(result).toEqual({ jour: 'mardi', horaire: '8h05' });
+  });
+
+  it('Recuperer Prochaine Ouverture : should return an error string', () => {
+    //Init structure
+    const s: Structure = new Structure();
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
 
-  it('should be created', () => {
-    expect(service).toBeTruthy();
+    //Init sur jeudi à 12h06
+    const result = _structureService.recupererProchaineOuverture(s, 4, 2, 1206);
+    expect(result).toEqual('Aucun horaire disponible');
   });
 });
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
index a72138d7e..dc5803152 100644
--- a/src/app/structure/services/structure.service.ts
+++ b/src/app/structure/services/structure.service.ts
@@ -37,7 +37,6 @@ export class StructureService {
       });
     }
     structure.ouvreLe = this.recupererProchaineOuverture(structure, jourSemaine, jourSemaine, now);
-
     return structure;
   }
 
@@ -58,6 +57,8 @@ export class StructureService {
         return structure.horaires.samedi;
       case 7:
         return structure.horaires.dimanche;
+      default:
+        return null;
     }
   }
   //Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
@@ -110,7 +111,20 @@ export class StructureService {
         return this.recupererProchaineOuverture(s, 1, baseJour, baseHeure);
       }
     }
-    return 'Aucun horaire disponible';
+    var lastChancehoraire = this.recupererHoraire(s, j + 1);
+    var lastJour: any;
+    if (lastChancehoraire.open) {
+      lastChancehoraire.time.every((periode) => {
+        if (periode.openning && periode.openning < baseHeure) {
+          lastJour = { jour: this.numberToDay(j + 1), horaire: this.numberToHour(periode.openning) };
+          return false;
+        }
+        lastJour = 'Aucun horaire disponible';
+      });
+    } else {
+      lastJour = 'Aucun horaire disponible';
+    }
+    return lastJour;
   }
 
   numberToDay(n: number) {
@@ -129,6 +143,8 @@ export class StructureService {
         return 'samedi';
       case 7:
         return 'dimanche';
+      default:
+        return null;
     }
   }
 
-- 
GitLab


From c5b1c9d732c5db6497ee66bf6fef51c242da0ce2 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 12 Oct 2020 10:21:45 +0200
Subject: [PATCH 07/50] fix(card) : add condition for monday problem + export
 date from service to component
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Condition supplémentaire sur la fonction récursive pour gérer le cas d'un Lundi.
Suppression de l'import Luxon dans le service.
---
 .../components/card/card.component.ts         |  4 +-
 .../services/structure.service.spec.ts        | 51 ++++++++++++++++++-
 .../structure/services/structure.service.ts   | 19 ++++---
 3 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
index 093bdde33..ad3154950 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure/components/card/card.component.ts
@@ -1,6 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { Structure } from '../../models/structure.model';
 import { StructureService } from '../../services/structure.service';
+const { DateTime } = require('luxon');
 
 @Component({
   selector: 'app-card',
@@ -12,9 +13,10 @@ export class CardComponent implements OnInit {
   constructor(private _structureService: StructureService) {}
 
   ngOnInit(): void {
+    var dt = DateTime.local();
     this._structureService.recupererStructures().subscribe((structures: Structure[]) => {
       structures.forEach((s: Structure) => {
-        this.structures.push(this._structureService.majOuvertureStructure(s));
+        this.structures.push(this._structureService.majOuvertureStructure(s, dt));
       });
     });
   }
diff --git a/src/app/structure/services/structure.service.spec.ts b/src/app/structure/services/structure.service.spec.ts
index e4f26a5ac..7c885d669 100644
--- a/src/app/structure/services/structure.service.spec.ts
+++ b/src/app/structure/services/structure.service.spec.ts
@@ -133,7 +133,7 @@ describe('StructureService', () => {
   });
 
   it('Recuperer Prochaine Ouverture pour la semaine prochaine sur le même jour : should return an object ({Jour/Horaire})', () => {
-    //Init structure
+    //Init structure avec deux horaires le mardi
     const s: Structure = new Structure();
     var horaire = [
       { openning: 805, closing: 1200 },
@@ -156,7 +156,7 @@ describe('StructureService', () => {
   });
 
   it('Recuperer Prochaine Ouverture : should return an error string', () => {
-    //Init structure
+    //Init structure avec aucun horaire
     const s: Structure = new Structure();
     s.horaires = new horaireStructure();
     s.horaires.lundi = new Jour();
@@ -171,4 +171,51 @@ describe('StructureService', () => {
     const result = _structureService.recupererProchaineOuverture(s, 4, 2, 1206);
     expect(result).toEqual('Aucun horaire disponible');
   });
+
+  it('Mise à jour ouverture de la structure : should return true', () => {
+    var horaire = [
+      { openning: 805, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
+    //Init structure avec aucun horaire
+    const s: Structure = new Structure();
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
+
+    s.horaires.jeudi.open = true;
+    s.horaires.jeudi.time = horaire;
+
+    //Init date sur un jeudi à 9h05
+    var dt = new DateTime.local(2020, 10, 8, 9, 5);
+    const result = _structureService.majOuvertureStructure(s, dt);
+    expect(result.estOuvert).toEqual(true);
+  });
+
+  it('Mise à jour ouverture de la structure : should return false', () => {
+    var horaire = [{ openning: 1400, closing: 1600 }];
+    //Init structure avec aucun horaire
+    const s: Structure = new Structure();
+    s.horaires = new horaireStructure();
+    s.horaires.lundi = new Jour();
+    s.horaires.mardi = new Jour();
+    s.horaires.mercredi = new Jour();
+    s.horaires.jeudi = new Jour();
+    s.horaires.vendredi = new Jour();
+    s.horaires.samedi = new Jour();
+    s.horaires.dimanche = new Jour();
+
+    s.horaires.jeudi.open = true;
+    s.horaires.jeudi.time = horaire;
+
+    //Init date sur un jeudi à 9h05
+    var dt = new DateTime.local(2020, 10, 8, 9, 5);
+    const result = _structureService.majOuvertureStructure(s, dt);
+    expect(result.estOuvert).toEqual(false);
+  });
 });
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
index dc5803152..f18978024 100644
--- a/src/app/structure/services/structure.service.ts
+++ b/src/app/structure/services/structure.service.ts
@@ -1,7 +1,6 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Jour, Structure } from '../models/structure.model';
-const { DateTime } = require('luxon');
 
 @Injectable({
   providedIn: 'root',
@@ -13,17 +12,16 @@ export class StructureService {
     return this.http.get('/api/Structures');
   }
 
-  majOuvertureStructure(structure: Structure) {
+  majOuvertureStructure(structure: Structure, dateActuelle: any) {
     //Récupère le jour de la semaine.
-    var dt = DateTime.local();
-    var jourSemaine: number = dt.weekday;
+    var jourSemaine: number = dateActuelle.weekday;
 
     //Vérifie si les minutes commencent par zéro pour éviter la suppression.
     var now: number;
-    if (dt.minute.toString().length != 1) {
-      now = parseInt('' + dt.hour + dt.minute, 10);
+    if (dateActuelle.minute.toString().length != 1) {
+      now = parseInt('' + dateActuelle.hour + dateActuelle.minute, 10);
     } else {
-      now = parseInt('' + dt.hour + 0 + dt.minute, 10);
+      now = parseInt('' + dateActuelle.hour + 0 + dateActuelle.minute, 10);
     }
 
     //Récupérer les horaires d'une structure en fonction de son jour pour indiquer si elle est ouverte.
@@ -104,10 +102,15 @@ export class StructureService {
           return jourOuverture;
         }
       } else {
-        //Si le jour est égal à Dimanche, on le positionne sur Lundi.
+        //Si le jour n'est pas égal à Dimanche, on l'incrémente de 1.
         if (j != 7) {
           return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
         }
+        //Si le jour est égal à Lundi, on le positionne sur 0 pour activer la condition d'arrêt.
+        if (baseJour == 1) {
+          return this.recupererProchaineOuverture(s, 0, baseJour, baseHeure);
+        }
+        //Si le jour est égal à Dimanche, on le positionne sur Lundi.
         return this.recupererProchaineOuverture(s, 1, baseJour, baseHeure);
       }
     }
-- 
GitLab


From aa7cac38b2ab92413058db0a90392657cc0f88ba Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 12 Oct 2020 14:48:54 +0200
Subject: [PATCH 08/50] feat(search) : add html style + icon search

---
 .../recherche/recherche.component.html        |  38 +++-
 .../recherche/recherche.component.scss        | 172 ++++++++++++++++++
 src/app/structure/structure.component.html    |   7 +-
 src/app/structure/structure.component.scss    |  11 ++
 src/assets/scss/_icons.scss                   |  20 ++
 5 files changed, 245 insertions(+), 3 deletions(-)

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index 63c7b1a72..bca3c4b6f 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -1 +1,37 @@
-<p>recherche works!</p>
+<div class="header">
+  <span class="title">Acteurs de la médiation</span>
+</div>
+<div class="content" fxLayout="column">
+  <div class="searchSection" fxLayout="row" fxLayoutGap="1.5vw">
+    <div class="icon">
+      <div class="ico-pin-search grey"></div>
+    </div>
+    <input type="text" placeholder="Rechercher une adresse, une association..." />
+    <button type="button">Rechercher</button>
+  </div>
+
+  <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
+    <button type="button">
+      <span class="btnText">Services</span>
+      <div class="arrow"></div>
+    </button>
+    <button type="button">
+      <span class="btnText">Accueil</span>
+      <div class="arrow"></div>
+    </button>
+    <button type="button">
+      <span class="btnText">Plus de filtres</span>
+      <div class="arrow"></div>
+    </button>
+  </div>
+</div>
+<div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
+  <div class="checkbox">
+    <label>
+      <input type="checkbox" />
+      <span class="customCheck"></span>
+      Pass numérique
+    </label>
+  </div>
+  <a href="">Ajouter une structure</a>
+</div>
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index e69de29bb..41a606c70 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -0,0 +1,172 @@
+@import '../../../../assets/scss/icons';
+@import '../../../../assets/scss/color';
+.header {
+  .title {
+    font-family: Times New Roman;
+    font-style: normal;
+    font-weight: bold;
+    font-size: 20px;
+    line-height: 103%;
+    padding: 16px 0 16px 0;
+
+    display: flex;
+    align-items: center;
+    text-transform: uppercase;
+  }
+}
+.content {
+  margin: 10px 0 0px 0;
+  .icon {
+    border: 1px solid $grey;
+    padding: 4px 6px 8px 6px;
+    border-radius: 4px;
+    cursor: pointer;
+  }
+  input {
+    width: 100%;
+    background-color: $grey-4;
+    border: none;
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 12px;
+    line-height: 17px;
+    display: flex;
+    align-items: center;
+    padding-left: 10px;
+    text-overflow: ellipsis;
+    color: $grey-1;
+    outline: none;
+  }
+  .searchSection {
+    button {
+      border: none;
+      cursor: pointer;
+      background-color: $purple;
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 100%;
+      align-items: center;
+      text-align: center;
+      color: $white;
+      padding: 0 10px 0 10px;
+      outline: none;
+    }
+  }
+  .btnSection {
+    padding: 16px 0 16px 0;
+    button {
+      border: 1px solid $grey;
+      border-radius: 33px;
+      background-color: $white;
+      padding: 2px 6px 2px 13px;
+      align-items: center;
+      display: flex;
+      cursor: pointer;
+
+      .btnText {
+        justify-content: center;
+        font-family: Trebuchet MS;
+        font-style: normal;
+        font-weight: normal;
+        font-size: 13px;
+        line-height: 19px;
+        display: flex;
+        align-items: center;
+      }
+      &:focus {
+        border: 1px solid $orange-light;
+        color: $orange-light;
+        outline: none;
+        .arrow {
+          background-color: transparent;
+          border-bottom: 1px solid $orange-light;
+          border-right: 1px solid $orange-light;
+          transform: translateY(25%) rotate(-135deg);
+          margin: 0 5px 0 10px;
+          height: 7px;
+          width: 7px;
+        }
+      }
+    }
+    .arrow {
+      background-color: transparent;
+      border-bottom: 1px solid $grey;
+      border-right: 1px solid $grey;
+      transform: translateY(-25%) rotate(45deg);
+      margin: 0 5px 0 10px;
+      height: 7px;
+      width: 7px;
+    }
+  }
+}
+.footer {
+  margin: 0px 0 16px 0;
+  a {
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: bold;
+    font-size: 13px;
+    line-height: 18px;
+    /* or 120% */
+
+    display: flex;
+    align-items: center;
+    text-decoration-line: underline;
+  }
+  .checkbox {
+    position: relative;
+    padding-left: 27px;
+    label {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: normal;
+      font-size: 15px;
+      line-height: 21px;
+    }
+    input {
+      position: absolute;
+      opacity: 0;
+      height: 0;
+      width: 0;
+      &:checked ~ .customCheck {
+        background-color: $orange-light;
+        border-color: transparent;
+      }
+      &:checked ~ .customCheck:after {
+        display: block;
+      }
+    }
+    .customCheck {
+      position: absolute;
+      height: 18px;
+      width: 18px;
+      background-color: $white;
+      border: 1px solid $grey;
+      cursor: pointer;
+      top: 0;
+      left: 0;
+      &:hover {
+        background-color: $grey-4;
+      }
+      &:after {
+        content: '';
+        position: absolute;
+        display: none;
+      }
+      &:after {
+        left: 6.5px;
+        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/structure.component.html b/src/app/structure/structure.component.html
index a6dbe19b7..86c8f6308 100644
--- a/src/app/structure/structure.component.html
+++ b/src/app/structure/structure.component.html
@@ -1,2 +1,5 @@
-<app-recherche></app-recherche>
-<app-card></app-card>
+<div class="container">
+  <app-recherche></app-recherche>
+  <div class="divider"></div>
+  <app-card></app-card>
+</div>
diff --git a/src/app/structure/structure.component.scss b/src/app/structure/structure.component.scss
index e69de29bb..2d506b58d 100644
--- a/src/app/structure/structure.component.scss
+++ b/src/app/structure/structure.component.scss
@@ -0,0 +1,11 @@
+@import '../../assets/scss/color';
+
+.divider {
+  width: 100%;
+  height: 1px;
+  background-color: $grey-4;
+}
+//En attendant de l'intégrer avec la map
+.container {
+  width: 320px;
+}
diff --git a/src/assets/scss/_icons.scss b/src/assets/scss/_icons.scss
index a44fae8f2..54bf61acf 100644
--- a/src/assets/scss/_icons.scss
+++ b/src/assets/scss/_icons.scss
@@ -64,6 +64,26 @@
     background: $orange;
   }
 }
+.ico-pin-search {
+  width: 18px;
+  height: 18px;
+  border-radius: 50% 50% 50% 0;
+  -webkit-transform: rotate(-45deg);
+  transform: rotate(-45deg);
+  &:before {
+    content: '';
+    position: absolute;
+    left: 5px;
+    top: 6px;
+    width: 7px;
+    height: 7px;
+    border-radius: 4px;
+    background-color: white;
+  }
+  &.grey {
+    background-color: #828282;
+  }
+}
 .ico-dot-available {
   height: 12px;
   width: 12px;
-- 
GitLab


From 4dd91784c1d12a3866de6d54b71c5b5e874c0e58 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 12 Oct 2020 15:40:03 +0200
Subject: [PATCH 09/50] fix(search) : Fix btn design clicked + init modal
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Utilisation du TS plutôt que des propriétés CSS pour la gestion Activé/Désactivé des filtres
---
 .../recherche/recherche.component.html        |  7 ++--
 .../recherche/recherche.component.scss        | 39 ++++++++++++-------
 .../recherche/recherche.component.ts          | 37 ++++++++++++++++--
 3 files changed, 62 insertions(+), 21 deletions(-)

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index bca3c4b6f..a1e2b199d 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -11,19 +11,20 @@
   </div>
 
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
-    <button type="button">
+    <button type="button" [className]="btnServicesChecked ? 'selected' : ''" (click)="openModal(this.modalType[0])">
       <span class="btnText">Services</span>
       <div class="arrow"></div>
     </button>
-    <button type="button">
+    <button type="button" [className]="btnHomeChecked ? 'selected' : ''" (click)="openModal(this.modalType[1])">
       <span class="btnText">Accueil</span>
       <div class="arrow"></div>
     </button>
-    <button type="button">
+    <button type="button" [className]="btnMoreFilterchecked ? 'selected' : ''" (click)="openModal(this.modalType[2])">
       <span class="btnText">Plus de filtres</span>
       <div class="arrow"></div>
     </button>
   </div>
+  <div *ngIf="modalOpened" class="modal"></div>
 </div>
 <div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index 41a606c70..b1e1cac04 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -58,6 +58,8 @@
   .btnSection {
     padding: 16px 0 16px 0;
     button {
+      outline: none;
+
       border: 1px solid $grey;
       border-radius: 33px;
       background-color: $white;
@@ -65,7 +67,6 @@
       align-items: center;
       display: flex;
       cursor: pointer;
-
       .btnText {
         justify-content: center;
         font-family: Trebuchet MS;
@@ -76,19 +77,18 @@
         display: flex;
         align-items: center;
       }
-      &:focus {
-        border: 1px solid $orange-light;
-        color: $orange-light;
-        outline: none;
-        .arrow {
-          background-color: transparent;
-          border-bottom: 1px solid $orange-light;
-          border-right: 1px solid $orange-light;
-          transform: translateY(25%) rotate(-135deg);
-          margin: 0 5px 0 10px;
-          height: 7px;
-          width: 7px;
-        }
+    }
+    .selected {
+      border: 1px solid $orange-light;
+      color: $orange-light;
+      .arrow {
+        background-color: transparent;
+        border-bottom: 1px solid $orange-light;
+        border-right: 1px solid $orange-light;
+        transform: translateY(25%) rotate(-135deg);
+        margin: 0 5px 0 10px;
+        height: 7px;
+        width: 7px;
       }
     }
     .arrow {
@@ -170,3 +170,14 @@
     }
   }
 }
+.modal {
+  height: 500px;
+  width: 1100px;
+  background: $white;
+  border: 1px solid $purple;
+  box-sizing: border-box;
+  border-radius: 8px;
+  z-index: 1;
+  position: fixed;
+  margin-top: 80px;
+}
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
index b37a52c87..f47084959 100644
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ b/src/app/structure/components/recherche/recherche.component.ts
@@ -3,13 +3,42 @@ import { Component, OnInit } from '@angular/core';
 @Component({
   selector: 'app-recherche',
   templateUrl: './recherche.component.html',
-  styleUrls: ['./recherche.component.scss']
+  styleUrls: ['./recherche.component.scss'],
 })
 export class RechercheComponent implements OnInit {
-
-  constructor() { }
-
+  constructor() {}
+  modalOpened: string;
+  modalType: string[] = ['services', 'accueil', 'plusFiltres'];
+  btnServicesChecked: boolean;
+  btnHomeChecked: boolean;
+  btnMoreFilterchecked: boolean;
   ngOnInit(): void {
+    this.modalOpened = null;
+    this.btnServicesChecked = false;
   }
 
+  openModal(option: string) {
+    this.modalOpened = null;
+    switch (option) {
+      case this.modalType[0]:
+        this.btnServicesChecked = !this.btnServicesChecked;
+        this.btnHomeChecked = false;
+        this.btnMoreFilterchecked = false;
+        if (this.btnServicesChecked) this.modalOpened = this.modalType[0];
+
+        break;
+      case this.modalType[1]:
+        this.btnHomeChecked = !this.btnHomeChecked;
+        this.btnMoreFilterchecked = false;
+        this.btnServicesChecked = false;
+        if (this.btnHomeChecked) this.modalOpened = this.modalType[1];
+        break;
+      case this.modalType[2]:
+        this.btnMoreFilterchecked = !this.btnMoreFilterchecked;
+        this.btnServicesChecked = false;
+        this.btnHomeChecked = false;
+        if (this.btnMoreFilterchecked) this.modalOpened = this.modalType[2];
+        break;
+    }
+  }
 }
-- 
GitLab


From 2f26a9680a3df06fd520bcd73c84b0d703890d33 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 13 Oct 2020 09:14:28 +0200
Subject: [PATCH 10/50] fix(search) : add modal + module list

---
 .../recherche/recherche.component.html        |  30 ++-
 .../recherche/recherche.component.scss        | 171 ++++++++++++------
 .../recherche/recherche.component.ts          |  45 ++++-
 src/app/structure/models/recherche.model.ts   |   5 +
 4 files changed, 192 insertions(+), 59 deletions(-)
 create mode 100644 src/app/structure/models/recherche.model.ts

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index a1e2b199d..b5b6f48af 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -24,7 +24,35 @@
       <div class="arrow"></div>
     </button>
   </div>
-  <div *ngIf="modalOpened" class="modal"></div>
+  <div *ngIf="modalOpened" class="modal" fxLayout="column" fxLayoutAlign="space-between">
+    <div class="contentModal" fxLayout="row wrap">
+      <!--<div class="blockFiltre" *ngFor="let s of services">-->
+      <div class="blockFiltre" *ngFor="let s of services">
+        <div class="blockLigne">
+          <h4>{{ s.titre }}</h4>
+          <div
+            fxLayout="row"
+            class="ligneFiltre"
+            fxLayoutAlign="space-between center"
+            *ngFor="let categ of s.categories"
+          >
+            <div class="checkbox">
+              <label>
+                <input type="checkbox" />
+                <span class="customCheck"></span>
+                {{ categ }}
+              </label>
+            </div>
+            <span class="nbResult">34</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
+      <a href="">Effacer</a>
+      <button type="button" (click)="applyFilter()">Appliquer</button>
+    </div>
+  </div>
 </div>
 <div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index b1e1cac04..81da77faf 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -1,5 +1,6 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
+
 .header {
   .title {
     font-family: Times New Roman;
@@ -51,7 +52,7 @@
       align-items: center;
       text-align: center;
       color: $white;
-      padding: 0 10px 0 10px;
+      padding: 3px 16px 3px 16px;
       outline: none;
     }
   }
@@ -116,68 +117,126 @@
     align-items: center;
     text-decoration-line: underline;
   }
-  .checkbox {
-    position: relative;
-    padding-left: 27px;
-    label {
+}
+.modal {
+  height: 654px;
+  max-width: 1100px;
+  background: $white;
+  border: 1px solid $purple;
+  box-sizing: border-box;
+  border-radius: 8px;
+  z-index: 1;
+  position: absolute;
+  margin-top: 80px;
+  .contentModal {
+    writing-mode: vertical-lr;
+    padding: 20px 5px 10px 5px;
+    overflow-y: hidden;
+    max-width: 1100px;
+    .blockFiltre {
+      writing-mode: horizontal-tb;
+      max-width: 320px;
+      padding: 0 10px 10px 10px;
+    }
+    .ligneFiltre {
+      margin: 5px 0 5px 0;
+    }
+    h4 {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 17px;
+      display: flex;
+      align-items: center;
+      margin: 0;
+    }
+    .nbResult {
       font-family: Trebuchet MS;
       font-style: normal;
       font-weight: normal;
-      font-size: 15px;
-      line-height: 21px;
+      font-size: 13px;
+      line-height: 15px;
     }
-    input {
-      position: absolute;
-      opacity: 0;
-      height: 0;
-      width: 0;
-      &:checked ~ .customCheck {
-        background-color: $orange-light;
-        border-color: transparent;
-      }
-      &:checked ~ .customCheck:after {
-        display: block;
-      }
+    label {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: normal;
+      font-size: 14px;
+      line-height: 16px;
     }
-    .customCheck {
-      position: absolute;
-      height: 18px;
-      width: 18px;
-      background-color: $white;
-      border: 1px solid $grey;
+  }
+  .footer {
+    height: 32px;
+    padding-right: 24px;
+    button {
+      height: 100%;
+      border: none;
       cursor: pointer;
-      top: 0;
-      left: 0;
-      &:hover {
-        background-color: $grey-4;
-      }
-      &:after {
-        content: '';
-        position: absolute;
-        display: none;
-      }
-      &:after {
-        left: 6.5px;
-        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);
-      }
+      background-color: $purple;
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 100%;
+      align-items: center;
+      text-align: center;
+      color: $white;
+      padding: 3px 16px 3px 16px;
+      outline: none;
     }
   }
 }
-.modal {
-  height: 500px;
-  width: 1100px;
-  background: $white;
-  border: 1px solid $purple;
-  box-sizing: border-box;
-  border-radius: 8px;
-  z-index: 1;
-  position: fixed;
-  margin-top: 80px;
+.checkbox {
+  position: relative;
+  padding-left: 27px;
+  label {
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 15px;
+    line-height: 21px;
+  }
+  input {
+    position: absolute;
+    opacity: 0;
+    height: 0;
+    width: 0;
+    &:checked ~ .customCheck {
+      background-color: $orange-light;
+      border-color: transparent;
+    }
+    &:checked ~ .customCheck:after {
+      display: block;
+    }
+  }
+  .customCheck {
+    position: absolute;
+    height: 18px;
+    width: 18px;
+    background-color: $white;
+    border: 1px solid $grey;
+    cursor: pointer;
+    top: 0;
+    left: 0;
+    &:hover {
+      background-color: $grey-4;
+    }
+    &:after {
+      content: '';
+      position: absolute;
+      display: none;
+    }
+    &:after {
+      left: 6.5px;
+      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/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
index f47084959..15fb2c9cf 100644
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ b/src/app/structure/components/recherche/recherche.component.ts
@@ -1,4 +1,5 @@
 import { Component, OnInit } from '@angular/core';
+import { Service } from '../../models/recherche.model';
 
 @Component({
   selector: 'app-recherche',
@@ -12,11 +13,32 @@ export class RechercheComponent implements OnInit {
   btnServicesChecked: boolean;
   btnHomeChecked: boolean;
   btnMoreFilterchecked: boolean;
+  test = '50%';
+  services: Service[];
+
   ngOnInit(): void {
-    this.modalOpened = null;
+    this.modalOpened = 'services';
     this.btnServicesChecked = false;
+    this.services = [];
+    this.mockService('Accompagnement aux démarches en ligne', 'CAF', 7);
+    this.mockService('Insertion sociale et professionnelle', 'Diffuser son CV en ligne', 5);
+    this.mockService('Accès aux droits', 'Déclarer ses revenus en ligne et découvertes des services proposés', 8);
+    this.mockService('Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
+    this.mockService('Compétences de base', 'Faire un diagnostic des compétences', 8);
+    this.mockService('Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
+    console.log(this.services);
+    this.calcSizeCol(this.services);
   }
 
+  mockService(titre: string, categ: string, nbCateg: number) {
+    var service1 = new Service();
+    service1.titre = titre;
+    service1.categories = [];
+    for (var i = 0; i < nbCateg; i++) {
+      service1.categories.push(categ + '_' + i);
+    }
+    this.services.push(service1);
+  }
   openModal(option: string) {
     this.modalOpened = null;
     switch (option) {
@@ -25,7 +47,6 @@ export class RechercheComponent implements OnInit {
         this.btnHomeChecked = false;
         this.btnMoreFilterchecked = false;
         if (this.btnServicesChecked) this.modalOpened = this.modalType[0];
-
         break;
       case this.modalType[1]:
         this.btnHomeChecked = !this.btnHomeChecked;
@@ -41,4 +62,24 @@ export class RechercheComponent implements OnInit {
         break;
     }
   }
+  applyFilter() {
+    this.openModal(this.modalOpened);
+  }
+
+  calcSizeCol(services: Service[]) {
+    for (var i = 0; i < services.length; i++) {
+      if (services[i + 1]) {
+        var nb1, nb2: number;
+        nb1 = services[i].categories.length;
+        nb2 = services[i + 1].categories.length;
+        if (nb1 + nb2 <= 13) {
+          services[i].size = parseFloat((nb1 / 13).toPrecision(2)) * 100;
+          services[i + 1].size = parseFloat((1 - services[i].size / 100).toPrecision(2)) * 100;
+          i++;
+        } else {
+          services[i].size = 100;
+        }
+      }
+    }
+  }
 }
diff --git a/src/app/structure/models/recherche.model.ts b/src/app/structure/models/recherche.model.ts
new file mode 100644
index 000000000..5904abd46
--- /dev/null
+++ b/src/app/structure/models/recherche.model.ts
@@ -0,0 +1,5 @@
+export class Service {
+  titre: string;
+  categories: string[];
+  size: number;
+}
-- 
GitLab


From 74601392794bfbe07e66ae53bcf29fa65b673d05 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 13 Oct 2020 09:55:55 +0200
Subject: [PATCH 11/50] fix(checkbox) : fix checkbox display checked

---
 .../recherche/recherche.component.html        | 12 +++++--
 .../recherche/recherche.component.scss        | 32 +++++++++++--------
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index b5b6f48af..d5174958b 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -1,3 +1,11 @@
+<div class="checkbox">
+  <label>
+    <input type="checkbox" />
+    <span class="customCheck"></span>
+  </label>
+  <div class="test">text ici</div>
+</div>
+
 <div class="header">
   <span class="title">Acteurs de la médiation</span>
 </div>
@@ -40,8 +48,8 @@
               <label>
                 <input type="checkbox" />
                 <span class="customCheck"></span>
-                {{ categ }}
               </label>
+              <div class="label">{{ categ }}</div>
             </div>
             <span class="nbResult">34</span>
           </div>
@@ -59,8 +67,8 @@
     <label>
       <input type="checkbox" />
       <span class="customCheck"></span>
-      Pass numérique
     </label>
+    <div class="label">Pass numérique</div>
   </div>
   <a href="">Ajouter une structure</a>
 </div>
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index 81da77faf..fa45288d7 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -189,19 +189,12 @@
 }
 .checkbox {
   position: relative;
-  padding-left: 27px;
-  label {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 15px;
-    line-height: 21px;
-  }
+  display: grid;
+  align-items: center;
+  grid-template-columns: min-content auto;
   input {
-    position: absolute;
     opacity: 0;
-    height: 0;
-    width: 0;
+    display: none;
     &:checked ~ .customCheck {
       background-color: $orange-light;
       border-color: transparent;
@@ -210,13 +203,24 @@
       display: block;
     }
   }
+  .label {
+    padding-left: 15px;
+
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 15px;
+    line-height: 21px;
+  }
   .customCheck {
-    position: absolute;
-    height: 18px;
+    display: inline-grid;
     width: 18px;
+    height: 18px;
     background-color: $white;
     border: 1px solid $grey;
     cursor: pointer;
+    position: relative;
+
     top: 0;
     left: 0;
     &:hover {
@@ -228,7 +232,7 @@
       display: none;
     }
     &:after {
-      left: 6.5px;
+      left: 7px;
       top: 3px;
       width: 4px;
       height: 8px;
-- 
GitLab


From 046684b4a75808fee6ee1fa882dd701d6ed0c467 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 13 Oct 2020 10:46:03 +0200
Subject: [PATCH 12/50] fix(checkbox) : add btn + form + clear

---
 .../recherche/recherche.component.html        | 31 +++++-----
 .../recherche/recherche.component.scss        | 20 ++++---
 .../recherche/recherche.component.ts          | 57 +++++++++++++------
 src/app/structure/structure.module.ts         |  3 +-
 4 files changed, 71 insertions(+), 40 deletions(-)

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index d5174958b..7c5564162 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -1,11 +1,3 @@
-<div class="checkbox">
-  <label>
-    <input type="checkbox" />
-    <span class="customCheck"></span>
-  </label>
-  <div class="test">text ici</div>
-</div>
-
 <div class="header">
   <span class="title">Acteurs de la médiation</span>
 </div>
@@ -32,7 +24,15 @@
       <div class="arrow"></div>
     </button>
   </div>
-  <div *ngIf="modalOpened" class="modal" fxLayout="column" fxLayoutAlign="space-between">
+  <form
+    [formGroup]="form"
+    (ngSubmit)="applyFilter()"
+    novalidate
+    *ngIf="modalOpened"
+    class="modal"
+    fxLayout="column"
+    fxLayoutAlign="space-between"
+  >
     <div class="contentModal" fxLayout="row wrap">
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
       <div class="blockFiltre" *ngFor="let s of services">
@@ -46,7 +46,12 @@
           >
             <div class="checkbox">
               <label>
-                <input type="checkbox" />
+                <input
+                  type="checkbox"
+                  [checked]="isChecked(categ)"
+                  [value]="categ"
+                  (change)="onCheckboxChange($event, true)"
+                />
                 <span class="customCheck"></span>
               </label>
               <div class="label">{{ categ }}</div>
@@ -57,10 +62,10 @@
       </div>
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
-      <a href="">Effacer</a>
-      <button type="button" (click)="applyFilter()">Appliquer</button>
+      <a (click)="onCheckboxChange($event, false)">Effacer</a>
+      <button type="submit" value="Submit">Appliquer</button>
     </div>
-  </div>
+  </form>
 </div>
 <div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index fa45288d7..9ea829dac 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -128,15 +128,17 @@
   z-index: 1;
   position: absolute;
   margin-top: 80px;
+  padding: 20px 16px 10px 16px;
   .contentModal {
     writing-mode: vertical-lr;
-    padding: 20px 5px 10px 5px;
     overflow-y: hidden;
     max-width: 1100px;
+    border-bottom: 1px solid grey;
+    margin-bottom: 10px;
     .blockFiltre {
       writing-mode: horizontal-tb;
       max-width: 320px;
-      padding: 0 10px 10px 10px;
+      padding: 0 30px 10px 10px;
     }
     .ligneFiltre {
       margin: 5px 0 5px 0;
@@ -149,7 +151,7 @@
       line-height: 17px;
       display: flex;
       align-items: center;
-      margin: 0;
+      margin-top: 0;
     }
     .nbResult {
       font-family: Trebuchet MS;
@@ -168,7 +170,6 @@
   }
   .footer {
     height: 32px;
-    padding-right: 24px;
     button {
       height: 100%;
       border: none;
@@ -203,14 +204,17 @@
       display: block;
     }
   }
+  label {
+    display: inline-grid;
+  }
   .label {
-    padding-left: 15px;
-
+    padding-left: 8px;
     font-family: Trebuchet MS;
     font-style: normal;
     font-weight: normal;
-    font-size: 15px;
-    line-height: 21px;
+    font-size: 14px;
+    line-height: 17px;
+    padding: 0 16px 0 16px;
   }
   .customCheck {
     display: inline-grid;
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
index 15fb2c9cf..5aaac22ef 100644
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ b/src/app/structure/components/recherche/recherche.component.ts
@@ -1,5 +1,6 @@
 import { Component, OnInit } from '@angular/core';
 import { Service } from '../../models/recherche.model';
+import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';
 
 @Component({
   selector: 'app-recherche',
@@ -7,7 +8,12 @@ import { Service } from '../../models/recherche.model';
   styleUrls: ['./recherche.component.scss'],
 })
 export class RechercheComponent implements OnInit {
-  constructor() {}
+  constructor(private fb: FormBuilder) {
+    this.form = this.fb.group({
+      checkArray: this.fb.array([]),
+    });
+  }
+  form: FormGroup;
   modalOpened: string;
   modalType: string[] = ['services', 'accueil', 'plusFiltres'];
   btnServicesChecked: boolean;
@@ -17,19 +23,19 @@ export class RechercheComponent implements OnInit {
   services: Service[];
 
   ngOnInit(): void {
-    this.modalOpened = 'services';
+    this.modalOpened = null;
     this.btnServicesChecked = false;
     this.services = [];
+    //Block en attendant
     this.mockService('Accompagnement aux démarches en ligne', 'CAF', 7);
-    this.mockService('Insertion sociale et professionnelle', 'Diffuser son CV en ligne', 5);
+    this.mockService('Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
     this.mockService('Accès aux droits', 'Déclarer ses revenus en ligne et découvertes des services proposés', 8);
     this.mockService('Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
     this.mockService('Compétences de base', 'Faire un diagnostic des compétences', 8);
     this.mockService('Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
-    console.log(this.services);
-    this.calcSizeCol(this.services);
+    //Fin block en attendant
   }
-
+  //Fonction en attendant
   mockService(titre: string, categ: string, nbCateg: number) {
     var service1 = new Service();
     service1.titre = titre;
@@ -39,6 +45,7 @@ export class RechercheComponent implements OnInit {
     }
     this.services.push(service1);
   }
+  //Fin fonction en attendant
   openModal(option: string) {
     this.modalOpened = null;
     switch (option) {
@@ -64,22 +71,36 @@ export class RechercheComponent implements OnInit {
   }
   applyFilter() {
     this.openModal(this.modalOpened);
+    console.log(this.form.value);
   }
 
-  calcSizeCol(services: Service[]) {
-    for (var i = 0; i < services.length; i++) {
-      if (services[i + 1]) {
-        var nb1, nb2: number;
-        nb1 = services[i].categories.length;
-        nb2 = services[i + 1].categories.length;
-        if (nb1 + nb2 <= 13) {
-          services[i].size = parseFloat((nb1 / 13).toPrecision(2)) * 100;
-          services[i + 1].size = parseFloat((1 - services[i].size / 100).toPrecision(2)) * 100;
+  onCheckboxChange(e, reset: boolean) {
+    const checkArray: FormArray = this.form.get('checkArray') as FormArray;
+    if (reset) {
+      if (e.target.checked) {
+        checkArray.push(new FormControl(e.target.value));
+      } else {
+        let i: number = 0;
+        checkArray.controls.forEach((item: FormControl) => {
+          if (item.value == e.target.value) {
+            checkArray.removeAt(i);
+            return;
+          }
           i++;
-        } else {
-          services[i].size = 100;
-        }
+        });
       }
+    } else {
+      checkArray.clear();
     }
   }
+  isChecked(module: string) {
+    const checkArray: FormArray = this.form.get('checkArray') as FormArray;
+    var bool: boolean = false;
+    checkArray.controls.forEach((item: FormControl) => {
+      if (item.value == module) {
+        bool = true;
+      }
+    });
+    return bool;
+  }
 }
diff --git a/src/app/structure/structure.module.ts b/src/app/structure/structure.module.ts
index 335604aef..fdc77203d 100644
--- a/src/app/structure/structure.module.ts
+++ b/src/app/structure/structure.module.ts
@@ -5,10 +5,11 @@ import { CardComponent } from './components/card/card.component';
 import { RechercheComponent } from './components/recherche/recherche.component';
 import { HttpClientModule } from '@angular/common/http';
 import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 @NgModule({
   declarations: [StructureComponent, CardComponent, RechercheComponent],
-  imports: [CommonModule, HttpClientModule, FlexLayoutModule],
+  imports: [CommonModule, HttpClientModule, FlexLayoutModule, ReactiveFormsModule],
   exports: [StructureComponent],
 })
 export class StructureModule {}
-- 
GitLab


From 8120b0a3ba74c06e8d9008b56c85fbefe05ff2af Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 13 Oct 2020 17:08:25 +0200
Subject: [PATCH 13/50] fix(checkbox) : fix checkbox + clean/maj code

Etat stable des checkbox multiples dans les modals
---
 .../recherche/recherche.component.html        |  44 +++--
 .../recherche/recherche.component.scss        |   9 +-
 .../recherche/recherche.component.ts          | 174 +++++++++++-------
 src/app/structure/models/recherche.model.ts   |   2 +-
 4 files changed, 137 insertions(+), 92 deletions(-)

diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
index 7c5564162..00eecd6da 100644
--- a/src/app/structure/components/recherche/recherche.component.html
+++ b/src/app/structure/components/recherche/recherche.component.html
@@ -11,46 +11,50 @@
   </div>
 
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
-    <button type="button" [className]="btnServicesChecked ? 'selected' : ''" (click)="openModal(this.modalType[0])">
+    <button
+      type="button"
+      [className]="modalOpened == modalType[0] ? 'selected' : ''"
+      (click)="openModal(this.modalType[0])"
+    >
       <span class="btnText">Services</span>
       <div class="arrow"></div>
     </button>
-    <button type="button" [className]="btnHomeChecked ? 'selected' : ''" (click)="openModal(this.modalType[1])">
+    <button
+      type="button"
+      [className]="modalOpened == modalType[1] ? 'selected' : ''"
+      (click)="openModal(this.modalType[1])"
+    >
       <span class="btnText">Accueil</span>
       <div class="arrow"></div>
     </button>
-    <button type="button" [className]="btnMoreFilterchecked ? 'selected' : ''" (click)="openModal(this.modalType[2])">
+    <button
+      type="button"
+      [className]="modalOpened == modalType[2] ? 'selected' : ''"
+      (click)="openModal(this.modalType[2])"
+    >
       <span class="btnText">Plus de filtres</span>
       <div class="arrow"></div>
     </button>
   </div>
-  <form
-    [formGroup]="form"
-    (ngSubmit)="applyFilter()"
-    novalidate
-    *ngIf="modalOpened"
-    class="modal"
-    fxLayout="column"
-    fxLayoutAlign="space-between"
-  >
+  <div *ngIf="modalOpened" fxLayout="column" fxLayoutAlign="space-between" [ngClass]="['modal', 'modal' + modalOpened]">
     <div class="contentModal" fxLayout="row wrap">
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
-      <div class="blockFiltre" *ngFor="let s of services">
+      <div class="blockFiltre" *ngFor="let m of modules">
         <div class="blockLigne">
-          <h4>{{ s.titre }}</h4>
+          <h4>{{ m.titre }}</h4>
           <div
             fxLayout="row"
             class="ligneFiltre"
             fxLayoutAlign="space-between center"
-            *ngFor="let categ of s.categories"
+            *ngFor="let categ of m.categories"
           >
             <div class="checkbox">
               <label>
                 <input
                   type="checkbox"
-                  [checked]="isChecked(categ)"
+                  [checked]="this.checkedTab.indexOf(categ) > -1"
                   [value]="categ"
-                  (change)="onCheckboxChange($event, true)"
+                  (change)="onCheckboxChange($event, false)"
                 />
                 <span class="customCheck"></span>
               </label>
@@ -62,10 +66,10 @@
       </div>
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
-      <a (click)="onCheckboxChange($event, false)">Effacer</a>
-      <button type="submit" value="Submit">Appliquer</button>
+      <a (click)="onCheckboxChange($event, true)">Effacer</a>
+      <button type="button" (click)="applyFilter(modalOpened)">Appliquer</button>
     </div>
-  </form>
+  </div>
 </div>
 <div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
index 9ea829dac..e1ac58b8d 100644
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ b/src/app/structure/components/recherche/recherche.component.scss
@@ -118,8 +118,14 @@
     text-decoration-line: underline;
   }
 }
+.modalaccueil {
+  margin-left: 100px;
+}
+.modalplusFiltres {
+  margin-left: 196px;
+}
 .modal {
-  height: 654px;
+  max-height: 654px;
   max-width: 1100px;
   background: $white;
   border: 1px solid $purple;
@@ -193,6 +199,7 @@
   display: grid;
   align-items: center;
   grid-template-columns: min-content auto;
+  min-height: 25px;
   input {
     opacity: 0;
     display: none;
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
index 5aaac22ef..34881d906 100644
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ b/src/app/structure/components/recherche/recherche.component.ts
@@ -1,6 +1,5 @@
 import { Component, OnInit } from '@angular/core';
-import { Service } from '../../models/recherche.model';
-import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';
+import { Module } from '../../models/recherche.model';
 
 @Component({
   selector: 'app-recherche',
@@ -8,99 +7,134 @@ import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';
   styleUrls: ['./recherche.component.scss'],
 })
 export class RechercheComponent implements OnInit {
-  constructor(private fb: FormBuilder) {
-    this.form = this.fb.group({
-      checkArray: this.fb.array([]),
-    });
-  }
-  form: FormGroup;
-  modalOpened: string;
+  constructor() {}
+  //Variables btn filtres
   modalType: string[] = ['services', 'accueil', 'plusFiltres'];
-  btnServicesChecked: boolean;
-  btnHomeChecked: boolean;
-  btnMoreFilterchecked: boolean;
-  test = '50%';
-  services: Service[];
+
+  //Variable gestion liste modal
+  servicesCategories: Module[];
+  modaliteCategories: Module[];
+  modules: Module[];
+  filtresCategories: Module[];
+  modalOpened: string;
+
+  //Variable gestion Checkbox
+  checkedTab: string[];
+  filterCheck: string[];
 
   ngOnInit(): void {
+    //Sert à afficher la modal et indiquer le type de filtre choisit
     this.modalOpened = null;
-    this.btnServicesChecked = false;
-    this.services = [];
-    //Block en attendant
-    this.mockService('Accompagnement aux démarches en ligne', 'CAF', 7);
-    this.mockService('Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
-    this.mockService('Accès aux droits', 'Déclarer ses revenus en ligne et découvertes des services proposés', 8);
-    this.mockService('Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
-    this.mockService('Compétences de base', 'Faire un diagnostic des compétences', 8);
-    this.mockService('Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
-    //Fin block en attendant
-  }
-  //Fonction en attendant
-  mockService(titre: string, categ: string, nbCateg: number) {
-    var service1 = new Service();
-    service1.titre = titre;
-    service1.categories = [];
-    for (var i = 0; i < nbCateg; i++) {
-      service1.categories.push(categ + '_' + i);
-    }
-    this.services.push(service1);
+
+    //Sert à stocker les différentes catégories
+    this.servicesCategories = [];
+    this.modaliteCategories = [];
+    this.modules = [];
+    this.filtresCategories = [];
+
+    //Sert à gérer la checkbox multiple
+    this.checkedTab = new Array();
+    this.filterCheck = new Array();
   }
-  //Fin fonction en attendant
+
+  //Ouvrir la modal et afficher la liste en fonction du btn de filtre appuyé
   openModal(option: string) {
-    this.modalOpened = null;
+    this.modules = [];
     switch (option) {
       case this.modalType[0]:
-        this.btnServicesChecked = !this.btnServicesChecked;
-        this.btnHomeChecked = false;
-        this.btnMoreFilterchecked = false;
-        if (this.btnServicesChecked) this.modalOpened = this.modalType[0];
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[0]) {
+          this.modalOpened = this.modalType[0];
+          this.fakeDataServices();
+        } else {
+          this.modalOpened = null;
+        }
         break;
       case this.modalType[1]:
-        this.btnHomeChecked = !this.btnHomeChecked;
-        this.btnMoreFilterchecked = false;
-        this.btnServicesChecked = false;
-        if (this.btnHomeChecked) this.modalOpened = this.modalType[1];
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[1]) {
+          this.modalOpened = this.modalType[1];
+          this.fakeDataModalite();
+        } else {
+          this.modalOpened = null;
+        }
         break;
       case this.modalType[2]:
-        this.btnMoreFilterchecked = !this.btnMoreFilterchecked;
-        this.btnServicesChecked = false;
-        this.btnHomeChecked = false;
-        if (this.btnMoreFilterchecked) this.modalOpened = this.modalType[2];
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[2]) {
+          this.modalOpened = this.modalType[2];
+          this.fakeDataFiltres();
+        } else {
+          this.modalOpened = null;
+        }
         break;
     }
+    //Initialisation de la liste temporaire
+    this.checkedTab = this.filterCheck.slice();
   }
+
+  //Envoie d'un tableau contenant tous les filtres
   applyFilter() {
+    this.filterCheck = this.checkedTab.slice();
     this.openModal(this.modalOpened);
-    console.log(this.form.value);
+    console.log(this.filterCheck);
   }
 
+  //Gestion de l'evenement checkbox(Cocher/Décocher)
   onCheckboxChange(e, reset: boolean) {
-    const checkArray: FormArray = this.form.get('checkArray') as FormArray;
-    if (reset) {
+    //Condition btn effacer filtre d'une liste
+    if (!reset) {
       if (e.target.checked) {
-        checkArray.push(new FormControl(e.target.value));
+        this.checkedTab.push(e.target.value);
       } else {
-        let i: number = 0;
-        checkArray.controls.forEach((item: FormControl) => {
-          if (item.value == e.target.value) {
-            checkArray.removeAt(i);
-            return;
-          }
-          i++;
-        });
+        //Vérifie si la case décochée est présente dans la liste temporaire et la supprime
+        if (this.checkedTab.indexOf(e.target.value) > -1) {
+          this.checkedTab.splice(this.checkedTab.indexOf(e.target.value), 1);
+        }
       }
     } else {
-      checkArray.clear();
+      //Efface uniquement les éléments de la liste en cours
+      this.modules.forEach((m) => {
+        m.categories.forEach((categ) => {
+          if (this.checkedTab.indexOf(categ) > -1) this.checkedTab.splice(this.checkedTab.indexOf(categ), 1);
+        });
+      });
     }
   }
-  isChecked(module: string) {
-    const checkArray: FormArray = this.form.get('checkArray') as FormArray;
-    var bool: boolean = false;
-    checkArray.controls.forEach((item: FormControl) => {
-      if (item.value == module) {
-        bool = true;
-      }
-    });
-    return bool;
+
+  /**
+   * En attendant les apis
+   */
+  mockService(module: Module[], titre: string, categ: string, nbCateg: number) {
+    var m = new Module();
+    m.titre = titre;
+    m.categories = [];
+    for (var i = 0; i < nbCateg; i++) {
+      m.categories.push(categ + i);
+    }
+    module.push(m);
+  }
+  fakeDataServices() {
+    this.mockService(this.modules, 'Accompagnement aux démarches en ligne', 'CAF', 7);
+    this.mockService(this.modules, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
+    this.mockService(
+      this.modules,
+      'Accès aux droits',
+      'Déclarer ses revenus en ligne et découvertes des services proposés',
+      8
+    );
+    this.mockService(this.modules, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
+    this.mockService(this.modules, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
+    this.mockService(this.modules, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
+  }
+  fakeDataModalite() {
+    this.mockService(this.modules, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
+  }
+  fakeDataFiltres() {
+    this.mockService(this.modules, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
+    this.mockService(this.modules, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
+    this.mockService(this.modules, 'Publics', 'Langues étrangères autres qu’anglais', 12);
+    this.mockService(this.modules, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
+    this.mockService(this.modules, 'Type de structure', 'Espace de co-working', 6);
   }
 }
diff --git a/src/app/structure/models/recherche.model.ts b/src/app/structure/models/recherche.model.ts
index 5904abd46..a498b7318 100644
--- a/src/app/structure/models/recherche.model.ts
+++ b/src/app/structure/models/recherche.model.ts
@@ -1,4 +1,4 @@
-export class Service {
+export class Module {
   titre: string;
   categories: string[];
   size: number;
-- 
GitLab


From 62be28151167b6e6b9bcbe44fab751852a992da0 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 17:06:47 +0200
Subject: [PATCH 14/50] fix(search) : Fix merge problem

---
 .../recherche/recherche.component.html        |  79 +++++-
 .../recherche/recherche.component.scss        | 257 ++++++++++++++++++
 .../recherche/recherche.component.spec.ts     |   5 +-
 .../recherche/recherche.component.ts          | 130 ++++++++-
 .../structure-list/models/category.model.ts   |   5 +
 .../structure-list.component.html             |   7 +-
 .../structure-list.component.scss             |  11 +
 .../structure-list.component.ts               |   1 +
 8 files changed, 488 insertions(+), 7 deletions(-)
 create mode 100644 src/app/structure-list/models/category.model.ts
 create mode 100644 src/app/structure-list/structure-list.component.scss

diff --git a/src/app/structure-list/components/recherche/recherche.component.html b/src/app/structure-list/components/recherche/recherche.component.html
index 63c7b1a72..211a03bea 100644
--- a/src/app/structure-list/components/recherche/recherche.component.html
+++ b/src/app/structure-list/components/recherche/recherche.component.html
@@ -1 +1,78 @@
-<p>recherche works!</p>
+<div class="header">
+  <span class="title">Acteurs de la médiation</span>
+</div>
+<div class="content" fxLayout="column">
+  <div class="searchSection" fxLayout="row" fxLayoutGap="1.5vw">
+    <div class="icon">
+      <div class="ico-pin-search grey"></div>
+    </div>
+    <input type="text" placeholder="Rechercher une adresse, une association..." />
+    <button type="button">Rechercher</button>
+  </div>
+
+  <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
+    <button
+      type="button"
+      [className]="modalOpened == modalType[0] ? 'selected' : ''"
+      (click)="openModal(this.modalType[0])"
+    >
+      <span class="btnText">Services</span>
+      <div class="arrow"></div>
+    </button>
+    <button
+      type="button"
+      [className]="modalOpened == modalType[1] ? 'selected' : ''"
+      (click)="openModal(this.modalType[1])"
+    >
+      <span class="btnText">Accueil</span>
+      <div class="arrow"></div>
+    </button>
+    <button
+      type="button"
+      [className]="modalOpened == modalType[2] ? 'selected' : ''"
+      (click)="openModal(this.modalType[2])"
+    >
+      <span class="btnText">Plus de filtres</span>
+      <div class="arrow"></div>
+    </button>
+  </div>
+  <div *ngIf="modalOpened" fxLayout="column" fxLayoutAlign="space-between" [ngClass]="['modal', 'modal' + modalOpened]">
+    <div class="contentModal" fxLayout="row wrap">
+      <!--<div class="blockFiltre" *ngFor="let s of services">-->
+      <div class="blockFiltre" *ngFor="let c of categories">
+        <div class="blockLigne">
+          <h4>{{ c.titre }}</h4>
+          <div fxLayout="row" class="ligneFiltre" fxLayoutAlign="space-between center" *ngFor="let module of c.modules">
+            <div class="checkbox">
+              <label>
+                <input
+                  type="checkbox"
+                  [checked]="this.checkedTab.indexOf(module) > -1"
+                  [value]="module"
+                  (change)="onCheckboxChange($event, false)"
+                />
+                <span class="customCheck"></span>
+              </label>
+              <div class="label">{{ module }}</div>
+            </div>
+            <span class="nbResult">34</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
+      <a (click)="onCheckboxChange($event, true)">Effacer</a>
+      <button type="button" (click)="applyFilter(modalOpened)">Appliquer</button>
+    </div>
+  </div>
+</div>
+<div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
+  <div class="checkbox">
+    <label>
+      <input type="checkbox" />
+      <span class="customCheck"></span>
+    </label>
+    <div class="label">Pass numérique</div>
+  </div>
+  <a href="">Ajouter une structure</a>
+</div>
diff --git a/src/app/structure-list/components/recherche/recherche.component.scss b/src/app/structure-list/components/recherche/recherche.component.scss
index e69de29bb..e1ac58b8d 100644
--- a/src/app/structure-list/components/recherche/recherche.component.scss
+++ b/src/app/structure-list/components/recherche/recherche.component.scss
@@ -0,0 +1,257 @@
+@import '../../../../assets/scss/icons';
+@import '../../../../assets/scss/color';
+
+.header {
+  .title {
+    font-family: Times New Roman;
+    font-style: normal;
+    font-weight: bold;
+    font-size: 20px;
+    line-height: 103%;
+    padding: 16px 0 16px 0;
+
+    display: flex;
+    align-items: center;
+    text-transform: uppercase;
+  }
+}
+.content {
+  margin: 10px 0 0px 0;
+  .icon {
+    border: 1px solid $grey;
+    padding: 4px 6px 8px 6px;
+    border-radius: 4px;
+    cursor: pointer;
+  }
+  input {
+    width: 100%;
+    background-color: $grey-4;
+    border: none;
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 12px;
+    line-height: 17px;
+    display: flex;
+    align-items: center;
+    padding-left: 10px;
+    text-overflow: ellipsis;
+    color: $grey-1;
+    outline: none;
+  }
+  .searchSection {
+    button {
+      border: none;
+      cursor: pointer;
+      background-color: $purple;
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 100%;
+      align-items: center;
+      text-align: center;
+      color: $white;
+      padding: 3px 16px 3px 16px;
+      outline: none;
+    }
+  }
+  .btnSection {
+    padding: 16px 0 16px 0;
+    button {
+      outline: none;
+
+      border: 1px solid $grey;
+      border-radius: 33px;
+      background-color: $white;
+      padding: 2px 6px 2px 13px;
+      align-items: center;
+      display: flex;
+      cursor: pointer;
+      .btnText {
+        justify-content: center;
+        font-family: Trebuchet MS;
+        font-style: normal;
+        font-weight: normal;
+        font-size: 13px;
+        line-height: 19px;
+        display: flex;
+        align-items: center;
+      }
+    }
+    .selected {
+      border: 1px solid $orange-light;
+      color: $orange-light;
+      .arrow {
+        background-color: transparent;
+        border-bottom: 1px solid $orange-light;
+        border-right: 1px solid $orange-light;
+        transform: translateY(25%) rotate(-135deg);
+        margin: 0 5px 0 10px;
+        height: 7px;
+        width: 7px;
+      }
+    }
+    .arrow {
+      background-color: transparent;
+      border-bottom: 1px solid $grey;
+      border-right: 1px solid $grey;
+      transform: translateY(-25%) rotate(45deg);
+      margin: 0 5px 0 10px;
+      height: 7px;
+      width: 7px;
+    }
+  }
+}
+.footer {
+  margin: 0px 0 16px 0;
+  a {
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: bold;
+    font-size: 13px;
+    line-height: 18px;
+    /* or 120% */
+
+    display: flex;
+    align-items: center;
+    text-decoration-line: underline;
+  }
+}
+.modalaccueil {
+  margin-left: 100px;
+}
+.modalplusFiltres {
+  margin-left: 196px;
+}
+.modal {
+  max-height: 654px;
+  max-width: 1100px;
+  background: $white;
+  border: 1px solid $purple;
+  box-sizing: border-box;
+  border-radius: 8px;
+  z-index: 1;
+  position: absolute;
+  margin-top: 80px;
+  padding: 20px 16px 10px 16px;
+  .contentModal {
+    writing-mode: vertical-lr;
+    overflow-y: hidden;
+    max-width: 1100px;
+    border-bottom: 1px solid grey;
+    margin-bottom: 10px;
+    .blockFiltre {
+      writing-mode: horizontal-tb;
+      max-width: 320px;
+      padding: 0 30px 10px 10px;
+    }
+    .ligneFiltre {
+      margin: 5px 0 5px 0;
+    }
+    h4 {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 17px;
+      display: flex;
+      align-items: center;
+      margin-top: 0;
+    }
+    .nbResult {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: normal;
+      font-size: 13px;
+      line-height: 15px;
+    }
+    label {
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: normal;
+      font-size: 14px;
+      line-height: 16px;
+    }
+  }
+  .footer {
+    height: 32px;
+    button {
+      height: 100%;
+      border: none;
+      cursor: pointer;
+      background-color: $purple;
+      font-family: Trebuchet MS;
+      font-style: normal;
+      font-weight: bold;
+      font-size: 13px;
+      line-height: 100%;
+      align-items: center;
+      text-align: center;
+      color: $white;
+      padding: 3px 16px 3px 16px;
+      outline: none;
+    }
+  }
+}
+.checkbox {
+  position: relative;
+  display: grid;
+  align-items: center;
+  grid-template-columns: min-content auto;
+  min-height: 25px;
+  input {
+    opacity: 0;
+    display: none;
+    &:checked ~ .customCheck {
+      background-color: $orange-light;
+      border-color: transparent;
+    }
+    &:checked ~ .customCheck:after {
+      display: block;
+    }
+  }
+  label {
+    display: inline-grid;
+  }
+  .label {
+    padding-left: 8px;
+    font-family: Trebuchet MS;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 14px;
+    line-height: 17px;
+    padding: 0 16px 0 16px;
+  }
+  .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-4;
+    }
+    &: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/recherche/recherche.component.spec.ts b/src/app/structure-list/components/recherche/recherche.component.spec.ts
index e38e4d4e8..211150ab6 100644
--- a/src/app/structure-list/components/recherche/recherche.component.spec.ts
+++ b/src/app/structure-list/components/recherche/recherche.component.spec.ts
@@ -8,9 +8,8 @@ describe('RechercheComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ RechercheComponent ]
-    })
-    .compileComponents();
+      declarations: [RechercheComponent],
+    }).compileComponents();
   });
 
   beforeEach(() => {
diff --git a/src/app/structure-list/components/recherche/recherche.component.ts b/src/app/structure-list/components/recherche/recherche.component.ts
index 7754a323b..94e354989 100644
--- a/src/app/structure-list/components/recherche/recherche.component.ts
+++ b/src/app/structure-list/components/recherche/recherche.component.ts
@@ -1,4 +1,5 @@
 import { Component, OnInit } from '@angular/core';
+import { Category } from '../../models/category.model';
 
 @Component({
   selector: 'app-recherche',
@@ -7,6 +8,133 @@ import { Component, OnInit } from '@angular/core';
 })
 export class RechercheComponent implements OnInit {
   constructor() {}
+  //Variables btn filtres
+  modalType: string[] = ['services', 'accueil', 'plusFiltres'];
 
-  ngOnInit(): void {}
+  //Variable gestion liste modal
+  servicesCategories: Category[];
+  modaliteCategories: Category[];
+  categories: Category[];
+  filtresCategories: Category[];
+  modalOpened: string;
+
+  //Variable gestion Checkbox
+  checkedTab: string[];
+  filterCheck: string[];
+
+  ngOnInit(): void {
+    //Sert à afficher la modal et indiquer le type de filtre choisit
+    this.modalOpened = null;
+
+    //Sert à stocker les différentes catégories
+    this.servicesCategories = [];
+    this.modaliteCategories = [];
+    this.categories = [];
+    this.filtresCategories = [];
+
+    //Sert à gérer la checkbox multiple
+    this.checkedTab = new Array();
+    this.filterCheck = new Array();
+  }
+
+  //Ouvrir la modal et afficher la liste en fonction du btn de filtre appuyé
+  openModal(option: string) {
+    this.categories = [];
+    switch (option) {
+      case this.modalType[0]:
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[0]) {
+          this.modalOpened = this.modalType[0];
+          this.fakeDataServices();
+        } else {
+          this.modalOpened = null;
+        }
+        break;
+      case this.modalType[1]:
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[1]) {
+          this.modalOpened = this.modalType[1];
+          this.fakeDataModalite();
+        } else {
+          this.modalOpened = null;
+        }
+        break;
+      case this.modalType[2]:
+        //Vérifie si le btn n'est pas actif
+        if (this.modalOpened != this.modalType[2]) {
+          this.modalOpened = this.modalType[2];
+          this.fakeDataFiltres();
+        } else {
+          this.modalOpened = null;
+        }
+        break;
+    }
+    //Initialisation de la liste temporaire
+    this.checkedTab = this.filterCheck.slice();
+  }
+
+  //Envoie d'un tableau contenant tous les filtres
+  applyFilter() {
+    this.filterCheck = this.checkedTab.slice();
+    this.openModal(this.modalOpened);
+    console.log(this.filterCheck);
+  }
+
+  //Gestion de l'evenement checkbox(Cocher/Décocher)
+  onCheckboxChange(e, reset: boolean) {
+    //Condition btn effacer filtre d'une liste
+    if (!reset) {
+      if (e.target.checked) {
+        this.checkedTab.push(e.target.value);
+      } else {
+        //Vérifie si la case décochée est présente dans la liste temporaire et la supprime
+        if (this.checkedTab.indexOf(e.target.value) > -1) {
+          this.checkedTab.splice(this.checkedTab.indexOf(e.target.value), 1);
+        }
+      }
+    } else {
+      //Efface uniquement les éléments de la liste en cours
+      this.categories.forEach((m) => {
+        m.modules.forEach((categ) => {
+          if (this.checkedTab.indexOf(categ) > -1) this.checkedTab.splice(this.checkedTab.indexOf(categ), 1);
+        });
+      });
+    }
+  }
+
+  /**
+   * En attendant les apis
+   */
+  mockService(module: Category[], titre: string, categ: string, nbCateg: number) {
+    var m = new Category();
+    m.titre = titre;
+    m.modules = [];
+    for (var i = 0; i < nbCateg; i++) {
+      m.modules.push(categ + i);
+    }
+    module.push(m);
+  }
+  fakeDataServices() {
+    this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
+    this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
+    this.mockService(
+      this.categories,
+      'Accès aux droits',
+      'Déclarer ses revenus en ligne et découvertes des services proposés',
+      8
+    );
+    this.mockService(this.categories, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
+    this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
+    this.mockService(this.categories, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
+  }
+  fakeDataModalite() {
+    this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
+  }
+  fakeDataFiltres() {
+    this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
+    this.mockService(this.categories, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
+    this.mockService(this.categories, 'Publics', 'Langues étrangères autres qu’anglais', 12);
+    this.mockService(this.categories, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
+    this.mockService(this.categories, 'Type de structure', 'Espace de co-working', 6);
+  }
 }
diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts
new file mode 100644
index 000000000..5610acca0
--- /dev/null
+++ b/src/app/structure-list/models/category.model.ts
@@ -0,0 +1,5 @@
+export class Category {
+  titre: string;
+  modules: string[];
+  size: number;
+}
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index a6dbe19b7..86c8f6308 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,2 +1,5 @@
-<app-recherche></app-recherche>
-<app-card></app-card>
+<div class="container">
+  <app-recherche></app-recherche>
+  <div class="divider"></div>
+  <app-card></app-card>
+</div>
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
new file mode 100644
index 000000000..2d506b58d
--- /dev/null
+++ b/src/app/structure-list/structure-list.component.scss
@@ -0,0 +1,11 @@
+@import '../../assets/scss/color';
+
+.divider {
+  width: 100%;
+  height: 1px;
+  background-color: $grey-4;
+}
+//En attendant de l'intégrer avec la map
+.container {
+  width: 320px;
+}
diff --git a/src/app/structure-list/structure-list.component.ts b/src/app/structure-list/structure-list.component.ts
index 276b325e4..6ea9c6fde 100644
--- a/src/app/structure-list/structure-list.component.ts
+++ b/src/app/structure-list/structure-list.component.ts
@@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core';
 @Component({
   selector: 'app-structure-list',
   templateUrl: './structure-list.component.html',
+  styleUrls: ['./structure-list.component.scss'],
 })
 export class StructureListComponent implements OnInit {
   constructor() {}
-- 
GitLab


From 3917bb881cf333801fd8365f00cd75c8595d7d5d Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 17:10:37 +0200
Subject: [PATCH 15/50] fix(search) : rename component

---
 .../search.component.html}                             |  2 +-
 .../search.component.scss}                             |  0
 .../search.component.spec.ts}                          | 10 +++++-----
 .../search.component.ts}                               | 10 +++++-----
 src/app/structure-list/models/category.model.ts        |  2 +-
 src/app/structure-list/structure-list.component.html   |  2 +-
 src/app/structure-list/structure-list.module.ts        |  4 ++--
 7 files changed, 15 insertions(+), 15 deletions(-)
 rename src/app/structure-list/components/{recherche/recherche.component.html => search/search.component.html} (98%)
 rename src/app/structure-list/components/{recherche/recherche.component.scss => search/search.component.scss} (100%)
 rename src/app/structure-list/components/{recherche/recherche.component.spec.ts => search/search.component.spec.ts} (60%)
 rename src/app/structure-list/components/{recherche/recherche.component.ts => search/search.component.ts} (96%)

diff --git a/src/app/structure-list/components/recherche/recherche.component.html b/src/app/structure-list/components/search/search.component.html
similarity index 98%
rename from src/app/structure-list/components/recherche/recherche.component.html
rename to src/app/structure-list/components/search/search.component.html
index 211a03bea..3b769e950 100644
--- a/src/app/structure-list/components/recherche/recherche.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -41,7 +41,7 @@
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
       <div class="blockFiltre" *ngFor="let c of categories">
         <div class="blockLigne">
-          <h4>{{ c.titre }}</h4>
+          <h4>{{ c.title }}</h4>
           <div fxLayout="row" class="ligneFiltre" fxLayoutAlign="space-between center" *ngFor="let module of c.modules">
             <div class="checkbox">
               <label>
diff --git a/src/app/structure-list/components/recherche/recherche.component.scss b/src/app/structure-list/components/search/search.component.scss
similarity index 100%
rename from src/app/structure-list/components/recherche/recherche.component.scss
rename to src/app/structure-list/components/search/search.component.scss
diff --git a/src/app/structure-list/components/recherche/recherche.component.spec.ts b/src/app/structure-list/components/search/search.component.spec.ts
similarity index 60%
rename from src/app/structure-list/components/recherche/recherche.component.spec.ts
rename to src/app/structure-list/components/search/search.component.spec.ts
index 211150ab6..56e05f1d6 100644
--- a/src/app/structure-list/components/recherche/recherche.component.spec.ts
+++ b/src/app/structure-list/components/search/search.component.spec.ts
@@ -1,19 +1,19 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { RechercheComponent } from './recherche.component';
+import { SearchComponent } from './search.component';
 
 describe('RechercheComponent', () => {
-  let component: RechercheComponent;
-  let fixture: ComponentFixture<RechercheComponent>;
+  let component: SearchComponent;
+  let fixture: ComponentFixture<SearchComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [RechercheComponent],
+      declarations: [SearchComponent],
     }).compileComponents();
   });
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(RechercheComponent);
+    fixture = TestBed.createComponent(SearchComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
diff --git a/src/app/structure-list/components/recherche/recherche.component.ts b/src/app/structure-list/components/search/search.component.ts
similarity index 96%
rename from src/app/structure-list/components/recherche/recherche.component.ts
rename to src/app/structure-list/components/search/search.component.ts
index 94e354989..c9d533d63 100644
--- a/src/app/structure-list/components/recherche/recherche.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -2,11 +2,11 @@ import { Component, OnInit } from '@angular/core';
 import { Category } from '../../models/category.model';
 
 @Component({
-  selector: 'app-recherche',
-  templateUrl: './recherche.component.html',
-  styleUrls: ['./recherche.component.scss'],
+  selector: 'app-search',
+  templateUrl: './search.component.html',
+  styleUrls: ['./search.component.scss'],
 })
-export class RechercheComponent implements OnInit {
+export class SearchComponent implements OnInit {
   constructor() {}
   //Variables btn filtres
   modalType: string[] = ['services', 'accueil', 'plusFiltres'];
@@ -107,7 +107,7 @@ export class RechercheComponent implements OnInit {
    */
   mockService(module: Category[], titre: string, categ: string, nbCateg: number) {
     var m = new Category();
-    m.titre = titre;
+    m.title = titre;
     m.modules = [];
     for (var i = 0; i < nbCateg; i++) {
       m.modules.push(categ + i);
diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts
index 5610acca0..102ac062a 100644
--- a/src/app/structure-list/models/category.model.ts
+++ b/src/app/structure-list/models/category.model.ts
@@ -1,5 +1,5 @@
 export class Category {
-  titre: string;
+  title: string;
   modules: string[];
   size: number;
 }
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index 86c8f6308..ade358e27 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,5 +1,5 @@
 <div class="container">
-  <app-recherche></app-recherche>
+  <app-search></app-search>
   <div class="divider"></div>
   <app-card></app-card>
 </div>
diff --git a/src/app/structure-list/structure-list.module.ts b/src/app/structure-list/structure-list.module.ts
index 7067e0fef..7fe5bcf83 100644
--- a/src/app/structure-list/structure-list.module.ts
+++ b/src/app/structure-list/structure-list.module.ts
@@ -2,12 +2,12 @@ import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { StructureListComponent } from './structure-list.component';
 import { CardComponent } from './components/card/card.component';
-import { RechercheComponent } from './components/recherche/recherche.component';
+import { SearchComponent } from './components/search/search.component';
 import { HttpClientModule } from '@angular/common/http';
 import { FlexLayoutModule } from '@angular/flex-layout';
 
 @NgModule({
-  declarations: [StructureListComponent, CardComponent, RechercheComponent],
+  declarations: [StructureListComponent, CardComponent, SearchComponent],
   imports: [CommonModule, HttpClientModule, FlexLayoutModule],
   exports: [StructureListComponent],
 })
-- 
GitLab


From 577b48167dc7f89141b03d9cdaa922af17c3c175 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 17:45:40 +0200
Subject: [PATCH 16/50] fix(search) : french to english + clean code

---
 .../components/search/search.component.html   |  19 +-
 .../components/search/search.component.ts     | 164 ++++++++----------
 2 files changed, 80 insertions(+), 103 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 3b769e950..15cadf914 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -13,7 +13,7 @@
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
     <button
       type="button"
-      [className]="modalOpened == modalType[0] ? 'selected' : ''"
+      [className]="modalTypeOpened == modalType[0] ? 'selected' : ''"
       (click)="openModal(this.modalType[0])"
     >
       <span class="btnText">Services</span>
@@ -21,7 +21,7 @@
     </button>
     <button
       type="button"
-      [className]="modalOpened == modalType[1] ? 'selected' : ''"
+      [className]="modalTypeOpened == modalType[1] ? 'selected' : ''"
       (click)="openModal(this.modalType[1])"
     >
       <span class="btnText">Accueil</span>
@@ -29,14 +29,19 @@
     </button>
     <button
       type="button"
-      [className]="modalOpened == modalType[2] ? 'selected' : ''"
+      [className]="modalTypeOpened == modalType[2] ? 'selected' : ''"
       (click)="openModal(this.modalType[2])"
     >
       <span class="btnText">Plus de filtres</span>
       <div class="arrow"></div>
     </button>
   </div>
-  <div *ngIf="modalOpened" fxLayout="column" fxLayoutAlign="space-between" [ngClass]="['modal', 'modal' + modalOpened]">
+  <div
+    *ngIf="modalTypeOpened"
+    fxLayout="column"
+    fxLayoutAlign="space-between"
+    [ngClass]="['modal', 'modal' + modalTypeOpened]"
+  >
     <div class="contentModal" fxLayout="row wrap">
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
       <div class="blockFiltre" *ngFor="let c of categories">
@@ -47,7 +52,7 @@
               <label>
                 <input
                   type="checkbox"
-                  [checked]="this.checkedTab.indexOf(module) > -1"
+                  [checked]="this.checkedModules.indexOf(module) > -1"
                   [value]="module"
                   (change)="onCheckboxChange($event, false)"
                 />
@@ -61,8 +66,8 @@
       </div>
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
-      <a (click)="onCheckboxChange($event, true)">Effacer</a>
-      <button type="button" (click)="applyFilter(modalOpened)">Appliquer</button>
+      <a (click)="clearFilters()">Effacer</a>
+      <button type="button" (click)="applyFilter(modalTypeOpened)">Appliquer</button>
     </div>
   </div>
 </div>
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index c9d533d63..634973a08 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -8,102 +8,74 @@ import { Category } from '../../models/category.model';
 })
 export class SearchComponent implements OnInit {
   constructor() {}
-  //Variables btn filtres
-  modalType: string[] = ['services', 'accueil', 'plusFiltres'];
 
-  //Variable gestion liste modal
-  servicesCategories: Category[];
-  modaliteCategories: Category[];
+  // button variable
+  modalType: string[] = ['services', 'modalite', 'plusFiltres'];
+
+  // Modal variable
   categories: Category[];
-  filtresCategories: Category[];
-  modalOpened: string;
+  modalTypeOpened: string;
 
-  //Variable gestion Checkbox
-  checkedTab: string[];
-  filterCheck: string[];
+  // Checkbox variable
+  checkedModules: string[];
+  checkedModulesFilter: string[];
 
   ngOnInit(): void {
-    //Sert à afficher la modal et indiquer le type de filtre choisit
-    this.modalOpened = null;
-
-    //Sert à stocker les différentes catégories
-    this.servicesCategories = [];
-    this.modaliteCategories = [];
+    // Store the different categories
     this.categories = [];
-    this.filtresCategories = [];
 
-    //Sert à gérer la checkbox multiple
-    this.checkedTab = new Array();
-    this.filterCheck = new Array();
+    // Manage checkbox
+    this.checkedModules = new Array();
+    this.checkedModulesFilter = new Array();
   }
 
-  //Ouvrir la modal et afficher la liste en fonction du btn de filtre appuyé
+  // Open the modal and display the list according to the right filter button
   openModal(option: string) {
     this.categories = [];
-    switch (option) {
-      case this.modalType[0]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[0]) {
-          this.modalOpened = this.modalType[0];
-          this.fakeDataServices();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
-      case this.modalType[1]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[1]) {
-          this.modalOpened = this.modalType[1];
-          this.fakeDataModalite();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
-      case this.modalType[2]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[2]) {
-          this.modalOpened = this.modalType[2];
-          this.fakeDataFiltres();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
+    if (this.modalTypeOpened !== option) {
+      this.modalTypeOpened = option;
+      this.fakeData(option);
+    } else {
+      this.modalTypeOpened = null;
     }
-    //Initialisation de la liste temporaire
-    this.checkedTab = this.filterCheck.slice();
+
+    // Init checked list modules
+    this.checkedModules = this.checkedModulesFilter.slice();
   }
 
-  //Envoie d'un tableau contenant tous les filtres
+  // Sends an array containing all filters
   applyFilter() {
-    this.filterCheck = this.checkedTab.slice();
-    this.openModal(this.modalOpened);
-    console.log(this.filterCheck);
+    this.checkedModulesFilter = this.checkedModules.slice();
+    this.openModal(this.modalTypeOpened);
+
+    // Simulation send filter
+    console.log(this.checkedModulesFilter);
   }
 
-  //Gestion de l'evenement checkbox(Cocher/Décocher)
-  onCheckboxChange(e, reset: boolean) {
-    //Condition btn effacer filtre d'une liste
-    if (!reset) {
-      if (e.target.checked) {
-        this.checkedTab.push(e.target.value);
-      } else {
-        //Vérifie si la case décochée est présente dans la liste temporaire et la supprime
-        if (this.checkedTab.indexOf(e.target.value) > -1) {
-          this.checkedTab.splice(this.checkedTab.indexOf(e.target.value), 1);
-        }
-      }
+  // Management of the checkbox event (Check / Uncheck)
+  onCheckboxChange(event) {
+    if (event.target.checked) {
+      this.checkedModules.push(event.target.value);
     } else {
-      //Efface uniquement les éléments de la liste en cours
-      this.categories.forEach((m) => {
-        m.modules.forEach((categ) => {
-          if (this.checkedTab.indexOf(categ) > -1) this.checkedTab.splice(this.checkedTab.indexOf(categ), 1);
-        });
-      });
+      // Check if the unchecked module is present in the list and remove it
+      if (this.checkedModules.indexOf(event.target.value) > -1) {
+        this.checkedModules.splice(this.checkedModules.indexOf(event.target.value), 1);
+      }
     }
   }
 
+  // Clear only filters in the current modal
+  clearFilters() {
+    this.categories.forEach((categ) => {
+      categ.modules.forEach((module) => {
+        if (this.checkedModules.indexOf(module) > -1)
+          this.checkedModules.splice(this.checkedModules.indexOf(module), 1);
+      });
+    });
+  }
+
   /**
-   * En attendant les apis
+   * En attendant l'api
    */
   mockService(module: Category[], titre: string, categ: string, nbCateg: number) {
     var m = new Category();
@@ -114,27 +86,27 @@ export class SearchComponent implements OnInit {
     }
     module.push(m);
   }
-  fakeDataServices() {
-    this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
-    this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
-    this.mockService(
-      this.categories,
-      'Accès aux droits',
-      'Déclarer ses revenus en ligne et découvertes des services proposés',
-      8
-    );
-    this.mockService(this.categories, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
-    this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
-    this.mockService(this.categories, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
-  }
-  fakeDataModalite() {
-    this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
-  }
-  fakeDataFiltres() {
-    this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
-    this.mockService(this.categories, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
-    this.mockService(this.categories, 'Publics', 'Langues étrangères autres qu’anglais', 12);
-    this.mockService(this.categories, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
-    this.mockService(this.categories, 'Type de structure', 'Espace de co-working', 6);
+  fakeData(option: string) {
+    if (option === this.modalType[0]) {
+      this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
+      this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
+      this.mockService(
+        this.categories,
+        'Accès aux droits',
+        'Déclarer ses revenus en ligne et découvertes des services proposés',
+        8
+      );
+      this.mockService(this.categories, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
+      this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
+      this.mockService(this.categories, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
+    } else if (option === this.modalType[1]) {
+      this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
+    } else if (option === this.modalType[2]) {
+      this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
+      this.mockService(this.categories, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
+      this.mockService(this.categories, 'Publics', 'Langues étrangères autres qu’anglais', 12);
+      this.mockService(this.categories, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
+      this.mockService(this.categories, 'Type de structure', 'Espace de co-working', 6);
+    }
   }
 }
-- 
GitLab


From d9afa82ce8b4900c5e6ed1323d3e64d5a11af191 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 18:11:17 +0200
Subject: [PATCH 17/50] fix(search) : fix scss using defined variables

---
 .../components/search/search.component.scss   | 68 ++++---------------
 1 file changed, 13 insertions(+), 55 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index e1ac58b8d..6f46f7690 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -1,15 +1,11 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
 
 .header {
   .title {
-    font-family: Times New Roman;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 20px;
-    line-height: 103%;
+    @include cn-bold-20;
     padding: 16px 0 16px 0;
-
     display: flex;
     align-items: center;
     text-transform: uppercase;
@@ -27,11 +23,7 @@
     width: 100%;
     background-color: $grey-4;
     border: none;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 12px;
-    line-height: 17px;
+    @include cn-regular-14;
     display: flex;
     align-items: center;
     padding-left: 10px;
@@ -44,11 +36,7 @@
       border: none;
       cursor: pointer;
       background-color: $purple;
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
-      line-height: 100%;
+      @include cn-bold-14;
       align-items: center;
       text-align: center;
       color: $white;
@@ -60,7 +48,6 @@
     padding: 16px 0 16px 0;
     button {
       outline: none;
-
       border: 1px solid $grey;
       border-radius: 33px;
       background-color: $white;
@@ -70,11 +57,7 @@
       cursor: pointer;
       .btnText {
         justify-content: center;
-        font-family: Trebuchet MS;
-        font-style: normal;
-        font-weight: normal;
-        font-size: 13px;
-        line-height: 19px;
+        @include cn-regular-14;
         display: flex;
         align-items: center;
       }
@@ -106,13 +89,7 @@
 .footer {
   margin: 0px 0 16px 0;
   a {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 13px;
-    line-height: 18px;
-    /* or 120% */
-
+    @include cn-bold-14;
     display: flex;
     align-items: center;
     text-decoration-line: underline;
@@ -139,7 +116,7 @@
     writing-mode: vertical-lr;
     overflow-y: hidden;
     max-width: 1100px;
-    border-bottom: 1px solid grey;
+    border-bottom: 1px solid $grey;
     margin-bottom: 10px;
     .blockFiltre {
       writing-mode: horizontal-tb;
@@ -150,28 +127,16 @@
       margin: 5px 0 5px 0;
     }
     h4 {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
-      line-height: 17px;
+      @include cn-bold-14;
       display: flex;
       align-items: center;
       margin-top: 0;
     }
     .nbResult {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: normal;
-      font-size: 13px;
-      line-height: 15px;
+      @include cn-regular-14;
     }
     label {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: normal;
-      font-size: 14px;
-      line-height: 16px;
+      @include cn-regular-14;
     }
   }
   .footer {
@@ -181,10 +146,7 @@
       border: none;
       cursor: pointer;
       background-color: $purple;
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
+      @include cn-bold-14;
       line-height: 100%;
       align-items: center;
       text-align: center;
@@ -216,11 +178,7 @@
   }
   .label {
     padding-left: 8px;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 14px;
-    line-height: 17px;
+    @include cn-regular-14;
     padding: 0 16px 0 16px;
   }
   .customCheck {
@@ -247,7 +205,7 @@
       top: 3px;
       width: 4px;
       height: 8px;
-      border: solid white;
+      border: solid $white;
       border-width: 0 2px 2px 0;
       transform: rotate(45deg);
       -webkit-transform: rotate(45deg);
-- 
GitLab


From f410599698b70808a87d609a0c5cbac8dfdebe3c Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 16 Oct 2020 10:28:10 +0200
Subject: [PATCH 18/50] fix(search) : fix search input + list

---
 .../components/card/card.component.ts         | 16 +++++++++++++--
 .../components/search/search.component.html   |  4 ++--
 .../components/search/search.component.ts     | 20 ++++++++++++-------
 src/app/structure-list/models/filter.model.ts |  9 +++++++++
 .../services/structure-list.service.ts        | 20 +++++++++++++++++--
 .../structure-list.component.html             |  4 ++--
 .../structure-list.component.ts               |  6 +++++-
 .../structure-list/structure-list.module.ts   |  3 ++-
 8 files changed, 65 insertions(+), 17 deletions(-)
 create mode 100644 src/app/structure-list/models/filter.model.ts

diff --git a/src/app/structure-list/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
index 5594b507f..5a255e1e1 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
+import { Filter } from '../../models/filter.model';
 import { Structure } from '../../models/structure.model';
 import { StructureService } from '../../services/structure-list.service';
 const { DateTime } = require('luxon');
@@ -10,10 +11,21 @@ const { DateTime } = require('luxon');
 })
 export class CardComponent implements OnInit {
   structures: Structure[] = [];
+  @Input() filter: string;
   constructor(private structureService: StructureService) {}
 
   ngOnInit(): void {
-    this.structureService.getStructures().subscribe((structures) => {
+    this.getStructures(null);
+  }
+  ngOnChanges(): void {
+    let filters: Filter[] = [];
+    filters.push(new Filter('nom', this.filter));
+    this.getStructures(filters);
+  }
+
+  public getStructures(filters): void {
+    this.structureService.getStructures(filters).subscribe((structures) => {
+      this.structures = [];
       structures.forEach((s: Structure) => {
         this.structures.push(this.structureService.updateOpeningStructure(s, DateTime.local()));
       });
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 15cadf914..0beaafe5d 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -6,8 +6,8 @@
     <div class="icon">
       <div class="ico-pin-search grey"></div>
     </div>
-    <input type="text" placeholder="Rechercher une adresse, une association..." />
-    <button type="button">Rechercher</button>
+    <input type="text" [(ngModel)]="searchTerm" placeholder="Rechercher une adresse, une association..." />
+    <button type="button" (click)="submitSearch(searchTerm)">Rechercher</button>
   </div>
 
   <div class="btnSection" 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 634973a08..13c3c7ebd 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, EventEmitter, OnInit, Output } from '@angular/core';
 import { Category } from '../../models/category.model';
 
 @Component({
@@ -9,6 +9,8 @@ import { Category } from '../../models/category.model';
 export class SearchComponent implements OnInit {
   constructor() {}
 
+  @Output() searchEvent = new EventEmitter();
+  searchTerm: string = '';
   // button variable
   modalType: string[] = ['services', 'modalite', 'plusFiltres'];
 
@@ -30,7 +32,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Open the modal and display the list according to the right filter button
-  openModal(option: string) {
+  private openModal(option: string): void {
     this.categories = [];
     if (this.modalTypeOpened !== option) {
       this.modalTypeOpened = option;
@@ -44,7 +46,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Sends an array containing all filters
-  applyFilter() {
+  private applyFilter(): void {
     this.checkedModulesFilter = this.checkedModules.slice();
     this.openModal(this.modalTypeOpened);
 
@@ -53,7 +55,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Management of the checkbox event (Check / Uncheck)
-  onCheckboxChange(event) {
+  private onCheckboxChange(event): void {
     if (event.target.checked) {
       this.checkedModules.push(event.target.value);
     } else {
@@ -65,7 +67,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Clear only filters in the current modal
-  clearFilters() {
+  private clearFilters(): void {
     this.categories.forEach((categ) => {
       categ.modules.forEach((module) => {
         if (this.checkedModules.indexOf(module) > -1)
@@ -74,10 +76,14 @@ export class SearchComponent implements OnInit {
     });
   }
 
+  private submitSearch(searchTerm: string): void {
+    this.searchEvent.emit(searchTerm);
+  }
+
   /**
    * En attendant l'api
    */
-  mockService(module: Category[], titre: string, categ: string, nbCateg: number) {
+  private mockService(module: Category[], titre: string, categ: string, nbCateg: number): void {
     var m = new Category();
     m.title = titre;
     m.modules = [];
@@ -86,7 +92,7 @@ export class SearchComponent implements OnInit {
     }
     module.push(m);
   }
-  fakeData(option: string) {
+  private fakeData(option: string): void {
     if (option === this.modalType[0]) {
       this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
       this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
diff --git a/src/app/structure-list/models/filter.model.ts b/src/app/structure-list/models/filter.model.ts
new file mode 100644
index 000000000..1cee683bd
--- /dev/null
+++ b/src/app/structure-list/models/filter.model.ts
@@ -0,0 +1,9 @@
+export class Filter {
+  name: string;
+  value: string;
+
+  constructor(name: string, value: string) {
+    this.name = name;
+    this.value = value;
+  }
+}
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 9394b38c1..6ac879463 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -11,6 +11,7 @@ import { Time } from '../models/time.model';
 import { Weekday } from '../enum/weekday.enum';
 import { Week } from '../models/week.model';
 import { WeekDay } from '@angular/common';
+import { Filter } from '../models/filter.model';
 
 @Injectable({
   providedIn: 'root',
@@ -18,8 +19,23 @@ import { WeekDay } from '@angular/common';
 export class StructureService {
   constructor(private http: HttpClient) {}
 
-  public getStructures(): Observable<Structure[]> {
-    return this.http.get('/api/Structures').pipe(map((data: any[]) => data.map((item) => new Structure(item))));
+  public getStructures(filters: Filter[]): Observable<Structure[]> {
+    return this.http
+      .get('/api/Structures?' + this.constructApi(filters))
+      .pipe(map((data: any[]) => data.map((item) => new Structure(item))));
+  }
+
+  private constructApi(filters: Filter[]): string {
+    let api: string = '';
+    if (filters) {
+      filters.forEach((filter) => {
+        if (api) {
+          api = api + '&';
+        }
+        api = api + filter.name + '_like=' + filter.value;
+      });
+    }
+    return api;
   }
 
   /**
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index ade358e27..38562830e 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,5 +1,5 @@
 <div class="container">
-  <app-search></app-search>
+  <app-search (searchEvent)="fetchResults($event)"></app-search>
   <div class="divider"></div>
-  <app-card></app-card>
+  <app-card [filter]="currentFilter"></app-card>
 </div>
diff --git a/src/app/structure-list/structure-list.component.ts b/src/app/structure-list/structure-list.component.ts
index 6ea9c6fde..8db285d5f 100644
--- a/src/app/structure-list/structure-list.component.ts
+++ b/src/app/structure-list/structure-list.component.ts
@@ -7,6 +7,10 @@ import { Component, OnInit } from '@angular/core';
 })
 export class StructureListComponent implements OnInit {
   constructor() {}
-
+  currentFilter: string;
   ngOnInit(): void {}
+
+  fetchResults(filter: string) {
+    this.currentFilter = filter;
+  }
 }
diff --git a/src/app/structure-list/structure-list.module.ts b/src/app/structure-list/structure-list.module.ts
index 7fe5bcf83..9947bca5b 100644
--- a/src/app/structure-list/structure-list.module.ts
+++ b/src/app/structure-list/structure-list.module.ts
@@ -5,10 +5,11 @@ import { CardComponent } from './components/card/card.component';
 import { SearchComponent } from './components/search/search.component';
 import { HttpClientModule } from '@angular/common/http';
 import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
 
 @NgModule({
   declarations: [StructureListComponent, CardComponent, SearchComponent],
-  imports: [CommonModule, HttpClientModule, FlexLayoutModule],
+  imports: [CommonModule, HttpClientModule, FlexLayoutModule, FormsModule],
   exports: [StructureListComponent],
 })
 export class StructureListModule {}
-- 
GitLab


From 89839b8f970db79d39b34d15f4e21375c6eb7de7 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Fri, 16 Oct 2020 14:32:45 +0200
Subject: [PATCH 19/50] fix(search) : design scroll bar  + fix modal design

---
 .../components/search/search.component.html   | 39 ++++++-----
 .../components/search/search.component.scss   | 68 +++++++++++++------
 .../components/search/search.component.ts     | 15 ++--
 3 files changed, 76 insertions(+), 46 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 0beaafe5d..ab6ba5235 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -16,7 +16,7 @@
       [className]="modalTypeOpened == modalType[0] ? 'selected' : ''"
       (click)="openModal(this.modalType[0])"
     >
-      <span class="btnText">Services</span>
+      <span class="btnText">Accompagnement</span>
       <div class="arrow"></div>
     </button>
     <button
@@ -24,7 +24,7 @@
       [className]="modalTypeOpened == modalType[1] ? 'selected' : ''"
       (click)="openModal(this.modalType[1])"
     >
-      <span class="btnText">Accueil</span>
+      <span class="btnText">Formations</span>
       <div class="arrow"></div>
     </button>
     <button
@@ -42,27 +42,30 @@
     fxLayoutAlign="space-between"
     [ngClass]="['modal', 'modal' + modalTypeOpened]"
   >
-    <div class="contentModal" fxLayout="row wrap">
+    <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start">
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
       <div class="blockFiltre" *ngFor="let c of categories">
-        <div class="blockLigne">
-          <h4>{{ c.title }}</h4>
+        <h4>{{ c.title }}</h4>
+
+        <ul class="blockLigne">
           <div fxLayout="row" class="ligneFiltre" fxLayoutAlign="space-between center" *ngFor="let module of c.modules">
-            <div class="checkbox">
-              <label>
-                <input
-                  type="checkbox"
-                  [checked]="this.checkedModules.indexOf(module) > -1"
-                  [value]="module"
-                  (change)="onCheckboxChange($event, false)"
-                />
-                <span class="customCheck"></span>
-              </label>
-              <div class="label">{{ module }}</div>
-            </div>
+            <li class="checkbox">
+              <div class="testBox">
+                <label>
+                  <input
+                    type="checkbox"
+                    [checked]="this.checkedModules.indexOf(module) > -1"
+                    [value]="module"
+                    (change)="onCheckboxChange($event, false)"
+                  />
+                  <span class="customCheck"></span>
+                </label>
+                <div class="label">{{ module }}</div>
+              </div>
+            </li>
             <span class="nbResult">34</span>
           </div>
-        </div>
+        </ul>
       </div>
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 6f46f7690..2a64a6845 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -86,15 +86,6 @@
     }
   }
 }
-.footer {
-  margin: 0px 0 16px 0;
-  a {
-    @include cn-bold-14;
-    display: flex;
-    align-items: center;
-    text-decoration-line: underline;
-  }
-}
 .modalaccueil {
   margin-left: 100px;
 }
@@ -103,28 +94,48 @@
 }
 .modal {
   max-height: 654px;
-  max-width: 1100px;
+  max-width: 754px;
   background: $white;
-  border: 1px solid $purple;
+  border: 1px solid $grey;
   box-sizing: border-box;
-  border-radius: 8px;
   z-index: 1;
   position: absolute;
   margin-top: 80px;
-  padding: 20px 16px 10px 16px;
+
+  ::-webkit-scrollbar {
+    width: 10px;
+  }
+  ::-webkit-scrollbar-track {
+    background: $grey-4;
+  }
+  ::-webkit-scrollbar-thumb {
+    background: $grey;
+    border-radius: 6px;
+  }
+
   .contentModal {
-    writing-mode: vertical-lr;
-    overflow-y: hidden;
+    overflow-y: auto;
     max-width: 1100px;
     border-bottom: 1px solid $grey;
     margin-bottom: 10px;
+
     .blockFiltre {
-      writing-mode: horizontal-tb;
-      max-width: 320px;
-      padding: 0 30px 10px 10px;
+      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: 1;
+      column-gap: 46px;
+      column-rule: dashed 1px $grey;
     }
     .ligneFiltre {
-      margin: 5px 0 5px 0;
+      padding: 5px 0 5px 0;
     }
     h4 {
       @include cn-bold-14;
@@ -140,6 +151,13 @@
     }
   }
   .footer {
+    margin: 0px 20px 16px 0;
+    a {
+      @include cn-bold-14;
+      display: flex;
+      align-items: center;
+      text-decoration-line: underline;
+    }
     height: 32px;
     button {
       height: 100%;
@@ -157,11 +175,19 @@
   }
 }
 .checkbox {
-  position: relative;
+  .testBox {
+    position: relative;
+    display: inline-grid;
+    align-items: center;
+    grid-template-columns: min-content auto;
+    min-height: 25px;
+  }
+  /*position: relative;
   display: grid;
   align-items: center;
   grid-template-columns: min-content auto;
-  min-height: 25px;
+  min-height: 25px;*/
+  list-style-type: none;
   input {
     opacity: 0;
     display: none;
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 13c3c7ebd..9c3694255 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -32,7 +32,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Open the modal and display the list according to the right filter button
-  private openModal(option: string): void {
+  public openModal(option: string): void {
     this.categories = [];
     if (this.modalTypeOpened !== option) {
       this.modalTypeOpened = option;
@@ -46,7 +46,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Sends an array containing all filters
-  private applyFilter(): void {
+  public applyFilter(): void {
     this.checkedModulesFilter = this.checkedModules.slice();
     this.openModal(this.modalTypeOpened);
 
@@ -55,7 +55,7 @@ export class SearchComponent implements OnInit {
   }
 
   // Management of the checkbox event (Check / Uncheck)
-  private onCheckboxChange(event): void {
+  public onCheckboxChange(event): void {
     if (event.target.checked) {
       this.checkedModules.push(event.target.value);
     } else {
@@ -76,7 +76,7 @@ export class SearchComponent implements OnInit {
     });
   }
 
-  private submitSearch(searchTerm: string): void {
+  public submitSearch(searchTerm: string): void {
     this.searchEvent.emit(searchTerm);
   }
 
@@ -95,6 +95,8 @@ export class SearchComponent implements OnInit {
   private fakeData(option: string): void {
     if (option === this.modalType[0]) {
       this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
+    } else if (option === this.modalType[1]) {
+      this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
       this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
       this.mockService(
         this.categories,
@@ -103,12 +105,11 @@ export class SearchComponent implements OnInit {
         8
       );
       this.mockService(this.categories, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
-      this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
       this.mockService(this.categories, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
-    } else if (option === this.modalType[1]) {
-      this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
     } else if (option === this.modalType[2]) {
       this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
+      this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
+
       this.mockService(this.categories, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
       this.mockService(this.categories, 'Publics', 'Langues étrangères autres qu’anglais', 12);
       this.mockService(this.categories, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
-- 
GitLab


From c83eac6e7538bd18bb5a18cd21bb9da89f59561c Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 19 Oct 2020 17:04:53 +0200
Subject: [PATCH 20/50] fix(search) : Add checkbox filter + clean code

---
 .../components/card/card.component.ts         |   8 +-
 .../components/search/search.component.html   |  80 +++---
 .../components/search/search.component.scss   |  21 +-
 .../components/search/search.component.ts     | 106 +++++---
 .../structure-list/models/category.model.ts   |   7 +-
 src/app/structure-list/models/filter.model.ts |   6 +-
 src/app/structure-list/models/module.model.ts |   9 +
 .../services/search.service.spec.ts           |  16 ++
 .../structure-list/services/search.service.ts |  14 +
 .../services/structure-list.service.ts        |   7 +-
 .../structure-list.component.ts               |   5 +-
 .../components/card/card.component.html       |  25 --
 .../components/card/card.component.scss       |  52 ----
 .../components/card/card.component.spec.ts    |  25 --
 .../components/card/card.component.ts         |  23 --
 .../recherche/recherche.component.html        |  83 ------
 .../recherche/recherche.component.scss        | 257 ------------------
 .../recherche/recherche.component.spec.ts     |  25 --
 .../recherche/recherche.component.ts          | 140 ----------
 src/app/structure/models/recherche.model.ts   |   5 -
 src/app/structure/models/structure.model.ts   |  44 ---
 .../services/structure.service.spec.ts        | 221 ---------------
 .../structure/services/structure.service.ts   | 163 -----------
 src/app/structure/structure.component.html    |   5 -
 src/app/structure/structure.component.scss    |  11 -
 src/app/structure/structure.component.spec.ts |  25 --
 src/app/structure/structure.component.ts      |  15 -
 src/app/structure/structure.module.ts         |  15 -
 28 files changed, 184 insertions(+), 1229 deletions(-)
 create mode 100644 src/app/structure-list/models/module.model.ts
 create mode 100644 src/app/structure-list/services/search.service.spec.ts
 create mode 100644 src/app/structure-list/services/search.service.ts
 delete mode 100644 src/app/structure/components/card/card.component.html
 delete mode 100644 src/app/structure/components/card/card.component.scss
 delete mode 100644 src/app/structure/components/card/card.component.spec.ts
 delete mode 100644 src/app/structure/components/card/card.component.ts
 delete mode 100644 src/app/structure/components/recherche/recherche.component.html
 delete mode 100644 src/app/structure/components/recherche/recherche.component.scss
 delete mode 100644 src/app/structure/components/recherche/recherche.component.spec.ts
 delete mode 100644 src/app/structure/components/recherche/recherche.component.ts
 delete mode 100644 src/app/structure/models/recherche.model.ts
 delete mode 100644 src/app/structure/models/structure.model.ts
 delete mode 100644 src/app/structure/services/structure.service.spec.ts
 delete mode 100644 src/app/structure/services/structure.service.ts
 delete mode 100644 src/app/structure/structure.component.html
 delete mode 100644 src/app/structure/structure.component.scss
 delete mode 100644 src/app/structure/structure.component.spec.ts
 delete mode 100644 src/app/structure/structure.component.ts
 delete mode 100644 src/app/structure/structure.module.ts

diff --git a/src/app/structure-list/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
index 5a255e1e1..a54d92069 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -11,7 +11,7 @@ const { DateTime } = require('luxon');
 })
 export class CardComponent implements OnInit {
   structures: Structure[] = [];
-  @Input() filter: string;
+  @Input() filter: Filter[];
   constructor(private structureService: StructureService) {}
 
   ngOnInit(): void {
@@ -19,8 +19,10 @@ export class CardComponent implements OnInit {
   }
   ngOnChanges(): void {
     let filters: Filter[] = [];
-    filters.push(new Filter('nom', this.filter));
-    this.getStructures(filters);
+    if (this.filter) {
+      filters = this.filter;
+      this.getStructures(filters);
+    }
   }
 
   public getStructures(filters): void {
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index ab6ba5235..8236e0fcd 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -7,34 +7,36 @@
       <div class="ico-pin-search grey"></div>
     </div>
     <input type="text" [(ngModel)]="searchTerm" placeholder="Rechercher une adresse, une association..." />
-    <button type="button" (click)="submitSearch(searchTerm)">Rechercher</button>
+    <button type="button" (click)="applyFilter()">Rechercher</button>
   </div>
 
-  <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
-    <button
-      type="button"
-      [className]="modalTypeOpened == modalType[0] ? 'selected' : ''"
-      (click)="openModal(this.modalType[0])"
-    >
-      <span class="btnText">Accompagnement</span>
-      <div class="arrow"></div>
-    </button>
-    <button
-      type="button"
-      [className]="modalTypeOpened == modalType[1] ? 'selected' : ''"
-      (click)="openModal(this.modalType[1])"
-    >
-      <span class="btnText">Formations</span>
-      <div class="arrow"></div>
-    </button>
-    <button
-      type="button"
-      [className]="modalTypeOpened == modalType[2] ? 'selected' : ''"
-      (click)="openModal(this.modalType[2])"
-    >
-      <span class="btnText">Plus de filtres</span>
-      <div class="arrow"></div>
-    </button>
+  <div class="btnSection">
+    <div class="phoneSection" fxLayout="row" fxLayoutAlign="center center">
+      <button
+        type="button"
+        [className]="modalTypeOpened === modalType[0] ? 'selected' : ''"
+        (click)="openModal(this.modalType[0])"
+      >
+        <span class="btnText">Accompagnement</span>
+        <div class="arrow"></div>
+      </button>
+      <button
+        type="button"
+        [className]="modalTypeOpened === modalType[1] ? 'selected' : ''"
+        (click)="openModal(this.modalType[1])"
+      >
+        <span class="btnText">Formations</span>
+        <div class="arrow"></div>
+      </button>
+      <button
+        type="button"
+        [className]="modalTypeOpened === modalType[2] ? 'selected' : ''"
+        (click)="openModal(this.modalType[2])"
+      >
+        <span class="btnText">Plus de filtres</span>
+        <div class="arrow"></div>
+      </button>
+    </div>
   </div>
   <div
     *ngIf="modalTypeOpened"
@@ -42,25 +44,25 @@
     fxLayoutAlign="space-between"
     [ngClass]="['modal', 'modal' + modalTypeOpened]"
   >
-    <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start">
+    <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
       <!--<div class="blockFiltre" *ngFor="let s of services">-->
       <div class="blockFiltre" *ngFor="let c of categories">
-        <h4>{{ c.title }}</h4>
+        <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="testBox">
+              <div class="checkboxItem">
                 <label>
                   <input
                     type="checkbox"
-                    [checked]="this.checkedModules.indexOf(module) > -1"
-                    [value]="module"
-                    (change)="onCheckboxChange($event, false)"
+                    [checked]="getIndex(module.id, c.name) > -1"
+                    [value]="module.id"
+                    (change)="onCheckboxChange($event, c.name)"
                   />
                   <span class="customCheck"></span>
                 </label>
-                <div class="label">{{ module }}</div>
+                <div class="label">{{ module.text }}</div>
               </div>
             </li>
             <span class="nbResult">34</span>
@@ -76,11 +78,13 @@
 </div>
 <div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
-    <label>
-      <input type="checkbox" />
-      <span class="customCheck"></span>
-    </label>
-    <div class="label">Pass numérique</div>
+    <div class="checkboxItem">
+      <label>
+        <input type="checkbox" />
+        <span class="customCheck"></span>
+      </label>
+      <div class="label">Pass numérique</div>
+    </div>
   </div>
   <a href="">Ajouter une structure</a>
 </div>
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 2a64a6845..cbe065b6c 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -1,6 +1,7 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
 @import '../../../../assets/scss/typography';
+@import '../../../../assets/scss/breakpoint';
 
 .header {
   .title {
@@ -46,6 +47,9 @@
   }
   .btnSection {
     padding: 16px 0 16px 0;
+    .phoneSection {
+      display: none;
+    }
     button {
       outline: none;
       border: 1px solid $grey;
@@ -130,7 +134,7 @@
       -moz-column-gap: 46px;
       -webkit-column-count: 2;
       -webkit-column-gap: 46px;
-      column-count: 1;
+      column-count: 2;
       column-gap: 46px;
       column-rule: dashed 1px $grey;
     }
@@ -175,18 +179,13 @@
   }
 }
 .checkbox {
-  .testBox {
+  .checkboxItem {
     position: relative;
     display: inline-grid;
     align-items: center;
     grid-template-columns: min-content auto;
     min-height: 25px;
   }
-  /*position: relative;
-  display: grid;
-  align-items: center;
-  grid-template-columns: min-content auto;
-  min-height: 25px;*/
   list-style-type: none;
   input {
     opacity: 0;
@@ -239,3 +238,11 @@
     }
   }
 }
+/*@media #{$phone} {
+  .allSection {
+    display: none !important;
+  }
+  .phoneSection {
+    display: flex;
+  }
+}*/
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 9c3694255..86550580e 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -1,5 +1,8 @@
 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
 import { Category } from '../../models/category.model';
+import { Filter } from '../../models/filter.model';
+import { Module } from '../../models/module.model';
+import { SearchService } from '../../services/search.service';
 
 @Component({
   selector: 'app-search',
@@ -7,11 +10,14 @@ import { Category } from '../../models/category.model';
   styleUrls: ['./search.component.scss'],
 })
 export class SearchComponent implements OnInit {
-  constructor() {}
+  constructor(private searchService: SearchService) {}
 
   @Output() searchEvent = new EventEmitter();
+
+  // Search input variable
   searchTerm: string = '';
-  // button variable
+
+  // Button variable
   modalType: string[] = ['services', 'modalite', 'plusFiltres'];
 
   // Modal variable
@@ -19,11 +25,11 @@ export class SearchComponent implements OnInit {
   modalTypeOpened: string;
 
   // Checkbox variable
-  checkedModules: string[];
-  checkedModulesFilter: string[];
+  checkedModules: Module[];
+  checkedModulesFilter: Module[];
 
   ngOnInit(): void {
-    // Store the different categories
+    // Will store the different categories
     this.categories = [];
 
     // Manage checkbox
@@ -31,6 +37,11 @@ export class SearchComponent implements OnInit {
     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 = [];
@@ -50,62 +61,81 @@ export class SearchComponent implements OnInit {
     this.checkedModulesFilter = this.checkedModules.slice();
     this.openModal(this.modalTypeOpened);
 
-    // Simulation send filter
-    console.log(this.checkedModulesFilter);
+    // Send search input filter
+    let filters: Filter[] = [];
+    if (this.searchTerm) {
+      filters.push(new Filter('nom', this.searchTerm, false));
+    }
+
+    // Send checked box filter
+    this.checkedModulesFilter.forEach((cm) => {
+      filters.push(new Filter(this.fromStringToIdExcel(cm.text), this.mockApiNumber(cm.id), false));
+    });
+    this.searchEvent.emit(filters);
   }
 
   // Management of the checkbox event (Check / Uncheck)
-  public onCheckboxChange(event): void {
+  public onCheckboxChange(event, categ: string): void {
+    const checkValue: number = parseInt(event.target.value);
     if (event.target.checked) {
-      this.checkedModules.push(event.target.value);
+      this.checkedModules.push(new Module(checkValue, categ));
     } else {
       // Check if the unchecked module is present in the list and remove it
-      if (this.checkedModules.indexOf(event.target.value) > -1) {
-        this.checkedModules.splice(this.checkedModules.indexOf(event.target.value), 1);
+      if (this.getIndex(checkValue, categ) > -1) {
+        this.checkedModules.splice(this.getIndex(checkValue, categ), 1);
       }
     }
   }
 
+  // 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);
+  }
+
   // Clear only filters in the current modal
-  private clearFilters(): void {
-    this.categories.forEach((categ) => {
-      categ.modules.forEach((module) => {
-        if (this.checkedModules.indexOf(module) > -1)
-          this.checkedModules.splice(this.checkedModules.indexOf(module), 1);
+  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);
       });
     });
   }
 
-  public submitSearch(searchTerm: string): void {
-    this.searchEvent.emit(searchTerm);
+  // 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++) {
+      splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
+    }
+    return splitStr
+      .join('')
+      .normalize('NFD')
+      .replace(/[\u0300-\u036f'’°()]/g, '')
+      .replace(/[\s-]/g, ' ')
+      .replace('?', '');
   }
-
-  /**
-   * En attendant l'api
-   */
-  private mockService(module: Category[], titre: string, categ: string, nbCateg: number): void {
-    var m = new Category();
-    m.title = titre;
+  // Fake service api
+  private mockService(module: Category[], titre: string, categ: any, nbCateg: number): void {
+    let m = new Category();
+    m.name = titre;
     m.modules = [];
-    for (var i = 0; i < nbCateg; i++) {
-      m.modules.push(categ + i);
+    for (let i = 0; i < nbCateg; i++) {
+      m.modules.push(new Module(categ.id, categ.name + i));
     }
     module.push(m);
   }
+
+  // Fake data
   private fakeData(option: string): void {
     if (option === this.modalType[0]) {
-      this.mockService(this.categories, 'Accompagnement aux démarches en ligne', 'CAF', 7);
+      this.mockService(this.categories, 'Accompagnement des démarches', { name: 'CAF', id: '' }, 7);
     } else if (option === this.modalType[1]) {
-      this.mockService(this.categories, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
-      this.mockService(this.categories, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
-      this.mockService(
-        this.categories,
-        'Accès aux droits',
-        'Déclarer ses revenus en ligne et découvertes des services proposés',
-        8
-      );
-      this.mockService(this.categories, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
-      this.mockService(this.categories, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
+      this.searchService.getCategories().subscribe((d) => {
+        d.forEach((element) => {
+          this.categories.push(element);
+        });
+      });
     } else if (option === this.modalType[2]) {
       this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
       this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts
index 102ac062a..f6c60e54e 100644
--- a/src/app/structure-list/models/category.model.ts
+++ b/src/app/structure-list/models/category.model.ts
@@ -1,5 +1,6 @@
+import { Module } from './module.model';
+
 export class Category {
-  title: string;
-  modules: string[];
-  size: number;
+  name: string;
+  modules: Module[];
 }
diff --git a/src/app/structure-list/models/filter.model.ts b/src/app/structure-list/models/filter.model.ts
index 1cee683bd..826633f50 100644
--- a/src/app/structure-list/models/filter.model.ts
+++ b/src/app/structure-list/models/filter.model.ts
@@ -1,9 +1,11 @@
 export class Filter {
   name: string;
   value: string;
+  isStrict: boolean;
 
-  constructor(name: string, value: string) {
+  constructor(name: string, value: any, isStrict: boolean) {
     this.name = name;
-    this.value = value;
+    this.value = value.toString();
+    this.isStrict = isStrict;
   }
 }
diff --git a/src/app/structure-list/models/module.model.ts b/src/app/structure-list/models/module.model.ts
new file mode 100644
index 000000000..83d025356
--- /dev/null
+++ b/src/app/structure-list/models/module.model.ts
@@ -0,0 +1,9 @@
+export class Module {
+  id: number;
+  text: string;
+
+  constructor(id: number, text: string) {
+    this.id = id;
+    this.text = text;
+  }
+}
diff --git a/src/app/structure-list/services/search.service.spec.ts b/src/app/structure-list/services/search.service.spec.ts
new file mode 100644
index 000000000..23c42c7bb
--- /dev/null
+++ b/src/app/structure-list/services/search.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { SearchService } from './search.service';
+
+describe('SearchService', () => {
+  let service: SearchService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(SearchService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/app/structure-list/services/search.service.ts b/src/app/structure-list/services/search.service.ts
new file mode 100644
index 000000000..d48c602e1
--- /dev/null
+++ b/src/app/structure-list/services/search.service.ts
@@ -0,0 +1,14 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class SearchService {
+  constructor(private http: HttpClient) {}
+
+  public getCategories(): Observable<any> {
+    return this.http.get('/api/Categories');
+  }
+}
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 6ac879463..0a1d1e34a 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -9,7 +9,6 @@ import { OpeningDay } from '../models/openingDay.model';
 import { Structure } from '../models/structure.model';
 import { Time } from '../models/time.model';
 import { Weekday } from '../enum/weekday.enum';
-import { Week } from '../models/week.model';
 import { WeekDay } from '@angular/common';
 import { Filter } from '../models/filter.model';
 
@@ -32,7 +31,11 @@ export class StructureService {
         if (api) {
           api = api + '&';
         }
-        api = api + filter.name + '_like=' + filter.value;
+        if (filter.isStrict) {
+          api = api + filter.name + '=' + filter.value;
+        } else {
+          api = api + filter.name + '_like=' + filter.value;
+        }
       });
     }
     return api;
diff --git a/src/app/structure-list/structure-list.component.ts b/src/app/structure-list/structure-list.component.ts
index 8db285d5f..e62cff38c 100644
--- a/src/app/structure-list/structure-list.component.ts
+++ b/src/app/structure-list/structure-list.component.ts
@@ -1,4 +1,5 @@
 import { Component, OnInit } from '@angular/core';
+import { Filter } from './models/filter.model';
 
 @Component({
   selector: 'app-structure-list',
@@ -7,10 +8,10 @@ import { Component, OnInit } from '@angular/core';
 })
 export class StructureListComponent implements OnInit {
   constructor() {}
-  currentFilter: string;
+  currentFilter: Filter[];
   ngOnInit(): void {}
 
-  fetchResults(filter: string) {
+  fetchResults(filter: Filter[]) {
     this.currentFilter = filter;
   }
 }
diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
deleted file mode 100644
index e2443b8c8..000000000
--- a/src/app/structure/components/card/card.component.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<span class="nbStructuresLabel">{{ structures.length }} structures</span>
-<div class="structure" fxLayout="column" *ngFor="let structure of structures">
-  <span class="nomStructure">{{ structure.nom }}</span>
-
-  <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
-    <span class="typeStructure">{{ structure.type_de_structure }}</span>
-    <span class="distanceStructure">|-| 63 m</span>
-  </div>
-  <br />
-  <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="1vw">
-    <div *ngIf="structure.estOuvert; else closed">
-      <span class="ico-dot-available"></span>
-      <span> Ouvert actuellement</span>
-    </div>
-    <ng-template #closed>
-      <span class="ico-dot-unavailable"></span>
-      <span *ngIf="structure.ouvreLe.jour; else noTime">
-        Fermé - Ouvre {{ structure.ouvreLe.jour }} à {{ structure.ouvreLe.horaire }}</span
-      >
-    </ng-template>
-  </div>
-</div>
-<ng-template #noTime>
-  <span> Fermé - Aucun horaire disponible</span>
-</ng-template>
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure/components/card/card.component.scss
deleted file mode 100644
index f3f374801..000000000
--- a/src/app/structure/components/card/card.component.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-@import '../../../../assets/scss/icons';
-.nbStructuresLabel {
-  color: #828282;
-  font-family: Trebuchet MS;
-  font-style: normal;
-  font-weight: normal;
-  font-size: 16px;
-  line-height: 19px;
-  display: flex;
-  align-items: center;
-}
-.structure {
-  padding: 12px 0 12px 0;
-  border-bottom: 1px dashed #bdbdbd;
-  .typeStructure {
-    color: #828282;
-    font-family: Times New Roman;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 16px;
-    line-height: 100%;
-  }
-  .nomStructure {
-    padding-top: 13px;
-    color: #594d59;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 20px;
-    line-height: 103%;
-    padding-bottom: 5px;
-  }
-  .distanceStructure {
-    font-family: Times New Roman;
-    font-style: normal;
-    font-size: 16px;
-    line-height: 103%;
-    color: #594d59;
-  }
-  &:last-child {
-    border-bottom: none;
-  }
-}
-.statusStructure {
-  span {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 15px;
-    line-height: 103%;
-  }
-}
diff --git a/src/app/structure/components/card/card.component.spec.ts b/src/app/structure/components/card/card.component.spec.ts
deleted file mode 100644
index c0787da7b..000000000
--- a/src/app/structure/components/card/card.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { CardComponent } from './card.component';
-import { HttpClientModule } from '@angular/common/http';
-describe('CardComponent', () => {
-  let component: CardComponent;
-  let fixture: ComponentFixture<CardComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [HttpClientModule],
-      declarations: [CardComponent],
-    }).compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(CardComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
deleted file mode 100644
index ad3154950..000000000
--- a/src/app/structure/components/card/card.component.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { Structure } from '../../models/structure.model';
-import { StructureService } from '../../services/structure.service';
-const { DateTime } = require('luxon');
-
-@Component({
-  selector: 'app-card',
-  templateUrl: './card.component.html',
-  styleUrls: ['./card.component.scss'],
-})
-export class CardComponent implements OnInit {
-  structures: Structure[] = [];
-  constructor(private _structureService: StructureService) {}
-
-  ngOnInit(): void {
-    var dt = DateTime.local();
-    this._structureService.recupererStructures().subscribe((structures: Structure[]) => {
-      structures.forEach((s: Structure) => {
-        this.structures.push(this._structureService.majOuvertureStructure(s, dt));
-      });
-    });
-  }
-}
diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure/components/recherche/recherche.component.html
deleted file mode 100644
index 00eecd6da..000000000
--- a/src/app/structure/components/recherche/recherche.component.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<div class="header">
-  <span class="title">Acteurs de la médiation</span>
-</div>
-<div class="content" fxLayout="column">
-  <div class="searchSection" fxLayout="row" fxLayoutGap="1.5vw">
-    <div class="icon">
-      <div class="ico-pin-search grey"></div>
-    </div>
-    <input type="text" placeholder="Rechercher une adresse, une association..." />
-    <button type="button">Rechercher</button>
-  </div>
-
-  <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
-    <button
-      type="button"
-      [className]="modalOpened == modalType[0] ? 'selected' : ''"
-      (click)="openModal(this.modalType[0])"
-    >
-      <span class="btnText">Services</span>
-      <div class="arrow"></div>
-    </button>
-    <button
-      type="button"
-      [className]="modalOpened == modalType[1] ? 'selected' : ''"
-      (click)="openModal(this.modalType[1])"
-    >
-      <span class="btnText">Accueil</span>
-      <div class="arrow"></div>
-    </button>
-    <button
-      type="button"
-      [className]="modalOpened == modalType[2] ? 'selected' : ''"
-      (click)="openModal(this.modalType[2])"
-    >
-      <span class="btnText">Plus de filtres</span>
-      <div class="arrow"></div>
-    </button>
-  </div>
-  <div *ngIf="modalOpened" fxLayout="column" fxLayoutAlign="space-between" [ngClass]="['modal', 'modal' + modalOpened]">
-    <div class="contentModal" fxLayout="row wrap">
-      <!--<div class="blockFiltre" *ngFor="let s of services">-->
-      <div class="blockFiltre" *ngFor="let m of modules">
-        <div class="blockLigne">
-          <h4>{{ m.titre }}</h4>
-          <div
-            fxLayout="row"
-            class="ligneFiltre"
-            fxLayoutAlign="space-between center"
-            *ngFor="let categ of m.categories"
-          >
-            <div class="checkbox">
-              <label>
-                <input
-                  type="checkbox"
-                  [checked]="this.checkedTab.indexOf(categ) > -1"
-                  [value]="categ"
-                  (change)="onCheckboxChange($event, false)"
-                />
-                <span class="customCheck"></span>
-              </label>
-              <div class="label">{{ categ }}</div>
-            </div>
-            <span class="nbResult">34</span>
-          </div>
-        </div>
-      </div>
-    </div>
-    <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
-      <a (click)="onCheckboxChange($event, true)">Effacer</a>
-      <button type="button" (click)="applyFilter(modalOpened)">Appliquer</button>
-    </div>
-  </div>
-</div>
-<div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
-  <div class="checkbox">
-    <label>
-      <input type="checkbox" />
-      <span class="customCheck"></span>
-    </label>
-    <div class="label">Pass numérique</div>
-  </div>
-  <a href="">Ajouter une structure</a>
-</div>
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure/components/recherche/recherche.component.scss
deleted file mode 100644
index e1ac58b8d..000000000
--- a/src/app/structure/components/recherche/recherche.component.scss
+++ /dev/null
@@ -1,257 +0,0 @@
-@import '../../../../assets/scss/icons';
-@import '../../../../assets/scss/color';
-
-.header {
-  .title {
-    font-family: Times New Roman;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 20px;
-    line-height: 103%;
-    padding: 16px 0 16px 0;
-
-    display: flex;
-    align-items: center;
-    text-transform: uppercase;
-  }
-}
-.content {
-  margin: 10px 0 0px 0;
-  .icon {
-    border: 1px solid $grey;
-    padding: 4px 6px 8px 6px;
-    border-radius: 4px;
-    cursor: pointer;
-  }
-  input {
-    width: 100%;
-    background-color: $grey-4;
-    border: none;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 12px;
-    line-height: 17px;
-    display: flex;
-    align-items: center;
-    padding-left: 10px;
-    text-overflow: ellipsis;
-    color: $grey-1;
-    outline: none;
-  }
-  .searchSection {
-    button {
-      border: none;
-      cursor: pointer;
-      background-color: $purple;
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
-      line-height: 100%;
-      align-items: center;
-      text-align: center;
-      color: $white;
-      padding: 3px 16px 3px 16px;
-      outline: none;
-    }
-  }
-  .btnSection {
-    padding: 16px 0 16px 0;
-    button {
-      outline: none;
-
-      border: 1px solid $grey;
-      border-radius: 33px;
-      background-color: $white;
-      padding: 2px 6px 2px 13px;
-      align-items: center;
-      display: flex;
-      cursor: pointer;
-      .btnText {
-        justify-content: center;
-        font-family: Trebuchet MS;
-        font-style: normal;
-        font-weight: normal;
-        font-size: 13px;
-        line-height: 19px;
-        display: flex;
-        align-items: center;
-      }
-    }
-    .selected {
-      border: 1px solid $orange-light;
-      color: $orange-light;
-      .arrow {
-        background-color: transparent;
-        border-bottom: 1px solid $orange-light;
-        border-right: 1px solid $orange-light;
-        transform: translateY(25%) rotate(-135deg);
-        margin: 0 5px 0 10px;
-        height: 7px;
-        width: 7px;
-      }
-    }
-    .arrow {
-      background-color: transparent;
-      border-bottom: 1px solid $grey;
-      border-right: 1px solid $grey;
-      transform: translateY(-25%) rotate(45deg);
-      margin: 0 5px 0 10px;
-      height: 7px;
-      width: 7px;
-    }
-  }
-}
-.footer {
-  margin: 0px 0 16px 0;
-  a {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 13px;
-    line-height: 18px;
-    /* or 120% */
-
-    display: flex;
-    align-items: center;
-    text-decoration-line: underline;
-  }
-}
-.modalaccueil {
-  margin-left: 100px;
-}
-.modalplusFiltres {
-  margin-left: 196px;
-}
-.modal {
-  max-height: 654px;
-  max-width: 1100px;
-  background: $white;
-  border: 1px solid $purple;
-  box-sizing: border-box;
-  border-radius: 8px;
-  z-index: 1;
-  position: absolute;
-  margin-top: 80px;
-  padding: 20px 16px 10px 16px;
-  .contentModal {
-    writing-mode: vertical-lr;
-    overflow-y: hidden;
-    max-width: 1100px;
-    border-bottom: 1px solid grey;
-    margin-bottom: 10px;
-    .blockFiltre {
-      writing-mode: horizontal-tb;
-      max-width: 320px;
-      padding: 0 30px 10px 10px;
-    }
-    .ligneFiltre {
-      margin: 5px 0 5px 0;
-    }
-    h4 {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
-      line-height: 17px;
-      display: flex;
-      align-items: center;
-      margin-top: 0;
-    }
-    .nbResult {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: normal;
-      font-size: 13px;
-      line-height: 15px;
-    }
-    label {
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: normal;
-      font-size: 14px;
-      line-height: 16px;
-    }
-  }
-  .footer {
-    height: 32px;
-    button {
-      height: 100%;
-      border: none;
-      cursor: pointer;
-      background-color: $purple;
-      font-family: Trebuchet MS;
-      font-style: normal;
-      font-weight: bold;
-      font-size: 13px;
-      line-height: 100%;
-      align-items: center;
-      text-align: center;
-      color: $white;
-      padding: 3px 16px 3px 16px;
-      outline: none;
-    }
-  }
-}
-.checkbox {
-  position: relative;
-  display: grid;
-  align-items: center;
-  grid-template-columns: min-content auto;
-  min-height: 25px;
-  input {
-    opacity: 0;
-    display: none;
-    &:checked ~ .customCheck {
-      background-color: $orange-light;
-      border-color: transparent;
-    }
-    &:checked ~ .customCheck:after {
-      display: block;
-    }
-  }
-  label {
-    display: inline-grid;
-  }
-  .label {
-    padding-left: 8px;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 14px;
-    line-height: 17px;
-    padding: 0 16px 0 16px;
-  }
-  .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-4;
-    }
-    &: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/components/recherche/recherche.component.spec.ts b/src/app/structure/components/recherche/recherche.component.spec.ts
deleted file mode 100644
index e38e4d4e8..000000000
--- a/src/app/structure/components/recherche/recherche.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { RechercheComponent } from './recherche.component';
-
-describe('RechercheComponent', () => {
-  let component: RechercheComponent;
-  let fixture: ComponentFixture<RechercheComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ RechercheComponent ]
-    })
-    .compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(RechercheComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure/components/recherche/recherche.component.ts
deleted file mode 100644
index 34881d906..000000000
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { Module } from '../../models/recherche.model';
-
-@Component({
-  selector: 'app-recherche',
-  templateUrl: './recherche.component.html',
-  styleUrls: ['./recherche.component.scss'],
-})
-export class RechercheComponent implements OnInit {
-  constructor() {}
-  //Variables btn filtres
-  modalType: string[] = ['services', 'accueil', 'plusFiltres'];
-
-  //Variable gestion liste modal
-  servicesCategories: Module[];
-  modaliteCategories: Module[];
-  modules: Module[];
-  filtresCategories: Module[];
-  modalOpened: string;
-
-  //Variable gestion Checkbox
-  checkedTab: string[];
-  filterCheck: string[];
-
-  ngOnInit(): void {
-    //Sert à afficher la modal et indiquer le type de filtre choisit
-    this.modalOpened = null;
-
-    //Sert à stocker les différentes catégories
-    this.servicesCategories = [];
-    this.modaliteCategories = [];
-    this.modules = [];
-    this.filtresCategories = [];
-
-    //Sert à gérer la checkbox multiple
-    this.checkedTab = new Array();
-    this.filterCheck = new Array();
-  }
-
-  //Ouvrir la modal et afficher la liste en fonction du btn de filtre appuyé
-  openModal(option: string) {
-    this.modules = [];
-    switch (option) {
-      case this.modalType[0]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[0]) {
-          this.modalOpened = this.modalType[0];
-          this.fakeDataServices();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
-      case this.modalType[1]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[1]) {
-          this.modalOpened = this.modalType[1];
-          this.fakeDataModalite();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
-      case this.modalType[2]:
-        //Vérifie si le btn n'est pas actif
-        if (this.modalOpened != this.modalType[2]) {
-          this.modalOpened = this.modalType[2];
-          this.fakeDataFiltres();
-        } else {
-          this.modalOpened = null;
-        }
-        break;
-    }
-    //Initialisation de la liste temporaire
-    this.checkedTab = this.filterCheck.slice();
-  }
-
-  //Envoie d'un tableau contenant tous les filtres
-  applyFilter() {
-    this.filterCheck = this.checkedTab.slice();
-    this.openModal(this.modalOpened);
-    console.log(this.filterCheck);
-  }
-
-  //Gestion de l'evenement checkbox(Cocher/Décocher)
-  onCheckboxChange(e, reset: boolean) {
-    //Condition btn effacer filtre d'une liste
-    if (!reset) {
-      if (e.target.checked) {
-        this.checkedTab.push(e.target.value);
-      } else {
-        //Vérifie si la case décochée est présente dans la liste temporaire et la supprime
-        if (this.checkedTab.indexOf(e.target.value) > -1) {
-          this.checkedTab.splice(this.checkedTab.indexOf(e.target.value), 1);
-        }
-      }
-    } else {
-      //Efface uniquement les éléments de la liste en cours
-      this.modules.forEach((m) => {
-        m.categories.forEach((categ) => {
-          if (this.checkedTab.indexOf(categ) > -1) this.checkedTab.splice(this.checkedTab.indexOf(categ), 1);
-        });
-      });
-    }
-  }
-
-  /**
-   * En attendant les apis
-   */
-  mockService(module: Module[], titre: string, categ: string, nbCateg: number) {
-    var m = new Module();
-    m.titre = titre;
-    m.categories = [];
-    for (var i = 0; i < nbCateg; i++) {
-      m.categories.push(categ + i);
-    }
-    module.push(m);
-  }
-  fakeDataServices() {
-    this.mockService(this.modules, 'Accompagnement aux démarches en ligne', 'CAF', 7);
-    this.mockService(this.modules, 'Insertion sociale et professionnelle', ' Diffuser son CV en ligne', 5);
-    this.mockService(
-      this.modules,
-      'Accès aux droits',
-      'Déclarer ses revenus en ligne et découvertes des services proposés',
-      8
-    );
-    this.mockService(this.modules, 'Aide à la parentalité/éducation', 'Découvrir l’univers des jeux vidéos', 4);
-    this.mockService(this.modules, 'Compétences de base', 'Faire un diagnostic des compétences', 8);
-    this.mockService(this.modules, 'Culture et sécurité numérique', 'Traitement de texte : découverte', 4);
-  }
-  fakeDataModalite() {
-    this.mockService(this.modules, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
-  }
-  fakeDataFiltres() {
-    this.mockService(this.modules, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
-    this.mockService(this.modules, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
-    this.mockService(this.modules, 'Publics', 'Langues étrangères autres qu’anglais', 12);
-    this.mockService(this.modules, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
-    this.mockService(this.modules, 'Type de structure', 'Espace de co-working', 6);
-  }
-}
diff --git a/src/app/structure/models/recherche.model.ts b/src/app/structure/models/recherche.model.ts
deleted file mode 100644
index a498b7318..000000000
--- a/src/app/structure/models/recherche.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export class Module {
-  titre: string;
-  categories: string[];
-  size: number;
-}
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
deleted file mode 100644
index 5617a7948..000000000
--- a/src/app/structure/models/structure.model.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-export class Structure {
-  numero: string;
-  date_de_creation: string;
-  derniere_modification: string;
-  nom_de_lusager: string;
-  votre_structure_est_elle: string;
-  nom_de_votre_structure: string;
-  type_de_structure: string;
-  description: string;
-  n: string;
-  voie: string;
-  telephone: string;
-  courriel: string;
-  site_web: string;
-  facebook: string;
-  twitter: string;
-  instagram: string;
-  civilite: string;
-  nom: string;
-  prenom: string;
-  email_contact: string;
-  fonction: string;
-  accessibilite_personnes_a_mobilite_reduite_pmr: boolean;
-  jaccompagne_les_usagers_dans_leurs_demarches_en_ligne: boolean;
-  accompagnement_des_demarches: string[];
-  wifi: boolean;
-  horaires: horaireStructure;
-  estOuvert: boolean;
-  ouvreLe: { jour: string; horaire: string };
-}
-
-export class horaireStructure {
-  lundi: Jour;
-  mardi: Jour;
-  mercredi: Jour;
-  jeudi: Jour;
-  vendredi: Jour;
-  samedi: Jour;
-  dimanche: Jour;
-}
-export class Jour {
-  open: boolean;
-  time: { openning: number; closing: number }[];
-}
diff --git a/src/app/structure/services/structure.service.spec.ts b/src/app/structure/services/structure.service.spec.ts
deleted file mode 100644
index 7c885d669..000000000
--- a/src/app/structure/services/structure.service.spec.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-import { HttpClient, HttpClientModule } from '@angular/common/http';
-import { inject, TestBed } from '@angular/core/testing';
-import { horaireStructure, Jour, Structure } from '../models/structure.model';
-import { StructureService } from './structure.service';
-const { DateTime } = require('luxon');
-
-describe('StructureService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      imports: [HttpClientModule],
-    });
-  });
-  let _structureService: StructureService;
-  beforeEach(inject([StructureService], (_s: StructureService) => {
-    _structureService = _s;
-  }));
-  it('should return an hour string', () => {
-    const result = _structureService.numberToHour(928);
-    expect(result).toBe('9h28');
-  });
-
-  it('should return a day string', () => {
-    const result = _structureService.numberToDay(1);
-    expect(result).toBe('lundi');
-  });
-  it('should return null', () => {
-    const result = _structureService.numberToDay(8);
-    expect(result).toBeNull();
-  });
-
-  it('Comparer Horaire : should return true', () => {
-    const result = _structureService.comparerHoraire(830, 1200, 900);
-    expect(result).toBeTrue();
-  });
-
-  it('Comparer Horaire : should return false', () => {
-    const result = _structureService.comparerHoraire(830, 1200, 800);
-    expect(result).toBeFalse();
-  });
-
-  it('Recuperer Horaire : should return an object (Jour)', () => {
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 800, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.mardi = new Jour();
-    s.horaires.mardi.open = true;
-    s.horaires.mardi.time = horaire;
-    const jour: Jour = new Jour();
-    jour.open = true;
-    jour.time = horaire;
-    const result = _structureService.recupererHoraire(s, 2);
-    expect(result).toEqual(jour);
-  });
-
-  it('Recuperer Horaire : should return undefined', () => {
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 800, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.lundi.open = true;
-    s.horaires.lundi.time = horaire;
-    const jour: Jour = new Jour();
-    jour.open = true;
-    jour.time = horaire;
-    const result = _structureService.recupererHoraire(s, 2);
-    expect(result).toBeUndefined();
-  });
-
-  it('Recuperer Horaire : should return null', () => {
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 800, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.mardi = new Jour();
-    s.horaires.mardi.open = true;
-    s.horaires.mardi.time = horaire;
-    const result = _structureService.recupererHoraire(s, 8);
-    expect(result).toBeNull();
-  });
-
-  it('Recuperer Prochaine Ouverture : should return an object ({Jour/Horaire})', () => {
-    //Init structure
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 805, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-    s.horaires.mardi.open = true;
-    s.horaires.mardi.time = horaire;
-
-    //Init sur vendredi à 14h00
-    const result = _structureService.recupererProchaineOuverture(s, 5, 5, 1400);
-    expect(result).toEqual({ jour: 'mardi', horaire: '8h05' });
-  });
-
-  it('Recuperer Prochaine Ouverture dans la journée : should return an object ({Jour/Horaire})', () => {
-    //Init structure
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 805, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-    s.horaires.mardi.open = true;
-    s.horaires.mardi.time = horaire;
-
-    //Init sur mardi à 12h06
-    const result = _structureService.recupererProchaineOuverture(s, 2, 2, 1206);
-    expect(result).toEqual({ jour: ' ', horaire: '14h00' });
-  });
-
-  it('Recuperer Prochaine Ouverture pour la semaine prochaine sur le même jour : should return an object ({Jour/Horaire})', () => {
-    //Init structure avec deux horaires le mardi
-    const s: Structure = new Structure();
-    var horaire = [
-      { openning: 805, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-    s.horaires.mardi.open = true;
-    s.horaires.mardi.time = horaire;
-
-    //Init sur mardi à 15h15
-    const result = _structureService.recupererProchaineOuverture(s, 2, 2, 1515);
-    expect(result).toEqual({ jour: 'mardi', horaire: '8h05' });
-  });
-
-  it('Recuperer Prochaine Ouverture : should return an error string', () => {
-    //Init structure avec aucun horaire
-    const s: Structure = new Structure();
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-
-    //Init sur jeudi à 12h06
-    const result = _structureService.recupererProchaineOuverture(s, 4, 2, 1206);
-    expect(result).toEqual('Aucun horaire disponible');
-  });
-
-  it('Mise à jour ouverture de la structure : should return true', () => {
-    var horaire = [
-      { openning: 805, closing: 1200 },
-      { openning: 1400, closing: 1600 },
-    ];
-    //Init structure avec aucun horaire
-    const s: Structure = new Structure();
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-
-    s.horaires.jeudi.open = true;
-    s.horaires.jeudi.time = horaire;
-
-    //Init date sur un jeudi à 9h05
-    var dt = new DateTime.local(2020, 10, 8, 9, 5);
-    const result = _structureService.majOuvertureStructure(s, dt);
-    expect(result.estOuvert).toEqual(true);
-  });
-
-  it('Mise à jour ouverture de la structure : should return false', () => {
-    var horaire = [{ openning: 1400, closing: 1600 }];
-    //Init structure avec aucun horaire
-    const s: Structure = new Structure();
-    s.horaires = new horaireStructure();
-    s.horaires.lundi = new Jour();
-    s.horaires.mardi = new Jour();
-    s.horaires.mercredi = new Jour();
-    s.horaires.jeudi = new Jour();
-    s.horaires.vendredi = new Jour();
-    s.horaires.samedi = new Jour();
-    s.horaires.dimanche = new Jour();
-
-    s.horaires.jeudi.open = true;
-    s.horaires.jeudi.time = horaire;
-
-    //Init date sur un jeudi à 9h05
-    var dt = new DateTime.local(2020, 10, 8, 9, 5);
-    const result = _structureService.majOuvertureStructure(s, dt);
-    expect(result.estOuvert).toEqual(false);
-  });
-});
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
deleted file mode 100644
index f18978024..000000000
--- a/src/app/structure/services/structure.service.ts
+++ /dev/null
@@ -1,163 +0,0 @@
-import { HttpClient } from '@angular/common/http';
-import { Injectable } from '@angular/core';
-import { Jour, Structure } from '../models/structure.model';
-
-@Injectable({
-  providedIn: 'root',
-})
-export class StructureService {
-  constructor(private http: HttpClient) {}
-
-  recupererStructures() {
-    return this.http.get('/api/Structures');
-  }
-
-  majOuvertureStructure(structure: Structure, dateActuelle: any) {
-    //Récupère le jour de la semaine.
-    var jourSemaine: number = dateActuelle.weekday;
-
-    //Vérifie si les minutes commencent par zéro pour éviter la suppression.
-    var now: number;
-    if (dateActuelle.minute.toString().length != 1) {
-      now = parseInt('' + dateActuelle.hour + dateActuelle.minute, 10);
-    } else {
-      now = parseInt('' + dateActuelle.hour + 0 + dateActuelle.minute, 10);
-    }
-
-    //Récupérer les horaires d'une structure en fonction de son jour pour indiquer si elle est ouverte.
-    var horaireStructure: Jour = this.recupererHoraire(structure, jourSemaine);
-    structure.estOuvert = false;
-    if (horaireStructure.open) {
-      horaireStructure.time.forEach((periode) => {
-        if (this.comparerHoraire(periode.openning, periode.closing, now)) {
-          structure.estOuvert = true;
-        }
-      });
-    }
-    structure.ouvreLe = this.recupererProchaineOuverture(structure, jourSemaine, jourSemaine, now);
-    return structure;
-  }
-
-  //Récupère les horaires d'une structure en fonction du jour de la semaine
-  recupererHoraire(structure: Structure, jourActuel: number) {
-    switch (jourActuel) {
-      case 1:
-        return structure.horaires.lundi;
-      case 2:
-        return structure.horaires.mardi;
-      case 3:
-        return structure.horaires.mercredi;
-      case 4:
-        return structure.horaires.jeudi;
-      case 5:
-        return structure.horaires.vendredi;
-      case 6:
-        return structure.horaires.samedi;
-      case 7:
-        return structure.horaires.dimanche;
-      default:
-        return null;
-    }
-  }
-  //Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
-  comparerHoraire(heureDeb: number, heureFin: number, heureActuelle: number) {
-    return heureActuelle >= heureDeb && heureActuelle <= heureFin;
-  }
-
-  recupererProchaineOuverture(s: Structure, j: number, baseJour: number, baseHeure: number) {
-    //Récupérer horaire du jour en cours
-    var horaires = this.recupererHoraire(s, j);
-    //Condition pour stopper la récursion (Si le jour du compteur est égal au jour en cours)
-    if (j + 1 != baseJour) {
-      if (horaires.open) {
-        //Vérifie si le compteur correspond au jour en cours pour éviter de proposer
-        //les horaires déjà passés.
-        if (j != baseJour) {
-          var jourOuverture = null;
-          horaires.time.every((periode) => {
-            if (periode.openning) {
-              jourOuverture = { jour: this.numberToDay(j), horaire: this.numberToHour(periode.openning) };
-              return false;
-            }
-            return true;
-          });
-          //Si pas de période trouvée, on réitère.
-          if (!jourOuverture) {
-            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
-          }
-          return jourOuverture;
-        } else {
-          var jourOuverture = null;
-          horaires.time.every((periode) => {
-            if (periode.openning >= baseHeure) {
-              jourOuverture = { jour: ' ', horaire: this.numberToHour(periode.openning) };
-              return false;
-            }
-            return true;
-          });
-          //Si pas de période trouvée, on réitère.
-          if (!jourOuverture) {
-            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
-          }
-          return jourOuverture;
-        }
-      } else {
-        //Si le jour n'est pas égal à Dimanche, on l'incrémente de 1.
-        if (j != 7) {
-          return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
-        }
-        //Si le jour est égal à Lundi, on le positionne sur 0 pour activer la condition d'arrêt.
-        if (baseJour == 1) {
-          return this.recupererProchaineOuverture(s, 0, baseJour, baseHeure);
-        }
-        //Si le jour est égal à Dimanche, on le positionne sur Lundi.
-        return this.recupererProchaineOuverture(s, 1, baseJour, baseHeure);
-      }
-    }
-    var lastChancehoraire = this.recupererHoraire(s, j + 1);
-    var lastJour: any;
-    if (lastChancehoraire.open) {
-      lastChancehoraire.time.every((periode) => {
-        if (periode.openning && periode.openning < baseHeure) {
-          lastJour = { jour: this.numberToDay(j + 1), horaire: this.numberToHour(periode.openning) };
-          return false;
-        }
-        lastJour = 'Aucun horaire disponible';
-      });
-    } else {
-      lastJour = 'Aucun horaire disponible';
-    }
-    return lastJour;
-  }
-
-  numberToDay(n: number) {
-    switch (n) {
-      case 1:
-        return 'lundi';
-      case 2:
-        return 'mardi';
-      case 3:
-        return 'mercredi';
-      case 4:
-        return 'jeudi';
-      case 5:
-        return 'vendredi';
-      case 6:
-        return 'samedi';
-      case 7:
-        return 'dimanche';
-      default:
-        return null;
-    }
-  }
-
-  numberToHour(n: number) {
-    if (n.toString().length == 3) {
-      var tabNum = n.toString().match(/.{1,1}/g);
-      return tabNum[0] + 'h' + tabNum[1] + tabNum[2];
-    } else if (n.toString().length == 4) {
-      var tabNum = n.toString().match(/.{1,2}/g);
-      return tabNum[0] + 'h' + tabNum[1];
-    }
-  }
-}
diff --git a/src/app/structure/structure.component.html b/src/app/structure/structure.component.html
deleted file mode 100644
index 86c8f6308..000000000
--- a/src/app/structure/structure.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div class="container">
-  <app-recherche></app-recherche>
-  <div class="divider"></div>
-  <app-card></app-card>
-</div>
diff --git a/src/app/structure/structure.component.scss b/src/app/structure/structure.component.scss
deleted file mode 100644
index 2d506b58d..000000000
--- a/src/app/structure/structure.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@import '../../assets/scss/color';
-
-.divider {
-  width: 100%;
-  height: 1px;
-  background-color: $grey-4;
-}
-//En attendant de l'intégrer avec la map
-.container {
-  width: 320px;
-}
diff --git a/src/app/structure/structure.component.spec.ts b/src/app/structure/structure.component.spec.ts
deleted file mode 100644
index 47da9d53d..000000000
--- a/src/app/structure/structure.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { StructureComponent } from './structure.component';
-
-describe('StructureComponent', () => {
-  let component: StructureComponent;
-  let fixture: ComponentFixture<StructureComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ StructureComponent ]
-    })
-    .compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(StructureComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/app/structure/structure.component.ts b/src/app/structure/structure.component.ts
deleted file mode 100644
index c74423ddc..000000000
--- a/src/app/structure/structure.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
-  selector: 'app-structure',
-  templateUrl: './structure.component.html',
-  styleUrls: ['./structure.component.scss']
-})
-export class StructureComponent implements OnInit {
-
-  constructor() { }
-
-  ngOnInit(): void {
-  }
-
-}
diff --git a/src/app/structure/structure.module.ts b/src/app/structure/structure.module.ts
deleted file mode 100644
index fdc77203d..000000000
--- a/src/app/structure/structure.module.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { StructureComponent } from './structure.component';
-import { CardComponent } from './components/card/card.component';
-import { RechercheComponent } from './components/recherche/recherche.component';
-import { HttpClientModule } from '@angular/common/http';
-import { FlexLayoutModule } from '@angular/flex-layout';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-
-@NgModule({
-  declarations: [StructureComponent, CardComponent, RechercheComponent],
-  imports: [CommonModule, HttpClientModule, FlexLayoutModule, ReactiveFormsModule],
-  exports: [StructureComponent],
-})
-export class StructureModule {}
-- 
GitLab


From bbe32831003a66a4fa9b58c344c9baa94616676d Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 19 Oct 2020 17:10:31 +0200
Subject: [PATCH 21/50] fix(search) : fix selector html

---
 src/app/structure-list/components/card/card.component.ts | 2 +-
 .../components/search/search.component.scss              | 9 ---------
 .../structure-list/components/search/search.component.ts | 2 +-
 src/app/structure-list/structure-list.component.html     | 4 ++--
 4 files changed, 4 insertions(+), 13 deletions(-)

diff --git a/src/app/structure-list/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
index a54d92069..dc782ec45 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -5,7 +5,7 @@ import { StructureService } from '../../services/structure-list.service';
 const { DateTime } = require('luxon');
 
 @Component({
-  selector: 'app-card',
+  selector: 'app-structure-list-card',
   templateUrl: './card.component.html',
   styleUrls: ['./card.component.scss'],
 })
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index cbe065b6c..4a8926c2f 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -1,7 +1,6 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
 @import '../../../../assets/scss/typography';
-@import '../../../../assets/scss/breakpoint';
 
 .header {
   .title {
@@ -238,11 +237,3 @@
     }
   }
 }
-/*@media #{$phone} {
-  .allSection {
-    display: none !important;
-  }
-  .phoneSection {
-    display: flex;
-  }
-}*/
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 86550580e..30c27b5f7 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -5,7 +5,7 @@ import { Module } from '../../models/module.model';
 import { SearchService } from '../../services/search.service';
 
 @Component({
-  selector: 'app-search',
+  selector: 'app-structure-list-search',
   templateUrl: './search.component.html',
   styleUrls: ['./search.component.scss'],
 })
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index 38562830e..d9375a386 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,5 +1,5 @@
 <div class="container">
-  <app-search (searchEvent)="fetchResults($event)"></app-search>
+  <app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
   <div class="divider"></div>
-  <app-card [filter]="currentFilter"></app-card>
+  <app-structure-list-card [filter]="currentFilter"></app-structure-list-card>
 </div>
-- 
GitLab


From 908281b7ff6ad231b15ece95b361806faa45c67d Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 09:28:42 +0200
Subject: [PATCH 22/50] fix(search) : fix multiple filter checkbox

---
 api/server.js                                 | 30 +++++++++++++++++++
 .../components/search/search.component.html   |  2 +-
 .../components/search/search.component.ts     | 15 +++++++---
 .../structure-list/models/category.model.ts   |  4 +++
 src/app/structure-list/models/module.model.ts |  1 +
 .../structure-list/services/search.service.ts | 20 +++++++++++--
 .../services/structure-list.service.ts        | 12 ++++++--
 7 files changed, 75 insertions(+), 9 deletions(-)
 create mode 100644 api/server.js

diff --git a/api/server.js b/api/server.js
new file mode 100644
index 000000000..0bcb25ead
--- /dev/null
+++ b/api/server.js
@@ -0,0 +1,30 @@
+const jsonServer = require('json-server');
+const server = jsonServer.create();
+const router = jsonServer.router('db.json');
+const middlewares = jsonServer.defaults();
+
+// Set default middlewares (logger, static, cors and no-cache)
+server.use(middlewares);
+
+// Add custom routes before JSON Server router
+server.get('/structures/count', (req, res) => {
+  let structureCountTab = [];
+  structureCountTab.push({ id: 260, count: 3 });
+  structureCountTab.push({ id: 260, count: 3 });
+  structureCountTab.push({ id: 259, count: 3 });
+  structureCountTab.push({ id: 261, count: 3 });
+  structureCountTab.push({ id: 249, count: 3 });
+  structureCountTab.push({ id: 222, count: 2 });
+  structureCountTab.push({ id: 212, count: 3 });
+  structureCountTab.push({ id: 186, count: 2 });
+  structureCountTab.push({ id: 183, count: 2 });
+  return res.status(200).jsonp({
+    structureCountTab,
+  });
+});
+
+// Use default router
+server.use(router);
+server.listen(3000, () => {
+  console.log('JSON Server is running');
+});
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 8236e0fcd..df0c51915 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -65,7 +65,7 @@
                 <div class="label">{{ module.text }}</div>
               </div>
             </li>
-            <span class="nbResult">34</span>
+            <span class="nbResult">{{ module.count ? module.count : '0' }}</span>
           </div>
         </ul>
       </div>
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 30c27b5f7..259d6e208 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -77,6 +77,8 @@ export class SearchComponent implements OnInit {
   // Management of the checkbox event (Check / Uncheck)
   public onCheckboxChange(event, categ: string): void {
     const checkValue: number = parseInt(event.target.value);
+    console.log(checkValue);
+
     if (event.target.checked) {
       this.checkedModules.push(new Module(checkValue, categ));
     } else {
@@ -131,10 +133,15 @@ export class SearchComponent implements OnInit {
     if (option === this.modalType[0]) {
       this.mockService(this.categories, 'Accompagnement des démarches', { name: 'CAF', id: '' }, 7);
     } else if (option === this.modalType[1]) {
-      this.searchService.getCategories().subscribe((d) => {
-        d.forEach((element) => {
-          this.categories.push(element);
-        });
+      this.searchService.getCategories().subscribe((categories: Category[]) => {
+        this.searchService
+          .getFakeCounterModule()
+          .subscribe((res: { structureCountTab: { id: number; count: number }[] }) => {
+            categories.forEach((category) => {
+              category = this.searchService.setCountModules(category, res.structureCountTab);
+              this.categories.push(category);
+            });
+          });
       });
     } else if (option === this.modalType[2]) {
       this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts
index f6c60e54e..cb5a96eee 100644
--- a/src/app/structure-list/models/category.model.ts
+++ b/src/app/structure-list/models/category.model.ts
@@ -3,4 +3,8 @@ import { Module } from './module.model';
 export class Category {
   name: string;
   modules: Module[];
+
+  constructor(obj?: any) {
+    Object.assign(this, obj);
+  }
 }
diff --git a/src/app/structure-list/models/module.model.ts b/src/app/structure-list/models/module.model.ts
index 83d025356..340c04092 100644
--- a/src/app/structure-list/models/module.model.ts
+++ b/src/app/structure-list/models/module.model.ts
@@ -1,6 +1,7 @@
 export class Module {
   id: number;
   text: string;
+  count: number;
 
   constructor(id: number, text: string) {
     this.id = id;
diff --git a/src/app/structure-list/services/search.service.ts b/src/app/structure-list/services/search.service.ts
index d48c602e1..4ae64b197 100644
--- a/src/app/structure-list/services/search.service.ts
+++ b/src/app/structure-list/services/search.service.ts
@@ -1,6 +1,9 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Category } from '../models/category.model';
+import { Module } from '../models/module.model';
 
 @Injectable({
   providedIn: 'root',
@@ -8,7 +11,20 @@ import { Observable } from 'rxjs';
 export class SearchService {
   constructor(private http: HttpClient) {}
 
-  public getCategories(): Observable<any> {
-    return this.http.get('/api/Categories');
+  public getCategories(): Observable<Category[]> {
+    return this.http.get('/api/Categories').pipe(map((data: any[]) => data.map((item) => new Category(item))));
+  }
+  public getFakeCounterModule(): Observable<any> {
+    return this.http.get('http://localhost:3000/structures/count');
+  }
+  public setCountModules(category: Category, structureCountTab: { id: number; count: number }[]): Category {
+    category.modules.forEach((m: Module) => {
+      for (let i = 0; i < structureCountTab.length; i++) {
+        if (structureCountTab[i].id === m.id) {
+          m.count = structureCountTab[i].count;
+        }
+      }
+    });
+    return category;
   }
 }
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 0a1d1e34a..2b9f77512 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -32,9 +32,17 @@ export class StructureService {
           api = api + '&';
         }
         if (filter.isStrict) {
-          api = api + filter.name + '=' + filter.value;
+          if (api.includes(filter.name)) {
+            api = api + '=' + filter.value;
+          } else {
+            api = api + filter.name + '=' + filter.value;
+          }
         } else {
-          api = api + filter.name + '_like=' + filter.value;
+          if (api.includes(filter.name)) {
+            api = api + filter.value;
+          } else {
+            api = api + filter.name + '_like=' + filter.value;
+          }
         }
       });
     }
-- 
GitLab


From fae81e5cdf6d1f803106223e8dd3ddd939fb5b72 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 09:40:45 +0200
Subject: [PATCH 23/50] fix(search) : add data counter

---
 api/server.js | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/api/server.js b/api/server.js
index 0bcb25ead..08ca86cb0 100644
--- a/api/server.js
+++ b/api/server.js
@@ -9,6 +9,7 @@ server.use(middlewares);
 // Add custom routes before JSON Server router
 server.get('/structures/count', (req, res) => {
   let structureCountTab = [];
+  // Compétences de base
   structureCountTab.push({ id: 260, count: 3 });
   structureCountTab.push({ id: 260, count: 3 });
   structureCountTab.push({ id: 259, count: 3 });
@@ -18,6 +19,45 @@ server.get('/structures/count', (req, res) => {
   structureCountTab.push({ id: 212, count: 3 });
   structureCountTab.push({ id: 186, count: 2 });
   structureCountTab.push({ id: 183, count: 2 });
+  // Accès aux droits
+  structureCountTab.push({ id: 176, count: 2 });
+  structureCountTab.push({ id: 175, count: 1 });
+  structureCountTab.push({ id: 174, count: 1 });
+  structureCountTab.push({ id: 173, count: 1 });
+  structureCountTab.push({ id: 172, count: 1 });
+  structureCountTab.push({ id: 171, count: 1 });
+  structureCountTab.push({ id: 167, count: 1 });
+  structureCountTab.push({ id: 165, count: 1 });
+  // Insertion sociale et professionnelle
+  structureCountTab.push({ id: 254, count: 2 });
+  structureCountTab.push({ id: 240, count: 2 });
+  structureCountTab.push({ id: 194, count: 3 });
+  structureCountTab.push({ id: 193, count: 3 });
+  structureCountTab.push({ id: 192, count: 3 });
+  structureCountTab.push({ id: 191, count: 3 });
+  structureCountTab.push({ id: 262, count: 3 });
+  structureCountTab.push({ id: 263, count: 2 });
+  structureCountTab.push({ id: 3, count: 2 });
+  // Aide à la parentalité
+  structureCountTab.push({ id: 257, count: 2 });
+  structureCountTab.push({ id: 238, count: 2 });
+  structureCountTab.push({ id: 178, count: 1 });
+  structureCountTab.push({ id: 166, count: 1 });
+  // Culture et sécurité numérique
+  structureCountTab.push({ id: 264, count: 2 });
+  structureCountTab.push({ id: 255, count: 2 });
+  structureCountTab.push({ id: 265, count: 2 });
+  structureCountTab.push({ id: 232, count: 2 });
+  structureCountTab.push({ id: 225, count: 2 });
+  structureCountTab.push({ id: 221, count: 2 });
+  structureCountTab.push({ id: 218, count: 1 });
+  structureCountTab.push({ id: 209, count: 1 });
+  structureCountTab.push({ id: 208, count: 1 });
+  structureCountTab.push({ id: 206, count: 2 });
+  structureCountTab.push({ id: 195, count: 1 });
+  structureCountTab.push({ id: 164, count: 1 });
+  structureCountTab.push({ id: 163, count: 1 });
+  structureCountTab.push({ id: 162, count: 2 });
   return res.status(200).jsonp({
     structureCountTab,
   });
-- 
GitLab


From 465f7da090442cd554a29110fb568cc571376c69 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 11:41:04 +0200
Subject: [PATCH 24/50] fix(search) : fix design

---
 src/app/home/home.component.html              |  4 +-
 .../components/card/card.component.html       | 42 +++++++-------
 .../components/search/search.component.html   | 58 ++++++++++---------
 .../components/search/search.component.scss   | 40 ++++++++-----
 .../components/search/search.component.ts     |  5 +-
 .../structure-list.component.html             |  8 ++-
 .../structure-list.component.scss             |  5 +-
 src/assets/scss/_color.scss                   |  1 +
 src/assets/scss/_typography.scss              |  2 +-
 9 files changed, 91 insertions(+), 74 deletions(-)

diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html
index 22f5aeb0f..9b962fa14 100644
--- a/src/app/home/home.component.html
+++ b/src/app/home/home.component.html
@@ -1,5 +1,3 @@
 <div class="content-container">
-  <div class="section-container">
-    <app-structure-list></app-structure-list>
-  </div>
+  <app-structure-list></app-structure-list>
 </div>
diff --git a/src/app/structure-list/components/card/card.component.html b/src/app/structure-list/components/card/card.component.html
index 490d59af8..7afed396a 100644
--- a/src/app/structure-list/components/card/card.component.html
+++ b/src/app/structure-list/components/card/card.component.html
@@ -1,25 +1,27 @@
 <span class="nbStructuresLabel">{{ structures.length }} structures</span>
-<div class="structure" fxLayout="column" *ngFor="let structure of structures">
-  <span class="nomStructure">{{ structure.nom }}</span>
+<div class="listStructure">
+  <div class="structure" fxLayout="column" *ngFor="let structure of structures">
+    <span class="nomStructure">{{ structure.nom }}</span>
 
-  <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
-    <span class="typeStructure">{{ structure.typeDeStructure }}</span>
-    <span class="distanceStructure">├─┤ 63 m</span>
-  </div>
-  <br />
-  <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center">
-    <div *ngIf="structure.isOpen; else closed">
-      <span class="ico-dot-available"></span>
-      <span>Ouvert actuellement</span>
+    <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
+      <span class="typeStructure">{{ structure.typeDeStructure }}</span>
+      <span class="distanceStructure">├─┤ 63 m</span>
+    </div>
+    <br />
+    <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center">
+      <div *ngIf="structure.isOpen; else closed">
+        <span class="ico-dot-available"></span>
+        <span>Ouvert actuellement</span>
+      </div>
+      <ng-template #closed>
+        <span class="ico-dot-unavailable"></span>
+        <span *ngIf="structure.openedOn.day; else noTime">
+          Fermé - Ouvre {{ structure.openedOn.day }} à {{ structure.openedOn.schedule }}</span
+        >
+      </ng-template>
+      <ng-template #noTime>
+        <span> Fermé - Aucun horaire disponible</span>
+      </ng-template>
     </div>
-    <ng-template #closed>
-      <span class="ico-dot-unavailable"></span>
-      <span *ngIf="structure.openedOn.day; else noTime">
-        Fermé - Ouvre {{ structure.openedOn.day }} à {{ structure.openedOn.schedule }}</span
-      >
-    </ng-template>
-    <ng-template #noTime>
-      <span> Fermé - Aucun horaire disponible</span>
-    </ng-template>
   </div>
 </div>
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index df0c51915..730c6b49d 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -10,32 +10,36 @@
     <button type="button" (click)="applyFilter()">Rechercher</button>
   </div>
 
-  <div class="btnSection">
-    <div class="phoneSection" fxLayout="row" fxLayoutAlign="center center">
-      <button
-        type="button"
-        [className]="modalTypeOpened === modalType[0] ? 'selected' : ''"
-        (click)="openModal(this.modalType[0])"
-      >
-        <span class="btnText">Accompagnement</span>
-        <div class="arrow"></div>
-      </button>
-      <button
-        type="button"
-        [className]="modalTypeOpened === modalType[1] ? 'selected' : ''"
-        (click)="openModal(this.modalType[1])"
-      >
-        <span class="btnText">Formations</span>
-        <div class="arrow"></div>
-      </button>
-      <button
-        type="button"
-        [className]="modalTypeOpened === modalType[2] ? 'selected' : ''"
-        (click)="openModal(this.modalType[2])"
-      >
-        <span class="btnText">Plus de filtres</span>
-        <div class="arrow"></div>
-      </button>
+  <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
+    <div
+      class="button"
+      [ngClass]="{ selected: modalTypeOpened === modalType[0] }"
+      (click)="openModal(this.modalType[0])"
+      fxLayout="row"
+      fxLayoutAlign="space-between center"
+    >
+      <span class="btnText">Accompagnement</span>
+      <div class="arrow"></div>
+    </div>
+    <div
+      class="button"
+      [ngClass]="{ selected: modalTypeOpened === modalType[1] }"
+      (click)="openModal(this.modalType[1])"
+      fxLayout="row"
+      fxLayoutAlign="space-between center"
+    >
+      <span class="btnText">Formations</span>
+      <div class="arrow"></div>
+    </div>
+    <div
+      class="button"
+      [ngClass]="{ selected: modalTypeOpened === modalType[2] }"
+      (click)="openModal(this.modalType[2])"
+      fxLayout="row"
+      fxLayoutAlign="space-between center"
+    >
+      <span class="btnText">Plus de filtres</span>
+      <div class="arrow"></div>
     </div>
   </div>
   <div
@@ -76,7 +80,7 @@
     </div>
   </div>
 </div>
-<div class="footer" fxLayout="row" fxLayoutAlign="space-between center">
+<div class="footerSearchSection" fxLayout="row" fxLayoutAlign="space-between center">
   <div class="checkbox">
     <div class="checkboxItem">
       <label>
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 4a8926c2f..b6196462f 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -21,7 +21,7 @@
   }
   input {
     width: 100%;
-    background-color: $grey-4;
+    background-color: $grey-5;
     border: none;
     @include cn-regular-14;
     display: flex;
@@ -45,11 +45,10 @@
     }
   }
   .btnSection {
-    padding: 16px 0 16px 0;
-    .phoneSection {
-      display: none;
-    }
-    button {
+    padding: 16px 0 8px 0;
+    .button {
+      height: 40px;
+      width: 190px;
       outline: none;
       border: 1px solid $grey;
       border-radius: 33px;
@@ -89,27 +88,29 @@
     }
   }
 }
-.modalaccueil {
-  margin-left: 100px;
+.modalformations {
+  margin-left: 206px;
 }
 .modalplusFiltres {
-  margin-left: 196px;
+  margin-left: 412px;
 }
 .modal {
-  max-height: 654px;
-  max-width: 754px;
+  -moz-box-shadow: -5px 5px 10px 0px $grey;
+  box-shadow: -5px 5px 10px 0px $grey;
+  max-height: 648px;
+  width: 754px;
   background: $white;
   border: 1px solid $grey;
   box-sizing: border-box;
   z-index: 1;
   position: absolute;
-  margin-top: 80px;
+  margin-top: 96px;
 
   ::-webkit-scrollbar {
     width: 10px;
   }
   ::-webkit-scrollbar-track {
-    background: $grey-4;
+    background: $grey-5;
   }
   ::-webkit-scrollbar-thumb {
     background: $grey;
@@ -159,7 +160,6 @@
       @include cn-bold-14;
       display: flex;
       align-items: center;
-      text-decoration-line: underline;
     }
     height: 32px;
     button {
@@ -203,7 +203,6 @@
   .label {
     padding-left: 8px;
     @include cn-regular-14;
-    padding: 0 16px 0 16px;
   }
   .customCheck {
     display: inline-grid;
@@ -217,7 +216,7 @@
     top: 0;
     left: 0;
     &:hover {
-      background-color: $grey-4;
+      background-color: $grey-5;
     }
     &:after {
       content: '';
@@ -237,3 +236,12 @@
     }
   }
 }
+.footerSearchSection {
+  margin-bottom: 30px;
+  margin-right: 20px;
+
+  a {
+    @include cn-bold-14;
+    font-weight: bold;
+  }
+}
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 259d6e208..8ce476264 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -18,7 +18,7 @@ export class SearchComponent implements OnInit {
   searchTerm: string = '';
 
   // Button variable
-  modalType: string[] = ['services', 'modalite', 'plusFiltres'];
+  modalType: string[] = ['accompagnement', 'formations', 'plusFiltres'];
 
   // Modal variable
   categories: Category[];
@@ -77,8 +77,6 @@ export class SearchComponent implements OnInit {
   // Management of the checkbox event (Check / Uncheck)
   public onCheckboxChange(event, categ: string): void {
     const checkValue: number = parseInt(event.target.value);
-    console.log(checkValue);
-
     if (event.target.checked) {
       this.checkedModules.push(new Module(checkValue, categ));
     } else {
@@ -117,6 +115,7 @@ export class SearchComponent implements OnInit {
       .replace(/[\s-]/g, ' ')
       .replace('?', '');
   }
+
   // Fake service api
   private mockService(module: Category[], titre: string, categ: any, nbCateg: number): void {
     let m = new Category();
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index d9375a386..84d1d39ee 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,5 +1,7 @@
 <div class="container">
-  <app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
-  <div class="divider"></div>
-  <app-structure-list-card [filter]="currentFilter"></app-structure-list-card>
+  <div class="content">
+    <app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
+    <div class="divider"></div>
+    <app-structure-list-card [filter]="currentFilter"></app-structure-list-card>
+  </div>
 </div>
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
index 2d506b58d..fa639184d 100644
--- a/src/app/structure-list/structure-list.component.scss
+++ b/src/app/structure-list/structure-list.component.scss
@@ -7,5 +7,8 @@
 }
 //En attendant de l'intégrer avec la map
 .container {
-  width: 320px;
+  width: 640px;
+  .content {
+    padding: 0 20px 0 20px;
+  }
 }
diff --git a/src/assets/scss/_color.scss b/src/assets/scss/_color.scss
index 2a650bee2..319c1008e 100644
--- a/src/assets/scss/_color.scss
+++ b/src/assets/scss/_color.scss
@@ -7,6 +7,7 @@ $grey-1: #333333;
 $grey-2: #eeeeee;
 $grey-3: #c3c3c3;
 $grey-4: #f2ecf2;
+$grey-5: #f2f2f2;
 /* YELLOW */
 $yellow: #f2cb04;
 $yellow-light: #fff8d6;
diff --git a/src/assets/scss/_typography.scss b/src/assets/scss/_typography.scss
index d21536e48..0fd92b3fc 100644
--- a/src/assets/scss/_typography.scss
+++ b/src/assets/scss/_typography.scss
@@ -1,4 +1,4 @@
-$text-font: 'Courier New', 'Helvetica', sans-serif;
+$text-font: 'Trebuchet MS';
 $footer-text-font: 'Arial', 'Helvetica', sans-serif;
 $title-font: 'Courier New', 'Helvetica', sans-serif;
 
-- 
GitLab


From bb2610f1965490ae2a0500431c384dcc7ed2bcf2 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 13:48:47 +0200
Subject: [PATCH 25/50] fix(search) : fix modal responsive

---
 .../components/search/search.component.scss      | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index b6196462f..a8e53de50 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -1,6 +1,7 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
 @import '../../../../assets/scss/typography';
+@import '../../../../assets/scss/breakpoint';
 
 .header {
   .title {
@@ -89,16 +90,24 @@
   }
 }
 .modalformations {
+  @media #{$desktop} {
+    margin-left: 0;
+  }
+
   margin-left: 206px;
 }
 .modalplusFiltres {
+  @media #{$desktop} {
+    margin-left: 0;
+  }
   margin-left: 412px;
 }
 .modal {
   -moz-box-shadow: -5px 5px 10px 0px $grey;
   box-shadow: -5px 5px 10px 0px $grey;
   max-height: 648px;
-  width: 754px;
+  max-width: 754px;
+  width: 94%;
   background: $white;
   border: 1px solid $grey;
   box-sizing: border-box;
@@ -137,6 +146,11 @@
       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;
-- 
GitLab


From 1ea159c97c5d118b0d7ac69e035d0f87437ef265 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 13:52:37 +0200
Subject: [PATCH 26/50] fix(search) : change div to btn

---
 .../components/search/search.component.html    | 18 +++++++++---------
 .../components/search/search.component.scss    |  2 +-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 730c6b49d..7df7b8806 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -11,8 +11,8 @@
   </div>
 
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
-    <div
-      class="button"
+    <button
+      type="button"
       [ngClass]="{ selected: modalTypeOpened === modalType[0] }"
       (click)="openModal(this.modalType[0])"
       fxLayout="row"
@@ -20,9 +20,9 @@
     >
       <span class="btnText">Accompagnement</span>
       <div class="arrow"></div>
-    </div>
-    <div
-      class="button"
+    </button>
+    <button
+      type="button"
       [ngClass]="{ selected: modalTypeOpened === modalType[1] }"
       (click)="openModal(this.modalType[1])"
       fxLayout="row"
@@ -30,9 +30,9 @@
     >
       <span class="btnText">Formations</span>
       <div class="arrow"></div>
-    </div>
-    <div
-      class="button"
+    </button>
+    <button
+      type="button"
       [ngClass]="{ selected: modalTypeOpened === modalType[2] }"
       (click)="openModal(this.modalType[2])"
       fxLayout="row"
@@ -40,7 +40,7 @@
     >
       <span class="btnText">Plus de filtres</span>
       <div class="arrow"></div>
-    </div>
+    </button>
   </div>
   <div
     *ngIf="modalTypeOpened"
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index a8e53de50..76dc8311b 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -47,7 +47,7 @@
   }
   .btnSection {
     padding: 16px 0 8px 0;
-    .button {
+    button {
       height: 40px;
       width: 190px;
       outline: none;
-- 
GitLab


From 8aaf7497318ff2b0065c448da3989d053e145940 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 16:44:18 +0200
Subject: [PATCH 27/50] fix(search) : fix label checkbox + fake data

---
 .../components/search/search.component.html   |  4 +--
 .../components/search/search.component.scss   | 10 +++++--
 .../components/search/search.component.ts     | 26 ++++++++++++-------
 3 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 7df7b8806..709182b53 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -65,8 +65,8 @@
                     (change)="onCheckboxChange($event, c.name)"
                   />
                   <span class="customCheck"></span>
+                  <div class="label">{{ module.text }}</div>
                 </label>
-                <div class="label">{{ module.text }}</div>
               </div>
             </li>
             <span class="nbResult">{{ module.count ? module.count : '0' }}</span>
@@ -86,8 +86,8 @@
       <label>
         <input type="checkbox" />
         <span class="customCheck"></span>
+        <div class="label">Pass numérique</div>
       </label>
-      <div class="label">Pass numérique</div>
     </div>
   </div>
   <a href="">Ajouter une structure</a>
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 76dc8311b..160f8dffe 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -174,6 +174,7 @@
       @include cn-bold-14;
       display: flex;
       align-items: center;
+      text-decoration: underline;
     }
     height: 32px;
     button {
@@ -193,11 +194,11 @@
 }
 .checkbox {
   .checkboxItem {
-    position: relative;
+    /*position: relative;
     display: inline-grid;
     align-items: center;
     grid-template-columns: min-content auto;
-    min-height: 25px;
+    min-height: 25px;*/
   }
   list-style-type: none;
   input {
@@ -212,7 +213,11 @@
     }
   }
   label {
+    //display: inline-grid;
+    align-items: center;
+    grid-template-columns: min-content auto;
     display: inline-grid;
+    cursor: pointer;
   }
   .label {
     padding-left: 8px;
@@ -257,5 +262,6 @@
   a {
     @include cn-bold-14;
     font-weight: bold;
+    text-decoration: underline;
   }
 }
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 8ce476264..2bc7ad008 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -89,6 +89,9 @@ export class SearchComponent implements OnInit {
 
   // Return index of a specific module in array modules
   public getIndex(id: number, categ: string): number {
+    console.log(this.checkedModules);
+    console.log(id);
+    console.log(categ);
     return this.checkedModules.findIndex((m: Module) => m.id === id && m.text === categ);
   }
 
@@ -122,7 +125,7 @@ export class SearchComponent implements OnInit {
     m.name = titre;
     m.modules = [];
     for (let i = 0; i < nbCateg; i++) {
-      m.modules.push(new Module(categ.id, categ.name + i));
+      m.modules.push(new Module(categ.id + i, categ.name + i));
     }
     module.push(m);
   }
@@ -130,7 +133,7 @@ export class SearchComponent implements OnInit {
   // Fake data
   private fakeData(option: string): void {
     if (option === this.modalType[0]) {
-      this.mockService(this.categories, 'Accompagnement des démarches', { name: 'CAF', id: '' }, 7);
+      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
@@ -143,13 +146,18 @@ export class SearchComponent implements OnInit {
           });
       });
     } else if (option === this.modalType[2]) {
-      this.mockService(this.categories, 'Équipements', 'Accès à des revues ou livres infoirmatiques numériques', 8);
-      this.mockService(this.categories, "Modalité d'accueil", 'Matériel mis à dispostion', 6);
-
-      this.mockService(this.categories, "Type d'acteurs", 'Lieux de médiation (Pimms, assos...)', 5);
-      this.mockService(this.categories, 'Publics', 'Langues étrangères autres qu’anglais', 12);
-      this.mockService(this.categories, 'Labelisation', 'Prescripteur du Pass Numérique', 6);
-      this.mockService(this.categories, 'Type de structure', 'Espace de co-working', 6);
+      this.mockService(
+        this.categories,
+        'Équipements',
+        { name: 'Accès à des revues ou livres infoirmatiques numériques', id: 1 },
+        8
+      );
+      this.mockService(this.categories, "Modalité d'accueil", { name: 'Matériel mis à dispostion', id: 2 }, 6);
+
+      this.mockService(this.categories, "Type d'acteurs", { name: 'Lieux de médiation (Pimms, assos...)', id: 3 }, 5);
+      this.mockService(this.categories, 'Publics', { name: 'Langues étrangères autres qu’anglais', id: 4 }, 12);
+      this.mockService(this.categories, 'Labelisation', { name: 'Prescripteur du Pass Numérique', id: 5 }, 6);
+      this.mockService(this.categories, 'Type de structure', { name: 'Espace de co-working', id: 6 }, 6);
     }
   }
 }
-- 
GitLab


From 5f1db7c6b99d0343e5f726eda3e5518b4d6a6033 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Tue, 20 Oct 2020 17:38:22 +0200
Subject: [PATCH 28/50] fix(search) : fix submit search when press enter key

---
 .../components/search/search.component.html   | 21 ++++++++++++------
 .../components/search/search.component.ts     | 22 ++++++++++---------
 .../structure-list/structure-list.module.ts   |  4 ++--
 3 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 709182b53..8f8826d2e 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -2,12 +2,19 @@
   <span class="title">Acteurs de la médiation</span>
 </div>
 <div class="content" fxLayout="column">
-  <div class="searchSection" fxLayout="row" fxLayoutGap="1.5vw">
-    <div class="icon">
-      <div class="ico-pin-search grey"></div>
-    </div>
-    <input type="text" [(ngModel)]="searchTerm" placeholder="Rechercher une adresse, une association..." />
-    <button type="button" (click)="applyFilter()">Rechercher</button>
+  <div class="searchSection">
+    <form
+      [formGroup]="searchForm"
+      fxLayout="row"
+      fxLayoutGap="1.5vw"
+      (ngSubmit)="applyFilter(searchForm.value.searchTerm)"
+    >
+      <div class="icon">
+        <div class="ico-pin-search grey"></div>
+      </div>
+      <input type="text" formControlName="searchTerm" placeholder="Rechercher une adresse, une association..." />
+      <button type="submit">Rechercher</button>
+    </form>
   </div>
 
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
@@ -76,7 +83,7 @@
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
       <a (click)="clearFilters()">Effacer</a>
-      <button type="button" (click)="applyFilter(modalTypeOpened)">Appliquer</button>
+      <button type="button" (click)="applyFilter(searchForm.value.searchTerm)">Appliquer</button>
     </div>
   </div>
 </div>
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 2bc7ad008..a2c205d20 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -1,4 +1,6 @@
 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';
 import { Module } from '../../models/module.model';
@@ -10,12 +12,16 @@ import { SearchService } from '../../services/search.service';
   styleUrls: ['./search.component.scss'],
 })
 export class SearchComponent implements OnInit {
-  constructor(private searchService: SearchService) {}
+  constructor(private searchService: SearchService, private fb: FormBuilder) {
+    this.searchForm = this.fb.group({
+      searchTerm: '',
+    });
+  }
 
   @Output() searchEvent = new EventEmitter();
 
-  // Search input variable
-  searchTerm: string = '';
+  // Form search input
+  searchForm: FormGroup;
 
   // Button variable
   modalType: string[] = ['accompagnement', 'formations', 'plusFiltres'];
@@ -57,14 +63,13 @@ export class SearchComponent implements OnInit {
   }
 
   // Sends an array containing all filters
-  public applyFilter(): void {
+  public applyFilter(term: string): void {
     this.checkedModulesFilter = this.checkedModules.slice();
     this.openModal(this.modalTypeOpened);
-
     // Send search input filter
     let filters: Filter[] = [];
-    if (this.searchTerm) {
-      filters.push(new Filter('nom', this.searchTerm, false));
+    if (term) {
+      filters.push(new Filter('nom', term, false));
     }
 
     // Send checked box filter
@@ -89,9 +94,6 @@ export class SearchComponent implements OnInit {
 
   // Return index of a specific module in array modules
   public getIndex(id: number, categ: string): number {
-    console.log(this.checkedModules);
-    console.log(id);
-    console.log(categ);
     return this.checkedModules.findIndex((m: Module) => m.id === id && m.text === categ);
   }
 
diff --git a/src/app/structure-list/structure-list.module.ts b/src/app/structure-list/structure-list.module.ts
index 9947bca5b..eac1b0ac0 100644
--- a/src/app/structure-list/structure-list.module.ts
+++ b/src/app/structure-list/structure-list.module.ts
@@ -5,11 +5,11 @@ import { CardComponent } from './components/card/card.component';
 import { SearchComponent } from './components/search/search.component';
 import { HttpClientModule } from '@angular/common/http';
 import { FlexLayoutModule } from '@angular/flex-layout';
-import { FormsModule } from '@angular/forms';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 @NgModule({
   declarations: [StructureListComponent, CardComponent, SearchComponent],
-  imports: [CommonModule, HttpClientModule, FlexLayoutModule, FormsModule],
+  imports: [CommonModule, HttpClientModule, FlexLayoutModule, FormsModule, ReactiveFormsModule],
   exports: [StructureListComponent],
 })
 export class StructureListModule {}
-- 
GitLab


From 49defde1d759b866cd5ddff5507e43cef6f200c7 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 21 Oct 2020 10:59:40 +0200
Subject: [PATCH 29/50] fix(search) : add some test + fix design modal

---
 debug.log                                     |  1 +
 .../components/search/search.component.html   | 61 +++++++++++--------
 .../components/search/search.component.scss   | 16 +++--
 .../search/search.component.spec.ts           | 28 ++++++++-
 .../services/search.service.spec.ts           |  6 +-
 .../services/structure-list.service.spec.ts   | 12 ++--
 6 files changed, 83 insertions(+), 41 deletions(-)
 create mode 100644 debug.log

diff --git a/debug.log b/debug.log
new file mode 100644
index 000000000..e4874e229
--- /dev/null
+++ b/debug.log
@@ -0,0 +1 @@
+[1021/094448.838:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 8f8826d2e..f59c9ba93 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -55,35 +55,42 @@
     fxLayoutAlign="space-between"
     [ngClass]="['modal', 'modal' + modalTypeOpened]"
   >
-    <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
-      <!--<div class="blockFiltre" *ngFor="let s of services">-->
-      <div class="blockFiltre" *ngFor="let c of categories">
-        <h4>{{ c.name }}</h4>
+    <div class="borderTricks">
+      <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
+        <!--<div class="blockFiltre" *ngFor="let s of services">-->
+        <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>
+          <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 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>
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 160f8dffe..e15560478 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -103,13 +103,18 @@
   margin-left: 412px;
 }
 .modal {
-  -moz-box-shadow: -5px 5px 10px 0px $grey;
-  box-shadow: -5px 5px 10px 0px $grey;
   max-height: 648px;
   max-width: 754px;
   width: 94%;
   background: $white;
-  border: 1px solid $grey;
+  border-left: 6.5px solid transparent;
+  border-bottom: 6.5px solid transparent;
+  border-radius: 11px;
+  //repeating-linear-gradient(37deg, transparent 0, transparent 1px, $grey 2px, $grey 2px) 12;
+  //border-image: repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) 8;
+
+  background: linear-gradient($white, $white) padding-box,
+    repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) border-box;
   box-sizing: border-box;
   z-index: 1;
   position: absolute;
@@ -125,12 +130,15 @@
     background: $grey;
     border-radius: 6px;
   }
-
+  .borderTricks {
+    border: 1px solid #e0e0e0;
+  }
   .contentModal {
     overflow-y: auto;
     max-width: 1100px;
     border-bottom: 1px solid $grey;
     margin-bottom: 10px;
+    max-height: 500px;
 
     .blockFiltre {
       width: 100%;
diff --git a/src/app/structure-list/components/search/search.component.spec.ts b/src/app/structure-list/components/search/search.component.spec.ts
index 56e05f1d6..62c81724c 100644
--- a/src/app/structure-list/components/search/search.component.spec.ts
+++ b/src/app/structure-list/components/search/search.component.spec.ts
@@ -1,14 +1,20 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-
+import { ReactiveFormsModule } from '@angular/forms';
+import { Category } from '../../models/category.model';
+import { Filter } from '../../models/filter.model';
+import { Module } from '../../models/module.model';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { SearchComponent } from './search.component';
+import { SearchService } from '../../services/search.service';
 
-describe('RechercheComponent', () => {
+describe('SearchComponent', () => {
   let component: SearchComponent;
   let fixture: ComponentFixture<SearchComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [SearchComponent],
+      imports: [HttpClientTestingModule, ReactiveFormsModule],
     }).compileComponents();
   });
 
@@ -21,4 +27,22 @@ describe('RechercheComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should emit filters', () => {
+    const filter: Filter[] = [new Filter('nom', 'valInput', false)];
+    spyOn(component.searchEvent, 'emit');
+    component.applyFilter('valInput');
+    expect(component.searchEvent.emit).toHaveBeenCalled();
+    expect(component.searchEvent.emit).toHaveBeenCalledWith(filter);
+  });
+
+  it('should update categories', () => {
+    let categories: Category[] = [new Category({ name: 'Accompagnement des démarches' })];
+    categories[0].modules = [];
+    for (let i = 0; i < 7; i++) {
+      categories[0].modules.push(new Module(5 + i, 'CAF' + i));
+    }
+    component.openModal('accompagnement');
+    expect(component.categories).toEqual(categories);
+  });
 });
diff --git a/src/app/structure-list/services/search.service.spec.ts b/src/app/structure-list/services/search.service.spec.ts
index 23c42c7bb..d8b757560 100644
--- a/src/app/structure-list/services/search.service.spec.ts
+++ b/src/app/structure-list/services/search.service.spec.ts
@@ -1,12 +1,14 @@
 import { TestBed } from '@angular/core/testing';
-
+import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { SearchService } from './search.service';
 
 describe('SearchService', () => {
   let service: SearchService;
 
   beforeEach(() => {
-    TestBed.configureTestingModule({});
+    TestBed.configureTestingModule({
+      imports: [HttpClientTestingModule],
+    });
     service = TestBed.inject(SearchService);
   });
 
diff --git a/src/app/structure-list/services/structure-list.service.spec.ts b/src/app/structure-list/services/structure-list.service.spec.ts
index 243602d45..230f2e331 100644
--- a/src/app/structure-list/services/structure-list.service.spec.ts
+++ b/src/app/structure-list/services/structure-list.service.spec.ts
@@ -1,4 +1,4 @@
-import { HttpClientModule } from '@angular/common/http';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { inject, TestBed } from '@angular/core/testing';
 import { Day } from '../models/day.model';
 import { Structure } from '../models/structure.model';
@@ -7,15 +7,15 @@ import { StructureService } from './structure-list.service';
 const { DateTime } = require('luxon');
 
 describe('StructureService', () => {
+  let structureService: StructureService;
+
   beforeEach(() => {
     TestBed.configureTestingModule({
-      imports: [HttpClientModule],
+      imports: [HttpClientTestingModule],
+      providers: [StructureService],
     });
+    structureService = TestBed.inject(StructureService);
   });
-  let structureService: StructureService;
-  beforeEach(inject([StructureService], (s: StructureService) => {
-    structureService = s;
-  }));
 
   it('Mise à jour ouverture de la structure : should return true', () => {
     // Init structure avec aucun horaire
-- 
GitLab


From 6510c5e4049ffdc729488a97bddb5b0c3ac807b5 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 21 Oct 2020 15:34:16 +0200
Subject: [PATCH 30/50] fix merge

---
 src/app/app.module.ts                            | 16 +++++++++++++---
 src/app/home/home.component.ts                   | 11 ++++++++++-
 .../components/search/search.component.scss      |  4 +++-
 .../components/search/search.component.ts        |  2 +-
 .../structure-list/structure-list.component.scss | 13 +++++++------
 src/app/structure-list/structure-list.scss       | 10 ----------
 6 files changed, 34 insertions(+), 22 deletions(-)
 delete mode 100644 src/app/structure-list/structure-list.scss

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 7cb7bc0d7..4934e7b00 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -12,9 +12,10 @@ import { FooterComponent } from './footer/footer.component';
 import { HeaderComponent } from './header/header.component';
 import { SharedModule } from './shared/shared.module';
 import { MapModule } from './map/map.module';
-import { RechercheComponent } from './structure-list/components/recherche/recherche.component';
 import { StructureListComponent } from './structure-list/structure-list.component';
 import { CardComponent } from './structure-list/components/card/card.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { SearchComponent } from './structure-list/components/search/search.component';
 
 @NgModule({
   declarations: [
@@ -24,9 +25,18 @@ import { CardComponent } from './structure-list/components/card/card.component';
     HomeComponent,
     StructureListComponent,
     CardComponent,
-    RechercheComponent,
+    SearchComponent,
+  ],
+  imports: [
+    BrowserModule,
+    HttpClientModule,
+    AppRoutingModule,
+    FlexLayoutModule,
+    SharedModule,
+    MapModule,
+    FormsModule,
+    ReactiveFormsModule,
   ],
-  imports: [BrowserModule, HttpClientModule, AppRoutingModule, FlexLayoutModule, SharedModule, MapModule],
   providers: [{ provide: LOCALE_ID, useValue: 'fr' }, CustomBreakPointsProvider],
   bootstrap: [AppComponent],
 })
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index 2264953e0..1c41605d4 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
 import { mergeMap } from 'rxjs/operators';
 import { Structure } from '../models/structure.model';
 import { StructureService } from '../services/structure-list.service';
+import { Filter } from '../structure-list/models/filter.model';
 const { DateTime } = require('luxon');
 
 @Component({
@@ -14,7 +15,15 @@ export class HomeComponent implements OnInit {
   constructor(private structureService: StructureService) {}
 
   ngOnInit(): void {
-    this.structureService.getStructures().subscribe((structures) => {
+    this.structureService.getStructures(null).subscribe((structures) => {
+      this.structures = structures.map((structure) =>
+        this.structureService.updateOpeningStructure(structure, DateTime.local())
+      );
+    });
+  }
+
+  fetchResults(filters: Filter[]) {
+    this.structureService.getStructures(filters).subscribe((structures) => {
       this.structures = structures.map((structure) =>
         this.structureService.updateOpeningStructure(structure, DateTime.local())
       );
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index e15560478..b904c1283 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -110,11 +110,14 @@
   border-left: 6.5px solid transparent;
   border-bottom: 6.5px solid transparent;
   border-radius: 11px;
+  z-index: 401 !important;
+
   //repeating-linear-gradient(37deg, transparent 0, transparent 1px, $grey 2px, $grey 2px) 12;
   //border-image: repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) 8;
 
   background: linear-gradient($white, $white) padding-box,
     repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) border-box;
+  //repeating-linear-gradient(-51deg, transparent 0, transparent 1px, $grey 1px, $grey 2px) border-box;
   box-sizing: border-box;
   z-index: 1;
   position: absolute;
@@ -139,7 +142,6 @@
     border-bottom: 1px solid $grey;
     margin-bottom: 10px;
     max-height: 500px;
-
     .blockFiltre {
       width: 100%;
       padding: 32px 40px 10px 40px;
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index a2c205d20..778430893 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -69,7 +69,7 @@ export class SearchComponent implements OnInit {
     // Send search input filter
     let filters: Filter[] = [];
     if (term) {
-      filters.push(new Filter('nom', term, false));
+      filters.push(new Filter('nomDeVotreStructure', term, false));
     }
 
     // Send checked box filter
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
index fa639184d..3be0db3da 100644
--- a/src/app/structure-list/structure-list.component.scss
+++ b/src/app/structure-list/structure-list.component.scss
@@ -1,14 +1,15 @@
 @import '../../assets/scss/color';
+@import '../../assets/scss/icons';
+@import '../../assets/scss/typography';
 
 .divider {
   width: 100%;
   height: 1px;
   background-color: $grey-4;
 }
-//En attendant de l'intégrer avec la map
-.container {
-  width: 640px;
-  .content {
-    padding: 0 20px 0 20px;
-  }
+.nbStructuresLabel {
+  color: $grey;
+  @include cn-regular-16;
+  display: flex;
+  align-items: center;
 }
diff --git a/src/app/structure-list/structure-list.scss b/src/app/structure-list/structure-list.scss
deleted file mode 100644
index 68c10dffe..000000000
--- a/src/app/structure-list/structure-list.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../../assets/scss/icons';
-@import '../../assets/scss/color';
-@import '../../assets/scss/typography';
-
-.nbStructuresLabel {
-  color: $grey;
-  @include cn-regular-16;
-  display: flex;
-  align-items: center;
-}
-- 
GitLab


From 91e9f74a88010c7db5ad1a6f6e823f289aff1615 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 21 Oct 2020 17:42:38 +0200
Subject: [PATCH 31/50] fix(search) : set scroll bar to list structures + fix
 test

---
 src/app/app.component.scss                          |  4 ++--
 src/app/footer/footer.component.scss                |  1 +
 src/app/header/header.component.scss                |  1 +
 src/app/home/home.component.html                    |  3 ++-
 src/app/home/home.component.scss                    |  5 ++---
 .../components/search/search.component.spec.ts      |  2 +-
 .../structure-list/structure-list.component.html    | 13 +++++++++----
 .../structure-list/structure-list.component.scss    |  7 +++++++
 8 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index 4f5c46104..803b77c89 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -10,8 +10,8 @@
 }
 
 .app-body {
-  flex: 1 0 auto;
-  overflow-y: auto;
+  flex: 1 1 auto;
+  overflow-y: hidden;
   overflow-x: hidden;
   position: relative;
 }
diff --git a/src/app/footer/footer.component.scss b/src/app/footer/footer.component.scss
index 038add29a..008df688f 100644
--- a/src/app/footer/footer.component.scss
+++ b/src/app/footer/footer.component.scss
@@ -10,6 +10,7 @@
   align-items: center !important;
   justify-content: space-between !important;
   padding: 0px 4vw;
+  flex: 0 0 auto;
   a {
     color: $white;
     margin: 0 10px 0 12px;
diff --git a/src/app/header/header.component.scss b/src/app/header/header.component.scss
index f22e53e19..6dfdc3889 100644
--- a/src/app/header/header.component.scss
+++ b/src/app/header/header.component.scss
@@ -11,6 +11,7 @@
   justify-content: space-between;
   padding: 0px 0 0 4vw;
   text-align: center;
+  flex: 0 0 auto;
   a {
     &.active {
       @include highlight;
diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html
index 39a5681a1..930a43cf2 100644
--- a/src/app/home/home.component.html
+++ b/src/app/home/home.component.html
@@ -1,8 +1,9 @@
-<div fxLayout="row">
+<div fxLayout="row" style="height: 100%">
   <app-structure-list
     (searchEvent)="fetchResults($event)"
     [structureList]="structures"
     class="left-pane"
+    fxLayout="column"
   ></app-structure-list>
   <app-map [structures]="structures" fxFlex="100"></app-map>
 </div>
diff --git a/src/app/home/home.component.scss b/src/app/home/home.component.scss
index 1a2d33f8e..f2884d25f 100644
--- a/src/app/home/home.component.scss
+++ b/src/app/home/home.component.scss
@@ -1,5 +1,4 @@
 .left-pane {
-  padding: 0 25px;
-  width: 590px;
-  min-width: 590px;
+  width: 640px;
+  min-width: 640px;
 }
diff --git a/src/app/structure-list/components/search/search.component.spec.ts b/src/app/structure-list/components/search/search.component.spec.ts
index 62c81724c..790ae3595 100644
--- a/src/app/structure-list/components/search/search.component.spec.ts
+++ b/src/app/structure-list/components/search/search.component.spec.ts
@@ -29,7 +29,7 @@ describe('SearchComponent', () => {
   });
 
   it('should emit filters', () => {
-    const filter: Filter[] = [new Filter('nom', 'valInput', false)];
+    const filter: Filter[] = [new Filter('nomDeVotreStructure', 'valInput', false)];
     spyOn(component.searchEvent, 'emit');
     component.applyFilter('valInput');
     expect(component.searchEvent.emit).toHaveBeenCalled();
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index 030bcf353..e0de815ee 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,4 +1,9 @@
-<app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
-<div class="divider"></div>
-<span class="nbStructuresLabel">{{ structureList.length }} structures</span>
-<app-card *ngFor="let structure of structureList" [structure]="structure"></app-card>
+<div class="topBlock">
+  <app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
+  <div class="divider"></div>
+  <span class="nbStructuresLabel">{{ structureList.length }} structures</span>
+</div>
+
+<div class="listCard">
+  <app-card *ngFor="let structure of structureList" [structure]="structure"></app-card>
+</div>
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
index 3be0db3da..5b09b7ee8 100644
--- a/src/app/structure-list/structure-list.component.scss
+++ b/src/app/structure-list/structure-list.component.scss
@@ -13,3 +13,10 @@
   display: flex;
   align-items: center;
 }
+.listCard {
+  overflow-y: auto;
+  padding: 0 25px;
+}
+.topBlock {
+  padding: 0 25px;
+}
-- 
GitLab


From ec70e6e11f866e22a5d7fe508b10ae66833a5f22 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Mon, 26 Oct 2020 12:11:25 +0100
Subject: [PATCH 32/50] fix: small fix

---
 debug.log                                     |  1 -
 src/app/home/home.component.ts                |  2 +-
 src/app/services/structure-list.service.ts    | 25 +++++++++----------
 .../structure-list/models/category.model.ts   |  4 ++-
 4 files changed, 16 insertions(+), 16 deletions(-)
 delete mode 100644 debug.log

diff --git a/debug.log b/debug.log
deleted file mode 100644
index e4874e229..000000000
--- a/debug.log
+++ /dev/null
@@ -1 +0,0 @@
-[1021/094448.838:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index 1c41605d4..090ae1018 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -22,7 +22,7 @@ export class HomeComponent implements OnInit {
     });
   }
 
-  fetchResults(filters: Filter[]) {
+  public fetchResults(filters: Filter[]): void {
     this.structureService.getStructures(filters).subscribe((structures) => {
       this.structures = structures.map((structure) =>
         this.structureService.updateOpeningStructure(structure, DateTime.local())
diff --git a/src/app/services/structure-list.service.ts b/src/app/services/structure-list.service.ts
index 745a69a54..9f2425166 100644
--- a/src/app/services/structure-list.service.ts
+++ b/src/app/services/structure-list.service.ts
@@ -18,35 +18,34 @@ export class StructureService {
   constructor(private http: HttpClient) {}
 
   public getStructures(filters: Filter[]): Observable<Structure[]> {
-    console.log(this.constructApi(filters));
     return this.http
-      .get('/api/Structures?' + this.constructApi(filters))
+      .get('/api/Structures?' + this.constructSearchRequest(filters))
       .pipe(map((data: any[]) => data.map((item) => new Structure(item))));
   }
 
-  private constructApi(filters: Filter[]): string {
-    let api: string = '';
+  private constructSearchRequest(filters: Filter[]): string {
+    let requestParam = '';
     if (filters) {
       filters.forEach((filter) => {
-        if (api) {
-          api = api + '&';
+        if (requestParam) {
+          requestParam = requestParam + '&';
         }
         if (filter.isStrict) {
-          if (api.includes(filter.name)) {
-            api = api + '=' + filter.value;
+          if (requestParam.includes(filter.name)) {
+            requestParam = requestParam + '=' + filter.value;
           } else {
-            api = api + filter.name + '=' + filter.value;
+            requestParam = requestParam + filter.name + '=' + filter.value;
           }
         } else {
-          if (api.includes(filter.name)) {
-            api = api + filter.value;
+          if (requestParam.includes(filter.name)) {
+            requestParam = requestParam + filter.value;
           } else {
-            api = api + filter.name + '_like=' + filter.value;
+            requestParam = requestParam + filter.name + '_like=' + filter.value;
           }
         }
       });
     }
-    return api;
+    return requestParam;
   }
 
   /**
diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts
index cb5a96eee..0ffaec8dc 100644
--- a/src/app/structure-list/models/category.model.ts
+++ b/src/app/structure-list/models/category.model.ts
@@ -5,6 +5,8 @@ export class Category {
   modules: Module[];
 
   constructor(obj?: any) {
-    Object.assign(this, obj);
+    Object.assign(this, obj, {
+      modules: obj && obj.modules ? obj.modules.map((module) => new Module(module.id, module.text)) : null,
+    });
   }
 }
-- 
GitLab


From c32212be2a853cdd5649242341cc8fec9446daf7 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Mon, 26 Oct 2020 12:11:56 +0100
Subject: [PATCH 33/50] fix: search component code

---
 .../structure-list/components/search/search.component.ts  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 778430893..aa70de956 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -67,7 +67,7 @@ export class SearchComponent implements OnInit {
     this.checkedModulesFilter = this.checkedModules.slice();
     this.openModal(this.modalTypeOpened);
     // Send search input filter
-    let filters: Filter[] = [];
+    const filters: Filter[] = [];
     if (term) {
       filters.push(new Filter('nomDeVotreStructure', term, false));
     }
@@ -81,7 +81,7 @@ export class SearchComponent implements OnInit {
 
   // Management of the checkbox event (Check / Uncheck)
   public onCheckboxChange(event, categ: string): void {
-    const checkValue: number = parseInt(event.target.value);
+    const checkValue: number = parseInt(event.target.value, 10);
     if (event.target.checked) {
       this.checkedModules.push(new Module(checkValue, categ));
     } else {
@@ -101,8 +101,9 @@ export class SearchComponent implements OnInit {
   public clearFilters(): void {
     this.categories.forEach((categ: Category) => {
       categ.modules.forEach((module: Module) => {
-        if (this.getIndex(module.id, categ.name) > -1)
+        if (this.getIndex(module.id, categ.name) > -1) {
           this.checkedModules.splice(this.getIndex(module.id, categ.name), 1);
+        }
       });
     });
   }
@@ -155,7 +156,6 @@ export class SearchComponent implements OnInit {
         8
       );
       this.mockService(this.categories, "Modalité d'accueil", { name: 'Matériel mis à dispostion', id: 2 }, 6);
-
       this.mockService(this.categories, "Type d'acteurs", { name: 'Lieux de médiation (Pimms, assos...)', id: 3 }, 5);
       this.mockService(this.categories, 'Publics', { name: 'Langues étrangères autres qu’anglais', id: 4 }, 12);
       this.mockService(this.categories, 'Labelisation', { name: 'Prescripteur du Pass Numérique', id: 5 }, 6);
-- 
GitLab


From 3d45ba5323372d4b5241ec5313ff1c36f5e6af1a Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Tue, 27 Oct 2020 10:48:27 +0100
Subject: [PATCH 34/50] fix: improve border style

---
 .../components/search/search.component.html   |  3 +--
 .../components/search/search.component.scss   | 19 +++++-------------
 src/assets/scss/_shapes.scss                  | 20 +++++++++++++++++++
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index f59c9ba93..68ef0abfa 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -55,9 +55,8 @@
     fxLayoutAlign="space-between"
     [ngClass]="['modal', 'modal' + modalTypeOpened]"
   >
-    <div class="borderTricks">
+    <div class="body-wrap">
       <div class="contentModal" fxLayout="row wrap" fxLayoutAlign="flex-start" *ngIf="categories.length > 0">
-        <!--<div class="blockFiltre" *ngFor="let s of services">-->
         <div class="blockFiltre" *ngFor="let c of categories">
           <h4>{{ c.name }}</h4>
 
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index b904c1283..5b8230750 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -2,6 +2,7 @@
 @import '../../../../assets/scss/color';
 @import '../../../../assets/scss/typography';
 @import '../../../../assets/scss/breakpoint';
+@import '../../../../assets/scss/shapes';
 
 .header {
   .title {
@@ -106,23 +107,16 @@
   max-height: 648px;
   max-width: 754px;
   width: 94%;
-  background: $white;
   border-left: 6.5px solid transparent;
   border-bottom: 6.5px solid transparent;
   border-radius: 11px;
   z-index: 401 !important;
-
-  //repeating-linear-gradient(37deg, transparent 0, transparent 1px, $grey 2px, $grey 2px) 12;
-  //border-image: repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) 8;
-
-  background: linear-gradient($white, $white) padding-box,
-    repeating-linear-gradient(-45deg, transparent 0, transparent 4px, $grey 4px, $grey 5px) border-box;
-  //repeating-linear-gradient(-51deg, transparent 0, transparent 1px, $grey 1px, $grey 2px) border-box;
-  box-sizing: border-box;
-  z-index: 1;
+  margin: 8px 8px 0 0;
   position: absolute;
   margin-top: 96px;
-
+  border: 1px solid $grey-5;
+  border-radius: 6px;
+  @include background-hash;
   ::-webkit-scrollbar {
     width: 10px;
   }
@@ -133,9 +127,6 @@
     background: $grey;
     border-radius: 6px;
   }
-  .borderTricks {
-    border: 1px solid #e0e0e0;
-  }
   .contentModal {
     overflow-y: auto;
     max-width: 1100px;
diff --git a/src/assets/scss/_shapes.scss b/src/assets/scss/_shapes.scss
index 21c498f05..22281d819 100644
--- a/src/assets/scss/_shapes.scss
+++ b/src/assets/scss/_shapes.scss
@@ -33,3 +33,23 @@ $mat-tab-shadow: 0px 2px 7px rgba(0, 0, 0, 0.25);
   background-repeat: no-repeat;
   background-position-y: 12px;
 }
+
+@mixin background-hash {
+  background: linear-gradient(
+    -45deg,
+    $grey 2.5%,
+    $white 2.5%,
+    $white 47.5%,
+    $grey 47.5%,
+    $grey 52.5%,
+    $white 52.5%,
+    $white 97.5%,
+    $grey 97.5%
+  );
+  background-size: 5px 5px;
+  background-position: 25px 25px;
+  padding: 0 0 8px 8px;
+  .body-wrap {
+    background-color: $white;
+  }
+}
-- 
GitLab


From d27fbaccd36deffb1c87e99aa1f1299d4b27e147 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Wed, 28 Oct 2020 15:40:27 +0100
Subject: [PATCH 35/50] fix: dockerfile

---
 Dockerfile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Dockerfile b/Dockerfile
index de073df46..6cc3c3cac 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -28,6 +28,7 @@ FROM nginx:1.16.0-alpine
 # copy artifact build from the 'build environment'
 
 COPY --from=build /app/dist/fr /usr/share/nginx/html
+COPY --from=build /app/dist/fr /usr/share/nginx/html/fr
 
 RUN touch /var/run/nginx.pid
 
-- 
GitLab


From 59522f66145b3667f4c145f9e8145de915894982 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Wed, 28 Oct 2020 15:49:44 +0100
Subject: [PATCH 36/50] fix: fix background shape style

---
 src/app/map/components/map.component.scss | 1 -
 src/assets/scss/_shapes.scss              | 8 ++++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/app/map/components/map.component.scss b/src/app/map/components/map.component.scss
index d12f41e83..c91352723 100644
--- a/src/app/map/components/map.component.scss
+++ b/src/app/map/components/map.component.scss
@@ -11,7 +11,6 @@
 
 #map {
   height: calc(100vh - #{$header-height} - #{$footer-height} - 50px);
-  width: 100%;
   border: 10px solid white;
   border-radius: 6px;
 }
diff --git a/src/assets/scss/_shapes.scss b/src/assets/scss/_shapes.scss
index 164a637b1..fec384566 100644
--- a/src/assets/scss/_shapes.scss
+++ b/src/assets/scss/_shapes.scss
@@ -37,14 +37,14 @@ $mat-tab-shadow: 0px 2px 7px rgba(0, 0, 0, 0.25);
 @mixin background-hash {
   background: linear-gradient(
     -45deg,
-    $grey 2.5%,
+    $grey-2 2.5%,
     $white 2.5%,
     $white 47.5%,
-    $grey 47.5%,
-    $grey 52.5%,
+    $grey-2 47.5%,
+    $grey-2 52.5%,
     $white 52.5%,
     $white 97.5%,
-    $grey 97.5%
+    $grey-2 97.5%
   );
   background-size: 5px 5px;
   background-position: 25px 25px;
-- 
GitLab


From 8b3bd921778fd2c18dd4a1ec6e28894a757a094b Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Fri, 30 Oct 2020 19:59:31 +0100
Subject: [PATCH 37/50] fix: tooltip status issue

---
 src/app/map/components/map.component.ts | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/app/map/components/map.component.ts b/src/app/map/components/map.component.ts
index 08bacc687..81b35c455 100644
--- a/src/app/map/components/map.component.ts
+++ b/src/app/map/components/map.component.ts
@@ -74,7 +74,15 @@ export class MapComponent implements OnChanges {
    * @param structure Structure
    */
   private buildToolTip(structure: Structure): string {
-    const cssAvailabilityClass = structure.isOpen ? 'available' : 'unavailable';
+    let cssAvailabilityClass = structure.isOpen ? 'available' : null;
+    if (cssAvailabilityClass === null) {
+      if (structure.openedOn.day) {
+        cssAvailabilityClass = 'unavailable';
+      } else {
+        cssAvailabilityClass = 'unknown';
+      }
+    }
+
     return (
       '<h1>' +
       structure.nomDeVotreStructure +
-- 
GitLab


From 7d6177ad2402f84c148922663ed21ad96b125296 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Fri, 30 Oct 2020 22:28:00 +0100
Subject: [PATCH 38/50] feat: add address on strucutre details

---
 src/app/home/home.component.ts                             | 1 +
 src/app/map/models/geoJsonProperties.model.ts              | 7 +++++++
 src/app/map/models/geojson.model.ts                        | 3 ++-
 src/app/models/structure.model.ts                          | 1 +
 .../structure-details/structure-details.component.html     | 2 +-
 5 files changed, 12 insertions(+), 2 deletions(-)
 create mode 100644 src/app/map/models/geoJsonProperties.model.ts

diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index 6630be72c..e198b3374 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -52,6 +52,7 @@ export class HomeComponent implements OnInit {
   private getStructurePosition(structure: Structure): Promise<Structure> {
     return new Promise((resolve, reject) => {
       this.getCoord(structure.voie).subscribe((coord: GeoJson) => {
+        structure.address = coord.properties.name + ' - ' + coord.properties.postcode + ' ' + coord.properties.city;
         structure.distance = this.geoJsonService.getDistance(
           coord.geometry.getLon(),
           coord.geometry.getLat(),
diff --git a/src/app/map/models/geoJsonProperties.model.ts b/src/app/map/models/geoJsonProperties.model.ts
new file mode 100644
index 000000000..fc9abed8d
--- /dev/null
+++ b/src/app/map/models/geoJsonProperties.model.ts
@@ -0,0 +1,7 @@
+export class GeoJsonProperties {
+  public city: string;
+  public country: string;
+  public name: string;
+  public postcode: string;
+  public state: string;
+}
diff --git a/src/app/map/models/geojson.model.ts b/src/app/map/models/geojson.model.ts
index 3407c70da..8ca263895 100644
--- a/src/app/map/models/geojson.model.ts
+++ b/src/app/map/models/geojson.model.ts
@@ -1,9 +1,10 @@
 import { AddressGeometry } from './addressGeometry.model';
+import { GeoJsonProperties } from './geoJsonProperties.model';
 
 export class GeoJson {
   public geometry: AddressGeometry;
   public type: string;
-  public properties: object;
+  public properties: GeoJsonProperties;
 
   constructor(obj?: any) {
     Object.assign(this, obj, {
diff --git a/src/app/models/structure.model.ts b/src/app/models/structure.model.ts
index 16f2781e6..6cc2c585f 100644
--- a/src/app/models/structure.model.ts
+++ b/src/app/models/structure.model.ts
@@ -36,6 +36,7 @@ export class Structure {
   public isOpen: boolean;
   public openedOn: OpeningDay;
   public distance?: string;
+  public address?: string;
 
   constructor(obj?: any) {
     Object.assign(this, obj, {
diff --git a/src/app/structure-list/components/structure-details/structure-details.component.html b/src/app/structure-list/components/structure-details/structure-details.component.html
index 03cbfe870..ba303e734 100644
--- a/src/app/structure-list/components/structure-details/structure-details.component.html
+++ b/src/app/structure-list/components/structure-details/structure-details.component.html
@@ -12,7 +12,7 @@
         <div fxLayout="column" fxFlex="60%">
           <div *ngIf="structure.voie" fxLayout="row" fxLayoutAlign="none center">
             <em class="ico-marker-pin-sm absolute"></em>
-            <p>{{ structure.voie }}</p>
+            <p>{{ structure.n }} {{ structure.address }}</p>
           </div>
           <div *ngIf="structure.siteWeb" fxLayout="row" fxLayoutAlign="none center">
             <em class="ic-globe-alt"></em>
-- 
GitLab


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 39/50] 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


From 51df52c9078cd00b0d536f09536de99a56df5265 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 12:15:18 +0100
Subject: [PATCH 40/50] fix(search) : fix button + color

---
 .../modal-filter/modal-filter.component.scss  |  20 +--
 .../components/search/search.component.html   |   4 +-
 .../components/search/search.component.scss   | 157 ++----------------
 .../components/search/search.component.ts     |  10 +-
 src/assets/scss/_buttons.scss                 |  31 ++++
 src/assets/scss/_color.scss                   |  12 +-
 src/assets/scss/_inputs.scss                  |   0
 7 files changed, 67 insertions(+), 167 deletions(-)
 create mode 100644 src/assets/scss/_buttons.scss
 create mode 100644 src/assets/scss/_inputs.scss

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
index 08adc9c1c..b4b705285 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.scss
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -3,6 +3,7 @@
 @import '../../../../assets/scss/typography';
 @import '../../../../assets/scss/breakpoint';
 @import '../../../../assets/scss/shapes';
+@import '../../../../assets/scss/buttons';
 
 .modalformations {
   @media #{$desktop} {
@@ -88,31 +89,16 @@
       display: flex;
       align-items: center;
       text-decoration: underline;
+      color: $secondary-color;
     }
     height: 32px;
     button {
-      height: 100%;
-      border: none;
-      cursor: pointer;
-      background-color: $purple;
+      @include btn-search-filter;
       @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;
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 8f962c47d..b4b59c342 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -13,7 +13,9 @@
         <div class="ico-pin-search grey"></div>
       </div>
       <input type="text" formControlName="searchTerm" placeholder="Rechercher une adresse, une association..." />
-      <button type="submit">Rechercher</button>
+      <div class="searchButton">
+        <button type="submit">Rechercher</button>
+      </div>
     </form>
   </div>
 
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 5b8230750..559e50345 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -3,6 +3,7 @@
 @import '../../../../assets/scss/typography';
 @import '../../../../assets/scss/breakpoint';
 @import '../../../../assets/scss/shapes';
+@import '../../../../assets/scss/buttons';
 
 .header {
   .title {
@@ -34,45 +35,32 @@
     outline: none;
   }
   .searchSection {
-    button {
-      border: none;
-      cursor: pointer;
-      background-color: $purple;
-      @include cn-bold-14;
-      align-items: center;
-      text-align: center;
-      color: $white;
-      padding: 3px 16px 3px 16px;
-      outline: none;
+    .searchButton {
+      border: 1px solid $grey-6;
+      border-radius: 6px;
+      @include background-hash;
+      padding: 0 0 4px 5px;
+      button {
+        @include btn-search;
+        @include cn-bold-14;
+      }
     }
   }
   .btnSection {
     padding: 16px 0 8px 0;
     button {
-      height: 40px;
-      width: 190px;
-      outline: none;
-      border: 1px solid $grey;
-      border-radius: 33px;
-      background-color: $white;
-      padding: 2px 6px 2px 13px;
-      align-items: center;
-      display: flex;
-      cursor: pointer;
+      @include btn-filter;
       .btnText {
-        justify-content: center;
         @include cn-regular-14;
-        display: flex;
-        align-items: center;
       }
     }
     .selected {
-      border: 1px solid $orange-light;
-      color: $orange-light;
+      border: 1px solid $primary-color;
+      color: $primary-color;
       .arrow {
         background-color: transparent;
-        border-bottom: 1px solid $orange-light;
-        border-right: 1px solid $orange-light;
+        border-bottom: 1px solid $primary-color;
+        border-right: 1px solid $primary-color;
         transform: translateY(25%) rotate(-135deg);
         margin: 0 5px 0 10px;
         height: 7px;
@@ -81,8 +69,8 @@
     }
     .arrow {
       background-color: transparent;
-      border-bottom: 1px solid $grey;
-      border-right: 1px solid $grey;
+      border-bottom: 1px solid $grey-2;
+      border-right: 1px solid $grey-2;
       transform: translateY(-25%) rotate(45deg);
       margin: 0 5px 0 10px;
       height: 7px;
@@ -90,117 +78,8 @@
     }
   }
 }
-.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;
-  margin: 8px 8px 0 0;
-  position: absolute;
-  margin-top: 96px;
-  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;
@@ -242,8 +121,6 @@
       content: '';
       position: absolute;
       display: none;
-    }
-    &:after {
       left: 7px;
       top: 3px;
       width: 4px;
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index c7440073c..c8baac522 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -96,13 +96,13 @@ export class SearchComponent implements OnInit {
 
   // Fake service api
   private mockService(module: Category[], titre: string, categ: any, nbCateg: number): void {
-    let m = new Category();
-    m.name = titre;
-    m.modules = [];
+    const category = new Category();
+    category.name = titre;
+    category.modules = [];
     for (let i = 0; i < nbCateg; i++) {
-      m.modules.push(new Module(categ.id + i, categ.name + i));
+      category.modules.push(new Module(categ.id + i, categ.name + i));
     }
-    module.push(m);
+    module.push(category);
   }
 
   // Fake data
diff --git a/src/assets/scss/_buttons.scss b/src/assets/scss/_buttons.scss
new file mode 100644
index 000000000..4d203db52
--- /dev/null
+++ b/src/assets/scss/_buttons.scss
@@ -0,0 +1,31 @@
+@import './color';
+@import './shapes';
+
+@mixin btn-filter {
+  background: $white;
+  height: 40px;
+  width: 190px;
+  border: 1px solid $grey-6;
+  padding: 3px 16px 3px 16px;
+  outline: none;
+  border-radius: 4px;
+  cursor: pointer;
+}
+@mixin btn-search {
+  background: $white;
+  height: 34px;
+  border: none;
+  color: $primary-color;
+  padding: 3px 16px 3px 16px;
+  outline: none;
+  cursor: pointer;
+}
+@mixin btn-search-filter {
+  background: $secondary-color;
+  height: 40px;
+  border: none;
+  color: $white;
+  padding: 3px 16px 3px 16px;
+  outline: none;
+  cursor: pointer;
+}
diff --git a/src/assets/scss/_color.scss b/src/assets/scss/_color.scss
index 40d9d77e3..bf291a307 100644
--- a/src/assets/scss/_color.scss
+++ b/src/assets/scss/_color.scss
@@ -8,6 +8,7 @@ $grey-2: #4f4f4f;
 $grey-3: #c3c3c3;
 $grey-4: #f2ecf2;
 $grey-5: #f2f2f2;
+$grey-6: #bdbdbd;
 /* YELLOW */
 $yellow: #f2cb04;
 $yellow-light: #fff8d6;
@@ -17,13 +18,16 @@ $orange-light: #f29f05;
 $orange-3: #fff4ea;
 /* GREEN */
 $green: #41c29c;
-/* OTHERS */
-$blue: #b3f8f8;
+/* BLUE */
+$blue: #348899;
+
+$blue-light: #b3f8f8;
 $blue-dark: #2f5480;
+/* OTHERS */
 $purple: #594d59;
 $red-metro: #d50000;
 /* APP COLORS */
-$primary-color: $yellow;
-$secondary-color: $orange;
+$primary-color: $red-metro;
+$secondary-color: $blue;
 $default-link-color: $grey-2;
 $button-secondary: $blue-dark;
diff --git a/src/assets/scss/_inputs.scss b/src/assets/scss/_inputs.scss
new file mode 100644
index 000000000..e69de29bb
-- 
GitLab


From 8cde8224f36925adf0306d867ecee3a62f7a60d3 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 12:45:42 +0100
Subject: [PATCH 41/50] fix(search) : fix input + design

---
 .../modal-filter/modal-filter.component.scss  |  5 +--
 .../components/search/search.component.html   | 12 +++++--
 .../components/search/search.component.scss   | 35 +++++++++++--------
 .../components/search/search.component.ts     |  5 +++
 src/assets/scss/_icons.scss                   | 24 +++++++++++--
 src/assets/scss/_inputs.scss                  |  9 +++++
 6 files changed, 69 insertions(+), 21 deletions(-)

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
index b4b705285..5275c2945 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.scss
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -10,13 +10,13 @@
     margin-left: 0;
   }
 
-  margin-left: 206px;
+  margin-left: 196px;
 }
 .modalplusFiltres {
   @media #{$desktop} {
     margin-left: 0;
   }
-  margin-left: 412px;
+  margin-left: 396px;
 }
 .modal {
   max-height: 648px;
@@ -29,6 +29,7 @@
   position: absolute;
   border: 1px solid $grey-5;
   border-radius: 6px;
+  margin-top: 3.5px;
   @include background-hash;
   ::-webkit-scrollbar {
     width: 10px;
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index b4b59c342..44fa60bd2 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -9,10 +9,16 @@
       fxLayoutGap="1.5vw"
       (ngSubmit)="applyFilter(searchForm.value.searchTerm)"
     >
-      <div class="icon">
-        <div class="ico-pin-search grey"></div>
+      <div class="inputSection" fxLayout="row" fxLayoutAlign="space-between center">
+        <input type="text" formControlName="searchTerm" placeholder="Rechercher une adresse, une association..." />
+        <div class="icon close" (click)="clearInput()">
+          <div class="ico-close grey"></div>
+        </div>
+        <div class="separator"></div>
+        <div class="icon pin">
+          <div class="ico-pin-search blue"></div>
+        </div>
       </div>
-      <input type="text" formControlName="searchTerm" placeholder="Rechercher une adresse, une association..." />
       <div class="searchButton">
         <button type="submit">Rechercher</button>
       </div>
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 559e50345..5b8368862 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -4,6 +4,7 @@
 @import '../../../../assets/scss/breakpoint';
 @import '../../../../assets/scss/shapes';
 @import '../../../../assets/scss/buttons';
+@import '../../../../assets/scss/inputs';
 
 .header {
   .title {
@@ -17,24 +18,31 @@
 .content {
   margin: 10px 0 0px 0;
   .icon {
-    border: 1px solid $grey;
-    padding: 4px 6px 8px 6px;
+    padding: 0 6px 0 6px;
     border-radius: 4px;
     cursor: pointer;
+    &.pin {
+      margin-bottom: 4px;
+    }
   }
   input {
-    width: 100%;
-    background-color: $grey-5;
-    border: none;
     @include cn-regular-14;
-    display: flex;
-    align-items: center;
-    padding-left: 10px;
-    text-overflow: ellipsis;
-    color: $grey-1;
-    outline: none;
+    @include input-search;
   }
   .searchSection {
+    .separator {
+      height: 100%;
+      width: 2px;
+      background-color: $grey-6;
+      margin: 0 5px 0 5px;
+    }
+    .inputSection {
+      padding: 6px 3px 6px 6px;
+      min-width: 463px;
+      border: 1px solid $grey-6;
+      background-color: $white;
+      height: 40px;
+    }
     .searchButton {
       border: 1px solid $grey-6;
       border-radius: 6px;
@@ -47,7 +55,7 @@
     }
   }
   .btnSection {
-    padding: 16px 0 8px 0;
+    padding: 16px 0 0px 0;
     button {
       @include btn-filter;
       .btnText {
@@ -134,8 +142,7 @@
   }
 }
 .footerSearchSection {
-  margin-bottom: 30px;
-  margin-right: 20px;
+  margin: 17px 0px 17px 0px;
 
   a {
     @include cn-bold-14;
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index c8baac522..d95cf649b 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -38,6 +38,11 @@ export class SearchComponent implements OnInit {
 
     this.checkedModulesFilter = new Array();
   }
+  // Clear input search
+  public clearInput(): void {
+    this.searchForm.reset();
+    this.applyFilter(null);
+  }
 
   // Sends an array containing all filters
   public applyFilter(term: string): void {
diff --git a/src/assets/scss/_icons.scss b/src/assets/scss/_icons.scss
index 77ed9a879..52da3fd2e 100644
--- a/src/assets/scss/_icons.scss
+++ b/src/assets/scss/_icons.scss
@@ -66,8 +66,8 @@
     border-radius: 4px;
     background-color: white;
   }
-  &.grey {
-    background-color: #828282;
+  &.blue {
+    background-color: $secondary-color;
   }
 }
 .ico-dot-available {
@@ -123,3 +123,23 @@
     border-left: 2px solid $purple;
   }
 }
+
+.ico-close {
+  width: 15px;
+  height: 13px;
+  text-align: center;
+  &:before {
+    transform: rotate(45deg);
+  }
+  &:after {
+    transform: rotate(-45deg);
+  }
+}
+.ico-close:before,
+.ico-close:after {
+  position: absolute;
+  content: '';
+  height: 14px;
+  width: 2px;
+  background-color: $grey-6;
+}
diff --git a/src/assets/scss/_inputs.scss b/src/assets/scss/_inputs.scss
index e69de29bb..dac479e10 100644
--- a/src/assets/scss/_inputs.scss
+++ b/src/assets/scss/_inputs.scss
@@ -0,0 +1,9 @@
+@mixin input-search {
+  width: 100%;
+  border: none;
+  padding-left: 10px;
+  text-overflow: ellipsis;
+  color: $grey-1;
+  outline: none;
+  font-style: italic;
+}
-- 
GitLab


From da50466067477ccbe8337f2b8ab51d5192cd1bdb Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 14:21:30 +0100
Subject: [PATCH 42/50] fix(search) : use proxy

---
 api/routes.json                                   | 3 ---
 api/server.js                                     | 6 +++++-
 src/app/structure-list/services/search.service.ts | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)
 delete mode 100644 api/routes.json

diff --git a/api/routes.json b/api/routes.json
deleted file mode 100644
index 6a7af55fa..000000000
--- a/api/routes.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "/api/*": "/$1"
-}
diff --git a/api/server.js b/api/server.js
index 08ca86cb0..43c5b108c 100644
--- a/api/server.js
+++ b/api/server.js
@@ -1,13 +1,17 @@
 const jsonServer = require('json-server');
 const server = jsonServer.create();
 const router = jsonServer.router('db.json');
-const middlewares = jsonServer.defaults();
+const routes = {
+  '/api/*': '/$1',
+};
+const middlewares = [jsonServer.defaults(), jsonServer.rewriter(routes)];
 
 // Set default middlewares (logger, static, cors and no-cache)
 server.use(middlewares);
 
 // Add custom routes before JSON Server router
 server.get('/structures/count', (req, res) => {
+  console.log('ok');
   let structureCountTab = [];
   // Compétences de base
   structureCountTab.push({ id: 260, count: 3 });
diff --git a/src/app/structure-list/services/search.service.ts b/src/app/structure-list/services/search.service.ts
index fc3e73583..906fc3aee 100644
--- a/src/app/structure-list/services/search.service.ts
+++ b/src/app/structure-list/services/search.service.ts
@@ -17,7 +17,7 @@ export class SearchService {
       .pipe(map((data: any[]) => data.map((item) => new Category(item))));
   }
   public getFakeCounterModule(): Observable<any> {
-    return this.http.get('http://localhost:3000/structures/count');
+    return this.http.get('/api/structures/count');
   }
   public setCountModules(category: Category, structureCountTab: { id: number; count: number }[]): Category {
     category.modules.forEach((m: Module) => {
-- 
GitLab


From 5a94bf4e393741c1cf465f3834e08b6c12ad23a3 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 15:51:09 +0100
Subject: [PATCH 43/50] fix(search) : fix review merge

---
 api/server.js                                 |  5 +-
 .../modal-filter/modal-filter.component.scss  |  4 +-
 .../components/search/search.component.html   | 14 +++---
 .../components/search/search.component.ts     | 49 ++++++++++---------
 src/app/structure-list/enum/typeModal.enum.ts |  5 ++
 .../models/structureCounter.model.ts          |  8 +++
 .../structure-list/services/search.service.ts | 10 ++--
 .../structure-list.component.html             |  1 -
 .../structure-list.component.scss             |  5 --
 9 files changed, 57 insertions(+), 44 deletions(-)
 create mode 100644 src/app/structure-list/enum/typeModal.enum.ts
 create mode 100644 src/app/structure-list/models/structureCounter.model.ts

diff --git a/api/server.js b/api/server.js
index 43c5b108c..e85ef232a 100644
--- a/api/server.js
+++ b/api/server.js
@@ -11,7 +11,6 @@ server.use(middlewares);
 
 // Add custom routes before JSON Server router
 server.get('/structures/count', (req, res) => {
-  console.log('ok');
   let structureCountTab = [];
   // Compétences de base
   structureCountTab.push({ id: 260, count: 3 });
@@ -62,9 +61,7 @@ server.get('/structures/count', (req, res) => {
   structureCountTab.push({ id: 164, count: 1 });
   structureCountTab.push({ id: 163, count: 1 });
   structureCountTab.push({ id: 162, count: 2 });
-  return res.status(200).jsonp({
-    structureCountTab,
-  });
+  return res.status(200).jsonp(structureCountTab);
 });
 
 // Use default router
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
index 5275c2945..ccb052e16 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.scss
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -5,14 +5,14 @@
 @import '../../../../assets/scss/shapes';
 @import '../../../../assets/scss/buttons';
 
-.modalformations {
+.modaltraining {
   @media #{$desktop} {
     margin-left: 0;
   }
 
   margin-left: 196px;
 }
-.modalplusFiltres {
+.modalmoreFilters {
   @media #{$desktop} {
     margin-left: 0;
   }
diff --git a/src/app/structure-list/components/search/search.component.html b/src/app/structure-list/components/search/search.component.html
index 44fa60bd2..9de95de24 100644
--- a/src/app/structure-list/components/search/search.component.html
+++ b/src/app/structure-list/components/search/search.component.html
@@ -14,7 +14,7 @@
         <div class="icon close" (click)="clearInput()">
           <div class="ico-close grey"></div>
         </div>
-        <div class="separator"></div>
+        <span class="separator"></span>
         <div class="icon pin">
           <div class="ico-pin-search blue"></div>
         </div>
@@ -28,8 +28,8 @@
   <div class="btnSection" fxLayout="row" fxLayoutAlign="space-between center">
     <button
       type="button"
-      [ngClass]="{ selected: modalTypeOpened === modalType[0] }"
-      (click)="openModal(this.modalType[0])"
+      [ngClass]="{ selected: modalTypeOpened === TypeModal[0] }"
+      (click)="openModal(TypeModal[0])"
       fxLayout="row"
       fxLayoutAlign="space-between center"
     >
@@ -38,8 +38,8 @@
     </button>
     <button
       type="button"
-      [ngClass]="{ selected: modalTypeOpened === modalType[1] }"
-      (click)="openModal(this.modalType[1])"
+      [ngClass]="{ selected: modalTypeOpened === TypeModal[1] }"
+      (click)="openModal(TypeModal[1])"
       fxLayout="row"
       fxLayoutAlign="space-between center"
     >
@@ -48,8 +48,8 @@
     </button>
     <button
       type="button"
-      [ngClass]="{ selected: modalTypeOpened === modalType[2] }"
-      (click)="openModal(this.modalType[2])"
+      [ngClass]="{ selected: modalTypeOpened === TypeModal[2] }"
+      (click)="openModal(TypeModal[2])"
       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 d95cf649b..1fb011826 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -1,8 +1,11 @@
 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
 import { FormBuilder, FormGroup } from '@angular/forms';
+import { forkJoin } from 'rxjs';
+import { TypeModal } from '../../enum/typeModal.enum';
 import { Category } from '../../models/category.model';
 import { Filter } from '../../models/filter.model';
 import { Module } from '../../models/module.model';
+import { StructureCounter } from '../../models/structureCounter.model';
 import { SearchService } from '../../services/search.service';
 
 @Component({
@@ -20,24 +23,26 @@ export class SearchComponent implements OnInit {
   @Output() searchEvent = new EventEmitter();
 
   // Form search input
-  searchForm: FormGroup;
-
-  // Button variable
-  modalType: string[] = ['accompagnement', 'formations', 'plusFiltres'];
-
+  private searchForm: FormGroup;
   // Modal variable
-  categories: Category[];
-  modalTypeOpened: string;
-
+  private categories: Category[];
+  private modalTypeOpened: string;
   // Checkbox variable
-  checkedModulesFilter: Module[];
+  private checkedModulesFilter: Module[];
 
   ngOnInit(): void {
     // Will store the different categories
     this.categories = [];
 
     this.checkedModulesFilter = new Array();
+    console.log(TypeModal[0]);
   }
+
+  // Accessor to template angular.
+  public get TypeModal(): typeof TypeModal {
+    return TypeModal;
+  }
+
   // Clear input search
   public clearInput(): void {
     this.searchForm.reset();
@@ -110,22 +115,22 @@ export class SearchComponent implements OnInit {
     module.push(category);
   }
 
-  // Fake data
+  // Get the correct list of checkbox/modules depending on the type of modal.
   private fakeData(option: string): void {
-    if (option === this.modalType[0]) {
+    if (option === TypeModal[0]) {
       this.mockService(this.categories, 'Accompagnement des démarches', { name: 'CAF', id: 5 }, 7);
-    } else if (option === this.modalType[1]) {
-      this.searchService.getCategoriesFormations().subscribe((categories: Category[]) => {
-        this.searchService
-          .getFakeCounterModule()
-          .subscribe((res: { structureCountTab: { id: number; count: number }[] }) => {
-            categories.forEach((category) => {
-              category = this.searchService.setCountModules(category, res.structureCountTab);
-              this.categories.push(category);
-            });
+    } else if (option === TypeModal[1]) {
+      forkJoin([this.searchService.getCategoriesFormations(), this.searchService.getFakeCounterModule()]).subscribe(
+        (res) => {
+          const categories: Category[] = res[0];
+          const structureCounter: StructureCounter[] = res[1];
+          categories.forEach((category) => {
+            category = this.searchService.setCountModules(category, structureCounter);
+            this.categories.push(category);
           });
-      });
-    } else if (option === this.modalType[2]) {
+        }
+      );
+    } else if (option === TypeModal[2]) {
       this.mockService(
         this.categories,
         'Équipements',
diff --git a/src/app/structure-list/enum/typeModal.enum.ts b/src/app/structure-list/enum/typeModal.enum.ts
new file mode 100644
index 000000000..ab391e2f6
--- /dev/null
+++ b/src/app/structure-list/enum/typeModal.enum.ts
@@ -0,0 +1,5 @@
+export enum TypeModal {
+  accompaniment,
+  training,
+  moreFilters,
+}
diff --git a/src/app/structure-list/models/structureCounter.model.ts b/src/app/structure-list/models/structureCounter.model.ts
new file mode 100644
index 000000000..d208192f0
--- /dev/null
+++ b/src/app/structure-list/models/structureCounter.model.ts
@@ -0,0 +1,8 @@
+export class StructureCounter {
+  id: number;
+  count: number;
+
+  constructor(obj?: any) {
+    Object.assign(this, obj);
+  }
+}
diff --git a/src/app/structure-list/services/search.service.ts b/src/app/structure-list/services/search.service.ts
index 906fc3aee..1b6a33b59 100644
--- a/src/app/structure-list/services/search.service.ts
+++ b/src/app/structure-list/services/search.service.ts
@@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { Category } from '../models/category.model';
 import { Module } from '../models/module.model';
+import { StructureCounter } from '../models/structureCounter.model';
 
 @Injectable({
   providedIn: 'root',
@@ -16,10 +17,13 @@ export class SearchService {
       .get('/api/CategoriesFormations')
       .pipe(map((data: any[]) => data.map((item) => new Category(item))));
   }
-  public getFakeCounterModule(): Observable<any> {
-    return this.http.get('/api/structures/count');
+
+  public getFakeCounterModule(): Observable<StructureCounter[]> {
+    return this.http
+      .get('/api/structures/count')
+      .pipe(map((data: any[]) => data.map((item) => new StructureCounter(item))));
   }
-  public setCountModules(category: Category, structureCountTab: { id: number; count: number }[]): Category {
+  public setCountModules(category: Category, structureCountTab: StructureCounter[]): Category {
     category.modules.forEach((m: Module) => {
       for (let i = 0; i < structureCountTab.length; i++) {
         if (structureCountTab[i].id === m.id) {
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index e0de815ee..95735d1d1 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,6 +1,5 @@
 <div class="topBlock">
   <app-structure-list-search (searchEvent)="fetchResults($event)"></app-structure-list-search>
-  <div class="divider"></div>
   <span class="nbStructuresLabel">{{ structureList.length }} structures</span>
 </div>
 
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
index 5b09b7ee8..ee31dcc05 100644
--- a/src/app/structure-list/structure-list.component.scss
+++ b/src/app/structure-list/structure-list.component.scss
@@ -2,11 +2,6 @@
 @import '../../assets/scss/icons';
 @import '../../assets/scss/typography';
 
-.divider {
-  width: 100%;
-  height: 1px;
-  background-color: $grey-4;
-}
 .nbStructuresLabel {
   color: $grey;
   @include cn-regular-16;
-- 
GitLab


From aa058269ad28874fc4b4e99472eb3ed0bf8b75e8 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 16:16:43 +0100
Subject: [PATCH 44/50] fix(search) : fix review request merge

---
 debug.log                                     |  1 +
 .../modal-filter/modal-filter.component.html  |  2 +-
 .../modal-filter/modal-filter.component.scss  |  1 -
 .../modal-filter.component.spec.ts            | 14 +++++++++++---
 .../modal-filter/modal-filter.component.ts    |  8 ++++----
 .../components/search/search.component.scss   |  1 -
 .../search/search.component.spec.ts           |  4 ++--
 .../components/search/search.component.ts     |  3 +--
 .../services/search.service.spec.ts           | 19 +++++++++++++++++++
 9 files changed, 39 insertions(+), 14 deletions(-)
 create mode 100644 debug.log

diff --git a/debug.log b/debug.log
new file mode 100644
index 000000000..a9f90adc5
--- /dev/null
+++ b/debug.log
@@ -0,0 +1 @@
+[1102/160447.168:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
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
index d006c7cac..12b002559 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.html
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.html
@@ -27,7 +27,7 @@
     </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>
+      <button type="button" (click)="emitFilter()">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
index ccb052e16..420969748 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.scss
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -113,7 +113,6 @@
     }
   }
   label {
-    //display: inline-grid;
     align-items: center;
     grid-template-columns: min-content auto;
     display: inline-grid;
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
index 5228b636c..bf696da42 100644
--- 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
@@ -1,4 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { Filter } from '../../models/filter.model';
 
 import { ModalFilterComponent } from './modal-filter.component';
 
@@ -8,9 +10,9 @@ describe('ModalFilterComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ ModalFilterComponent ]
-    })
-    .compileComponents();
+      declarations: [ModalFilterComponent],
+      imports: [ReactiveFormsModule],
+    }).compileComponents();
   });
 
   beforeEach(() => {
@@ -22,4 +24,10 @@ describe('ModalFilterComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should emit filters', () => {
+    spyOn(component.searchEvent, 'emit');
+    component.emitFilter();
+    expect(component.searchEvent.emit).toHaveBeenCalled();
+  });
 });
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
index 3be4344db..ff6050e60 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.ts
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.ts
@@ -17,7 +17,7 @@ export class ModalFilterComponent implements OnInit {
   }
   @Input() public modalType: string;
   @Input() public categories: Category[];
-  @Input() public modules: Module[];
+  @Input() public modules: Module[] = [];
   @Output() searchEvent = new EventEmitter();
   // Checkbox variable
   checkedModules: Module[];
@@ -29,12 +29,12 @@ export class ModalFilterComponent implements OnInit {
   }
 
   // Return index of a specific module in array modules
-  public getIndex(id: number, categ: string): number {
+  private 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 {
+  private onCheckboxChange(event, categ: string): void {
     const checkValue: number = parseInt(event.target.value, 10);
     if (event.target.checked) {
       this.checkedModules.push(new Module(checkValue, categ));
@@ -47,7 +47,7 @@ export class ModalFilterComponent implements OnInit {
   }
 
   // Clear only filters in the current modal
-  public clearFilters(): void {
+  private clearFilters(): void {
     this.categories.forEach((categ: Category) => {
       categ.modules.forEach((module: Module) => {
         if (this.getIndex(module.id, categ.name) > -1) {
diff --git a/src/app/structure-list/components/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 5b8368862..279b2772b 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -101,7 +101,6 @@
     }
   }
   label {
-    //display: inline-grid;
     align-items: center;
     grid-template-columns: min-content auto;
     display: inline-grid;
diff --git a/src/app/structure-list/components/search/search.component.spec.ts b/src/app/structure-list/components/search/search.component.spec.ts
index 790ae3595..a5507ed76 100644
--- a/src/app/structure-list/components/search/search.component.spec.ts
+++ b/src/app/structure-list/components/search/search.component.spec.ts
@@ -5,7 +5,7 @@ import { Filter } from '../../models/filter.model';
 import { Module } from '../../models/module.model';
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { SearchComponent } from './search.component';
-import { SearchService } from '../../services/search.service';
+import { TypeModal } from '../../enum/typeModal.enum';
 
 describe('SearchComponent', () => {
   let component: SearchComponent;
@@ -42,7 +42,7 @@ describe('SearchComponent', () => {
     for (let i = 0; i < 7; i++) {
       categories[0].modules.push(new Module(5 + i, 'CAF' + i));
     }
-    component.openModal('accompagnement');
+    component.openModal(TypeModal[0]);
     expect(component.categories).toEqual(categories);
   });
 });
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 1fb011826..6db165c6c 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -25,7 +25,7 @@ export class SearchComponent implements OnInit {
   // Form search input
   private searchForm: FormGroup;
   // Modal variable
-  private categories: Category[];
+  public categories: Category[];
   private modalTypeOpened: string;
   // Checkbox variable
   private checkedModulesFilter: Module[];
@@ -35,7 +35,6 @@ export class SearchComponent implements OnInit {
     this.categories = [];
 
     this.checkedModulesFilter = new Array();
-    console.log(TypeModal[0]);
   }
 
   // Accessor to template angular.
diff --git a/src/app/structure-list/services/search.service.spec.ts b/src/app/structure-list/services/search.service.spec.ts
index d8b757560..4da5c5954 100644
--- a/src/app/structure-list/services/search.service.spec.ts
+++ b/src/app/structure-list/services/search.service.spec.ts
@@ -1,6 +1,9 @@
 import { TestBed } from '@angular/core/testing';
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { SearchService } from './search.service';
+import { StructureCounter } from '../models/structureCounter.model';
+import { Category } from '../models/category.model';
+import { Module } from '../models/module.model';
 
 describe('SearchService', () => {
   let service: SearchService;
@@ -15,4 +18,20 @@ describe('SearchService', () => {
   it('should be created', () => {
     expect(service).toBeTruthy();
   });
+
+  it('should return category with number of modules inside', () => {
+    const structureCount: StructureCounter[] = [
+      { id: 176, count: 2 },
+      { id: 172, count: 1 },
+      { id: 173, count: 1 },
+    ];
+    const m1: Module = { id: 176, text: 'strm1', count: 0 };
+    const m2: Module = { id: 173, text: 'strm2', count: 0 };
+    const m3: Module = { id: 172, text: 'strm3', count: 0 };
+    const category: Category = { name: 'strCateg', modules: [m1, m2, m3] };
+    const result = service.setCountModules(category, structureCount);
+    expect(result.modules[0].count).toBe(2);
+    expect(result.modules[1].count).toBe(1);
+    expect(result.modules[2].count).toBe(1);
+  });
 });
-- 
GitLab


From 1ea5c8f619afca077ca7265f1281576f71f03f9c Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 17:35:31 +0100
Subject: [PATCH 45/50] fix(search) : Add unit test

---
 debug.log                                     |  1 +
 .../modal-filter/modal-filter.component.html  |  2 +-
 .../modal-filter.component.spec.ts            | 62 ++++++++++++++++++-
 .../modal-filter/modal-filter.component.ts    | 10 +--
 .../components/search/search.component.ts     |  6 +-
 5 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/debug.log b/debug.log
index a9f90adc5..301edff39 100644
--- a/debug.log
+++ b/debug.log
@@ -1 +1,2 @@
 [1102/160447.168:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
+[1102/165734.564:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
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
index 12b002559..ec2d69fb0 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.html
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.html
@@ -27,7 +27,7 @@
     </div>
     <div class="footer" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="3vw">
       <a (click)="clearFilters()">Effacer</a>
-      <button type="button" (click)="emitFilter()">Appliquer</button>
+      <button type="button" (click)="emitModules()">Appliquer</button>
     </div>
   </div>
 </div>
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
index bf696da42..9c1ad3d14 100644
--- 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
@@ -1,6 +1,8 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { ReactiveFormsModule } from '@angular/forms';
+import { Category } from '../../models/category.model';
 import { Filter } from '../../models/filter.model';
+import { Module } from '../../models/module.model';
 
 import { ModalFilterComponent } from './modal-filter.component';
 
@@ -25,9 +27,65 @@ describe('ModalFilterComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  it('should emit filters', () => {
+  it('should emit modules', () => {
+    const modules: Module[] = [
+      { id: 176, text: 'training', count: 3 },
+      { id: 173, text: 'training', count: 2 },
+      { id: 172, text: 'training', count: 2 },
+    ];
+    component.checkedModules = modules;
     spyOn(component.searchEvent, 'emit');
-    component.emitFilter();
+    component.emitModules();
     expect(component.searchEvent.emit).toHaveBeenCalled();
+    expect(component.searchEvent.emit).toHaveBeenCalledWith(modules);
+  });
+  it('should return an index or -1', () => {
+    const modules: Module[] = [
+      { id: 176, text: 'training', count: 0 },
+      { id: 173, text: 'training', count: 0 },
+      { id: 172, text: 'training', count: 0 },
+    ];
+    component.checkedModules = modules;
+    const foundItem = component.getIndex(173, 'training');
+    const notFoundItem = component.getIndex(189, 'training');
+    expect(foundItem).toEqual(1);
+    expect(notFoundItem).toEqual(-1);
+  });
+  it('should add a module to checkedModule array', () => {
+    const modules: Module[] = [
+      { id: 176, text: 'training', count: 0 },
+      { id: 173, text: 'training', count: 0 },
+      { id: 172, text: 'training', count: 0 },
+    ];
+    component.checkedModules = modules;
+    const evt = { target: { checked: true, value: 175 } };
+    component.onCheckboxChange(evt, 'training');
+    expect(component.checkedModules.length).toEqual(4);
+  });
+  it('should remove a module to checkedModule array', () => {
+    const modules: Module[] = [
+      { id: 176, text: 'training', count: 0 },
+      { id: 173, text: 'training', count: 0 },
+      { id: 172, text: 'training', count: 0 },
+    ];
+    component.checkedModules = modules;
+    const evt = { target: { checked: false, value: 173 } };
+    component.onCheckboxChange(evt, 'training');
+    expect(component.checkedModules.length).toEqual(2);
+  });
+  it('should remove all modules checked from same modal, here morefilters', () => {
+    const modules: Module[] = [
+      { id: 176, text: 'morefilters', count: 0 },
+      { id: 173, text: 'morefilters', count: 0 },
+      { id: 172, text: 'morefilters', count: 0 },
+      { id: 179, text: 'training', count: 0 },
+      { id: 190, text: 'training', count: 0 },
+      { id: 167, text: 'training', count: 0 },
+    ];
+    component.checkedModules = modules;
+    const category: Category = { name: 'morefilters', modules: [modules[0], modules[1], modules[2]] };
+    component.categories = [category];
+    component.clearFilters();
+    expect(component.checkedModules.length).toEqual(3);
   });
 });
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
index ff6050e60..2f46075fa 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.ts
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.ts
@@ -29,12 +29,12 @@ export class ModalFilterComponent implements OnInit {
   }
 
   // Return index of a specific module in array modules
-  private getIndex(id: number, categ: string): number {
+  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)
-  private onCheckboxChange(event, categ: string): void {
+  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));
@@ -47,7 +47,7 @@ export class ModalFilterComponent implements OnInit {
   }
 
   // Clear only filters in the current modal
-  private clearFilters(): void {
+  public clearFilters(): void {
     this.categories.forEach((categ: Category) => {
       categ.modules.forEach((module: Module) => {
         if (this.getIndex(module.id, categ.name) > -1) {
@@ -57,8 +57,8 @@ export class ModalFilterComponent implements OnInit {
     });
   }
 
-  // Sends an array containing all filters
-  public emitFilter(): void {
+  // Sends an array containing all modules
+  public emitModules(): void {
     this.searchEvent.emit(this.checkedModules);
   }
 }
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 6db165c6c..5ad6e6a1f 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -23,12 +23,12 @@ export class SearchComponent implements OnInit {
   @Output() searchEvent = new EventEmitter();
 
   // Form search input
-  private searchForm: FormGroup;
+  public searchForm: FormGroup;
   // Modal variable
   public categories: Category[];
-  private modalTypeOpened: string;
+  public modalTypeOpened: string;
   // Checkbox variable
-  private checkedModulesFilter: Module[];
+  public checkedModulesFilter: Module[];
 
   ngOnInit(): void {
     // Will store the different categories
-- 
GitLab


From 82f2a129a935fc350b1bdeded742fb1116b90258 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Mon, 2 Nov 2020 17:36:08 +0100
Subject: [PATCH 46/50] Update debug.log

---
 debug.log | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/debug.log b/debug.log
index 301edff39..168913fe1 100644
--- a/debug.log
+++ b/debug.log
@@ -1,2 +1 @@
-[1102/160447.168:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
-[1102/165734.564:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d’accès spécifié est introuvable. (0x3)
+[1102/160447.168:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d�acc�s sp�cifi� est introuvable. (0x3)
-- 
GitLab


From 4be3f698d993e30918ee555b7c8eb5522aea58e9 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Mon, 2 Nov 2020 17:39:24 +0100
Subject: [PATCH 47/50] fix: put checkbox style in global style + small fixes

---
 .../modal-filter/modal-filter.component.scss  | 55 ------------------
 .../components/search/search.component.scss   | 54 +-----------------
 .../components/search/search.component.ts     | 10 ++--
 src/styles.scss                               | 56 +++++++++++++++++++
 4 files changed, 61 insertions(+), 114 deletions(-)

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
index 420969748..8317c3f19 100644
--- a/src/app/structure-list/components/modal-filter/modal-filter.component.scss
+++ b/src/app/structure-list/components/modal-filter/modal-filter.component.scss
@@ -99,58 +99,3 @@
     }
   }
 }
-.checkbox {
-  list-style-type: none;
-  input {
-    opacity: 0;
-    display: none;
-    &:checked ~ .customCheck {
-      background-color: $orange-light;
-      border-color: transparent;
-    }
-    &:checked ~ .customCheck:after {
-      display: block;
-    }
-  }
-  label {
-    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/search/search.component.scss b/src/app/structure-list/components/search/search.component.scss
index 279b2772b..6ee105f2f 100644
--- a/src/app/structure-list/components/search/search.component.scss
+++ b/src/app/structure-list/components/search/search.component.scss
@@ -49,6 +49,7 @@
       @include background-hash;
       padding: 0 0 4px 5px;
       button {
+        border-radius: 6px;
         @include btn-search;
         @include cn-bold-14;
       }
@@ -87,59 +88,6 @@
   }
 }
 
-.checkbox {
-  list-style-type: none;
-  input {
-    opacity: 0;
-    display: none;
-    &:checked ~ .customCheck {
-      background-color: $orange-light;
-      border-color: transparent;
-    }
-    &:checked ~ .customCheck:after {
-      display: block;
-    }
-  }
-  label {
-    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;
-      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);
-    }
-  }
-}
 .footerSearchSection {
   margin: 17px 0px 17px 0px;
 
diff --git a/src/app/structure-list/components/search/search.component.ts b/src/app/structure-list/components/search/search.component.ts
index 5ad6e6a1f..10f0393f2 100644
--- a/src/app/structure-list/components/search/search.component.ts
+++ b/src/app/structure-list/components/search/search.component.ts
@@ -51,7 +51,7 @@ export class SearchComponent implements OnInit {
   // Sends an array containing all filters
   public applyFilter(term: string): void {
     // Add search input filter
-    let filters: Filter[] = [];
+    const filters: Filter[] = [];
     if (term) {
       filters.push(new Filter('nomDeVotreStructure', term, false));
     }
@@ -69,7 +69,7 @@ export class SearchComponent implements OnInit {
   }
 
   public fetchResults(checkedModules: Module[]): void {
-    let inputTerm = this.searchForm.get('searchTerm').value;
+    const inputTerm = this.searchForm.get('searchTerm').value;
 
     // Store checked modules
     this.checkedModulesFilter = checkedModules;
@@ -91,7 +91,7 @@ export class SearchComponent implements OnInit {
   }
 
   private fromStringToIdExcel(categ: string): string {
-    let splitStr = categ.toLowerCase().split(' ');
+    const splitStr = categ.toLowerCase().split(' ');
     for (let i = 1; i < splitStr.length; i++) {
       splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
     }
@@ -105,9 +105,7 @@ export class SearchComponent implements OnInit {
 
   // Fake service api
   private mockService(module: Category[], titre: string, categ: any, nbCateg: number): void {
-    const category = new Category();
-    category.name = titre;
-    category.modules = [];
+    const category = new Category({ name: titre, modules: [] });
     for (let i = 0; i < nbCateg; i++) {
       category.modules.push(new Module(categ.id + i, categ.name + i));
     }
diff --git a/src/styles.scss b/src/styles.scss
index b0d48863f..8f149c3a9 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -68,3 +68,59 @@ a {
     width: unset;
   }
 }
+
+/** Checkboxes **/
+
+.checkbox {
+  list-style-type: none;
+  input {
+    opacity: 0;
+    display: none;
+    &:checked ~ .customCheck {
+      background-color: $primary-color;
+      border-color: transparent;
+    }
+    &:checked ~ .customCheck:after {
+      display: block;
+    }
+  }
+  label {
+    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;
+      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);
+    }
+  }
+}
-- 
GitLab


From 4b9254baf0f2153040e779983ce1b8693425adc1 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Mon, 2 Nov 2020 17:40:35 +0100
Subject: [PATCH 48/50] fix: remove debug.log

---
 debug.log | 1 -
 1 file changed, 1 deletion(-)
 delete mode 100644 debug.log

diff --git a/debug.log b/debug.log
deleted file mode 100644
index 168913fe1..000000000
--- a/debug.log
+++ /dev/null
@@ -1 +0,0 @@
-[1102/160447.168:ERROR:directory_reader_win.cc(43)] FindFirstFile: Le chemin d�acc�s sp�cifi� est introuvable. (0x3)
-- 
GitLab


From e0ebab2600dff44cbf241a5f5068209c2bfbf397 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Tue, 3 Nov 2020 09:18:45 +0100
Subject: [PATCH 49/50] fix: build budget

---
 angular.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/angular.json b/angular.json
index 20abea0c5..6e95360f6 100644
--- a/angular.json
+++ b/angular.json
@@ -70,8 +70,8 @@
                 },
                 {
                   "type": "anyComponentStyle",
-                  "maximumWarning": "6kb",
-                  "maximumError": "10kb"
+                  "maximumWarning": "10kb",
+                  "maximumError": "15kb"
                 }
               ]
             },
-- 
GitLab


From c0f25b1a18df364e6dba539caaf4a2374bd589cf Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Tue, 3 Nov 2020 09:55:45 +0100
Subject: [PATCH 50/50] feat: update back deploy

---
 api/Dockerfile   | 11 ++++-------
 api/package.json |  4 ++--
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/api/Dockerfile b/api/Dockerfile
index 4a8add9b9..8866e160e 100644
--- a/api/Dockerfile
+++ b/api/Dockerfile
@@ -1,18 +1,15 @@
-# Stage 0, based on Node.js
-FROM node:12.16-slim
+# Based on Node.js
+FROM node:12.16
 
 WORKDIR /app
 
 # Copy the package.json file first in order to cache the modules
 COPY . .
 
-RUN mkdir api
-RUN cp routes.json ./api
-
 # Install npm dependencies
 RUN npm install
 
 # expose port 3000
-EXPOSE 80 3000
+EXPOSE 3000
 
-CMD ["npm", "run", "api"]
+CMD ["npm", "start"]
diff --git a/api/package.json b/api/package.json
index a74b88aa6..997401923 100644
--- a/api/package.json
+++ b/api/package.json
@@ -1,8 +1,8 @@
 {
   "name": "pamn-mock-api",
-  "version": "0.0.1",
+  "version": "0.1.0",
   "scripts": {
-    "api": "json-server api/db.json --routes api/routes.json --no-cors=true"
+    "start": "node server.js"
   },
   "private": true,
   "dependencies": {
-- 
GitLab