Skip to content

Commit

Permalink
Merge pull request #57 from Kleostro/feat/tu-01-06/user-authentification
Browse files Browse the repository at this point in the history
feat(tu-01-06): user authentification
  • Loading branch information
katyastan authored Aug 18, 2024
2 parents 8941b10 + c7149cc commit 0e51d07
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { HttpClientModule } from '@angular/common/http';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';

import { LogoutService } from '@/app/api/logoutService/logout.service';

import { AdminLayoutComponent } from './admin-layout.component';

describe('AdminLayoutComponent', () => {
Expand All @@ -9,8 +12,8 @@ describe('AdminLayoutComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AdminLayoutComponent],
providers: [{ provide: ActivatedRoute, useValue: {} }],
imports: [AdminLayoutComponent, HttpClientModule],
providers: [{ provide: ActivatedRoute, useValue: {} }, LogoutService],
}).compileComponents();

fixture = TestBed.createComponent(AdminLayoutComponent);
Expand Down
17 changes: 17 additions & 0 deletions src/app/api/logoutService/logout.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';

import { Observable } from 'rxjs';

import { LogoutResponse } from '../models/logoutResponse';

@Injectable({
providedIn: 'root',
})
export class LogoutService {
private httpClient = inject(HttpClient);

public logout(): Observable<LogoutResponse> {
return this.httpClient.delete<LogoutResponse>('logout');
}
}
1 change: 1 addition & 0 deletions src/app/api/models/logoutResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export interface LogoutResponse {}
5 changes: 5 additions & 0 deletions src/app/auth/components/logout/logout.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- @if (!isLoggedIn) { -->
<p-button text title="Log Out" (click)="logout()">
<span class="pi pi-sign-out"></span>
</p-button>
<!-- } -->
1 change: 1 addition & 0 deletions src/app/auth/components/logout/logout.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'variables';
36 changes: 36 additions & 0 deletions src/app/auth/components/logout/logout.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { Router, RouterLink } from '@angular/router';

import { ButtonModule } from 'primeng/button';
import { firstValueFrom } from 'rxjs';

import { LogoutService } from '@/app/api/logoutService/logout.service';

import { NavigationComponent } from '../../../core/components/navigation/navigation.component';
import { LocalStorageService } from '../../../core/services/local-storage/local-storage.service';

@Component({
selector: 'app-logout',
standalone: true,
imports: [ButtonModule, NavigationComponent, RouterLink],

templateUrl: './logout.component.html',
styleUrl: './logout.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LogoutComponent {
public localStorageService = inject(LocalStorageService);
private logoutService: LogoutService = inject(LogoutService);
private router = inject(Router);

public logout(): void {
firstValueFrom(this.logoutService.logout())
.then(() => {
this.localStorageService.clear();
this.router.navigate(['/sign-in']);
})
.catch(() => {
// TBD: handle error
});
}
}
47 changes: 46 additions & 1 deletion src/app/auth/pages/login/login.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
<p>login works!</p>
<section class="login-container">
<form class="login-form" [formGroup]="loginForm" (ngSubmit)="submitForm()">
<h2 class="login-title">Sign In</h2>

<div class="login-form-item">
<label for="email" class="login-label">Email</label>
<div class="login-field">
<input
id="email"
type="email"
pInputText
formControlName="email"
placeholder="Enter your email"
class="login-input p-inputtext"
/>
@if (loginForm.get('email')?.invalid && loginForm.get('email')?.touched) {
@if (loginForm.get('email')?.errors?.['required']) {
<small class="p-error">Please input your email!</small>
}
}
</div>
</div>
<div class="login-form-item">
<label for="password" class="login-label">Password</label>
<div class="login-field">
<input
id="password"
type="password"
pInputText
formControlName="password"
placeholder="Enter your password"
class="login-input p-inputtext"
/>
@if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {
@if (loginForm.get('password')?.errors?.['required']) {
<small class="p-error">Please input your password!</small>
}
}
</div>
</div>
<div class="login-button-container">
<p-button type="submit" label="Sign in" [disabled]="!loginForm.valid" class="p-mt-2"></p-button>
<p-link pButton routerLink="/sign-up" label="Sign Up" class="p-button-text p-mt-2"></p-link>
</div>
</form>
</section>
25 changes: 25 additions & 0 deletions src/app/auth/pages/login/login.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.login-container {
display: flex;
justify-content: center;
height: 100%;
}

.login-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

width: 30rem;
height: auto;
margin: auto;
padding: 2rem;

background-color: rgb(199 199 199 / 14%);
box-shadow: 0 0 10px 0 rgb(0 0 0 / 30%);

.login-title {
margin-bottom: 1rem;
font-weight: 700;
}
}
22 changes: 0 additions & 22 deletions src/app/auth/pages/login/login.component.spec.ts

This file was deleted.

60 changes: 57 additions & 3 deletions src/app/auth/pages/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,65 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router, RouterLink } from '@angular/router';

