Skip to content

Commit

Permalink
Merge pull request #150 from Konkuk-KUIT/hamxxn
Browse files Browse the repository at this point in the history
[9주차]
  • Loading branch information
Turtle-Hwan authored Nov 30, 2024
2 parents ff17533 + 5443985 commit 7f72a8c
Show file tree
Hide file tree
Showing 6 changed files with 487 additions and 0 deletions.
133 changes: 133 additions & 0 deletions week9/hamxxn/todo/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const todoListEl = document.getElementById("todoList");
const todoInputEl = document.getElementById("todoInput");
const API_URL = "http://localhost:3000/todos";
fetch(API_URL)
.then((response) => response.json())
.then((data) => renderTodo(data))
.catch((error) => console.log("error: " + error));
const fetchTodos = () => __awaiter(this, void 0, void 0, function* () {
const response = yield fetch(API_URL);
return yield response.json();
});
//post 요청
const fetchPost = (newToDo) => __awaiter(this, void 0, void 0, function* () {
return yield fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(Object.assign({}, newToDo)),
}).then((response) => response.json());
});
const fetchDelete = (todoId) => {
return fetch(API_URL + "/" + todoId, {
method: "DELETE",
});
};
//patㅊh
const fetchPatch = (todoId, newTitle) => {
return fetch(API_URL + "/" + todoId, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: newTitle,
}),
});
};
//만약 null일 시 return 하도록 return
const renderTodo = (newTodos) => {
if (!todoListEl)
return;
todoListEl.innerHTML = "";
newTodos.forEach((todo) => {
const listEl = document.createElement("li");
listEl.textContent = todo.title;
listEl.id = `todo-${todo.id}`;
const deleteEl = document.createElement("span");
deleteEl.textContent = "🗑️";
deleteEl.onclick = () => deleteTodo(todo.id);
const updateEl = document.createElement("span");
updateEl.textContent = "✏️";
updateEl.onclick = () => updateTodo(todo.id, todo.title);
listEl.append(deleteEl);
listEl.append(updateEl);
todoListEl.append(listEl);
});
};
//null 처리 필요
const addTodo = () => {
if (todoInputEl == null)
return;
const title = todoInputEl.value;
const date = new Date();
const createdAt = date.toDateString();
if (!title)
return;
//Omit <Todo,"completed"> => 그냥 개념만 알고 가기 ㅇㅇ
const newTodo = {
id: date.getTime(),
title,
createdAt,
completed: false,
};
fetchPost(newTodo)
.then(() => {
todoInputEl.value = "";
return fetchTodos();
})
.then((data) => renderTodo(data));
};
const deleteTodo = (todoId) => {
if (todoId == null)
return;
fetchDelete(todoId)
.then(() => fetchTodos())
.then((data) => renderTodo(data));
};
const updateTodo = (todoId, title) => {
//id에 해당하는 아이템 불러옴
const todoItem = document.querySelector(`#todo-${todoId}`);
if (!todoItem)
return;
todoItem.innerHTML = "";
const updateInput = document.createElement("input");
updateInput.type = "text";
updateInput.value = title;
todoItem.append(updateInput);
const updateTodoItem = (event) => {
if (event.key === "Enter") {
const newTitle = updateInput.value.trim();
if (!newTitle) {
alert("Todo의 title을 입력해주세요.");
return;
}
updateToDoTitle(todoId, updateInput.value)
.then(() => {
todoItem.innerHTML = "";
return fetchTodos();
})
.then((data) => renderTodo(data))
.catch((error) => {
console.log("error: ", error);
});
}
};
updateInput.addEventListener("keydown", updateTodoItem);
};
//DB 수정
const updateToDoTitle = (todoId, newTitle) => {
if (!newTitle)
return Promise.reject(new Error("title cannot be empty"));
return fetchPatch(todoId, newTitle);
};
147 changes: 147 additions & 0 deletions week9/hamxxn/todo/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
const todoListEl = document.getElementById("todoList") as HTMLInputElement;
const todoInputEl = document.getElementById("todoInput") as HTMLInputElement;

const API_URL = "http://localhost:3000/todos";

//Todo 인터페이스 만들기0
interface ToDo {
id: number;
title: string;
createdAt: string;
completed: boolean;
}

fetch(API_URL)
.then((response) => response.json())
.then((data) => renderTodo(data))
.catch((error) => console.log("error: " + error));

const fetchTodos = async (): Promise<ToDo[]> => {
const response = await fetch(API_URL);
return await response.json();
};

