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.
141 lines
4.4 KiB
141 lines
4.4 KiB
import { CommonModule, ViewportScroller } from '@angular/common';
|
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
|
import { NavigationEnd, Router } from '@angular/router';
|
|
import { Subscription } from 'rxjs';
|
|
import { filter } from 'rxjs/operators';
|
|
import { Pin } from '../../model/Pin';
|
|
import { ImageService } from '../../services/image/image.service';
|
|
import { ModalService } from '../../services/modal/modal.service';
|
|
import { PinService } from '../../services/pin/pin.service';
|
|
|
|
@Component({
|
|
selector: 'app-timeline',
|
|
standalone: true,
|
|
imports: [CommonModule],
|
|
templateUrl: './timeline.component.html',
|
|
})
|
|
export class TimelineComponent implements OnInit, OnDestroy {
|
|
pins: Pin[] = [];
|
|
imageUrls: SafeUrl[][] = [];
|
|
loading = true;
|
|
groupedPins: { [year: string]: Pin[] } = {};
|
|
sortedYears: string[] = [];
|
|
carouselIndexes: number[] = [];
|
|
expandedDescriptions: { [index: number]: boolean } = {};
|
|
private navigationSubscription: Subscription;
|
|
|
|
constructor(
|
|
private pinService: PinService,
|
|
private imageService: ImageService,
|
|
private sanitizer: DomSanitizer,
|
|
private modalService: ModalService,
|
|
private router: Router,
|
|
private viewportScroller: ViewportScroller
|
|
) {
|
|
// Écouter les événements de navigation
|
|
this.navigationSubscription = this.router.events
|
|
.pipe(filter((event) => event instanceof NavigationEnd))
|
|
.subscribe(() => {
|
|
// Attendre que le contenu soit chargé
|
|
if (!this.loading) {
|
|
this.restoreScrollPosition();
|
|
}
|
|
});
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
// Nettoyer la souscription lors de la destruction du composant
|
|
if (this.navigationSubscription) {
|
|
this.navigationSubscription.unsubscribe();
|
|
}
|
|
}
|
|
|
|
private restoreScrollPosition() {
|
|
const scrollPosition = sessionStorage.getItem('timelineScrollPosition');
|
|
if (scrollPosition) {
|
|
window.scrollTo({
|
|
top: parseInt(scrollPosition),
|
|
behavior: 'smooth',
|
|
});
|
|
sessionStorage.removeItem('timelineScrollPosition');
|
|
}
|
|
}
|
|
|
|
openPinModal() {
|
|
this.modalService.openModal('add-pin-modal');
|
|
}
|
|
|
|
navigateToPinOnMap(pinId: string) {
|
|
const scrollPosition = window.scrollY;
|
|
sessionStorage.setItem('timelineScrollPosition', scrollPosition.toString());
|
|
this.router.navigate(['/map'], { queryParams: { pin: pinId } });
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.pinService.getPins().subscribe((pins: Pin[]) => {
|
|
this.pins = pins
|
|
.filter((pin) => !!pin.date)
|
|
.sort((a, b) => (a.date! > b.date! ? 1 : -1));
|
|
this.imageUrls = this.pins.map(() => []); // initialise le tableau d'images
|
|
|
|
this.pins.forEach((pin, index) => {
|
|
if (pin.files && pin.files.length > 0) {
|
|
pin.files.forEach((imageId) => {
|
|
this.imageService.getImage(imageId).subscribe((blob) => {
|
|
const objectUrl = URL.createObjectURL(blob);
|
|
const safeUrl = this.sanitizer.bypassSecurityTrustUrl(objectUrl);
|
|
this.imageUrls[index].push(safeUrl);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
this.carouselIndexes = this.pins.map(() => 0);
|
|
this.loading = false;
|
|
this.groupPinsByYear();
|
|
|
|
// Attendre que le DOM soit mis à jour avant de restaurer la position
|
|
setTimeout(() => {
|
|
this.restoreScrollPosition();
|
|
}, 100);
|
|
});
|
|
}
|
|
|
|
private groupPinsByYear(): void {
|
|
this.groupedPins = {};
|
|
|
|
for (const pin of this.pins) {
|
|
const year = new Date(pin.date!).getFullYear().toString();
|
|
if (!this.groupedPins[year]) {
|
|
this.groupedPins[year] = [];
|
|
}
|
|
this.groupedPins[year].push(pin);
|
|
}
|
|
|
|
// Trie les pins dans chaque groupe (au cas où)
|
|
for (const year in this.groupedPins) {
|
|
this.groupedPins[year].sort((a, b) => a.date!.localeCompare(b.date!));
|
|
}
|
|
|
|
// Trie les années dans l'ordre croissant (utilisé dans le template)
|
|
this.sortedYears = Object.keys(this.groupedPins).sort((a, b) => +a - +b);
|
|
}
|
|
|
|
nextImage(index: number) {
|
|
const images = this.imageUrls[index];
|
|
this.carouselIndexes[index] =
|
|
(this.carouselIndexes[index] + 1) % images.length;
|
|
}
|
|
|
|
prevImage(index: number) {
|
|
const images = this.imageUrls[index];
|
|
this.carouselIndexes[index] =
|
|
(this.carouselIndexes[index] - 1 + images.length) % images.length;
|
|
}
|
|
|
|
toggleDescription(index: number): void {
|
|
this.expandedDescriptions[index] = !this.expandedDescriptions[index];
|
|
}
|
|
}
|