You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
front/src/app/components/edit-pin-popup/edit-pin-popup.component.ts

273 lines
8.0 KiB

import { CommonModule } from '@angular/common';
import {
AfterViewInit,
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import {
FormBuilder,
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { NavigationEnd, Router } from '@angular/router';
import { of, Subscription } from 'rxjs';
import {
catchError,
debounceTime,
distinctUntilChanged,
filter,
switchMap,
take,
} from 'rxjs/operators';
import { Pin } from '../../model/Pin';
import { AutocompleteService } from '../../services/auto-complete/auto-complete.service';
import { ExifService } from '../../services/exif/exif.service';
import { MapReloadService } from '../../services/map-reload/map-reload.service';
import { ModalService } from '../../services/modal/modal.service';
import { PinService } from '../../services/pin/pin.service';
import { DragDropComponent } from '../drag-drop/drag-drop.component';
@Component({
selector: 'app-edit-pin-popup',
standalone: true,
imports: [ReactiveFormsModule, CommonModule, DragDropComponent],
templateUrl: './edit-pin-popup.component.html',
})
export class EditPinPopupComponent implements OnInit, AfterViewInit, OnDestroy {
@Input() isHomePage: boolean = false;
@Input() pin!: Pin;
form!: FormGroup;
suggestions: any[] = [];
inputFocused: boolean = false;
files: any[] = [];
isPinModalOpen: boolean = false;
@Input() modalId!: string;
private modalOpenSubscription!: Subscription;
private routerSubscription!: Subscription;
private locationSubscription!: Subscription;
constructor(
private fb: FormBuilder,
private autocompleteService: AutocompleteService,
private pinService: PinService,
private exifService: ExifService,
private modalService: ModalService,
private router: Router,
private mapReloadService: MapReloadService
) {
// Initialiser le formulaire avec des valeurs par défaut
this.form = this.fb.group({
title: new FormControl(''),
description: new FormControl(''),
location: new FormControl(''),
files: new FormControl(null),
});
}
onFocus(): void {
this.inputFocused = true;
}
onBlur(): void {
setTimeout(() => {
this.inputFocused = false; // Désactiver le focus après un petit délai pour permettre un clic sur la liste
}, 200);
}
ngOnInit(): void {
// Initialiser le formulaire avec les valeurs de base
this.form.patchValue({
title: this.pin?.title || '',
description: this.pin?.description || '',
location: "Chargement de l'adresse...",
});
// Vérifier si nous avons des coordonnées valides dans pin.location
if (
this.pin?.location &&
Array.isArray(this.pin.location) &&
this.pin.location.length >= 2
) {
const lat = this.pin.location[0];
const lon = this.pin.location[1];
if (lat !== undefined && lon !== undefined) {
// Récupérer l'adresse à partir des coordonnées
this.locationSubscription = this.autocompleteService
.getAddressFromCoordinates(lat, lon)
.pipe(take(1))
.subscribe(
(address) => {
if (address && address.display_name) {
this.form.patchValue({ location: address.display_name });
} else {
this.form.patchValue({ location: `${lat}, ${lon}` });
}
},
(error) => {
console.error(
"Erreur lors de la récupération de l'adresse:",
error
);
this.form.patchValue({ location: `${lat}, ${lon}` });
}
);
}
}
// S'abonner aux changements d'état du modal
this.modalOpenSubscription = this.modalService
.getModalState(this.modalId)
.subscribe((state) => {
this.isPinModalOpen = state;
if (state) {
setTimeout(() => this.moveModalToBody(), 0);
}
});
// S'abonner aux événements de navigation du router
this.routerSubscription = this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe(() => {
// Attendre que le DOM soit mis à jour après la navigation
setTimeout(() => this.moveModalToBody(), 0);
});
// Configuration de l'autocomplétion pour le champ d'adresse
this.form
.get('location')
?.valueChanges.pipe(
debounceTime(300), // Attendre 300ms après la dernière frappe
distinctUntilChanged(), // Ignorer si la nouvelle valeur est la même que la précédente
switchMap((query) => {
// Vérifier que query est une chaîne de caractères
if (typeof query !== 'string') {
return of([]);
}
const trimmedQuery = query.trim();
if (trimmedQuery.length > 2) {
return this.autocompleteService.getAddressSuggestions(trimmedQuery);
}
return of([]);
}),
catchError((error) => {
console.error('Error fetching suggestions:', error);
return of([]);
})
)
.subscribe((data) => {
this.suggestions = data;
});
}
ngAfterViewInit() {
// Appel initial pour déplacer le modal
this.moveModalToBody();
}
ngOnDestroy() {
// Nettoyage des abonnements pour éviter les fuites de mémoire
if (this.modalOpenSubscription) {
this.modalOpenSubscription.unsubscribe();
}
if (this.routerSubscription) {
this.routerSubscription.unsubscribe();
}
if (this.locationSubscription) {
this.locationSubscription.unsubscribe();
}
}
// Méthode dédiée pour déplacer le modal vers le body
private moveModalToBody(): void {
const modal = document.getElementById('pin-modal');
if (modal && modal.parentElement !== document.body) {
document.body.appendChild(modal);
}
const bg = document.getElementById('pin-modal-background');
if (bg && bg.parentElement !== document.body) {
document.body.appendChild(bg);
}
}
selectSuggestion(suggestion: any): void {
const locationControl = this.form.get('location');
if (locationControl instanceof FormControl) {
locationControl.setValue(suggestion.display_name);
}
this.suggestions = [];
}
async onFilesReceived(files: FileList): Promise<void> {
this.files = Array.from(files);
for (let i = 0; i < this.files.length; i++) {
try {
const data = await this.exifService.getLocation(this.files[i]);
if (data.latitude !== undefined && data.longitude !== undefined) {
try {
// Utiliser pipe(take(1)) pour s'assurer que l'observable se termine
const address = await this.autocompleteService
.getAddressFromCoordinates(data.latitude, data.longitude)
.pipe(take(1))
.toPromise();
if (address) {
this.form.get('location')?.setValue(address.display_name);
break;
}
} catch (addressError) {
console.error(
"Erreur lors de la récupération de l'adresse:",
addressError
);
// Utiliser les coordonnées brutes en cas d'échec
this.form
.get('location')
?.setValue(`${data.latitude}, ${data.longitude}`);
}
}
} catch (error) {
console.error('Erreur :', error);
}
}
}
submitForm(): void {
if (this.form.valid) {
this.files = this.files.map((file) => {
return file.name; //TODO: Mettre le hash du fichier
});
const pinData = {
...this.form.value,
files: this.files,
user_id: this.pin.user_id,
};
this.pinService.updatePin(this.pin.id, pinData).subscribe(() => {
this.mapReloadService.requestReload(); // Demander le rechargement de la carte
this.closePinModal();
});
} else {
console.error('Le formulaire est invalide');
}
}
openPinModal() {
this.modalService.openModal(this.modalId);
}
closePinModal() {
this.modalService.closeModal(this.modalId);
}
}