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 ;
}