//post 요청
const fetchPost = async (newToDo: ToDo): Promise<ToDo[]> => {
return await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...newToDo }),
}).then((response) => response.json());
};
const fetchDelete = (todoId: number): Promise<Response> => {
return fetch(API_URL + "/" + todoId, {
method: "DELETE",
});
};

//patㅊh
const fetchPatch = (todoId: number, newTitle: string): Promise<Response> => {
return fetch(API_URL + "/" + todoId, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: newTitle,
}),
});
};

//만약 null일 시 return 하도록 return
const renderTodo = (newTodos: ToDo[]): void => {
if (!todoListEl) return;
todoListEl.innerHTML = "";
newTodos.forEach((todo: ToDo) => {
const listEl = document.createElement("li");
listEl.textContent = todo.title;
listEl.id = `todo-${todo.id}`;

const deleteEl = document.createElement("span");
deleteEl.textContent = "🗑️";
deleteEl.onclick = () => deleteTodo(todo.id);

const updateEl = document.createElement("span");
updateEl.textContent = "✏️";
updateEl.onclick = () => updateTodo(todo.id, todo.title);

listEl.append(deleteEl);
listEl.append(updateEl);
todoListEl.append(listEl);
});
};

//null 처리 필요
const addTodo = (): void => {
if (todoInputEl == null) return;
const title = todoInputEl.value;
const date = new Date();
const createdAt = date.toDateString();

if (!title) return;
//Omit <Todo,"completed"> => 그냥 개념만 알고 가기 ㅇㅇ
const newTodo: ToDo = {
id: date.getTime(),
title,
createdAt,
completed: false,
};
fetchPost(newTodo)
.then(() => {
todoInputEl.value = "";
return fetchTodos();
})
.then((data) => renderTodo(data));
};

const deleteTodo = (todoId: number): void => {
if (todoId == null) return;

fetchDelete(todoId)
.then(() => fetchTodos())
.then((data) => renderTodo(data));
};

const updateTodo = (todoId: number, title: string): void => {
//id에 해당하는 아이템 불러옴
const todoItem = document.querySelector(`#todo-${todoId}`) as HTMLElement;
if (!todoItem) return;
todoItem.innerHTML = "";

const updateInput = document.createElement("input");
updateInput.type = "text";
updateInput.value = title;
todoItem.append(updateInput);

const updateTodoItem = (event: { key: string }) => {
if (event.key === "Enter") {
const newTitle = updateInput.value.trim();
if (!newTitle) {
alert("Todo의 title을 입력해주세요.");
return;
}
updateToDoTitle(todoId, updateInput.value)
.then(() => {
todoItem.innerHTML = "";
return fetchTodos();
})
.then((data) => renderTodo(data))
.catch((error) => {
console.log("error: ", error);
});
}
};

updateInput.addEventListener("keydown", updateTodoItem);
};

//DB 수정
const updateToDoTitle = (
todoId: number,
newTitle: string
): Promise<Response> => {
if (!newTitle) return Promise.reject(new Error("title cannot be empty"));
return fetchPatch(todoId, newTitle);
};
16 changes: 16 additions & 0 deletions week9/hamxxn/todo/db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"todos": [
{
"id": "bfbe",
"title": "",
"createdAt": "Tue Nov 26 2024",
"completed": false
},
{
"id": 1732586913655,
"title": "ㅅㅂ",
"createdAt": "Tue Nov 26 2024",
"completed": false
}
]
}
60 changes: 60 additions & 0 deletions week9/hamxxn/todo/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: #f5f5f5;
font-family: "Arial", sans-serif;
}
.app {
width: 400px;
margin: 30px auto;
background-color: #fff;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.header {
font-size: 1.5em;
margin-bottom: 20px;
text-align: center;
}
.inputContainer {
display: flex;
}
#todoInput {
flex: 1;
padding: 10px;
font-size: 1em;
border: 1px solid #ddd;
}
button {
background-color: #28a745;
color: #fff;
padding: 10px;
font-size: 1em;
cursor: pointer;
}
button:hover {
background-color: #218838;
}
ul {
list-style-type: none;
}
li {
padding: 10px;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
}
li:last-child {
border-bottom: none;
}
.deleteBtn {
cursor: pointer;
color: #ff0000;
}
.deleteBtn:hover {
text-decoration: underline;
}
19 changes: 19 additions & 0 deletions week9/hamxxn/todo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Todo App</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="app">
<div class="header">My Todos</div>
<div class="inputContainer">
<input id="todoInput" placeholder="What needs to be done?" />
<button onclick="addTodo()">Add</button>
</div>
<ul id="todoList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
Loading

0 comments on commit 7f72a8c

Please sign in to comment.