diff --git a/frontend/src/app/pages/agenda/agenda.ts b/frontend/src/app/pages/agenda/agenda.ts index 4544184..b93ec9d 100644 --- a/frontend/src/app/pages/agenda/agenda.ts +++ b/frontend/src/app/pages/agenda/agenda.ts @@ -92,6 +92,22 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { const limitParam = map.get('limit'); const limit = limitParam ? Number(limitParam) : null; const viewParam = (map.get('view') || '').trim(); + const searchParam = (map.get('search') || '').trim(); + + // Gérer le paramètre search pour préremplir le champ de recherche + // Ignorer si c'est le même que celui déjà présent (pour éviter les boucles) + const decodedSearch = searchParam ? decodeURIComponent(searchParam) : ''; + if (this.filterText !== decodedSearch) { + this.filterText = decodedSearch; + // Déclencher le filtre directement sans passer par le Subject pour éviter le debounce + if (decodedSearch) { + // Appliquer le filtre immédiatement + this.applyWhatFilter(); + } else { + // Si le paramètre est vide ou absent, réinitialiser le filtre + this.applyWhatFilter(); + } + } // Définir le filtre what avant de charger les événements if (what) { @@ -222,7 +238,9 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { } convertToCalendarEvents() { - const source = this.filteredEvents.length ? this.filteredEvents : this.events; + // Toujours utiliser filteredEvents si un filtre est actif (texte ou what) + const hasActiveFilter = this.filterText.trim() || this.selectedWhatFilter; + const source = (hasActiveFilter || this.filteredEvents.length > 0) ? this.filteredEvents : this.events; this.calendarEvents = source.map(event => { const startDate = this.parseEventDate(event.properties.start || event.properties.when); const endDate = event.properties.stop ? this.parseEventDate(event.properties.stop) : null; @@ -297,6 +315,58 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { this.availableWhatTypes = Array.from(set).sort(); } + /** + * Normalise un texte en enlevant les accents et en mettant en minuscule + * pour permettre une recherche insensible à la casse et aux accents + */ + private normalizeText(text: string): string { + if (!text) return ''; + return text + .toLowerCase() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, ''); // Enlève les accents + } + + /** + * Cherche récursivement dans toutes les propriétés d'un objet + * pour trouver si une valeur correspond au texte de recherche + */ + private searchInObject(obj: any, searchText: string): boolean { + if (!obj || searchText === '') return false; + + const normalizedSearch = this.normalizeText(searchText); + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const value = obj[key]; + + // Si c'est un objet ou un tableau, chercher récursivement + if (typeof value === 'object' && value !== null) { + if (Array.isArray(value)) { + // Chercher dans chaque élément du tableau + if (value.some(item => this.searchInObject(item, searchText))) { + return true; + } + } else { + // Chercher récursivement dans l'objet + if (this.searchInObject(value, searchText)) { + return true; + } + } + } else { + // Convertir en string et chercher + const stringValue = String(value); + const normalizedValue = this.normalizeText(stringValue); + if (normalizedValue.includes(normalizedSearch)) { + return true; + } + } + } + } + + return false; + } + applyWhatFilter() { console.log('🔍 Application du filtre what:', this.selectedWhatFilter); console.log('📊 Événements avant filtrage:', this.events.length); @@ -313,17 +383,12 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { // Appliquer le filtre texte si présent if (this.filterText.trim()) { - const searchText = this.filterText.trim().toLowerCase(); + const searchText = this.filterText.trim(); filtered = filtered.filter(e => { - const props = e?.properties || {}; - return ( - (props.label || '').toLowerCase().includes(searchText) || - (props.name || '').toLowerCase().includes(searchText) || - (props.description || '').toLowerCase().includes(searchText) || - (props.what || '').toLowerCase().includes(searchText) || - (props.where || '').toLowerCase().includes(searchText) - ); + // Chercher dans tout l'objet événement (properties, geometry, etc.) + return this.searchInObject(e, searchText); }); + console.log('✅ Événements après filtrage texte:', filtered.length); } this.filteredEvents = filtered; @@ -340,8 +405,32 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { } filterEventsByText(text: string) { - this.filterText = text; + const trimmedText = text ? text.trim() : ''; + this.filterText = trimmedText; this.applyWhatFilter(); + + // Mettre à jour l'URL avec le paramètre search (seulement si différent de l'URL actuelle) + const currentSearchParam = this.route.snapshot.queryParamMap.get('search') || ''; + const decodedCurrentSearch = currentSearchParam ? decodeURIComponent(currentSearchParam) : ''; + + // Ne mettre à jour l'URL que si la valeur a changé + if (decodedCurrentSearch !== trimmedText) { + const currentParams = { ...this.route.snapshot.queryParams }; + if (trimmedText) { + // Encoder le texte de recherche pour l'URL + currentParams['search'] = encodeURIComponent(trimmedText); + } else { + // Supprimer le paramètre search si le champ est vide + delete currentParams['search']; + } + + this.router.navigate([], { + relativeTo: this.route, + queryParams: currentParams, + queryParamsHandling: 'merge', + replaceUrl: true // Utiliser replaceUrl pour éviter d'ajouter des entrées dans l'historique + }); + } } onWhatFilterChange(value: string) { @@ -362,7 +451,9 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { buildGroupedEvents() { const groups: Record = {}; - const source = this.filteredEvents.length ? this.filteredEvents : this.events; + // Toujours utiliser filteredEvents si un filtre est actif (texte ou what) + const hasActiveFilter = this.filterText.trim() || this.selectedWhatFilter; + const source = (hasActiveFilter || this.filteredEvents.length > 0) ? this.filteredEvents : this.events; for (const ev of source) { const d = this.getEventStartDate(ev); const key = this.toDateKey(d); @@ -423,7 +514,9 @@ export class Agenda implements OnInit, OnDestroy, AfterViewInit { const selectedDateKey = this.toDateKey(this.selectedDate); const groups: Record = {}; - const source = this.filteredEvents.length ? this.filteredEvents : this.events; + // Toujours utiliser filteredEvents si un filtre est actif (texte ou what) + const hasActiveFilter = this.filterText.trim() || this.selectedWhatFilter; + const source = (hasActiveFilter || this.filteredEvents.length > 0) ? this.filteredEvents : this.events; for (const ev of source) { const d = this.getEventStartDate(ev);