diff --git a/eslint.config.mjs b/eslint.config.mjs index cf5d66b..e5b2817 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -48,6 +48,21 @@ const eslintConfig = [ }, }, ...storybook.configs["flat/recommended"], + // 260612 추가 : 공식문서 참고 + { + rules: { + "react/no-unescaped-entities": "off", + "@next/next/no-page-custom-font": "off", + }, + }, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), ]; export default eslintConfig; diff --git a/package.json b/package.json index 51f53ce..1d0b1f7 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "eslint-config-next": "15.4.10", "eslint-config-prettier": "^10.1.8", "eslint-plugin-jest-dom": "^5.5.0", + "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-storybook": "^10.0.8", "eslint-plugin-testing-library": "^7.13.4", "globals": "^16.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42f7f62..bba7d99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,9 @@ importers: eslint-plugin-jest-dom: specifier: ^5.5.0 version: 5.5.0(@testing-library/dom@10.4.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: ^7.1.1 + version: 7.1.1(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-storybook: specifier: ^10.0.8 version: 10.0.8(eslint@9.39.1(jiti@2.6.1))(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.1)))(typescript@5.9.3) @@ -3237,6 +3240,12 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} @@ -3563,6 +3572,12 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -5517,6 +5532,15 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zustand@5.0.8: resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} engines: {node: '>=12.20.0'} @@ -8997,6 +9021,17 @@ snapshots: dependencies: eslint: 9.39.1(jiti@2.6.1) + eslint-plugin-react-hooks@7.1.1(eslint@9.39.1(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 + eslint: 9.39.1(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): dependencies: array-includes: 3.1.9 @@ -9367,6 +9402,12 @@ snapshots: dependencies: function-bind: 1.1.2 + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 @@ -11626,6 +11667,12 @@ snapshots: yocto-queue@0.1.0: {} + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} + zustand@5.0.8(@types/react@19.2.6)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)): optionalDependencies: '@types/react': 19.2.6 diff --git a/src/hooks/queries/goals/useDeleteGoalMutation.ts b/src/hooks/queries/goals/useDeleteGoalMutation.ts index 0b802ee..b4eb485 100644 --- a/src/hooks/queries/goals/useDeleteGoalMutation.ts +++ b/src/hooks/queries/goals/useDeleteGoalMutation.ts @@ -7,6 +7,7 @@ import { deleteGoal } from "@/api/goal"; import goalsQueryKeys from "./queryKeys"; import { useRouter } from "next/navigation"; import { Goal, GoalResponse } from "@/api/types/goal"; +import { toast } from "sonner"; type GoalsCache = | { nextCursor: number | null; totalCount: number; goals: Goal[] } @@ -23,63 +24,27 @@ export function useDeleteGoalMutation() { await queryClient.cancelQueries({ queryKey: goalsQueryKeys.detail(goalId), }); - await queryClient.cancelQueries({ - queryKey: goalsQueryKeys.list(), - }); + await queryClient.cancelQueries({ queryKey: goalsQueryKeys.infinite(), }); - queryClient.setQueriesData( - { queryKey: goalsQueryKeys.list() }, - (old) => { - if (!old?.goals) return old; - return { - ...old, - totalCount: old.totalCount - 1, - goals: old.goals.filter((goal) => goal.id !== goalId), - }; - }, - ); - - queryClient.setQueriesData>( - { queryKey: goalsQueryKeys.infinite() }, - (old) => { - if (!old?.pages) return old; - return { - ...old, - pages: old.pages.map((page) => ({ - ...page, - totalCount: page.totalCount - 1, - goals: page.goals.filter((goal) => goal.id !== goalId), - })), - }; - }, - ); - queryClient.removeQueries({ queryKey: goalsQueryKeys.detail(goalId), }); }, onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: goalsQueryKeys.list(), - }); - queryClient.invalidateQueries({ - queryKey: goalsQueryKeys.infinite(), - }); - router.replace("/dashboard"); }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey: goalsQueryKeys.list() }); + queryClient.invalidateQueries({ queryKey: goalsQueryKeys.infinite() }); + }, + onError: () => { - queryClient.invalidateQueries({ - queryKey: goalsQueryKeys.list(), - }); - queryClient.invalidateQueries({ - queryKey: goalsQueryKeys.infinite(), - }); + toast.error("삭제에 실패했습니다."); }, }); }