Skip to content

Commit 803a2b6

Browse files
committed
Merge remote-tracking branch 'todo-list/main' into yoonseo_working
2 parents 50a2ee1 + 30c3404 commit 803a2b6

File tree

8 files changed

+69
-60
lines changed

8 files changed

+69
-60
lines changed

src/App.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,41 @@ import TodoForm from "./components/TodoForm.js";
33
import TodoList from "./components/TodoList.js";
44
import TodoCount from "./components/TodoCount.js";
55
import { setItem } from "./utils/storage.js";
6-
import { TodoCount as TodoCnt, TodoItem } from "./types/todo.js";
6+
import { TodoCount as TodoCnt, TodoList as TodoLi } from "./types/todo.js";
77

88
export default class App {
99
private readonly todoList: TodoList;
1010
private readonly todoCount: TodoCount;
1111

1212
constructor(
1313
private readonly $target: HTMLElement,
14-
private readonly initialState: TodoItem[],
14+
private readonly initialState: TodoLi,
1515
private readonly initialCount: TodoCnt
1616
) {
17-
new Header(this.$target, "Todo List");
17+
new Header($target, "Todo List");
1818

1919
new TodoForm(
20-
this.$target,
20+
$target,
2121
(text: string) => {
22-
const nextState = [...this.todoList.state, { text, isCompleted: false }];
22+
const nextState = [
23+
...this.todoList.state,
24+
{ text, isCompleted: false }
25+
];
2326
this.todoList.setState(nextState);
2427
},
2528
);
2629

2730
this.todoList = new TodoList(
28-
this.$target,
29-
this.initialState,
30-
(state: TodoItem[]) => this.#updateCount(state)
31+
$target,
32+
initialState,
33+
(state: TodoLi) => this.#updateCount(state)
3134
);
3235

33-
this.todoCount = new TodoCount(this.$target, this.initialCount);
36+
this.todoCount = new TodoCount($target, initialCount);
3437
}
3538

3639
// 카운트 업데이트
37-
#updateCount(todoList: TodoItem[]) {
40+
#updateCount(todoList: TodoLi) {
3841
const done = todoList.filter((todo) => todo.isCompleted).length;
3942
const nextState = { total: todoList.length, done };
4043
this.todoCount.setState(nextState);

src/components/Header.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default class Header {
55
private readonly $target: HTMLElement,
66
private readonly text: string
77
) {
8-
this.$target.appendChild(this.$header);
8+
$target.appendChild(this.$header);
99
this.render();
1010
};
1111

src/components/TodoCount.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ export default class TodoCount {
88
private readonly $target: HTMLElement,
99
private readonly initialCount: TodoCnt
1010
) {
11-
this.$target.appendChild(this.$container);
11+
$target.appendChild(this.$container);
1212

13-
if (this.initialCount.total) {
14-
this.state = this.initialCount;
15-
} else this.state = { total: 0, done: 0 };
13+
if (initialCount.total) this.state = initialCount;
14+
else this.state = { total: 0, done: 0 };
1615

1716
this.render();
1817
}

src/components/TodoForm.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default class TodoForm {
77
private readonly $target: HTMLElement,
88
private readonly onSubmit: (text: string) => void
99
) {
10-
this.$target.appendChild(this.$form);
10+
$target.appendChild(this.$form);
1111
this.render();
1212
}
1313

@@ -17,17 +17,17 @@ export default class TodoForm {
1717
<button>추가</button>
1818
`;
1919

20-
if (!this.isInit) {
21-
this.$form.addEventListener("submit", (e) => {
22-
e.preventDefault();
23-
const $todo = this.$form.querySelector<HTMLInputElement>("input[name=todo]");
24-
if (!$todo) return;
25-
const text = $todo.value;
26-
if (text.length > 1) {
27-
$todo.value = "";
28-
this.onSubmit(text);
29-
} else alert("두 글자 이상 입력해주세요");
30-
});
31-
}
20+
if (this.isInit) return;
21+
22+
this.$form.addEventListener("submit", (e) => {
23+
e.preventDefault();
24+
const $todo = this.$form.querySelector<HTMLInputElement>("input[name=todo]");
25+
if (!$todo) return;
26+
const text = $todo.value;
27+
if (text.length > 1) {
28+
$todo.value = "";
29+
this.onSubmit(text);
30+
} else alert("두 글자 이상 입력해주세요");
31+
});
3232
};
3333
}

src/components/TodoList.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { setItem } from "../utils/storage.js";
22
import validation from "../utils/validation.js";
3-
import { TodoItem } from "../types/todo.js";
3+
import { TodoList as TodoLi } from "../types/todo.js";
44

55
export default class TodoList {
6-
state: TodoItem[];
6+
state: TodoLi;
77
private readonly $todoList = document.createElement("div");
88

99
constructor(
1010
private readonly $target: HTMLElement,
11-
private readonly initialState: TodoItem[],
12-
private readonly updateCount: (state: TodoItem[]) => void
11+
private readonly initialState: TodoLi,
12+
private readonly updateCount: (state: TodoLi) => void
1313
) {
14-
this.$target.appendChild(this.$todoList);
14+
$target.appendChild(this.$todoList);
1515

16-
if (Array.isArray(this.initialState)) this.state = this.initialState;
16+
if (Array.isArray(initialState)) this.state = initialState;
1717
else this.state = [];
1818

1919
this.render();
@@ -22,29 +22,29 @@ export default class TodoList {
2222
const target = e.target as HTMLLIElement;
2323
const $li = target.closest("li");
2424

25-
if ($li) {
26-
const newState = [...this.state];
27-
if (typeof $li.dataset.index !== "string") return;
28-
const index = +$li.dataset.index;
25+
if (!$li) return;
2926

30-
if (target.className === "deleteBtn") {
31-
newState.splice(index, 1);
32-
this.setState(newState);
33-
} else if (target.className.includes("todoList")) {
34-
const isCompleted = target.className.includes("completed");
35-
if (isCompleted) target.classList.remove("completed");
36-
else target.classList.add("completed");
37-
newState[index] = {
38-
...newState[index],
39-
isCompleted: !isCompleted,
40-
};
41-
this.setState(newState);
42-
}
27+
const newState = [...this.state];
28+
if (typeof $li.dataset.index !== "string") return;
29+
const index = +$li.dataset.index;
30+
31+
if (target.className === "deleteBtn") {
32+
newState.splice(index, 1);
33+
this.setState(newState);
34+
} else if (target.className.includes("todoList")) {
35+
const isCompleted = target.className.includes("completed");
36+
if (isCompleted) target.classList.remove("completed");
37+
else target.classList.add("completed");
38+
newState[index] = {
39+
...newState[index],
40+
isCompleted: !isCompleted,
41+
};
42+
this.setState(newState);
4343
}
4444
});
4545
}
4646

47-
setState(nextState: TodoItem[]) {
47+
setState(nextState: TodoLi) {
4848
const newState = validation.state(nextState);
4949
this.state = newState;
5050
setItem("todo", JSON.stringify(newState));

src/types/todo.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
export interface TodoItem {
1+
export type StorageKey = "todo" | "count";
2+
3+
export type TodoList = TodoItem[];
4+
5+
interface TodoItem {
26
text: string;
37
isCompleted: boolean;
48
}
59

610
export interface TodoCount {
711
total: number;
812
done: number;
9-
}
13+
}

src/utils/storage.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1+
import { StorageKey } from "../types/todo";
2+
13
const storage = window.localStorage;
24

35
export const setItem = (key: string, value: string) => {
46
try {
57
storage.setItem(key, value);
6-
} catch (error) {
7-
console.log(error);
8+
}
9+
catch (error: unknown) {
10+
if (error instanceof Error) console.log(error);
811
}
912
};
1013

11-
export const getItem = <T>(key: string, defaultValue: T): T => {
14+
export const getItem = <T>(key: StorageKey, defaultValue: T): T => {
1215
try {
1316
const data = storage.getItem(key);
1417
if (data) return JSON.parse(data);
1518
return defaultValue;
1619
} catch (error) {
17-
console.log(error);
20+
if (error instanceof Error) console.log(error);
1821
return defaultValue;
1922
}
2023
};

src/utils/validation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { TodoItem } from "../types/todo.js";
1+
import { TodoList } from "../types/todo.js";
22

33
const validation = {
4-
state(todoList: TodoItem[]) {
4+
state(todoList: TodoList) {
55
return todoList.filter(
66
(todo) =>
77
typeof todo?.text === "string" && typeof todo?.isCompleted === "boolean"

0 commit comments

Comments
 (0)