From 7a703350c753e2f2e269734acabe6fa0f63d5a40 Mon Sep 17 00:00:00 2001
From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com>
Date: Sun, 13 Oct 2024 12:38:49 -0500
Subject: [PATCH] feat(webauthn-angular): Add Login form with register form
---
.../authenticator.component.html | 7 +--
.../components/login/login.component.html | 39 +++++++------
.../components/login/login.component.scss | 23 ++++++++
.../home/components/login/login.component.ts | 7 +++
.../register/register.component.html | 58 ++++++++++++-------
.../components/register/register.component.ts | 22 +++++--
.../src/app/pages/home/home.component.ts | 4 +-
.../src/app/services/auth/auth.service.ts | 22 ++++++-
apps/webauthn-angular/src/styles.scss | 8 +--
9 files changed, 131 insertions(+), 59 deletions(-)
diff --git a/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html b/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html
index b9bb8ff..9720c8d 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html
+++ b/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html
@@ -3,9 +3,6 @@
@@ -24,8 +21,8 @@
{{ item.credentialID }}
Public Key
-
- {{ item.credentialPublicKey | bufferToBase64}}
+
+ {{ item.credentialPublicKey | bufferToBase64 }}
diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html
index be341ff..a8b9321 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html
+++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html
@@ -1,19 +1,22 @@
-
-
+
+
+
+
+
+
diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss
index e69de29..77b1266 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss
+++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss
@@ -0,0 +1,23 @@
+.login {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ padding: 1rem;
+
+ &__title {
+ text-align: center;
+ }
+
+ &__form {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ padding: 1rem;
+ }
+
+ &__actions {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
+}
diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts
index 3858998..724511b 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts
+++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts
@@ -36,14 +36,21 @@ export class LoginComponent {
private readonly authService = inject(AuthService);
private readonly snackBar = inject(MatSnackBar);
private readonly formBuilder = inject(FormBuilder);
+ readonly isLoading = this.authService.isLoading;
onLogin = output();
+ onGoBack = output();
loginForm: FormGroup> = this.formBuilder.group({
username: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(255)]],
password: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(128)]]
});
+ goBack() {
+ this.onGoBack.emit();
+ this.loginForm.reset();
+ }
+
login() {
const { username, password } = this.loginForm.getRawValue();
this.authService.login(username, password).subscribe({
diff --git a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html
index 6a7ff72..158a7b5 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html
+++ b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html
@@ -1,26 +1,40 @@
+
+ @if (!hasAccount()) {
+
+ } @else {
+
+ }
+
+
+
+
Sign In
-
-
diff --git a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts
index d8fed4f..7336212 100644
--- a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts
+++ b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts
@@ -1,7 +1,8 @@
import { MAT_FORM_FIELD_CUSTOM } from '@/core/config';
import { TypedFormControls } from '@/core/interface/forms/forms.interface';
import { AuthService } from '@/services/auth';
-import { ChangeDetectionStrategy, Component, inject, output } from '@angular/core';
+import { NgTemplateOutlet } from '@angular/common';
+import { ChangeDetectionStrategy, Component, inject, output, signal } from '@angular/core';
import {
FormBuilder,
FormGroup,
@@ -15,6 +16,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar';
import { RegisterUser } from '@skyzerozx/shared-interfaces';
+import { LoginComponent } from '../login/login.component';
@Component({
selector: 'app-register',
@@ -25,7 +27,9 @@ import { RegisterUser } from '@skyzerozx/shared-interfaces';
MatFormFieldModule,
MatButtonModule,
MatInputModule,
- MatDialogModule
+ MatDialogModule,
+ NgTemplateOutlet,
+ LoginComponent
],
templateUrl: './register.component.html',
styleUrl: './register.component.scss',
@@ -36,8 +40,10 @@ export class RegisterComponent {
private readonly authService = inject(AuthService);
private readonly snackBar = inject(MatSnackBar);
private readonly formBuilder = inject(FormBuilder);
+ readonly isLoading = this.authService.isLoading;
- onRegister = output();
+ onClose = output();
+ hasAccount = signal(false);
registerForm: FormGroup> = this.formBuilder.group({
username: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(255)]],
@@ -46,11 +52,19 @@ export class RegisterComponent {
lastName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(255)]]
});
+ hideLogin() {
+ this.hasAccount.set(false);
+ }
+
+ showLogin() {
+ this.hasAccount.set(true);
+ }
+
register() {
this.authService.register(this.registerForm.getRawValue()).subscribe({
next: () => {
this.snackBar.open('User Registration Success', 'OK');
- this.onRegister.emit();
+ this.onClose.emit();
}
});
}
diff --git a/apps/webauthn-angular/src/app/pages/home/home.component.ts b/apps/webauthn-angular/src/app/pages/home/home.component.ts
index af518ae..134f089 100644
--- a/apps/webauthn-angular/src/app/pages/home/home.component.ts
+++ b/apps/webauthn-angular/src/app/pages/home/home.component.ts
@@ -40,7 +40,7 @@ export class HomeComponent implements OnInit {
switchMap(() => authenticators$),
shareReplay(1)
);
- console.log('Authenticators');
+
return toSignal(refreshAuthenticators$, {
initialValue: []
});
@@ -56,6 +56,6 @@ export class HomeComponent implements OnInit {
disableClose: true
});
- dialogRef.componentRef.instance.onRegister.subscribe(() => dialogRef.close());
+ dialogRef.componentRef.instance.onClose.subscribe(() => dialogRef.close());
}
}
diff --git a/apps/webauthn-angular/src/app/services/auth/auth.service.ts b/apps/webauthn-angular/src/app/services/auth/auth.service.ts
index 3607feb..737fdc4 100644
--- a/apps/webauthn-angular/src/app/services/auth/auth.service.ts
+++ b/apps/webauthn-angular/src/app/services/auth/auth.service.ts
@@ -1,4 +1,4 @@
-import { concatMap, tap } from 'rxjs';
+import { concatMap, finalize, tap } from 'rxjs';
import { jwtDecode } from 'jwt-decode';
import { HttpClient } from '@angular/common/http';
import { inject, Injectable, signal } from '@angular/core';
@@ -19,19 +19,35 @@ import { STORAGE_KEYS } from '../../core/constants';
export class AuthService {
private readonly http = inject(HttpClient);
private readonly userStorage = signal(this.decodeToken());
+ private readonly _isLoading = signal(false);
+
+ get isLoading() {
+ return this._isLoading.asReadonly();
+ }
register(registerUser: RegisterUser) {
+ this._isLoading.set(false);
return this.http
.post>(`${environment.API_URL}/users/register`, registerUser)
- .pipe(concatMap(() => this.login(registerUser.username, registerUser.password)));
+ .pipe(
+ tap(() => this._isLoading.set(true)),
+ concatMap(() => this.login(registerUser.username, registerUser.password)),
+ finalize(() => this._isLoading.set(false))
+ );
}
login(username: string, password: string) {
+ this._isLoading.set(false);
+
return this.http
.post<
ResponseFormat
>(`${environment.API_URL}/auth/login`, { username, password })
- .pipe(tap(({ data }) => this.saveUserStorage(data)));
+ .pipe(
+ tap(() => this._isLoading.set(true)),
+ tap(({ data }) => this.saveUserStorage(data)),
+ finalize(() => this._isLoading.set(false))
+ );
}
saveUserStorage({ token, user }: UserAuthenticated) {
diff --git a/apps/webauthn-angular/src/styles.scss b/apps/webauthn-angular/src/styles.scss
index 3cdf21d..5bd7fda 100644
--- a/apps/webauthn-angular/src/styles.scss
+++ b/apps/webauthn-angular/src/styles.scss
@@ -11,18 +11,16 @@ body {
.register-dialog-container {
width: 600px;
- height: 600px;
+
@media (width <= 600px) {
width: 400px;
- height: 550px;
}
}
.json-viewer-dialog-container {
- width: 600px;
- height: 560px;
+ width: 900px;
+
@media (width <= 600px) {
width: 400px;
- height: 530px;
}
}