Add payment form and improve order stepper UI

Introduces a payment step with card input masking using ngx-mask, refactors the order stepper to include address and payment forms with validation, and enhances UI/UX with new styles and layout adjustments. Also updates dependencies and module imports to support ngx-mask and Material Checkbox.
This commit is contained in:
2025-11-13 22:36:09 +01:00
parent cb065c8e39
commit 41c9d85e9b
9 changed files with 231 additions and 65 deletions

43
package-lock.json generated
View File

@@ -18,6 +18,7 @@
"@angular/router": "^20.3.0",
"@infinimotion/model-frontend": "^0.0.89",
"@tailwindcss/postcss": "^4.1.14",
"ngx-mask": "^20.0.3",
"postcss": "^8.5.6",
"rxjs": "~7.8.0",
"tailwindcss": "^4.1.14",
@@ -440,6 +441,7 @@
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.12.tgz",
"integrity": "sha512-hz8GtiMy3N9/e8407ZfrByHD5GEC4SkWtxyUknWuTM9P88AOie0jDZ6CfQg9gQ0OJX+6BAbJV3RpYZA1uzNUqA==",
"license": "MIT",
"peer": true,
"dependencies": {
"parse5": "^8.0.0",
"tslib": "^2.3.0"
@@ -490,6 +492,7 @@
"resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.10.tgz",
"integrity": "sha512-12fEzvKbEqjqy1fSk9DMYlJz6dF1MJVXuC5BB+oWWJpd+2lfh4xJ62pkvvLGAICI89hfM5n9Cy5kWnXwnqPZsA==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -506,6 +509,7 @@
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.10.tgz",
"integrity": "sha512-cW939Lr8GZjPSYfbQKIDNrUaHWmn2M+zBbERThfq5skLuY+xM60bJFv4NqBekfX6YqKLCY62ilUZlnImYIXaqA==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -519,6 +523,7 @@
"integrity": "sha512-9BemvpFxA26yIVdu8ROffadMkEdlk/AQQ2Jb486w7RPkrvUQ0pbEJukhv9aryJvhbMopT66S5H/j4ipOUMzmzQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/core": "7.28.3",
"@jridgewell/sourcemap-codec": "^1.4.14",
@@ -551,6 +556,7 @@
"resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.10.tgz",
"integrity": "sha512-g99Qe+NOVo72OLxowVF9NjCckswWYHmvO7MgeiZTDJbTjF9tXH96dMx7AWq76/GUinV10sNzDysVW16NoAbCRQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -576,6 +582,7 @@
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.10.tgz",
"integrity": "sha512-9yWr51EUauTEINB745AaHwZNTHLpXIm4uxuykxzOg+g2QskEgVfH26uS8G2ogdNuwYpB8wnsXWr34qhM3qgOWw==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -611,6 +618,7 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.10.tgz",
"integrity": "sha512-UV8CGoB5P3FmJciI3/I/n3L7C3NVgGh7bIlZ1BaB/qJDtv0Wq0rRAGwmT/Z3gwmrRtfHZWme7/CeQ2CYJmMyUQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -677,6 +685,7 @@
"integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
@@ -1633,6 +1642,7 @@
"integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@inquirer/checkbox": "^4.2.1",
"@inquirer/confirm": "^5.1.14",
@@ -3865,6 +3875,7 @@
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -4198,6 +4209,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754",
@@ -5294,6 +5306,7 @@
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.0",
@@ -6245,7 +6258,8 @@
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.9.0.tgz",
"integrity": "sha512-OMUvF1iI6+gSRYOhMrH4QYothVLN9C3EJ6wm4g7zLJlnaTl8zbaPOr0bTw70l7QxkoM7sVFOWo83u9B2Fe2Zng==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/jiti": {
"version": "2.6.1",
@@ -6339,6 +6353,7 @@
"integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@colors/colors": "1.5.0",
"body-parser": "^1.19.0",
@@ -7055,6 +7070,7 @@
"integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cli-truncate": "^4.0.0",
"colorette": "^2.0.20",
@@ -7693,6 +7709,20 @@
"node": ">= 0.6"
}
},
"node_modules/ngx-mask": {
"version": "20.0.3",
"resolved": "https://registry.npmjs.org/ngx-mask/-/ngx-mask-20.0.3.tgz",
"integrity": "sha512-5bmrgbFGudj0mFN6cPv/TI+cFJxT4l61mLIFskdvaXsJL/Oj7thRmWYqvqHXjCboOcx8gT6T/Zypl5u9l2J8Jg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0",
"@angular/forms": ">=14.0.0"
}
},
"node_modules/node-addon-api": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
@@ -8712,6 +8742,7 @@
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -8768,6 +8799,7 @@
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
@@ -9616,7 +9648,8 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
"license": "0BSD",
"peer": true
},
"node_modules/tuf-js": {
"version": "3.1.0",
@@ -9654,6 +9687,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -9840,6 +9874,7 @@
"integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -10243,6 +10278,7 @@
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -10261,7 +10297,8 @@
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
"integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
"license": "MIT"
"license": "MIT",
"peer": true
}
}
}

