Skip to content
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
97 changes: 4 additions & 93 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@ <h1 id="user-title" data-username="eastjun">
</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>
<button class="ripple user-delete-button" data-action="deleteUser">
삭제 -
</button>

</div>
</section>

Expand All @@ -36,93 +29,11 @@ <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>
<ul class="todo-list"></ul>
</section>
<div class="count-container">
<span class="todo-count">총 <strong>0</strong> 개</span>
<ul class="filters">
<li>
<a href="#" class="all selected">전체보기</a>
</li>
<li>
<a href="#active" class="active">해야할 일</a>
</li>
<li>
<a href="#completed" class="completed">완료한 일</a>
</li>
</ul>
<button class="clear-completed">모두 삭제</button>
</div>
<div class="count-container"></div>
</section>
</div>
<script src="./src/js/index.js"></script>
<script src="./src/js/main.js" type="module"></script>
</body>
</html>
56 changes: 56 additions & 0 deletions src/js/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { $, $$ } from "./util/util.js";

import { Title } from "./component/Title.js"
import { TodoFilter } from "./component/TodoFilter.js";
import { TodoInput } from "./component/TodoInput.js";
import { UserList } from "./component/UserList.js";
import { TodoList } from "./component/TodoList.js";
import { userAPI, todoAPI } from "./api/api.js";

import UserState from "../store/userState.js";
import FilterState from "../store/FilterState.js";
import SelectedUserState from "../store/SelectedUserState.js";
import CountState from "../store/countState.js";

export default class App{
constructor(){
this.selectedUserState = new SelectedUserState;
this.userState = new UserState;
this.filterState = new FilterState;
this.init();
}
async init(){
//conponent
this.title = new Title(this.selectedUserState);
this.userList = new UserList(this.userState, this.selectedUserState);
//console.log(this.selectedUserState)
this.todoInput = new TodoInput(this.selectedUserState);
this.todoList = new TodoList(this.selectedUserState, this.filterState);
this.todoFilter = new TodoFilter(this.selectedUserState, this.filterState);
//subscribe

this.selectedUserState.subscribe(this.title);
this.selectedUserState.subscribe(this.userList);
this.selectedUserState.subscribe(this.todoFilter);
this.selectedUserState.subscribe(this.todoList);


this.userState.subscribe(this.userList);
//this.userState.subscribe(this.todoList);
//this.userState.subscribe(this.todoFilter);

// this.todoState.subscribe(this.todoList);
// this.todoState.subscribe(this.todoFilter);

this.filterState.subscribe(this.todoList);
this.filterState.subscribe(this.todoFilter);

//this.countState.subscribe(this.todoFilter);
//초기데이터
const initData = await userAPI.getAllUser();
this.userState.set(initData);
this.selectedUserState.set(initData[0]);

}

}
44 changes: 44 additions & 0 deletions src/js/api/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { HTTP_REQUEST } from "./util.js";

const BASE_URL = 'https://js-todo-list-9ca3a.df.r.appspot.com/api/users';


export const userAPI = {
async getAllUser(){
return await fetch(BASE_URL).then(data => data.json());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then-catch대신 async-await를 사용 하신 것 같습니다 !
then 사용 대신 변수에 담아서 반환하셔도 될 것 같아요 !

    try {
      const res = await fetch(BASE_URL);
      return res.json();
    } catch (error) {
      // Error
    }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇네요! async-await적용을 전체를 다 하지못했네요~
수정하겠습니당!

},
async deleteUser(id){
return await fetch(`${BASE_URL}/${id}`,HTTP_REQUEST.DELETE());
},
async addUser(data){
return await fetch(`${BASE_URL}`,HTTP_REQUEST.POST(data)).then(data=>data.json());
},
async getUser(id){
return await fetch(`${BASE_URL}/${id}`).then(data => data.json());
}
}


export const todoAPI = {
async getTodoItem(id){
return await fetch(`${BASE_URL}/${id}/items`).then(data => data.json);
},
async addTodoItem(id, item){
return await fetch(`${BASE_URL}/${id}/items`, HTTP_REQUEST.POST(item));
},
async deleteAllTodoItem(id){
return await fetch(`${BASE_URL}/${id}/items`,HTTP_REQUEST.DELETE());
},
async deleteTodoItem(userId, itemId){
return await fetch(`${BASE_URL}/${userId}/items/${itemId}`,HTTP_REQUEST.DELETE());
},
async updateTodoItem(userId, itemId, newItem){
return await fetch(`${BASE_URL}/${userId}/items/${itemId}`, HTTP_REQUEST.PUT(newItem));
},
async updateTodoPriority(userId, itemId, priority){
return await fetch(`${BASE_URL}/${userId}/items/${itemId}/priority`, HTTP_REQUEST.PUT(priority));
},
async toggleTodoItem(userId, itemId){
return await fetch(`${BASE_URL}/${userId}/items/${itemId}/toggle`, HTTP_REQUEST.PUT())
}
}
28 changes: 28 additions & 0 deletions src/js/api/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const HTTP_REQUEST ={

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

따로 유틸 파일로 분리하셔서 사용하기 편리해 보입니다!

POST(data){
return {
method : "POST",
headers :{
'Content-Type' :'application/json'
},
body: JSON.stringify(data)
}
},
DELETE(){
return {
method : "DELETE",

}
},
PUT(data){
return {
method : "PUT",
headers :{
'Content-Type' :'application/json'
},
body:JSON.stringify(data)
}
}
}

