From de2b2387bda3ab5c31a30540493c83654074ee40 Mon Sep 17 00:00:00 2001 From: Constantin Simonis Date: Wed, 27 Nov 2024 16:12:27 +0100 Subject: [PATCH] ez --- package-lock.json | 262 ++++----------- src/app/app.component.html | 335 +------------------ src/app/app.component.ts | 4 +- src/app/app.routes.ts | 18 +- src/app/navbar.component.ts | 37 ++ src/app/settings/settings.component.ts | 38 +++ src/app/settings/settings.service.ts | 42 +++ src/app/settings/settings.ts | 4 + src/app/todo/add-todo.component.ts | 62 ++++ src/app/todo/table/table-filter.component.ts | 34 ++ src/app/todo/table/todo-table.component.html | 37 ++ src/app/todo/table/todo-table.component.ts | 62 ++++ src/app/todo/todo.service.ts | 44 +++ src/app/todo/todo.ts | 7 + src/index.html | 1 + 15 files changed, 460 insertions(+), 527 deletions(-) create mode 100644 src/app/navbar.component.ts create mode 100644 src/app/settings/settings.component.ts create mode 100644 src/app/settings/settings.service.ts create mode 100644 src/app/settings/settings.ts create mode 100644 src/app/todo/add-todo.component.ts create mode 100644 src/app/todo/table/table-filter.component.ts create mode 100644 src/app/todo/table/todo-table.component.html create mode 100644 src/app/todo/table/todo-table.component.ts create mode 100644 src/app/todo/todo.service.ts create mode 100644 src/app/todo/todo.ts diff --git a/package-lock.json b/package-lock.json index 5f7ee7a..617ee89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -437,6 +437,34 @@ "typescript": ">=5.4 <5.6" } }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/core": { "version": "18.2.12", "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.12.tgz", @@ -5154,18 +5182,39 @@ "dev": true }, "node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "dependencies": { - "readdirp": "^4.0.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/chownr": { @@ -7975,30 +8024,6 @@ "source-map-support": "^0.5.5" } }, - "node_modules/karma/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -8016,18 +8041,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/karma/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/karma/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -8037,30 +8050,6 @@ "node": ">=8" } }, - "node_modules/karma/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/karma/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -10254,16 +10243,27 @@ } }, "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { - "node": ">= 14.16.0" + "node": ">=8.6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/reflect-metadata": { @@ -10665,66 +10665,6 @@ } } }, - "node_modules/sass/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/sass/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sass/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/sass/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", @@ -12750,30 +12690,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -12794,18 +12710,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", @@ -12845,30 +12749,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", diff --git a/src/app/app.component.html b/src/app/app.component.html index 36093e1..f733ffe 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,336 +1,3 @@ - - - - - - - - - - - -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - - } -
- -
-
-
- - - - - - - - - + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b8505e9..a585c96 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,12 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import {TodoTableComponent} from "./todo/table/todo-table.component"; +import {NavbarComponent} from "./navbar.component"; @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet], + imports: [RouterOutlet, TodoTableComponent, NavbarComponent], templateUrl: './app.component.html', styleUrl: './app.component.css' }) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index dc39edb..752fd47 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,3 +1,19 @@ import { Routes } from '@angular/router'; +import {AddTodoComponent} from "./todo/add-todo.component"; +import {TodoTableComponent} from "./todo/table/todo-table.component"; +import {SettingsComponent} from "./settings/settings.component"; -export const routes: Routes = []; +export const routes: Routes = [ + { + path: 'todos', + component: TodoTableComponent, + }, + { + path: 'todos/new', + component: AddTodoComponent, + }, + { + path: 'settings', + component: SettingsComponent, + } +]; diff --git a/src/app/navbar.component.ts b/src/app/navbar.component.ts new file mode 100644 index 0000000..99a1f6f --- /dev/null +++ b/src/app/navbar.component.ts @@ -0,0 +1,37 @@ +import {Component} from "@angular/core"; +import {RouterLink} from "@angular/router"; + + +@Component({ + standalone: true, + selector: 'app-navbar', + imports: [ + RouterLink + ], + template: ` + + ` +}) +export class NavbarComponent { + +} diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts new file mode 100644 index 0000000..6f513f1 --- /dev/null +++ b/src/app/settings/settings.component.ts @@ -0,0 +1,38 @@ +import {Component, inject} from "@angular/core"; +import {SettingsService} from "./settings.service"; + +@Component({ + standalone: true, + selector: 'app-settings', + template: ` +
+
+

Settings

+
+ + +
+
+ + +
+
+
+ ` +}) +export class SettingsComponent { + + settingsService: SettingsService = inject(SettingsService); + + toggleDeleteButton($event: Event) { + this.settingsService.setDeleteButton(($event.target as HTMLInputElement).checked) + } + + toggleSortTodos($event: Event) { + this.settingsService.setSortTodos(($event.target as HTMLInputElement).checked) + } +} diff --git a/src/app/settings/settings.service.ts b/src/app/settings/settings.service.ts new file mode 100644 index 0000000..c6ff032 --- /dev/null +++ b/src/app/settings/settings.service.ts @@ -0,0 +1,42 @@ +import {Injectable} from "@angular/core"; +import {Settings} from "./settings"; + +const STORAGE_KEY = 'settings'; + +@Injectable({ + providedIn: 'root' +}) +export class SettingsService { + + setDeleteButton(checked: boolean) { + const settings = this.settings; + settings.displayDeleteButton = checked; + this.settings = settings; + } + + setSortTodos(checked: boolean) { + const settings = this.settings; + settings.sortTodos = checked; + this.settings = settings; + } + + get settings(): Settings { + const settingsJson = localStorage.getItem(STORAGE_KEY); + + if (!settingsJson) { + const settings = { + sortTodos: false, + displayDeleteButton: true + }; + + this.settings = settings; + return settings; + } + + return JSON.parse(settingsJson) as Settings; + } + + set settings(settings: Settings) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); + } +} diff --git a/src/app/settings/settings.ts b/src/app/settings/settings.ts new file mode 100644 index 0000000..9a9dd2f --- /dev/null +++ b/src/app/settings/settings.ts @@ -0,0 +1,4 @@ +export interface Settings { + sortTodos: boolean; + displayDeleteButton: boolean; +} diff --git a/src/app/todo/add-todo.component.ts b/src/app/todo/add-todo.component.ts new file mode 100644 index 0000000..b6993cf --- /dev/null +++ b/src/app/todo/add-todo.component.ts @@ -0,0 +1,62 @@ +import {Component, inject, OnInit} from "@angular/core"; +import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; +import {TodoService} from "./todo.service"; +import {Router} from "@angular/router"; + + +@Component({ + standalone: true, + selector: 'app-add-todo', + imports: [ + ReactiveFormsModule, + ], + template: ` +
+
+ + +
+
+ + +
+
+ + +
+ +
+ ` +}) +export class AddTodoComponent implements OnInit { + form!: FormGroup; + + todoService: TodoService = inject(TodoService); + + router: Router = inject(Router); + + defaultDate!: Date; + + ngOnInit() { + const today = new Date(); + const tomorrow = new Date(today); + tomorrow.setDate(today.getDate() + 1); + + this.form = new FormGroup({ + title: new FormControl('', [Validators.required]), + dueDate: new FormControl(tomorrow.toISOString().split('T')[0], [Validators.required]), + category: new FormControl('', [Validators.required]), + }); + } + + submit() { + const newTodo = { + title: this.form.get('title')?.value, + dueDate: this.form.get('dueDate')?.value, + category: this.form.get('category')?.value, + } + + this.todoService.add(newTodo); + this.router.navigate(['/todos']); + } +} diff --git a/src/app/todo/table/table-filter.component.ts b/src/app/todo/table/table-filter.component.ts new file mode 100644 index 0000000..c766b86 --- /dev/null +++ b/src/app/todo/table/table-filter.component.ts @@ -0,0 +1,34 @@ +import {Component, EventEmitter, inject, Output} from "@angular/core"; +import {TodoService} from "../todo.service"; +import {NgForOf} from "@angular/common"; + + +@Component({ + standalone: true, + selector: 'app-table-filter', + imports: [ + NgForOf + ], + template: ` + + ` +}) +export class TableFilterComponent { + + todoService: TodoService = inject(TodoService); + + categories: string[] = this.todoService.categories; + + @Output() + updateFiler: EventEmitter = new EventEmitter() + + updateFilter(event: Event) { + const inputElement = event.target as HTMLInputElement; + const filterValue = inputElement.value; + + this.updateFiler.emit(filterValue); + } +} diff --git a/src/app/todo/table/todo-table.component.html b/src/app/todo/table/todo-table.component.html new file mode 100644 index 0000000..047ad24 --- /dev/null +++ b/src/app/todo/table/todo-table.component.html @@ -0,0 +1,37 @@ +
+ +
+

