diff --git a/src/app/app.component.html b/src/app/app.component.html index 90c6b64..1e15754 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1 +1,2 @@ - \ No newline at end of file + + diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 167878b..1056484 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -16,6 +16,7 @@ import {MatDialogModule} from '@angular/material/dialog'; import {MatButtonModule} from '@angular/material/button'; import {ReactiveFormsModule} from '@angular/forms'; import {MatSnackBarModule} from '@angular/material/snack-bar'; +import { HeaderComponent } from './core/components/header/header.component'; @NgModule({ declarations: [ @@ -24,7 +25,8 @@ import {MatSnackBarModule} from '@angular/material/snack-bar'; AddTaskComponent, DisplayTaskComponent, TaskListsComponent, - AddTaskListComponent + AddTaskListComponent, + HeaderComponent ], imports: [ BrowserModule, diff --git a/src/app/core/components/header/header.component.html b/src/app/core/components/header/header.component.html new file mode 100644 index 0000000..13d060a --- /dev/null +++ b/src/app/core/components/header/header.component.html @@ -0,0 +1,6 @@ + diff --git a/src/app/core/components/header/header.component.scss b/src/app/core/components/header/header.component.scss new file mode 100644 index 0000000..a3e6be0 --- /dev/null +++ b/src/app/core/components/header/header.component.scss @@ -0,0 +1,14 @@ +nav { + position: fixed; + top: 0; + left: 0; + right: 0; + display: flex; + align-items: center; + height: 4rem; + + .title { + font-size: 1.5rem; + margin: 0 1rem; + } +} diff --git a/src/app/core/components/header/header.component.ts b/src/app/core/components/header/header.component.ts new file mode 100644 index 0000000..5468361 --- /dev/null +++ b/src/app/core/components/header/header.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { AddTaskListComponent } from 'src/app/task-lists/add-task-list/add-task-list.component'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.scss'] +}) +export class HeaderComponent implements OnInit { + + constructor( + private _dialog: MatDialog, + ) {} + + ngOnInit(): void { + } + + openNewListForm(): void { + this._dialog.open(AddTaskListComponent); + } +} diff --git a/src/app/core/entity/store.ts b/src/app/core/entity/store.ts index 57069d8..c286ff1 100644 --- a/src/app/core/entity/store.ts +++ b/src/app/core/entity/store.ts @@ -1,5 +1,6 @@ import { TaskList } from "./task-list"; export interface Store { + activeTaskListId: string | undefined; taskLists: TaskList[]; } diff --git a/src/app/core/service/store-persistence.service.ts b/src/app/core/service/store-persistence.service.ts index e4d2eea..cfefb53 100644 --- a/src/app/core/service/store-persistence.service.ts +++ b/src/app/core/service/store-persistence.service.ts @@ -28,6 +28,7 @@ export class StorePersistenceService { } } else { return { + activeTaskListId: undefined, taskLists: [] } as Store; } diff --git a/src/app/core/service/task-list.service.ts b/src/app/core/service/task-list.service.ts index 76c4c9e..447c42e 100644 --- a/src/app/core/service/task-list.service.ts +++ b/src/app/core/service/task-list.service.ts @@ -1,53 +1,70 @@ import { Injectable } from "@angular/core"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, Observable } from "rxjs"; import { Task } from "../entity/task"; import { TaskList } from "../entity/task-list"; import { StorePersistenceService } from "./store-persistence.service"; import { v4 as uuidv4 } from 'uuid'; +import { filter, throttleTime } from 'rxjs/operators'; +import { Store } from "../entity/store"; @Injectable({ providedIn: 'root' }) export class TaskListService { private _activeTaskList: BehaviorSubject = new BehaviorSubject(undefined as unknown as TaskList); + private _store: BehaviorSubject = new BehaviorSubject(undefined as unknown as Store); constructor( private _storePersistenceService: StorePersistenceService - ) { - this._activeTaskList.asObservable() - .subscribe(activeTaskList => { - const store = this._storePersistenceService.load(); - const storedActiveList = store.taskLists.find(taskList => activeTaskList.id === taskList.id); - if (storedActiveList) { - storedActiveList.name = activeTaskList.name; - storedActiveList.tasks = activeTaskList.tasks; - } else { - store.taskLists.push(activeTaskList); - } - this._storePersistenceService.save(store); - }); - } - - addTask(task: Task): void { - const activeTaskList = this._activeTaskList.value; - - if (!activeTaskList.tasks) { - activeTaskList.tasks = []; + ) { + this.store$.subscribe(store => { + this._storePersistenceService.save(store); + }); } - activeTaskList.tasks.push(task); - this._activeTaskList.next(activeTaskList); - } + get store$(): Observable { + return this._store.asObservable() + .pipe(filter(store => !!store)); + } - createTaskList(taskListName: string): void { - const newTaskList = { - id: uuidv4(), - name: taskListName, - tasks: [] - } as TaskList; + private get store(): Store { + return this._storePersistenceService.load(); + } - const store = this._storePersistenceService.load(); - store.taskLists.push(newTaskList); - this._storePersistenceService.save(store); + addTask(task: Task): void { + const store = this.store; + const activeTaskList = store.taskLists.find(taskList => taskList.id === store.activeTaskListId); + if (!activeTaskList) { + throw new Error("No active tasklist"); + } + + if (!activeTaskList.tasks) { + activeTaskList.tasks = []; + } + + activeTaskList?.tasks.push(task); + this._store.next(store); + } + + createTaskList(taskListName: string): void { + const newTaskList = { + id: uuidv4(), + name: taskListName, + tasks: [] + } as TaskList; + + const store = this.store; + store.taskLists.push(newTaskList); + this._store.next(store); + } + + getAll(): TaskList[] { + return this.store.taskLists ?? []; + } + + setActive(taskList: TaskList) { + const store = this.store; + store.activeTaskListId = taskList.id; + this._store.next(store); + } } -} diff --git a/src/app/task-lists/task-lists.component.html b/src/app/task-lists/task-lists.component.html index c5f31d9..1a3ea09 100644 --- a/src/app/task-lists/task-lists.component.html +++ b/src/app/task-lists/task-lists.component.html @@ -1,2 +1,15 @@ - - +
+
+
+ + + {{taskList.tasks?.length}} tâches + + + {{taskList.tasks?.length}} tâche + + +
+ {{taskList.name}} +
+
diff --git a/src/app/task-lists/task-lists.component.scss b/src/app/task-lists/task-lists.component.scss index e69de29..78d2bf2 100644 --- a/src/app/task-lists/task-lists.component.scss +++ b/src/app/task-lists/task-lists.component.scss @@ -0,0 +1,26 @@ +.task-lists { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: auto; + max-width: 80%; + + .task-list-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 1rem; + + .task-list { + width: 150px; + height: 150px; + display: flex; + justify-content: center; + align-items: center; + border-radius: .5rem; + background-color: aliceblue; + margin-bottom: .5rem; + } + } +} diff --git a/src/app/task-lists/task-lists.component.ts b/src/app/task-lists/task-lists.component.ts index 46d2f0e..c89ac19 100644 --- a/src/app/task-lists/task-lists.component.ts +++ b/src/app/task-lists/task-lists.component.ts @@ -1,5 +1,8 @@ -import { Component, OnInit } from '@angular/core'; -import {MatDialog, MatDialogModule} from '@angular/material/dialog'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { Subscription } from 'rxjs'; +import { TaskList } from '../core/entity/task-list'; +import { TaskListService } from '../core/service/task-list.service'; import { AddTaskListComponent } from './add-task-list/add-task-list.component'; @Component({ @@ -7,16 +10,31 @@ import { AddTaskListComponent } from './add-task-list/add-task-list.component'; templateUrl: './task-lists.component.html', styleUrls: ['./task-lists.component.scss'] }) -export class TaskListsComponent implements OnInit { +export class TaskListsComponent implements OnInit, OnDestroy { + taskLists: TaskList[] = []; + private _storeSubscription?: Subscription; constructor( - private _dialog: MatDialog + private _dialog: MatDialog, + private _taskListService: TaskListService, ) {} ngOnInit(): void { + this.taskLists = this._taskListService.getAll(); + this._storeSubscription = this._taskListService.store$.subscribe(store => { + this.taskLists = store.taskLists; + }); + } + + ngOnDestroy(): void { + this._storeSubscription?.unsubscribe(); } openNewListForm(): void { this._dialog.open(AddTaskListComponent); } + + selectActiveTaskList(taskList: TaskList): void { + this._taskListService.setActive(taskList); + } } diff --git a/src/styles.scss b/src/styles.scss index 7e7239a..b901991 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,4 +1,26 @@ /* You can add global styles to this file, and also import other style files */ html, body { height: 100%; } -body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +body { + margin: 0; + font-family: Roboto, "Helvetica Neue", sans-serif; + padding-top: 4rem; +} + + + + + +.shadowed { + box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0, 0, 0, 0.12); + transition: box-shadow .2s ease-out; + + &:hover { + box-shadow: 0 .2em .5em #777; + } +} + +a.no-style { + color: inherit; + text-decoration: none; +}