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