From 1c745de58a0e7d38a4b74ea4b8bdbc66bdf9ff5c Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Wed, 7 Aug 2024 20:47:38 +0200 Subject: [PATCH 01/17] feat: add drag drop module --- src/app/app.config.ts | 2 ++ .../components/kanban/kanban.component.html | 2 ++ .../components/kanban/kanban.component.scss | 24 +++++++++++++++++++ src/app/components/kanban/kanban.component.ts | 9 ++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 9ede28a..8e58c7d 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -15,6 +15,7 @@ import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { DragDropModule } from '@angular/cdk/drag-drop'; console.info('Angular CDK version', CDK_VERSION.full); console.info('Angular Material version', MAT_VERSION.full); @@ -24,6 +25,7 @@ export const appConfig: ApplicationConfig = { provideAnimations(), provideRouter(routes), importProvidersFrom( + DragDropModule, BrowserModule, MatSidenavModule, MatToolbarModule, diff --git a/src/app/components/kanban/kanban.component.html b/src/app/components/kanban/kanban.component.html index bac2c12..4885ee5 100644 --- a/src/app/components/kanban/kanban.component.html +++ b/src/app/components/kanban/kanban.component.html @@ -1 +1,3 @@

kanban works!

+ +
diff --git a/src/app/components/kanban/kanban.component.scss b/src/app/components/kanban/kanban.component.scss index e69de29..37bf82b 100644 --- a/src/app/components/kanban/kanban.component.scss +++ b/src/app/components/kanban/kanban.component.scss @@ -0,0 +1,24 @@ +:host { + #item { + width: 15em; + height: 15em; + cursor: move; + background-color: dodgerblue; + border: 1px solid darkblue; + border-radius: 5%; + box-shadow: + 0 3px 1px -2px rgba(0, 0, 0, 0.2), + 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 1px 5px 0 rgba(0, 0, 0, 0.12); + + &:active { + background-color: tomato; + border-color: darkred; + + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); + } + } +} diff --git a/src/app/components/kanban/kanban.component.ts b/src/app/components/kanban/kanban.component.ts index 171e5a0..40debb0 100644 --- a/src/app/components/kanban/kanban.component.ts +++ b/src/app/components/kanban/kanban.component.ts @@ -1,12 +1,11 @@ +import { CdkDrag } from '@angular/cdk/drag-drop'; import { Component } from '@angular/core'; @Component({ selector: 'app-kanban', standalone: true, - imports: [], + imports: [CdkDrag], templateUrl: './kanban.component.html', - styleUrl: './kanban.component.scss' + styleUrl: './kanban.component.scss', }) -export class KanbanComponent { - -} +export class KanbanComponent {} From 0728c38f2c28d12cd774f56f2d342f6d3f73e1e5 Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Sun, 11 Aug 2024 20:44:05 +0200 Subject: [PATCH 02/17] feat: add two pannels --- src/app/app.config.ts | 4 +- .../components/kanban/kanban.component.html | 35 +++++++- .../components/kanban/kanban.component.scss | 84 ++++++++++++++----- src/app/components/kanban/kanban.component.ts | 35 +++++++- 4 files changed, 128 insertions(+), 30 deletions(-) diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 8e58c7d..b89d827 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -25,13 +25,13 @@ export const appConfig: ApplicationConfig = { provideAnimations(), provideRouter(routes), importProvidersFrom( - DragDropModule, BrowserModule, + DragDropModule, + FormsModule, MatSidenavModule, MatToolbarModule, MatButtonModule, MatNativeDateModule, - FormsModule, MatFormFieldModule, MatSelectModule, MatInputModule diff --git a/src/app/components/kanban/kanban.component.html b/src/app/components/kanban/kanban.component.html index 4885ee5..6bcfdee 100644 --- a/src/app/components/kanban/kanban.component.html +++ b/src/app/components/kanban/kanban.component.html @@ -1,3 +1,34 @@ -

kanban works!

+
+
+

To do

-
+
+ @for (item of todo; track item) { +
+ {{ item }} +
+
+ } +
+
+ +
+

Done

+ +
+ @for (item of done; track item) { +
+ {{ item }} +
+ } +
+
+
diff --git a/src/app/components/kanban/kanban.component.scss b/src/app/components/kanban/kanban.component.scss index 37bf82b..9c3d9e0 100644 --- a/src/app/components/kanban/kanban.component.scss +++ b/src/app/components/kanban/kanban.component.scss @@ -1,24 +1,62 @@ -:host { - #item { - width: 15em; - height: 15em; - cursor: move; - background-color: dodgerblue; - border: 1px solid darkblue; - border-radius: 5%; - box-shadow: - 0 3px 1px -2px rgba(0, 0, 0, 0.2), - 0 2px 2px 0 rgba(0, 0, 0, 0.14), - 0 1px 5px 0 rgba(0, 0, 0, 0.12); - - &:active { - background-color: tomato; - border-color: darkred; - - box-shadow: - 0 5px 5px -3px rgba(0, 0, 0, 0.2), - 0 8px 10px 1px rgba(0, 0, 0, 0.14), - 0 3px 14px 2px rgba(0, 0, 0, 0.12); - } - } +.example-container { + width: 400px; + max-width: 100%; + margin: 0 25px 25px 0; + display: inline-block; + vertical-align: top; +} + +.example-list { + border: solid 1px #ccc; + min-height: 60px; + background: white; + border-radius: 4px; + overflow: hidden; + display: block; +} + +.example-box { + padding: 20px 10px; + border-bottom: solid 1px #ccc; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + cursor: move; + background: white; + font-size: 14px; +} + +.cdk-drag-preview { + box-sizing: border-box; + border-radius: 4px; + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.cdk-drag-placeholder { + opacity: 0; +} + +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.example-box:last-child { + border: none; +} + +.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.example-custom-placeholder { + background: #ccc; + border: dotted 3px #999; + min-height: 60px; + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } diff --git a/src/app/components/kanban/kanban.component.ts b/src/app/components/kanban/kanban.component.ts index 40debb0..a8f433a 100644 --- a/src/app/components/kanban/kanban.component.ts +++ b/src/app/components/kanban/kanban.component.ts @@ -1,11 +1,40 @@ -import { CdkDrag } from '@angular/cdk/drag-drop'; +import { + CdkDrag, + CdkDragDrop, + CdkDragPlaceholder, + CdkDropList, + CdkDropListGroup, + moveItemInArray, + transferArrayItem, +} from '@angular/cdk/drag-drop'; import { Component } from '@angular/core'; @Component({ selector: 'app-kanban', standalone: true, - imports: [CdkDrag], + imports: [CdkDrag, CdkDropListGroup, CdkDropList, CdkDragPlaceholder], templateUrl: './kanban.component.html', styleUrl: './kanban.component.scss', }) -export class KanbanComponent {} +export class KanbanComponent { + todo = ['Get to work', 'Pick up groceries', 'Go home', 'Fall asleep']; + + done = ['Get up', 'Brush teeth', 'Take a shower', 'Check e-mail', 'Walk dog']; + + drop(event: CdkDragDrop) { + if (event.previousContainer === event.container) { + moveItemInArray( + event.container.data, + event.previousIndex, + event.currentIndex + ); + } else { + transferArrayItem( + event.previousContainer.data, + event.container.data, + event.previousIndex, + event.currentIndex + ); + } + } +} From 1c108be52323c3a510b780eb6d632ef9b37d150e Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Wed, 14 Aug 2024 20:11:31 +0200 Subject: [PATCH 03/17] chore(project): change deprecated configuration options --- angular.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/angular.json b/angular.json index cd1222e..a3c63ad 100644 --- a/angular.json +++ b/angular.json @@ -62,7 +62,6 @@ "development": { "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -74,10 +73,10 @@ "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "materials-test:build:production" + "buildTarget": "materials-test:build:production" }, "development": { - "browserTarget": "materials-test:build:development" + "buildTarget": "materials-test:build:development" } }, "defaultConfiguration": "development" @@ -85,7 +84,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "materials-test:build" + "buildTarget": "materials-test:build" } }, "lint": { From eefb20529906daa6ece1044f0f8d6cb07d29a6c6 Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Thu, 15 Aug 2024 21:27:57 +0200 Subject: [PATCH 04/17] feat(IN-1): create todo form dialog --- src/app/app.config.ts | 6 +- .../kanban/form/todo-form.component.html | 6 ++ .../kanban/form/todo-form.component.scss | 3 + .../kanban/form/todo-form.component.spec.ts | 23 +++++++ .../kanban/form/todo-form.component.ts | 23 +++++++ .../components/kanban/kanban.component.html | 41 +++--------- .../components/kanban/kanban.component.scss | 65 ++----------------- src/app/components/kanban/kanban.component.ts | 42 ++++++------ .../kanban/model/dummy-board.data.ts | 31 --------- .../kanban/model/kanban-board.data.ts | 5 -- .../kanban/model/kanban-board.interface.ts | 5 -- .../kanban/model/kanban-list.insterface.ts | 7 -- .../kanban/model/kanban-task.interface.ts | 4 -- src/app/components/kanban/model/todo.ts | 6 ++ .../kanban/services/kanban-state.service.ts | 48 -------------- .../kanban/services/todos.service.ts | 14 ++++ 16 files changed, 114 insertions(+), 215 deletions(-) create mode 100644 src/app/components/kanban/form/todo-form.component.html create mode 100644 src/app/components/kanban/form/todo-form.component.scss create mode 100644 src/app/components/kanban/form/todo-form.component.spec.ts create mode 100644 src/app/components/kanban/form/todo-form.component.ts delete mode 100644 src/app/components/kanban/model/dummy-board.data.ts delete mode 100644 src/app/components/kanban/model/kanban-board.data.ts delete mode 100644 src/app/components/kanban/model/kanban-board.interface.ts delete mode 100644 src/app/components/kanban/model/kanban-list.insterface.ts delete mode 100644 src/app/components/kanban/model/kanban-task.interface.ts create mode 100644 src/app/components/kanban/model/todo.ts delete mode 100644 src/app/components/kanban/services/kanban-state.service.ts create mode 100644 src/app/components/kanban/services/todos.service.ts diff --git a/src/app/app.config.ts b/src/app/app.config.ts index b89d827..e22588a 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -3,6 +3,7 @@ import { MatButtonModule } from '@angular/material/button'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatToolbarModule } from '@angular/material/toolbar'; import { BrowserModule } from '@angular/platform-browser'; +import { MatIconModule } from '@angular/material/icon'; import { provideAnimations } from '@angular/platform-browser/animations'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; @@ -12,6 +13,7 @@ import { MatNativeDateModule, } from '@angular/material/core'; import { FormsModule } from '@angular/forms'; +import { MatDialogModule } from '@angular/material/dialog'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -31,10 +33,12 @@ export const appConfig: ApplicationConfig = { MatSidenavModule, MatToolbarModule, MatButtonModule, + MatDialogModule, MatNativeDateModule, MatFormFieldModule, MatSelectModule, - MatInputModule + MatInputModule, + MatIconModule ), provideAnimations(), ], diff --git a/src/app/components/kanban/form/todo-form.component.html b/src/app/components/kanban/form/todo-form.component.html new file mode 100644 index 0000000..301f195 --- /dev/null +++ b/src/app/components/kanban/form/todo-form.component.html @@ -0,0 +1,6 @@ +

Crear una tarefa

+ Aquí vai un formulario + + + + diff --git a/src/app/components/kanban/form/todo-form.component.scss b/src/app/components/kanban/form/todo-form.component.scss new file mode 100644 index 0000000..fd90cf1 --- /dev/null +++ b/src/app/components/kanban/form/todo-form.component.scss @@ -0,0 +1,3 @@ +mat-dialog-actions { + justify-content: end; +} diff --git a/src/app/components/kanban/form/todo-form.component.spec.ts b/src/app/components/kanban/form/todo-form.component.spec.ts new file mode 100644 index 0000000..5652c7f --- /dev/null +++ b/src/app/components/kanban/form/todo-form.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TodoFormComponent } from './todo-form.component'; + +describe('TodoFormComponent', () => { + let component: TodoFormComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TodoFormComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TodoFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/kanban/form/todo-form.component.ts b/src/app/components/kanban/form/todo-form.component.ts new file mode 100644 index 0000000..75a97f4 --- /dev/null +++ b/src/app/components/kanban/form/todo-form.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle, +} from '@angular/material/dialog'; + +@Component({ + selector: 'app-todo-form', + standalone: true, + imports: [ + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose, + MatButtonModule, + ], + templateUrl: './todo-form.component.html', + styleUrl: './todo-form.component.scss', +}) +export class TodoFormComponent {} diff --git a/src/app/components/kanban/kanban.component.html b/src/app/components/kanban/kanban.component.html index 6bcfdee..70f9fdb 100644 --- a/src/app/components/kanban/kanban.component.html +++ b/src/app/components/kanban/kanban.component.html @@ -1,34 +1,9 @@ -
-
-

To do

+

Tasks list

-
- @for (item of todo; track item) { -
- {{ item }} -
-
- } -
-
- -
-

Done

- -
- @for (item of done; track item) { -
- {{ item }} -
- } -
-
-
+ diff --git a/src/app/components/kanban/kanban.component.scss b/src/app/components/kanban/kanban.component.scss index 9c3d9e0..e82c108 100644 --- a/src/app/components/kanban/kanban.component.scss +++ b/src/app/components/kanban/kanban.component.scss @@ -1,62 +1,5 @@ -.example-container { - width: 400px; - max-width: 100%; - margin: 0 25px 25px 0; - display: inline-block; - vertical-align: top; -} - -.example-list { - border: solid 1px #ccc; - min-height: 60px; - background: white; - border-radius: 4px; - overflow: hidden; - display: block; -} - -.example-box { - padding: 20px 10px; - border-bottom: solid 1px #ccc; - color: rgba(0, 0, 0, 0.87); - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - box-sizing: border-box; - cursor: move; - background: white; - font-size: 14px; -} - -.cdk-drag-preview { - box-sizing: border-box; - border-radius: 4px; - box-shadow: - 0 5px 5px -3px rgba(0, 0, 0, 0.2), - 0 8px 10px 1px rgba(0, 0, 0, 0.14), - 0 3px 14px 2px rgba(0, 0, 0, 0.12); -} - -.cdk-drag-placeholder { - opacity: 0; -} - -.cdk-drag-animating { - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); -} - -.example-box:last-child { - border: none; -} - -.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); -} - -.example-custom-placeholder { - background: #ccc; - border: dotted 3px #999; - min-height: 60px; - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +.add { + position: absolute; + top: 1em; + right: 1em; } diff --git a/src/app/components/kanban/kanban.component.ts b/src/app/components/kanban/kanban.component.ts index a8f433a..39c4e31 100644 --- a/src/app/components/kanban/kanban.component.ts +++ b/src/app/components/kanban/kanban.component.ts @@ -7,34 +7,36 @@ import { moveItemInArray, transferArrayItem, } from '@angular/cdk/drag-drop'; -import { Component } from '@angular/core'; +import { Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { TodoFormComponent } from './form/todo-form.component'; +import { Todo } from './model/todo'; +import { TodosService } from './services/todos.service'; @Component({ selector: 'app-kanban', standalone: true, - imports: [CdkDrag, CdkDropListGroup, CdkDropList, CdkDragPlaceholder], + imports: [ + CdkDrag, + CdkDropListGroup, + CdkDropList, + CdkDragPlaceholder, + MatButtonModule, + MatIconModule, + ], templateUrl: './kanban.component.html', styleUrl: './kanban.component.scss', }) export class KanbanComponent { - todo = ['Get to work', 'Pick up groceries', 'Go home', 'Fall asleep']; + private readonly dialog = inject(MatDialog); + private readonly todoService = inject(TodosService); - done = ['Get up', 'Brush teeth', 'Take a shower', 'Check e-mail', 'Walk dog']; - - drop(event: CdkDragDrop) { - if (event.previousContainer === event.container) { - moveItemInArray( - event.container.data, - event.previousIndex, - event.currentIndex - ); - } else { - transferArrayItem( - event.previousContainer.data, - event.container.data, - event.previousIndex, - event.currentIndex - ); - } + addTodo() { + const dialogRef = this.dialog.open(TodoFormComponent); + dialogRef.afterClosed().subscribe((todo: Todo) => { + this.todoService.saveTodo(todo); + }); } } diff --git a/src/app/components/kanban/model/dummy-board.data.ts b/src/app/components/kanban/model/dummy-board.data.ts deleted file mode 100644 index 8ced704..0000000 --- a/src/app/components/kanban/model/dummy-board.data.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { KanbanBoard } from './kanban-board.data'; - -const toDoColumn = { - id: 1, - title: 'Pendente', - tasks: [ - { id: 4, description: 'Configurar os Drags e DropLists.' }, - { id: 5, description: 'Engadir métodos para procesar as accións.' }, - { id: 6, description: 'Amosar estilos e animacións.' }, - { id: 7, description: 'Converter accións en comandos.' }, - ], -}; - -const inProgressColumn = { - id: 2, - title: 'En Proceso', - tasks: [ - { id: 2, description: 'Engadir material cdk.' }, - { id: 3, description: 'Explicar elementos básicos do Drag & Drop.' }, - ], -}; - -const completedColumn = { - id: 3, - title: 'Completadas', - tasks: [{ id: 1, description: 'Crear a estrutura básica da aplicación.' }], -}; - -export const dummyBoard: KanbanBoard = { - lists: [toDoColumn, inProgressColumn, completedColumn], -}; diff --git a/src/app/components/kanban/model/kanban-board.data.ts b/src/app/components/kanban/model/kanban-board.data.ts deleted file mode 100644 index 0967934..0000000 --- a/src/app/components/kanban/model/kanban-board.data.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { KanbanList } from './kanban-list.insterface'; - -export interface KanbanBoard { - lists: KanbanList[]; -} diff --git a/src/app/components/kanban/model/kanban-board.interface.ts b/src/app/components/kanban/model/kanban-board.interface.ts deleted file mode 100644 index 1dd0af6..0000000 --- a/src/app/components/kanban/model/kanban-board.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { KanbanList } from "./kanban-list.insterface"; - -export interface KanbanBoard { - lists: KanbanList[]; -} diff --git a/src/app/components/kanban/model/kanban-list.insterface.ts b/src/app/components/kanban/model/kanban-list.insterface.ts deleted file mode 100644 index 6afa243..0000000 --- a/src/app/components/kanban/model/kanban-list.insterface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { KanbanTask } from './kanban-task.interface'; - -export interface KanbanList { - id: number; - title: string; - tasks: KanbanTask[]; -} diff --git a/src/app/components/kanban/model/kanban-task.interface.ts b/src/app/components/kanban/model/kanban-task.interface.ts deleted file mode 100644 index da3b33a..0000000 --- a/src/app/components/kanban/model/kanban-task.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface KanbanTask { - id: number; - description: string; -} diff --git a/src/app/components/kanban/model/todo.ts b/src/app/components/kanban/model/todo.ts new file mode 100644 index 0000000..af95231 --- /dev/null +++ b/src/app/components/kanban/model/todo.ts @@ -0,0 +1,6 @@ +export interface Todo { + uid: string; + title: string; + description: string; + createAt: number; +} diff --git a/src/app/components/kanban/services/kanban-state.service.ts b/src/app/components/kanban/services/kanban-state.service.ts deleted file mode 100644 index c75263e..0000000 --- a/src/app/components/kanban/services/kanban-state.service.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Injectable } from '@angular/core'; -import { dummyBoard } from '../model/dummy-board.data'; -import { KanbanBoard } from '../model/kanban-board.data'; - -@Injectable() -export class KanbanStateService { - public board: KanbanBoard = dummyBoard; - - constructor() {} - /* - updateListTitle(list: KanbanList, newTitle: string): void { - list.title = newTitle; - } - - moveList(fromIndex: number, toIndex: number): void { - moveItemInArray(this.board.lists, fromIndex, toIndex); - } - - removeList(listToRemove: KanbanList): void { - this.board.lists = this.board.lists.filter((list) => list !== listToRemove); - } - - addTaskToList(list: KanbanList): void { - list.tasks.push(KanbanTaskFactory.createDefault()); - } - - removeTaskFromList(list: KanbanList, taskIndex: number): void { - list.tasks.splice(taskIndex, 1); - } - - updateTask(task: KanbanTask, newDescription: string): void { - task.description = newDescription; - } - - reorderTask(list: KanbanList, fromIndex: number, toIndex: number): void { - moveItemInArray(list.tasks, fromIndex, toIndex); - } - - transferTask({ - fromList, - toList, - fromIndex, - toIndex, - }: TransferTaskData): void { - transferArrayItem(fromList.tasks, toList.tasks, fromIndex, toIndex); - } - */ -} diff --git a/src/app/components/kanban/services/todos.service.ts b/src/app/components/kanban/services/todos.service.ts new file mode 100644 index 0000000..418e416 --- /dev/null +++ b/src/app/components/kanban/services/todos.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { Todo } from '../model/todo'; + +@Injectable({ + providedIn: 'root', +}) +export class TodosService { + constructor() {} + + saveTodo(todo: Todo) { + console.log('save todo'); + console.log(todo); + } +} From 208c61e13505ff25e5ffe0bc5216b740370144ed Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Sat, 17 Aug 2024 19:42:22 +0200 Subject: [PATCH 05/17] feat(IN-1): save a todo --- package-lock.json | 28 ++++++++++++--- package.json | 6 ++-- src/app/app.config.ts | 6 ++-- .../kanban/form/todo-form.component.html | 19 ++++++++-- .../kanban/form/todo-form.component.scss | 11 ++++++ .../kanban/form/todo-form.component.ts | 36 +++++++++++++++++-- src/app/components/kanban/model/todo.ts | 7 ++++ .../kanban/services/todos.service.ts | 19 +++++++--- 8 files changed, 115 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79cdca2..d90f739 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@angular/router": "18.1.4", "rxjs": "7.8.1", "tslib": "2.6.3", + "uuid": "^10.0.0", "zone.js": "0.14.10" }, "devDependencies": { @@ -36,6 +37,7 @@ "@babel/preset-typescript": "7.24.7", "@types/jest": "29.5.12", "@types/node": "22.2.0", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "8.0.1", "@typescript-eslint/parser": "8.0.1", "babel-jest": "29.7.0", @@ -6241,6 +6243,12 @@ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true + }, "node_modules/@types/wrap-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", @@ -17443,6 +17451,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", @@ -18606,10 +18623,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 28aaf74..d2768b4 100644 --- a/package.json +++ b/package.json @@ -27,22 +27,24 @@ "@angular/router": "18.1.4", "rxjs": "7.8.1", "tslib": "2.6.3", + "uuid": "^10.0.0", "zone.js": "0.14.10" }, "devDependencies": { - "@angular/cli": "18.1.4", - "@angular/compiler-cli": "18.1.4", "@angular-devkit/build-angular": "18.1.4", "@angular-eslint/builder": "18.2.0", "@angular-eslint/eslint-plugin": "18.2.0", "@angular-eslint/eslint-plugin-template": "18.2.0", "@angular-eslint/schematics": "18.2.0", "@angular-eslint/template-parser": "18.2.0", + "@angular/cli": "18.1.4", + "@angular/compiler-cli": "18.1.4", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.24.7", "@types/jest": "29.5.12", "@types/node": "22.2.0", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "8.0.1", "@typescript-eslint/parser": "8.0.1", "babel-jest": "29.7.0", diff --git a/src/app/app.config.ts b/src/app/app.config.ts index e22588a..586392a 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -12,7 +12,7 @@ import { VERSION as MAT_VERSION, MatNativeDateModule, } from '@angular/material/core'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDialogModule } from '@angular/material/dialog'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; @@ -30,6 +30,7 @@ export const appConfig: ApplicationConfig = { BrowserModule, DragDropModule, FormsModule, + ReactiveFormsModule, MatSidenavModule, MatToolbarModule, MatButtonModule, @@ -38,7 +39,8 @@ export const appConfig: ApplicationConfig = { MatFormFieldModule, MatSelectModule, MatInputModule, - MatIconModule + MatIconModule, + MatInputModule ), provideAnimations(), ], diff --git a/src/app/components/kanban/form/todo-form.component.html b/src/app/components/kanban/form/todo-form.component.html index 301f195..bbfa2df 100644 --- a/src/app/components/kanban/form/todo-form.component.html +++ b/src/app/components/kanban/form/todo-form.component.html @@ -1,6 +1,21 @@

Crear una tarefa

- Aquí vai un formulario + +
+ + Título + + + + + Descrición da tarefa + + +
+
- + diff --git a/src/app/components/kanban/form/todo-form.component.scss b/src/app/components/kanban/form/todo-form.component.scss index fd90cf1..b3c00ee 100644 --- a/src/app/components/kanban/form/todo-form.component.scss +++ b/src/app/components/kanban/form/todo-form.component.scss @@ -1,3 +1,14 @@ +.task-form { + min-width: 150px; + max-width: 500px; + width: 100%; +} + +.title, +.description { + width: 100%; +} + mat-dialog-actions { justify-content: end; } diff --git a/src/app/components/kanban/form/todo-form.component.ts b/src/app/components/kanban/form/todo-form.component.ts index 75a97f4..4d6192c 100644 --- a/src/app/components/kanban/form/todo-form.component.ts +++ b/src/app/components/kanban/form/todo-form.component.ts @@ -1,11 +1,25 @@ -import { Component } from '@angular/core'; +import { Component, Inject, inject } from '@angular/core'; +import { + FormBuilder, + FormControl, + ReactiveFormsModule, + Validators, +} from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { + MAT_DIALOG_DATA, MatDialogActions, MatDialogClose, MatDialogContent, + MatDialogRef, MatDialogTitle, } from '@angular/material/dialog'; +import { MatInputModule } from '@angular/material/input'; + +interface DialogData { + title?: string | null | undefined; + description?: string | null | undefined; +} @Component({ selector: 'app-todo-form', @@ -16,8 +30,26 @@ import { MatDialogActions, MatDialogClose, MatButtonModule, + MatInputModule, + ReactiveFormsModule, ], templateUrl: './todo-form.component.html', styleUrl: './todo-form.component.scss', }) -export class TodoFormComponent {} +export class TodoFormComponent { + fb = inject(FormBuilder); + + form = this.fb.group({ + title: ['My title', { validators: [Validators.required] }], + description: [ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,', + { validators: [Validators.required] }, + ], + }); + + constructor(public dialogRef: MatDialogRef) {} + + saveData(): void { + this.dialogRef.close(this.form.value); + } +} diff --git a/src/app/components/kanban/model/todo.ts b/src/app/components/kanban/model/todo.ts index af95231..5fb7310 100644 --- a/src/app/components/kanban/model/todo.ts +++ b/src/app/components/kanban/model/todo.ts @@ -3,4 +3,11 @@ export interface Todo { title: string; description: string; createAt: number; + status: TodoStatusEnum; +} + +export enum TodoStatusEnum { + TODO = 'todo', + ACTIVE = 'active', + DONE = 'done', } diff --git a/src/app/components/kanban/services/todos.service.ts b/src/app/components/kanban/services/todos.service.ts index 418e416..1033935 100644 --- a/src/app/components/kanban/services/todos.service.ts +++ b/src/app/components/kanban/services/todos.service.ts @@ -1,14 +1,23 @@ import { Injectable } from '@angular/core'; -import { Todo } from '../model/todo'; - +import { Todo, TodoStatusEnum } from '../model/todo'; +import * as uuid from 'uuid'; @Injectable({ providedIn: 'root', }) export class TodosService { + TODOS_KEY = 'TODOS'; + todos: Todo[] = []; + constructor() {} - saveTodo(todo: Todo) { - console.log('save todo'); - console.log(todo); + saveTodo(data: { title: string; description: string }) { + const todo: Todo = { + ...data, + uid: uuid.v4(), + createAt: new Date().getTime(), + status: TodoStatusEnum.TODO, + }; + this.todos.push(todo); + window.localStorage.setItem(this.TODOS_KEY, JSON.stringify(this.todos)); } } From 3b7feac8694cca16a23c9e8b463db20c86121a79 Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Tue, 20 Aug 2024 20:25:02 +0200 Subject: [PATCH 06/17] fix(IN-1): avoid save template value on form todo cancel button clicked --- src/app/components/kanban/form/todo-form.component.html | 8 +++++++- src/app/components/kanban/form/todo-form.component.ts | 7 ++----- src/app/components/kanban/kanban.component.ts | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/app/components/kanban/form/todo-form.component.html b/src/app/components/kanban/form/todo-form.component.html index bbfa2df..fc8e3d5 100644 --- a/src/app/components/kanban/form/todo-form.component.html +++ b/src/app/components/kanban/form/todo-form.component.html @@ -17,5 +17,11 @@

Crear una tarefa

- + diff --git a/src/app/components/kanban/form/todo-form.component.ts b/src/app/components/kanban/form/todo-form.component.ts index 4d6192c..71f965d 100644 --- a/src/app/components/kanban/form/todo-form.component.ts +++ b/src/app/components/kanban/form/todo-form.component.ts @@ -40,11 +40,8 @@ export class TodoFormComponent { fb = inject(FormBuilder); form = this.fb.group({ - title: ['My title', { validators: [Validators.required] }], - description: [ - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,', - { validators: [Validators.required] }, - ], + title: ['', { validators: [Validators.required] }], + description: ['', { validators: [Validators.required] }], }); constructor(public dialogRef: MatDialogRef) {} diff --git a/src/app/components/kanban/kanban.component.ts b/src/app/components/kanban/kanban.component.ts index 39c4e31..abd1dfd 100644 --- a/src/app/components/kanban/kanban.component.ts +++ b/src/app/components/kanban/kanban.component.ts @@ -36,7 +36,7 @@ export class KanbanComponent { addTodo() { const dialogRef = this.dialog.open(TodoFormComponent); dialogRef.afterClosed().subscribe((todo: Todo) => { - this.todoService.saveTodo(todo); + if (todo) this.todoService.saveTodo(todo); }); } } From 3845da74d447d2ac5496d0e24ee565f84f682133 Mon Sep 17 00:00:00 2001 From: Alexandre Insua Moreira Date: Wed, 21 Aug 2024 16:58:17 +0200 Subject: [PATCH 07/17] feat(IN-1): implements columns --- src/app/app.config.ts | 2 ++ .../todo-list/todo-list.component.html | 5 ++++ .../todo-list/todo-list.component.scss | 0 .../todo-list/todo-list.component.spec.ts | 23 +++++++++++++++++++ .../todo-list/todo-list.component.ts | 16 +++++++++++++ .../components/todo/todo.component.html | 9 ++++++++ .../components/todo/todo.component.scss | 0 .../components/todo/todo.component.spec.ts | 23 +++++++++++++++++++ .../kanban/components/todo/todo.component.ts | 15 ++++++++++++ .../todos-wrapper.component.html | 5 ++++ .../todos-wrapper.component.scss | 0 .../todos-wrapper.component.spec.ts | 22 ++++++++++++++++++ .../todos-wrapper/todos-wrapper.component.ts | 15 ++++++++++++ .../components/kanban/kanban.component.html | 17 ++++++++++++++ .../components/kanban/kanban.component.scss | 10 ++++++++ src/app/components/kanban/kanban.component.ts | 14 +++++++++-- src/app/components/kanban/model/todo.ts | 2 +- .../kanban/services/todos.service.ts | 12 ++++++++-- 18 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 src/app/components/kanban/components/todo-list/todo-list.component.html create mode 100644 src/app/components/kanban/components/todo-list/todo-list.component.scss create mode 100644 src/app/components/kanban/components/todo-list/todo-list.component.spec.ts create mode 100644 src/app/components/kanban/components/todo-list/todo-list.component.ts create mode 100644 src/app/components/kanban/components/todo/todo.component.html create mode 100644 src/app/components/kanban/components/todo/todo.component.scss create mode 100644 src/app/components/kanban/components/todo/todo.component.spec.ts create mode 100644 src/app/components/kanban/components/todo/todo.component.ts create mode 100644 src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.html create mode 100644 src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.scss create mode 100644 src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.spec.ts create mode 100644 src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.ts diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 586392a..e136612 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -18,6 +18,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatFormFieldModule } from '@angular/material/form-field'; import { DragDropModule } from '@angular/cdk/drag-drop'; +import { MatCardModule } from '@angular/material/card'; console.info('Angular CDK version', CDK_VERSION.full); console.info('Angular Material version', MAT_VERSION.full); @@ -31,6 +32,7 @@ export const appConfig: ApplicationConfig = { DragDropModule, FormsModule, ReactiveFormsModule, + MatCardModule, MatSidenavModule, MatToolbarModule, MatButtonModule, diff --git a/src/app/components/kanban/components/todo-list/todo-list.component.html b/src/app/components/kanban/components/todo-list/todo-list.component.html new file mode 100644 index 0000000..8b24d98 --- /dev/null +++ b/src/app/components/kanban/components/todo-list/todo-list.component.html @@ -0,0 +1,5 @@ +

{{ title }}

+ + diff --git a/src/app/components/kanban/components/todo-list/todo-list.component.scss b/src/app/components/kanban/components/todo-list/todo-list.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/kanban/components/todo-list/todo-list.component.spec.ts b/src/app/components/kanban/components/todo-list/todo-list.component.spec.ts new file mode 100644 index 0000000..906be65 --- /dev/null +++ b/src/app/components/kanban/components/todo-list/todo-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TodoListComponent } from './todo-list.component'; + +describe('TodoListComponent', () => { + let component: TodoListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TodoListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TodoListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/kanban/components/todo-list/todo-list.component.ts b/src/app/components/kanban/components/todo-list/todo-list.component.ts new file mode 100644 index 0000000..4678075 --- /dev/null +++ b/src/app/components/kanban/components/todo-list/todo-list.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from '@angular/core'; +import { TodostWrapperComponent } from '../todos-wrapper/todos-wrapper.component'; +import { Todo } from '../../model/todo'; + +@Component({ + selector: 'app-todo-list', + standalone: true, + imports: [TodostWrapperComponent], + templateUrl: './todo-list.component.html', + styleUrl: './todo-list.component.scss', +}) +export class TodoListComponent { + @Input() title!: string; + @Input() identifier!: string; + @Input() todos!: Todo[]; +} diff --git a/src/app/components/kanban/components/todo/todo.component.html b/src/app/components/kanban/components/todo/todo.component.html new file mode 100644 index 0000000..f28a16c --- /dev/null +++ b/src/app/components/kanban/components/todo/todo.component.html @@ -0,0 +1,9 @@ + + + + {{ todo.title }} + {{ todo.createAt | date: 'long' }} + + + >{{ todo.description }} + diff --git a/src/app/components/kanban/components/todo/todo.component.scss b/src/app/components/kanban/components/todo/todo.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/kanban/components/todo/todo.component.spec.ts b/src/app/components/kanban/components/todo/todo.component.spec.ts new file mode 100644 index 0000000..dade0bc --- /dev/null +++ b/src/app/components/kanban/components/todo/todo.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TodoComponent } from './todo.component'; + +describe('TodoComponent', () => { + let component: TodoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TodoComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TodoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/kanban/components/todo/todo.component.ts b/src/app/components/kanban/components/todo/todo.component.ts new file mode 100644 index 0000000..24c35cf --- /dev/null +++ b/src/app/components/kanban/components/todo/todo.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; +import { Todo } from '../../model/todo'; +import { MatCardModule } from '@angular/material/card'; +import { DatePipe } from '@angular/common'; + +@Component({ + selector: 'app-todo', + standalone: true, + imports: [DatePipe, MatCardModule], + templateUrl: './todo.component.html', + styleUrl: './todo.component.scss', +}) +export class TodoComponent { + @Input() todo!: Todo; +} diff --git a/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.html b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.html new file mode 100644 index 0000000..ec8e035 --- /dev/null +++ b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.html @@ -0,0 +1,5 @@ +
+ @for (todo of todos; track todo) { + + } +
diff --git a/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.scss b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.spec.ts b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.spec.ts new file mode 100644 index 0000000..5508edf --- /dev/null +++ b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TodostWrapperComponent } from './todos-wrapper.component'; + +describe('TodoListWrapperComponent', () => { + let component: TodostWrapperComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TodostWrapperComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(TodostWrapperComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.ts b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.ts new file mode 100644 index 0000000..20b862e --- /dev/null +++ b/src/app/components/kanban/components/todos-wrapper/todos-wrapper.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; +import { TodoComponent } from '../todo/todo.component'; +import { Todo } from '../../model/todo'; + +@Component({ + selector: 'app-todos-wrapper', + standalone: true, + imports: [TodoComponent], + templateUrl: './todos-wrapper.component.html', + styleUrl: './todos-wrapper.component.scss', +}) +export class TodostWrapperComponent { + @Input() identifier!: string; + @Input() todos!: Todo[]; +} diff --git a/src/app/components/kanban/kanban.component.html b/src/app/components/kanban/kanban.component.html index 70f9fdb..a3b067a 100644 --- a/src/app/components/kanban/kanban.component.html +++ b/src/app/components/kanban/kanban.component.html @@ -1,5 +1,22 @@

Tasks list

+
+ + + + + +
+