export {HTTP_REQUEST};
22 changes: 22 additions & 0 deletions src/js/component/Title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Observer from "../core/observer.js";
import { $ } from "../util/util.js";

export class Title extends Observer{
constructor(selectedUserIdState){
super();
this.state = selectedUserIdState;
}
template(){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

template가 먼저 보이는거 좋아요:)

const name = this.state.get().name;
return `
<span><strong>${name}</strong>'s Todo List</span>
`
}
render(){
const target = $("#user-title");
target.innerHTML = this.template();
}
update(){
this.render();
}
}
72 changes: 72 additions & 0 deletions src/js/component/TodoFilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Observer from "../core/observer.js";
import { $, $$ } from "../util/util.js";
import { FILTER } from "../constants/constants.js";
import { todoAPI, userAPI } from "../api/api.js";

export class TodoFilter extends Observer{
constructor(selectedUserState, filterState){
super();
this.selectedUserState = selectedUserState;
this.filterState = filterState;
}
templete(){
const filter = this.filterState.get();
const todo = this.selectedUserState.get().todoList;
const count = this.counTotalTodo(filter, todo);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coun 오타가 있습니다

return `
<span class="todo-count">총 <strong>${count}</strong> 개</span>
<ul class="filters">
<li class="li-filter">
<a href="#" class="all ${filter =="all"?"selected":""}">전체보기</a>
</li>
<li class="li-filter">
<a href="#active" class="active ${filter =="active"?"selected":""}">해야할 일</a>
</li>
<li class="li-filter">
<a href="#completed" class="completed ${filter =="completed"?"selected":""}">완료한 일</a>
</li>
</ul>
<button class="clear-completed">모두 삭제</button>

`
}
render(){
const target = $(".count-container");
target.innerHTML = this.templete();
this.mounted();
}
mounted(){
const filterBtn = $$('.li-filter');
filterBtn.forEach(btn => btn.addEventListener('click',this.onFilterChange.bind(this)));

const deleteAllBtn = $('.clear-completed');
deleteAllBtn.addEventListener('click', this.onDeleteAllTodo.bind(this));
}
update(){
this.render();
}
async onDeleteAllTodo(){
const selectedId = this.selectedUserState.get()._id;
const response = await todoAPI.deleteAllTodoItem(selectedId);
if(response.ok){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응답코드 체크는 만드신 api파일에서 확인해주시면 더 간결해 보일 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 넵~ 수정해야겠네요 ㅎㅎ

const data = await userAPI.getUser(selectedId);
this.selectedUserState.set(data);
}
}
onFilterChange(e){
const mode= e.target.className.replace('selected','').trim();
this.filterState.set(mode);
}
counTotalTodo(filter, todo){
if(filter ==FILTER.ALL){
return todo.length;
}

if(filter == FILTER.ACTIVE){
return todo.filter(item => !item.isCompleted).length
}
if(filter == FILTER.COMPLETED){
return todo.filter(item => item.isCompleted).length
}
}
}
30 changes: 30 additions & 0 deletions src/js/component/TodoInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//import Observer from "../core/observer.js";
import { $ } from "../util/util.js";
import { userAPI, todoAPI } from "../api/api.js";


export class TodoInput {
constructor(selectedUserState){
this.selectedUserState = selectedUserState;
this.addEvent();
}
addEvent(){
const target = $(".new-todo");
target.addEventListener('keyup', this.onAddTodo.bind(this));
}
async onAddTodo(e){
if(e.key==='Enter'){
const value = e.target.value;
const id = this.selectedUserState.get()._id;
if(value.length <2 ){
alert("콘텐츠의 길이는 최소 2글자이상이어야 합니다.");
return;
}
await todoAPI.addTodoItem(id, {"contents":value});
const data = await userAPI.getUser(id);
this.selectedUserState.set(data);
e.target.value = "";
}
}

}
Loading