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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 b2fdd75ba94f05bb6d9ca52def3f4d600bcfcec9 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 09:58:18 +0200
Subject: [PATCH 08/20] fix(card) : change char dist

---
 src/app/structure/components/card/card.component.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index e2443b8c8..ab0ce63ce 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -4,7 +4,7 @@
 
   <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between center">
     <span class="typeStructure">{{ structure.type_de_structure }}</span>
-    <span class="distanceStructure">|-| 63 m</span>
+    <span class="distanceStructure">├─┤ 63 m</span>
   </div>
   <br />
   <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="1vw">
-- 
GitLab


From 6fccc3d90482fa4f42bfe4788e23fa5a9e4c6c79 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 10:11:33 +0200
Subject: [PATCH 09/20] fix(card) : use global color

---
 src/assets/scss/_color.scss | 2 ++
 src/assets/scss/_icons.scss | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/assets/scss/_color.scss b/src/assets/scss/_color.scss
index e1ac547a8..2a650bee2 100644
--- a/src/assets/scss/_color.scss
+++ b/src/assets/scss/_color.scss
@@ -14,6 +14,8 @@ $yellow-light: #fff8d6;
 $orange: #f27405;
 $orange-light: #f29f05;
 $orange-3: #fff4ea;
+/* GREEN */
+$green: #41c29c;
 /* OTHERS */
 $blue: #b3f8f8;
 $purple: #594d59;
diff --git a/src/assets/scss/_icons.scss b/src/assets/scss/_icons.scss
index a44fae8f2..de969d5b3 100644
--- a/src/assets/scss/_icons.scss
+++ b/src/assets/scss/_icons.scss
@@ -67,14 +67,14 @@
 .ico-dot-available {
   height: 12px;
   width: 12px;
-  background-color: #41c29c;
+  background-color: $green;
   border-radius: 50%;
   display: inline-block;
 }
 .ico-dot-unavailable {
   height: 12px;
   width: 12px;
-  background-color: #b7b7b7;
+  background-color: $grey;
   border-radius: 50%;
   display: inline-block;
 }
-- 
GitLab


From 1c22bf0e097a345c02e5f38841e58c32360af2dc Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 10:15:34 +0200
Subject: [PATCH 10/20] fix(card) : fix space btw icon and status text

---
 src/app/structure/components/card/card.component.html | 4 ++--
 src/app/structure/components/card/card.component.scss | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index ab0ce63ce..9652e8d66 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -7,10 +7,10 @@
     <span class="distanceStructure">├─┤ 63 m</span>
   </div>
   <br />
-  <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="1vw">
+  <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center">
     <div *ngIf="structure.estOuvert; else closed">
       <span class="ico-dot-available"></span>
-      <span> Ouvert actuellement</span>
+      <span>Ouvert actuellement</span>
     </div>
     <ng-template #closed>
       <span class="ico-dot-unavailable"></span>
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure/components/card/card.component.scss
index f3f374801..0f2322644 100644
--- a/src/app/structure/components/card/card.component.scss
+++ b/src/app/structure/components/card/card.component.scss
@@ -48,5 +48,6 @@
     font-weight: normal;
     font-size: 15px;
     line-height: 103%;
+    margin-right: 8px;
   }
 }
-- 
GitLab


From 490f1ecae36122c99fb3a4504980676135c3b48f Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 10:57:47 +0200
Subject: [PATCH 11/20] fix(card) : add models + type method&return + use TS
 variable declaration

---
 .../components/card/card.component.html       |  6 +-
 .../components/card/card.component.ts         |  1 +
 src/app/structure/models/structure.model.ts   | 13 +++
 .../structure/services/structure.service.ts   | 96 ++++++++-----------
 4 files changed, 56 insertions(+), 60 deletions(-)

diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index 9652e8d66..d9bd09750 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -18,8 +18,8 @@
         Fermé - Ouvre {{ structure.ouvreLe.jour }} à {{ structure.ouvreLe.horaire }}</span
       >
     </ng-template>
