Skip to content

Commit 841ec30

Browse files
committed
feat: 할 일 완료/진행 중 상태 변경 기능 추가
1 parent 925b61d commit 841ec30

File tree

8 files changed

+113
-15
lines changed

8 files changed

+113
-15
lines changed

src/actions/add-task.action.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default async function addTaskAction(
1212
if (!name) return { status: false, error: "할 일을 입력해주세요" };
1313

1414
try {
15-
const response = await fetch(`${process.env.NEXT_API_URL}/items`, {
15+
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/items`, {
1616
method: "POST",
1717
headers: {
1818
"Content-Type": "application/json",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use server";
2+
3+
import { revalidateTag } from "next/cache";
4+
5+
export default async function revalidateTodo() {
6+
revalidateTag("todo");
7+
}

src/components/todo/check-list.module.css

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@
1313
letter-spacing: 0%;
1414
}
1515

16+
.check_list_container > button {
17+
background: none; /* 배경 제거 */
18+
border: none; /* 테두리 제거 */
19+
padding: 0; /* 패딩 제거 */
20+
font: inherit; /* 부모 요소의 폰트 상속 */
21+
color: inherit; /* 부모 요소의 글자색 상속 */
22+
cursor: pointer; /* 마우스 커서를 포인터로 설정 */
23+
outline: inherit; /* focus 시 나타나는 외곽선 상속 */
24+
}
25+
1626
.checked {
1727
background-color: var(--violet-100);
1828
text-decoration: line-through;
1929
}
20-
21-
.check_btn {
22-
cursor: pointer;
23-
}

src/components/todo/check-list.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import Image from "next/image";
44
import styles from "./check-list.module.css";
55
import notCheck from "../../../public/not_check.svg";
66
import checkedIcon from "../../../public/checked.svg";
7+
import { useState } from "react";
8+
import useCompleteTodo from "@/hooks/useCompleteTodo";
9+
import { TodoDetailData } from "@/types";
10+
import Spinner from "../loading/spinner";
711

812
export default function CheckList({
913
id,
@@ -14,6 +18,12 @@ export default function CheckList({
1418
name: string;
1519
isCompleted: boolean;
1620
}) {
21+
const [task, setTask] = useState<TodoDetailData | null>(null);
22+
const { isLoading } = useCompleteTodo(id, task);
23+
const onClickSetTask = () => {
24+
setTask({ name, memo: "", imageUrl: "", isCompleted: !isCompleted });
25+
};
26+
1727
return (
1828
<div
1929
className={
@@ -22,13 +32,22 @@ export default function CheckList({
2232
: styles.check_list_container
2333
}
2434
>
25-
<Image
26-
className={styles.check_btn}
27-
src={isCompleted ? checkedIcon : notCheck}
28-
width={32}
29-
height={32}
30-
alt={isCompleted ? "완료" : "미완료"}
31-
/>
35+
<button
36+
type="button"
37+
onClick={onClickSetTask}
38+
disabled={isLoading ? true : false}
39+
>
40+
{isLoading ? (
41+
<Spinner />
42+
) : (
43+
<Image
44+
src={isCompleted ? checkedIcon : notCheck}
45+
width={32}
46+
height={32}
47+
alt={isCompleted ? "완료" : "미완료"}
48+
/>
49+
)}
50+
</button>
3251
<p>{name}</p>
3352
</div>
3453
);

src/components/todo/todo-section.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@ export default function TodoSection({
1212
}: TodoSectionProps) {
1313
return (
1414
<>
15-
<Image src={img} width={101} height={36} alt={imgAlt} />
15+
<Image src={img} width={101} height={36} alt={imgAlt} priority />
1616
{list.length > 0 ? (
1717
list.map((todo) => <CheckList key={todo.id} {...todo} />)
1818
) : (
1919
<div className={styles.empty}>
20-
<Image src={emptyImg} width={240} height={240} alt="리스트 없음" />
20+
<Image
21+
src={emptyImg}
22+
width={240}
23+
height={240}
24+
alt="리스트 없음"
25+
priority
26+
/>
2127
<p className={styles.empty_msg}>{emptyMsg}</p>
2228
</div>
2329
)}

src/components/todo/todoList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import emptyDone from "../../../public/empty_done.png";
77
import TodoSection from "./todo-section";
88

99
async function getAllTodoList() {
10-
const response = await fetch(`${process.env.NEXT_API_URL}/items`, {
10+
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/items`, {
1111
next: { tags: ["todo"] },
1212
});
1313

src/hooks/useCompleteTodo.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import revalidateTodo from "@/actions/revalidate-todo.action";
2+
import { TodoDetailData } from "@/types";
3+
import { useEffect, useState } from "react";
4+
5+
export default function useCompleteTodo(
6+
id: number,
7+
todoData: TodoDetailData | null
8+
) {
9+
const [isLoading, setIsLoading] = useState<boolean>(false);
10+
const [error, setError] = useState<boolean>(false);
11+
12+
const onClickComplete = async (taskId: number, data: TodoDetailData) => {
13+
setIsLoading(true);
14+
15+
try {
16+
const response = await fetch(
17+
`${process.env.NEXT_PUBLIC_API_URL}/items/${taskId}`,
18+
{
19+
method: "PATCH",
20+
headers: {
21+
"Content-Type": "application/json",
22+
},
23+
body: JSON.stringify(data),
24+
}
25+
);
26+
27+
if (!response.ok) {
28+
alert(`완료하지 못했습니다`);
29+
setError(true);
30+
return;
31+
}
32+
33+
revalidateTodo();
34+
} catch (error) {
35+
alert("완료하지 못했습니다");
36+
setError(true);
37+
} finally {
38+
setIsLoading(false);
39+
}
40+
};
41+
42+
useEffect(() => {
43+
if (!todoData) return;
44+
45+
onClickComplete(id, todoData);
46+
}, [id, todoData]);
47+
48+
return {
49+
isLoading,
50+
error,
51+
onClickComplete,
52+
};
53+
}

src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ export interface TodoData {
77
isCompleted: boolean;
88
}
99

10+
export interface TodoDetailData {
11+
name: string;
12+
isCompleted: boolean;
13+
memo: string;
14+
imageUrl: string;
15+
}
16+
1017
export interface SeparatedTodos {
1118
completed: TodoData[];
1219
incomplete: TodoData[];

0 commit comments

Comments
 (0)