From ade5479a74b60296155f80d1e218c611a6057be1 Mon Sep 17 00:00:00 2001 From: Piet Ostendorp Date: Fri, 21 Nov 2025 15:53:42 +0100 Subject: [PATCH] Add functionality to cancel tickets Introduces a cancel order confirmation dialog and integrates it into the order flow. Refactors error and success components to support singular/plural seat messaging and retry actions. Updates navigation and button behaviors for better user experience. Fixes minor UI and logic issues in reservation, purchase, and conversion flows. --- src/app/app-module.ts | 2 + src/app/cancel-order/cancel-order.dialog.css | 3 ++ src/app/cancel-order/cancel-order.dialog.html | 10 ++++ src/app/cancel-order/cancel-order.dialog.ts | 22 +++++++++ .../cancellation-failed.component.html | 6 +-- .../cancellation-failed.component.ts | 12 ++++- .../cancellation-success.component.html | 8 +-- .../cancellation-success.component.ts | 18 ++++++- .../conversion-failed.component.html | 6 +-- .../conversion-failed.component.ts | 12 ++++- src/app/loading.service.ts | 21 ++++++-- .../movie-importer.component.html | 2 +- .../movie-importer.component.ts | 10 ++-- src/app/order/order.component.css | 4 ++ src/app/order/order.component.html | 22 ++++----- src/app/order/order.component.ts | 49 ++++++++++++++++++- .../pay-for-order.component.html | 6 +-- .../pay-for-order/pay-for-order.component.ts | 2 +- .../purchase-failed.component.html | 6 +-- .../purchase-failed.component.ts | 20 +++++++- .../purchase-success.component.html | 6 +-- .../purchase-success.component.ts | 14 ++++++ .../reservation-failed.component.html | 6 +-- .../reservation-failed.component.ts | 20 +++++++- .../reservation-success.component.html | 8 +-- .../reservation-success.component.ts | 18 +++++-- src/app/selected-seats.service.ts | 2 + .../theater-overlay.component.html | 2 +- .../theater-overlay.component.ts | 7 +++ 29 files changed, 266 insertions(+), 58 deletions(-) create mode 100644 src/app/cancel-order/cancel-order.dialog.css create mode 100644 src/app/cancel-order/cancel-order.dialog.html create mode 100644 src/app/cancel-order/cancel-order.dialog.ts diff --git a/src/app/app-module.ts b/src/app/app-module.ts index 59d2558..2558a4e 100644 --- a/src/app/app-module.ts +++ b/src/app/app-module.ts @@ -69,6 +69,7 @@ import { CancellationSuccessComponent } from './cancellation-success/cancellatio import { CancellationFailedComponent } from './cancellation-failed/cancellation-failed.component'; import { ConversionFailedComponent } from './conversion-failed/conversion-failed.component'; import { PayForOrderComponent } from './pay-for-order/pay-for-order.component'; +import { CancelOrderDialog } from './cancel-order/cancel-order.dialog'; @NgModule({ @@ -117,6 +118,7 @@ import { PayForOrderComponent } from './pay-for-order/pay-for-order.component'; CancellationFailedComponent, ConversionFailedComponent, PayForOrderComponent, + CancelOrderDialog, ], imports: [ AppRoutingModule, diff --git a/src/app/cancel-order/cancel-order.dialog.css b/src/app/cancel-order/cancel-order.dialog.css new file mode 100644 index 0000000..f785beb --- /dev/null +++ b/src/app/cancel-order/cancel-order.dialog.css @@ -0,0 +1,3 @@ +button { + min-width: 100px; +} diff --git a/src/app/cancel-order/cancel-order.dialog.html b/src/app/cancel-order/cancel-order.dialog.html new file mode 100644 index 0000000..0c953f3 --- /dev/null +++ b/src/app/cancel-order/cancel-order.dialog.html @@ -0,0 +1,10 @@ +

Möchten Sie Ihre Bestellung wirklich stornieren?

+ + +

