Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2단계 - todo list] 에어(김준서) 미션 제출합니다. #6

Open
wants to merge 13 commits into
base: kjunseo
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,29 @@

## 🎯 요구사항

- [ ] 1. User 추가하기
- [ ] 2. User의 투두리스트 불러오기
- [ ] 3. User 삭제하기
- [ ] 3. todoItem 추가하기
- [ ] 4. todoItem 불러오기
- [ ] 5. todoItem complete하기
- [ ] 6. todoItem 삭제하기
- [ ] 7. todoItem contents 내용 수정하기
- [x] 1. User 추가하기
- [x] 2. User의 투두리스트 불러오기
- [x] 3. User 삭제하기
- [x] 4. todoItem 추가하기
- [x] 5. todoItem 불러오기
- [x] 6. todoItem complete하기
- [x] 7. todoItem 삭제하기
- [x] 8. todoItem contents 내용 수정하기

<br/>

## 🎯🎯 심화 요구사항

- [ ] 1. fetch api 사용하는 부분을 async await을 사용하여 리팩토링하기.
- [ ] 2. github issue에서 라벨을 붙이는 것처럼, 우선순위에 따라서 label를 추가하기.
- [ ] 3. ES6 impot & export를 이용해 자바스크립트 파일을 리팩토링하기.
- [x] 1. fetch api 사용하는 부분을 async await을 사용하여 리팩토링하기.
- [x] 2. github issue에서 라벨을 붙이는 것처럼, 우선순위에 따라서 label를 추가하기.
- [x] 3. ES6 impot & export를 이용해 자바스크립트 파일을 리팩토링하기.

<br/>

## 🕵️‍♂️ 제약사항

- [ ] 1. User의 이름은 최소 2글자 이상이어야 한다.
- [ ] 2. TodoItem Contents는 최소 2글자 이상이어야 한다.
- [x] 1. User의 이름은 최소 2글자 이상이어야 한다.
- [x] 2. TodoItem Contents는 최소 2글자 이상이어야 한다.

<br/>

