composant recherche et filtre disponible dans toute l'application
This commit is contained in:
12
src/app/domain/search/search.repository.ts
Normal file
12
src/app/domain/search/search.repository.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { SearchFilters } from '@app/domain/search/search-filters';
|
||||||
|
import { WritableSignal } from '@angular/core';
|
||||||
|
|
||||||
|
export interface SearchRepository {
|
||||||
|
search(query: string): void;
|
||||||
|
sortBy(value: string): void;
|
||||||
|
filterByProfileVerified(): void;
|
||||||
|
filterBySecteur(secteur: string): void;
|
||||||
|
filterByProfession(profession: string): void;
|
||||||
|
reset(): void;
|
||||||
|
getFilters(): WritableSignal<SearchFilters>;
|
||||||
|
}
|
||||||
57
src/app/infrastructure/search/search.service.ts
Normal file
57
src/app/infrastructure/search/search.service.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Injectable, signal, WritableSignal } from '@angular/core';
|
||||||
|
import { SearchRepository } from '@app/domain/search/search.repository';
|
||||||
|
import { SearchFilters } from '@app/domain/search/search-filters';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class SearchService implements SearchRepository {
|
||||||
|
private filters = signal<SearchFilters>({
|
||||||
|
search: '',
|
||||||
|
verified: false,
|
||||||
|
secteur: null,
|
||||||
|
profession: null,
|
||||||
|
sort: 'recent',
|
||||||
|
});
|
||||||
|
|
||||||
|
filterByProfession(profession: string | null) {
|
||||||
|
const filter = { ...this.filters(), profession };
|
||||||
|
this.filters.set(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
filterByProfileVerified() {
|
||||||
|
const filters = { ...this.filters(), verified: true };
|
||||||
|
this.filters.set(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
filterBySecteur(secteur: string | null) {
|
||||||
|
const filters = { ...this.filters(), secteur };
|
||||||
|
this.filters.set(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilters(): WritableSignal<SearchFilters> {
|
||||||
|
return this.filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
const filters = {
|
||||||
|
...this.filters(),
|
||||||
|
verified: false,
|
||||||
|
sort: 'recent',
|
||||||
|
search: '',
|
||||||
|
profession: null,
|
||||||
|
secteur: null,
|
||||||
|
};
|
||||||
|
this.filters.set(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
search(query: string) {
|
||||||
|
const filters = { ...this.filters(), search: query };
|
||||||
|
this.filters.set(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
sortBy(value: string) {
|
||||||
|
const filters = { ...this.filters(), sort: value };
|
||||||
|
this.filters.set(filters);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { SearchComponent } from '@app/shared/features/search/search.component';
|
import { SearchComponent } from '@app/shared/features/search/search.component';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { SearchFilters } from '@app/domain/search-filters';
|
import { SearchFilters } from '@app/domain/search/search-filters';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { UntilDestroy } from '@ngneat/until-destroy';
|
|||||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||||
import { LoadingComponent } from '@app/shared/components/loading/loading.component';
|
import { LoadingComponent } from '@app/shared/components/loading/loading.component';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { SearchFilters } from '@app/domain/search-filters';
|
import { SearchFilters } from '@app/domain/search/search-filters';
|
||||||
|
import { SearchService } from '@app/infrastructure/search/search.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-profile-list',
|
selector: 'app-profile-list',
|
||||||
@@ -16,6 +17,7 @@ import { SearchFilters } from '@app/domain/search-filters';
|
|||||||
})
|
})
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
export class ProfileListComponent implements OnInit {
|
export class ProfileListComponent implements OnInit {
|
||||||
|
private readonly searchService = inject(SearchService);
|
||||||
private readonly facade = inject(ProfileFacade);
|
private readonly facade = inject(ProfileFacade);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
@@ -23,12 +25,13 @@ export class ProfileListComponent implements OnInit {
|
|||||||
protected readonly loading = this.facade.loading;
|
protected readonly loading = this.facade.loading;
|
||||||
protected readonly error = this.facade.error;
|
protected readonly error = this.facade.error;
|
||||||
|
|
||||||
|
protected readonly searchFilters = this.searchService.getFilters();
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.facade.load();
|
this.facade.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
showNewQuery(filters: SearchFilters) {
|
showNewQuery(filters: SearchFilters) {
|
||||||
console.log(filters);
|
|
||||||
this.router.navigate(['/profiles'], { queryParams: { search: filters.search } });
|
this.router.navigate(['/profiles'], { queryParams: { search: filters.search } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,24 +29,24 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="toggleVerifiedFilter()"
|
(click)="toggleVerifiedFilter()"
|
||||||
[class.ring-2]="filters.verified"
|
[class.ring-2]="filters().verified"
|
||||||
[class.ring-purple-500]="filters.verified"
|
[class.ring-purple-500]="filters().verified"
|
||||||
class="group relative flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
class="group relative flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
class="flex-shrink-0 w-5 h-5 rounded-full flex items-center justify-center"
|
class="flex-shrink-0 w-5 h-5 rounded-full flex items-center justify-center"
|
||||||
[class.bg-purple-100]="filters.verified"
|
[class.bg-purple-100]="filters().verified"
|
||||||
[class.dark:bg-purple-900]="filters.verified"
|
[class.dark:bg-purple-900]="filters().verified"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="w-4 h-4"
|
class="w-4 h-4"
|
||||||
[class.text-purple-600]="filters.verified"
|
[class.text-purple-600]="filters().verified"
|
||||||
[class.dark:text-purple-400]="filters.verified"
|
[class.dark:text-purple-400]="filters().verified"
|
||||||
[class.text-gray-400]="!filters.verified"
|
[class.text-gray-400]="!filters().verified"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300"> Profils vérifiés </span>
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300"> Profils vérifiés </span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (filters.verified) {
|
@if (filters().verified) {
|
||||||
<div
|
<div
|
||||||
class="flex-shrink-0 w-5 h-5 rounded-full bg-purple-600 text-white flex items-center justify-center"
|
class="flex-shrink-0 w-5 h-5 rounded-full bg-purple-600 text-white flex items-center justify-center"
|
||||||
>
|
>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
<!-- Tags des filtres actifs -->
|
<!-- Tags des filtres actifs -->
|
||||||
@if (hasActiveFilters()) {
|
@if (hasActiveFilters()) {
|
||||||
<div class="flex flex-wrap gap-2 mt-4">
|
<div class="flex flex-wrap gap-2 mt-4">
|
||||||
@if (filters.verified) {
|
@if (filters().verified) {
|
||||||
<span
|
<span
|
||||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
||||||
>
|
>
|
||||||
@@ -126,11 +126,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@if (filters.secteur) {
|
@if (filters().secteur) {
|
||||||
<span
|
<span
|
||||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
||||||
>
|
>
|
||||||
{{ filters.secteur }}
|
{{ filters().secteur }}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="selectSector(null)"
|
(click)="selectSector(null)"
|
||||||
@@ -149,11 +149,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@if (filters.profession) {
|
@if (filters().profession) {
|
||||||
<span
|
<span
|
||||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-xs font-medium"
|
||||||
>
|
>
|
||||||
{{ filters.profession }}
|
{{ filters().profession }}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="selectProfession(null)"
|
(click)="selectProfession(null)"
|
||||||
@@ -181,8 +181,8 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="toggleSectorDropdown()"
|
(click)="toggleSectorDropdown()"
|
||||||
[class.ring-2]="filters.secteur"
|
[class.ring-2]="filters().secteur"
|
||||||
[class.ring-purple-500]="filters.secteur"
|
[class.ring-purple-500]="filters().secteur"
|
||||||
class="w-full flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
class="w-full flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -191,9 +191,9 @@
|
|||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="w-5 h-5"
|
class="w-5 h-5"
|
||||||
[class.text-purple-600]="filters.secteur"
|
[class.text-purple-600]="filters().secteur"
|
||||||
[class.dark:text-purple-400]="filters.secteur"
|
[class.dark:text-purple-400]="filters().secteur"
|
||||||
[class.text-gray-400]="!filters.secteur"
|
[class.text-gray-400]="!filters().secteur"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
<path d="M16.5 6.5h-1v8.75a1.25 1.25 0 102.5 0V8a1.5 1.5 0 00-1.5-1.5z" />
|
<path d="M16.5 6.5h-1v8.75a1.25 1.25 0 102.5 0V8a1.5 1.5 0 00-1.5-1.5z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{{ filters.secteur || 'Secteur' }}
|
{{ filters().secteur || 'Secteur' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<svg
|
<svg
|
||||||
@@ -229,8 +229,8 @@
|
|||||||
type="button"
|
type="button"
|
||||||
(click)="selectSector(null)"
|
(click)="selectSector(null)"
|
||||||
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
[class.bg-purple-50]="!filters.secteur"
|
[class.bg-purple-50]="!filters().secteur"
|
||||||
[class.dark:bg-purple-900]="!filters.secteur"
|
[class.dark:bg-purple-900]="!filters().secteur"
|
||||||
>
|
>
|
||||||
<span class="text-gray-700 dark:text-gray-300">Tous les secteurs</span>
|
<span class="text-gray-700 dark:text-gray-300">Tous les secteurs</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -239,8 +239,8 @@
|
|||||||
type="button"
|
type="button"
|
||||||
(click)="selectSector(sector.nom)"
|
(click)="selectSector(sector.nom)"
|
||||||
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
[class.bg-purple-50]="filters.secteur === sector.nom"
|
[class.bg-purple-50]="filters().secteur === sector.nom"
|
||||||
[class.dark:bg-purple-900]="filters.secteur === sector.nom"
|
[class.dark:bg-purple-900]="filters().secteur === sector.nom"
|
||||||
>
|
>
|
||||||
<span class="text-gray-700 dark:text-gray-300">{{ sector.nom }}</span>
|
<span class="text-gray-700 dark:text-gray-300">{{ sector.nom }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -255,8 +255,8 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="toggleProfessionDropdown()"
|
(click)="toggleProfessionDropdown()"
|
||||||
[class.ring-2]="filters.profession"
|
[class.ring-2]="filters().profession"
|
||||||
[class.ring-purple-500]="filters.profession"
|
[class.ring-purple-500]="filters().profession"
|
||||||
class="w-full flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
class="w-full flex items-center justify-between gap-3 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-700 hover:border-purple-500 dark:hover:border-purple-400 transition-all bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -265,9 +265,9 @@
|
|||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="w-5 h-5"
|
class="w-5 h-5"
|
||||||
[class.text-purple-600]="filters.profession"
|
[class.text-purple-600]="filters().profession"
|
||||||
[class.dark:text-purple-400]="filters.profession"
|
[class.dark:text-purple-400]="filters().profession"
|
||||||
[class.text-gray-400]="!filters.profession"
|
[class.text-gray-400]="!filters().profession"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{{ filters.profession || 'Profession' }}
|
{{ filters().profession || 'Profession' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<svg
|
<svg
|
||||||
@@ -305,8 +305,8 @@
|
|||||||
type="button"
|
type="button"
|
||||||
(click)="selectProfession(null)"
|
(click)="selectProfession(null)"
|
||||||
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
[class.bg-purple-50]="!filters.profession"
|
[class.bg-purple-50]="!filters().profession"
|
||||||
[class.dark:bg-purple-900]="!filters.profession"
|
[class.dark:bg-purple-900]="!filters().profession"
|
||||||
>
|
>
|
||||||
<span class="text-gray-700 dark:text-gray-300">Toutes les professions</span>
|
<span class="text-gray-700 dark:text-gray-300">Toutes les professions</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -315,8 +315,8 @@
|
|||||||
type="button"
|
type="button"
|
||||||
(click)="selectProfession(profile.profession)"
|
(click)="selectProfession(profile.profession)"
|
||||||
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
[class.bg-purple-50]="filters.profession === profile.profession"
|
[class.bg-purple-50]="filters().profession === profile.profession"
|
||||||
[class.dark:bg-purple-900]="filters.profession === profile.profession"
|
[class.dark:bg-purple-900]="filters().profession === profile.profession"
|
||||||
>
|
>
|
||||||
<span class="text-gray-700 dark:text-gray-300">{{ profile.profession }}</span>
|
<span class="text-gray-700 dark:text-gray-300">{{ profile.profession }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -374,8 +374,8 @@
|
|||||||
type="button"
|
type="button"
|
||||||
(click)="selectSort(sort)"
|
(click)="selectSort(sort)"
|
||||||
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
class="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
[class.bg-purple-50]="filters.sort === sort.value"
|
[class.bg-purple-50]="filters().sort === sort.value"
|
||||||
[class.dark:bg-purple-900]="filters.sort === sort.value"
|
[class.dark:bg-purple-900]="filters().sort === sort.value"
|
||||||
>
|
>
|
||||||
<span class="text-gray-700 dark:text-gray-300">{{ sort.label }}</span>
|
<span class="text-gray-700 dark:text-gray-300">{{ sort.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Component, inject, OnInit, output } from '@angular/core';
|
import { Component, inject, OnInit } from '@angular/core';
|
||||||
import { SearchFilters } from '@app/domain/search-filters';
|
|
||||||
import { SectorFacade } from '@app/ui/sectors/sector.facade';
|
import { SectorFacade } from '@app/ui/sectors/sector.facade';
|
||||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||||
import { NgTemplateOutlet } from '@angular/common';
|
import { NgTemplateOutlet } from '@angular/common';
|
||||||
|
import { SearchService } from '@app/infrastructure/search/search.service';
|
||||||
|
|
||||||
interface SortOption {
|
interface SortOption {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -18,7 +18,7 @@ interface SortOption {
|
|||||||
styleUrl: './filter.component.scss',
|
styleUrl: './filter.component.scss',
|
||||||
})
|
})
|
||||||
export class FilterComponent implements OnInit {
|
export class FilterComponent implements OnInit {
|
||||||
filtersChanged = output<SearchFilters>();
|
private readonly searchService = inject(SearchService);
|
||||||
|
|
||||||
// État des dropdowns
|
// État des dropdowns
|
||||||
showSectorDropdown = false;
|
showSectorDropdown = false;
|
||||||
@@ -26,13 +26,7 @@ export class FilterComponent implements OnInit {
|
|||||||
showSortDropdown = false;
|
showSortDropdown = false;
|
||||||
|
|
||||||
// Filtres
|
// Filtres
|
||||||
filters: SearchFilters = {
|
filters = this.searchService.getFilters();
|
||||||
search: '',
|
|
||||||
verified: false,
|
|
||||||
secteur: null,
|
|
||||||
profession: null,
|
|
||||||
sort: 'recent',
|
|
||||||
};
|
|
||||||
|
|
||||||
protected readonly sectorFacade = inject(SectorFacade);
|
protected readonly sectorFacade = inject(SectorFacade);
|
||||||
protected readonly sectors = this.sectorFacade.sectors;
|
protected readonly sectors = this.sectorFacade.sectors;
|
||||||
@@ -57,13 +51,12 @@ export class FilterComponent implements OnInit {
|
|||||||
];
|
];
|
||||||
|
|
||||||
get sortLabel(): string {
|
get sortLabel(): string {
|
||||||
return this.sortOptions.find((s) => s.value === this.filters.sort)?.label || 'Trier par';
|
return this.sortOptions.find((s) => s.value === this.filters().sort)?.label || 'Trier par';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gestion du filtre "Vérifiés"
|
// Gestion du filtre "Vérifiés"
|
||||||
toggleVerifiedFilter(): void {
|
toggleVerifiedFilter(): void {
|
||||||
this.filters.verified = !this.filters.verified;
|
this.filters().verified = !this.filters().verified;
|
||||||
this.emitFilters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gestion des dropdowns
|
// Gestion des dropdowns
|
||||||
@@ -87,42 +80,27 @@ export class FilterComponent implements OnInit {
|
|||||||
|
|
||||||
// Sélection des filtres
|
// Sélection des filtres
|
||||||
selectSector(sector: string | null): void {
|
selectSector(sector: string | null): void {
|
||||||
this.filters.secteur = sector;
|
this.searchService.filterBySecteur(sector);
|
||||||
this.showSectorDropdown = false;
|
this.showSectorDropdown = false;
|
||||||
this.emitFilters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectProfession(profession: string | null): void {
|
selectProfession(profession: string | null): void {
|
||||||
this.filters.profession = profession;
|
this.searchService.filterByProfession(profession);
|
||||||
this.showProfessionDropdown = false;
|
this.showProfessionDropdown = false;
|
||||||
this.emitFilters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectSort(sort: SortOption): void {
|
selectSort(sort: SortOption): void {
|
||||||
this.filters.sort = sort.value;
|
this.searchService.sortBy(sort.value);
|
||||||
this.showSortDropdown = false;
|
this.showSortDropdown = false;
|
||||||
this.emitFilters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifier si des filtres sont actifs
|
// Vérifier si des filtres sont actifs
|
||||||
hasActiveFilters(): boolean {
|
hasActiveFilters(): boolean {
|
||||||
return this.filters.verified || !!this.filters.secteur || !!this.filters.profession;
|
return this.filters().verified || !!this.filters().secteur || !!this.filters().profession;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effacer tous les filtres
|
// Effacer tous les filtres
|
||||||
clearAllFilters(): void {
|
clearAllFilters(): void {
|
||||||
this.filters = {
|
this.searchService.reset();
|
||||||
search: '',
|
|
||||||
verified: false,
|
|
||||||
secteur: null,
|
|
||||||
profession: null,
|
|
||||||
sort: 'recent',
|
|
||||||
};
|
|
||||||
this.emitFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Émettre les changements de filtres
|
|
||||||
private emitFilters(): void {
|
|
||||||
this.filtersChanged.emit({ ...this.filters });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="w-full space-y-4 sm:space-y-6 z-[800]">
|
<div class="w-full space-y-4 sm:space-y-6 z-[800]">
|
||||||
<!-- Filtres -->
|
<!-- Filtres -->
|
||||||
<div>
|
<div>
|
||||||
<app-filter (filtersChanged)="onFiltersChanged($event)" />
|
<app-filter />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Barre de recherche -->
|
<!-- Barre de recherche -->
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Component, inject, output } from '@angular/core';
|
import { Component, inject, output } from '@angular/core';
|
||||||
import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { FilterComponent } from '@app/shared/features/filter/filter.component';
|
import { FilterComponent } from '@app/shared/features/filter/filter.component';
|
||||||
import { SearchFilters } from '@app/domain/search-filters';
|
import { SearchFilters } from '@app/domain/search/search-filters';
|
||||||
import { NgTemplateOutlet } from '@angular/common';
|
import { NgTemplateOutlet } from '@angular/common';
|
||||||
|
import { SearchService } from '@app/infrastructure/search/search.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search',
|
selector: 'app-search',
|
||||||
@@ -12,28 +13,18 @@ import { NgTemplateOutlet } from '@angular/common';
|
|||||||
styleUrl: './search.component.scss',
|
styleUrl: './search.component.scss',
|
||||||
})
|
})
|
||||||
export class SearchComponent {
|
export class SearchComponent {
|
||||||
|
private readonly searchService = inject(SearchService);
|
||||||
onSearchChange = output<SearchFilters>();
|
onSearchChange = output<SearchFilters>();
|
||||||
private formBuilder: FormBuilder = inject(FormBuilder);
|
private formBuilder: FormBuilder = inject(FormBuilder);
|
||||||
|
|
||||||
// Filtres
|
|
||||||
filters: SearchFilters = {
|
|
||||||
search: '',
|
|
||||||
verified: false,
|
|
||||||
secteur: null,
|
|
||||||
profession: null,
|
|
||||||
sort: 'recent',
|
|
||||||
};
|
|
||||||
|
|
||||||
searchForm = this.formBuilder.group({
|
searchForm = this.formBuilder.group({
|
||||||
search: new FormControl('', Validators.required),
|
search: new FormControl('', Validators.required),
|
||||||
});
|
});
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
const search = this.searchForm.value.search?.toLowerCase()!;
|
const search = this.searchForm.value.search?.toLowerCase()!;
|
||||||
this.onSearchChange.emit({ ...this.filters, search });
|
this.searchService.search(search);
|
||||||
}
|
const filters = this.searchService.getFilters();
|
||||||
|
this.onSearchChange.emit({ ...filters(), search });
|
||||||
onFiltersChanged(event: SearchFilters) {
|
|
||||||
this.filters = event;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user