This commit is contained in:
2025-11-15 00:41:18 +01:00
parent de5990db91
commit 4ec3795697
12 changed files with 88 additions and 19 deletions

View File

@@ -141,7 +141,7 @@
<!-- Card Name -->
<mat-form-field class="w-full">
<mat-label>Kartenname</mat-label>
<mat-label>Name des Besitzers</mat-label>
<input matInput formControlName="cardName" />
@if (fPayment['cardName'].hasError('minlength')) { <mat-error>Mindestens 3 Zeichen</mat-error> }
</mat-form-field>

View File

@@ -27,11 +27,13 @@ export class OrderComponent {
private httpService = inject(HttpService)
private selectedSeatsService = inject(SelectedSeatsService);
confetti: any;
constructor(private fb: FormBuilder) {}
// Form-Validation
ngOnInit(): void {
async ngOnInit() {
this.paymentForm = this.fb.group({
cardNumber: ['', [Validators.required, Validators.pattern(/^\d{16}$/)]],
cardName: ['', [Validators.required, Validators.minLength(3)]],
@@ -43,6 +45,7 @@ export class OrderComponent {
email: ['', [Validators.required, Validators.email]],
accept: ['', Validators.requiredTrue],
});
this.confetti = (await import('canvas-confetti')).default;
}
get fData() { return this.dataForm.controls; }
@@ -116,7 +119,6 @@ export class OrderComponent {
const order = this.generateNewOrderObject(this.dataForm.value.email, false);
const seats = this.selectedSeatsService.getSelectedSeatsList();
const performance = this.performance()!;
this.successful = true;
this.sendToBackend(order, seats, performance);
this.seatsReserved = true;
}
@@ -128,7 +130,6 @@ export class OrderComponent {
const order = this.generateNewOrderObject(this.dataForm.value.email, true);
const seats = this.selectedSeatsService.getSelectedSeatsList();
const performance = this.performance()!;
this.successful = true;
this.sendToBackend(order, seats, performance);
this.seatsPurchased = true;
}
@@ -147,13 +148,28 @@ export class OrderComponent {
});
Promise.all(ticketCreations.map(obs => obs.toPromise()))
.then(createdTickets => {
.then(async createdTickets => {
this.createdTickets = createdTickets.filter(
(ticket): ticket is Eintrittskarte => ticket !== undefined
);
this.successful = true;
this.selectedSeatsService.setCommitedTrue();
this.loadingService.hide();
this.enableInputs();
this.confetti({
particleCount: 100,
angle: 0,
spread: 180,
origin: { x: -0.1, y: 0.75 }
});
this.confetti({
particleCount: 100,
angle: 180,
spread: 180,
origin: { x: 1.1, y: 0.75 }
});
})
.catch(err => {
this.loadingService.showError(err);

View File

@@ -1,7 +1,7 @@
<button (click)="updateSelectedSeats(this.seat())" [disabled]="state() == TheaterSeatState.BOOKED || state() == TheaterSeatState.RESERVED || !seatService.getSeatIsSelectable()" class="mx-0.5">
<mat-icon
[class]="isHoverable()? 'hover:opacity-50' : ''"
[ngStyle]="{color: isSelectedAndAvaliable() ? '#6366f1': getSeatStateColor() }"
[ngStyle]="{color : getSeatStateColor() }"
[style]="!seatService.getSeatIsSelectable()? 'transition: color 0.5s ease, transform 0.3s ease-in-out;' : ''"
style="font-size: 30px; width: 30px; height: 30px;">
{{ seat().row.category.icon }}

View File

@@ -19,15 +19,22 @@ export class SeatComponent{
protected readonly TheaterSeatState = TheaterSeatState;
getSeatStateColor(): string {
if (!this.seatService.getSeatIsSelectable()) return 'gray'
if (this.isSelectedAndAvaliable()) {
return this.seatService.getCommited()? '#00c951' : '#6366f1';
}
if (!this.seatService.getSeatIsSelectable()) {
return '#e0e0e0'
}
switch (this.state()) {
case TheaterSeatState.RESERVED:
return '#d6c9a9';
return this.seatService.getDebug()? '#f7e8c3' : '#c0c0c0';
case TheaterSeatState.BOOKED:
return '#d9abab';
return this.seatService.getDebug()? '#ffc9c9' : '#c0c0c0';
default:
case TheaterSeatState.AVAILABLE:
return 'black';
return '#1B1B23';
}
}
@@ -50,7 +57,6 @@ export class SeatComponent{
}
this.selected = !this.selected;
//console.log(this.selected)
}
isSelectedAndAvaliable(): boolean {

View File

@@ -7,6 +7,8 @@ import {Sitzplatz} from '@infinimotion/model-frontend';
export class SelectedSeatsService {
private selectedSeatsSignal = signal<Sitzplatz[]>([]);
private seatIsSelectable: boolean = true;
private commited = false;
private debug = false;
get selectedSeats() {
return this.selectedSeatsSignal;
@@ -32,6 +34,7 @@ export class SelectedSeatsService {
clearSelectedSeatsList(): void {
this.selectedSeatsSignal.set([]);
this.commited = false;
}
getSeatIsSelectable(): boolean{
@@ -40,10 +43,27 @@ export class SelectedSeatsService {
setSeatIsSelectableTrue(): void {
this.seatIsSelectable = true;
this.commited = false;
}
setSeatIsSelectableFalse(): void {
this.seatIsSelectable = false;
}
getCommited(): boolean {
return this.commited;
}
setCommitedTrue(): void {
this.commited = true;
}
getDebug(): boolean {
return this.debug;
}
toggleDebug(): void {
this.debug = !this.debug;
}
}

View File

@@ -1,4 +1,4 @@
<div class="m-auto w-200 h-10 bg-gray-200 mb-22" style="clip-path: polygon(0% 0%,100% 0%,90% 100%,10% 100%);">
<div class="m-auto w-200 h-10 bg-gray-200 mb-22" style="clip-path: polygon(0% 0%,100% 0%,90% 100%,10% 100%);" (click)="selectedSeatsService.toggleDebug()">
<p class="flex justify-center text-lg font-bold p-1.5">
Leinwand
</p>

View File

@@ -1,4 +1,5 @@
import {Component, input} from '@angular/core';
import { SelectedSeatsService } from './../selected-seats.service';
import {Component, inject, input} from '@angular/core';
import {Sitzplatz} from '@infinimotion/model-frontend';
import {TheaterSeatState} from '../model/theater-seat-state.model';
@@ -10,4 +11,6 @@ import {TheaterSeatState} from '../model/theater-seat-state.model';
})
export class TheaterLayoutComponent {
seatsPerRow = input.required<{ seat: Sitzplatz, state: TheaterSeatState }[][]>();
protected selectedSeatsService = inject(SelectedSeatsService);
}

View File

@@ -3,9 +3,8 @@
<div class="flex justify-between h-100">
<div class="w-7/10 p-10 h-188">
<!-- <div class="bg-linear-to-b from-indigo-300 to-pink-300 h-full rounded-lg"> -->
<div>
@if (loading.loading$ | async){
@if (!performance && (loading.loading$ | async)){
<div class="w-full h-full flex items-center justify-center mt-70">
<mat-progress-spinner
mode="indeterminate"

View File

@@ -1,9 +1,21 @@
<div class="bg-white rounded-md shadow-sm w-full h-fit p-1 flex space-x-1 justify-between items-center">
<mat-icon class="opacity-50" style="font-size: 40px; width: 40px; height: 40px">
<img src="assets/logo.png" class="h-10 border-r-2 pr-0.5 border-dotted border-gray-400" />
<!-- <mat-icon class="opacity-50 mx-1" style="font-size: 42px; width: 42px; height: 42px">
local_activity
</mat-icon>
</mat-icon> -->
<div class="flex flex-col flex-1 text-sm leading-tight ml-1">
<p>{{ticket().seat.row.category.name}} • Reihe {{convertIntoRowName(ticket().seat.row.position)}} Platz {{ticket().seat.position}}</p>
<p>
{{ ticket().seat.row.category.name }}
@if (ticket().seat.row.category.name.length > 10) {
<br>
}
@else {
} Reihe
<span class="font-mono"><strong>{{ convertIntoRowName(ticket().seat.row.position) }}</strong></span>
Platz
<span class="font-mono"><strong>{{ ticket().seat.position }}</strong></span>
</p>
<div class="flex items-center space-x-2">
<p>Ticketcode:</p>
<p class="font-mono">

1
src/typings.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module 'canvas-confetti';