View File

@@ -32,6 +32,7 @@
"@angular/router": "^20.3.0",
"@infinimotion/model-frontend": "^0.0.89",
"@tailwindcss/postcss": "^4.1.14",
"ngx-mask": "^20.0.3",
"postcss": "^8.5.6",
"rxjs": "~7.8.0",
"tailwindcss": "^4.1.14",

View File

@@ -3,11 +3,11 @@ import { NgModule, provideBrowserGlobalErrorListeners } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { AppRoutingModule } from './app-routing-module';
import { App } from './app';
import { NgxMaskDirective, NgxMaskPipe, provideNgxMask } from 'ngx-mask';
import { MatIconModule } from '@angular/material/icon';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
@@ -21,6 +21,7 @@ import { MatButtonModule, MatIconButton } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatDialogClose, MatDialogTitle, MatDialogContent, MatDialogActions } from "@angular/material/dialog";
import { MatStepperModule } from '@angular/material/stepper';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { HeaderComponent } from './header/header.component';
import { HomeComponent } from './home/home.component';
@@ -29,7 +30,6 @@ import { MainLayoutComponent } from './layouts/main-layout/main-layout.component
import { NavbarComponent } from './navbar/navbar.component';
import { PocModelComponent } from './poc-model-component/poc-model-component';
import { ScheduleComponent } from './schedule/schedule.component';
import { MovieDurationComponent } from './movie-duration/movie-duration.component';
import { MoviePerformanceComponent } from './movie-performance/movie-performance.component';
import { MoviePosterComponent } from './movie-poster/movie-poster.component';
@@ -115,13 +115,17 @@ import { NoSeatsInHallComponent } from './no-seats-in-hall/no-seats-in-hall.comp
MatDialogTitle,
MatDialogContent,
MatDialogActions,
MatStepperModule
],
MatCheckboxModule,
MatStepperModule,
NgxMaskDirective,
NgxMaskPipe,
],
providers: [
provideBrowserGlobalErrorListeners(),
provideHttpClient(
withFetch(),
)
),
provideNgxMask(),
],
bootstrap: [App]
})

View File

@@ -1,7 +1,19 @@
mat-stepper {
background: transparent !important;
}
::ng-deep .mat-step-header {
background-color: transparent !important;
}
::ng-deep .mat-horizontal-stepper-header{
pointer-events: none !important;
}
.performance-info-space {
margin-top: calc(var(--spacing) * 24)
}
::ng-deep .checkbox-invalid.mat-mdc-checkbox .mat-internal-form-field {
color: red !important;
}

View File

