From 4ff49f91fc41ba593913f33f51dead25c657febf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Thu, 21 Sep 2023 02:11:49 +0900 Subject: [PATCH 01/19] feat : add favicon, title --- package-lock.json | 14 +++++++------- public/favicon.ico | Bin 3870 -> 67646 bytes public/index.html | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb6e658d3..c320648af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16064,16 +16064,16 @@ } }, "node_modules/typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { @@ -28588,9 +28588,9 @@ } }, "typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true }, "unbox-primitive": { diff --git a/public/favicon.ico b/public/favicon.ico index a11777cc471a4344702741ab1c8a588998b1311a..221d3baf136442353f2985b29c4c6d4ed3b76ccc 100644 GIT binary patch literal 67646 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 D)&c+T literal 3870 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ diff --git a/public/index.html b/public/index.html index aa069f27c..ebb0e69a0 100644 --- a/public/index.html +++ b/public/index.html @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + To-Do list From e0ee46ebefac0cb4a32d3c5458c42a266af2eff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Thu, 21 Sep 2023 02:53:51 +0900 Subject: [PATCH 02/19] =?UTF-8?q?feat:=20TodoList=20=EB=BC=88=EB=8C=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 12 +++++++----- src/Clock.js | 9 +++++++++ src/ListContainer.js | 8 ++++++++ src/TodoList.js | 23 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/Clock.js create mode 100644 src/ListContainer.js create mode 100644 src/TodoList.js diff --git a/src/App.js b/src/App.js index 867910d2a..d12098a8c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,11 @@ +import TodoList from "./TodoList"; + function App() { - return ( -
-

18기 프론트 화이팅~ 푸하항ㅋ

-
- ); + return ( +
+ +
+ ); } export default App; diff --git a/src/Clock.js b/src/Clock.js new file mode 100644 index 000000000..fd1205031 --- /dev/null +++ b/src/Clock.js @@ -0,0 +1,9 @@ +const Clock = () => { + return ( +
+

시계

+
+ ); +}; + +export default Clock; diff --git a/src/ListContainer.js b/src/ListContainer.js new file mode 100644 index 000000000..0540194e9 --- /dev/null +++ b/src/ListContainer.js @@ -0,0 +1,8 @@ +const ListContainer = () => { + return ( +
+

리스트컨테이너

+
+ ); +}; +export default ListContainer; diff --git a/src/TodoList.js b/src/TodoList.js new file mode 100644 index 000000000..307016cab --- /dev/null +++ b/src/TodoList.js @@ -0,0 +1,23 @@ +import Clock from "./Clock"; +import ListContainer from "./ListContainer"; + +const TodoList = () => { + return ( +
+ +
To Do List
+
+ + +
+
+ +
+
+ +
+
+ ); +}; + +export default TodoList; From 87c055f1c68888f1acb2c70b3ce9f85eb433cbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Thu, 21 Sep 2023 03:12:16 +0900 Subject: [PATCH 03/19] feat : clock.js --- src/Clock.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Clock.js b/src/Clock.js index fd1205031..4ab78f306 100644 --- a/src/Clock.js +++ b/src/Clock.js @@ -1,7 +1,25 @@ +import { useState, useEffect } from "react"; + const Clock = () => { + const [time, setTime] = useState(new Date()); + + useEffect(() => { + const id = setInterval(() => { + setTime(new Date()); + }, 1000); + return () => clearInterval(id); + }, []); + + const timeOptions = { + hour12: false, // 24 시간 형식 사용 + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }; + return (
-

시계

+

{time.toLocaleTimeString([], timeOptions)}

); }; From 3e73431ddbe916085a33b4a41eff78bea5b54b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 02:50:27 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat=20:=20TodoInput,=20ListContainer=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Clock.js | 2 +- src/ListContainer.js | 9 +++++++-- src/TodoInput.js | 42 ++++++++++++++++++++++++++++++++++++++++++ src/TodoItem.js | 11 +++++++++++ src/TodoList.js | 22 ++++++++++++++++------ 5 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 src/TodoInput.js create mode 100644 src/TodoItem.js diff --git a/src/Clock.js b/src/Clock.js index 4ab78f306..dfb0f0438 100644 --- a/src/Clock.js +++ b/src/Clock.js @@ -12,7 +12,7 @@ const Clock = () => { const timeOptions = { hour12: false, // 24 시간 형식 사용 - hour: "2-digit", + hour: "2-digit", //항상 두자릿수로 표현 minute: "2-digit", second: "2-digit", }; diff --git a/src/ListContainer.js b/src/ListContainer.js index 0540194e9..66c46417d 100644 --- a/src/ListContainer.js +++ b/src/ListContainer.js @@ -1,8 +1,13 @@ -const ListContainer = () => { +import TodoItem from "./TodoItem"; + +const ListContainer = ({ data }) => { return (
-

리스트컨테이너

+

Todo 🟡

+ +
{data && data.map((it) => )}
); }; + export default ListContainer; diff --git a/src/TodoInput.js b/src/TodoInput.js new file mode 100644 index 000000000..5c83a6fdf --- /dev/null +++ b/src/TodoInput.js @@ -0,0 +1,42 @@ +import { useRef, useState } from "react"; + +const TodoInput = ({ onCreate }) => { + const contentInput = useRef(); + const [content, setContent] = useState(""); + + const handleKeyDown = (e) => { + if (e.key === "Enter") { + handleSubmit(); + } + }; + + const handleSubmit = () => { + if (content.trim() !== "") { + onCreate(content); + alert("Good Luck!👍🏻"); + setContent(""); + } else { + //todo 입력값이 없으면 input칸 focus 기능 + contentInput.current.focus(); + return; + } + }; + + return ( +
+
+ { + setContent(e.target.value); + }} + onKeyDown={handleKeyDown} + /> + +
+
+ ); +}; +export default TodoInput; diff --git a/src/TodoItem.js b/src/TodoItem.js new file mode 100644 index 000000000..3dcd52e43 --- /dev/null +++ b/src/TodoItem.js @@ -0,0 +1,11 @@ +const TodoItem = ({ value, id, isDone }) => { + return ( +
+
+ {value} +
+
+ ); +}; + +export default TodoItem; diff --git a/src/TodoList.js b/src/TodoList.js index 307016cab..3b055fa25 100644 --- a/src/TodoList.js +++ b/src/TodoList.js @@ -1,20 +1,30 @@ import Clock from "./Clock"; +import TodoInput from "./TodoInput"; import ListContainer from "./ListContainer"; +import { useState } from "react"; const TodoList = () => { + const [data, setData] = useState([]); + + const onCreate = (content) => { + const created_date = new Date().getTime(); + const newItem = { + value: content, + id: created_date, + isDone: false, + }; + setData([...data, newItem]); + }; return (
To Do List
-
- - -
+
- +
- +
); From b7acc9c5ba16bf997eff362bd97edc87e9285ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 03:34:10 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat=20:=20=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ListContainer.js | 9 +++++++-- src/TodoItem.js | 17 ++++++++++++----- src/TodoList.js | 16 +++++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/ListContainer.js b/src/ListContainer.js index 66c46417d..76557a7e9 100644 --- a/src/ListContainer.js +++ b/src/ListContainer.js @@ -1,11 +1,16 @@ import TodoItem from "./TodoItem"; -const ListContainer = ({ data }) => { +const ListContainer = ({ onDelete, data }) => { return (

Todo 🟡

-
{data && data.map((it) => )}
+
+ {data && + data.map((it) => ( + + ))} +
); }; diff --git a/src/TodoItem.js b/src/TodoItem.js index 3dcd52e43..75c7cc1f7 100644 --- a/src/TodoItem.js +++ b/src/TodoItem.js @@ -1,9 +1,16 @@ -const TodoItem = ({ value, id, isDone }) => { +const TodoItem = ({ onDelete, value, id, isDone }) => { return ( -
-
- {value} -
+
+
{value}
+
); }; diff --git a/src/TodoList.js b/src/TodoList.js index 3b055fa25..ee83c3909 100644 --- a/src/TodoList.js +++ b/src/TodoList.js @@ -1,11 +1,16 @@ import Clock from "./Clock"; import TodoInput from "./TodoInput"; import ListContainer from "./ListContainer"; -import { useState } from "react"; +import { useEffect, useState } from "react"; const TodoList = () => { const [data, setData] = useState([]); + //콘솔창에서 data 확인용 + useEffect(() => { + console.log(data); + }); + const onCreate = (content) => { const created_date = new Date().getTime(); const newItem = { @@ -15,16 +20,21 @@ const TodoList = () => { }; setData([...data, newItem]); }; + + const onDelete = (targetId) => { + const newTodoList = data.filter((it) => it.id !== targetId); + setData(newTodoList); + }; return (
To Do List
- +
- +
); From 504598f4494d47fe16779fb3cdcd9d0b4c2aed46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 03:37:43 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat=20:=20count=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ListContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ListContainer.js b/src/ListContainer.js index 76557a7e9..1123e3e6a 100644 --- a/src/ListContainer.js +++ b/src/ListContainer.js @@ -4,7 +4,7 @@ const ListContainer = ({ onDelete, data }) => { return (

Todo 🟡

- +

You have {data.length} things to do.

{data && data.map((it) => ( From 7c9cbab1c9a7b630de7d048ecf492048b19fe740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 05:40:52 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat=20:=20moveItem=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ListContainer.js | 44 ++++++++++++++++++++++++++++++++++++-------- src/TodoItem.js | 13 +++++++++---- src/TodoList.js | 26 ++++++++++++++++++++------ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/ListContainer.js b/src/ListContainer.js index 1123e3e6a..dbc608ab1 100644 --- a/src/ListContainer.js +++ b/src/ListContainer.js @@ -1,15 +1,43 @@ import TodoItem from "./TodoItem"; -const ListContainer = ({ onDelete, data }) => { +const ListContainer = ({ onDelete, moveItem, data }) => { + // isDone 값이 false인 데이터만 필터링 + const todoData = data.filter((item) => !item.isDone); + + // isDone 값이 true인 데이터만 필터링 + const doneData = data.filter((item) => item.isDone); + return (
-

Todo 🟡

-

You have {data.length} things to do.

-
- {data && - data.map((it) => ( - - ))} +
+

"Todo 🟡"

+

You have {todoData.length} things to do.

+
+ {todoData && + todoData.map((it) => ( + + ))} +
+
+
+

"Done 🔵"

+

You've done {doneData.length} things.

+
+ {doneData && + doneData.map((it) => ( + + ))} +
); diff --git a/src/TodoItem.js b/src/TodoItem.js index 75c7cc1f7..0e8300730 100644 --- a/src/TodoItem.js +++ b/src/TodoItem.js @@ -1,11 +1,16 @@ -const TodoItem = ({ onDelete, value, id, isDone }) => { +const TodoItem = ({ onDelete, moveItem, value, id, isDone }) => { return ( -
+
{ + moveItem(id); + }} + >
{value}
-
-
+ + { + setContent(e.target.value); + }} + onKeyDown={handleKeyDown} + /> + + ); }; export default TodoInput; + +const Container = styled.div` + width: 380px; + padding: 0.5rem; + margin-top: 1.5rem; + margin-bottom: 1.5rem; + display: flex; + justify-content: center; + align-items: center; +`; + +const InputBox = styled.input` + width: 200px; + flex: 1; + padding: 0.8rem; + border: none; + outline: none; + border-radius: 10px; +`; + +const InputBtn = styled.button` + width: 40px; + background-color: black; + color: #ffffff; + border: none; + border-radius: 10px; + padding: 0.8rem; + cursor: pointer; + margin-left: 10px; + &:hover { + background-color: gray; /* 마우스 호버 시 배경색 변경 */ + } +`; diff --git a/src/TodoItem.js b/src/TodoItem.js index 0e8300730..aa7298d06 100644 --- a/src/TodoItem.js +++ b/src/TodoItem.js @@ -1,13 +1,15 @@ +import { styled } from "styled-components"; + const TodoItem = ({ onDelete, moveItem, value, id, isDone }) => { return ( -
{ moveItem(id); }} > -
{value}
- -
+ + ); }; export default TodoItem; + +const DeleteBtn = styled.button` + opacity: 0; + border: none; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 5px; + padding: 0.3rem 0.5rem; + cursor: pointer; + &:hover { + opacity: 1; + } +`; + +const Datalist = styled.div` + padding-top: 0.5rem; + padding-bottom: 0.5rem; +`; + +const DataContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +`; diff --git a/src/TodoList.js b/src/TodoList.js index f7d50750b..e4cb394b8 100644 --- a/src/TodoList.js +++ b/src/TodoList.js @@ -2,6 +2,7 @@ import Clock from "./Clock"; import TodoInput from "./TodoInput"; import ListContainer from "./ListContainer"; import { useEffect, useState } from "react"; +import { styled } from "styled-components"; const TodoList = () => { const [data, setData] = useState([]); @@ -30,7 +31,7 @@ const TodoList = () => { const moveItem = (targetId) => { const updatedData = data.map((item) => { if (item.id === targetId) { - if (window.confirm(`Move this task?`)) { + if (window.confirm(`일을 이동시키겠습니까?`)) { return { ...item, isDone: !item.isDone, @@ -43,15 +44,36 @@ const TodoList = () => { }; return ( -
+ -
To Do List
+ To Do List
-
+ ); }; export default TodoList; + +//CSS +const Container = styled.div` + background-color: rgba(255, 255, 255, 0.2); + padding: 100px; + padding-top: 10px; + padding-bottom: 140px; + margin-top: 0px; + display: flex; + flex-direction: column; + width: 400px; + height: 600px; + overflow: hidden; +`; + +const Title = styled.div` + display: flex; + justify-content: center; + font-size: 30px; + margin: 0 auto; +`; From 9c361b7d5e8845852473339b4c33970c966e8115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 12:55:44 +0900 Subject: [PATCH 09/19] =?UTF-8?q?fix=20:=20=ED=95=9C=EA=B8=80=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EB=9E=9C=EB=8D=94=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/TodoInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TodoInput.js b/src/TodoInput.js index 4740f636b..64b24821c 100644 --- a/src/TodoInput.js +++ b/src/TodoInput.js @@ -6,7 +6,7 @@ const TodoInput = ({ onCreate }) => { const handleKeyDown = (e) => { if (e.key === "Enter") { - e.preventDefault(); + if (e.nativeEvent.isComposing) return; handleSubmit(); } }; From 80f1066349d49bf5593c0be984a0833b4d548931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 18:20:57 +0900 Subject: [PATCH 10/19] feat : localstorage --- src/TodoList.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/TodoList.js b/src/TodoList.js index e4cb394b8..dec47f9fd 100644 --- a/src/TodoList.js +++ b/src/TodoList.js @@ -12,19 +12,35 @@ const TodoList = () => { console.log(data); }); + //localstorage + + useEffect(() => { + const localData = localStorage.getItem("todos"); + if (localData) { + const parsedDataList = JSON.parse(localData); + setData(parsedDataList); + } + }, []); + + //새로운 데이터를 추가하는 함수 const onCreate = (content) => { const created_date = new Date().getTime(); + const newItem = { value: content, id: created_date, isDone: false, }; + + const newData = [...data, newItem]; + localStorage.setItem("todos", JSON.stringify(newData)); setData([...data, newItem]); }; const onDelete = (targetId, e) => { e.stopPropagation(); const newTodoList = data.filter((it) => it.id !== targetId); + localStorage.setItem("todos", JSON.stringify(newTodoList)); setData(newTodoList); }; @@ -40,6 +56,7 @@ const TodoList = () => { } return item; }); + localStorage.setItem("todos", JSON.stringify(updatedData)); setData(updatedData); }; From e67856e7c9d62e1d22c1f5d6712db788a5ded0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=84=8B?= =?UTF-8?q?=E1=85=AF=E1=86=AB?= Date: Fri, 22 Sep 2023 19:22:44 +0900 Subject: [PATCH 11/19] =?UTF-8?q?feat=20:=20=EC=88=98=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ListContainer.js | 3 +- src/TodoItem.js | 92 ++++++++++++++++++++++++++++++++++++++------ src/TodoList.js | 14 ++++++- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/src/ListContainer.js b/src/ListContainer.js index fcac54290..12103ec61 100644 --- a/src/ListContainer.js +++ b/src/ListContainer.js @@ -1,7 +1,7 @@ import TodoItem from "./TodoItem"; import { styled } from "styled-components"; -const ListContainer = ({ onDelete, moveItem, data }) => { +const ListContainer = ({ onEdit, onDelete, moveItem, data }) => { // isDone 값이 false인 데이터만 필터링 const todoData = data.filter((item) => !item.isDone); @@ -24,6 +24,7 @@ const ListContainer = ({ onDelete, moveItem, data }) => { key={it.id} {...it} onDelete={onDelete} + onEdit={onEdit} moveItem={moveItem} /> ))} diff --git a/src/TodoItem.js b/src/TodoItem.js index aa7298d06..2adcb774c 100644 --- a/src/TodoItem.js +++ b/src/TodoItem.js @@ -1,6 +1,34 @@ +import { useState } from "react"; import { styled } from "styled-components"; -const TodoItem = ({ onDelete, moveItem, value, id, isDone }) => { +const TodoItem = ({ onEdit, onDelete, moveItem, value, id, isDone }) => { + const [isEdit, setIsEdit] = useState(false); + const [localContent, setLocalContent] = useState(value); + + const toggleIsEdit = (e) => { + e.stopPropagation(); + setIsEdit(!isEdit); + }; + + //수정 취소 + const handleQuitEdit = (e) => { + e.stopPropagation(); + setIsEdit(false); + setLocalContent(value); + }; + + //수정 완료 + const handleCompleteEdit = (e) => { + e.stopPropagation(); + if (localContent.trim() == "") { + return; + } + if (window.confirm(`할 일을 수정하시겠습니까?`)) { + onEdit(id, localContent); + toggleIsEdit(e); + } + }; + return ( { moveItem(id); }} > - {value} - { - if (window.confirm(`Delete this task?`)) { - onDelete(id, e); - } - }} - > - 🗑 - + + {isEdit ? ( + <> +