diff --git a/.agents/skills/api/timo-api-integration/SKILL.md b/.agents/skills/api/timo-api-integration/SKILL.md index 0fa82bd0..07369f40 100644 --- a/.agents/skills/api/timo-api-integration/SKILL.md +++ b/.agents/skills/api/timo-api-integration/SKILL.md @@ -38,11 +38,14 @@ ### Phase 3 — `_queries/` 훅 작성 -- 위치: `app/(domain)/_queries/use-xxx.ts` +- 위치: `app/(domain)/_queries/use-xxx-query.ts` (조회) / `use-xxx-mutation.ts` (변경) +- 네이밍: 파일명은 `-query.ts`/`-mutation.ts`로, export하는 함수명은 `~Query`/`~Mutation`으로 끝낸다. 파일당 훅 1개가 기본이다. → `docs/conventions/naming.md` 참조 - `useSuspenseQuery`를 쓸지 `useQuery`를 쓸지는 컴포넌트가 `AsyncBoundary`(Suspense) 안에 있는지로 결정한다. `AsyncBoundary`로 감싸져 있으면 `useSuspenseQuery`를 쓴다. - **주의**: 생성된 `getGetXxxQueryOptions()` 팩토리를 그대로 `useSuspenseQuery`에 스프레드하면 `UseQueryOptions`가 허용하는 `skipToken`과 `UseSuspenseQueryOptions`가 타입 충돌을 일으킨다. `queryKey`/`queryFn`은 생성된 `getGetXxxQueryKey` + 원본 fetcher 함수로 직접 조립한다. - `select`에서 `BaseResponse.data`를 언랩하고 로컬 zod 스키마로 `.parse()`해서 반환한다. +조회 훅 예시 (`_queries/use-home-view-query.ts`): + ```ts "use client"; @@ -54,7 +57,7 @@ import { } from "@/api/generated/endpoints/home/home"; import { homeViewDataSchema } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type"; -export const useHomeView = ({ filter, baseDate }: GetHomeViewParams) => +export const useHomeViewQuery = ({ filter, baseDate }: GetHomeViewParams) => useSuspenseQuery({ queryKey: getGetHomeQueryKey({ filter, baseDate }), queryFn: ({ signal }) => getHome({ filter, baseDate }, undefined, signal), @@ -62,6 +65,28 @@ export const useHomeView = ({ filter, baseDate }: GetHomeViewParams) => }); ``` +변경 훅 예시 (`_queries/use-withdraw-mutation.ts`): + +```ts +"use client"; + +import { useMutation } from "@tanstack/react-query"; + +import { withdraw } from "@/api/generated/endpoints/auth/auth"; +import { useClearSession } from "@/app/[locale]/(main)/settings/_hooks/use-clear-session"; + +export const useWithdrawMutation = () => { + const clearSession = useClearSession(); + + return useMutation({ + mutationFn: () => withdraw(), + onSuccess: () => { + clearSession(); + }, + }); +}; +``` + ### Phase 4 — 컨테이너 연결 - mock 함수 import를 제거하고 새 훅으로 교체한다. @@ -70,6 +95,7 @@ export const useHomeView = ({ filter, baseDate }: GetHomeViewParams) => ### Phase 5 — 자가 검토 +- [ ] 훅 파일명/함수명이 `-query`/`~Query`, `-mutation`/`~Mutation` 컨벤션을 따르는가 - [ ] `api/generated/` 내부 파일을 직접 수정하지 않았는가 (재생성 시 사라짐) - [ ] 응답을 로컬 zod 스키마로 `.parse()`해서 검증했는가 (gen 응답 스키마를 그대로 UI까지 노출하지 않았는가) - [ ] `useSuspenseQuery` 사용 시 `queryKey`/`queryFn`을 직접 조립해 타입 충돌을 피했는가 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 2ff607d1..e0aae773 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 @@ -14,7 +14,7 @@ import { } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-today-scroll"; import { useHomeTodosByDate } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date"; import { useHomeViewMode } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-view-mode"; -import { useHomeView } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view"; +import { useHomeViewQuery } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { StopCompleteModalContainer } from "@/containers/timer/StopCompleteModalContainer"; import { DetailTodoModalContainer } from "@/containers/todo-modal/detail/DetailTodoModalContainer"; @@ -39,7 +39,7 @@ export const HomeTodoContainer = () => { const filter: HomeViewFilter = isWeekView ? "WEEK" : "DEFAULT"; const baseDate = formatDateKey(referenceDate); - const { data: homeViewData } = useHomeView({ filter, baseDate }); + const { data: homeViewData } = useHomeViewQuery({ filter, baseDate }); const days = homeViewData.days; const [pendingCompleteTodo, setPendingCompleteTodo] = 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 f378ecf4..fff1170b 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 @@ -20,8 +20,8 @@ import { useReorderTodo, } from "@/api/generated/endpoints/todo/todo"; import { reorderTodos } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-order"; -import { useActiveTimer } from "@/hooks/use-active-timer"; -import { useTimerQueryInvalidation } from "@/hooks/use-timer-query-invalidation"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; +import { useTimerQueryInvalidation } from "@/hooks/timer/use-timer-query-invalidation"; import { useTimeSidebarStore } from "@/stores/time-sidebar/useTimeSidebarStore"; export interface UseHomeTodosByDateOptions { diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query.ts similarity index 88% rename from apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view.ts rename to apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query.ts index bcc2a2bf..84cb7a82 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query.ts @@ -10,7 +10,7 @@ import { } from "@/api/generated/endpoints/home/home"; import { homeViewDataSchema } from "@/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type"; -export const useHomeView = ({ filter, baseDate }: GetHomeViewParams) => +export const useHomeViewQuery = ({ filter, baseDate }: GetHomeViewParams) => useSuspenseQuery({ queryKey: getGetHomeQueryKey({ filter, baseDate }), queryFn: ({ signal }) => getHome({ filter, baseDate }, undefined, signal), diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts index 0c31e4ab..ef475f0e 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { dayOfWeekSchema, todoSchema } from "@/api/common/todo-schema"; +import { dayOfWeekSchema, todoSchema } from "@/schemas/todo/todo-schema"; export const homeViewFilterSchema = z.enum(["DEFAULT", "WEEK"]); diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.ts index 39f62e0a..fd452115 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.ts @@ -5,7 +5,7 @@ export { todoSubtaskSchema, todoSchema, todoCreateResponseSchema, -} from "@/api/common/todo-schema"; +} from "@/schemas/todo/todo-schema"; export type { TodoPriorityTypes, @@ -14,4 +14,4 @@ export type { TodoSubtask, Todo, TodoCreateResponseData, -} from "@/api/common/todo-schema"; +} from "@/schemas/todo/todo-schema"; diff --git a/apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx similarity index 100% rename from apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx rename to apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx index e18a965e..6331215b 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx @@ -2,14 +2,14 @@ import { useEffect, useState } from "react"; -import type { TodoTimerStatusTypes } from "@/api/common/todo-schema"; +import type { TodoTimerStatusTypes } from "@/schemas/todo/todo-schema"; import type { ReactNode } from "react"; import { TodayTodoCard, type SubTodo, type TodayTodoCardToolbar, -} from "@/app/[locale]/(main)/today/_components/TodayTodoCard"; +} from "@/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard"; export interface TodayTodoCardContainerProps { title: string; 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 2b030845..63646197 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 @@ -9,7 +9,7 @@ import type { TodoIconValue } from "@repo/timo-design-system/ui"; import { TodayDateHeaderContainer } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayDateHeaderContainer"; import { TodayTodoCardContainer } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer"; import { useTodayTodoList } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList"; -import { useToday } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today"; +import { useTodayQuery } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { StopCompleteModalContainer } from "@/containers/timer/StopCompleteModalContainer"; import { DetailTodoModalContainer } from "@/containers/todo-modal/detail/DetailTodoModalContainer"; @@ -30,7 +30,7 @@ const renderTodoIcon = (icon: string | undefined) => { export const TodayTodoListContainer = () => { const tToast = useTranslations("Toast"); - const { data } = useToday(); + const { data } = useTodayQuery(); const [pendingCompleteTodoId, setPendingCompleteTodoId] = useState< number | null diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts index dce36148..f3ce6441 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts @@ -3,8 +3,8 @@ import { useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; import type { TodoCreateRequest } from "@/api/generated/models"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import { getGetTodayQueryKey } from "@/api/generated/endpoints/home/home"; import { useCreateTodo } from "@/api/generated/endpoints/todo/todo"; 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 835b1fd2..b4b49af2 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 @@ -18,8 +18,8 @@ import { useChangeSubtaskStatus, useChangeTodoStatus, } from "@/api/generated/endpoints/todo/todo"; -import { useActiveTimer } from "@/hooks/use-active-timer"; -import { useTimerQueryInvalidation } from "@/hooks/use-timer-query-invalidation"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; +import { useTimerQueryInvalidation } from "@/hooks/timer/use-timer-query-invalidation"; import { useTimeSidebarStore } from "@/stores/time-sidebar/useTimeSidebarStore"; export interface UseTodayTodoListOptions { diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query.ts similarity index 92% rename from apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today.ts rename to apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query.ts index 4e92c6e8..31d93cae 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query.ts @@ -8,7 +8,7 @@ import { } from "@/api/generated/endpoints/home/home"; import { todayDataSchema } from "@/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type"; -export const useToday = () => +export const useTodayQuery = () => useSuspenseQuery({ queryKey: getGetTodayQueryKey(), queryFn: ({ signal }) => getToday(undefined, signal), diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.ts b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.ts index 266e4547..8d0beed4 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.ts +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { dayOfWeekSchema, todoSchema } from "@/api/common/todo-schema"; +import { dayOfWeekSchema, todoSchema } from "@/schemas/todo/todo-schema"; export const todayTodoSchema = todoSchema.extend({ date: z.string(), 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 ea734b1c..60ccb1fe 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 @@ -17,12 +17,12 @@ import { useChangeSubtaskStatus, useChangeTodoStatus, } from "@/api/generated/endpoints/todo/todo"; -import { useFocusTodo } from "@/app/[locale]/(main)/focus/_queries/use-focus-todo"; +import { useFocusTodoQuery } from "@/app/[locale]/(main)/focus/_queries/use-focus-todo-query"; import { convertDateToBadgeText } from "@/app/[locale]/(main)/focus/_utils/date"; -import { useActiveTimer } from "@/hooks/use-active-timer"; -import { useTimerActions } from "@/hooks/use-timer-actions"; -import { useTimerOvertime } from "@/hooks/use-timer-overtime"; -import { useTimerQueryInvalidation } from "@/hooks/use-timer-query-invalidation"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; +import { useTimerActions } from "@/hooks/timer/use-timer-actions"; +import { useTimerOvertime } from "@/hooks/timer/use-timer-overtime"; +import { useTimerQueryInvalidation } from "@/hooks/timer/use-timer-query-invalidation"; import { convertDurationToMinutes } from "@/utils/duration/convert-duration-to-minutes"; export interface UseFocusSessionOptions { @@ -38,7 +38,7 @@ export const useFocusSession = ({ const timerSessionControlsRef = useRef(null); const wasTimeUpRef = useRef(false); - const { data: focusView } = useFocusTodo(); + const { data: focusView } = useFocusTodoQuery(); const { data: activeTimer } = useActiveTimer(); const { invalidateActiveTimer, invalidateHomeView, invalidateTimeBoxes } = diff --git a/apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo.ts b/apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo-query.ts similarity index 91% rename from apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo.ts rename to apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo-query.ts index bb81c876..d0329ca0 100644 --- a/apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo.ts +++ b/apps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo-query.ts @@ -8,7 +8,7 @@ import { } from "@/api/generated/endpoints/focus/focus"; import { focusViewSchema } from "@/app/[locale]/(main)/focus/_types/task-type"; -export const useFocusTodo = () => +export const useFocusTodoQuery = () => useSuspenseQuery({ queryKey: getGetFocusTodoQueryKey(), queryFn: ({ signal }) => getFocusTodo(undefined, signal), diff --git a/apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx b/apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx index e8948d7c..518bb679 100644 --- a/apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx @@ -2,10 +2,10 @@ import { useTranslations } from "next-intl"; -import type { TermsType } from "@/types/terms-type"; +import type { TermsType } from "@/schemas/settings/terms-schema"; import { PolicyDocument } from "@/components/policy/PolicyDocument"; -import { useTerms } from "@/queries/use-terms"; +import { useTermsQuery } from "@/queries/settings/use-terms-query"; export interface SettingsTermsContainerProps { type: TermsType; @@ -15,7 +15,7 @@ export const SettingsTermsContainer = ({ type, }: SettingsTermsContainerProps) => { const t = useTranslations("Policy"); - const { data: term } = useTerms(type); + const { data: term } = useTermsQuery(type); return (
diff --git a/apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx b/apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx index 0ddec2cd..4b9582cd 100644 --- a/apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx @@ -8,12 +8,12 @@ import type { SettingsWithdrawalLabels } from "@/app/[locale]/(main)/settings/_t import { SettingsWithdrawalView } from "@/app/[locale]/(main)/settings/_components/withdrawal/SettingsWithdrawalView"; import { SettingsWithdrawModalContainer } from "@/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawModalContainer"; -import { useWithdrawAction } from "@/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw"; +import { useWithdrawMutation } from "@/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; export const SettingsWithdrawalContainer = () => { const t = useTranslations("Settings.withdrawal"); - const { mutate: withdrawMutate, isPending } = useWithdrawAction(); + const { mutate: withdrawMutate, isPending } = useWithdrawMutation(); const [isErrorToastOpen, setIsErrorToastOpen] = useState(false); const labels: SettingsWithdrawalLabels = { diff --git a/apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts b/apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts index 997fecfe..d39378c0 100644 --- a/apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts +++ b/apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts @@ -5,18 +5,18 @@ import { useTranslations } from "next-intl"; import type { SettingsLanguage } from "@/app/[locale]/(main)/settings/_types/account/profile-type"; -import { tagCreateDataSchema } from "@/api/common/tag-schema"; import { getGetMyProfileQueryKey, useUpdateLanguage, } from "@/api/generated/endpoints/user/user"; import { UpdateLanguageRequestLanguage } from "@/api/generated/models"; import { useSettingsLanguageParam } from "@/app/[locale]/(main)/settings/_hooks/account/use-settings-language-param"; -import { useLogoutAction } from "@/app/[locale]/(main)/settings/_queries/account/use-logout"; -import { useCreateTag } from "@/queries/tag/use-create-tag"; -import { useDeleteTag } from "@/queries/tag/use-delete-tag"; -import { useTags } from "@/queries/tag/use-tags"; -import { useMyProfile } from "@/queries/use-my-profile"; +import { useLogoutMutation } from "@/app/[locale]/(main)/settings/_queries/account/use-logout-mutation"; +import { useMyProfileQuery } from "@/queries/auth/use-my-profile-query"; +import { useCreateTagMutation } from "@/queries/tag/use-create-tag-mutation"; +import { useDeleteTagMutation } from "@/queries/tag/use-delete-tag-mutation"; +import { useTagsQuery } from "@/queries/tag/use-tags-query"; +import { tagCreateDataSchema } from "@/schemas/tag/tag-schema"; import { getDefaultTagLabelKey } from "@/utils/todo/tag-label"; const LANGUAGE_REQUEST_MAP: Record< @@ -44,15 +44,15 @@ export const useSettingsProfile = () => { const { locale, commitLanguage } = useSettingsLanguageParam(); const tCommon = useTranslations("Common"); - const { data: profile } = useMyProfile(); + const { data: profile } = useMyProfileQuery(); const { mutateAsync: updateLanguage } = useUpdateLanguage(); const queryClient = useQueryClient(); - const tagsQuery = useTags(); - const { mutate: createTag } = useCreateTag(); - const { mutate: deleteTag } = useDeleteTag(); - const { mutate: logoutMutate, isPending: isLoggingOut } = useLogoutAction(); + const tagsQuery = useTagsQuery(); + const { mutate: createTag } = useCreateTagMutation(); + const { mutate: deleteTag } = useDeleteTagMutation(); + const { mutate: logoutMutate, isPending: isLoggingOut } = useLogoutMutation(); const tagItems = (tagsQuery.data?.tags ?? []).map((tag) => { const labelKey = tag.isDefault diff --git a/apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout.ts b/apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout-mutation.ts similarity index 90% rename from apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout.ts rename to apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout-mutation.ts index f2310830..3c7b72dc 100644 --- a/apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout.ts +++ b/apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout-mutation.ts @@ -5,7 +5,7 @@ import { useMutation } from "@tanstack/react-query"; import { logout } from "@/api/generated/endpoints/auth/auth"; import { useClearSession } from "@/app/[locale]/(main)/settings/_hooks/use-clear-session"; -export const useLogoutAction = () => { +export const useLogoutMutation = () => { const clearSession = useClearSession(); return useMutation({ diff --git a/apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw.ts b/apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation.ts similarity index 89% rename from apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw.ts rename to apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation.ts index 5c5ecfde..6dddc62f 100644 --- a/apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw.ts +++ b/apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation.ts @@ -5,7 +5,7 @@ import { useMutation } from "@tanstack/react-query"; import { withdraw } from "@/api/generated/endpoints/auth/auth"; import { useClearSession } from "@/app/[locale]/(main)/settings/_hooks/use-clear-session"; -export const useWithdrawAction = () => { +export const useWithdrawMutation = () => { const clearSession = useClearSession(); return useMutation({ diff --git a/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx b/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx index 8b640da3..2472c9a5 100644 --- a/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx @@ -3,7 +3,7 @@ import { useTranslations } from "next-intl"; import { StatisticsCalendar } from "@/app/[locale]/(main)/statistics/_components/StatisticsCalendar"; -import { useStatisticsCalendarQuery } from "@/app/[locale]/(main)/statistics/_queries/statistics-queries"; +import { useStatisticsCalendarQuery } from "@/app/[locale]/(main)/statistics/_queries/use-statistics-query"; import { LottiePlayer } from "@/components/lottie/LottiePlayer"; import { formatDateKey } from "@/utils/date/date"; diff --git a/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx b/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx index 23611f5c..73dd709f 100644 --- a/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx @@ -12,7 +12,7 @@ import { StatisticsHeaderContainer } from "@/app/[locale]/(main)/statistics/_con import { useStatisticsDailyQuery, useStatisticsSummaryQuery, -} from "@/app/[locale]/(main)/statistics/_queries/statistics-queries"; +} from "@/app/[locale]/(main)/statistics/_queries/use-statistics-query"; import { formatStatisticsSidePanelDate } from "@/app/[locale]/(main)/statistics/_utils/format-statistics-date"; import { formatDateKey } from "@/utils/date/date"; diff --git a/apps/timo-web/app/[locale]/(main)/statistics/_queries/statistics-queries.ts b/apps/timo-web/app/[locale]/(main)/statistics/_queries/use-statistics-query.ts similarity index 100% rename from apps/timo-web/app/[locale]/(main)/statistics/_queries/statistics-queries.ts rename to apps/timo-web/app/[locale]/(main)/statistics/_queries/use-statistics-query.ts diff --git a/apps/timo-web/app/[locale]/layout.tsx b/apps/timo-web/app/[locale]/layout.tsx index 8f27108d..3409e676 100644 --- a/apps/timo-web/app/[locale]/layout.tsx +++ b/apps/timo-web/app/[locale]/layout.tsx @@ -9,7 +9,7 @@ import type { Metadata } from "next"; import { routing } from "@/i18n/routing"; import { AuthProvider } from "@/providers/auth/AuthProvider"; import { LanguageSyncProvider } from "@/providers/locale/LanguageSyncProvider"; -import { OverlayProvider } from "@/providers/OverlayProvider"; +import { OverlayProvider } from "@/providers/overlay/OverlayProvider"; import { QueryProvider } from "@/providers/query/QueryProvider"; const pretendard = localFont({ diff --git a/apps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsx b/apps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsx index e33ff9a7..4c40742a 100644 --- a/apps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsx +++ b/apps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsx @@ -2,10 +2,10 @@ import { useTranslations } from "next-intl"; -import type { TermsType } from "@/types/terms-type"; +import type { TermsType } from "@/schemas/settings/terms-schema"; import { PolicyDocument } from "@/components/policy/PolicyDocument"; -import { useTerms } from "@/queries/use-terms"; +import { useTermsQuery } from "@/queries/settings/use-terms-query"; export interface PolicyContainerProps { type: TermsType; @@ -13,7 +13,7 @@ export interface PolicyContainerProps { export const PolicyContainer = ({ type }: PolicyContainerProps) => { const t = useTranslations("Policy"); - const { data: term } = useTerms(type); + const { data: term } = useTermsQuery(type); if (!term) { return

{t("empty")}

; diff --git a/apps/timo-web/app/[locale]/policy/page.tsx b/apps/timo-web/app/[locale]/policy/page.tsx index 2366061b..1d55e4bc 100644 --- a/apps/timo-web/app/[locale]/policy/page.tsx +++ b/apps/timo-web/app/[locale]/policy/page.tsx @@ -11,7 +11,7 @@ import { AsyncBoundary } from "@/components/boundary/AsyncBoundary"; import { ROUTES } from "@/constants/routes"; import { Link } from "@/i18n/navigation"; import { routing } from "@/i18n/routing"; -import { termsTypeSchema } from "@/types/terms-type"; +import { termsTypeSchema } from "@/schemas/settings/terms-schema"; interface PolicyPageProps { params: Promise<{ locale: string }>; diff --git a/apps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsx b/apps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsx index df34b929..da45c122 100644 --- a/apps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsx +++ b/apps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsx @@ -3,8 +3,8 @@ import { cn } from "@repo/timo-design-system/utils"; import { useEffect, useState } from "react"; -import { useActiveTimer } from "@/hooks/use-active-timer"; -import { useTimeBoxes } from "@/queries/use-time-boxes"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; +import { useTimeBoxesQuery } from "@/queries/time-box/use-time-boxes-query"; import { formatDateKey } from "@/utils/date/date"; import { getHourLabel } from "@/utils/date/get-hour-label"; import { convertDurationToTimeText } from "@/utils/duration/convert-duration-to-time-text"; @@ -38,7 +38,7 @@ export const TimeboxPanel = ({ currentTime }: TimeboxPanelProps) => { const time = currentTime ?? now; const currentTimeOffset = timeToOffset(time); - const { data: timeBoxes } = useTimeBoxes(formatDateKey(time)); + const { data: timeBoxes } = useTimeBoxesQuery(formatDateKey(time)); const { data: activeTimer } = useActiveTimer(); return ( diff --git a/apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx b/apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx index 96c3abd0..562b0e4a 100644 --- a/apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx +++ b/apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx @@ -14,10 +14,10 @@ import { TimerSessionControls, type TimerSessionControlsHandle, } from "@/components/timer/TimerSessionControls"; -import { useActiveTimer } from "@/hooks/use-active-timer"; -import { useTimerActions } from "@/hooks/use-timer-actions"; -import { useTimerOvertime } from "@/hooks/use-timer-overtime"; -import { useTimerQueryInvalidation } from "@/hooks/use-timer-query-invalidation"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; +import { useTimerActions } from "@/hooks/timer/use-timer-actions"; +import { useTimerOvertime } from "@/hooks/timer/use-timer-overtime"; +import { useTimerQueryInvalidation } from "@/hooks/timer/use-timer-query-invalidation"; import { formatDateKey } from "@/utils/date/date"; import { convertDurationToMinutes } from "@/utils/duration/convert-duration-to-minutes"; import { convertDurationToTimeText } from "@/utils/duration/convert-duration-to-time-text"; diff --git a/apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx b/apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx index a09e600b..fcd580a0 100644 --- a/apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx +++ b/apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx @@ -6,10 +6,9 @@ import { CreateButton, TodoToolbar } from "@repo/timo-design-system/ui"; import { useTranslations } from "next-intl"; import { useController, useForm } from "react-hook-form"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import type { PriorityLevel } from "@repo/timo-design-system/ui"; -import { createTodoRequestSchema } from "@/api/common/todo-schema"; import { OverlayModal } from "@/components/modal/OverlayModal"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { TodoIconField } from "@/components/todo-modal/common/TodoIconField"; @@ -21,6 +20,7 @@ import { useRepeatField } from "@/hooks/todo-modal/create/use-repeat-field"; import { useSubtaskField } from "@/hooks/todo-modal/create/use-subtask-field"; import { useTimeField } from "@/hooks/todo-modal/create/use-time-field"; import { useTitleField } from "@/hooks/todo-modal/create/use-title-field"; +import { createTodoRequestSchema } from "@/schemas/todo/todo-schema"; import { formatDateKey, formatShortDateLabel } from "@/utils/date/date"; const createDefaultValues = (defaultDate?: Date): CreateTodoRequest => ({ diff --git a/apps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsx b/apps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsx index 23e069a8..0a04c1aa 100644 --- a/apps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsx +++ b/apps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsx @@ -5,7 +5,7 @@ import { useTranslations } from "next-intl"; import { overlay } from "overlay-kit"; import { useState } from "react"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { CreateTodoModalContent } from "@/components/todo-modal/create/CreateTodoModalContent"; diff --git a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx index ee442775..a2028a9d 100644 --- a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx +++ b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx @@ -9,9 +9,9 @@ import type { ReactNode } from "react"; import { useGetTodoDetail } from "@/api/generated/endpoints/todo/todo"; import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { DetailTodoModalContent } from "@/components/todo-modal/detail/DetailTodoModalContent"; +import { useActiveTimer } from "@/hooks/timer/use-active-timer"; import { useDeleteTodoSubmit } from "@/hooks/todo-modal/detail/use-delete-todo-submit"; import { useUpdateTodoSubmit } from "@/hooks/todo-modal/detail/use-update-todo-submit"; -import { useActiveTimer } from "@/hooks/use-active-timer"; export interface DetailTodoModalContainerProps { todoId: number; diff --git a/apps/timo-web/hooks/use-active-timer.ts b/apps/timo-web/hooks/timer/use-active-timer.ts similarity index 95% rename from apps/timo-web/hooks/use-active-timer.ts rename to apps/timo-web/hooks/timer/use-active-timer.ts index e3f36b20..5713a836 100644 --- a/apps/timo-web/hooks/use-active-timer.ts +++ b/apps/timo-web/hooks/timer/use-active-timer.ts @@ -7,7 +7,7 @@ import { getActiveTimer, getGetActiveTimerQueryKey, } from "@/api/generated/endpoints/timer/timer"; -import { activeTimerSchema } from "@/types/timer-type"; +import { activeTimerSchema } from "@/schemas/timer/timer-schema"; export const useActiveTimer = () => { const query = useQuery({ diff --git a/apps/timo-web/hooks/use-timer-actions.ts b/apps/timo-web/hooks/timer/use-timer-actions.ts similarity index 97% rename from apps/timo-web/hooks/use-timer-actions.ts rename to apps/timo-web/hooks/timer/use-timer-actions.ts index e356af93..6860499d 100644 --- a/apps/timo-web/hooks/use-timer-actions.ts +++ b/apps/timo-web/hooks/timer/use-timer-actions.ts @@ -7,7 +7,7 @@ import type { useStopTimer, } from "@/api/generated/endpoints/timer/timer"; import type { useChangeTodoStatus } from "@/api/generated/endpoints/todo/todo"; -import type { ActiveTimer } from "@/types/timer-type"; +import type { ActiveTimer } from "@/schemas/timer/timer-schema"; type ChangeStatusMutate = ReturnType["mutate"]; type ExtendTimerMutate = ReturnType["mutate"]; diff --git a/apps/timo-web/hooks/use-timer-overtime.ts b/apps/timo-web/hooks/timer/use-timer-overtime.ts similarity index 93% rename from apps/timo-web/hooks/use-timer-overtime.ts rename to apps/timo-web/hooks/timer/use-timer-overtime.ts index 59d24146..149be211 100644 --- a/apps/timo-web/hooks/use-timer-overtime.ts +++ b/apps/timo-web/hooks/timer/use-timer-overtime.ts @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; -import type { ActiveTimer } from "@/types/timer-type"; +import type { ActiveTimer } from "@/schemas/timer/timer-schema"; const STORAGE_KEY_PREFIX = "timo:overtime-base:"; diff --git a/apps/timo-web/hooks/use-timer-query-invalidation.ts b/apps/timo-web/hooks/timer/use-timer-query-invalidation.ts similarity index 100% rename from apps/timo-web/hooks/use-timer-query-invalidation.ts rename to apps/timo-web/hooks/timer/use-timer-query-invalidation.ts diff --git a/apps/timo-web/hooks/todo-modal/common/use-tag-field.tsx b/apps/timo-web/hooks/todo-modal/common/use-tag-field.tsx index 85ab0195..c8cfd5b8 100644 --- a/apps/timo-web/hooks/todo-modal/common/use-tag-field.tsx +++ b/apps/timo-web/hooks/todo-modal/common/use-tag-field.tsx @@ -5,10 +5,10 @@ import { useController } from "react-hook-form"; import type { Control, FieldValues, Path } from "react-hook-form"; -import { tagCreateDataSchema } from "@/api/common/tag-schema"; import { CreateTagModalContainer } from "@/components/tag/CreateTagModalContainer"; -import { useCreateTag } from "@/queries/tag/use-create-tag"; -import { useTags } from "@/queries/tag/use-tags"; +import { useCreateTagMutation } from "@/queries/tag/use-create-tag-mutation"; +import { useTagsQuery } from "@/queries/tag/use-tags-query"; +import { tagCreateDataSchema } from "@/schemas/tag/tag-schema"; import { getDefaultTagLabelKey } from "@/utils/todo/tag-label"; const MAX_TAG_COUNT = 8; @@ -43,8 +43,8 @@ export const useTagField = ({ const [isCreateTagErrorToastOpen, setIsCreateTagErrorToastOpen] = useState(false); - const tagsQuery = useTags(); - const { mutate: createTag } = useCreateTag(); + const tagsQuery = useTagsQuery(); + const { mutate: createTag } = useCreateTagMutation(); const tagOptions = (tagsQuery.data?.tags ?? []).map((tag) => { const defaultLabelKey = getDefaultTagLabelKey(tag.tagId); diff --git a/apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts b/apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts index f0027f28..d7074344 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts @@ -3,12 +3,12 @@ import { useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; import type { TodoCreateRequest } from "@/api/generated/models"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; -import { todoCreateResponseSchema } from "@/api/common/todo-schema"; import { getGetHomeQueryKey } from "@/api/generated/endpoints/home/home"; import { useCreateTodo } from "@/api/generated/endpoints/todo/todo"; +import { todoCreateResponseSchema } from "@/schemas/todo/todo-schema"; const buildCreateTodoRequestBody = ( data: CreateTodoRequest, diff --git a/apps/timo-web/hooks/todo-modal/create/use-icon-field.ts b/apps/timo-web/hooks/todo-modal/create/use-icon-field.ts index 42ad2f15..452f9624 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-icon-field.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-icon-field.ts @@ -1,7 +1,7 @@ import { useState } from "react"; import { useController } from "react-hook-form"; -import type { CreateTodoRequest, TodoIcon } from "@/api/common/todo-schema"; +import type { CreateTodoRequest, TodoIcon } from "@/schemas/todo/todo-schema"; import type { Control } from "react-hook-form"; export interface UseIconFieldParams { diff --git a/apps/timo-web/hooks/todo-modal/create/use-repeat-field.ts b/apps/timo-web/hooks/todo-modal/create/use-repeat-field.ts index 7119de66..b1cc14ff 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-repeat-field.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-repeat-field.ts @@ -4,7 +4,7 @@ import { useController } from "react-hook-form"; import type { CreateTodoRequest, TodoRepeatWeekday, -} from "@/api/common/todo-schema"; +} from "@/schemas/todo/todo-schema"; import type { RepeatFrequency } from "@repo/timo-design-system/ui"; import type { Control } from "react-hook-form"; diff --git a/apps/timo-web/hooks/todo-modal/create/use-subtask-field.ts b/apps/timo-web/hooks/todo-modal/create/use-subtask-field.ts index efd5319f..e18116ff 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-subtask-field.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-subtask-field.ts @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { useController } from "react-hook-form"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import type { SubtaskInputEntry } from "@/utils/todo/subtask-input-list"; import type { KeyboardEvent } from "react"; import type { Control } from "react-hook-form"; diff --git a/apps/timo-web/hooks/todo-modal/create/use-time-field.ts b/apps/timo-web/hooks/todo-modal/create/use-time-field.ts index 9223310b..231e0d3a 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-time-field.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-time-field.ts @@ -1,13 +1,13 @@ import { useState } from "react"; import { useController, useWatch } from "react-hook-form"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import type { TimeSelection } from "@repo/timo-design-system/ui"; import type { Control } from "react-hook-form"; -import { recommendDurationResponseSchema } from "@/api/common/todo-schema"; import { useRecommendDuration } from "@/api/generated/endpoints/ai/ai"; import { SECONDS_PER_HOUR, SECONDS_PER_MINUTE } from "@/constants/time"; +import { recommendDurationResponseSchema } from "@/schemas/todo/todo-schema"; import { convertApiDurationToSeconds, convertSecondsToApiDuration, diff --git a/apps/timo-web/hooks/todo-modal/create/use-title-field.ts b/apps/timo-web/hooks/todo-modal/create/use-title-field.ts index 8f1a28db..9239f170 100644 --- a/apps/timo-web/hooks/todo-modal/create/use-title-field.ts +++ b/apps/timo-web/hooks/todo-modal/create/use-title-field.ts @@ -1,6 +1,6 @@ import { useController } from "react-hook-form"; -import type { CreateTodoRequest } from "@/api/common/todo-schema"; +import type { CreateTodoRequest } from "@/schemas/todo/todo-schema"; import type { Control } from "react-hook-form"; import { diff --git a/apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts b/apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts index 96c127f5..dc74d87f 100644 --- a/apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts +++ b/apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from "react"; -import type { TodoSubtask } from "@/api/common/todo-schema"; +import type { TodoSubtask } from "@/schemas/todo/todo-schema"; import type { SubtaskInputEntry } from "@/utils/todo/subtask-input-list"; import type { KeyboardEvent } from "react"; diff --git a/apps/timo-web/providers/locale/LanguageSyncProvider.tsx b/apps/timo-web/providers/locale/LanguageSyncProvider.tsx index b7377bb5..4aca745e 100644 --- a/apps/timo-web/providers/locale/LanguageSyncProvider.tsx +++ b/apps/timo-web/providers/locale/LanguageSyncProvider.tsx @@ -5,14 +5,14 @@ import { useEffect } from "react"; import { AsyncBoundary } from "@/components/boundary/AsyncBoundary"; import { usePathname, useRouter } from "@/i18n/navigation"; -import { useMyProfile } from "@/queries/use-my-profile"; +import { useMyProfileQuery } from "@/queries/auth/use-my-profile-query"; import { useAuthStore } from "@/stores/auth/useAuthStore"; const isSupportedLocale = (value: string): value is "ko" | "en" => value === "ko" || value === "en"; const LanguageSync = () => { - const { data: profile } = useMyProfile(); + const { data: profile } = useMyProfileQuery(); const locale = useLocale(); const router = useRouter(); const pathname = usePathname(); diff --git a/apps/timo-web/providers/OverlayProvider.tsx b/apps/timo-web/providers/overlay/OverlayProvider.tsx similarity index 100% rename from apps/timo-web/providers/OverlayProvider.tsx rename to apps/timo-web/providers/overlay/OverlayProvider.tsx diff --git a/apps/timo-web/queries/use-my-profile.ts b/apps/timo-web/queries/auth/use-my-profile-query.ts similarity index 82% rename from apps/timo-web/queries/use-my-profile.ts rename to apps/timo-web/queries/auth/use-my-profile-query.ts index 474727dd..71e67bb3 100644 --- a/apps/timo-web/queries/use-my-profile.ts +++ b/apps/timo-web/queries/auth/use-my-profile-query.ts @@ -6,13 +6,13 @@ import { getGetMyProfileQueryKey, getMyProfile, } from "@/api/generated/endpoints/user/user"; -import { userProfileSchema } from "@/types/user-profile-type"; +import { userProfileSchema } from "@/schemas/auth/user-profile-schema"; /** * 로그인한 유저의 프로필을 조회한다. * accessToken이 보장되는 화면(AuthGuardProvider 하위 등)에서만 사용해야 한다. */ -export const useMyProfile = () => +export const useMyProfileQuery = () => useSuspenseQuery({ queryKey: getGetMyProfileQueryKey(), queryFn: ({ signal }) => getMyProfile(undefined, signal), diff --git a/apps/timo-web/queries/use-terms.ts b/apps/timo-web/queries/settings/use-terms-query.ts similarity index 82% rename from apps/timo-web/queries/use-terms.ts rename to apps/timo-web/queries/settings/use-terms-query.ts index 231999a0..0c1dae93 100644 --- a/apps/timo-web/queries/use-terms.ts +++ b/apps/timo-web/queries/settings/use-terms-query.ts @@ -7,14 +7,17 @@ import { getGetTermsByConditionQueryKey, getTermsByCondition, } from "@/api/generated/endpoints/terms/terms"; -import { termsDetailSchema, type TermsType } from "@/types/terms-type"; +import { + termsDetailSchema, + type TermsType, +} from "@/schemas/settings/terms-schema"; const TERMS_LANGUAGE_MAP: Record<"ko" | "en", string> = { ko: "KO", en: "EN", }; -export const useTerms = (type: TermsType) => { +export const useTermsQuery = (type: TermsType) => { const locale = useLocale() as "ko" | "en"; const params = { type, language: TERMS_LANGUAGE_MAP[locale] }; diff --git a/apps/timo-web/queries/tag/use-create-tag.ts b/apps/timo-web/queries/tag/use-create-tag-mutation.ts similarity index 92% rename from apps/timo-web/queries/tag/use-create-tag.ts rename to apps/timo-web/queries/tag/use-create-tag-mutation.ts index 89183f3f..2fffb2a4 100644 --- a/apps/timo-web/queries/tag/use-create-tag.ts +++ b/apps/timo-web/queries/tag/use-create-tag-mutation.ts @@ -10,7 +10,7 @@ import { getGetTagsQueryKey, } from "@/api/generated/endpoints/tag/tag"; -export const useCreateTag = () => { +export const useCreateTagMutation = () => { const queryClient = useQueryClient(); return useMutation({ diff --git a/apps/timo-web/queries/tag/use-delete-tag.ts b/apps/timo-web/queries/tag/use-delete-tag-mutation.ts similarity index 90% rename from apps/timo-web/queries/tag/use-delete-tag.ts rename to apps/timo-web/queries/tag/use-delete-tag-mutation.ts index 62d56bc3..092295e0 100644 --- a/apps/timo-web/queries/tag/use-delete-tag.ts +++ b/apps/timo-web/queries/tag/use-delete-tag-mutation.ts @@ -7,7 +7,7 @@ import { getGetTagsQueryKey, } from "@/api/generated/endpoints/tag/tag"; -export const useDeleteTag = () => { +export const useDeleteTagMutation = () => { const queryClient = useQueryClient(); return useMutation({ diff --git a/apps/timo-web/queries/tag/use-tags.ts b/apps/timo-web/queries/tag/use-tags-query.ts similarity index 65% rename from apps/timo-web/queries/tag/use-tags.ts rename to apps/timo-web/queries/tag/use-tags-query.ts index 9918b361..b43a2e2d 100644 --- a/apps/timo-web/queries/tag/use-tags.ts +++ b/apps/timo-web/queries/tag/use-tags-query.ts @@ -1,9 +1,9 @@ "use client"; -import { tagListDataSchema } from "@/api/common/tag-schema"; import { useGetTags } from "@/api/generated/endpoints/tag/tag"; +import { tagListDataSchema } from "@/schemas/tag/tag-schema"; -export const useTags = () => +export const useTagsQuery = () => useGetTags({ query: { select: ({ data }) => tagListDataSchema.parse(data), diff --git a/apps/timo-web/queries/use-time-boxes.ts b/apps/timo-web/queries/time-box/use-time-boxes-query.ts similarity index 75% rename from apps/timo-web/queries/use-time-boxes.ts rename to apps/timo-web/queries/time-box/use-time-boxes-query.ts index f83bf6fd..d8e3b9b8 100644 --- a/apps/timo-web/queries/use-time-boxes.ts +++ b/apps/timo-web/queries/time-box/use-time-boxes-query.ts @@ -6,9 +6,9 @@ import { getGetTimeBoxesQueryKey, getTimeBoxes, } from "@/api/generated/endpoints/time-box/time-box"; -import { timeBoxListSchema } from "@/types/timebox-type"; +import { timeBoxListSchema } from "@/schemas/timebox/timebox-schema"; -export const useTimeBoxes = (date: string) => +export const useTimeBoxesQuery = (date: string) => useQuery({ queryKey: getGetTimeBoxesQueryKey({ date }), queryFn: ({ signal }) => getTimeBoxes({ date }, undefined, signal), diff --git a/apps/timo-web/types/user-profile-type.ts b/apps/timo-web/schemas/auth/user-profile-schema.ts similarity index 100% rename from apps/timo-web/types/user-profile-type.ts rename to apps/timo-web/schemas/auth/user-profile-schema.ts diff --git a/apps/timo-web/types/terms-type.ts b/apps/timo-web/schemas/settings/terms-schema.ts similarity index 100% rename from apps/timo-web/types/terms-type.ts rename to apps/timo-web/schemas/settings/terms-schema.ts diff --git a/apps/timo-web/api/common/tag-schema.ts b/apps/timo-web/schemas/tag/tag-schema.ts similarity index 100% rename from apps/timo-web/api/common/tag-schema.ts rename to apps/timo-web/schemas/tag/tag-schema.ts diff --git a/apps/timo-web/types/timebox-type.ts b/apps/timo-web/schemas/timebox/timebox-schema.ts similarity index 100% rename from apps/timo-web/types/timebox-type.ts rename to apps/timo-web/schemas/timebox/timebox-schema.ts diff --git a/apps/timo-web/types/timer-type.ts b/apps/timo-web/schemas/timer/timer-schema.ts similarity index 100% rename from apps/timo-web/types/timer-type.ts rename to apps/timo-web/schemas/timer/timer-schema.ts diff --git a/apps/timo-web/api/common/todo-schema.ts b/apps/timo-web/schemas/todo/todo-schema.ts similarity index 100% rename from apps/timo-web/api/common/todo-schema.ts rename to apps/timo-web/schemas/todo/todo-schema.ts diff --git a/docs/conventions/naming.md b/docs/conventions/naming.md index f9f2ef85..ba5d0791 100644 --- a/docs/conventions/naming.md +++ b/docs/conventions/naming.md @@ -6,3 +6,13 @@ | 컴포넌트 파일 | `PascalCase` | `UserCard.tsx` | | Hook / API / Utils | `kebab-case` | `use-auth.ts`, `auth-api.ts`, `format-date.ts` | | TanStack Query | `kebab-case` | `use-user-query.ts`, `use-user-mutation.ts` | + +## TanStack Query 훅 네이밍 + +- 파일명: 조회(`useQuery`/`useSuspenseQuery`)는 `-query.ts`, 변경(`useMutation`)은 `-mutation.ts`로 끝난다. + - 예: `use-my-profile-query.ts`, `use-create-tag-mutation.ts` +- 함수명: 파일명과 대응해 `~Query`, `~Mutation` 접미사를 붙인다. + - 예: `useMyProfileQuery`, `useCreateTagMutation` +- 파일당 훅 1개가 기본이다. 같은 도메인의 조회/변경 훅을 한 파일에 묶지 않는다. +- 이 규칙은 react-query를 직접 감싸는 순수 조회/변경 훅에 적용한다. 조회 결과에 추가 상태·로직을 합성한 훅(예: 타이머 tick 로직이 섞인 훅)은 대상이 아니다 — 이런 훅은 역할을 드러내는 이름을 그대로 쓴다. +- 위치는 `docs/architecture/structure.md`의 `_queries/`(도메인 전용) / `queries/`(전역 공유) 규칙을 따른다.