Expand Down
72 changes: 1 addition & 71 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
<body>
<div id="app">
<h1 id="user-title" data-username="eastjun">
<span><strong>eastjun</strong>'s Todo List</span>
</h1>
<section>
<div id="user-list">
<button class="ripple active">makerjun</button>
<button class="ripple">eastjun</button>
<button class="ripple user-create-button" data-action="createUser">
+ 유저 생성
</button>
Expand All @@ -37,73 +34,6 @@ <h1 id="user-title" data-username="eastjun">
</section>
<section class="main">
<ul class="todo-list">
<li>
<div class="view">
<label class="label">
<div class="animated-background">
<div class="skel-mask-container">
<div class="skel-mask"></div>
</div>
</div>
</label>
</div>
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox" />
<label class="label">
<select class="chip select">
<option value="0" selected>순위</option>
<option value="1">1순위</option>
<option value="2">2순위</option>
</select>
해야할 아이템
</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox" />
<label class="label">
<span class="chip primary">1순위</span>
해야할 아이템
</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox" />
<label class="label">
<span class="chip secondary">2순위</span>
해야할 아이템
</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li class="completed">
<div class="view">
<input class="toggle" type="checkbox" checked />
<label class="label">완료된 아이템 </label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li class="editing">
<div class="view">
<input class="toggle" type="checkbox" checked />
<label class="label">
<span class="chip secondary">2순위</span>
수정중인 아이템
</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
</ul>
</section>
<div class="count-container">
Expand All @@ -123,6 +53,6 @@ <h1 id="user-title" data-username="eastjun">
</div>
</section>
</div>
<script src="./src/js/index.js"></script>
<script type="module" src="./src/js/index.js"></script>
</body>
</html>
224 changes: 220 additions & 4 deletions src/js/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,223 @@
const onUserCreateHandler = () => {
const userName = prompt("추가하고 싶은 이름을 입력해주세요.");
import * as form from "./requestForm.js";
import {todoTemplate} from "./todoItemTemplate.js";

const BASE_URL = 'https://js-todo-list-9ca3a.df.r.appspot.com';
const userTitle = document.getElementById("user-title");
const userList = document.getElementById("user-list");
const userCreateButton = document.querySelector(".user-create-button");
const userDeleteButton = document.querySelector(".user-delete-button");
const todoList = document.querySelector(".todo-list");
const todoInput = document.querySelector(".new-todo");
const deleteAllButton = document.querySelector(".clear-completed");

async function showAllUsers(userId) {
const showAllUsersResponse = await fetch(BASE_URL + "/api/users", form.getRequestForm());
const allUsers = await showAllUsersResponse.json();
for (let i = 0; i < allUsers.length; i++) {
if (document.getElementById(allUsers[i]._id) == null) {
const userButton = document.createElement("button");
userButton.id = allUsers[i]._id;
userButton.innerText = allUsers[i].name;
userButton.classList.add("ripple");
userList.prepend(userButton);
}
}
showActiveUser(userId);
}

function showActiveUser(userId) {
let activeUser = document.getElementById(userId);
if (activeUser == null) {
const defaultUser = userList.firstChild;
defaultUser.classList.add("active");
activeUser = defaultUser;
userLoad(activeUser.id);
} else {
active(activeUser);
}
showActiveUserTodo(activeUser);
}

async function userLoad(userId) {
userTitle.removeChild(userTitle.firstChild);
const userLoadResponse = await fetch(BASE_URL + "/api/users/" + userId, form.getRequestForm());
const user = await userLoadResponse.json();
userTitle.insertAdjacentHTML("beforeend", `<span><strong>${user.name}</strong>'s Todo List</span>`);
}

function active(activeUser) {
const activeUsers = document.getElementsByClassName("active");
for (let i = 0; i < activeUsers.length; i++) {
activeUsers[i].classList.remove("active");
}
activeUser.classList.add("active");
userLoad(activeUser.id);
}

async function userCreateHandler() {
const userName = prompt("추가하고 싶은 이름을 입력해주세요.");
if (userName.length >= 2) {
const userForm = form.createUserForm(userName);
const createdUserId = await createUser(userForm);
await showAllUsers(createdUserId);
} else {
alert("이름은 두 글자 이상이어야 합니다!");
}
}

async function createUser(userForm) {
const createdUserResponse = await fetch(BASE_URL + "/api/users", userForm);
const createdUser = await createdUserResponse.json();
return createdUser._id;
}

function selectUser(event) {
const button = event.target.closest("button");
if (button.id != null) {
const activeUser = event.target;
active(activeUser);
showActiveUserTodo(activeUser);
}
}

async function showActiveUserTodo(activeUser) {
const todoByUserIdResponse = await fetch(BASE_URL + "/api/users/" + activeUser.id, form.getRequestForm());
const todo = await todoByUserIdResponse.json();
const activeUserTodo = todo.todoList;
removeOtherTodo();
for (let i = 0; i < activeUserTodo.length; i++) {
const item = activeUserTodo[i];
todoList.insertAdjacentHTML("beforeend", todoTemplate(item));
}
updateCount();
}

function removeOtherTodo() {
while (todoList.hasChildNodes()) {
todoList.removeChild(todoList.firstChild);
}
}

async function deleteUserById() {
const activeUser = document.querySelector(".active");
await fetch(BASE_URL + "/api/users/" + activeUser.id, form.deleteForm());
userDeleteButton.classList.remove("active");
const deletedUser = document.getElementById(activeUser.id);
userList.removeChild(deletedUser);
showActiveUser();
}

async function addTodoByUser(event) {
const content = event.target.value;
if (event.key === "Enter") {
if (content.length < 2) {
alert("내용은 2글자 이상이어야합니다!");
return;
}
const activeUser = document.querySelector(".active");
const addTodoResponse = await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items", form.addContentForm(content));
const newTodo = await addTodoResponse.json();
todoList.insertAdjacentHTML("beforeend", todoTemplate(newTodo));
todoInput.value = "";
updateCount();
}
}

async function editTodoContent(activeUser, itemId, content) {
const editTodoResponse = await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items/" + itemId, form.editContentForm(content));
return await editTodoResponse.json();
}

async function toggleComplete(activeUser, itemId) {
const toggleCompleteResponse = await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items/" + itemId + "/toggle", form.toggleCompleteForm());
return await toggleCompleteResponse.json();
}

async function deleteAll() {
const activeUser = document.querySelector(".active");
await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items/", form.deleteForm());
showActiveUserTodo(activeUser);
}

async function deleteOne(activeUser, itemId) {
await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items/" + itemId, form.deleteForm());
}

async function changePriority(activeUser, itemId, priority) {
await fetch(BASE_URL + "/api/users/" + activeUser.id + "/items/" + itemId + "/priority", form.changePriorityForm(priority));
}

const userCreateButton = document.querySelector('.user-create-button')
userCreateButton.addEventListener('click', onUserCreateHandler)
function updateCount() {
let count = 0;
const allTodoList = todoList.childNodes;
for (let todo of allTodoList) {
count++;

}
document.querySelector(".todo-count").innerHTML = countTemplate(count);
}

function countTemplate(count) {
return `총<strong>${count}</strong>개`;
}

showAllUsers();

userCreateButton.addEventListener("click", userCreateHandler);
userDeleteButton.addEventListener("click", deleteUserById)
userList.addEventListener("click", selectUser);
todoInput.addEventListener("keypress", addTodoByUser);
deleteAllButton.addEventListener("click", deleteAll);

todoList.addEventListener("click", async function (event) {
const activeUser = document.querySelector(".active");
const li = event.target.closest("li");
const itemId = li.id;
if (event.target.classList.contains("toggle")) {
await toggleComplete(activeUser, itemId);
showActiveUserTodo(activeUser);
}
if (event.target.classList.contains("destroy")) {
await deleteOne(activeUser, itemId);
showActiveUserTodo(activeUser);
}
});

todoList.addEventListener("dblclick", function (event) {
const li = event.target.closest("li");
const label = li.getElementsByClassName("label")[0];
const editInput = li.getElementsByClassName("edit")[0];
const originalValue = label.innerText;

li.classList.toggle("editing");

editInput.addEventListener("keyup", async function (event) {
const item = event.target;
const itemId = item.parentNode.id;
const content = item.value;
if (event.key === "Enter" && content.length >= 2) {
const activeUser = document.querySelector(".active");
await editTodoContent(activeUser, itemId, content);
showActiveUserTodo(activeUser);
li.classList.remove("editing");
}
if (event.key === "Escape") {
event.target.value = originalValue;
li.classList.remove("editing");
}
});
});

todoList.addEventListener("change", async function (event) {
const activeUser = document.querySelector(".active");
const itemId = event.target.closest("li").id;
const option = event.target;
const selectedOption = option.options[option.selectedIndex].value;
if (selectedOption === "1") {
await changePriority(activeUser, itemId, "FIRST");
showActiveUserTodo(activeUser);
} else if (selectedOption === "2") {
await changePriority(activeUser, itemId, "SECOND");
showActiveUserTodo(activeUser);
}
});
Loading