Nach der Stornierung verlieren Sie Ihr Reservierungsrecht und die Sitzplätze können von anderen Kunden in Anspruch genommen werden. Dieser Prozess kann nicht rückgängig gemacht werden.

+
+ + + + + diff --git a/src/app/cancel-order/cancel-order.dialog.ts b/src/app/cancel-order/cancel-order.dialog.ts new file mode 100644 index 0000000..44dc764 --- /dev/null +++ b/src/app/cancel-order/cancel-order.dialog.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'app-cancel-order', + standalone: false, + templateUrl: './cancel-order.dialog.html', + styleUrl: './cancel-order.dialog.css', +}) +export class CancelOrderDialog { + constructor( + private dialogRef: MatDialogRef, + ) {} + + submit(): void { + this.dialogRef.close(true); + } + + cancel(): void { + this.dialogRef.close(false); + } +} diff --git a/src/app/cancellation-failed/cancellation-failed.component.html b/src/app/cancellation-failed/cancellation-failed.component.html index 0bd5a1d..773143e 100644 --- a/src/app/cancellation-failed/cancellation-failed.component.html +++ b/src/app/cancellation-failed/cancellation-failed.component.html @@ -3,9 +3,9 @@ warning

Stornierung fehlgeschlagen!

-

Leider konnten Ihre Sitzplätze nicht storniert werden. Möglicherweise wurden die Tickets bereits bezahlt oder storniert.

+

{{ infoText }}

