From ab60d014cf8579b2c6450223e313e9d6dbc35881 Mon Sep 17 00:00:00 2001 From: Jeong Daseul <98886223+goodaseul@users.noreply.github.com> Date: Wed, 31 Dec 2025 16:28:38 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20:=20=EB=AA=A9=ED=91=9C?= =?UTF-8?q?=EC=83=81=EC=84=B8=20-=20=EC=88=98=EC=A0=95=EB=B0=8F=20?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goals/[goalId]/_components/GoalHeader.tsx | 24 +++++++++++++++---- .../common/input/base-input/BaseInput.tsx | 3 +++ tests/unit/goals/goals.test.tsx | 22 ++++++++++++++++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/app/(protected)/goals/[goalId]/_components/GoalHeader.tsx b/src/app/(protected)/goals/[goalId]/_components/GoalHeader.tsx index a7766c1..08427b2 100644 --- a/src/app/(protected)/goals/[goalId]/_components/GoalHeader.tsx +++ b/src/app/(protected)/goals/[goalId]/_components/GoalHeader.tsx @@ -11,6 +11,7 @@ import { useDeleteGoalMutation } from "@/hooks/queries/goals/useDeleteGoalMutati import ConfirmModal from "@/components/common/popup-modal/ConfirmModal"; import { useRouter } from "next/navigation"; import { toast } from "@/lib/toast"; +import BaseInput from "@/components/common/input/base-input/BaseInput"; type GoalHeaderProps = { goalId: string; @@ -41,7 +42,7 @@ export default function GoalHeader({ goalId }: GoalHeaderProps) { text: "수정하기", onClick: () => { closeDropdown(); - setEditTitle(goal?.title ?? ""); + setEditTitle(""); setIsEditing(true); }, }, @@ -66,6 +67,11 @@ export default function GoalHeader({ goalId }: GoalHeaderProps) { ); }; + const handleCancelEdit = () => { + setEditTitle(""); + setIsEditing(false); + }; + const handleConfim = () => { deleteGoal(numericGoalId, { onSuccess: () => { @@ -86,11 +92,13 @@ export default function GoalHeader({ goalId }: GoalHeaderProps) {