@@ -1,4 +1,4 @@
<div class="w-full h-full">
<div class="w-full h-full relative">
@if (loadingService.loading$ | async){
<div class="w-full h-full flex items-center justify-center">
@@ -10,19 +10,21 @@
}
@else if (performance()) {
<mat-stepper
orientation="horizontal"
linear="true"
#stepper
>
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<div class="absolute top-18 z-20 w-full px-6">
<app-performance-info
class="w-full h-10"
[performance]="performance()!"
></app-performance-info>
</div>
<mat-stepper orientation="horizontal" linear="true" [disableRipple]="true" (selectionChange)="onStepChange($event)" #stepper>
<mat-step>
<ng-template matStepLabel>Warenkorb</ng-template>
<app-performance-info class="w-full h-50" [performance]="performance()!"></app-performance-info>
<div class="mb-4 mt-2 p-2">
<div class="performance-info-space"></div>
<!-- Seat-Selection Overview -->
<div class="mb-4 p-2">
@for (seatCategory of seatCategories(); track $index) {
<div class="h-2"></div>
<app-seat-selection [seatCategory]="seatCategory"></app-seat-selection>
@@ -30,55 +32,130 @@
@empty {
<app-no-seats-in-hall></app-no-seats-in-hall>
}
</div>
<mat-divider></mat-divider>
<!-- Total Price -->
<div class="flex justify-between p-2 mt-1 items-baseline">
<p class="font-semibold text-lg">
Tickets gesamt:
</p>
<p class="font-semibold text-2xl bg-gradient-to-r from-indigo-500 to-pink-600 bg-clip-text text-transparent">
<p class="font-semibold text-2xl bg-linear-to-r from-indigo-500 to-pink-600 bg-clip-text text-transparent">
{{ getPriceDisplay(totalPrice()) }}
</p>
</div>
<!-- Buttons -->
<div class="flex space-x-5 mt-10">
<button mat-button matButton="outlined" matStepperNext [disabled]="totalPrice()==0" class="w-1/2">Reservieren</button>
<button mat-button matButton="filled" matStepperNext class="w-1/2" [disabled]="totalPrice()==0">Buchen</button>
<button mat-button matButton="outlined" matStepperNext class="w-1/2" [disabled]="totalSeats()==0">Reservieren</button>
<button mat-button matButton="filled" matStepperNext class="w-1/2" [disabled]="totalSeats()==0">Buchen</button>
</div>
</mat-step>
<mat-step [stepControl]="dataForm">
<form [formGroup]="dataForm">
<ng-template matStepLabel>Anschrift</ng-template>
<div class="performance-info-space"></div>
<!-- Name -->
<mat-form-field class="w-full mt-8">
<mat-label>Name</mat-label>
<input matInput formControlName="name" placeholder="Max Mustermann" />
@if (fData['name'].hasError('minlength')) { <mat-error>Mindestens 3 Zeichen</mat-error> }
</mat-form-field>
<!-- E-Mail -->
<mat-form-field class="w-full mt-2">
<mat-label>E-Mail Adresse</mat-label>
<input matInput formControlName="email" placeholder="max.mustermann@edu.fhdw.de" />
@if (fData['email'].hasError('email')) { <mat-error>Ungültige E-Mail-Adresse</mat-error> }
</mat-form-field>
<!-- Checkbox -->
<div class="w-full my-4">
<mat-checkbox required formControlName="accept" class="checkbox-invalid" [class]="{ 'checkbox-invalid': submitted && fData['accept'].hasError('required') }">
Ich akzeptiere die AGB und die Datenbestimmung
</mat-checkbox>
</div>
<!-- Buttons -->
<div class="flex space-x-5 mt-10">
<button type="button" mat-button matButton="outlined" (click)="stepper.reset()" class="w-1/3">Zurück</button>
<button type="submit" mat-button matButton="filled" matStepperNext (click)="stupidCheckboxWorkaround()" class="w-2/3">Sitzplätze reservieren</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="paymentForm">
<form [formGroup]="paymentForm" (ngSubmit)="onSubmit()">
<ng-template matStepLabel>Zahlung</ng-template>
<div class="performance-info-space"></div>
<!-- Card Number -->
<mat-form-field class="w-full mt-8">
<mat-label>Kartennummer</mat-label>
<input
matInput
formControlName="cardNumber"
mask="0000 0000 0000 0000"
placeholder="1111 2222 3333 4444"
/>
@if (fPayment['cardNumber'].hasError('pattern')) { <mat-error>Ungültige Kartennummer</mat-error> }
</mat-form-field>
<!-- Card Name -->
<mat-form-field class="w-full">
<mat-label>Kartenname</mat-label>
<input matInput formControlName="cardName" />
@if (fPayment['cardName'].hasError('minlength')) { <mat-error>Mindestens 3 Zeichen</mat-error> }
</mat-form-field>
<!-- Expiry & CVV -->
<div class="flex space-x-4">
<mat-form-field class="flex-1">
<mat-label>Gültig bis (MM/YY)</mat-label>
<input
matInput
formControlName="expiry"
mask="00/00"
placeholder="MM/YY"
[dropSpecialCharacters]="false"
/>
@if (fPayment['expiry'].hasError('pattern')) { <mat-error>Ungültiges Format</mat-error> }
</mat-form-field>
<mat-form-field class="flex-1">
<mat-label>CVV</mat-label>
<input matInput type="password" maxlength="4" formControlName="cvv" />
@if (fPayment['cvv'].hasError('pattern')) { <mat-error>34 Ziffernt</mat-error> }
</mat-form-field>
</div>
<!-- Info -->
<div class="flex w-full space-x-2 mt-2 items-center">
<mat-icon class="material-symbols-outlined opacity-50" style="font-size: 32px; width: 32px; height: 32px">
encrypted
</mat-icon>
<p class="text-sm opacity-75">
Ihre Zahlung wird sicher über unsere Partner verarbeitet.<br>Wir speichern keine Zahlungsinformationen.
</p>
</div>
<!-- Buttons -->
<div class="flex space-x-4 mt-8">
<button mat-stroked-button color="primary" matStepperPrevious type="button" class="w-1/3">
Zurück
</button>
<button mat-flat-button color="accent" class="w-2/3" matStepperNext type="submit">
{{ getPriceDisplay(totalPrice()) }} jetzt bezahlen
</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>Anschrift</ng-template>
<mat-form-field>
<mat-label>Address</mat-label>
<input
matInput
formControlName="secondCtrl"
placeholder="Ex. 1 Main St, New York, NY"
required
/>
</mat-form-field>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
-
<mat-step>
<ng-template matStepLabel>Zahlung</ng-template>
<p>You are now done.</p>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
</mat-step>
</mat-stepper>
}
</div>

View File

@@ -2,7 +2,8 @@ import { SelectedSeatsService } from './../selected-seats.service';
import { LoadingService } from './../loading.service';
import { Sitzkategorie, Vorstellung } from '@infinimotion/model-frontend';
import { Component, computed, inject, input } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { StepperSelectionEvent } from '@angular/cdk/stepper';
@Component({
selector: 'app-order',
@@ -11,25 +12,59 @@ import { FormBuilder, Validators } from '@angular/forms';
styleUrl: './order.component.css'
})
export class OrderComponent {
paymentForm!: FormGroup;
dataForm!: FormGroup;
submitted = false;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.paymentForm = this.fb.group({
cardNumber: ['', [Validators.required, Validators.pattern(/^\d{16}$/)]],
cardName: ['', [Validators.required, Validators.minLength(3)]],
expiry: ['', [Validators.required, Validators.pattern(/^(0[1-9]|1[0-2])\/\d{2}$/)]],
cvv: ['', [Validators.required, Validators.pattern(/^\d{3,4}$/)]],
});
this.dataForm = this.fb.group({
name: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
accept: ['', Validators.requiredTrue],
});
}
get fData() { return this.dataForm.controls; }
get fPayment() { return this.paymentForm.controls; }
onSubmit() {
if (this.paymentForm.invalid) return;
console.log('Zahlungsdaten:', this.paymentForm.value);
}
onStepChange(event: StepperSelectionEvent) {
this.submitted = false;
}
stupidCheckboxWorkaround() {
this.submitted = true;
}
performance = input<Vorstellung>();
seatCategories = input.required<Sitzkategorie[]>();
private _formBuilder = inject(FormBuilder);
loadingService = inject(LoadingService);
private selectedSeatsService = inject(SelectedSeatsService);
firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required],
});
secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required],
});
totalPrice = computed(() =>
this.selectedSeatsService.getSelectedSeatsList().reduce((sum, seat) => sum + seat.row.category.price, 0)
);
totalSeats = computed(() =>
this.selectedSeatsService.getSelectedSeatsList().length
);
getPriceDisplay(price: number): string {
return `${(price / 100).toFixed(2)}`;
}
}

