You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.1 KiB
144 lines
4.1 KiB
import { Component, inject, signal } from "@angular/core";
|
|
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
|
|
import { Router, RouterLink } from "@angular/router";
|
|
import { MATERIAL } from "../shared/material";
|
|
import { ApiService } from "../core/api.service";
|
|
@Component({
|
|
standalone: true,
|
|
imports: [ReactiveFormsModule, RouterLink, ...MATERIAL],
|
|
template: `<main class="login">
|
|
<mat-card
|
|
><mat-card-content
|
|
><div class="logo">A</div>
|
|
<h1>Willkommen zurück</h1>
|
|
<p class="muted">Ausbildungsstunden übersichtlich dokumentieren.</p>
|
|
<form [formGroup]="form" (ngSubmit)="submit()">
|
|
<mat-form-field appearance="outline" class="full"
|
|
><mat-label>E-Mail</mat-label
|
|
><input
|
|
matInput
|
|
type="email"
|
|
formControlName="email"
|
|
autocomplete="email"
|
|
/><mat-icon matSuffix>mail</mat-icon><mat-hint></mat-hint></mat-form-field
|
|
><mat-form-field appearance="outline" class="full"
|
|
><mat-label>Passwort</mat-label
|
|
><input
|
|
matInput
|
|
type="password"
|
|
formControlName="password"
|
|
autocomplete="current-password"
|
|
/><mat-icon matSuffix>lock</mat-icon><mat-hint></mat-hint></mat-form-field
|
|
>
|
|
@if (error()) {
|
|
<p class="error">{{ error() }}</p>
|
|
}
|
|
<button
|
|
mat-flat-button
|
|
class="full"
|
|
[disabled]="form.invalid || loading()"
|
|
>
|
|
@if (loading()) {
|
|
<mat-spinner diameter="20" />
|
|
} @else {
|
|
Anmelden
|
|
}
|
|
</button>
|
|
<div class="auth-links">
|
|
<a routerLink="/forgot-password">Passwort vergessen?</a>
|
|
<a routerLink="/register">Konto registrieren</a>
|
|
</div>
|
|
<div class="legal"><a routerLink="/resend-confirmation">Bestätigungslink erneut senden</a></div>
|
|
<div class="legal"><a routerLink="/impressum">Impressum</a></div>
|
|
</form></mat-card-content
|
|
></mat-card
|
|
>
|
|
</main>`,
|
|
styles: [
|
|
`
|
|
.login {
|
|
min-height: 100%;
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 20px;
|
|
background:
|
|
radial-gradient(circle at top left, #d9e9ff, transparent 45%), #f5f7fb;
|
|
}
|
|
.login mat-card {
|
|
width: min(430px, 100%);
|
|
padding: 24px;
|
|
border-radius: 24px !important;
|
|
}
|
|
.logo {
|
|
width: 54px;
|
|
height: 54px;
|
|
border-radius: 16px;
|
|
display: grid;
|
|
place-items: center;
|
|
background: #155bd7;
|
|
color: #fff;
|
|
font-size: 25px;
|
|
font-weight: 800;
|
|
}
|
|
h1 {
|
|
margin: 22px 0 6px;
|
|
}
|
|
.full {
|
|
margin-top: 10px;
|
|
}
|
|
.error {
|
|
color: #b3261e;
|
|
}
|
|
button.full {
|
|
height: 48px;
|
|
}
|
|
.auth-links {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-top: 20px;
|
|
}
|
|
.auth-links a {
|
|
color: #155bd7;
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
.legal {
|
|
text-align: center;
|
|
margin-top: 18px;
|
|
}
|
|
.legal a {
|
|
color: #687287;
|
|
text-decoration: none;
|
|
font-size: 13px;
|
|
}
|
|
`,
|
|
],
|
|
})
|
|
export class LoginComponent {
|
|
private readonly fb = inject(FormBuilder);
|
|
readonly loading = signal(false);
|
|
readonly error = signal("");
|
|
readonly form = this.fb.nonNullable.group({
|
|
email: ["", [Validators.required, Validators.email]],
|
|
password: ["", Validators.required],
|
|
});
|
|
constructor(
|
|
private api: ApiService,
|
|
private router: Router,
|
|
) {}
|
|
submit() {
|
|
if (this.form.invalid) return;
|
|
this.loading.set(true);
|
|
this.error.set("");
|
|
this.api
|
|
.login(this.form.value.email!, this.form.value.password!)
|
|
.subscribe({
|
|
next: () => this.router.navigate(["/dashboard"]),
|
|
error: (e) => {
|
|
this.loading.set(false);
|
|
this.error.set(e.error?.error || "Anmeldung fehlgeschlagen");
|
|
},
|
|
});
|
|
}
|
|
}
|