292 lines
No EOL
8.1 KiB
TypeScript
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();
|
|
}
|
|
} |