Add reservation and purchase functionality

Introduces ReservationSuccess, ReservationFailed, PurchaseSuccess, PurchaseFailed, TicketSmall, and TicketList components for handling and displaying reservation and purchase outcomes. Updates order flow logic in OrderComponent to support reservation and purchase states, disables/enables form inputs during submission, and integrates new UI feedback. Also adds angularx-qrcode dependency and updates @infinimotion/model-frontend version.
This commit is contained in:
2025-11-14 17:56:33 +01:00
parent f165a91e3c
commit 50cac8ac24
30 changed files with 821 additions and 107 deletions

View File

@@ -0,0 +1,15 @@
@keyframes blink {
0% {
color: #6366f1;
}
50% {
color: #ffde05;
}
100% {
color: #6366f1;
}
}
.blink {
animation: blink 1s ease-in-out infinite;
}

View File

@@ -1,6 +1,11 @@
<button (click)="updateSelectedSeats(this.seat())" [disabled]="state() == TheaterSeatState.BOOKED || state() == TheaterSeatState.RESERVED || !seatService.getSeatIsSelected()" class="mx-0.5 hover:opacity-50">
<mat-icon [ngStyle]="{color: isSelectedAndAvaliable() ? '#6366f1': getSeatStateColor() }" style="font-size: 30px; width: 30px; height: 30px">
<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() }"
[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 }}
</mat-icon>
<!-- [ngClass]="{'blink': isSelectedAndAvaliable() && !seatService.getSeatIsSelectable()}" -->
</button>

View File

@@ -19,17 +19,29 @@ export class SeatComponent{
protected readonly TheaterSeatState = TheaterSeatState;
getSeatStateColor(): string {
if (!this.seatService.getSeatIsSelectable()) return 'gray'
switch (this.state()) {
case TheaterSeatState.RESERVED:
return 'orange';
return '#d6c9a9';
case TheaterSeatState.BOOKED:
return 'red';
return '#d9abab';
default:
case TheaterSeatState.AVAILABLE:
return 'black';
}
}
isHoverable(): boolean {
switch (this.state()) {
default:
case TheaterSeatState.AVAILABLE:
return this.seatService.getSeatIsSelectable();
case TheaterSeatState.RESERVED:
case TheaterSeatState.BOOKED:
return false;
}
}
updateSelectedSeats(selectedSeat: Sitzplatz) : void {
if(!this.selected){
this.seatService.pushSelectedSeat(selectedSeat);