So let me give a brief explanation of the mini-application I've designed using Angular :
A simple login page that requires user email and password as credentials. Once logged in, the user is moved to a page where a list of tasks is displayed in the form of individual boxes .
This code review is not focused on CSS, but on functionality so please can you focus on providing feedback on the following:
- authenticate() method (return value and code logic)
- login() method (code logic and debugging)
- task service (Correctness of object used and correctness of logic and best practices)
login component.html:
<form [formGroup]="loginForm" (ngSubmit)="login()">
<label>Email:</label>
<input type="email" formControlName="email">
<label>Password:</label>
<input type="text" formControlName="password">
<button>Login</button>
</form>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
authentication.service:
// src/app/auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private baseUrl= 'http://localhost:8080/api/v1/auth';
constructor(private http: HttpClient) {}
authenticate(credentials: {email: string, password: string}) : Observable<HttpResponse<any>> {
const apiUrl = `${this.baseUrl}/authenticate` ;
return this.http.post<any>(apiUrl, credentials, {observe: 'response'}) ;
}
}
login.component.ts :
// src/app/login/login.component.ts
import { Component } from '@angular/core';
import { AuthenticationService } from '../authentication/authentication.service';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { HttpResponse } from '@angular/common/http';
import { Router } from '@angular/router';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css', '../bootstrap-5.3.3-dist/css/bootstrap-grid.css'],
imports: [FormsModule, ReactiveFormsModule, RouterOutlet],
standalone: true
})
export class LoginComponent {
loginForm = new FormGroup ({
email: new FormControl<string>('', [Validators.required, Validators.email]),
password: new FormControl<string>('', Validators.required)
})
constructor(private authenticationService: AuthenticationService, private router: Router) {}
getEmail(): string {
return this.loginForm.get('email')?.value || '' ;
}
getPassword(){
return this.loginForm.get('password')?.value || '' ;
}
login() {
if (this.loginForm.invalid) {
return ;
}
const email: string = this.getEmail();
const password: string = this.getPassword();
this.authenticationService.authenticate({ email, password }).subscribe(
(response: HttpResponse<any>) => {
console.log('Response:', response);
if (response.status === 200) {
console.log('Navigation triggered');
const token = response.body.token ;
localStorage.setItem('token', token);
this.router.navigate(['/tasksForm']).then(
success => {
console.log(success);
if (!success) {
console.error('Navigation failed');
}
}
);
} else {
console.error('Error:', response.body);
}
},
error => {
console.error("Err:", error) ;
}
);
}
// login() {
// this.router.navigate(['/tasksForm']);
// }
tasks.component.html
<div class="task-container">
@for(task of tasks ; track task) {
<div class="task-box">
<h3>{{ task.description }}</h3>
<p><strong>ID:</strong> {{ task.ID }}</p>
<p><strong>Executor ID:</strong> {{ task.executorID }}</p>
<p><strong>Completed:</strong> {{ task.completed ? 'Yes' : 'No' }}</p>
<p><strong>Deadline:</strong> {{ task.deadline | date }}</p>
</div>
}
</div>
task.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Task } from '../models/Models.model';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TaskService {
baseUrl : string = "http://localhost:8080/Task"
constructor(private http : HttpClient) { }
get getTasks() : Observable<Task[]> {
const apiUrl = this.baseUrl ;
const token = localStorage.getItem('token');
const headers = {
'Authorization' : `Bearer ${token}`,
'cors':'no-cors'
}
return this.http.get<Task[]>(apiUrl, {headers})
}
}
app.routes.ts :
import { Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { TasksComponent } from './tasks/tasks.component';
export const routes: Routes = [
{path: '', component: LoginComponent },
{path: 'tasksForm', component: TasksComponent},
{path: '**', redirectTo: '' }
];
models :
export interface Task {
ID: Number ;
description : string ;
completed : boolean ;
executorID : Number ;
deadline : Date ;
}
export interface User {
firstname : string ;
lastname : string ;
email : string ;
password : string ;
}