diff --git a/src/app/app-module.ts b/src/app/app-module.ts
index c625000..59d2558 100644
--- a/src/app/app-module.ts
+++ b/src/app/app-module.ts
@@ -68,6 +68,7 @@ import { SelectionConflictInfoComponent } from './selection-conflict-info/select
import { CancellationSuccessComponent } from './cancellation-success/cancellation-success.component';
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';
@NgModule({
@@ -115,6 +116,7 @@ import { ConversionFailedComponent } from './conversion-failed/conversion-failed
CancellationSuccessComponent,
CancellationFailedComponent,
ConversionFailedComponent,
+ PayForOrderComponent,
],
imports: [
AppRoutingModule,
diff --git a/src/app/app-routing-module.ts b/src/app/app-routing-module.ts
index 1678c5f..5451ddc 100644
--- a/src/app/app-routing-module.ts
+++ b/src/app/app-routing-module.ts
@@ -8,6 +8,7 @@ import { ScheduleComponent } from './schedule/schedule.component';
import { TheaterOverlayComponent} from './theater-overlay/theater-overlay.component';
import { MovieImporterComponent } from './movie-importer/movie-importer.component';
import { AuthGuard } from './auth.guard';
+import { PayForOrderComponent } from './pay-for-order/pay-for-order.component';
const routes: Routes = [
// Seiten ohne Layout
@@ -29,6 +30,7 @@ const routes: Routes = [
},
{ path: 'checkout/performance/:performanceId', component: TheaterOverlayComponent},
{ path: 'checkout/order/:orderId', component: TheaterOverlayComponent},
+ { path: 'checkout/order', component: PayForOrderComponent},
],
},
diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts
index 5f2de5f..56a5ff0 100644
--- a/src/app/navbar/navbar.component.ts
+++ b/src/app/navbar/navbar.component.ts
@@ -10,6 +10,7 @@ import { Component, inject, computed, OnInit } from '@angular/core';
export class NavbarComponent {
navItems: { label:string, path:string }[] = [
{label: 'Programm', path: '/schedule'},
+ {label: 'Bezahlen', path: '/checkout/order'},
{label: 'Film importieren', path: '/admin/movie-importer'},
]
diff --git a/src/app/pay-for-order/pay-for-order.component.css b/src/app/pay-for-order/pay-for-order.component.css
new file mode 100644
index 0000000..7292745
--- /dev/null
+++ b/src/app/pay-for-order/pay-for-order.component.css
@@ -0,0 +1,7 @@
+.middle {
+ position: relative;
+ top: 40%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
diff --git a/src/app/pay-for-order/pay-for-order.component.html b/src/app/pay-for-order/pay-for-order.component.html
new file mode 100644
index 0000000..bac0bdd
--- /dev/null
+++ b/src/app/pay-for-order/pay-for-order.component.html
@@ -0,0 +1,40 @@
+
+
+
diff --git a/src/app/pay-for-order/pay-for-order.component.ts b/src/app/pay-for-order/pay-for-order.component.ts
new file mode 100644
index 0000000..c12b83b
--- /dev/null
+++ b/src/app/pay-for-order/pay-for-order.component.ts
@@ -0,0 +1,112 @@
+import { Component, DestroyRef, inject, OnInit } from '@angular/core';
+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 { ActivatedRoute, Router } from '@angular/router';
+
+@Component({
+ selector: 'app-pay-for-order',
+ standalone: false,
+ templateUrl: './pay-for-order.component.html',
+ styleUrl: './pay-for-order.component.css',
+})
+export class PayForOrderComponent implements OnInit {
+ private httpService = inject(HttpService);
+ private router = inject(Router);
+ private route = inject(ActivatedRoute);
+ private destroyRef = inject(DestroyRef);
+ public loadingService = inject(LoadingService);
+
+ queryError?: string;
+
+ formControl = new FormControl('', {
+ validators: [
+ Validators.required,
+ Validators.minLength(6),
+ Validators.maxLength(6)
+ ]
+ });
+
+ ngOnInit() {
+ const error = this.route.snapshot.queryParamMap.get('error');
+ const code = this.route.snapshot.queryParamMap.get('code');
+
+ if (code) {
+ this.formControl.setValue(code);
+ }
+
+ if (error) {
+ // Warte einen Tick, damit Angular das FormControl initialisiert hat
+ setTimeout(() => {
+ this.formControl.clearValidators();
+ this.formControl.setErrors({ [error]: true });
+ this.formControl.markAsTouched();
+ });
+
+ // Bei erster Änderung: Validatoren wieder aktivieren
+ this.formControl.valueChanges.pipe(
+ take(1),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe(() => {
+ this.formControl.setValidators([
+ Validators.required,
+ Validators.minLength(6),
+ Validators.maxLength(6)
+ ]);
+ this.formControl.updateValueAndValidity();
+ });
+ }
+ }
+
+ onInput(event: Event) {
+ this.queryError = undefined;
+ const input = event.target as HTMLInputElement;
+ const filtered = input.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
+ this.formControl.setValue(filtered, { emitEvent: false });
+ }
+
+ DoSubmit() {
+ this.formControl.markAsTouched();
+ if (this.formControl.invalid) return;
+
+ const code = this.formControl.value?.trim();
+ if (!code || code.length !== 6) return;
+
+ this.loadingService.show();
+ const orderFilter = [`eq;code;string;${code}`];
+
+ this.httpService.getOrdersByFilter(orderFilter).pipe(
+ map(orders => {
+ this.loadingService.hide();
+ if (orders.length === 0) {
+ this.formControl.setErrors({ invalid: true });
+ return
+ }
+
+ if (orders.length > 1) {
+ this.formControl.setErrors({ severalOrders: true });
+ return;
+ }
+ const order = orders[0];
+ if (order.booked) {
+ this.formControl.setErrors({ alreadyBooked: true });
+ return;
+ }
+ if (order.cancelled) {
+ this.formControl.setErrors({ cancelled: true });
+ return;
+ }
+ this.router.navigate(['/checkout/order', order.code]);
+ }),
+ catchError(err => {
+ this.loadingService.hide();
+ this.loadingService.showError(err);
+ this.formControl.setErrors({ serverError: true });
+ return of(null);
+ }),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe();
+ }
+}
diff --git a/src/app/theater-overlay/theater-overlay.component.ts b/src/app/theater-overlay/theater-overlay.component.ts
index 270f272..4545191 100644
--- a/src/app/theater-overlay/theater-overlay.component.ts
+++ b/src/app/theater-overlay/theater-overlay.component.ts
@@ -242,7 +242,7 @@ export class TheaterOverlayComponent implements OnInit, OnDestroy {
if (!tickets.length) {
return from(this.router.navigate(
['/checkout/order'],
- { queryParams: { error: 'invalid' } }
+ { queryParams: { error: 'invalid', code: orderCode } }
));
}
@@ -251,7 +251,7 @@ export class TheaterOverlayComponent implements OnInit, OnDestroy {
if (this.order.booked || this.order.cancelled) {
return from(this.router.navigate(
['/checkout/order'],
- { queryParams: { error: 'completed' } }
+ { queryParams: { error: 'completed', code: orderCode } }
));
}
@@ -264,14 +264,16 @@ export class TheaterOverlayComponent implements OnInit, OnDestroy {
return this.loadPerformanceAndSeats();
}),
catchError(err => {
- this.loading.hide();
console.error('Fehler beim Laden der Bestellung', err);
return from(this.router.navigate(
['/checkout/order'],
- { queryParams: { error: 'invalid' } }
+ { queryParams: { error: 'invalid', code: orderCode } }
));
}),
+ finalize(() => {
+ this.loading.hide();
+ }),
takeUntilDestroyed(this.destroyRef)
).subscribe();
}