import { Component, OnInit, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MeteocatService } from '../../services/meteocat.service'; import { Municipi } from '../../models/municipi.model'; import { PrediccioDiaria } from '../../models/prediccio-diaria.model'; import { PrediccioHoraria } from '../../models/prediccio-horaria.model'; import { EstacioMesCercanaResponse } from '../../models/estacio-mes-cercana.model'; import { PrediccioDiariaComponent } from '../prediccio-diaria/prediccio-diaria'; import { PrediccioHorariaComponent } from '../prediccio-horaria/prediccio-horaria'; @Component({ selector: 'app-home', imports: [CommonModule, PrediccioDiariaComponent, PrediccioHorariaComponent], templateUrl: './home.html', styleUrl: './home.scss', }) export class Home implements OnInit { // Municipio dinámico según GPS municipiCodi = signal('081075'); // Lliçà d'Amunt por defecto municipi = signal(null); prediccioDiaria = signal([]); prediccioHoraria = signal([]); estacioInfo = signal(null); loading = signal(true); error = signal(null); gettingLocation = signal(false); locationDenied = signal(false); // Menú hamburguesa menuOpen = signal(false); searchQuery = signal(''); searchResults = signal([]); searching = signal(false); // Modal GPS showGpsModal = signal(false); gpsPermissionAsked = signal(false); constructor(private meteocatService: MeteocatService) {} ngOnInit(): void { // Verificar si ya se pidió permiso GPS antes const gpsRejected = localStorage.getItem('gpsRejected'); const gpsAsked = localStorage.getItem('gpsAsked'); if (gpsRejected === 'true') { // Usuario rechazó GPS previamente, cargar datos por defecto this.gpsPermissionAsked.set(true); this.loadWeatherData(this.municipiCodi()); } else if (gpsAsked === 'true') { // Ya se pidió permiso antes, intentar obtener ubicación automáticamente this.gpsPermissionAsked.set(true); this.getCurrentLocation(); } else { // Primera vez, mostrar modal this.showGpsModal.set(true); this.loadWeatherData(this.municipiCodi()); // Cargar datos por defecto mientras } } getCurrentLocation(): void { if (!navigator.geolocation) { console.warn('Geolocalización no disponible, usando municipio por defecto'); this.loadWeatherData(this.municipiCodi()); return; } this.gettingLocation.set(true); this.loading.set(true); navigator.geolocation.getCurrentPosition( (position) => { const lat = position.coords.latitude; const lon = position.coords.longitude; console.log(`Ubicación GPS obtenida: ${lat}, ${lon}`); // Marcar que el usuario aceptó GPS localStorage.setItem('gpsAsked', 'true'); localStorage.removeItem('gpsRejected'); this.locationDenied.set(false); // Buscar municipio más cercano this.meteocatService.getMunicipiCercano(lat, lon).subscribe({ next: (municipi) => { console.log(`Municipio más cercano: ${municipi.nom} (${municipi.codi})`); this.municipiCodi.set(municipi.codi); this.gettingLocation.set(false); this.loadWeatherData(municipi.codi); }, error: (err) => { console.error('Error al buscar municipio cercano:', err); this.gettingLocation.set(false); // Usar municipio por defecto si falla this.loadWeatherData(this.municipiCodi()); } }); }, (error) => { console.warn('Error obteniendo ubicación:', error.message); this.gettingLocation.set(false); // Solo mostrar banner si el usuario lo solicitó manualmente if (!this.gpsPermissionAsked()) { this.locationDenied.set(true); } // Usar municipio por defecto si se deniega el permiso this.loadWeatherData(this.municipiCodi()); }, { enableHighAccuracy: true, timeout: 10000, maximumAge: 300000 // Cache de 5 minutos } ); } loadWeatherData(codiMunicipi: string): void { this.loading.set(true); this.error.set(null); // Cargar municipio this.meteocatService.getMunicipiByCode(codiMunicipi).subscribe({ next: (municipi) => { this.municipi.set(municipi); }, error: (err) => { console.error('Error al cargar municipio:', err); this.error.set('Error al cargar información del municipio'); } }); // Cargar predicción diaria this.meteocatService.getPrediccioDiaria(codiMunicipi).subscribe({ next: (prediccions) => { this.prediccioDiaria.set(prediccions); }, error: (err) => { console.error('Error al cargar predicción diaria:', err); this.error.set('Error al cargar predicción diaria'); } }); // Cargar predicción horaria this.meteocatService.getPrediccioHoraria(codiMunicipi).subscribe({ next: (prediccions) => { // Filtrar solo predicciones desde la hora actual y limitamos a 48 horas const now = new Date(); const filtered = prediccions .filter(p => { const predDate = new Date(p.dataHora); return predDate >= now; }) .slice(0, 48); // Limitar a 48 horas this.prediccioHoraria.set(filtered); this.loading.set(false); }, error: (err) => { console.error('Error al cargar predicción horaria:', err); this.error.set('Error al cargar predicción horaria'); this.loading.set(false); } }); // Cargar estación XEMA más cercana this.meteocatService.getEstacioCercana(codiMunicipi).subscribe({ next: (response) => { this.estacioInfo.set(response); }, error: (err) => { console.error('Error al cargar estación XEMA:', err); } }); } getCurrentTemperature(): number | null { const horariaData = this.prediccioHoraria(); if (horariaData && horariaData.length > 0) { return horariaData[0].temperatura; } return null; } getTodayMinMax(): { min: number; max: number } | null { const diariaData = this.prediccioDiaria(); if (diariaData && diariaData.length > 0) { return { min: diariaData[0].temperaturaMinima, max: diariaData[0].temperaturaMaxima }; } return null; } refresh(): void { // Recargar datos con el municipio actual this.loadWeatherData(this.municipiCodi()); } requestLocation(): void { // Solicitar ubicación nuevamente this.locationDenied.set(false); this.getCurrentLocation(); } acceptGpsModal(): void { this.showGpsModal.set(false); this.gpsPermissionAsked.set(true); localStorage.setItem('gpsAsked', 'true'); this.getCurrentLocation(); } rejectGpsModal(): void { this.showGpsModal.set(false); this.gpsPermissionAsked.set(true); localStorage.setItem('gpsRejected', 'true'); localStorage.setItem('gpsAsked', 'true'); // Ya tenemos los datos cargados por defecto } toggleMenu(): void { this.menuOpen.set(!this.menuOpen()); } closeMenu(): void { this.menuOpen.set(false); this.searchQuery.set(''); this.searchResults.set([]); } onSearchInput(event: Event): void { const input = event.target as HTMLInputElement; const query = input.value.trim(); this.searchQuery.set(query); if (query.length < 2) { this.searchResults.set([]); return; } this.searching.set(true); this.meteocatService.searchMunicipis(query).subscribe({ next: (results) => { this.searchResults.set(results); this.searching.set(false); }, error: (err) => { console.error('Error searching municipis:', err); this.searching.set(false); } }); } selectMunicipi(municipi: Municipi): void { console.log(`Seleccionado municipio: ${municipi.nom} (${municipi.codi})`); this.municipiCodi.set(municipi.codi); this.closeMenu(); this.loadWeatherData(municipi.codi); } getLastUpdateDate(): string | null { const horaria = this.prediccioHoraria(); if (!horaria || horaria.length === 0) { return null; } try { const lastDate = new Date(horaria[0].dataHora); const now = new Date(); const diffMinutes = Math.floor((now.getTime() - lastDate.getTime()) / 60000); if (diffMinutes < 60) { return `fa ${diffMinutes} minuts`; } else if (diffMinutes < 1440) { const hours = Math.floor(diffMinutes / 60); return `fa ${hours} ${hours === 1 ? 'hora' : 'hores'}`; } else { const options: Intl.DateTimeFormatOptions = { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }; return lastDate.toLocaleDateString('ca-ES', options); } } catch (error) { console.error('Error calculating last update date:', error); return null; } } }