From fb9037bfcfebb54587bf81a0eacf2c44304c848f Mon Sep 17 00:00:00 2001
From: "thibault.capt" <thibault.capt@etu.hesge.ch>
Date: Wed, 19 Feb 2025 16:56:35 +0100
Subject: [PATCH] (feat): delete a todo

---
 .../frontend/src/app/app.component.ts         | 16 +++++----
 todo-workspace/frontend/src/app/app.config.ts |  7 ++--
 .../core/adapters/in-memory-todo.service.ts   | 18 +++++++++-
 .../app/core/models/builder/todo.builder.ts   | 35 +++++++++++++++++++
 .../src/app/core/ports/todo.service.ts        |  2 ++
 .../todo-list/todo-list.component.html        |  5 ++-
 .../features/todo-list/todo-list.component.ts | 18 +++++++++-
 .../frontend/src/app/shared/fa-icons.ts       |  4 +++
 8 files changed, 93 insertions(+), 12 deletions(-)
 create mode 100644 todo-workspace/frontend/src/app/core/models/builder/todo.builder.ts
 create mode 100644 todo-workspace/frontend/src/app/shared/fa-icons.ts

diff --git a/todo-workspace/frontend/src/app/app.component.ts b/todo-workspace/frontend/src/app/app.component.ts
index 1c3a486..131bd9e 100644
--- a/todo-workspace/frontend/src/app/app.component.ts
+++ b/todo-workspace/frontend/src/app/app.component.ts
@@ -1,12 +1,16 @@
-import { Component } from '@angular/core';
-import {TodoListComponent} from "@features/todo-list/todo-list.component";
+import { Component, inject } from '@angular/core';
+import { TodoListComponent } from '@features/todo-list/todo-list.component';
+import { FaIconLibrary } from '@fortawesome/angular-fontawesome';
+import { faIcons } from '@shared/fa-icons';
 
 @Component({
   selector: 'app-root',
-  imports: [
-    TodoListComponent
-  ],
+  imports: [TodoListComponent],
   templateUrl: './app.component.html',
   styleUrl: './app.component.scss',
 })
-export class AppComponent {}
+export class AppComponent {
+  constructor() {
+    inject(FaIconLibrary).addIcons(...faIcons);
+  }
+}
diff --git a/todo-workspace/frontend/src/app/app.config.ts b/todo-workspace/frontend/src/app/app.config.ts
index 4735ffe..7a84a42 100644
--- a/todo-workspace/frontend/src/app/app.config.ts
+++ b/todo-workspace/frontend/src/app/app.config.ts
@@ -5,6 +5,7 @@ import { routes } from './app.routes';
 import { provideHttpClient } from '@angular/common/http';
 import { TodoService } from '@core/ports/todo.service';
 import { InMemoryTodoService } from '@core/adapters/in-memory-todo.service';