No Results found

+

Everything done!

+
+
+

Todos

+ + + + + + + + + + + + + + + + + + + + + + +
StatusIdTitleDue DateCategoryDelete
{{ todo.id }}{{ todo.title }}{{ todo.dueDate }}{{ todo.category }} + +
+
+
diff --git a/src/app/todo/table/todo-table.component.ts b/src/app/todo/table/todo-table.component.ts new file mode 100644 index 0000000..ed5d1c2 --- /dev/null +++ b/src/app/todo/table/todo-table.component.ts @@ -0,0 +1,62 @@ +import {Component, inject, OnInit} from "@angular/core"; +import {TodoService} from "../todo.service"; +import {Todo} from "../todo"; +import {NgForOf, NgIf} from "@angular/common"; +import {TableFilterComponent} from "./table-filter.component"; +import {SettingsService} from "../../settings/settings.service"; + + +@Component({ + selector: 'app-todo', + templateUrl: './todo-table.component.html', + imports: [ + NgForOf, + TableFilterComponent, + NgIf, + + ], + standalone: true +}) +export class TodoTableComponent implements OnInit { + todoService: TodoService = inject(TodoService); + + settingsService: SettingsService = inject(SettingsService); + + _todos: Todo[] = []; + + isFiltered: boolean = false; + + ngOnInit() { + this.todos = this.todoService.todos; + } + + deleteTodo(todo: Todo) { + this.todoService.delete(todo); + + this.todos = this.todoService.todos; + } + + toggleCompleted(todo: Todo) { + todo.completed = !todo.completed; + + this.todoService.set(this._todos); + this.ngOnInit(); + } + + updateFilter(filter: string) { + this.isFiltered = filter !== ''; + + this.todos = this.todoService.todos.filter(todo => todo.category.toLowerCase().includes(filter.toLowerCase())); + } + + get displayDeleteButton(): boolean { + return this.settingsService.settings.displayDeleteButton + } + + set todos(todos: Todo[]) { + if (this.settingsService.settings.sortTodos) { + todos = todos.sort((a, b) => Number(a.completed) - Number(b.completed)); + } + this._todos = todos; + } +} diff --git a/src/app/todo/todo.service.ts b/src/app/todo/todo.service.ts new file mode 100644 index 0000000..974b912 --- /dev/null +++ b/src/app/todo/todo.service.ts @@ -0,0 +1,44 @@ +import {Injectable} from "@angular/core"; +import {Todo} from "./todo"; + +const STORAGE_KEY = 'todos'; + +@Injectable({ + providedIn: 'root' +}) +export class TodoService { + get todos(): Todo[] { + const todos = localStorage.getItem(STORAGE_KEY); + + return todos ? JSON.parse(todos) as Todo[] : []; + } + + get categories(): string[] { + return this.todos.map(todo => todo.category).filter((value, index, self) => self.indexOf(value) === index); + } + + delete(todo: Todo): void { + const todos = this.todos; + const index = todos.findIndex(t => t.id === todo.id); + todos.splice(index, 1); + this.set(todos); + } + + add(newTodo: { dueDate: Date; title: string; category: string }) { + const todo = newTodo as Todo; + todo.id = this.todos.length + 1; + todo.completed = false; + this.set([...this.todos, todo]); + } + + set(todo: Todo[]): void { + localStorage.setItem(STORAGE_KEY, JSON.stringify(todo)); + } + + toggleCompleted(todo: Todo) { + const todos = this.todos; + const index = todos.findIndex(t => t.id === todo.id); + todos[index].completed = !todos[index].completed; + this.set(todos); + } +} diff --git a/src/app/todo/todo.ts b/src/app/todo/todo.ts new file mode 100644 index 0000000..c6d368e --- /dev/null +++ b/src/app/todo/todo.ts @@ -0,0 +1,7 @@ +export interface Todo { + id: number; + title: string; + completed: boolean; + dueDate: Date; + category: string; +} diff --git a/src/index.html b/src/index.html index 161a0a6..071b116 100644 --- a/src/index.html +++ b/src/index.html @@ -6,6 +6,7 @@ +