Skip to content

Commit

Permalink
import tasks from json
Browse files Browse the repository at this point in the history
  • Loading branch information
jyannick committed Dec 23, 2024
1 parent 3307d61 commit 848388f
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
RiQuestionLine,
RiQuestionMark,
RiFileDownloadLine,
RiFileUploadLine,
} from 'angular-remix-icon';
import { DragDropModule } from '@angular/cdk/drag-drop';

Expand All @@ -29,6 +30,7 @@ const icons = {
RiQuestionLine,
RiQuestionMark,
RiFileDownloadLine,
RiFileUploadLine,
};

@NgModule({
Expand Down
8 changes: 7 additions & 1 deletion src/app/keyboard-shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions src/app/todo-list/todo-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DELETE_SELECTION,
EDIT,
EXPORT_JSON,
IMPORT_JSON,
MARK_AS_DONE,
NEXT_ITEM,
NEXT_ITEM2,
Expand Down Expand Up @@ -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;
Expand Down
37 changes: 36 additions & 1 deletion src/app/todo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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
Expand All @@ -100,3 +134,4 @@ export class TodoService {
return todos?.length > 0 ? todos[todos.length - 1].id + 1 : 1;
}
}

26 changes: 26 additions & 0 deletions src/app/todo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
7 changes: 7 additions & 0 deletions src/app/toolbar/toolbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
>
<rmx-icon name="file-download-line" class="button-icon"></rmx-icon>
</div>
<div
class="button"
title="Import tasks from file"
(click)="importTasks()"
>
<rmx-icon name="file-upload-line" class="button-icon"></rmx-icon>
</div>
<div class="button" title="Help" (click)="toggleHelpScreen()">
<rmx-icon name="keyboard-line" class="button-icon"></rmx-icon>
</div>
Expand Down
4 changes: 4 additions & 0 deletions src/app/toolbar/toolbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ export class ToolbarComponent {
exportTasks() {
this.todoService.exportJson();
}

importTasks() {
this.todoService.importJson();
}
}

0 comments on commit 848388f

Please sign in to comment.