import { ButtonModule } from 'primeng/button';
import { InputTextModule } from 'primeng/inputtext';
import { PasswordModule } from 'primeng/password';
import { firstValueFrom } from 'rxjs';

import { OverriddenHttpErrorResponse } from '@/app/api/models/errorResponse';
import { SignInResponse } from '@/app/api/models/signInResponse';
import { User } from '@/app/api/models/user';
import { SignInService } from '@/app/api/signInService/sign-in.service';
import { LocalStorageService } from '@/app/core/services/local-storage/local-storage.service';

@Component({
selector: 'app-login',
standalone: true,
imports: [],
imports: [CommonModule, ReactiveFormsModule, InputTextModule, ButtonModule, PasswordModule, RouterLink],
templateUrl: './login.component.html',
styleUrl: './login.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginComponent {}
export class LoginComponent {
private signInService = inject(SignInService);
private localStorageService = inject(LocalStorageService);
private router = inject(Router);
private fb = inject(FormBuilder);

public loginForm = this.fb.group({
email: this.fb.control<string>('', [Validators.required.bind(this), Validators.email.bind(this)]),
password: this.fb.control<string>('', [Validators.required.bind(this)]),
});

public submitForm(): void {
if (this.loginForm.valid) {
firstValueFrom(this.signInService.signIn(this.userData))
.then((data: SignInResponse) => {
this.localStorageService.addValueByKey('email', this.userData.email);
this.localStorageService.addValueByKey('token', data.token);
this.router.navigate(['/']);
})
.catch((err: OverriddenHttpErrorResponse) => {
this.loginForm.setErrors({ [err.error.reason]: true });
});
} else {
Object.values(this.loginForm.controls).forEach((control) => {
if (control.invalid) {
control.markAsTouched();
control.updateValueAndValidity({
onlySelf: true,
});
}
});
}
}

private get userData(): User {
return {
email: this.loginForm.controls.email.value || '',
password: this.loginForm.controls.password.value || '',
};
}
}
2 changes: 0 additions & 2 deletions src/app/auth/pages/register/register.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,9 @@ describe('RegisterComponent', () => {
passwordControl.setValue('password123');
confirmControl.setValue('password1234');
fixture.detectChanges();
// eslint-disable-next-line dot-notation
expect(component.registrationForm.errors?.['passwordMismatch']).toBeTruthy();
confirmControl.setValue('password123');
fixture.detectChanges();
// eslint-disable-next-line dot-notation
expect(component.registrationForm.errors?.['passwordMismatch']).toBeUndefined();
});

Expand Down
1 change: 1 addition & 0 deletions src/app/core/components/header/header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<p-button icon="pi pi-home" size="large" routerLink="/" text class="link-back" />

<app-navigation></app-navigation>
<app-logout></app-logout>
</header>
</div>
3 changes: 2 additions & 1 deletion src/app/core/components/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { RouterLink } from '@angular/router';

import { ButtonModule } from 'primeng/button';

import { LogoutComponent } from '../../../auth/components/logout/logout.component';
import { LocalStorageService } from '../../services/local-storage/local-storage.service';
import { NavigationComponent } from '../navigation/navigation.component';

@Component({
selector: 'app-header',
standalone: true,
imports: [ButtonModule, NavigationComponent, RouterLink],
imports: [ButtonModule, NavigationComponent, RouterLink, LogoutComponent],

templateUrl: './header.component.html',
styleUrl: './header.component.scss',
Expand Down

0 comments on commit 0e51d07

Please sign in to comment.