feat(auth): add login and registration modal functionality
This commit is contained in:
parent
5bbfa5994e
commit
0079ee7bf2
11 changed files with 212 additions and 55 deletions
|
@ -1,5 +1,16 @@
|
|||
<div class="min-h-screen bg-deep-blue flex items-center justify-center">
|
||||
<div class="modal-card max-w-md w-full">
|
||||
<div class="modal-card max-w-md w-full bg-deep-blue rounded-lg shadow-xl p-6 relative">
|
||||
<!-- Close Button -->
|
||||
<button
|
||||
(click)="closeDialog.emit()"
|
||||
class="absolute top-4 right-4 text-text-secondary hover:text-white transition-colors"
|
||||
aria-label="Dialog schließen"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h2 class="modal-heading text-center">Anmelden</h2>
|
||||
|
||||
@if (errorMessage()) {
|
||||
|
@ -65,12 +76,12 @@
|
|||
<div class="mt-6 text-center">
|
||||
<p class="text-sm text-text-secondary">
|
||||
Noch kein Konto?
|
||||
<a
|
||||
routerLink="/register"
|
||||
<button
|
||||
(click)="switchToRegister()"
|
||||
class="font-medium text-emerald hover:text-emerald-light transition-all duration-200"
|
||||
>
|
||||
Registrieren
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, signal } from '@angular/core';
|
||||
import { Component, EventEmitter, Output, signal } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { LoginRequest } from '../../../model/auth/LoginRequest';
|
||||
import { AuthService } from '@service/auth.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
@ -8,13 +8,15 @@ import { CommonModule } from '@angular/common';
|
|||
@Component({
|
||||
selector: 'app-login',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, RouterLink],
|
||||
imports: [CommonModule, ReactiveFormsModule],
|
||||
templateUrl: './login.component.html',
|
||||
})
|
||||
export class LoginComponent {
|
||||
loginForm: FormGroup;
|
||||
errorMessage = signal('');
|
||||
isLoading = signal(false);
|
||||
@Output() switchForm = new EventEmitter<void>();
|
||||
@Output() closeDialog = new EventEmitter<void>();
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
|
@ -31,6 +33,10 @@ export class LoginComponent {
|
|||
return this.loginForm.controls;
|
||||
}
|
||||
|
||||
switchToRegister(): void {
|
||||
this.switchForm.emit();
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.loginForm.invalid) {
|
||||
return;
|
||||
|
@ -46,6 +52,7 @@ export class LoginComponent {
|
|||
|
||||
this.authService.login(loginRequest).subscribe({
|
||||
next: () => {
|
||||
this.closeDialog.emit();
|
||||
this.router.navigate(['/home']);
|
||||
},
|
||||
error: (err) => {
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<div class="min-h-screen bg-deep-blue flex items-center justify-center">
|
||||
<div class="modal-card max-w-md w-full">
|
||||
<div class="modal-card max-w-md w-full bg-deep-blue rounded-lg shadow-xl p-6 relative">
|
||||
<!-- Close Button -->
|
||||
<button
|
||||
(click)="closeDialog.emit()"
|
||||
class="absolute top-4 right-4 text-text-secondary hover:text-white transition-colors"
|
||||
aria-label="Dialog schließen"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h2 class="modal-heading text-center">Konto erstellen</h2>
|
||||
|
||||
@if (errorMessage()) {
|
||||
|
@ -107,12 +118,12 @@
|
|||
<div class="mt-6 text-center">
|
||||
<p class="text-sm text-text-secondary">
|
||||
Bereits ein Konto?
|
||||
<a
|
||||
routerLink="/login"
|
||||
<button
|
||||
(click)="switchToLogin()"
|
||||
class="font-medium text-emerald hover:text-emerald-light transition-all duration-200"
|
||||
>
|
||||
Anmelden
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, signal } from '@angular/core';
|
||||
import { Component, EventEmitter, Output, signal } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { RegisterRequest } from '../../../model/auth/RegisterRequest';
|
||||
import { AuthService } from '@service/auth.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
@ -9,7 +9,7 @@ import { HttpErrorResponse } from '@angular/common/http';
|
|||
@Component({
|
||||
selector: 'app-register',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, RouterLink],
|
||||
imports: [CommonModule, ReactiveFormsModule],
|
||||
templateUrl: './register.component.html',
|
||||
})
|
||||
export class RegisterComponent {
|
||||
|
@ -17,6 +17,8 @@ export class RegisterComponent {
|
|||
errorMessage = signal<string>('');
|
||||
isLoading = signal<boolean>(false);
|
||||
fieldErrors = signal<Record<string, string>>({});
|
||||
@Output() switchForm = new EventEmitter<void>();
|
||||
@Output() closeDialog = new EventEmitter<void>();
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
|
@ -34,6 +36,10 @@ export class RegisterComponent {
|
|||
return this.registerForm.controls;
|
||||
}
|
||||
|
||||
switchToLogin(): void {
|
||||
this.switchForm.emit();
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.registerForm.invalid) {
|
||||
return;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="min-h-screen bg-deep-blue text-text-primary">
|
||||
<div class="min-h-screen bg-deep-blue text-text-primary relative">
|
||||
<div class="container mx-auto px-4 py-8 sm:py-12">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="text-center mb-12 sm:mb-16">
|
||||
|
@ -17,18 +17,18 @@
|
|||
Spiele
|
||||
</a>
|
||||
} @else {
|
||||
<a
|
||||
routerLink="/register"
|
||||
<button
|
||||
(click)="showRegisterForm()"
|
||||
class="w-full sm:w-auto button-primary px-6 sm:px-8 py-3 shadow-lg"
|
||||
>
|
||||
Konto erstellen
|
||||
</a>
|
||||
<a
|
||||
routerLink="/login"
|
||||
</button>
|
||||
<button
|
||||
(click)="showLoginForm()"
|
||||
class="w-full sm:w-auto bg-slate-700 text-white hover:bg-slate-600 px-6 sm:px-8 py-3 shadow-lg rounded"
|
||||
>
|
||||
Anmelden
|
||||
</a>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -120,8 +120,8 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -136,8 +136,8 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -181,4 +181,39 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auth Forms Overlay -->
|
||||
@if (showLogin() || showRegister()) {
|
||||
<div
|
||||
class="fixed inset-0 bg-black/50 z-40"
|
||||
(click)="hideAuthForms()"
|
||||
(keydown.enter)="hideAuthForms()"
|
||||
tabindex="0"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
></div>
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center z-50 p-4"
|
||||
role="presentation"
|
||||
>
|
||||
<div
|
||||
class="relative"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
@if (showLogin()) {
|
||||
<app-login
|
||||
(switchForm)="showRegisterForm()"
|
||||
(closeDialog)="hideAuthForms()"
|
||||
></app-login>
|
||||
}
|
||||
@if (showRegister()) {
|
||||
<app-register
|
||||
(switchForm)="showLoginForm()"
|
||||
(closeDialog)="hideAuthForms()"
|
||||
></app-register>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { AuthService } from '@service/auth.service';
|
||||
import { LoginComponent } from '../auth/login/login.component';
|
||||
import { RegisterComponent } from '../auth/register/register.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-landing-page',
|
||||
standalone: true,
|
||||
imports: [NgFor, RouterLink],
|
||||
imports: [NgFor, RouterLink, LoginComponent, RegisterComponent],
|
||||
templateUrl: './landing.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
|
@ -14,13 +16,35 @@ export class LandingComponent implements OnInit, OnDestroy {
|
|||
currentSlide = 0;
|
||||
private autoplayInterval: ReturnType<typeof setInterval> | undefined;
|
||||
authService: AuthService = inject(AuthService);
|
||||
showLogin = signal(false);
|
||||
showRegister = signal(false);
|
||||
|
||||
ngOnInit() {
|
||||
this.startAutoplay();
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.stopAutoplay();
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
showLoginForm() {
|
||||
this.showLogin.set(true);
|
||||
this.showRegister.set(false);
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
showRegisterForm() {
|
||||
this.showRegister.set(true);
|
||||
this.showLogin.set(false);
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
hideAuthForms() {
|
||||
this.showLogin.set(false);
|
||||
this.showRegister.set(false);
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
prevSlide() {
|
||||
|
|
Reference in a new issue