Skip to content
Snippets Groups Projects
Commit b11ebed9 authored by Marlène SIMONDANT's avatar Marlène SIMONDANT
Browse files

Merge branch '476-3-annuaire-filtres-2' into 'dev'

476-3-annuaire-filtres-2

See merge request !932
parents f239433f f1bd1712
Branches
Tags
2 merge requests!945V3.3.0,!932476-3-annuaire-filtres-2
......@@ -14,14 +14,26 @@
[checkedModules]="employerCheckedModules"
(selectEvent)="onSelectEmployers($event)"
/>
<app-collapsable-filter
[label]="'Territoire'"
[categories]="territoryCategories"
[checkedModules]="territoryCheckedModules"
(selectEvent)="onSelectTerritory($event)"
/>
<app-collapsable-filter
[label]="'Commune'"
[categories]="communeCategories"
[checkedModules]="communeCheckedModules"
(selectEvent)="onSelectCommune($event)"
/>
</div>
</div>
<div *ngIf="searchService.checkedFilterList.length" class="filterTags isntPhoneContent">
<div *ngIf="checkedModulesFilter.length" class="filterTags isntPhoneContent">
<div class="title">Filtres :</div>
<app-tag-item
*ngFor="let filter of searchService.checkedFilterList"
*ngFor="let filter of checkedModulesFilter"
[ariaLabel]="'Supprimer filtre ' + filter"
[label]="filter"
[label]="filter.displayText"
[size]="'small'"
[color]="'grey'"
[iconName]="'cross'"
......
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin, lastValueFrom } from 'rxjs';
import { firstValueFrom, forkJoin, lastValueFrom } from 'rxjs';
import { Category } from '../../structure-list/models/category.model';
import { Module } from '../../structure-list/models/module.model';
import { SearchService } from '../../structure-list/services/search.service';
......@@ -12,22 +12,20 @@ import { SearchQuery } from '../models/searchQuery.model';
styleUrls: ['./annuaire-header.component.scss'],
})
export class AnnuaireHeaderComponent implements OnInit, OnChanges {
/** Input to reset filters, needed because a reset button is displayed on the result list when it is empty */
@Input() shouldResetFilters = 0;
@Output() searchEvent = new EventEmitter<SearchQuery>();
public jobGroupCategories: Category[] = [];
public employerCategories: Category[] = [];
public territoryCategories: Category[] = [];
public communeCategories: Category[] = [];
public searchInput = '';
// Checked modules for each filter (used to receive changes from collapsable-filter)
public checkedModulesFilter: Module[] = [];
public jobGroupCheckedModules: Module[] = [];
public employerCheckedModules: Module[] = [];
private jobGroups: string[] = [];
private employers: string[] = [];
private jobGroupFilterChecked: string[] = [];
private employerFilterChecked: string[] = [];
public territoryCheckedModules: Module[] = [];
public communeCheckedModules: Module[] = [];
constructor(
private activatedRoute: ActivatedRoute,
......@@ -36,12 +34,15 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
) {}
async ngOnInit(): Promise<void> {
this.loadQueryParams();
// Will store the different categories
await this.loadFilters();
this.loadQueryParams();
if (this.searchService.previousResult$.getValue().docs.length === 0) {
this.applyFilter();
} else {
this.setCheckedModulesFilter();
}
}
......@@ -54,15 +55,27 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
private loadQueryParams(): void {
const queryParams = this.activatedRoute.snapshot.queryParams;
this.searchInput = queryParams['search'] ?? '';
this.jobGroupFilterChecked = queryParams['jobs']?.split('|') ?? [];
this.employerFilterChecked = queryParams['employers']?.split('|') ?? [];
this.searchService.checkedFilterList = [...this.jobGroupFilterChecked, ...this.employerFilterChecked];
this.searchService.annuaireSearchQuery = {
search: this.searchInput,
page: Number(queryParams['page']) || 1,
jobFilters: this.jobGroupFilterChecked,
employerFilters: this.employerFilterChecked,
};
const jobGroupFilterChecked = queryParams['jobs']?.split('|') ?? [];
const employerFilterChecked = queryParams['employers']?.split('|') ?? [];
const territoryFilterChecked = queryParams['territories']?.split('|') ?? [];
const communeFilterChecked = queryParams['communes']?.split('|') ?? [];
// We need to map to set the type in module name, as it is done in checkedModules of the collapsable-filter/more-filters component
this.jobGroupCheckedModules = this.jobGroupCategories[0]?.modules
.filter((module) => jobGroupFilterChecked.includes(module.name))
.map((module) => ({ ...module, displayText: module.name, name: 'jobGroup' }));
this.employerCheckedModules = this.employerCategories[0]?.modules
.filter((module) => employerFilterChecked.includes(module.name))
.map((module) => ({ ...module, displayText: module.name, name: 'employer' }));
this.territoryCheckedModules = this.territoryCategories[0]?.modules
.filter((module) => territoryFilterChecked.includes(module.name))
.map((module) => ({ ...module, displayText: module.name, name: 'ctm' }));
this.communeCheckedModules = this.communeCategories[0]?.modules
.filter((module) => communeFilterChecked.includes(module.name))
.map((module) => ({ ...module, displayText: module.name, name: 'commune' }));
}
public onSearchSubmitted(value: string): void {
......@@ -76,13 +89,17 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
if (this.searchInput.trim()) {
queryParams.search = this.searchInput.trim();
}
if (this.jobGroupFilterChecked.length) {
queryParams.jobs = this.jobGroupFilterChecked.join('|');
if (this.jobGroupCheckedModules.length) {
queryParams.jobs = this.jobGroupCheckedModules.map((module) => module.displayText).join('|');
}
if (this.employerFilterChecked.length) {
queryParams.employers = this.employerFilterChecked.join('|');
if (this.employerCheckedModules.length) {
queryParams.employers = this.employerCheckedModules.map((module) => module.displayText).join('|');
}
if (this.territoryCheckedModules.length) {
queryParams.territories = this.territoryCheckedModules.map((module) => module.displayText).join('|');
}
if (this.communeCheckedModules.length) {
queryParams.communes = this.communeCheckedModules.map((module) => module.displayText).join('|');
}
// Delay to avoid error in console: "NG0100: ExpressionChangedAfterItHasBeenCheckedError"
......@@ -96,19 +113,25 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
);
}
public applyFilter(page = 1): void {
this.jobGroupCheckedModules = this.jobGroupFilterChecked.map((filter) => {
return new Module(filter, 'jobGroup', filter);
});
this.employerCheckedModules = this.employerFilterChecked.map((filter) => {
return new Module(filter, 'employer', filter);
});
private setCheckedModulesFilter(): void {
this.checkedModulesFilter = [
...this.jobGroupCheckedModules,
...this.employerCheckedModules,
...this.territoryCheckedModules,
...this.communeCheckedModules,
];
}
private applyFilter(page = 1): void {
this.setCheckedModulesFilter();
this.searchEvent.emit({
search: this.searchInput.trim(),
page: page,
jobFilters: this.jobGroupFilterChecked,
employerFilters: this.employerFilterChecked,
jobFilters: this.jobGroupCheckedModules.map((module) => module.id),
employerFilters: this.employerCheckedModules.map((module) => module.id),
territoryFilters: this.territoryCheckedModules.map((module) => module.id),
communeFilters: this.communeCheckedModules.map((module) => module.id),
});
this.updateQueryParams();
......@@ -122,8 +145,6 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
employers: this.searchService.getEmployers(),
}),
);
this.jobGroups = jobGroups;
this.employers = employers;
this.jobGroupCategories = [
{
id: 'jobGroup',
......@@ -135,8 +156,8 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
jobGroups.forEach((jobGroup) => {
this.jobGroupCategories[0].modules.push({
disabled: false,
name: jobGroup,
id: jobGroup,
name: jobGroup.name,
id: jobGroup._id,
});
});
......@@ -151,43 +172,86 @@ export class AnnuaireHeaderComponent implements OnInit, OnChanges {
employers.forEach((employer) => {
this.employerCategories[0].modules.push({
disabled: false,
name: employer,
id: employer,
name: employer.name,
id: employer._id,
});
});
}
private splitFilters(checkedFilterList: string[]): void {
this.jobGroupFilterChecked = checkedFilterList.filter((filter) => this.jobGroups.includes(filter));
this.employerFilterChecked = checkedFilterList.filter((filter) => this.employers.includes(filter));
// Territories
const categories = await firstValueFrom(this.searchService.getCategories());
const ctmCategory = categories.find((c) => c.id === 'ctm');
if (ctmCategory) {
this.territoryCategories = [
{
id: 'ctm',
name: 'ctm',
theme: 'ctm',
modules: ctmCategory.modules.map((module) => ({
disabled: false,
name: module.name,
id: module.id,
})),
},
];
}
// Communes
const communes = await lastValueFrom(this.searchService.getCommunesWithUsers());
this.communeCategories = [
{
id: 'commune',
name: 'Commune',
theme: 'Communes',
modules: communes.map((commune) => ({
disabled: false,
name: commune.commune,
id: commune.inseeCode,
})),
},
];
}
public onSelectJobGroups(jobGroupCheckedModules: Module[]): void {
this.jobGroupFilterChecked = jobGroupCheckedModules.map((module) => module.id);
this.searchService.checkedFilterList = [...this.jobGroupFilterChecked, ...this.employerFilterChecked];
this.jobGroupCheckedModules = jobGroupCheckedModules;
this.applyFilter();
}
public onSelectEmployers(employerCheckedModules: Module[]): void {
this.employerFilterChecked = employerCheckedModules.map((module) => module.id);
this.searchService.checkedFilterList = [...this.jobGroupFilterChecked, ...this.employerFilterChecked];
this.employerCheckedModules = employerCheckedModules;
this.applyFilter();
}
public onSelectTerritory(territoryCheckedModules: Module[]): void {
this.territoryCheckedModules = territoryCheckedModules;
this.applyFilter();
}
public onSelectCommune(communeCheckedModules: Module[]): void {
this.communeCheckedModules = communeCheckedModules;
this.applyFilter();
}
public resetFilters(): void {
this.searchInput = '';
this.searchService.checkedFilterList = [];
this.jobGroupFilterChecked = [];
this.employerFilterChecked = [];
this.jobGroupCheckedModules = [];
this.employerCheckedModules = [];
this.territoryCheckedModules = [];
this.communeCheckedModules = [];
this.applyFilter();
}
public removeFilter(filter: string): void {
const index = this.searchService.checkedFilterList.findIndex((checkedFilter: string) => checkedFilter === filter);
public removeFilter(module: Module): void {
const index: number = this.checkedModulesFilter.findIndex((m: Module) => m.id === module.id);
if (index !== -1) {
this.searchService.checkedFilterList.splice(index, 1);
this.splitFilters(this.searchService.checkedFilterList);
this.updateQueryParams();
// update global list of checked filters
this.checkedModulesFilter = this.checkedModulesFilter.filter((m: Module) => m.id !== module.id);
// update each select
this.jobGroupCheckedModules = this.checkedModulesFilter.filter((module) => module.name === 'jobGroup');
this.employerCheckedModules = this.checkedModulesFilter.filter((module) => module.name === 'employer');
this.territoryCheckedModules = this.checkedModulesFilter.filter((module) => module.name === 'ctm');
this.communeCheckedModules = this.checkedModulesFilter.filter((module) => module.name === 'commune');
// this.updateQueryParams();
this.applyFilter();
}
}
......
......@@ -24,16 +24,6 @@ export class AnnuaireComponent implements OnInit {
private isAlreadySearching = false;
ngOnInit(): void {
this.route.queryParams.subscribe((params) => {
const searchQuery: SearchQuery = {
search: params['search'] || '',
page: Number(params['page']) || 1,
jobFilters: params['jobs'] ? params['jobs'].split('|') : [],
employerFilters: params['employers'] ? params['employers'].split('|') : [],
};
this.searchUsers(searchQuery);
});
if (this.userIsLoggedIn()) {
this.userList = this.searchService.previousResult$.getValue().docs;
this.totalUserResult = this.searchService.previousResult$.getValue().count;
......@@ -66,7 +56,14 @@ export class AnnuaireComponent implements OnInit {
this.loadParams(params);
this.isLoading = true;
this.searchService
.searchUserRegistry(params.search, params.page, params.jobFilters, params.employerFilters)
.searchUserRegistry(
params.search,
params.page,
params.jobFilters,
params.employerFilters,
params.territoryFilters,
params.communeFilters,
)
.then((res) => {
// We only push new users instead of reassigning userList to avoid an unwanted scroll
this.userList.push(...res.docs);
......
......@@ -5,6 +5,8 @@ export interface SearchQuery {
page?: number;
jobFilters?: string[];
employerFilters?: string[];
territoryFilters?: string[];
communeFilters?: string[];
}
export interface SearchResults {
count: number;
......
......@@ -11,7 +11,6 @@ import { Module } from '../models/module.model';
})
export class SearchService {
public annuaireSearchQuery: SearchQuery;
public checkedFilterList: string[] = [];
public previousResult$ = new BehaviorSubject<SearchResults>({ count: 0, docs: [] });
constructor(private http: HttpClient) {}
......@@ -23,21 +22,25 @@ export class SearchService {
return this.http.get('/api/categories').pipe(map((data: any[]) => data.map((item) => new Category(item))));
}
public getJobsGroups(): Observable<any> {
return this.http.get('/api/jobs-groups').pipe(map((data: any[]) => data.map((item) => item.name)));
return this.http.get('/api/jobs-groups');
}
public getEmployers(): Observable<string[]> {
return this.http.get('/api/employer').pipe(map((data: any[]) => data.map((item) => item.name)));
public getEmployers(): Observable<any> {
return this.http.get('/api/employer');
}
public async searchUserRegistry(
searchTerm: string,
page: number,
jobsGroup?: string[],
employers?: string[],
territories?: string[],
communes?: string[],
): Promise<SearchResults> {
const users = await lastValueFrom(
this.http.post<SearchResults>(`/api/userRegistry/?search=${searchTerm}`, {
jobsGroup,
employer: employers,
territory: territories,
commune: communes,
page,
}),
);
......@@ -49,4 +52,7 @@ export class SearchService {
public getIndex(array: Module[], id: string, categ: string): number {
return array.findIndex((m: Module) => m.id === id && m.name === categ);
}
public getCommunesWithUsers(): Observable<any> {
return this.http.get<any>('/api/userRegistry/communesWithUsers');
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment