Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";

import type { HomeViewDay } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type";
Expand All @@ -16,7 +15,6 @@ import {
useStopTimer,
} from "@/generated/endpoints/timer/timer";
import {
getGetTodoDetailQueryKey,
useChangeSubtaskStatus,
useChangeTodoStatus,
useReorderTodo,
Expand Down Expand Up @@ -45,39 +43,39 @@ export const useHomeTodosByDate = (
) => {
const [todosByDate, setTodosByDate] = useState<Record<string, Todo[]>>({});
const openTimerPanel = useTimeSidebarStore((state) => state.openTimerPanel);
const queryClient = useQueryClient();
const { data: activeTimer, isFetching: isActiveTimerFetching } =
useActiveTimer();
const { mutate: changeTodoStatus } = useChangeTodoStatus();
const { mutate: changeSubtaskStatus } = useChangeSubtaskStatus();
const { mutate: reorderTodo } = useReorderTodo();
const { mutate: stopTimer } = useStopTimer();
const {
invalidateHomeView,
invalidateStatistics,
invalidateTimerState,
invalidateTimerProgress,
invalidateTimerFinish,
invalidateTimeBoxes,
invalidateFocusTodo,
invalidateTodoDetail,
} = useTimerQueryInvalidation();
const invalidateHomeAndFocus = () => {
invalidateHomeView();
invalidateFocusTodo();
};
const { mutate: changeTodoStatus } = useChangeTodoStatus({
mutation: {
onSuccess: (_data, variables) => {
invalidateHomeAndFocus();
invalidateTimeBoxes();
invalidateStatistics();
invalidateTodoDetail(variables.todoId, variables.data.date);
},
},
});
const { mutate: changeSubtaskStatus } = useChangeSubtaskStatus();
const { mutate: reorderTodo } = useReorderTodo();
const { mutate: stopTimer } = useStopTimer();

const { mutate: startTimer, isPending: isStartTimerPending } =
useStartTimer<ApiError>({
mutation: {
onSuccess: () => {
invalidateTimerState();
invalidateFocusTodo();
},
},
});
useStartTimer<ApiError>();
const { mutate: changeStatus, isPending: isChangeStatusPending } =
useChangeStatus({
mutation: {
onSuccess: () => {
invalidateTimerState();
invalidateFocusTodo();
},
},
});
useChangeStatus();

const isTimerActionPending =
isStartTimerPending || isChangeStatusPending || isActiveTimerFetching;
Expand All @@ -101,16 +99,6 @@ export const useHomeTodosByDate = (
}));
};

const invalidateHomeAndFocus = () => {
invalidateHomeView();
invalidateFocusTodo();
};
const invalidateTodoDetail = (dateKey: string, todoId: number) => {
queryClient.invalidateQueries({
queryKey: getGetTodoDetailQueryKey(todoId, { date: dateKey }),
});
};