View File

@@ -11,7 +11,7 @@
<div class="text-md">
<h3 class="opacity-75">{{ getStartTimeString() }} • {{ performance().hall.name }}</h3>
<h1 class="font-semibold mb-1.5">{{ movie().title }}</h1>
<h1 class="font-semibold mb-0.5">{{ movie().title }}</h1>
<div class="flex items-center">
<app-movie-rating [rating]="movie().rating" class="rounded-sm shadow-xs px-1 py-0.25 text-sm"></app-movie-rating>
<app-movie-duration [duration]="movie().duration" [showIcon]="false" class="ml-1.5 opacity-75"></app-movie-duration>

View File

@@ -1,4 +1,4 @@
import { Component, computed, input } from '@angular/core';
import { Component, input } from '@angular/core';
import { Vorstellung } from '@infinimotion/model-frontend';
@Component({

View File

@@ -61,8 +61,8 @@ html.dark {
backdrop-filter: blur(2px);
}
.mat-step-header .mat-step-icon:not(.mat-step-icon-selected):not(.mat-step-icon-completed) {
background-color: #ccc;
.mat-step-header .mat-step-icon:not(.mat-step-icon-selected):not(.mat-step-icon-completed):not(.mat-step-icon-state-edit) {
background-color: #bbb;
color: white;
}