diff --git a/src/app/components/add-pin-popup/add-pin-popup.component.ts b/src/app/components/add-pin-popup/add-pin-popup.component.ts index a96a4ee..4201de9 100644 --- a/src/app/components/add-pin-popup/add-pin-popup.component.ts +++ b/src/app/components/add-pin-popup/add-pin-popup.component.ts @@ -15,9 +15,9 @@ import { } from 'rxjs/operators'; 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 { PinService } from '../../services/pin/pin.service'; import { DragDropComponent } from '../drag-drop/drag-drop.component'; - @Component({ selector: 'app-add-pin-popup', standalone: true, @@ -36,7 +36,8 @@ export class AddPinPopupComponent implements OnInit { private fb: FormBuilder, private autocompleteService: AutocompleteService, private pinService: PinService, - private exifService: ExifService + private exifService: ExifService, + private mapReloadService: MapReloadService ) { this.form = this.fb.group({ title: new FormControl(''), @@ -121,7 +122,9 @@ export class AddPinPopupComponent implements OnInit { }; this.pinService.addPin(pinData).subscribe(() => { + this.mapReloadService.requestReload(); // Demander le rechargement de la carte this.closePinModal(); + this.form.reset(); // Réinitialiser le formulaire après soumission }); } else { console.error('Le formulaire est invalide'); diff --git a/src/app/components/confirm-modal/confirm-modal.component.html b/src/app/components/confirm-modal/confirm-modal.component.html new file mode 100644 index 0000000..bf51305 --- /dev/null +++ b/src/app/components/confirm-modal/confirm-modal.component.html @@ -0,0 +1,71 @@ + +
+ + +
+
+ +
+

+ Confirmation +

+ +
+

{{ message }}

+ +
+ + +
+
+
diff --git a/src/app/components/confirm-modal/confirm-modal.component.spec.ts b/src/app/components/confirm-modal/confirm-modal.component.spec.ts new file mode 100644 index 0000000..336c2b4 --- /dev/null +++ b/src/app/components/confirm-modal/confirm-modal.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfirmModalComponent } from './confirm-modal.component'; + +describe('ConfirmModalComponent', () => { + let component: ConfirmModalComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ConfirmModalComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ConfirmModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/confirm-modal/confirm-modal.component.ts b/src/app/components/confirm-modal/confirm-modal.component.ts new file mode 100644 index 0000000..ae7bfee --- /dev/null +++ b/src/app/components/confirm-modal/confirm-modal.component.ts @@ -0,0 +1,75 @@ +import { CommonModule } from '@angular/common'; +import { + Component, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, +} from '@angular/core'; +import { Subscription } from 'rxjs'; +import { ModalService } from '../../services/modal/modal.service'; + +@Component({ + selector: 'app-confirm-modal', + standalone: true, + imports: [CommonModule], + templateUrl: './confirm-modal.component.html', +}) +export class ConfirmModalComponent implements OnInit, OnDestroy { + @Input() modalId: string = 'confirm-modal'; + @Input() message: string = 'Es-tu sûr de vouloir supprimer ?'; + @Output() confirmed = new EventEmitter(); + @Output() cancelled = new EventEmitter(); + + isOpen = false; + private subscription!: Subscription; + + constructor(private modalService: ModalService) {} + + ngOnInit() { + this.subscription = this.modalService + .getModalState(this.modalId) + .subscribe((state) => { + this.isOpen = state; + if (state) { + setTimeout(() => this.moveModalToBody(), 0); + } + }); + } + + ngAfterViewInit() { + // Appel initial pour déplacer le modal + this.moveModalToBody(); + } + + ngOnDestroy() { + this.subscription?.unsubscribe(); + } + + confirm() { + this.confirmed.emit(); + this.modalService.closeModal(this.modalId); + } + + cancel() { + this.cancelled.emit(); + this.modalService.closeModal(this.modalId); + } + + closeModal() { + this.isOpen = false; + this.modalService.closeModal(this.modalId); + } + + private moveModalToBody(): void { + const modal = document.getElementById('confirm-modal'); + if (modal && modal.parentElement !== document.body) { + document.body.appendChild(modal); + } + const bg = document.getElementById('confirm-modal-background'); + if (bg && bg.parentElement !== document.body) { + document.body.appendChild(bg); + } + } +} diff --git a/src/app/components/edit-pin-popup/edit-pin-popup.component.html b/src/app/components/edit-pin-popup/edit-pin-popup.component.html index 9d50c32..c21d4b5 100644 --- a/src/app/components/edit-pin-popup/edit-pin-popup.component.html +++ b/src/app/components/edit-pin-popup/edit-pin-popup.component.html @@ -31,6 +31,7 @@ 'opacity-100': isPinModalOpen }" (click)="closePinModal()" + id="pin-modal-background" > diff --git a/src/app/components/edit-pin-popup/edit-pin-popup.component.ts b/src/app/components/edit-pin-popup/edit-pin-popup.component.ts index 8c978d0..b70a1c4 100644 --- a/src/app/components/edit-pin-popup/edit-pin-popup.component.ts +++ b/src/app/components/edit-pin-popup/edit-pin-popup.component.ts @@ -25,6 +25,7 @@ import { 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'; @@ -56,7 +57,8 @@ export class EditPinPopupComponent implements OnInit, AfterViewInit, OnDestroy { private pinService: PinService, private exifService: ExifService, private modalService: ModalService, - private router: Router + private router: Router, + private mapReloadService: MapReloadService ) { // Initialiser le formulaire avec des valeurs par défaut this.form = this.fb.group({ @@ -190,6 +192,10 @@ export class EditPinPopupComponent implements OnInit, AfterViewInit, OnDestroy { 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 { @@ -248,6 +254,7 @@ export class EditPinPopupComponent implements OnInit, AfterViewInit, OnDestroy { }; this.pinService.updatePin(this.pin.id, pinData).subscribe(() => { + this.mapReloadService.requestReload(); // Demander le rechargement de la carte this.closePinModal(); }); } else { diff --git a/src/app/components/leaflet-map/leaflet-map.component.ts b/src/app/components/leaflet-map/leaflet-map.component.ts index 110c9a7..1b4e4c3 100644 --- a/src/app/components/leaflet-map/leaflet-map.component.ts +++ b/src/app/components/leaflet-map/leaflet-map.component.ts @@ -6,6 +6,7 @@ import * as L from 'leaflet'; import 'leaflet/dist/leaflet.css'; import { Pin } from '../../model/Pin'; import { AutocompleteService } from '../../services/auto-complete/auto-complete.service'; +import { MapReloadService } from '../../services/map-reload/map-reload.service'; import { PinService } from '../../services/pin/pin.service'; import { PinMarkerComponent } from '../pin-marker/pin-marker.component'; @@ -31,12 +32,17 @@ export class LeafletMapComponent implements OnInit { private pinsService: PinService, private autocompleteService: AutocompleteService, private route: ActivatedRoute, - private router: Router + private router: Router, + private mapReloadService: MapReloadService ) {} ngOnInit(): void { this.initializeMap(); + this.mapReloadService.reload$.subscribe(() => { + this.loadPins(); // recharge les pins quand demandé + }); + this.route.queryParams.subscribe((params) => { const pinId = params['pin']; if (pinId) { @@ -68,34 +74,38 @@ export class LeafletMapComponent implements OnInit { this.allPins = pins; this.extractPersons(pins); - const countrySet = new Set(); - const requests = pins.map((pin) => - this.autocompleteService - .getAddressFromCoordinates(pin.location[0], pin.location[1]) - .toPromise() - .then((res: any) => { - const address = res?.address; - const country = - address?.country || - this.extractLastFromDisplayName(res?.display_name); - if (country) { - this.pinCountries[pin.id] = country; - countrySet.add(country); - } - }) - .catch((err: any) => { - console.error( - 'Erreur lors de la récupération du pays pour le pin', - pin.id, - err - ); - }) - ); - - Promise.all(requests).then(() => { - this.availableCountries = Array.from(countrySet).sort(); - this.renderPins(); - }); + this.renderPins(); // Afficher d'abord les pins sans les filtres + this.loadCountriesForFiltrers(pins); // Ensuite, charger les pays en arrière-plan + }); + } + + private loadCountriesForFiltrers(pins: Pin[]): void { + const countrySet = new Set(); + const requests = pins.map((pin) => + this.autocompleteService + .getAddressFromCoordinates(pin.location[0], pin.location[1]) + .toPromise() + .then((res: any) => { + const address = res?.address; + const country = + address?.country || + this.extractLastFromDisplayName(res?.display_name); + if (country) { + this.pinCountries[pin.id] = country; + countrySet.add(country); + } + }) + .catch((err: any) => { + console.error( + 'Erreur lors de la récupération du pays pour le pin', + pin.id, + err + ); + }) + ); + + Promise.all(requests).then(() => { + this.availableCountries = Array.from(countrySet).sort(); }); } @@ -210,4 +220,14 @@ export class LeafletMapComponent implements OnInit { popupAnchor: [0, -24], }); } + + public loadPins(): void { + this.pinsService.getPins().subscribe((pins: Pin[]) => { + this.allPins = pins; + this.extractPersons(pins); + this.renderPins(); // Afficher d'abord les pins sans les filtres + + this.loadCountriesForFiltrers(pins); // Ensuite, charger les pays en arrière-plan + }); + } } diff --git a/src/app/components/login-page/login-page.component.html b/src/app/components/login-page/login-page.component.html index ad6dd20..002facc 100644 --- a/src/app/components/login-page/login-page.component.html +++ b/src/app/components/login-page/login-page.component.html @@ -124,7 +124,7 @@ Vous n'êtes pas encore inscrit ? Créer un compte diff --git a/src/app/components/pin-marker/pin-marker.component.html b/src/app/components/pin-marker/pin-marker.component.html index 3863092..def3ec3 100644 --- a/src/app/components/pin-marker/pin-marker.component.html +++ b/src/app/components/pin-marker/pin-marker.component.html @@ -1,3 +1,8 @@ + +
diff --git a/src/app/services/map-reload/map-reload.service.spec.ts b/src/app/services/map-reload/map-reload.service.spec.ts new file mode 100644 index 0000000..ec33701 --- /dev/null +++ b/src/app/services/map-reload/map-reload.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { MapReloadService } from './map-reload.service'; + +describe('MapReloadService', () => { + let service: MapReloadService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(MapReloadService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/map-reload/map-reload.service.ts b/src/app/services/map-reload/map-reload.service.ts new file mode 100644 index 0000000..a328c01 --- /dev/null +++ b/src/app/services/map-reload/map-reload.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class MapReloadService { + private reloadSubject = new Subject(); + public reload$ = this.reloadSubject.asObservable(); + + requestReload(): void { + this.reloadSubject.next(); + } +}