const handleToggleCompleted = (
dateKey: string,
todoId: number,
Expand All @@ -131,12 +119,6 @@ export const useHomeTodosByDate = (
changeTodoStatus(
{ todoId, data: { isCompleted: completed, date: dateKey } },
{
onSuccess: () => {
invalidateHomeAndFocus();
invalidateTimeBoxes();
invalidateTodoDetail(dateKey, todoId);
invalidateStatistics();
},
onError: (error: ErrorType<ErrorDto>) => {
setTodosByDate((prev) => ({ ...prev, [dateKey]: previous }));
onUpdateError(error.response?.data.message);
Expand All @@ -153,22 +135,16 @@ export const useHomeTodosByDate = (
{
onSuccess: (response) => {
onStopFeedback(response.data?.aiFeedback ?? undefined);
invalidateTimerState();
invalidateTimerFinish(todoId);

updateTodo(dateKey, todoId, (todo) => ({
...todo,
completed: true,
}));
changeTodoStatus(
{ todoId, data: { isCompleted: true, date: dateKey } },
{
onSuccess: () => {
invalidateHomeAndFocus();
invalidateTodoDetail(dateKey, todoId);
invalidateStatistics();
},
},
);
Comment on lines -162 to -171

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

혹시 기존 onSuccess의 invalidate는 invalidateTimerFinish에서 동일한 쿼리들을 무효화하고 있어서 중복이라고 판단해 삭제하신 걸까요?
삭제하게 되면 현재 구조에서 PATCH 요청보다 invalidateTimerFinish가 먼저 실행되기 때문에 완료 상태가 서버에 반영되기 전에 GET 응답이 돌아올 수 있을 것 같아요. 이후에 PATCH가 정상적으로 완료되더라도 성공 이후에 다시 무효화하는 로직이 없기 때문에, 화면에는 서버와 다르게 미완료로 남아보일 가능성이 있다고 생각했어요. 지금은 서버 응답이 빨라서 눈으로 보기에 문제가 없어 보여서 이 정도 케이스는 고려하지 않아도 되는지 궁금합니다!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이번 이슈에서 중복 코드와 구조 정리에 초점을 맞추다 보니 놓친 부분이 있었네요.
changeTodoStatus의 무효화 로직을 focus/TimerPanel과 동일한 구조로 mutation 정의 시점의 onSuccess로 옮겨서 어떤 호출부에서 호출하든 PATCH가 실제로 성공한 뒤에 항상 재검증되도록 수정했습니다. home/today 양쪽 모두 동일하게 적용했습니다-!

changeTodoStatus({
todoId,
data: { isCompleted: true, date: dateKey },
});
},
},
);
Expand Down Expand Up @@ -197,7 +173,10 @@ export const useHomeTodosByDate = (
action: activeTimer.status === "RUNNING" ? "PAUSE" : "RESUME",
},
},
{ onSuccess: () => invalidateTodoDetail(dateKey, todoId) },
{
onSuccess: () =>
invalidateTimerProgress({ includeFocus: true, todoId }),
},
);
return;
}
Expand All @@ -211,7 +190,8 @@ export const useHomeTodosByDate = (
startTimer(
{ todoId, params: { date: dateKey } },
{
onSuccess: () => invalidateTodoDetail(dateKey, todoId),
onSuccess: () =>
invalidateTimerProgress({ includeFocus: true, todoId }),
onError: (error: ApiError) => {
onPlayError(error.message);
},
Expand Down Expand Up @@ -244,7 +224,7 @@ export const useHomeTodosByDate = (
onSuccess: () => {
invalidateHomeAndFocus();
invalidateTimeBoxes();
invalidateTodoDetail(dateKey, todoId);
invalidateTodoDetail(todoId, dateKey);
invalidateStatistics();
},
onError: (error: ErrorType<ErrorDto>) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";

import type { TodayTodo } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type";
Expand All @@ -13,7 +12,6 @@ import {
useStopTimer,
} from "@/generated/endpoints/timer/timer";
import {
getGetTodoDetailQueryKey,
useChangeSubtaskStatus,
useChangeTodoStatus,
} from "@/generated/endpoints/todo/todo";
Expand Down Expand Up @@ -41,38 +39,36 @@ export const useTodayTodoList = (
) => {
const [todos, setTodos] = useState<TodayTodo[]>(initialTodos);
const openTimerPanel = useTimeSidebarStore((state) => state.openTimerPanel);
const queryClient = useQueryClient();
const { data: activeTimer, isFetching: isActiveTimerFetching } =
useActiveTimer();
const { mutate: changeTodoStatus } = useChangeTodoStatus();
const { mutate: changeSubtaskStatus } = useChangeSubtaskStatus();
const { mutate: stopTimer } = useStopTimer();
const {
invalidateTimerState,
invalidateTimerProgress,
invalidateTimerFinish,
invalidateTimeBoxes,
invalidateTodayView,
invalidateFocusTodo,
invalidateStatistics,
invalidateTodoDetail,
} = useTimerQueryInvalidation();

const { mutate: startTimer, isPending: isStartTimerPending } = useStartTimer({
const { mutate: changeTodoStatus } = useChangeTodoStatus({
mutation: {
onSuccess: () => {
invalidateTimerState();
onSuccess: (_data, variables) => {
invalidateTodayView();
invalidateTimeBoxes();
invalidateFocusTodo();
invalidateStatistics();
invalidateTodoDetail(variables.todoId, variables.data.date);
},
},
});
const { mutate: changeSubtaskStatus } = useChangeSubtaskStatus();
const { mutate: stopTimer } = useStopTimer();

const { mutate: startTimer, isPending: isStartTimerPending } =
useStartTimer();

const { mutate: changeStatus, isPending: isChangeStatusPending } =
useChangeStatus({
mutation: {
onSuccess: () => {
invalidateTimerState();
invalidateFocusTodo();
},
},
});
useChangeStatus();

const isTimerActionPending =
isStartTimerPending || isChangeStatusPending || isActiveTimerFetching;
Expand All @@ -90,12 +86,6 @@ export const useTodayTodoList = (
);
};

const invalidateTodoDetail = (todoId: number, dateKey: string) => {
queryClient.invalidateQueries({
queryKey: getGetTodoDetailQueryKey(todoId, { date: dateKey }),
});
};

const handleToggleCompleted = (todoId: number, completed: boolean) => {
const dateKey = todos.find((todo) => todo.todoId === todoId)?.date;
if (!dateKey) return;
Expand All @@ -115,13 +105,6 @@ export const useTodayTodoList = (
changeTodoStatus(
{ todoId, data: { isCompleted: completed, date: dateKey } },
{
onSuccess: () => {
invalidateTodayView();
invalidateTimeBoxes();
invalidateTodoDetail(todoId, dateKey);
invalidateFocusTodo();
invalidateStatistics();
},
onError: (error: ErrorType<ErrorDto>) => {
setTodos(previous);
onUpdateError(error.response?.data.message);
Expand All @@ -141,20 +124,13 @@ export const useTodayTodoList = (
{
onSuccess: (response) => {
onStopFeedback(response.data?.aiFeedback ?? undefined);
invalidateTimerState();
invalidateTimerFinish(todoId);

updateTodo(todoId, (todo) => ({ ...todo, completed: true }));
changeTodoStatus(
{ todoId, data: { isCompleted: true, date: dateKey } },
{
onSuccess: () => {
invalidateTodayView();
invalidateTodoDetail(todoId, dateKey);
invalidateFocusTodo();
invalidateStatistics();
},
},
);
changeTodoStatus({
todoId,
data: { isCompleted: true, date: dateKey },
});
},
},
);
Expand Down Expand Up @@ -185,7 +161,10 @@ export const useTodayTodoList = (
action: activeTimer.status === "RUNNING" ? "PAUSE" : "RESUME",
},
},
{ onSuccess: () => invalidateTodoDetail(todoId, dateKey) },
{
onSuccess: () =>
invalidateTimerProgress({ includeFocus: true, todoId }),
},
);
return;
}
Expand All @@ -199,7 +178,8 @@ export const useTodayTodoList = (
startTimer(
{ todoId, params: { date: dateKey } },
{
onSuccess: () => invalidateTodoDetail(todoId, dateKey),
onSuccess: () =>
invalidateTimerProgress({ includeFocus: true, todoId }),
onError: (error: ErrorType<ErrorDto>) => {
onPlayError(error.response?.data.message);
},
Expand Down
Loading
Loading