From d22dbde2e75b17669d1ed7e95d3d66b2ac9d7355 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Fri, 10 Oct 2025 16:59:13 +0200 Subject: [PATCH] add search filter, toggle options, count unlocated events --- .../src/app/maps/all-events/all-events.html | 1 + frontend/src/app/pages/agenda/agenda.ts | 51 ++- .../community-upcoming/community-upcoming.ts | 6 +- .../app/pages/events-docs/events-docs.html | 60 ++- .../app/pages/events-docs/events-docs.scss | 99 +++++ .../src/app/pages/events-docs/events-docs.ts | 33 ++ frontend/src/app/pages/home/home.html | 351 +++++++++++------- frontend/src/app/pages/home/home.scss | 96 +++++ frontend/src/app/pages/home/home.ts | 221 +++++++++-- .../unlocated-events/unlocated-events.ts | 38 +- frontend/src/app/services/oedb-api.ts | 4 + frontend/src/index.html | 2 +- 12 files changed, 797 insertions(+), 165 deletions(-) diff --git a/frontend/src/app/maps/all-events/all-events.html b/frontend/src/app/maps/all-events/all-events.html index c0f8348..b0b34ab 100644 --- a/frontend/src/app/maps/all-events/all-events.html +++ b/frontend/src/app/maps/all-events/all-events.html @@ -1,6 +1,7 @@
diff --git a/frontend/src/app/pages/agenda/agenda.ts b/frontend/src/app/pages/agenda/agenda.ts index c05365c..67c17a4 100644 --- a/frontend/src/app/pages/agenda/agenda.ts +++ b/frontend/src/app/pages/agenda/agenda.ts @@ -6,6 +6,7 @@ import { EditForm } from '../../forms/edit-form/edit-form'; import { CalendarComponent, CalendarEvent } from './calendar/calendar'; import oedb from '../../../oedb-types'; import { WhatFilterComponent } from '../../shared/what-filter/what-filter'; +import { ActivatedRoute } from '@angular/router'; interface OedbEvent { id: string; @@ -34,6 +35,7 @@ interface OedbEvent { }) export class Agenda implements OnInit { private oedbApi = inject(OedbApi); + private route = inject(ActivatedRoute); events: OedbEvent[] = []; filteredEvents: OedbEvent[] = []; @@ -44,13 +46,26 @@ export class Agenda implements OnInit { groupedEvents: Array<{ dateKey: string; date: Date; items: OedbEvent[] }> = []; availableWhatTypes: string[] = []; - selectedWhatFilter = ''; + selectedWhatFilter = 'culture'; ngOnInit() { - this.loadEvents(); + this.route.queryParamMap.subscribe(map => { + const id = (map.get('id') || '').trim(); + const what = (map.get('what') || '').trim(); + const limitParam = map.get('limit'); + const limit = limitParam ? Number(limitParam) : null; + if (id) { + this.loadSingleEvent(id); + } else { + this.loadEvents({ what: what || undefined, limit: limit || undefined }); + } + if (what) { + this.selectedWhatFilter = what; + } + }); } - loadEvents() { + loadEvents(overrides: { what?: string; limit?: number } = {}) { this.isLoading = true; const today = new Date(); const startDate = new Date(today); @@ -58,11 +73,12 @@ export class Agenda implements OnInit { const endDate = new Date(today); endDate.setMonth(today.getMonth() + 3); // Charger 3 mois après - const params = { + const params: any = { start: startDate.toISOString().split('T')[0], end: endDate.toISOString().split('T')[0], - limit: 1000 + limit: overrides.limit ?? 1000 }; + if (overrides.what) params.what = overrides.what; this.oedbApi.getEvents(params).subscribe((response: any) => { this.events = Array.isArray(response?.features) ? response.features : []; @@ -72,6 +88,28 @@ export class Agenda implements OnInit { }); } + loadSingleEvent(id: string | number) { + this.isLoading = true; + this.oedbApi.getEventById(id).subscribe({ + next: (feature: any) => { + const f = (feature && (feature as any).type === 'Feature') ? feature : (feature?.feature || null); + this.events = f ? [f] as OedbEvent[] : []; + this.filteredEvents = this.events; + this.updateAvailableWhatTypes(); + this.applyWhatFilter(); + this.isLoading = false; + }, + error: () => { + this.events = []; + this.filteredEvents = []; + this.calendarEvents = []; + this.filteredCalendarEvents = []; + this.groupedEvents = []; + this.isLoading = false; + } + }); + } + convertToCalendarEvents() { const source = this.filteredEvents.length ? this.filteredEvents : this.events; this.calendarEvents = source.map(event => { @@ -150,7 +188,8 @@ export class Agenda implements OnInit { applyWhatFilter() { if (this.selectedWhatFilter) { - this.filteredEvents = this.events.filter(e => e?.properties?.what === this.selectedWhatFilter); + const prefix = this.selectedWhatFilter; + this.filteredEvents = this.events.filter(e => String(e?.properties?.what || '').startsWith(prefix)); } else { this.filteredEvents = [...this.events]; } diff --git a/frontend/src/app/pages/community-upcoming/community-upcoming.ts b/frontend/src/app/pages/community-upcoming/community-upcoming.ts index ff259ae..6ee8315 100644 --- a/frontend/src/app/pages/community-upcoming/community-upcoming.ts +++ b/frontend/src/app/pages/community-upcoming/community-upcoming.ts @@ -25,8 +25,10 @@ export class CommunityUpcoming { // when: NEXT7DAYS etc. Utilise le param 'when' déjà supporté par l'API const d = Math.max(1, Number(this.days()) || 7); const when = `NEXT${d}DAYS`; - this.api.getEvents({ when, what: 'commu', limit: 1000 }).subscribe((events: any) => { - this.features = Array.isArray(events?.features) ? events.features : []; + this.api.getEvents({ when, what: 'community', limit: 1000 }).subscribe((events: any) => { + const list = Array.isArray(events?.features) ? events.features : []; + // Filtrer côté client pour tout ce qui commence par "community" + this.features = list.filter((f: any) => String(f?.properties?.what || '').startsWith('community')); }); } } diff --git a/frontend/src/app/pages/events-docs/events-docs.html b/frontend/src/app/pages/events-docs/events-docs.html index 255ebb2..3bc0278 100644 --- a/frontend/src/app/pages/events-docs/events-docs.html +++ b/frontend/src/app/pages/events-docs/events-docs.html @@ -4,7 +4,7 @@

(1000 prochains pour les 30 prochains jours)

@@ -14,4 +14,62 @@ +@if (selectedWhatType && selectedTypeDetails) { +
+
+
+

+ @if (getEmojiForWhat(selectedWhatType)) { + {{ getEmojiForWhat(selectedWhatType) }} + } + @if (getImageForWhat(selectedWhatType)) { + + } + {{ selectedTypeDetails.label || selectedWhatType }} +

+ +
+ +
+

{{ selectedTypeDetails.description || 'Aucune description disponible' }}

+ + @if (selectedTypeDetails.category) { +
+ Catégorie: {{ selectedTypeDetails.category }} +
+ } + + @if (selectedTypeDetails.label && selectedTypeDetails.label !== selectedWhatType) { +
+ Nom court: {{ selectedTypeDetails.label }} +
+ } + + @if (selectedTypeDetails.durationHours) { +
+ Durée par défaut: {{ selectedTypeDetails.durationHours }} heures +
+ } + + @if (getPropertiesForWhat(selectedWhatType)) { +
+ Propriétés disponibles: +
    + @for (prop of getObjectKeys(getPropertiesForWhat(selectedWhatType)); track prop) { +
  • + {{ prop }}: + {{ getPropertiesForWhat(selectedWhatType)[prop].label || prop }} + @if (getPropertiesForWhat(selectedWhatType)[prop].description) { + ({{ getPropertiesForWhat(selectedWhatType)[prop].description }}) + } +
  • + } +
+
+ } +
+
+
+} + diff --git a/frontend/src/app/pages/events-docs/events-docs.scss b/frontend/src/app/pages/events-docs/events-docs.scss index 1c8d4bd..859d677 100644 --- a/frontend/src/app/pages/events-docs/events-docs.scss +++ b/frontend/src/app/pages/events-docs/events-docs.scss @@ -21,4 +21,103 @@ min-height: 60vh; } +.type-details-panel { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background: #fff; + border-top: 2px solid #1976d2; + box-shadow: 0 -4px 12px rgba(0,0,0,0.15); + z-index: 1000; + max-height: 50vh; + overflow: hidden; +} + +.panel-content { + padding: 16px; + max-height: 50vh; + overflow-y: auto; +} + +.panel-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + padding-bottom: 8px; + border-bottom: 1px solid #e0e0e0; +} + +.panel-header h3 { + margin: 0; + display: flex; + align-items: center; + gap: 8px; +} + +.emoji { + font-size: 1.2em; +} + +.type-image { + width: 24px; + height: 24px; + object-fit: contain; +} + +.close-btn { + background: #f5f5f5; + border: 1px solid #ddd; + border-radius: 4px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + font-size: 18px; + line-height: 1; +} + +.close-btn:hover { + background: #e0e0e0; +} + +.panel-body { + .description { + margin: 0 0 12px 0; + color: #555; + line-height: 1.4; + } +} + +.detail-item { + margin-bottom: 8px; + + strong { + color: #1976d2; + } +} + +.properties-list { + margin: 8px 0 0 16px; + padding: 0; + + li { + margin-bottom: 4px; + list-style: none; + + .prop-desc { + color: #666; + font-style: italic; + } + } +} + +button.selected { + background: #e3f2fd; + border-color: #1976d2; +} + diff --git a/frontend/src/app/pages/events-docs/events-docs.ts b/frontend/src/app/pages/events-docs/events-docs.ts index 4f91407..dc21319 100644 --- a/frontend/src/app/pages/events-docs/events-docs.ts +++ b/frontend/src/app/pages/events-docs/events-docs.ts @@ -2,6 +2,7 @@ import { Component, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { OedbApi } from '../../services/oedb-api'; import { AllEvents } from '../../maps/all-events/all-events'; +import oedb from '../../../oedb-types'; @Component({ selector: 'app-events-docs', @@ -16,6 +17,8 @@ export class EventsDocs { counts: Array<{ what: string, count: number }> = []; filtered: Array = []; selected: any | null = null; + selectedWhatType: string | null = null; + selectedTypeDetails: any = null; ngOnInit() { // Charger 1000 events récents @@ -38,6 +41,36 @@ export class EventsDocs { filterByWhat(what: string) { this.filtered = this.features.filter(f => String(f?.properties?.what || '').startsWith(what)); + this.selectedWhatType = what; + this.loadTypeDetails(what); + } + + loadTypeDetails(what: string) { + const presets = oedb.presets.what as any; + this.selectedTypeDetails = presets[what] || null; + } + + getEmojiForWhat(what: string): string | null { + const details = this.selectedTypeDetails; + return details?.emoji || null; + } + + getImageForWhat(what: string): string | null { + const details = this.selectedTypeDetails; + if (details?.image) { + const img: string = details.image; + return img.startsWith('/') ? img : `/${img}`; + } + return null; + } + + getPropertiesForWhat(what: string): any { + const details = this.selectedTypeDetails; + return details?.properties || null; + } + + getObjectKeys(obj: any): string[] { + return Object.keys(obj || {}); } } diff --git a/frontend/src/app/pages/home/home.html b/frontend/src/app/pages/home/home.html index 23ddfb0..c25a50a 100644 --- a/frontend/src/app/pages/home/home.html +++ b/frontend/src/app/pages/home/home.html @@ -1,42 +1,46 @@
+ @if(showOptions){
-
- - @if (isLoading) { - - } -
- - - -
+ -