diff --git a/src/app/theater-overlay/theater-overlay.component.html b/src/app/theater-overlay/theater-overlay.component.html
index 315e341..f2d7a36 100644
--- a/src/app/theater-overlay/theater-overlay.component.html
+++ b/src/app/theater-overlay/theater-overlay.component.html
@@ -13,7 +13,7 @@
}
@else {
-
+
}
diff --git a/src/app/theater-overlay/theater-overlay.component.ts b/src/app/theater-overlay/theater-overlay.component.ts
index 9050e31..5a3e55c 100644
--- a/src/app/theater-overlay/theater-overlay.component.ts
+++ b/src/app/theater-overlay/theater-overlay.component.ts
@@ -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,43 +16,78 @@ 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();
-}
+ ngOnInit() {
+ this.showId = Number(this.route.snapshot.paramMap.get('id')!);
+ this.selectedSeatService.clearSelection();
+ this.selectedSeatService.setSeatSelectable(true);
-loadPerformanceAndSeats() {
- this.loading.show();
+ this.startAutoRefresh();
+ }
- 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.loading.hide();
- }),
- catchError(err => {
- this.loading.showError(err);
- console.error('Fehler beim Laden', err);
- return of({ performance: null, seats: [] });
- })
- ).subscribe();
-}
+ ngOnDestroy() {
+ this.isPollingEnabled.set(false);
+ }
+
+ 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.set(this.converter(seats));
+
+ if (this.isInitialLoad()) {
+ this.loading.hide();
+ this.isInitialLoad.set(false);
+ }
+ }),
+ catchError(err => {
+ if (this.isInitialLoad()) {
+ this.loading.showError(err);
+ } 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: [] } });
+ })
+ );
+ }
converter(resp: { seats: Sitzplatz[], reserved: Sitzplatz[], booked: Sitzplatz[] }): {
seat: 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);
+ }
}