- - + + diff --git a/src/app/cancellation-failed/cancellation-failed.component.ts b/src/app/cancellation-failed/cancellation-failed.component.ts index a6e7519..05663f0 100644 --- a/src/app/cancellation-failed/cancellation-failed.component.ts +++ b/src/app/cancellation-failed/cancellation-failed.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, input, output } from '@angular/core'; @Component({ selector: 'app-cancellation-failed', @@ -7,5 +7,15 @@ import { Component } from '@angular/core'; styleUrl: './cancellation-failed.component.css', }) export class CancellationFailedComponent { + moreThanOne = input(false); + retry = output(); + + infoText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Leider konnten Ihre Sitzplätze nicht storniert werden. Möglicherweise wurden die Tickets bereits bezahlt oder storniert.' : + 'Leider konnte Ihr Sitzplatz nicht storniert werden. Möglicherweise wurde das Ticket bereits bezahlt oder storniert.'; + } } diff --git a/src/app/cancellation-success/cancellation-success.component.html b/src/app/cancellation-success/cancellation-success.component.html index d7d1c22..166309e 100644 --- a/src/app/cancellation-success/cancellation-success.component.html +++ b/src/app/cancellation-success/cancellation-success.component.html @@ -1,11 +1,11 @@ -
+
task_alt

Stornierung erfolgreich!

-

Ihre Sitzplätze wurden erfolgreich storniert und stehen wieder zur Buchung zur Verfügnug.

+

{{ infoText }}

- - + +
diff --git a/src/app/cancellation-success/cancellation-success.component.ts b/src/app/cancellation-success/cancellation-success.component.ts index 75e645f..6110bed 100644 --- a/src/app/cancellation-success/cancellation-success.component.ts +++ b/src/app/cancellation-success/cancellation-success.component.ts @@ -1,4 +1,5 @@ -import { Component, input } from '@angular/core'; +import { Component, inject, input } from '@angular/core'; +import { Router } from '@angular/router'; @Component({ selector: 'app-cancellation-success', @@ -8,4 +9,19 @@ import { Component, input } from '@angular/core'; }) export class CancellationSuccessComponent { performanceId = input.required(); + moreThanOne = input(false); + + router = inject(Router); + + infoText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Ihre Sitzplätze wurden erfolgreich storniert und stehen wieder zur Buchung zur Verfügnug.' : + 'Ihr Sitzplatz wurden erfolgreich storniert und steht wieder zur Buchung zur Verfügnug.'; + } + + navigate() { + window.location.href = `/checkout/performance/${this.performanceId()}`; + } } diff --git a/src/app/conversion-failed/conversion-failed.component.html b/src/app/conversion-failed/conversion-failed.component.html index d822ae3..018a3ad 100644 --- a/src/app/conversion-failed/conversion-failed.component.html +++ b/src/app/conversion-failed/conversion-failed.component.html @@ -3,9 +3,9 @@ warning

Kauf fehlgeschlagen!

-

Leider konnten Ihre Sitzplätze nicht bezahlt werden. Möglicherweise wurden die Tickets bereits storniert.

+

{{ infoText }}

- - + +
diff --git a/src/app/conversion-failed/conversion-failed.component.ts b/src/app/conversion-failed/conversion-failed.component.ts index 9ba4c68..3957541 100644 --- a/src/app/conversion-failed/conversion-failed.component.ts +++ b/src/app/conversion-failed/conversion-failed.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, input, output } from '@angular/core'; @Component({ selector: 'app-conversion-failed', @@ -7,5 +7,15 @@ import { Component } from '@angular/core'; styleUrl: './conversion-failed.component.css', }) export class ConversionFailedComponent { + moreThanOne = input(false); + retry = output(); + + infoText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Leider konnten Ihre Sitzplätze nicht bezahlt werden. Möglicherweise wurden die Tickets bereits storniert.' : + 'Leider konnte Ihr Sitzplatz nicht bezahlt werden. Möglicherweise wurde das Ticket bereits storniert.'; + } } diff --git a/src/app/loading.service.ts b/src/app/loading.service.ts index 988e652..532b309 100644 --- a/src/app/loading.service.ts +++ b/src/app/loading.service.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { BehaviorSubject } from 'rxjs'; +import { MatSnackBar, MatSnackBarRef } from '@angular/material/snack-bar'; +import { BehaviorSubject, Subscription } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -13,6 +13,9 @@ export class LoadingService { public loading$ = this.loadingSubject.asObservable(); public error$ = this.errorSubject.asObservable(); + private currentSnackBarRef?: MatSnackBarRef; + private currentSubscription?: Subscription; + constructor(private snackBar: MatSnackBar) {} show(): void { @@ -23,6 +26,7 @@ export class LoadingService { hide(): void { this.loadingSubject.next(false); this.errorSubject.next(false); + this.currentSnackBarRef?.dismiss(); } showError(messageOrError?: string | HttpErrorResponse | any): void { @@ -35,15 +39,22 @@ export class LoadingService { const message = this.getErrorMessage(messageOrError); - const snackBarRef = this.snackBar.open(message, 'Schließen', { + if (this.currentSnackBarRef) { + this.currentSubscription?.unsubscribe(); + this.currentSnackBarRef.dismiss(); + } + + this.currentSnackBarRef = this.snackBar.open(message, 'Schließen', { duration: 0, panelClass: ['error-snackbar'], horizontalPosition: 'center', verticalPosition: 'bottom' }); - snackBarRef.afterDismissed().subscribe(() => { - this.hide(); + this.currentSubscription = this.currentSnackBarRef.afterDismissed().subscribe(() => { + if (!this.loadingSubject.value) { + this.hide(); + } }); } diff --git a/src/app/movie-importer/movie-importer.component.html b/src/app/movie-importer/movie-importer.component.html index 6f614b8..59385ca 100644 --- a/src/app/movie-importer/movie-importer.component.html +++ b/src/app/movie-importer/movie-importer.component.html @@ -5,7 +5,7 @@
Film online suchen - + @if (formControl.hasError('noResults')) { Keine Suchergebnisse gefunden } diff --git a/src/app/movie-importer/movie-importer.component.ts b/src/app/movie-importer/movie-importer.component.ts index c68289b..2419b29 100644 --- a/src/app/movie-importer/movie-importer.component.ts +++ b/src/app/movie-importer/movie-importer.component.ts @@ -1,9 +1,10 @@ import { LoadingService } from './../loading.service'; -import { Component, inject } from '@angular/core'; +import { Component, DestroyRef, inject } from '@angular/core'; import { FormControl } from '@angular/forms'; import { catchError, finalize, of, tap } from 'rxjs'; import { HttpService } from '../http.service'; import { OmdbMovie } from '@infinimotion/model-frontend'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'app-movie-importer', @@ -21,13 +22,15 @@ export class MovieImporterComponent { private httpService = inject(HttpService) public loadingService = inject(LoadingService) + private destroyRef = inject(DestroyRef); + DoSubmit() { this.showAll = false; this.searchForMovies(); } - searchForMovies() { + private searchForMovies() { this.search_query = this.formControl.value?.trim() || ''; if (this.search_query?.length == 0) return; @@ -48,7 +51,8 @@ export class MovieImporterComponent { finalize(() => { this.isSearching = false; this.formControl.enable(); - }) + }), + takeUntilDestroyed(this.destroyRef) ).subscribe(); } diff --git a/src/app/order/order.component.css b/src/app/order/order.component.css index 367c809..9732f3d 100644 --- a/src/app/order/order.component.css +++ b/src/app/order/order.component.css @@ -1,3 +1,7 @@ +:host { + min-width: 500px; +} + mat-stepper { background: transparent !important; } diff --git a/src/app/order/order.component.html b/src/app/order/order.component.html index f9a2b58..ab9e36b 100644 --- a/src/app/order/order.component.html +++ b/src/app/order/order.component.html @@ -28,7 +28,7 @@ } - + Warenkorb
@@ -67,7 +67,7 @@
- +
Anschrift @@ -75,11 +75,11 @@ @if (isReservationSuccess() && !isSubmitting()) {
- + } - @else if (isReservationError() && !isSubmitting()) { + @else if (isReservationError() && !isSubmitting() && performance()) {
- + } @else { @@ -123,23 +123,23 @@ @if (isPurchaseSuccess() && !isSubmitting()) {
- + } - @else if (isPurchaseError() && !isSubmitting()) { + @else if (isPurchaseError() && !isSubmitting() && performance()) {
- + } @else if (isConversionError() && !isSubmitting()) {
- + } @else if (isCancellationSuccess() && !isSubmitting() && performance()) {
- + } @else if (isCancellationError() && !isSubmitting()) {
- + } @else { diff --git a/src/app/order/order.component.ts b/src/app/order/order.component.ts index e3aa851..e4631ef 100644 --- a/src/app/order/order.component.ts +++ b/src/app/order/order.component.ts @@ -8,6 +8,8 @@ import { HttpService } from '../http.service'; import { catchError, tap, finalize, EMPTY } from 'rxjs'; import { MatStepper } from '@angular/material/stepper'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { MatDialog } from '@angular/material/dialog'; +import { CancelOrderDialog } from '../cancel-order/cancel-order.dialog'; type OrderState = | { status: 'idle' } @@ -32,6 +34,7 @@ export class OrderComponent { private fb = inject(FormBuilder); private httpService = inject(HttpService); private destroyRef = inject(DestroyRef); + private dialog = inject(MatDialog); readonly loadingService = inject(LoadingService); readonly selectedSeatsService = inject(SelectedSeatsService); @@ -41,6 +44,7 @@ export class OrderComponent { existingOrder = input(); existingTickets = input(); + resumeWithCancel = input(true); stepChanged = output(); @@ -130,6 +134,10 @@ export class OrderComponent { cvv: ['', [Validators.required, Validators.pattern(/^\d{3,4}$/)]], }); this.confetti = (await import('canvas-confetti')).default; + + if (this.resumeWithCancel()) { + this.cancelReservation(); + } } get fData() { return this.dataForm.controls; } @@ -161,6 +169,7 @@ export class OrderComponent { this.makeReservation(); } else if (this.submissionMode() === 'purchase') { stepper.next(); + } } @@ -228,7 +237,7 @@ export class OrderComponent { } private submitOrder(order: Bestellung, seats: Sitzplatz[], performance: Vorstellung, mode: SubmissionMode) { - this.loadingService.hide(); + this.loadingService.show(); // Tickets anlegen const tickets = seats.map(seat => { @@ -324,7 +333,23 @@ export class OrderComponent { }; } + cancelReservation() { + const dialogRef = this.dialog.open(CancelOrderDialog, { + width: '500px', + disableClose: false, + enterAnimationDuration: '200ms', + exitAnimationDuration: '100ms' + }); + + dialogRef.afterClosed().subscribe(confirmed => { + if (confirmed) { + this.performCancellation(); + } + }); + } + + private performCancellation() { const order = this.existingOrder()!; order.cancelled = new Date(); @@ -365,4 +390,26 @@ export class OrderComponent { getPriceDisplay(price: number): string { return `${(price / 100).toFixed(2)} €`; } + + retryPurchase() { + this.orderState.set({ status: 'idle' }); + this.makePurchase(); + } + + retryReservation() { + this.orderState.set({ status: 'idle' }); + this.makeReservation(); + } + + retryConversion() { + this.orderState.set({ status: 'idle' }); + const order = this.existingOrder()!; + order.booked = new Date(); + this.convertOrder(order, this.existingTickets()!); + } + + retryCancellation() { + this.orderState.set({ status: 'idle' }); + this.cancelReservation(); + } } diff --git a/src/app/pay-for-order/pay-for-order.component.html b/src/app/pay-for-order/pay-for-order.component.html index bac0bdd..dff3f0f 100644 --- a/src/app/pay-for-order/pay-for-order.component.html +++ b/src/app/pay-for-order/pay-for-order.component.html @@ -8,7 +8,7 @@ @if (formControl.hasError('invalid')) { - Ungültiger Bestellcode + Ungültiger Reservierungscode } @else if (formControl.hasError('completed')) { Diese Bestellung wurde bereits abgeschlossen @@ -23,10 +23,10 @@ Diese Bestellung wurde bereits bezahlt } @else if (formControl.hasError('cancelled')) { - Diese Bestellung wurde storniert + Diese Reservierung wurde storniert } @else if (formControl.hasError('serverError')) { - Fehler beim Laden der Bestellung + Fehler beim Laden der Reservierung } diff --git a/src/app/pay-for-order/pay-for-order.component.ts b/src/app/pay-for-order/pay-for-order.component.ts index c12b83b..3c2c06f 100644 --- a/src/app/pay-for-order/pay-for-order.component.ts +++ b/src/app/pay-for-order/pay-for-order.component.ts @@ -3,7 +3,7 @@ import { FormControl, Validators } from '@angular/forms'; import { LoadingService } from '../loading.service'; import { HttpService } from '../http.service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { catchError, map, of, take } from 'rxjs'; +import { catchError, finalize, map, of, take } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; @Component({ diff --git a/src/app/purchase-failed/purchase-failed.component.html b/src/app/purchase-failed/purchase-failed.component.html index d841ce0..b2a104a 100644 --- a/src/app/purchase-failed/purchase-failed.component.html +++ b/src/app/purchase-failed/purchase-failed.component.html @@ -3,9 +3,9 @@ warning

Kauf fehlgeschlagen!

-

Leider konnten Ihre Sitzplätze nicht gekauft werden. Dies kann passieren, wenn andere Nutzer zeitgleich versucht haben, dieselben Sitzplätze zu kaufen.

+

{{ infoText }}

- - + + diff --git a/src/app/purchase-failed/purchase-failed.component.ts b/src/app/purchase-failed/purchase-failed.component.ts index 619d3e9..50c3db5 100644 --- a/src/app/purchase-failed/purchase-failed.component.ts +++ b/src/app/purchase-failed/purchase-failed.component.ts @@ -1,4 +1,5 @@ -import { Component } from '@angular/core'; +import { Component, inject, input, output } from '@angular/core'; +import { Router } from '@angular/router'; @Component({ selector: 'app-purchase-failed', @@ -7,5 +8,22 @@ import { Component } from '@angular/core'; styleUrl: './purchase-failed.component.css', }) export class PurchaseFailedComponent { + performanceId = input.required(); + moreThanOne = input(false); + retry = output(); + + private router = inject(Router); + + infoText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Leider konnten Ihre Sitzplätze nicht gekauft werden. Dies kann passieren, wenn andere Nutzer zeitgleich versucht haben, dieselben Sitzplätze zu kaufen.' : + 'Leider konnte Ihr Sitzplatz nicht gekauft werden. Dies kann passieren, wenn andere Nutzer zeitgleich versucht haben, denselben Sitzplatz zu kaufen.'; + } + + navigate() { + window.location.href = `/checkout/performance/${this.performanceId()}`; + } } diff --git a/src/app/purchase-success/purchase-success.component.html b/src/app/purchase-success/purchase-success.component.html index c439043..68777c2 100644 --- a/src/app/purchase-success/purchase-success.component.html +++ b/src/app/purchase-success/purchase-success.component.html @@ -1,11 +1,11 @@

Vielen Dank für Ihren Einkauf!

-

Ihre Sitzplätze wurden erfolgreich gebucht.

+

{{ infoText }}

- - + +
diff --git a/src/app/purchase-success/purchase-success.component.ts b/src/app/purchase-success/purchase-success.component.ts index 8dad591..3805ad4 100644 --- a/src/app/purchase-success/purchase-success.component.ts +++ b/src/app/purchase-success/purchase-success.component.ts @@ -9,4 +9,18 @@ import { Component, input } from '@angular/core'; }) export class PurchaseSuccessComponent { tickets = input.required(); + moreThanOne = input(false); + + infoText!: string; + buttonText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Ihre Sitzplätze wurden erfolgreich gebucht.' : + 'Ihr Sitzplatz wurden erfolgreich gebucht.'; + + this.buttonText = this.moreThanOne()? + 'Tickets herunterladen' : + 'Ticket herunterladen'; + } } diff --git a/src/app/reservation-failed/reservation-failed.component.html b/src/app/reservation-failed/reservation-failed.component.html index abd1532..8e89629 100644 --- a/src/app/reservation-failed/reservation-failed.component.html +++ b/src/app/reservation-failed/reservation-failed.component.html @@ -3,9 +3,9 @@ warning

Reservierung fehlgeschlagen!

-

Leider konnten Ihre Sitzplätze nicht reserviert werden. Dies kann passieren, wenn andere Nutzer gleichzeitig versucht haben, dieselben Sitzplätze zu reservieren.

+

{{ infoText }}

- - + + diff --git a/src/app/reservation-failed/reservation-failed.component.ts b/src/app/reservation-failed/reservation-failed.component.ts index 7693d1e..0018215 100644 --- a/src/app/reservation-failed/reservation-failed.component.ts +++ b/src/app/reservation-failed/reservation-failed.component.ts @@ -1,4 +1,5 @@ -import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { Component, inject, input, output } from '@angular/core'; @Component({ selector: 'app-reservation-failed', @@ -7,5 +8,22 @@ import { Component } from '@angular/core'; styleUrl: './reservation-failed.component.css', }) export class ReservationFailedComponent { + performanceId = input.required(); + moreThanOne = input(false); + retry = output(); + + router = inject(Router) + + infoText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Leider konnten Ihre Sitzplätze nicht reserviert werden. Dies kann passieren, wenn andere Nutzer gleichzeitig versucht haben, dieselben Sitzplätze zu reservieren.' : + 'Leider konnte Ihr Sitzplatz nicht reserviert werden. Dies kann passieren, wenn andere Nutzer gleichzeitig versucht haben, denselben Sitzplatz zu reservieren.'; + } + + navigate() { + window.location.href = `/checkout/performance/${this.performanceId()}`; + } } diff --git a/src/app/reservation-success/reservation-success.component.html b/src/app/reservation-success/reservation-success.component.html index a8c961c..fac0714 100644 --- a/src/app/reservation-success/reservation-success.component.html +++ b/src/app/reservation-success/reservation-success.component.html @@ -1,14 +1,14 @@

Reservierung erfolgreich!

-

Ihre Sitzplätze wurden erfolgreich reserviert. Bitte nennen sie den folgenden Code an der Kasse, um Ihre Reservierung in eine Buchung umzuwandeln.

+

{{ infoText }}

{{ order().code }}
- - -
+ + +
Reservierung stornieren
diff --git a/src/app/reservation-success/reservation-success.component.ts b/src/app/reservation-success/reservation-success.component.ts index 8754ae6..1efca8e 100644 --- a/src/app/reservation-success/reservation-success.component.ts +++ b/src/app/reservation-success/reservation-success.component.ts @@ -1,5 +1,5 @@ import { Bestellung } from '@infinimotion/model-frontend'; -import { Component, input } from '@angular/core'; +import { Component, input, OnInit, output } from '@angular/core'; @Component({ selector: 'app-reservation-success', @@ -7,10 +7,20 @@ import { Component, input } from '@angular/core'; templateUrl: './reservation-success.component.html', styleUrl: './reservation-success.component.css', }) -export class ReservationSuccessComponent { +export class ReservationSuccessComponent implements OnInit { order = input.required(); + moreThanOne = input(false); - cancelReservation() { - // Logic to cancel the reservation + infoText!: string; + buttonText!: string; + + ngOnInit(): void { + this.infoText = this.moreThanOne()? + 'Ihre Sitzplätze wurden erfolgreich reserviert.\nBitte nennen sie den folgenden Code an der Kasse, um Ihre Reservierung in eine Buchung umzuwandeln' : + 'Ihr Sitzplatz wurde erfolgreich reserviert.\nBitte nennen sie den folgenden Code an der Kasse, um Ihre Reservierung in eine Buchung umzuwandeln'; + + this.buttonText = this.moreThanOne()? + 'Tickets jetzt online bezahlen' : + 'Ticket jetzt online bezahlen'; } } diff --git a/src/app/selected-seats.service.ts b/src/app/selected-seats.service.ts index 8f54b22..9be1b06 100644 --- a/src/app/selected-seats.service.ts +++ b/src/app/selected-seats.service.ts @@ -61,6 +61,7 @@ export class SelectedSeatsService { } commit(): void { + this.erroredSignal.set(false); this.committedSignal.set(true); } @@ -69,6 +70,7 @@ export class SelectedSeatsService { } cancel(): void { + this.erroredSignal.set(false); this.cancelledSignal.set(true); } diff --git a/src/app/theater-overlay/theater-overlay.component.html b/src/app/theater-overlay/theater-overlay.component.html index d224028..d7599bd 100644 --- a/src/app/theater-overlay/theater-overlay.component.html +++ b/src/app/theater-overlay/theater-overlay.component.html @@ -18,6 +18,6 @@
- + diff --git a/src/app/theater-overlay/theater-overlay.component.ts b/src/app/theater-overlay/theater-overlay.component.ts index 4545191..d85cb6d 100644 --- a/src/app/theater-overlay/theater-overlay.component.ts +++ b/src/app/theater-overlay/theater-overlay.component.ts @@ -31,6 +31,7 @@ export class TheaterOverlayComponent implements OnInit, OnDestroy { orderId?: number; orderCode?: string | null; isResuming = false; + resumeWithCancel = false; tickets: Eintrittskarte[] | undefined; order: Bestellung | undefined; blockedSeats: Sitzplatz[] | undefined; @@ -56,8 +57,14 @@ export class TheaterOverlayComponent implements OnInit, OnDestroy { if (this.orderCode) { // Checkout fortsetzen this.isResuming = true; + this.loadExistingOrder(this.orderCode); + this.route.queryParams.subscribe(params => { + if (params['action'] === 'cancel') { + this.resumeWithCancel = true; + } + }); } else if (this.showId) { // Neuer Checkout this.isResuming = false;