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