+    <ng-template #noTime>
+      <span> Fermé - {{ 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.ts b/src/app/structure/components/card/card.component.ts
index ad3154950..a5d6f4109 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure/components/card/card.component.ts
@@ -14,6 +14,7 @@ export class CardComponent implements OnInit {
 
   ngOnInit(): void {
     var dt = DateTime.local();
+    console.log(typeof dt);
     this._structureService.recupererStructures().subscribe((structures: Structure[]) => {
       structures.forEach((s: Structure) => {
         this.structures.push(this._structureService.majOuvertureStructure(s, dt));
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
index 5617a7948..d186d809c 100644
--- a/src/app/structure/models/structure.model.ts
+++ b/src/app/structure/models/structure.model.ts
@@ -42,3 +42,16 @@ export class Jour {
   open: boolean;
   time: { openning: number; closing: number }[];
 }
+export class JourOuverture {
+  jour: string;
+  horaire: string;
+}
+export enum JourSemaine {
+  lundi = 1,
+  mardi,
+  mercredi,
+  jeudi,
+  vendredi,
+  samedi,
+  dimanche,
+}
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
index f18978024..c88f734c7 100644
--- a/src/app/structure/services/structure.service.ts
+++ b/src/app/structure/services/structure.service.ts
@@ -1,6 +1,7 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { Jour, Structure } from '../models/structure.model';
+import { Observable } from 'rxjs';
+import { Jour, JourOuverture, Structure, JourSemaine } from '../models/structure.model';
 
 @Injectable({
   providedIn: 'root',
@@ -8,24 +9,24 @@ import { Jour, Structure } from '../models/structure.model';
 export class StructureService {
   constructor(private http: HttpClient) {}
 
-  recupererStructures() {
+  public recupererStructures(): Observable<any> {
     return this.http.get('/api/Structures');
   }
 
-  majOuvertureStructure(structure: Structure, dateActuelle: any) {
-    //Récupère le jour de la semaine.
-    var jourSemaine: number = dateActuelle.weekday;
+  public majOuvertureStructure(structure: Structure, dateActuelle: any): Structure {
+    // Récupère le jour de la semaine
+    const jourSemaine: number = dateActuelle.weekday;
 
-    //Vérifie si les minutes commencent par zéro pour éviter la suppression.
-    var now: number;
+    // Vérifie si les minutes commencent par zéro pour éviter la suppression
+    let 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);
+    // Récupérer les horaires d'une structure en fonction de son jour pour indiquer si elle est ouverte
+    const horaireStructure: Jour = this.recupererHoraire(structure, jourSemaine);
     structure.estOuvert = false;
     if (horaireStructure.open) {
       horaireStructure.time.forEach((periode) => {
@@ -38,8 +39,8 @@ export class StructureService {
     return structure;
   }
 
-  //Récupère les horaires d'une structure en fonction du jour de la semaine
-  recupererHoraire(structure: Structure, jourActuel: number) {
+  // Récupère les horaires d'une structure en fonction du jour de la semaine
+  private recupererHoraire(structure: Structure, jourActuel: number): Jour {
     switch (jourActuel) {
       case 1:
         return structure.horaires.lundi;
@@ -59,104 +60,85 @@ export class StructureService {
         return null;
     }
   }
-  //Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
-  comparerHoraire(heureDeb: number, heureFin: number, heureActuelle: number) {
+  // Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
+  private comparerHoraire(heureDeb: number, heureFin: number, heureActuelle: number): Boolean {
     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) {
+  private recupererProchaineOuverture(s: Structure, j: number, baseJour: number, baseHeure: number): JourOuverture {
+    // Récupérer horaire du jour en cours
+    const 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;
+        // Vérifie si le compteur correspond au jour en cours pour éviter de proposer
+        // les horaires déjà passés
+        if (j !== baseJour) {
+          let jourOuverture: JourOuverture;
           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.
+          // 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;
+          let jourOuverture: JourOuverture;
           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.
+          // 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) {
+        // 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.
+        // 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.
+        // 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;
+    const lastChancehoraire = this.recupererHoraire(s, j + 1);
+    let lastJour: JourOuverture;
     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';
+        lastJour = { jour: '', horaire: 'Aucun horaire disponible' };
       });
     } else {
-      lastJour = 'Aucun horaire disponible';
+      lastJour = { jour: '', horaire: '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;
-    }
+  private numberToDay(n: number): string {
+    return JourSemaine[n];
   }
 
-  numberToHour(n: number) {
+  private numberToHour(n: number): string {
     if (n.toString().length == 3) {
-      var tabNum = n.toString().match(/.{1,1}/g);
+      const 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);
+      const tabNum = n.toString().match(/.{1,2}/g);
       return tabNum[0] + 'h' + tabNum[1];
     }
   }
-- 
GitLab


From 5173aae72dd9470f360de1b1ca78d698715e177a Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 16:07:17 +0200
Subject: [PATCH 12/20] fix(card) : camelCase update + fr to en

---
 .../components/card/card.component.html       |  10 +-
 .../components/card/card.component.ts         |   8 +-
 src/app/structure/models/structure.model.ts   |  57 ++++----
 .../structure/services/structure.service.ts   | 129 +++++++++---------
 4 files changed, 103 insertions(+), 101 deletions(-)

diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure/components/card/card.component.html
index d9bd09750..b2e9ee55a 100644
--- a/src/app/structure/components/card/card.component.html
+++ b/src/app/structure/components/card/card.component.html
@@ -3,23 +3,23 @@
   <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="typeStructure">{{ structure.typeDeStructure }}</span>
     <span class="distanceStructure">├─┤ 63 m</span>
   </div>
   <br />
   <div class="statusStructure" fxLayout="row" fxLayoutAlign="start center">
-    <div *ngIf="structure.estOuvert; else closed">
+    <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.ouvreLe.jour; else noTime">
-        Fermé - Ouvre {{ structure.ouvreLe.jour }} à {{ structure.ouvreLe.horaire }}</span
+      <span *ngIf="structure.openedOn.day; else noTime">
+        Fermé - Ouvre {{ structure.openedOn.day }} à {{ structure.openedOn.schedule }}</span
       >
     </ng-template>
     <ng-template #noTime>
-      <span> Fermé - {{ structure.ouvreLe.horaire }}</span>
+      <span> Fermé - {{ structure.openedOn.schedule }}</span>
     </ng-template>
   </div>
 </div>
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure/components/card/card.component.ts
index a5d6f4109..56802c487 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure/components/card/card.component.ts
@@ -10,14 +10,12 @@ const { DateTime } = require('luxon');
 })
 export class CardComponent implements OnInit {
   structures: Structure[] = [];
-  constructor(private _structureService: StructureService) {}
+  constructor(private structureService: StructureService) {}
 
   ngOnInit(): void {
-    var dt = DateTime.local();
-    console.log(typeof dt);
-    this._structureService.recupererStructures().subscribe((structures: Structure[]) => {
+    this.structureService.getStructures().subscribe((structures: Structure[]) => {
       structures.forEach((s: Structure) => {
-        this.structures.push(this._structureService.majOuvertureStructure(s, dt));
+        this.structures.push(this.structureService.updateOpeningStructure(s, DateTime.local()));
       });
     });
   }
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure/models/structure.model.ts
index d186d809c..8dea2e9a0 100644
--- a/src/app/structure/models/structure.model.ts
+++ b/src/app/structure/models/structure.model.ts
@@ -1,11 +1,11 @@
 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;
+  dateDeCreation: string;
+  derniereModification: string;
+  nomDeLusager: string;
+  votreStructureEstElle: string;
+  nomDeVotreStructure: string;
+  typeDeStructure: string;
   description: string;
   n: string;
   voie: string;
@@ -18,35 +18,38 @@ export class Structure {
   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[];
+  accessibilitePersonnesAMobiliteReduitePmr: boolean;
+  jaccompagneLesUsagersDansLeursDemarchesEnLigne: boolean;
+  accompagnementDesDemarches: string[];
   wifi: boolean;
-  horaires: horaireStructure;
-  estOuvert: boolean;
-  ouvreLe: { jour: string; horaire: string };
+  horaires: structureSchedules;
+  isOpen: boolean;
+  openedOn: OpeningDay;
 }
 
-export class horaireStructure {
-  lundi: Jour;
-  mardi: Jour;
-  mercredi: Jour;
-  jeudi: Jour;
-  vendredi: Jour;
-  samedi: Jour;
-  dimanche: Jour;
+export class structureSchedules {
+  lundi: Day;
+  mardi: Day;
+  mercredi: Day;
+  jeudi: Day;
+  vendredi: Day;
+  samedi: Day;
+  dimanche: Day;
 }
-export class Jour {
+export class Day {
   open: boolean;
-  time: { openning: number; closing: number }[];
+  time: Time[];
 }
-export class JourOuverture {
-  jour: string;
-  horaire: string;
+export class Time {
+  openning: number;
+  closing: number;
 }
-export enum JourSemaine {
+export class OpeningDay {
+  day: string;
+  schedule: string;
+}
+export enum Weekday {
   lundi = 1,
   mardi,
   mercredi,
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure/services/structure.service.ts
index c88f734c7..f2f5a0cb4 100644
--- a/src/app/structure/services/structure.service.ts
+++ b/src/app/structure/services/structure.service.ts
@@ -1,7 +1,7 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
-import { Jour, JourOuverture, Structure, JourSemaine } from '../models/structure.model';
+import { OpeningDay, Structure, Weekday, Day, Time } from '../models/structure.model';
 
 @Injectable({
   providedIn: 'root',
@@ -9,39 +9,39 @@ import { Jour, JourOuverture, Structure, JourSemaine } from '../models/structure
 export class StructureService {
   constructor(private http: HttpClient) {}
 
-  public recupererStructures(): Observable<any> {
+  public getStructures(): Observable<any> {
     return this.http.get('/api/Structures');
   }
 
-  public majOuvertureStructure(structure: Structure, dateActuelle: any): Structure {
-    // Récupère le jour de la semaine
-    const jourSemaine: number = dateActuelle.weekday;
+  public updateOpeningStructure(structure: Structure, currentDate: any): Structure {
+    // Get current day of week
+    const dayOfWeek: number = currentDate.weekday;
 
-    // Vérifie si les minutes commencent par zéro pour éviter la suppression
+    // Checks if minutes start with zero to avoid deletion
     let now: number;
-    if (dateActuelle.minute.toString().length != 1) {
-      now = parseInt('' + dateActuelle.hour + dateActuelle.minute, 10);
+    if (currentDate.minute.toString().length != 1) {
+      now = parseInt('' + currentDate.hour + currentDate.minute, 10);
     } else {
-      now = parseInt('' + dateActuelle.hour + 0 + dateActuelle.minute, 10);
+      now = parseInt('' + currentDate.hour + 0 + currentDate.minute, 10);
     }
 
-    // Récupérer les horaires d'une structure en fonction de son jour pour indiquer si elle est ouverte
-    const 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;
+    // Get the schedules of a structure according to his day to indicate if it's open
+    const structureSchedules: Day = this.getSchedules(structure, dayOfWeek);
+    structure.isOpen = false;
+    if (structureSchedules.open) {
+      structureSchedules.time.forEach((period: Time) => {
+        if (this.compareSchedules(period.openning, period.closing, now)) {
+          structure.isOpen = true;
         }
       });
     }
-    structure.ouvreLe = this.recupererProchaineOuverture(structure, jourSemaine, jourSemaine, now);
+    structure.openedOn = this.getNextOpening(structure, dayOfWeek, dayOfWeek, now);
     return structure;
   }
 
-  // Récupère les horaires d'une structure en fonction du jour de la semaine
-  private recupererHoraire(structure: Structure, jourActuel: number): Jour {
-    switch (jourActuel) {
+  // Get the schedules of a structure according to the day of the week
+  private getSchedules(structure: Structure, currentDay: number): Day {
+    switch (currentDay) {
       case 1:
         return structure.horaires.lundi;
       case 2:
@@ -60,77 +60,78 @@ export class StructureService {
         return null;
     }
   }
-  // Vérifie si l'heure actuelle est dans l'interval des horaires de la structure
-  private comparerHoraire(heureDeb: number, heureFin: number, heureActuelle: number): Boolean {
-    return heureActuelle >= heureDeb && heureActuelle <= heureFin;
+
+  // Checks if the current time is in the time interval of the structure
+  private compareSchedules(startTime: number, endTime: number, currentTime: number): Boolean {
+    return currentTime >= startTime && currentTime <= endTime;
   }
 
-  private recupererProchaineOuverture(s: Structure, j: number, baseJour: number, baseHeure: number): JourOuverture {
-    // Récupérer horaire du jour en cours
-    const 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) {
-          let jourOuverture: JourOuverture;
-          horaires.time.every((periode) => {
-            if (periode.openning) {
-              jourOuverture = { jour: this.numberToDay(j), horaire: this.numberToHour(periode.openning) };
+  private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
+    // Get the schedules of current day
+    const schedules = this.getSchedules(s, j);
+    // Condition to stop recursion (If the counter day is equal to the current day)
+    if (j + 1 !== dayBase) {
+      if (schedules.open) {
+        // Check if the counter corresponds to the current day to avoid proposing the schedules already passed
+        if (j !== dayBase) {
+          let openingDay: OpeningDay;
+          schedules.time.every((period: Time) => {
+            if (period.openning) {
+              openingDay = { day: this.numberToDay(j), schedule: this.numberToHour(period.openning) };
               return false;
             }
           });
-          // Si pas de période trouvée, on réitère
-          if (!jourOuverture) {
-            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+
+          // If no period found, repeat
+          if (!openingDay) {
+            return this.getNextOpening(s, j + 1, dayBase, hourBase);
           }
-          return jourOuverture;
+          return openingDay;
         } else {
-          let jourOuverture: JourOuverture;
-          horaires.time.every((periode) => {
-            if (periode.openning >= baseHeure) {
-              jourOuverture = { jour: ' ', horaire: this.numberToHour(periode.openning) };
+          let openingDay: OpeningDay;
+          schedules.time.every((period: Time) => {
+            if (period.openning >= hourBase) {
+              openingDay = { day: ' ', schedule: this.numberToHour(period.openning) };
               return false;
             }
           });
-          // Si pas de période trouvée, on réitère
-          if (!jourOuverture) {
-            return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+          // If no period found, repeat
+          if (!openingDay) {
+            return this.getNextOpening(s, j + 1, dayBase, hourBase);
           }
-          return jourOuverture;
+          return openingDay;
         }
       } else {
-        // Si le jour n'est pas égal à Dimanche, on l'incrémente de 1
+        // If the day isn't equal to Sunday, it is incremented by 1
         if (j !== 7) {
-          return this.recupererProchaineOuverture(s, j + 1, baseJour, baseHeure);
+          return this.getNextOpening(s, j + 1, dayBase, hourBase);
         }
-        // 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);
+        // If the day is equal to Monday, set position to 0 to activate the stop condition
+        if (dayBase == 1) {
+          return this.getNextOpening(s, 0, dayBase, hourBase);
         }
-        // Si le jour est égal à Dimanche, on le positionne sur Lundi
-        return this.recupererProchaineOuverture(s, 1, baseJour, baseHeure);
+        // If the day is equal to Sunday, set position to Monday
+        return this.getNextOpening(s, 1, dayBase, hourBase);
       }
     }
-    const lastChancehoraire = this.recupererHoraire(s, j + 1);
-    let lastJour: JourOuverture;
-    if (lastChancehoraire.open) {
-      lastChancehoraire.time.every((periode) => {
-        if (periode.openning && periode.openning < baseHeure) {
-          lastJour = { jour: this.numberToDay(j + 1), horaire: this.numberToHour(periode.openning) };
+    const schedulesOnSameCurrentDay = this.getSchedules(s, j + 1);
+    let lastJour: OpeningDay;
+    if (schedulesOnSameCurrentDay.open) {
+      schedulesOnSameCurrentDay.time.every((period: Time) => {
+        if (period.openning && period.openning < hourBase) {
+          lastJour = { day: this.numberToDay(j + 1), schedule: this.numberToHour(period.openning) };
           return false;
         }
-        lastJour = { jour: '', horaire: 'Aucun horaire disponible' };
+        lastJour = { day: '', schedule: 'Aucun horaire disponible' };
       });
     } else {
-      lastJour = { jour: '', horaire: 'Aucun horaire disponible' };
+      lastJour = { day: '', schedule: 'Aucun horaire disponible' };
     }
     return lastJour;
   }
 
   private numberToDay(n: number): string {
-    return JourSemaine[n];
+    return Weekday[n];
   }
 
   private numberToHour(n: number): string {
-- 
GitLab


From 414cfdc305e00d764a4dabce61d1f9b23c50cbab Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 16:17:31 +0200
Subject: [PATCH 13/20] fix(card) : Rename structure to structure-list

---
 src/app/app.module.ts                         |  7 ++-
 src/app/home/home.component.html              |  2 +-
 .../components/card/card.component.html       |  0
 .../components/card/card.component.scss       |  0
 .../components/card/card.component.spec.ts    |  0
 .../components/card/card.component.ts         |  2 +-
 .../recherche/recherche.component.html        |  0
 .../recherche/recherche.component.scss        |  0
 .../recherche/recherche.component.spec.ts     |  0
 .../recherche/recherche.component.ts          |  9 ++--
 .../models/structure.model.ts                 |  0
 .../services/structure-list.service.spec.ts}  |  2 +-
 .../services/structure-list.service.ts}       |  0
 .../structure-list.component.html             | 33 +-----------
 .../structure-list.component.scss             | 53 -------------------
 .../structure-list.component.spec.ts          |  7 ++-
 .../structure-list.component.ts               |  4 --
 .../structure-list.module.ts}                 |  8 +--
 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 ------
 22 files changed, 18 insertions(+), 151 deletions(-)
 rename src/app/{structure => structure-list}/components/card/card.component.html (100%)
 rename src/app/{structure => structure-list}/components/card/card.component.scss (100%)
 rename src/app/{structure => structure-list}/components/card/card.component.spec.ts (100%)
 rename src/app/{structure => structure-list}/components/card/card.component.ts (90%)
 rename src/app/{structure => structure-list}/components/recherche/recherche.component.html (100%)
 rename src/app/{structure => structure-list}/components/recherche/recherche.component.scss (100%)
 rename src/app/{structure => structure-list}/components/recherche/recherche.component.spec.ts (100%)
 rename src/app/{structure => structure-list}/components/recherche/recherche.component.ts (68%)
 rename src/app/{structure => structure-list}/models/structure.model.ts (100%)
 rename src/app/{structure/services/structure.service.spec.ts => structure-list/services/structure-list.service.spec.ts} (99%)
 rename src/app/{structure/services/structure.service.ts => structure-list/services/structure-list.service.ts} (100%)
 delete mode 100644 src/app/structure-list/structure-list.component.scss
 rename src/app/{structure/structure.module.ts => structure-list/structure-list.module.ts} (66%)
 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

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 9d221fe1a..1e828f0aa 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -7,15 +7,14 @@ import { FlexLayoutModule } from '@angular/flex-layout';
 import { AppComponent } from './app.component';
 import { HomeComponent } from './home/home.component';
 import { CustomBreakPointsProvider } from './config/custom-breakpoint';
-import { StructureListComponent } from './structure-list/structure-list.component';
 import { FooterComponent } from './footer/footer.component';
 import { HeaderComponent } from './header/header.component';
 import { SharedModule } from './shared/shared.module';
-import { StructureModule } from './structure/structure.module';
+import { StructureListModule } from './structure-list/structure-list.module';
 
 @NgModule({
-  declarations: [AppComponent, HeaderComponent, FooterComponent, HomeComponent, StructureListComponent],
-  imports: [BrowserModule, AppRoutingModule, FlexLayoutModule, SharedModule, StructureModule],
+  declarations: [AppComponent, HeaderComponent, FooterComponent, HomeComponent],
+  imports: [BrowserModule, AppRoutingModule, FlexLayoutModule, SharedModule, StructureListModule],
   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 a1abb68dc..22f5aeb0f 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">
-    <app-structure></app-structure>
+    <app-structure-list></app-structure-list>
   </div>
 </div>
diff --git a/src/app/structure/components/card/card.component.html b/src/app/structure-list/components/card/card.component.html
similarity index 100%
rename from src/app/structure/components/card/card.component.html
rename to src/app/structure-list/components/card/card.component.html
diff --git a/src/app/structure/components/card/card.component.scss b/src/app/structure-list/components/card/card.component.scss
similarity index 100%
rename from src/app/structure/components/card/card.component.scss
rename to src/app/structure-list/components/card/card.component.scss
diff --git a/src/app/structure/components/card/card.component.spec.ts b/src/app/structure-list/components/card/card.component.spec.ts
similarity index 100%
rename from src/app/structure/components/card/card.component.spec.ts
rename to src/app/structure-list/components/card/card.component.spec.ts
diff --git a/src/app/structure/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
similarity index 90%
rename from src/app/structure/components/card/card.component.ts
rename to src/app/structure-list/components/card/card.component.ts
index 56802c487..b49f678bc 100644
--- a/src/app/structure/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -1,6 +1,6 @@
 import { Component, OnInit } from '@angular/core';
 import { Structure } from '../../models/structure.model';
-import { StructureService } from '../../services/structure.service';
+import { StructureService } from '../../services/structure-list.service';
 const { DateTime } = require('luxon');
 
 @Component({
diff --git a/src/app/structure/components/recherche/recherche.component.html b/src/app/structure-list/components/recherche/recherche.component.html
similarity index 100%
rename from src/app/structure/components/recherche/recherche.component.html
rename to src/app/structure-list/components/recherche/recherche.component.html
diff --git a/src/app/structure/components/recherche/recherche.component.scss b/src/app/structure-list/components/recherche/recherche.component.scss
similarity index 100%
rename from src/app/structure/components/recherche/recherche.component.scss
rename to src/app/structure-list/components/recherche/recherche.component.scss
diff --git a/src/app/structure/components/recherche/recherche.component.spec.ts b/src/app/structure-list/components/recherche/recherche.component.spec.ts
similarity index 100%
rename from src/app/structure/components/recherche/recherche.component.spec.ts
rename to src/app/structure-list/components/recherche/recherche.component.spec.ts
diff --git a/src/app/structure/components/recherche/recherche.component.ts b/src/app/structure-list/components/recherche/recherche.component.ts
similarity index 68%
rename from src/app/structure/components/recherche/recherche.component.ts
rename to src/app/structure-list/components/recherche/recherche.component.ts
index b37a52c87..7754a323b 100644
--- a/src/app/structure/components/recherche/recherche.component.ts
+++ b/src/app/structure-list/components/recherche/recherche.component.ts
@@ -3,13 +3,10 @@ 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() { }
-
-  ngOnInit(): void {
-  }
-
+  ngOnInit(): void {}
 }
diff --git a/src/app/structure/models/structure.model.ts b/src/app/structure-list/models/structure.model.ts
similarity index 100%
rename from src/app/structure/models/structure.model.ts
rename to src/app/structure-list/models/structure.model.ts
diff --git a/src/app/structure/services/structure.service.spec.ts b/src/app/structure-list/services/structure-list.service.spec.ts
similarity index 99%
rename from src/app/structure/services/structure.service.spec.ts
rename to src/app/structure-list/services/structure-list.service.spec.ts
index 7c885d669..5a836edd4 100644
--- a/src/app/structure/services/structure.service.spec.ts
+++ b/src/app/structure-list/services/structure-list.service.spec.ts
@@ -1,7 +1,7 @@
 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';
+import { StructureService } from './structure-list.service';
 const { DateTime } = require('luxon');
 
 describe('StructureService', () => {
diff --git a/src/app/structure/services/structure.service.ts b/src/app/structure-list/services/structure-list.service.ts
similarity index 100%
rename from src/app/structure/services/structure.service.ts
rename to src/app/structure-list/services/structure-list.service.ts
diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html
index 15a9b1218..a6dbe19b7 100644
--- a/src/app/structure-list/structure-list.component.html
+++ b/src/app/structure-list/structure-list.component.html
@@ -1,31 +1,2 @@
-<div class="content-container no-pt">
-  <div
-    class="section-container no-max-width orange-background"
-    fxLayout="row"
-    fxLayout.lt-sm="column"
-    fxLayoutAlign="center baseline"
-    fxLayoutAlign.lt-sm="center center"
-    fxLayoutGap="20px"
-  >
-    <p>Vous faites partie d’une structure de médiation ?</p>
-    <a [href]="regisrationFormLink" target="_blank">Inscrivez-vous</a>
-  </div>
-  <div class="section-container card">
-    <div fxLayout="row" fxLayoutGap="40px" fxLayoutAlign="space-between center">
-      <div class="input-container" fxLayout="row" fxLayoutGap="16px">
-        <span class="ico-mglass purple"></span>
-        <input class="input-field" type="text" placeholder="Rechercher une adresse, une association..." name="search" />
-      </div>
-      <div fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="10px">
-        <span class="clickable ico-pin orange"></span>
-        <a>Me localiser</a>
-      </div>
-    </div>
-  </div>
-</div>
-
-<div class="content-container no-pt">
-  <div class="section-container">
-    <p>structure-list works!</p>
-  </div>
-</div>
+<app-recherche></app-recherche>
+<app-card></app-card>
diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss
deleted file mode 100644
index a88f76884..000000000
--- a/src/app/structure-list/structure-list.component.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-@import '../../assets/scss/color';
-@import '../../assets/scss/typography';
-@import '../../assets/scss/breakpoint';
-@import '../../assets/scss/icons';
-
-.orange-background {
-  background-color: $orange;
-  height: 130px;
-  color: $white;
-  padding-top: 20px;
-  p {
-    @include cn-bold-18;
-  }
-  a {
-    color: $white;
-    text-decoration: underline;
-  }
-  @media #{$large-phone} {
-    height: 15vh;
-    padding-top: 0px;
-  }
-}
-
-.card {
-  background: #ffffff;
-  border: 1px solid $grey-3;
-  box-sizing: border-box;
-  padding: 20px 24px;
-}
-
-.card {
-  margin-top: -60px;
-  a {
-    @include cn-bold-16;
-    color: $orange;
-    white-space: nowrap;
-    text-decoration: underline;
-  }
-}
-
-.input-container {
-  background-color: $grey-4;
-  align-items: center;
-  width: 100%;
-  height: 40px;
-  padding: 10px 14px;
-  .input-field {
-    width: 100%;
-    background-color: inherit;
-    border: unset;
-    outline: none; //TODO: accesibility issue
-  }
-}
diff --git a/src/app/structure-list/structure-list.component.spec.ts b/src/app/structure-list/structure-list.component.spec.ts
index 59320b9ae..bbd876b55 100644
--- a/src/app/structure-list/structure-list.component.spec.ts
+++ b/src/app/structure-list/structure-list.component.spec.ts
@@ -2,15 +2,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 
 import { StructureListComponent } from './structure-list.component';
 
-describe('StructureListComponent', () => {
+describe('StructureComponent', () => {
   let component: StructureListComponent;
   let fixture: ComponentFixture<StructureListComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ StructureListComponent ]
-    })
-    .compileComponents();
+      declarations: [StructureListComponent],
+    }).compileComponents();
   });
 
   beforeEach(() => {
diff --git a/src/app/structure-list/structure-list.component.ts b/src/app/structure-list/structure-list.component.ts
index 00d10eeb5..276b325e4 100644
--- a/src/app/structure-list/structure-list.component.ts
+++ b/src/app/structure-list/structure-list.component.ts
@@ -1,14 +1,10 @@
 import { Component, OnInit } from '@angular/core';
-import { environment } from '../../environments/environment';
 
 @Component({
   selector: 'app-structure-list',
   templateUrl: './structure-list.component.html',
-  styleUrls: ['./structure-list.component.scss'],
 })
 export class StructureListComponent implements OnInit {
-  public regisrationFormLink: string = environment.registrationForm;
-
   constructor() {}
 
   ngOnInit(): void {}
diff --git a/src/app/structure/structure.module.ts b/src/app/structure-list/structure-list.module.ts
similarity index 66%
rename from src/app/structure/structure.module.ts
rename to src/app/structure-list/structure-list.module.ts
index 335604aef..7067e0fef 100644
--- a/src/app/structure/structure.module.ts
+++ b/src/app/structure-list/structure-list.module.ts
@@ -1,14 +1,14 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { StructureComponent } from './structure.component';
+import { StructureListComponent } from './structure-list.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],
+  declarations: [StructureListComponent, CardComponent, RechercheComponent],
   imports: [CommonModule, HttpClientModule, FlexLayoutModule],
-  exports: [StructureComponent],
+  exports: [StructureListComponent],
 })
-export class StructureModule {}
+export class StructureListModule {}
diff --git a/src/app/structure/structure.component.html b/src/app/structure/structure.component.html
deleted file mode 100644
index a6dbe19b7..000000000
--- a/src/app/structure/structure.component.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<app-recherche></app-recherche>
-<app-card></app-card>
diff --git a/src/app/structure/structure.component.scss b/src/app/structure/structure.component.scss
deleted file mode 100644
index e69de29bb..000000000
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 {
-  }
-
-}
-- 
GitLab


From 79bb95d28aef9724e561f4a2f8b1426865d08a89 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 16:50:44 +0200
Subject: [PATCH 14/20] fix(card) : split each class into distinct model

---
 src/app/structure-list/models/day.model.ts    |  6 ++++
 .../structure-list/models/openingDay.model.ts |  4 +++
 .../structure-list/models/structure.model.ts  | 34 ++-----------------
 .../models/structureSchedules.model.ts        | 11 ++++++
 src/app/structure-list/models/time.model.ts   |  4 +++
 .../structure-list/models/weekday.model.ts    |  9 +++++
 .../services/structure-list.service.ts        |  6 +++-
 7 files changed, 42 insertions(+), 32 deletions(-)
 create mode 100644 src/app/structure-list/models/day.model.ts
 create mode 100644 src/app/structure-list/models/openingDay.model.ts
 create mode 100644 src/app/structure-list/models/structureSchedules.model.ts
 create mode 100644 src/app/structure-list/models/time.model.ts
 create mode 100644 src/app/structure-list/models/weekday.model.ts

diff --git a/src/app/structure-list/models/day.model.ts b/src/app/structure-list/models/day.model.ts
new file mode 100644
index 000000000..e46e81dd8
--- /dev/null
+++ b/src/app/structure-list/models/day.model.ts
@@ -0,0 +1,6 @@
+import { Time } from './time.model';
+
+export class Day {
+  open: boolean;
+  time: Time[];
+}
diff --git a/src/app/structure-list/models/openingDay.model.ts b/src/app/structure-list/models/openingDay.model.ts
new file mode 100644
index 000000000..515981c95
--- /dev/null
+++ b/src/app/structure-list/models/openingDay.model.ts
@@ -0,0 +1,4 @@
+export class OpeningDay {
+  day: string;
+  schedule: string;
+}
diff --git a/src/app/structure-list/models/structure.model.ts b/src/app/structure-list/models/structure.model.ts
index 8dea2e9a0..8679fb95e 100644
--- a/src/app/structure-list/models/structure.model.ts
+++ b/src/app/structure-list/models/structure.model.ts
@@ -1,3 +1,6 @@
+import { OpeningDay } from './openingDay.model';
+import { structureSchedules } from './structureSchedules.model';
+
 export class Structure {
   numero: string;
   dateDeCreation: string;
@@ -27,34 +30,3 @@ export class Structure {
   isOpen: boolean;
   openedOn: OpeningDay;
 }
-
-export class structureSchedules {
-  lundi: Day;
-  mardi: Day;
-  mercredi: Day;
-  jeudi: Day;
-  vendredi: Day;
-  samedi: Day;
-  dimanche: Day;
-}
-export class Day {
-  open: boolean;
-  time: Time[];
-}
-export class Time {
-  openning: number;
-  closing: number;
-}
-export class OpeningDay {
-  day: string;
-  schedule: string;
-}
-export enum Weekday {
-  lundi = 1,
-  mardi,
-  mercredi,
-  jeudi,
-  vendredi,
-  samedi,
-  dimanche,
-}
diff --git a/src/app/structure-list/models/structureSchedules.model.ts b/src/app/structure-list/models/structureSchedules.model.ts
new file mode 100644
index 000000000..b6f74440f
--- /dev/null
+++ b/src/app/structure-list/models/structureSchedules.model.ts
@@ -0,0 +1,11 @@
+import { Day } from './day.model';
+
+export class structureSchedules {
+  lundi: Day;
+  mardi: Day;
+  mercredi: Day;
+  jeudi: Day;
+  vendredi: Day;
+  samedi: Day;
+  dimanche: Day;
+}
diff --git a/src/app/structure-list/models/time.model.ts b/src/app/structure-list/models/time.model.ts
new file mode 100644
index 000000000..7e24d310e
--- /dev/null
+++ b/src/app/structure-list/models/time.model.ts
@@ -0,0 +1,4 @@
+export class Time {
+  openning: number;
+  closing: number;
+}
diff --git a/src/app/structure-list/models/weekday.model.ts b/src/app/structure-list/models/weekday.model.ts
new file mode 100644
index 000000000..bf87882db
--- /dev/null
+++ b/src/app/structure-list/models/weekday.model.ts
@@ -0,0 +1,9 @@
+export enum Weekday {
+  lundi = 1,
+  mardi,
+  mercredi,
+  jeudi,
+  vendredi,
+  samedi,
+  dimanche,
+}
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index f2f5a0cb4..1a465d3d9 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -1,7 +1,11 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
-import { OpeningDay, Structure, Weekday, Day, Time } from '../models/structure.model';
+import { Day } from '../models/day.model';
+import { OpeningDay } from '../models/openingDay.model';
+import { Structure } from '../models/structure.model';
+import { Time } from '../models/time.model';
+import { Weekday } from '../models/weekday.model';
 
 @Injectable({
   providedIn: 'root',
-- 
GitLab


From 3168ed52545130a7028a6903297b615c80d9f382 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Wed, 14 Oct 2020 16:58:11 +0200
Subject: [PATCH 15/20] fix(card) : use global color

---
 .../components/card/card.component.scss              | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/app/structure-list/components/card/card.component.scss b/src/app/structure-list/components/card/card.component.scss
index 0f2322644..95a7de802 100644
--- a/src/app/structure-list/components/card/card.component.scss
+++ b/src/app/structure-list/components/card/card.component.scss
@@ -1,6 +1,8 @@
 @import '../../../../assets/scss/icons';
+@import '../../../../assets/scss/color';
+
 .nbStructuresLabel {
-  color: #828282;
+  color: $grey;
   font-family: Trebuchet MS;
   font-style: normal;
   font-weight: normal;
@@ -11,9 +13,9 @@
 }
 .structure {
   padding: 12px 0 12px 0;
-  border-bottom: 1px dashed #bdbdbd;
+  border-bottom: 1px dashed $grey;
   .typeStructure {
-    color: #828282;
+    color: $grey;
     font-family: Times New Roman;
     font-style: normal;
     font-weight: normal;
@@ -22,7 +24,7 @@
   }
   .nomStructure {
     padding-top: 13px;
-    color: #594d59;
+    color: $purple;
     font-family: Trebuchet MS;
     font-style: normal;
     font-weight: bold;
@@ -35,7 +37,7 @@
     font-style: normal;
     font-size: 16px;
     line-height: 103%;
-    color: #594d59;
+    color: $purple;
   }
   &:last-child {
     border-bottom: none;
-- 
GitLab


From 6c280a603bb689eb514ec94b51766b88b7fc9309 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Wed, 14 Oct 2020 18:49:06 +0200
Subject: [PATCH 16/20] fix: clean code

---
 .../components/card/card.component.ts         |  2 +-
 src/app/structure-list/enum/weekday.enum.ts   |  9 ++
 src/app/structure-list/models/day.model.ts    |  6 ++
 .../structure-list/models/structure.model.ts  | 85 +++++++++++++------
 .../models/structureSchedules.model.ts        | 11 ---
 src/app/structure-list/models/time.model.ts   |  4 +
 src/app/structure-list/models/week.model.ts   | 24 ++++++
 .../structure-list/models/weekday.model.ts    |  9 --
 .../services/structure-list.service.ts        | 55 +++++-------
 9 files changed, 120 insertions(+), 85 deletions(-)
 create mode 100644 src/app/structure-list/enum/weekday.enum.ts
 delete mode 100644 src/app/structure-list/models/structureSchedules.model.ts
 create mode 100644 src/app/structure-list/models/week.model.ts
 delete mode 100644 src/app/structure-list/models/weekday.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 b49f678bc..5594b507f 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -13,7 +13,7 @@ export class CardComponent implements OnInit {
   constructor(private structureService: StructureService) {}
 
   ngOnInit(): void {
-    this.structureService.getStructures().subscribe((structures: Structure[]) => {
+    this.structureService.getStructures().subscribe((structures) => {
       structures.forEach((s: Structure) => {
         this.structures.push(this.structureService.updateOpeningStructure(s, DateTime.local()));
       });
diff --git a/src/app/structure-list/enum/weekday.enum.ts b/src/app/structure-list/enum/weekday.enum.ts
new file mode 100644
index 000000000..f4889072c
--- /dev/null
+++ b/src/app/structure-list/enum/weekday.enum.ts
@@ -0,0 +1,9 @@
+export enum Weekday {
+  monday = 1,
+  tuesday,
+  wednesday,
+  thursday,
+  friday,
+  saturday,
+  sunday,
+}
diff --git a/src/app/structure-list/models/day.model.ts b/src/app/structure-list/models/day.model.ts
index e46e81dd8..122b812db 100644
--- a/src/app/structure-list/models/day.model.ts
+++ b/src/app/structure-list/models/day.model.ts
@@ -3,4 +3,10 @@ import { Time } from './time.model';
 export class Day {
   open: boolean;
   time: Time[];
+
+  constructor(obj?: any) {
+    Object.assign(this, obj, {
+      time: obj && obj.time ? obj.time.map((time) => new Time(time)) : null,
+    });
+  }
 }
diff --git a/src/app/structure-list/models/structure.model.ts b/src/app/structure-list/models/structure.model.ts
index 8679fb95e..92ceb326d 100644
--- a/src/app/structure-list/models/structure.model.ts
+++ b/src/app/structure-list/models/structure.model.ts
@@ -1,32 +1,61 @@
+import { Day } from './day.model';
 import { OpeningDay } from './openingDay.model';
-import { structureSchedules } from './structureSchedules.model';
+import { Weekday } from '../enum/weekday.enum';
+import { Week } from './week.model';
 
 export class Structure {
-  numero: string;
-  dateDeCreation: string;
-  derniereModification: string;
-  nomDeLusager: string;
-  votreStructureEstElle: string;
-  nomDeVotreStructure: string;
-  typeDeStructure: 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;
-  fonction: string;
-  accessibilitePersonnesAMobiliteReduitePmr: boolean;
-  jaccompagneLesUsagersDansLeursDemarchesEnLigne: boolean;
-  accompagnementDesDemarches: string[];
-  wifi: boolean;
-  horaires: structureSchedules;
-  isOpen: boolean;
-  openedOn: OpeningDay;
+  public numero: string;
+  public dateDeCreation: string;
+  public derniereModification: string;
+  public nomDeLusager: string;
+  public votreStructureEstElle: string;
+  public nomDeVotreStructure: string;
+  public typeDeStructure: string;
+  public description: string;
+  public n: string;
+  public voie: string;
+  public telephone: string;
+  public courriel: string;
+  public siteWeb: string;
+  public facebook: string;
+  public twitter: string;
+  public instagram: string;
+  public civilite: string;
+  public nom: string;
+  public prenom: string;
+  public fonction: string;
+  public accessibilitePersonnesAMobiliteReduitePmr: boolean;
+  public jaccompagneLesUsagersDansLeursDemarchesEnLigne: boolean;
+  public accompagnementDesDemarches: string[];
+  public wifi: boolean;
+  public hours: Week;
+  public isOpen: boolean;
+  public openedOn: OpeningDay;
+
+  constructor(obj?: any) {
+    Object.assign(this, obj, {
+      hours: obj && obj.hours ? new Week(obj.hours) : null,
+    });
+  }
+
+  public getDayhours(day: Weekday): Day {
+    switch (day) {
+      case Weekday.monday:
+        return this.hours.monday;
+      case Weekday.tuesday:
+        return this.hours.tuesday;
+      case Weekday.thursday:
+        return this.hours.thursday;
+      case Weekday.wednesday:
+        return this.hours.wednesday;
+      case Weekday.friday:
+        return this.hours.friday;
+      case Weekday.saturday:
+        return this.hours.saturday;
+      case Weekday.sunday:
+        return this.hours.sunday;
+      default:
+        return null;
+    }
+  }
 }
diff --git a/src/app/structure-list/models/structureSchedules.model.ts b/src/app/structure-list/models/structureSchedules.model.ts
deleted file mode 100644
index b6f74440f..000000000
--- a/src/app/structure-list/models/structureSchedules.model.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Day } from './day.model';
-
-export class structureSchedules {
-  lundi: Day;
-  mardi: Day;
-  mercredi: Day;
-  jeudi: Day;
-  vendredi: Day;
-  samedi: Day;
-  dimanche: Day;
-}
diff --git a/src/app/structure-list/models/time.model.ts b/src/app/structure-list/models/time.model.ts
index 7e24d310e..242d51a4a 100644
--- a/src/app/structure-list/models/time.model.ts
+++ b/src/app/structure-list/models/time.model.ts
@@ -1,4 +1,8 @@
 export class Time {
   openning: number;
   closing: number;
+
+  constructor(obj?: any) {
+    Object.assign(this, obj);
+  }
 }
diff --git a/src/app/structure-list/models/week.model.ts b/src/app/structure-list/models/week.model.ts
new file mode 100644
index 000000000..60c023298
--- /dev/null
+++ b/src/app/structure-list/models/week.model.ts
@@ -0,0 +1,24 @@
+import { Day } from './day.model';
+import { Time } from './time.model';
+
+export class Week {
+  monday: Day;
+  tuesday: Day;
+  wednesday: Day;
+  thursday: Day;
+  friday: Day;
+  saturday: Day;
+  sunday: Day;
+
+  constructor(obj?: any) {
+    Object.assign(this, obj, {
+      monday: obj && obj.monday ? new Day(obj.monday) : null,
+      tuesday: obj && obj.tuesday ? new Day(obj.tuesday) : null,
+      wednesday: obj && obj.wednesday ? new Day(obj.wednesday) : null,
+      thursday: obj && obj.thursday ? new Day(obj.thursday) : null,
+      friday: obj && obj.friday ? new Day(obj.friday) : null,
+      saturday: obj && obj.saturday ? new Day(obj.saturday) : null,
+      sunday: obj && obj.sunday ? new Day(obj.sunday) : null,
+    });
+  }
+}
diff --git a/src/app/structure-list/models/weekday.model.ts b/src/app/structure-list/models/weekday.model.ts
deleted file mode 100644
index bf87882db..000000000
--- a/src/app/structure-list/models/weekday.model.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export enum Weekday {
-  lundi = 1,
-  mardi,
-  mercredi,
-  jeudi,
-  vendredi,
-  samedi,
-  dimanche,
-}
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 1a465d3d9..c21c668b6 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -1,11 +1,14 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+const { DateTime } = require('luxon');
+
 import { Day } from '../models/day.model';
 import { OpeningDay } from '../models/openingDay.model';
 import { Structure } from '../models/structure.model';
 import { Time } from '../models/time.model';
-import { Weekday } from '../models/weekday.model';
+import { Weekday } from '../enum/weekday.enum';
 
 @Injectable({
   providedIn: 'root',
@@ -13,24 +16,26 @@ import { Weekday } from '../models/weekday.model';
 export class StructureService {
   constructor(private http: HttpClient) {}
 
-  public getStructures(): Observable<any> {
-    return this.http.get('/api/Structures');
+  public getStructures(): Observable<Structure[]> {
+    return this.http.get('/api/Structures').pipe(map((data: any[]) => data.map((item) => new Structure(item))));
   }
 
-  public updateOpeningStructure(structure: Structure, currentDate: any): Structure {
+  public updateOpeningStructure(structure: Structure): Structure {
     // Get current day of week
-    const dayOfWeek: number = currentDate.weekday;
+    const currentDate = DateTime.local();
+    const dayOfWeek: number = DateTime.local().weekday;
 
     // Checks if minutes start with zero to avoid deletion
     let now: number;
-    if (currentDate.minute.toString().length != 1) {
+    if (currentDate.minute.toString().length !== 1) {
       now = parseInt('' + currentDate.hour + currentDate.minute, 10);
     } else {
       now = parseInt('' + currentDate.hour + 0 + currentDate.minute, 10);
     }
 
     // Get the schedules of a structure according to his day to indicate if it's open
-    const structureSchedules: Day = this.getSchedules(structure, dayOfWeek);
+    const structureSchedules: Day = structure.getDayhours(dayOfWeek);
+
     structure.isOpen = false;
     if (structureSchedules.open) {
       structureSchedules.time.forEach((period: Time) => {
@@ -43,36 +48,14 @@ export class StructureService {
     return structure;
   }
 
-  // Get the schedules of a structure according to the day of the week
-  private getSchedules(structure: Structure, currentDay: number): Day {
-    switch (currentDay) {
-      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;
-    }
-  }
-
   // Checks if the current time is in the time interval of the structure
-  private compareSchedules(startTime: number, endTime: number, currentTime: number): Boolean {
+  private compareSchedules(startTime: number, endTime: number, currentTime: number): boolean {
     return currentTime >= startTime && currentTime <= endTime;
   }
 
   private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
     // Get the schedules of current day
-    const schedules = this.getSchedules(s, j);
+    const schedules = s.getDayhours(j);
     // Condition to stop recursion (If the counter day is equal to the current day)
     if (j + 1 !== dayBase) {
       if (schedules.open) {
@@ -107,18 +90,18 @@ export class StructureService {
         }
       } else {
         // If the day isn't equal to Sunday, it is incremented by 1
-        if (j !== 7) {
+        if (j !== Weekday.sunday) {
           return this.getNextOpening(s, j + 1, dayBase, hourBase);
         }
         // If the day is equal to Monday, set position to 0 to activate the stop condition
-        if (dayBase == 1) {
+        if (dayBase === Weekday.monday) {
           return this.getNextOpening(s, 0, dayBase, hourBase);
         }
         // If the day is equal to Sunday, set position to Monday
         return this.getNextOpening(s, 1, dayBase, hourBase);
       }
     }
-    const schedulesOnSameCurrentDay = this.getSchedules(s, j + 1);
+    const schedulesOnSameCurrentDay = s.getDayhours(j + 1);
     let lastJour: OpeningDay;
     if (schedulesOnSameCurrentDay.open) {
       schedulesOnSameCurrentDay.time.every((period: Time) => {
@@ -139,10 +122,10 @@ export class StructureService {
   }
 
   private numberToHour(n: number): string {
-    if (n.toString().length == 3) {
+    if (n.toString().length === 3) {
       const tabNum = n.toString().match(/.{1,1}/g);
       return tabNum[0] + 'h' + tabNum[1] + tabNum[2];
-    } else if (n.toString().length == 4) {
+    } else if (n.toString().length === 4) {
       const tabNum = n.toString().match(/.{1,2}/g);
       return tabNum[0] + 'h' + tabNum[1];
     }
-- 
GitLab


From d36c6bfbf63033299c74f49f5b284fe2b9c646c5 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 12:03:01 +0200
Subject: [PATCH 17/20] fix(card) : fix openning day function

---
 .../components/card/card.component.html       |  2 +-
 .../components/card/card.component.ts         |  2 +-
 .../structure-list/models/openingDay.model.ts |  5 +++
 .../services/structure-list.service.ts        | 36 +++++++++++++++++--
 4 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/src/app/structure-list/components/card/card.component.html b/src/app/structure-list/components/card/card.component.html
index b2e9ee55a..490d59af8 100644
--- a/src/app/structure-list/components/card/card.component.html
+++ b/src/app/structure-list/components/card/card.component.html
@@ -19,7 +19,7 @@
       >
     </ng-template>
     <ng-template #noTime>
-      <span> Fermé - {{ structure.openedOn.schedule }}</span>
+      <span> Fermé - Aucun horaire disponible</span>
     </ng-template>
   </div>
 </div>
diff --git a/src/app/structure-list/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
index 5594b507f..458483a74 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -15,7 +15,7 @@ export class CardComponent implements OnInit {
   ngOnInit(): void {
     this.structureService.getStructures().subscribe((structures) => {
       structures.forEach((s: Structure) => {
-        this.structures.push(this.structureService.updateOpeningStructure(s, DateTime.local()));
+        this.structures.push(this.structureService.updateOpeningStructure(s));
       });
     });
   }
diff --git a/src/app/structure-list/models/openingDay.model.ts b/src/app/structure-list/models/openingDay.model.ts
index 515981c95..5e286fe22 100644
--- a/src/app/structure-list/models/openingDay.model.ts
+++ b/src/app/structure-list/models/openingDay.model.ts
@@ -1,4 +1,9 @@
 export class OpeningDay {
   day: string;
   schedule: string;
+
+  constructor(day: string, schedule: string) {
+    this.day = day;
+    this.schedule = schedule;
+  }
 }
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index c21c668b6..507a61bd0 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -44,7 +44,7 @@ export class StructureService {
         }
       });
     }
-    structure.openedOn = this.getNextOpening(structure, dayOfWeek, dayOfWeek, now);
+    structure.openedOn = this.getNextOpening(structure, dayOfWeek, now);
     return structure;
   }
 
@@ -53,7 +53,38 @@ export class StructureService {
     return currentTime >= startTime && currentTime <= endTime;
   }
 
-  private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
+  private getNextOpening(s: Structure, dayOfWeek: number, hourBase: number): OpeningDay {
+    const arrayOfWeek = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
+    let periodBeforeCurrentDay = null;
+
+    // Browse day of week
+    for (let i in s.hours) {
+      const period = s.hours[i];
+      if (period.open) {
+        // Check if it's current day
+        if (i === this.numberToDay(dayOfWeek)) {
+          if (
+            (period.time[0].openning <= hourBase && period.time[0].closing >= hourBase) ||
+            (period.time[1].openning <= hourBase && period.time[1].closing >= hourBase)
+          ) {
+            return new OpeningDay(i, null);
+          } else if (period.time[0].openning >= hourBase) {
+            return new OpeningDay(i, this.numberToHour(period.time[0].openning));
+          } else if (period.time[1].openning >= hourBase) {
+            return new OpeningDay(i, this.numberToHour(period.time[1].openning));
+          }
+          // Return the next day > current day.
+        } else if (arrayOfWeek.indexOf(i) > arrayOfWeek.indexOf(this.numberToDay(dayOfWeek))) {
+          return new OpeningDay(i, this.numberToHour(period.time[0].openning));
+          // Return the next day < current day.
+        } else if (!periodBeforeCurrentDay) {
+          periodBeforeCurrentDay = new OpeningDay(i, this.numberToHour(period.time[0].openning));
+        }
+      }
+    }
+    return periodBeforeCurrentDay ? periodBeforeCurrentDay : '';
+  }
+  /*private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
     // Get the schedules of current day
     const schedules = s.getDayhours(j);
     // Condition to stop recursion (If the counter day is equal to the current day)
@@ -116,6 +147,7 @@ export class StructureService {
     }
     return lastJour;
   }
+  */
 
   private numberToDay(n: number): string {
     return Weekday[n];
-- 
GitLab


From 74cd5037a10287346cd70917938508f9a22e91b5 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Thu, 15 Oct 2020 13:36:42 +0200
Subject: [PATCH 18/20] fix: clean code

---
 .../components/card/card.component.scss       | 24 ++----
 .../services/structure-list.service.ts        | 78 +++----------------
 2 files changed, 17 insertions(+), 85 deletions(-)

diff --git a/src/app/structure-list/components/card/card.component.scss b/src/app/structure-list/components/card/card.component.scss
index 95a7de802..d5c8e1116 100644
--- a/src/app/structure-list/components/card/card.component.scss
+++ b/src/app/structure-list/components/card/card.component.scss
@@ -1,12 +1,10 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
 
 .nbStructuresLabel {
   color: $grey;
-  font-family: Trebuchet MS;
-  font-style: normal;
-  font-weight: normal;
-  font-size: 16px;
+  @include cn-regular-16;
   line-height: 19px;
   display: flex;
   align-items: center;
@@ -16,26 +14,19 @@
   border-bottom: 1px dashed $grey;
   .typeStructure {
     color: $grey;
-    font-family: Times New Roman;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 16px;
+    @include cn-regular-16;
     line-height: 100%;
   }
   .nomStructure {
     padding-top: 13px;
     color: $purple;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: bold;
+    @include cn-bold-20;
     font-size: 20px;
     line-height: 103%;
     padding-bottom: 5px;
   }
   .distanceStructure {
-    font-family: Times New Roman;
-    font-style: normal;
-    font-size: 16px;
+    @include cn-regular-16;
     line-height: 103%;
     color: $purple;
   }
@@ -45,10 +36,7 @@
 }
 .statusStructure {
   span {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 15px;
+    @include cn-regular-16;
     line-height: 103%;
     margin-right: 8px;
   }
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 507a61bd0..f7e3f6904 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -20,6 +20,10 @@ export class StructureService {
     return this.http.get('/api/Structures').pipe(map((data: any[]) => data.map((item) => new Structure(item))));
   }
 
+  /**
+   * Update opening hours of structure
+   * @param structure Structure model
+   */
   public updateOpeningStructure(structure: Structure): Structure {
     // Get current day of week
     const currentDate = DateTime.local();
@@ -48,7 +52,12 @@ export class StructureService {
     return structure;
   }
 
-  // Checks if the current time is in the time interval of the structure
+  /**
+   * Checks if the current time is in the time interval of the structure
+   * @param startTime start of period
+   * @param endTime end of period
+   * @param currentTime actual time
+   */
   private compareSchedules(startTime: number, endTime: number, currentTime: number): boolean {
     return currentTime >= startTime && currentTime <= endTime;
   }
@@ -58,8 +67,7 @@ export class StructureService {
     let periodBeforeCurrentDay = null;
 
     // Browse day of week
-    for (let i in s.hours) {
-      const period = s.hours[i];
+    for (const [i, period] of Object.entries(s.hours)) {
       if (period.open) {
         // Check if it's current day
         if (i === this.numberToDay(dayOfWeek)) {
@@ -84,70 +92,6 @@ export class StructureService {
     }
     return periodBeforeCurrentDay ? periodBeforeCurrentDay : '';
   }
-  /*private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
-    // Get the schedules of current day
-    const schedules = s.getDayhours(j);
-    // Condition to stop recursion (If the counter day is equal to the current day)
-    if (j + 1 !== dayBase) {
-      if (schedules.open) {
-        // Check if the counter corresponds to the current day to avoid proposing the schedules already passed
-        if (j !== dayBase) {
-          let openingDay: OpeningDay;
-          schedules.time.every((period: Time) => {
-            if (period.openning) {
-              openingDay = { day: this.numberToDay(j), schedule: this.numberToHour(period.openning) };
-              return false;
-            }
-          });
-
-          // If no period found, repeat
-          if (!openingDay) {
-            return this.getNextOpening(s, j + 1, dayBase, hourBase);
-          }
-          return openingDay;
-        } else {
-          let openingDay: OpeningDay;
-          schedules.time.every((period: Time) => {
-            if (period.openning >= hourBase) {
-              openingDay = { day: ' ', schedule: this.numberToHour(period.openning) };
-              return false;
-            }
-          });
-          // If no period found, repeat
-          if (!openingDay) {
-            return this.getNextOpening(s, j + 1, dayBase, hourBase);
-          }
-          return openingDay;
-        }
-      } else {
-        // If the day isn't equal to Sunday, it is incremented by 1
-        if (j !== Weekday.sunday) {
-          return this.getNextOpening(s, j + 1, dayBase, hourBase);
-        }
-        // If the day is equal to Monday, set position to 0 to activate the stop condition
-        if (dayBase === Weekday.monday) {
-          return this.getNextOpening(s, 0, dayBase, hourBase);
-        }
-        // If the day is equal to Sunday, set position to Monday
-        return this.getNextOpening(s, 1, dayBase, hourBase);
-      }
-    }
-    const schedulesOnSameCurrentDay = s.getDayhours(j + 1);
-    let lastJour: OpeningDay;
-    if (schedulesOnSameCurrentDay.open) {
-      schedulesOnSameCurrentDay.time.every((period: Time) => {
-        if (period.openning && period.openning < hourBase) {
-          lastJour = { day: this.numberToDay(j + 1), schedule: this.numberToHour(period.openning) };
-          return false;
-        }
-        lastJour = { day: '', schedule: 'Aucun horaire disponible' };
-      });
-    } else {
-      lastJour = { day: '', schedule: 'Aucun horaire disponible' };
-    }
-    return lastJour;
-  }
-  */
 
   private numberToDay(n: number): string {
     return Weekday[n];
-- 
GitLab


From aa597fc90c5638c4f7667aa8929599bda3603f50 Mon Sep 17 00:00:00 2001
From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com>
Date: Thu, 15 Oct 2020 14:55:21 +0200
Subject: [PATCH 19/20] fix(card) : fix test + switch array with enum

---
 .../components/card/card.component.scss       |  30 +--
 .../components/card/card.component.ts         |   2 +-
 .../services/structure-list.service.spec.ts   | 215 +++---------------
 .../services/structure-list.service.ts        |  90 ++------
 4 files changed, 56 insertions(+), 281 deletions(-)

diff --git a/src/app/structure-list/components/card/card.component.scss b/src/app/structure-list/components/card/card.component.scss
index 95a7de802..732c84c03 100644
--- a/src/app/structure-list/components/card/card.component.scss
+++ b/src/app/structure-list/components/card/card.component.scss
@@ -1,13 +1,10 @@
 @import '../../../../assets/scss/icons';
 @import '../../../../assets/scss/color';
+@import '../../../../assets/scss/typography';
 
 .nbStructuresLabel {
   color: $grey;
-  font-family: Trebuchet MS;
-  font-style: normal;
-  font-weight: normal;
-  font-size: 16px;
-  line-height: 19px;
+  @include cn-regular-16;
   display: flex;
   align-items: center;
 }
@@ -16,27 +13,16 @@
   border-bottom: 1px dashed $grey;
   .typeStructure {
     color: $grey;
-    font-family: Times New Roman;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 16px;
-    line-height: 100%;
+    @include cn-regular-16;
   }
   .nomStructure {
     padding-top: 13px;
     color: $purple;
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: bold;
-    font-size: 20px;
-    line-height: 103%;
+    @include cn-bold-20;
     padding-bottom: 5px;
   }
   .distanceStructure {
-    font-family: Times New Roman;
-    font-style: normal;
-    font-size: 16px;
-    line-height: 103%;
+    @include cn-regular-16;
     color: $purple;
   }
   &:last-child {
@@ -45,11 +31,7 @@
 }
 .statusStructure {
   span {
-    font-family: Trebuchet MS;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 15px;
-    line-height: 103%;
+    @include cn-regular-14;
     margin-right: 8px;
   }
 }
diff --git a/src/app/structure-list/components/card/card.component.ts b/src/app/structure-list/components/card/card.component.ts
index 458483a74..5594b507f 100644
--- a/src/app/structure-list/components/card/card.component.ts
+++ b/src/app/structure-list/components/card/card.component.ts
@@ -15,7 +15,7 @@ export class CardComponent implements OnInit {
   ngOnInit(): void {
     this.structureService.getStructures().subscribe((structures) => {
       structures.forEach((s: Structure) => {
-        this.structures.push(this.structureService.updateOpeningStructure(s));
+        this.structures.push(this.structureService.updateOpeningStructure(s, DateTime.local()));
       });
     });
   }
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 5a836edd4..628a012ff 100644
--- a/src/app/structure-list/services/structure-list.service.spec.ts
+++ b/src/app/structure-list/services/structure-list.service.spec.ts
@@ -1,6 +1,8 @@
-import { HttpClient, HttpClientModule } from '@angular/common/http';
+import { HttpClientModule } from '@angular/common/http';
 import { inject, TestBed } from '@angular/core/testing';
-import { horaireStructure, Jour, Structure } from '../models/structure.model';
+import { Day } from '../models/day.model';
+import { Structure } from '../models/structure.model';
+import { Week } from '../models/week.model';
 import { StructureService } from './structure-list.service';
 const { DateTime } = require('luxon');
 
@@ -14,163 +16,6 @@ describe('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 = [
@@ -179,43 +24,43 @@ describe('StructureService', () => {
     ];
     //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;
+    s.hours = new Week();
+    s.hours.monday = new Day(false);
+    s.hours.tuesday = new Day(false);
+    s.hours.wednesday = new Day(false);
+    s.hours.thursday = new Day(false);
+    s.hours.friday = new Day(false);
+    s.hours.saturday = new Day(false);
+    s.hours.sunday = new Day(false);
+
+    s.hours.thursday.open = true;
+    s.hours.thursday.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);
+    const result = _structureService.updateOpeningStructure(s, dt);
+    expect(result.isOpen).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;
+    s.hours = new Week();
+    s.hours.monday = new Day();
+    s.hours.tuesday = new Day();
+    s.hours.wednesday = new Day();
+    s.hours.thursday = new Day();
+    s.hours.friday = new Day();
+    s.hours.saturday = new Day();
+    s.hours.sunday = new Day();
+
+    s.hours.thursday.open = true;
+    s.hours.thursday.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);
+    const result = _structureService.updateOpeningStructure(s, dt);
+    expect(result.isOpen).toEqual(false);
   });
 });
diff --git a/src/app/structure-list/services/structure-list.service.ts b/src/app/structure-list/services/structure-list.service.ts
index 507a61bd0..fcad269ec 100644
--- a/src/app/structure-list/services/structure-list.service.ts
+++ b/src/app/structure-list/services/structure-list.service.ts
@@ -9,6 +9,8 @@ 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';
 
 @Injectable({
   providedIn: 'root',
@@ -20,10 +22,10 @@ export class StructureService {
     return this.http.get('/api/Structures').pipe(map((data: any[]) => data.map((item) => new Structure(item))));
   }
 
-  public updateOpeningStructure(structure: Structure): Structure {
+  public updateOpeningStructure(structure: Structure, dateTime): Structure {
     // Get current day of week
-    const currentDate = DateTime.local();
-    const dayOfWeek: number = DateTime.local().weekday;
+    const currentDate = dateTime;
+    const dayOfWeek: number = currentDate.weekday;
 
     // Checks if minutes start with zero to avoid deletion
     let now: number;
@@ -53,8 +55,16 @@ export class StructureService {
     return currentTime >= startTime && currentTime <= endTime;
   }
 
+  // Get enum key
+  private getEnumKeyByEnumValue(enumBase, enumValue): number {
+    let keys = Object.keys(enumBase).filter((x) => {
+      if (enumBase[x].toString().toLowerCase() == enumValue) {
+        return x;
+      }
+    });
+    return keys.length > 0 ? parseInt(keys[0]) : null;
+  }
   private getNextOpening(s: Structure, dayOfWeek: number, hourBase: number): OpeningDay {
-    const arrayOfWeek = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
     let periodBeforeCurrentDay = null;
 
     // Browse day of week
@@ -65,16 +75,18 @@ export class StructureService {
         if (i === this.numberToDay(dayOfWeek)) {
           if (
             (period.time[0].openning <= hourBase && period.time[0].closing >= hourBase) ||
-            (period.time[1].openning <= hourBase && period.time[1].closing >= hourBase)
+            (period.time[1] && period.time[1].openning <= hourBase && period.time[1].closing >= hourBase)
           ) {
             return new OpeningDay(i, null);
           } else if (period.time[0].openning >= hourBase) {
             return new OpeningDay(i, this.numberToHour(period.time[0].openning));
-          } else if (period.time[1].openning >= hourBase) {
+          } else if (period.time[1] && period.time[1].openning >= hourBase) {
             return new OpeningDay(i, this.numberToHour(period.time[1].openning));
           }
           // Return the next day > current day.
-        } else if (arrayOfWeek.indexOf(i) > arrayOfWeek.indexOf(this.numberToDay(dayOfWeek))) {
+        } else if (
+          this.getEnumKeyByEnumValue(WeekDay, i) > this.getEnumKeyByEnumValue(WeekDay, this.numberToDay(dayOfWeek))
+        ) {
           return new OpeningDay(i, this.numberToHour(period.time[0].openning));
           // Return the next day < current day.
         } else if (!periodBeforeCurrentDay) {
@@ -84,70 +96,6 @@ export class StructureService {
     }
     return periodBeforeCurrentDay ? periodBeforeCurrentDay : '';
   }
-  /*private getNextOpening(s: Structure, j: number, dayBase: number, hourBase: number): OpeningDay {
-    // Get the schedules of current day
-    const schedules = s.getDayhours(j);
-    // Condition to stop recursion (If the counter day is equal to the current day)
-    if (j + 1 !== dayBase) {
-      if (schedules.open) {
-        // Check if the counter corresponds to the current day to avoid proposing the schedules already passed
-        if (j !== dayBase) {
-          let openingDay: OpeningDay;
-          schedules.time.every((period: Time) => {
-            if (period.openning) {
-              openingDay = { day: this.numberToDay(j), schedule: this.numberToHour(period.openning) };
-              return false;
-            }
-          });
-
-          // If no period found, repeat
-          if (!openingDay) {
-            return this.getNextOpening(s, j + 1, dayBase, hourBase);
-          }
-          return openingDay;
-        } else {
-          let openingDay: OpeningDay;
-          schedules.time.every((period: Time) => {
-            if (period.openning >= hourBase) {
-              openingDay = { day: ' ', schedule: this.numberToHour(period.openning) };
-              return false;
-            }
-          });
-          // If no period found, repeat
-          if (!openingDay) {
-            return this.getNextOpening(s, j + 1, dayBase, hourBase);
-          }
-          return openingDay;
-        }
-      } else {
-        // If the day isn't equal to Sunday, it is incremented by 1
-        if (j !== Weekday.sunday) {
-          return this.getNextOpening(s, j + 1, dayBase, hourBase);
-        }
-        // If the day is equal to Monday, set position to 0 to activate the stop condition
-        if (dayBase === Weekday.monday) {
-          return this.getNextOpening(s, 0, dayBase, hourBase);
-        }
-        // If the day is equal to Sunday, set position to Monday
-        return this.getNextOpening(s, 1, dayBase, hourBase);
-      }
-    }
-    const schedulesOnSameCurrentDay = s.getDayhours(j + 1);
-    let lastJour: OpeningDay;
-    if (schedulesOnSameCurrentDay.open) {
-      schedulesOnSameCurrentDay.time.every((period: Time) => {
-        if (period.openning && period.openning < hourBase) {
-          lastJour = { day: this.numberToDay(j + 1), schedule: this.numberToHour(period.openning) };
-          return false;
-        }
-        lastJour = { day: '', schedule: 'Aucun horaire disponible' };
-      });
-    } else {
-      lastJour = { day: '', schedule: 'Aucun horaire disponible' };
-    }
-    return lastJour;
-  }
-  */
 
   private numberToDay(n: number): string {
     return Weekday[n];
-- 
GitLab


From 1e357d3bbd698a40bc71920518636eb67de2f7eb Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Thu, 15 Oct 2020 15:19:37 +0200
Subject: [PATCH 20/20] fix: clean code

---
 .../services/structure-list.service.spec.ts   | 34 +++++++++----------
 1 file changed, 16 insertions(+), 18 deletions(-)

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 628a012ff..243602d45 100644
--- a/src/app/structure-list/services/structure-list.service.spec.ts
+++ b/src/app/structure-list/services/structure-list.service.spec.ts
@@ -12,17 +12,13 @@ describe('StructureService', () => {
       imports: [HttpClientModule],
     });
   });
-  let _structureService: StructureService;
-  beforeEach(inject([StructureService], (_s: StructureService) => {
-    _structureService = _s;
+  let structureService: StructureService;
+  beforeEach(inject([StructureService], (s: StructureService) => {
+    structureService = s;
   }));
 
   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
+    // Init structure avec aucun horaire
     const s: Structure = new Structure();
     s.hours = new Week();
     s.hours.monday = new Day(false);
@@ -34,17 +30,19 @@ describe('StructureService', () => {
     s.hours.sunday = new Day(false);
 
     s.hours.thursday.open = true;
-    s.hours.thursday.time = horaire;
+    s.hours.thursday.time = [
+      { openning: 805, closing: 1200 },
+      { openning: 1400, closing: 1600 },
+    ];
 
-    //Init date sur un jeudi à 9h05
-    var dt = new DateTime.local(2020, 10, 8, 9, 5);
-    const result = _structureService.updateOpeningStructure(s, dt);
+    // Init date sur un jeudi à 9h05
+    const dt = new DateTime.local(2020, 10, 8, 9, 5);
+    const result = structureService.updateOpeningStructure(s, dt);
     expect(result.isOpen).toEqual(true);
   });
 
   it('Mise à jour ouverture de la structure : should return false', () => {
-    var horaire = [{ openning: 1400, closing: 1600 }];
-    //Init structure avec aucun horaire
+    // Init structure avec aucun horaire
     const s: Structure = new Structure();
     s.hours = new Week();
     s.hours.monday = new Day();
@@ -56,11 +54,11 @@ describe('StructureService', () => {
     s.hours.sunday = new Day();
 
     s.hours.thursday.open = true;
-    s.hours.thursday.time = horaire;
+    s.hours.thursday.time = [{ openning: 1400, closing: 1600 }];
 
-    //Init date sur un jeudi à 9h05
-    var dt = new DateTime.local(2020, 10, 8, 9, 5);
-    const result = _structureService.updateOpeningStructure(s, dt);
+    // Init date sur un jeudi à 9h05
+    const dt = new DateTime.local(2020, 10, 8, 9, 5);
+    const result = structureService.updateOpeningStructure(s, dt);
     expect(result.isOpen).toEqual(false);
   });
 });
-- 
GitLab