diff --git a/apps/timo-web/api/generated/endpoints/timer/timer.ts b/apps/timo-web/api/generated/endpoints/timer/timer.ts index 47dd634c..68c2c738 100644 --- a/apps/timo-web/api/generated/endpoints/timer/timer.ts +++ b/apps/timo-web/api/generated/endpoints/timer/timer.ts @@ -58,6 +58,9 @@ const withQueryKey = ( /** * 투두의 타이머를 시작합니다. * 한 번에 한 개의 타이머만 실행 가능하며, 이미 실행/일시정지 중인 타이머가 있으면 409를 반환합니다. + * + * 응답의 date는 타이머가 귀속되는 날짜(사용자 시간대 기준 시작일)입니다. + * 반복 투두는 여러 날짜에 같은 todoId로 노출되므로, 실행중 표시는 todoId가 아닌 (todoId, date) 조합으로 구분해야 합니다. * @summary 타이머 시작 */ export const startTimer = ( @@ -499,6 +502,9 @@ export const useCompleteTimer = < * 로그인한 사용자의 현재 실행 중(RUNNING/PAUSED)인 타이머를 단건 조회합니다. * 한 사용자당 시작 이후 완료/종료되지 않은 타이머는 최대 1개만 존재할 수 있습니다. * 실행 중인 타이머가 없으면 data: null을 반환합니다. + * + * 응답의 date는 타이머가 귀속되는 날짜(사용자 시간대 기준 시작일)입니다. + * 반복 투두는 여러 날짜에 같은 todoId로 노출되므로, 실행중 표시는 todoId가 아닌 (todoId, date) 조합으로 구분해야 합니다. * @summary 현재 실행 중인 타이머 조회 */ export const getActiveTimer = ( diff --git a/apps/timo-web/api/generated/endpoints/timer/timer.zod.ts b/apps/timo-web/api/generated/endpoints/timer/timer.zod.ts index ffc1e441..644d29f4 100644 --- a/apps/timo-web/api/generated/endpoints/timer/timer.zod.ts +++ b/apps/timo-web/api/generated/endpoints/timer/timer.zod.ts @@ -10,6 +10,9 @@ import * as zod from "zod"; /** * 투두의 타이머를 시작합니다. * 한 번에 한 개의 타이머만 실행 가능하며, 이미 실행/일시정지 중인 타이머가 있으면 409를 반환합니다. + * + * 응답의 date는 타이머가 귀속되는 날짜(사용자 시간대 기준 시작일)입니다. + * 반복 투두는 여러 날짜에 같은 todoId로 노출되므로, 실행중 표시는 todoId가 아닌 (todoId, date) 조합으로 구분해야 합니다. * @summary 타이머 시작 */ export const StartTimerParams = zod.object({ @@ -23,6 +26,7 @@ export const StartTimerResponse = zod.object({ .object({ timerId: zod.number(), todoId: zod.number(), + date: zod.string(), status: zod.string(), plannedSeconds: zod.number(), startedAt: zod.string(), @@ -153,6 +157,9 @@ export const CompleteTimerResponse = zod.object({ * 로그인한 사용자의 현재 실행 중(RUNNING/PAUSED)인 타이머를 단건 조회합니다. * 한 사용자당 시작 이후 완료/종료되지 않은 타이머는 최대 1개만 존재할 수 있습니다. * 실행 중인 타이머가 없으면 data: null을 반환합니다. + * + * 응답의 date는 타이머가 귀속되는 날짜(사용자 시간대 기준 시작일)입니다. + * 반복 투두는 여러 날짜에 같은 todoId로 노출되므로, 실행중 표시는 todoId가 아닌 (todoId, date) 조합으로 구분해야 합니다. * @summary 현재 실행 중인 타이머 조회 */ export const GetActiveTimerResponse = zod.object({ @@ -162,6 +169,7 @@ export const GetActiveTimerResponse = zod.object({ .object({ timerId: zod.number(), todoId: zod.number(), + date: zod.string(), todoTitle: zod.string(), iconType: zod.string().optional(), status: zod.string(), diff --git a/apps/timo-web/api/generated/models/timerActiveResponse.ts b/apps/timo-web/api/generated/models/timerActiveResponse.ts index 1002b981..b0f76183 100644 --- a/apps/timo-web/api/generated/models/timerActiveResponse.ts +++ b/apps/timo-web/api/generated/models/timerActiveResponse.ts @@ -9,6 +9,7 @@ export interface TimerActiveResponse { timerId: number; todoId: number; + date: string; todoTitle: string; iconType?: string; status: string; diff --git a/apps/timo-web/api/generated/models/timerStartResponse.ts b/apps/timo-web/api/generated/models/timerStartResponse.ts index aa2cad40..7c736fa9 100644 --- a/apps/timo-web/api/generated/models/timerStartResponse.ts +++ b/apps/timo-web/api/generated/models/timerStartResponse.ts @@ -9,6 +9,7 @@ export interface TimerStartResponse { timerId: number; todoId: number; + date: string; status: string; plannedSeconds: number; startedAt: string; diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx index aa7064f9..dcb13590 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx @@ -134,7 +134,9 @@ export const HomeTodoContainer = () => { {todos.map((todo) => { const [firstSubtask] = todo.subtasks; const isActiveTodo = - activeTimer && activeTimer.todoId === todo.todoId; + activeTimer && + activeTimer.todoId === todo.todoId && + activeTimer.date === dateKey; const durationSeconds = isActiveTodo ? activeTimer.plannedSeconds + activeTimer.extendedSeconds : todo.durationSeconds; diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts index 7d2c5ad8..fffe9424 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts @@ -105,7 +105,11 @@ export const useHomeTodosByDate = ( todoId: number, completed: boolean, ) => { - if (completed && activeTimer?.todoId === todoId) { + if ( + completed && + activeTimer?.todoId === todoId && + activeTimer.date === dateKey + ) { onNeedStopConfirm(dateKey, todoId); return; } @@ -165,7 +169,11 @@ export const useHomeTodosByDate = ( openTimerPanel(); } - if (activeTimer && activeTimer.todoId === todoId) { + if ( + activeTimer && + activeTimer.todoId === todoId && + activeTimer.date === dateKey + ) { changeStatus( { timerId: activeTimer.timerId, diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx index d45e5db7..09fd520c 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx @@ -88,7 +88,9 @@ export const TodayTodoListContainer = () => {
{todos.map((todo) => { const isActiveTodo = - activeTimer && activeTimer.todoId === todo.todoId; + activeTimer && + activeTimer.todoId === todo.todoId && + activeTimer.date === todo.date; const durationSeconds = isActiveTodo ? activeTimer.plannedSeconds + activeTimer.extendedSeconds : todo.durationSeconds; diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts index 5e087253..22481f04 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts @@ -88,14 +88,18 @@ export const useTodayTodoList = ( }; const handleToggleCompleted = (todoId: number, completed: boolean) => { - if (completed && activeTimer?.todoId === todoId) { + const dateKey = todos.find((todo) => todo.todoId === todoId)?.date; + if (!dateKey) return; + + if ( + completed && + activeTimer?.todoId === todoId && + activeTimer.date === dateKey + ) { onNeedStopConfirm(todoId); return; } - const dateKey = todos.find((todo) => todo.todoId === todoId)?.date; - if (!dateKey) return; - const previous = todos; updateTodo(todoId, (todo) => ({ ...todo, completed })); @@ -155,7 +159,11 @@ export const useTodayTodoList = ( openTimerPanel(); } - if (activeTimer && activeTimer.todoId === todoId) { + if ( + activeTimer && + activeTimer.todoId === todoId && + activeTimer.date === dateKey + ) { changeStatus( { timerId: activeTimer.timerId, diff --git a/apps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.ts b/apps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.ts index e7e104df..ff2d713e 100644 --- a/apps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.ts +++ b/apps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.ts @@ -137,7 +137,10 @@ export const useFocusSession = ({ const todo = focusView.todo; const timer = - activeTimer && todo && activeTimer.todoId === todo.todoId + activeTimer && + todo && + activeTimer.todoId === todo.todoId && + activeTimer.date === focusView.date ? activeTimer : undefined; const isRunning = timer?.status === "RUNNING"; diff --git a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx index c80dbb85..c7c6f771 100644 --- a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx +++ b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx @@ -59,7 +59,9 @@ const DetailTodoModalQuery = ({ const { handleToggle } = useToggleSubtaskSubmit(); const { data: activeTimer } = useActiveTimer(); const todo = data?.data; - const isPlayHighlighted = !activeTimer || activeTimer.todoId === todoId; + const isPlayHighlighted = + !activeTimer || + (activeTimer.todoId === todoId && activeTimer.date === date); useEffect(() => { if (isError && error) { @@ -70,7 +72,9 @@ const DetailTodoModalQuery = ({ if (isError || !todo) return null; const timerStatus = - activeTimer?.todoId === todoId ? activeTimer.status : todo.timerStatus; + activeTimer?.todoId === todoId && activeTimer.date === date + ? activeTimer.status + : todo.timerStatus; const deleteTodo = () => { handleDelete(todoId, { diff --git a/apps/timo-web/messages/en.json b/apps/timo-web/messages/en.json index eb0745ef..e2ca3938 100644 --- a/apps/timo-web/messages/en.json +++ b/apps/timo-web/messages/en.json @@ -249,7 +249,7 @@ "title": "Shall we stop now?", "description": "The {minutes} completed so far will be recorded in the timebox.", "continueButton": "Continue", - "switchButton": "Switch" + "switchButton": "Finish" }, "completeModal": { "title": "The task has been completed!", diff --git a/apps/timo-web/schemas/timer/timer-schema.ts b/apps/timo-web/schemas/timer/timer-schema.ts index c28567ad..48222df8 100644 --- a/apps/timo-web/schemas/timer/timer-schema.ts +++ b/apps/timo-web/schemas/timer/timer-schema.ts @@ -4,6 +4,7 @@ import { z } from "zod"; export const activeTimerSchema = z.object({ timerId: z.number(), todoId: z.number(), + date: z.string(), iconType: z .enum(TODO_ICON_VALUES) .nullish()