From 848388fac5d38001871d513501a0e8ae71571120 Mon Sep 17 00:00:00 2001 From: Yannick Jeandroz Date: Mon, 23 Dec 2024 18:22:04 +0100 Subject: [PATCH] import tasks from json --- src/app/app.module.ts | 2 ++ src/app/keyboard-shortcuts.ts | 8 ++++- src/app/todo-list/todo-list.component.ts | 7 +++++ src/app/todo.service.ts | 37 +++++++++++++++++++++++- src/app/todo.ts | 26 +++++++++++++++++ src/app/toolbar/toolbar.component.html | 7 +++++ src/app/toolbar/toolbar.component.ts | 4 +++ 7 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8fb2496..cd18b61 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,6 +11,7 @@ import { RiQuestionLine, RiQuestionMark, RiFileDownloadLine, + RiFileUploadLine, } from 'angular-remix-icon'; import { DragDropModule } from '@angular/cdk/drag-drop'; @@ -29,6 +30,7 @@ const icons = { RiQuestionLine, RiQuestionMark, RiFileDownloadLine, + RiFileUploadLine, }; @NgModule({ diff --git a/src/app/keyboard-shortcuts.ts b/src/app/keyboard-shortcuts.ts index e4fe92b..8ba3622 100644 --- a/src/app/keyboard-shortcuts.ts +++ b/src/app/keyboard-shortcuts.ts @@ -14,6 +14,7 @@ export const EDIT = 'control.e'; export const DELETE_SELECTION = 'control.delete'; export const DELETE_ALL = 'control.shift.delete'; export const EXPORT_JSON = 'control.shift.e'; +export const IMPORT_JSON = 'control.shift.i'; export const HELP_SCREEN = 'control.h'; export interface Action { @@ -89,10 +90,15 @@ export const ACTIONS: Action[] = [ details: 'all done items will be lost forever', }, { - name: 'download JSON', + name: 'export JSON', shortcut: EXPORT_JSON, details: 'all items will be exported to a file', }, + { + name: 'import JSON', + shortcut: IMPORT_JSON, + details: 'all items from a file will be loaded', + }, { name: 'show this help screen', shortcut: HELP_SCREEN, diff --git a/src/app/todo-list/todo-list.component.ts b/src/app/todo-list/todo-list.component.ts index 76ecab5..de5e5cf 100644 --- a/src/app/todo-list/todo-list.component.ts +++ b/src/app/todo-list/todo-list.component.ts @@ -17,6 +17,7 @@ import { DELETE_SELECTION, EDIT, EXPORT_JSON, + IMPORT_JSON, MARK_AS_DONE, NEXT_ITEM, NEXT_ITEM2, @@ -238,6 +239,12 @@ export class TodoListComponent implements OnInit { this.todoService.exportJson(); } + @HostListener(`document:keydown.${IMPORT_JSON}`, ['$event']) + importJson(event?: Event) { + event?.preventDefault(); + this.todoService.importJson(); + } + newTodo(label: string) { this.todoService.addTodo(label); this.isInputDisplayed = false; diff --git a/src/app/todo.service.ts b/src/app/todo.service.ts index 0942287..40bef39 100644 --- a/src/app/todo.service.ts +++ b/src/app/todo.service.ts @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { moveItemInArray } from '@angular/cdk/drag-drop'; -import { Todo } from './todo'; +import { Todo, isATodo } from './todo'; const LOCAL_STORAGE_ITEM = 'yaka-todos'; @@ -84,6 +84,40 @@ export class TodoService { link.click(); } + importJson() { + var fileChooser = document.createElement('input'); + fileChooser.type = "file"; + fileChooser.accept = ".json"; + fileChooser.onchange = (e: Event) => { + if (fileChooser.files){ + this.readJson(fileChooser.files[0]); + } + } + fileChooser.click(); + } + + readJson(file: File) { + var reader = new FileReader(); + reader.onload = () => { + const importedTodos = JSON.parse(String(reader.result)); + if (!Array.isArray(importedTodos)) { + console.log("Incorrect value for imported TODOs:", importedTodos); + return; + } + let isFormatOk = true; + importedTodos.forEach((element: any) => { + if (!isATodo(element)){ + console.log("Incorrect value for imported TODOs:", element); + isFormatOk = false; + } + }); + if (isFormatOk) { + this.todos = importedTodos; + } + } + reader.readAsText(file); + } + private loadLocalStorage() { const savedTodos = localStorage.getItem(LOCAL_STORAGE_ITEM); this.todos = savedTodos @@ -100,3 +134,4 @@ export class TodoService { return todos?.length > 0 ? todos[todos.length - 1].id + 1 : 1; } } + diff --git a/src/app/todo.ts b/src/app/todo.ts index 7a34bd7..e0952c9 100644 --- a/src/app/todo.ts +++ b/src/app/todo.ts @@ -3,3 +3,29 @@ export interface Todo { label: string; done: boolean; } + +export function isATodo(value: any): value is Todo { + if(typeof value !== 'object') { + return false; + } + // check the property exists by "in" operator + if('id' in value === false) { + return false; + } + if(typeof value.id !== 'number') { + return false; + } + if('label' in value === false) { + return false; + } + if(typeof value.label !== 'string') { + return false; + } + if('done' in value === false) { + return false; + } + if(typeof value.done !== 'boolean') { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/app/toolbar/toolbar.component.html b/src/app/toolbar/toolbar.component.html index 44fbf0e..24e35af 100644 --- a/src/app/toolbar/toolbar.component.html +++ b/src/app/toolbar/toolbar.component.html @@ -14,6 +14,13 @@ > +
+ +
diff --git a/src/app/toolbar/toolbar.component.ts b/src/app/toolbar/toolbar.component.ts index 0128049..c241930 100644 --- a/src/app/toolbar/toolbar.component.ts +++ b/src/app/toolbar/toolbar.component.ts @@ -29,4 +29,8 @@ export class ToolbarComponent { exportTasks() { this.todoService.exportJson(); } + + importTasks() { + this.todoService.importJson(); + } }