Add auto-refresh polling to theater overlay

Introduces periodic polling to refresh seat and performance data in TheaterOverlayComponent using RxJS interval and Angular signals. Polling is paused when the component is destroyed or manually via new methods, and the template is updated to use the seatsPerRow signal.
This commit is contained in:
2025-11-15 02:28:43 +01:00
parent e5707709bf
commit be680da692
2 changed files with 81 additions and 31 deletions

View File

@@ -13,7 +13,7 @@
</div>
}
@else {
<app-theater-layout [seatsPerRow]="seatsPerRow"></app-theater-layout>
<app-theater-layout [seatsPerRow]="seatsPerRow()"></app-theater-layout>
}
</div>
</div>

View File

@@ -1,11 +1,14 @@
import {Component, inject, OnInit} from '@angular/core';
import {Component, DestroyRef, inject, OnDestroy, OnInit, signal} from '@angular/core';
import {HttpService} from '../http.service';
import {LoadingService} from '../loading.service';
import {catchError, forkJoin, of, tap} from 'rxjs';
import {catchError, filter, forkJoin, interval, of, startWith, switchMap, tap} from 'rxjs';
import {Sitzkategorie, Sitzplatz, Vorstellung} from '@infinimotion/model-frontend';
import {TheaterSeatState} from '../model/theater-seat-state.model';
import {ActivatedRoute} from '@angular/router';
import {SelectedSeatsService} from '../selected-seats.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
const POLLING_INTERVAL_MS = 5000;
@Component({
selector: 'app-theater-overlay',
@@ -13,42 +16,77 @@ import {SelectedSeatsService} from '../selected-seats.service';
templateUrl: './theater-overlay.component.html',
styleUrl: './theater-overlay.component.css'
})
export class TheaterOverlayComponent implements OnInit {
export class TheaterOverlayComponent implements OnInit, OnDestroy {
private http = inject(HttpService);
loading = inject(LoadingService)
private route = inject(ActivatedRoute);
private destroyRef = inject(DestroyRef);
private selectedSeatService = inject(SelectedSeatsService);
readonly loading = inject(LoadingService);
showId!: number;
seatsPerRow: { seat: Sitzplatz, state: TheaterSeatState }[][] = []
seatsPerRow = signal<{ seat: Sitzplatz, state: TheaterSeatState }[][]>([]);
performance: Vorstellung | undefined;
seatCategories: Sitzkategorie[] = [];
constructor(private route: ActivatedRoute, private selectedSeatService : SelectedSeatsService) {}
private isPollingEnabled = signal(true);
private isInitialLoad = signal(true);
ngOnInit() {
this.showId = Number(this.route.snapshot.paramMap.get('id')!);
this.selectedSeatService.clearSelection();
this.selectedSeatService.setSeatSelectable(true);
this.loadPerformanceAndSeats();
this.startAutoRefresh();
}
loadPerformanceAndSeats() {
this.loading.show();
ngOnDestroy() {
this.isPollingEnabled.set(false);
}
forkJoin({
private startAutoRefresh() {
interval(POLLING_INTERVAL_MS).pipe(
startWith(0),
filter(() => this.isPollingEnabled()),
filter(() => !this.selectedSeatService.committed()),
switchMap(() => this.loadPerformanceAndSeats()),
takeUntilDestroyed(this.destroyRef)
).subscribe();
}
private loadPerformanceAndSeats() {
if (this.isInitialLoad()) {
this.loading.show();
}
return forkJoin({
performance: this.http.getPerformaceById(this.showId),
seats: this.http.getSeatsByShowId(this.showId)
}).pipe(
tap(({ performance, seats }) => {
this.performance = performance;
this.seatsPerRow = this.converter(seats);
this.seatsPerRow.set(this.converter(seats));
if (this.isInitialLoad()) {
this.loading.hide();
this.isInitialLoad.set(false);
}
}),
catchError(err => {
if (this.isInitialLoad()) {
this.loading.showError(err);
console.error('Fehler beim Laden', err);
return of({ performance: null, seats: [] });
} else {
console.warn('Fehler beim Aktualisieren der Sitze:', err);
}
if (this.isInitialLoad()) {
this.loading.hide();
this.isInitialLoad.set(false);
}
return of({ performance: null, seats: { seats: [], reserved: [], booked: [] } });
})
).subscribe();
);
}
converter(resp: { seats: Sitzplatz[], reserved: Sitzplatz[], booked: Sitzplatz[] }): {
@@ -80,6 +118,18 @@ loadPerformanceAndSeats() {
rows.forEach(row => row.sort((a, b) => a.seat.position - b.seat.position));
return rows;
}
refreshSeats(): void {
this.loadPerformanceAndSeats().subscribe();
}
pausePolling(): void { //TODO: Ab Stepper Schritt 2 Polling pausieren
this.isPollingEnabled.set(false);
}
resumePolling(): void {
this.isPollingEnabled.set(true);
}
}