+import { TodoBuilder } from '@core/models/builder/todo.builder';
 
 export const appConfig: ApplicationConfig = {
   providers: [
@@ -15,9 +16,9 @@ export const appConfig: ApplicationConfig = {
       provide: TodoService,
       useFactory: () =>
         new InMemoryTodoService().withTodos([
-          { id: 1, name: 'Apprendre Angular 19', completed: false },
-          { id: 1, name: 'Apprendre Java Spring Boot', completed: true },
-          { id: 1, name: 'Apprendre PostgreSQL', completed: false },
+          new TodoBuilder().withId(1).withName('Apprendre Angular 19').uncomplete().build(),
+          new TodoBuilder().withId(2).withName('Apprendre Java Spring Boot').complete().build(),
+          new TodoBuilder().withId(3).withName('Apprendre PostgreSQL').uncomplete().build(),
         ]),
     },
   ],
diff --git a/todo-workspace/frontend/src/app/core/adapters/in-memory-todo.service.ts b/todo-workspace/frontend/src/app/core/adapters/in-memory-todo.service.ts
index fe8fe48..a81b057 100644
--- a/todo-workspace/frontend/src/app/core/adapters/in-memory-todo.service.ts
+++ b/todo-workspace/frontend/src/app/core/adapters/in-memory-todo.service.ts
@@ -1,6 +1,7 @@
 import { Observable, of } from 'rxjs';
 import { TodoService } from '@core/ports/todo.service';
 import { Todo, Todos } from '@core/models/todo';
+import { TodoBuilder } from '@core/models/builder/todo.builder';
 
 export class InMemoryTodoService extends TodoService {
   private todos: Todos = [];
@@ -15,8 +16,23 @@ export class InMemoryTodoService extends TodoService {
   }
 
   override add(todoName: string): Observable<Todo> {
-    const todo: Todo = { id: this.todos.length + 1, name: todoName, completed: false };
+    const todo: Todo = new TodoBuilder()
+      .withId(this.todos.length + 1)
+      .withName(todoName)
+      .uncomplete()
+      .build();
     this.todos = [...this.todos, todo];
     return of(todo);
   }
+
+  override toggleCompleted(todoId: number): Observable<Todo> {
+    const todo = this.todos.find((todo) => todo.id === todoId)!;
+    todo.completed = !todo.completed;
+    return of(todo);
+  }
+
+  override remove(todoId: number): Observable<void> {
+    this.todos = this.todos.filter((todo) => todo.id !== todoId);
+    return of(void 0);
+  }
 }
diff --git a/todo-workspace/frontend/src/app/core/models/builder/todo.builder.ts b/todo-workspace/frontend/src/app/core/models/builder/todo.builder.ts
new file mode 100644
index 0000000..2a7a6e1
--- /dev/null
+++ b/todo-workspace/frontend/src/app/core/models/builder/todo.builder.ts
@@ -0,0 +1,35 @@
+import { Todo } from '@core/models/todo';
+
+export class TodoBuilder {
+  protected id!: number;
+  protected name!: string;
+  protected completed!: boolean;
+
+  withId(id: number): this {
+    this.id = id;
+    return this;
+  }
+
+  withName(name: string): this {
+    this.name = name;
+    return this;
+  }
+
+  complete(): this {
+    this.completed = true;
+    return this;
+  }
+
+  uncomplete(): this {
+    this.completed = false;
+    return this;
+  }
+
+  build(): Todo {
+    return {
+      id: this.id,
+      name: this.name,
+      completed: this.completed,
+    };
+  }
+}
diff --git a/todo-workspace/frontend/src/app/core/ports/todo.service.ts b/todo-workspace/frontend/src/app/core/ports/todo.service.ts
index 7663e92..ffae5f1 100644
--- a/todo-workspace/frontend/src/app/core/ports/todo.service.ts
+++ b/todo-workspace/frontend/src/app/core/ports/todo.service.ts
@@ -4,4 +4,6 @@ import { Todo, Todos } from '@core/models/todo';
 export abstract class TodoService {
   abstract getAll(): Observable<Todos>;
   abstract add(todoName: string): Observable<Todo>;
+  abstract toggleCompleted(todoId: number): Observable<Todo>;
+  abstract remove(todoId: number): Observable<void>;
 }
diff --git a/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.html b/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.html
index 96cb86c..a9933ea 100644
--- a/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.html
+++ b/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.html
@@ -23,8 +23,11 @@
           @for (todo of todos(); track todo.id) {
             <li class="py-2 w-full">
               <label class="fieldset-label">
-                <input type="checkbox" [checked]="todo.completed" class="checkbox" />
+                <input type="checkbox" [checked]="todo.completed" class="checkbox" (change)="toggleCompleted(todo)" />
                 <span [ngClass]="{ 'line-through': todo.completed }">{{ todo.name }}</span>
+                <button class="btn btn-ghost btn-error" (click)="remove(todo)">
+                  <fa-icon [icon]="['fas', 'trash']"></fa-icon>
+                </button>
               </label>
             </li>
           }
diff --git a/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.ts b/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.ts
index d757965..e77a171 100644
--- a/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.ts
+++ b/todo-workspace/frontend/src/app/features/todo-list/todo-list.component.ts
@@ -4,10 +4,12 @@ import { toSignal } from '@angular/core/rxjs-interop';
 import { NgClass } from '@angular/common';
 import { BehaviorSubject, switchMap, tap } from 'rxjs';
 import { FormsModule } from '@angular/forms';
+import { Todo } from '@core/models/todo';
+import { FaIconComponent } from '@fortawesome/angular-fontawesome';
 
 @Component({
   selector: 'app-todo-list',
-  imports: [NgClass, FormsModule],
+  imports: [NgClass, FormsModule, FaIconComponent],
   templateUrl: './todo-list.component.html',
   styleUrl: './todo-list.component.scss',
 })
@@ -28,4 +30,18 @@ export class TodoListComponent {
       .pipe(tap(() => this.reload$$.next()))
       .subscribe();
   }
+
+  toggleCompleted(todo: Todo) {
+    this.todoService
+      .toggleCompleted(todo.id)
+      .pipe(tap(() => this.reload$$.next()))
+      .subscribe();
+  }
+
+  remove(todo: Todo) {
+    this.todoService
+      .remove(todo.id)
+      .pipe(tap(() => this.reload$$.next()))
+      .subscribe();
+  }
 }
diff --git a/todo-workspace/frontend/src/app/shared/fa-icons.ts b/todo-workspace/frontend/src/app/shared/fa-icons.ts
new file mode 100644
index 0000000..a4bf0df
--- /dev/null
+++ b/todo-workspace/frontend/src/app/shared/fa-icons.ts
@@ -0,0 +1,4 @@
+import { IconDefinition } from '@fortawesome/angular-fontawesome';
+import { faTrash } from '@fortawesome/free-solid-svg-icons';
+
+export const faIcons: IconDefinition[] = [faTrash];
-- 
GitLab