{goal?.title}

) : (
- setEditTitle(e.target.value)} + placeholder="수정할 목표를 적어주세요." onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); @@ -98,10 +106,16 @@ export default function GoalHeader({ goalId }: GoalHeaderProps) { } }} /> + - 수정 완료 + 수정 + + + 취소
)} diff --git a/src/components/common/input/base-input/BaseInput.tsx b/src/components/common/input/base-input/BaseInput.tsx index 19885ad..6c4aab4 100644 --- a/src/components/common/input/base-input/BaseInput.tsx +++ b/src/components/common/input/base-input/BaseInput.tsx @@ -9,6 +9,7 @@ export interface BaseInputProps { id?: string; value: string; onChange: (e: React.ChangeEvent) => void; + onKeyDown?: (e: React.KeyboardEvent) => void; placeholder?: string; type?: InputType; className?: string; @@ -20,6 +21,7 @@ export default function BaseInput({ id, value, onChange, + onKeyDown, placeholder = "", type = "text", className, @@ -46,6 +48,7 @@ export default function BaseInput({ value={value} placeholder={placeholder} onChange={onChange} + onKeyDown={onKeyDown} className={inputClassName} /> {rightIcon} diff --git a/tests/unit/goals/goals.test.tsx b/tests/unit/goals/goals.test.tsx index 0518c61..784c3db 100644 --- a/tests/unit/goals/goals.test.tsx +++ b/tests/unit/goals/goals.test.tsx @@ -34,6 +34,26 @@ describe("목표 영역", () => { expect(screen.getByText("수정하기")).toBeInTheDocument(); expect(screen.getByText("삭제하기")).toBeInTheDocument(); }); + it("목표 수정 중 취소를 누르면 수정 모드가 종료된다", async () => { + const user = userEvent.setup(); + + renderWithQueryClient(); + + await user.click(screen.getByLabelText("goal-options")); + await user.click(screen.getByText("수정하기")); + + const input = screen.getByRole("textbox"); + expect(input).toBeInTheDocument(); + + await user.type(input, "할일"); + + await user.click(screen.getByText("취소")); + + expect(screen.queryByRole("textbox")).not.toBeInTheDocument(); + + expect(updateGoal).not.toHaveBeenCalled(); + }); + it("목표를 수정하면 입력한 값으로 변경된다", async () => { const user = userEvent.setup(); (updateGoal as jest.Mock).mockResolvedValueOnce({ @@ -53,7 +73,7 @@ describe("목표 영역", () => { await user.clear(input); await user.type(input, "새 목표"); - await user.click(screen.getByText("수정 완료")); + await user.click(screen.getByText("수정")); expect(await screen.findByText("새 목표")).toBeInTheDocument(); From e54a276808676eae9fb7898f46720e5b56a58930 Mon Sep 17 00:00:00 2001 From: Jeong Daseul <98886223+goodaseul@users.noreply.github.com> Date: Wed, 31 Dec 2025 17:19:04 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=92=84=20Style=20:=20=EB=8C=80?= =?UTF-8?q?=EC=8B=9C=EB=B3=B4=EB=93=9C=20=EC=B5=9C=EA=B7=BC=EB=93=B1?= =?UTF-8?q?=EB=A1=9D/=EC=A7=84=ED=96=89=EB=8F=84=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=B0=94=EC=9A=B4=EB=8D=94=EB=A6=AC=20=ED=83=9C=EA=B7=B8?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../todos/progress/ProgressTodos.tsx | 17 ++++++++++++++++- .../_components/todos/recent/RecentTodos.tsx | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/(protected)/dashboard/_components/todos/progress/ProgressTodos.tsx b/src/app/(protected)/dashboard/_components/todos/progress/ProgressTodos.tsx index 7a251f9..a8f4517 100644 --- a/src/app/(protected)/dashboard/_components/todos/progress/ProgressTodos.tsx +++ b/src/app/(protected)/dashboard/_components/todos/progress/ProgressTodos.tsx @@ -3,6 +3,8 @@ import ProgressCardSkeleton from "@/components/skeleton/ProgressCardSkeleton"; import ProgressContent from "./ProgressContent"; import { useAuthStore } from "@/store/useAuthStore"; import { AsyncBoundary } from "@/app/(protected)/_components/AsyncBoundary"; +import { FallbackProps } from "react-error-boundary"; +import Button from "@/components/common/button/Button"; export default function ProgressTodos() { const user = useAuthStore((state) => state.user); @@ -22,7 +24,20 @@ export default function ProgressTodos() {
- }> + } + errorFallback={({ error, resetErrorBoundary }: FallbackProps) => ( +
+

+ {error.message} +

+ +
+ )}>
diff --git a/src/app/(protected)/dashboard/_components/todos/recent/RecentTodos.tsx b/src/app/(protected)/dashboard/_components/todos/recent/RecentTodos.tsx index 5d63441..6cf2948 100644 --- a/src/app/(protected)/dashboard/_components/todos/recent/RecentTodos.tsx +++ b/src/app/(protected)/dashboard/_components/todos/recent/RecentTodos.tsx @@ -4,6 +4,8 @@ import { ChevronRightIcon } from "@heroicons/react/24/outline"; import { ListSkeleton } from "@/components/skeleton/ListSkeleton"; import RecentTodosContent from "./RecentTodosContent"; import { AsyncBoundary } from "@/app/(protected)/_components/AsyncBoundary"; +import { FallbackProps } from "react-error-boundary"; +import Button from "@/components/common/button/Button"; export default function RecentTodos() { return ( @@ -30,9 +32,22 @@ export default function RecentTodos() { loadingFallback={ - }> + } + errorFallback={({ error, resetErrorBoundary }: FallbackProps) => ( +
+

+ {error.message} +

+ +
+ )}>
From 45a55b41e0077f92fa4f4922f072777000250d51 Mon Sep 17 00:00:00 2001 From: Jeong Daseul <98886223+goodaseul@users.noreply.github.com> Date: Wed, 31 Dec 2025 17:31:03 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=92=84=20Style=20:=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=B0=94=EC=9A=B4=EB=8D=94=EB=A6=AC=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/goal/GoalSkeleton.tsx | 9 ++++----- .../_components/GoalContainerSkeleton.tsx | 19 ++++++++----------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/app/(protected)/dashboard/_components/goal/GoalSkeleton.tsx b/src/app/(protected)/dashboard/_components/goal/GoalSkeleton.tsx index bdf4bfc..b65c012 100644 --- a/src/app/(protected)/dashboard/_components/goal/GoalSkeleton.tsx +++ b/src/app/(protected)/dashboard/_components/goal/GoalSkeleton.tsx @@ -9,13 +9,13 @@ export default function GoalSkeleton() {
-
-
+
+
-
-
+
+
@@ -33,7 +33,6 @@ export default function GoalSkeleton() { title="DONE" variant="done"> diff --git a/src/app/(protected)/goals/[goalId]/_components/GoalContainerSkeleton.tsx b/src/app/(protected)/goals/[goalId]/_components/GoalContainerSkeleton.tsx index 62a24a0..cabcfdc 100644 --- a/src/app/(protected)/goals/[goalId]/_components/GoalContainerSkeleton.tsx +++ b/src/app/(protected)/goals/[goalId]/_components/GoalContainerSkeleton.tsx @@ -3,31 +3,27 @@ import { ListSkeleton } from "@/components/skeleton/ListSkeleton"; export default function GoalContainerSkeleton() { return (
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
+
+
+
@@ -36,6 +32,7 @@ export default function GoalContainerSkeleton() {
From baa89b9ba97e8a809b6ea3d47ef07f248ca378b1 Mon Sep 17 00:00:00 2001 From: Jeong Daseul <98886223+goodaseul@users.noreply.github.com> Date: Wed, 31 Dec 2025 18:04:27 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20:=20=EB=AA=A9=ED=91=9C?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=8A=A4=ED=81=AC=EB=A1=A4=202=EA=B0=9C?= =?UTF-8?q?=20=EC=9D=B4=EC=8A=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goals/[goalId]/_components/Goal.tsx | 1 + .../_components/GoalContainerData.tsx | 19 +++++++++++++++++++ .../[goalId]/_components/GoalSection.tsx | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/app/(protected)/goals/[goalId]/_components/Goal.tsx b/src/app/(protected)/goals/[goalId]/_components/Goal.tsx index 562dc7e..df60db2 100644 --- a/src/app/(protected)/goals/[goalId]/_components/Goal.tsx +++ b/src/app/(protected)/goals/[goalId]/_components/Goal.tsx @@ -9,6 +9,7 @@ export default function Goal({ goalTodos }: { goalTodos: ListTodoType[] }) { const goalTodoChecked = goalTodos.filter((goalTodo) => !goalTodo.checked); const goalTodoCheckedDone = goalTodos.filter((goalTodo) => goalTodo.checked); + return (
0 ? goalTodos[0].id : null; + useEffect(() => { + const handleResize = () => { + if (window.innerWidth >= 640) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = ""; + } + }; + + handleResize(); + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + document.body.style.overflow = ""; + }; + }, []); return ( <>
diff --git a/src/app/(protected)/goals/[goalId]/_components/GoalSection.tsx b/src/app/(protected)/goals/[goalId]/_components/GoalSection.tsx index bc8e05e..219cc7a 100644 --- a/src/app/(protected)/goals/[goalId]/_components/GoalSection.tsx +++ b/src/app/(protected)/goals/[goalId]/_components/GoalSection.tsx @@ -42,7 +42,7 @@ export default function GoalSection({ className="grid sm:gap-0.5 lg:gap-1" items={items} onToggleChecked={onToggleChecked} - containerClassName="sm:h-110" + containerClassName="sm:h-110 overflow-hidden overflow-y-auto" /> )}