import { Component, inject, signal , OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { FormsModule } from '@angular/forms'; import {Menu} from './menu/menu'; import { AllEvents } from '../../maps/all-events/all-events'; import { EditForm } from '../../forms/edit-form/edit-form'; import { OedbApi } from '../../services/oedb-api'; import { ActivatedRoute } from '@angular/router'; import oedb from '../../../oedb-types'; import { UnlocatedEvents } from '../../shared/unlocated-events/unlocated-events'; import { OsmAuth } from '../../services/osm-auth'; import { Osm } from '../../forms/osm/osm'; import { WhatFilterComponent } from '../../shared/what-filter/what-filter'; @Component({ selector: 'app-home', standalone: true, imports: [ Menu, AllEvents, UnlocatedEvents, EditForm, Osm, FormsModule, WhatFilterComponent ], templateUrl: './home.html', styleUrl: './home.scss' }) export class Home implements OnInit, OnDestroy { OedbApi = inject(OedbApi); route = inject(ActivatedRoute); private router = inject(Router); private osmAuth = inject(OsmAuth); features: Array = []; filteredFeatures: Array = []; selected: any | null = null; showTable = false; showFilters = false; showEditForm = true; selectionMode: 'none' | 'rectangle' | 'polygon' = 'none'; selectedIds: Array = []; batchAction: 'none' | 'changeWhat' | 'delete' = 'none'; batchWhat = ''; // Nouvelles propriétés pour le rechargement automatique et la sélection de jours autoReloadEnabled = true; autoReloadInterval: any = null; daysAhead = 7; // Nombre de jours dans le futur par défaut isLoading = false; // Propriétés pour les filtres searchText = ''; selectedWhatFilter = ''; availableWhatTypes: string[] = []; theme = signal(null); subthemes: Array<{ key: string, label: string, emoji: string }> = []; activeSubtheme = signal(null); ngOnInit() { this.loadEvents(); this.startAutoReload(); } ngOnDestroy() { this.stopAutoReload(); } createEvent() { this.selected = null; //this.showTable = false; //this.showFilters = true; this.showEditForm = true; } loadEvents() { this.isLoading = true; const today = new Date(); const endDate = new Date(today); endDate.setDate(today.getDate() + this.daysAhead); const params = { start: today.toISOString().split('T')[0], end: endDate.toISOString().split('T')[0], limit: 3000 }; this.OedbApi.getEvents(params).subscribe((events: any) => { this.features = Array.isArray(events?.features) ? events.features : []; this.updateAvailableWhatTypes(); this.applyFilters(); this.isLoading = false; }); } startAutoReload() { if (this.autoReloadEnabled && !this.autoReloadInterval) { this.autoReloadInterval = setInterval(() => { this.loadEvents(); }, 60000); // 1 minute } } stopAutoReload() { if (this.autoReloadInterval) { clearInterval(this.autoReloadInterval); this.autoReloadInterval = null; } } toggleAutoReload() { this.autoReloadEnabled = !this.autoReloadEnabled; if (this.autoReloadEnabled) { this.startAutoReload(); } else { this.stopAutoReload(); } } onDaysAheadChange() { this.loadEvents(); } updateAvailableWhatTypes() { const whatTypes = new Set(); this.features.forEach(feature => { if (feature?.properties?.what) { whatTypes.add(feature.properties.what); } }); this.route.queryParams.subscribe(p => { const t = (p?.['theme'] || '').trim(); this.theme.set(t || null); this.buildSubthemes(); }); this.availableWhatTypes = Array.from(whatTypes).sort(); } onSearchChange() { this.applyFilters(); } onWhatFilterChange() { this.applyFilters(); } applyFilters() { let filtered = [...this.features]; // Filtre par texte de recherche if (this.searchText.trim()) { const searchLower = this.searchText.toLowerCase(); filtered = filtered.filter(feature => { const label = feature?.properties?.label || feature?.properties?.name || ''; const description = feature?.properties?.description || ''; const what = feature?.properties?.what || ''; return label.toLowerCase().includes(searchLower) || description.toLowerCase().includes(searchLower) || what.toLowerCase().includes(searchLower); }); } // Filtre par type d'événement if (this.selectedWhatFilter) { filtered = filtered.filter(feature => feature?.properties?.what === this.selectedWhatFilter ); } this.filteredFeatures = filtered; } goToNewCategories() { this.router.navigate(['/nouvelles-categories']); } onSelect(feature: any) { this.selected = feature; } onPickCoords(coords: [number, number]) { const [lon, lat] = coords; if (this.selected && this.selected.properties) { this.selected = { ...this.selected, geometry: { type: 'Point', coordinates: [lon, lat] } }; } else { const osmUsername = this.osmAuth.getUsername(); const whatKey = this.activeSubtheme(); let label = ''; let description = ''; if (whatKey) { const preset = (oedb.presets.what as any)[whatKey]; if (preset) { label = preset.label || ''; description = preset.description || ''; } } this.selected = { id: null, properties: { label: '', description: '', what: whatKey || '', where: '', ...(osmUsername && { last_modified_by: osmUsername }) }, geometry: { type: 'Point', coordinates: [lon, lat] } }; } } onSaved(_res: any) { // refresh list after update this.loadEvents(); } onCreated(_res: any) { this.selected = null; this.loadEvents(); } onDeleted(_res: any) { this.selected = null; this.loadEvents(); } // Selection from map onSelection(ids: Array) { this.selectedIds = ids; } startRectSelection() { this.selectionMode = this.selectionMode === 'rectangle' ? 'none' : 'rectangle'; } startPolySelection() { this.selectionMode = this.selectionMode === 'polygon' ? 'none' : 'polygon'; } clearSelection() { this.selectionMode = 'none'; this.selectedIds = []; this.batchAction = 'none'; this.batchWhat = ''; } async applyBatch() { if (!this.selectedIds.length || this.batchAction === 'none') return; if (this.batchAction === 'delete') { for (const id of this.selectedIds) { await new Promise((resolve) => { this.OedbApi.deleteEvent(id).subscribe({ next: () => resolve(), error: () => resolve() }); }); } this.loadEvents(); this.clearSelection(); return; } if (this.batchAction === 'changeWhat') { const what = this.batchWhat.trim(); if (!what) return; for (const id of this.selectedIds) { const feature = this.features.find(f => (f?.properties?.id ?? f?.id) === id); if (!feature) continue; const updated = { ...feature, properties: { ...feature.properties, what } }; await new Promise((resolve) => { this.OedbApi.updateEvent(id, updated).subscribe({ next: () => resolve(), error: () => resolve() }); }); } this.loadEvents(); this.clearSelection(); } } onCanceled() { this.showEditForm = false; } ngAfterViewInit() { // reserved } toggleView() { this.showTable = !this.showTable; } private buildSubthemes() { const t = this.theme(); if (!t) { this.subthemes = []; this.activeSubtheme.set(null); return; } const what = oedb.presets.what as Record; const list: Array<{ key: string, label: string, emoji: string }> = []; Object.keys(what).forEach(k => { if (k === t || k.startsWith(`${t}.`)) { list.push({ key: k, label: what[k].label || k, emoji: what[k].emoji || '' }); } }); this.subthemes = list.sort((a, b) => a.key.localeCompare(b.key)); const exact = this.subthemes.find(s => s.key === t); this.activeSubtheme.set(exact ? exact.key : (this.subthemes[0]?.key || null)); } downloadGeoJSON() { const blob = new Blob([JSON.stringify({ type: 'FeatureCollection', features: this.filteredFeatures }, null, 2)], { type: 'application/geo+json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'events.geojson'; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); a.remove(); } downloadCSV() { const header = ['id', 'what', 'label', 'start', 'stop', 'lon', 'lat']; const rows = this.filteredFeatures.map((f: any) => [ JSON.stringify(f?.properties?.id ?? f?.id ?? ''), JSON.stringify(f?.properties?.what ?? ''), JSON.stringify(f?.properties?.label ?? f?.properties?.name ?? ''), JSON.stringify(f?.properties?.start ?? f?.properties?.when ?? ''), JSON.stringify(f?.properties?.stop ?? ''), JSON.stringify(f?.geometry?.coordinates?.[0] ?? ''), JSON.stringify(f?.geometry?.coordinates?.[1] ?? '') ].join(',')); const csv = [header.join(','), ...rows].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'events.csv'; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); a.remove(); } }