oedb-backend/frontend/src/app/pages/agenda/agenda.ts

292 lines
No EOL
8.1 KiB
TypeScript

import { Component, inject, OnInit, ViewChild, TemplateRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { OedbApi } from '../../services/oedb-api';
import { EditForm } from '../../forms/edit-form/edit-form';
import { CalendarModule, CalendarView, CalendarEvent } from 'angular-calendar';
import { CalendarEventAction, CalendarEventTimesChangedEvent } from 'angular-calendar';
import oedb from '../../../oedb-types';
interface OedbEvent {
id: string;
properties: {
label?: string;
name?: string;
what?: string;
start?: string;
when?: string;
stop?: string;
description?: string;
where?: string;
};
geometry?: {
type: string;
coordinates: [number, number];
};
}
interface DayEvents {
date: Date;
events: OedbEvent[];
}
@Component({
selector: 'app-agenda',
standalone: true,
imports: [CommonModule, FormsModule, EditForm, CalendarModule],
templateUrl: './agenda.html',
styleUrl: './agenda.scss'
})
export class Agenda implements OnInit {
private oedbApi = inject(OedbApi);
@ViewChild('eventTitleTemplate', { static: true }) eventTitleTemplate!: TemplateRef<any>;
events: OedbEvent[] = [];
filteredEvents: OedbEvent[] = [];
calendarEvents: CalendarEvent[] = [];
selectedEvent: OedbEvent | null = null;
showSidePanel = false;
showFiltersPanel = false;
view: CalendarView = CalendarView.Month;
viewDate: Date = new Date();
oedbPresets = oedb.presets.what;
// Propriétés pour les filtres
hideTrafficEvents = true; // Par défaut, masquer les événements de type traffic
selectedEventTypes: string[] = [];
availableEventTypes: string[] = [];
// Exposer CalendarView pour l'utiliser dans le template
CalendarView = CalendarView;
ngOnInit() {
this.loadEvents();
}
loadEvents() {
const today = new Date();
const startDate = new Date(today);
startDate.setDate(today.getDate() - 10);
const endDate = new Date(today);
endDate.setDate(today.getDate() + 10);
const params = {
start: `${startDate.toISOString().split('T')[0]}`,
end: `${endDate.toISOString().split('T')[0]}`,
limit: 1000
};
this.oedbApi.getEvents(params).subscribe((response: any) => {
this.events = Array.isArray(response?.features) ? response.features : [];
this.updateAvailableEventTypes();
this.applyFilters();
});
}
updateAvailableEventTypes() {
const eventTypes = new Set<string>();
this.events.forEach(event => {
if (event?.properties?.what) {
eventTypes.add(event.properties.what);
}
});
this.availableEventTypes = Array.from(eventTypes).sort();
}
applyFilters() {
let filtered = [...this.events];
// Filtre par défaut : masquer les événements de type traffic
if (this.hideTrafficEvents) {
filtered = filtered.filter(event =>
!event?.properties?.what?.startsWith('traffic.')
);
}
// Filtre par types d'événements sélectionnés
if (this.selectedEventTypes.length > 0) {
filtered = filtered.filter(event =>
this.selectedEventTypes.includes(event?.properties?.what || '')
);
}
this.filteredEvents = filtered;
this.organizeEventsByDay();
}
organizeEventsByDay() {
this.calendarEvents = this.filteredEvents.map(event => {
const eventDate = this.getEventDate(event);
const preset = this.getEventPreset(event);
return {
id: event.id,
title: this.getEventTitle(event),
start: eventDate || new Date(),
color: this.getEventColor(preset),
meta: {
event: event,
preset: preset
}
};
});
}
getEventDate(event: OedbEvent): Date | null {
const startDate = event.properties.start || event.properties.when;
if (startDate) {
return new Date(startDate);
}
return null;
}
getEventTitle(event: OedbEvent): string {
return event.properties.label || event.properties.name || 'Événement sans titre';
}
getEventTime(event: OedbEvent): string {
const startDate = event.properties.start || event.properties.when;
if (startDate) {
const date = new Date(startDate);
return date.toLocaleTimeString('fr-FR', {
hour: '2-digit',
minute: '2-digit'
});
}
return '';
}
selectEvent(event: OedbEvent) {
this.selectedEvent = event;
this.showSidePanel = true;
}
onEventClicked({ event }: { event: CalendarEvent; sourceEvent: MouseEvent | KeyboardEvent }) {
if (event.meta && event.meta.event) {
this.selectEvent(event.meta.event);
}
}
getEventPreset(event: OedbEvent): any {
const what = event.properties.what;
if (what && (this.oedbPresets as any)[what]) {
return (this.oedbPresets as any)[what];
}
return null;
}
getEventIcon(preset: any): string {
if (preset) {
return preset.emoji || '📅';
}
return '📅';
}
getEventColor(preset: any): any {
if (preset) {
// Couleurs basées sur la catégorie
const categoryColors: { [key: string]: any } = {
'Communauté': { primary: '#007bff', secondary: '#cce7ff' },
'Culture': { primary: '#28a745', secondary: '#d4edda' },
'Musique': { primary: '#ffc107', secondary: '#fff3cd' },
'Énergie': { primary: '#dc3545', secondary: '#f8d7da' },
'Commerce': { primary: '#6f42c1', secondary: '#e2d9f3' },
'Temps': { primary: '#17a2b8', secondary: '#d1ecf1' },
'Tourisme': { primary: '#fd7e14', secondary: '#ffeaa7' },
'Circulation': { primary: '#6c757d', secondary: '#e9ecef' },
'Randonnée': { primary: '#20c997', secondary: '#d1f2eb' },
'Vie sauvage': { primary: '#795548', secondary: '#efebe9' },
'Météo': { primary: '#2196f3', secondary: '#e3f2fd' }
};
const category = preset.category || 'Communauté';
return categoryColors[category] || { primary: '#6c757d', secondary: '#e9ecef' };
}
return { primary: '#6c757d', secondary: '#e9ecef' };
}
closeSidePanel() {
this.showSidePanel = false;
this.selectedEvent = null;
}
onEventSaved(event: any) {
this.loadEvents(); // Recharger les événements après modification
this.closeSidePanel();
}
onEventCreated(event: any) {
this.loadEvents(); // Recharger les événements après création
this.closeSidePanel();
}
onEventDeleted(event: any) {
this.loadEvents(); // Recharger les événements après suppression
this.closeSidePanel();
}
setView(view: CalendarView) {
this.view = view;
}
dayClicked(event: any): void {
// Gérer les différents types d'événements selon la vue
let date: Date;
let events: CalendarEvent[] = [];
if (event.day) {
// Vue mois : { day: MonthViewDay, sourceEvent: MouseEvent | KeyboardEvent }
date = event.day.date;
events = event.day.events || [];
} else if (event.date) {
// Vue semaine/jour : { date: Date, events: CalendarEvent[], sourceEvent: MouseEvent | KeyboardEvent }
date = event.date;
events = event.events || [];
} else {
// Fallback pour les autres cas
console.warn('Type d\'événement dayClicked non reconnu:', event);
return;
}
console.log('Day clicked:', date, events);
}
eventTimesChanged({
event,
newStart,
newEnd,
}: CalendarEventTimesChangedEvent): void {
console.log('Event times changed:', event, newStart, newEnd);
}
toggleFiltersPanel() {
this.showFiltersPanel = !this.showFiltersPanel;
}
onHideTrafficChange() {
this.applyFilters();
}
onEventTypeChange(eventType: string, checked: boolean) {
if (checked) {
if (!this.selectedEventTypes.includes(eventType)) {
this.selectedEventTypes.push(eventType);
}
} else {
this.selectedEventTypes = this.selectedEventTypes.filter(type => type !== eventType);
}
this.applyFilters();
}
isEventTypeSelected(eventType: string): boolean {
return this.selectedEventTypes.includes(eventType);
}
clearAllFilters() {
this.selectedEventTypes = [];
this.hideTrafficEvents = true;
this.applyFilters();
}
}