From 263857845248a77155e976c93291fd56ba58d3ba Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Tue, 12 May 2026 13:36:42 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20=EB=B6=81=EB=A7=88=ED=81=AC=20api?= =?UTF-8?q?=20error=20toast=EB=AA=A8=EB=8B=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/api/activity.ts | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/shared/api/activity.ts b/src/shared/api/activity.ts index c58ef0a..8495f8c 100644 --- a/src/shared/api/activity.ts +++ b/src/shared/api/activity.ts @@ -1,12 +1,13 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { QueryKey } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; import type { ActivityPostType, ReadPostType } from "./activity.types"; import api from "./api"; import { SHARED_QUERY_KEY } from "../consts/queryKeys"; import { updateBookmarkState } from "../lib/updateBookmarkState"; -import { - API_ENDPOINTS, - getActivityPostsEndpoint, -} from "../consts/endpoints"; +import { API_ENDPOINTS, getActivityPostsEndpoint } from "../consts/endpoints"; +import { ACTIVITY_ERROR } from "@/shared/consts/errorCodes"; +import { toast } from "react-toastify"; export type { ActivityPostType }; @@ -21,7 +22,12 @@ export const usePostBookmark = () => { const queryClient = useQueryClient(); const postsQueryKey = [SHARED_QUERY_KEY.POSTS] as const; - return useMutation({ + return useMutation< + unknown, + AxiosError<{ code: string; message: string }>, + number, + { previousQueries: [QueryKey, unknown][] } + >({ mutationFn: (postId: number) => postBookmark(postId), onMutate: async postId => { await queryClient.cancelQueries({ queryKey: postsQueryKey }); @@ -37,8 +43,15 @@ export const usePostBookmark = () => { return { previousQueries }; }, - onError: () => - queryClient.invalidateQueries({ queryKey: postsQueryKey }), + onError: (e, _, context) => { + if (e?.response?.data?.code === ACTIVITY_ERROR.ALREADY_BOOKMARKED) { + toast.error(e.response.data.message); + } + context?.previousQueries.forEach(([queryKey, data]) => { + queryClient.setQueryData(queryKey, data); + }); + queryClient.invalidateQueries({ queryKey: postsQueryKey }); + }, }); }; @@ -53,7 +66,12 @@ export const useDeleteBookmark = () => { const queryClient = useQueryClient(); const postsQueryKey = [SHARED_QUERY_KEY.POSTS] as const; - return useMutation({ + return useMutation< + unknown, + AxiosError<{ code: string; message: string }>, + number, + { previousQueries: [QueryKey, unknown][] } + >({ mutationFn: (postId: number) => deleteBookmark(postId), onMutate: async postId => { await queryClient.cancelQueries({ queryKey: postsQueryKey }); @@ -68,8 +86,15 @@ export const useDeleteBookmark = () => { return { previousQueries }; }, - onError: () => - queryClient.invalidateQueries({ queryKey: postsQueryKey }), + onError: (e, _, context) => { + if (e?.response?.data?.code === ACTIVITY_ERROR.BOOKMARK_NOT_FOUND) { + toast.error(e.response.data.message); + } + context?.previousQueries.forEach(([queryKey, data]) => { + queryClient.setQueryData(queryKey, data); + }); + queryClient.invalidateQueries({ queryKey: postsQueryKey }); + }, }); }; From 59c7a88b8cb810e74eb5211fa6a6f873ff321c34 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Tue, 12 May 2026 14:20:30 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20query=EC=99=80=20mutatuon=20error?= =?UTF-8?q?=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main.tsx b/src/main.tsx index d52e33d..cdb0e2f 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -9,16 +9,30 @@ import { HelmetProvider } from "react-helmet-async"; import App from "@/app/App"; import router from "@/app/routes"; import { initGlobalNavigate } from "@/shared/lib/globalNavigate"; +import { toast } from "react-toastify"; initGlobalNavigate((path) => router.navigate(path)); +const isServerError = (error: unknown) => + axios.isAxiosError(error) && + (error.response?.status === 500 || error.response?.status === 503); + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: (failureCount, error) => { if (axios.isAxiosError(error) && !error.response) return false; + if (isServerError(error)) return false; return failureCount < 3; }, + throwOnError: (error) => isServerError(error), + }, + mutations: { + onError: (error) => { + if (isServerError(error)) { + toast.error("서버에 문제가 발생했습니다. 잠시 후 다시 시도해주세요."); + } + }, }, }, }); From 37d24e46d1aa881e85fdcf985c9f188dd4cf1209 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Tue, 12 May 2026 14:21:38 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20onError=EC=A0=9C=EA=B1=B0=20=ED=9B=84=20=EC=A0=84?= =?UTF-8?q?=EC=97=AD=EC=97=90=EC=84=9C=20error=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/mypage/api/account.ts | 1 - src/features/onboarding/api/onboarding.ts | 2 +- src/shared/api/activity.ts | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/features/mypage/api/account.ts b/src/features/mypage/api/account.ts index fb63ae0..7c02129 100644 --- a/src/features/mypage/api/account.ts +++ b/src/features/mypage/api/account.ts @@ -11,6 +11,5 @@ export const useDeleteAccount = (onSuccess: () => void) => { return useMutation({ mutationFn: deleteAccount, onSuccess: () => onSuccess?.(), - onError: err => console.error(err), }); }; diff --git a/src/features/onboarding/api/onboarding.ts b/src/features/onboarding/api/onboarding.ts index af1b662..1f3415d 100644 --- a/src/features/onboarding/api/onboarding.ts +++ b/src/features/onboarding/api/onboarding.ts @@ -15,6 +15,6 @@ export const useSubmitOnboarding = () => { return useMutation({ mutationFn: (body: OnboardingRequestType) => postOnboarding(body), onSuccess: () => navigate("/"), - onError: err => console.log(err), + // onError: err => console.log(err), }); }; diff --git a/src/shared/api/activity.ts b/src/shared/api/activity.ts index 8495f8c..d4d0b87 100644 --- a/src/shared/api/activity.ts +++ b/src/shared/api/activity.ts @@ -133,8 +133,5 @@ export const usePostReadPost = () => { onSuccess: () => { queryClient.invalidateQueries({ queryKey: postsQueryKey }); }, - onError: err => { - console.log(err); - }, }); }; From b818b0cb01a8aa816a66925cdae6a1e4ea530f9e Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Tue, 12 May 2026 14:34:03 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=20=ED=83=88?= =?UTF-8?q?=ED=87=B4=20error=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/mypage/api/account.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/features/mypage/api/account.ts b/src/features/mypage/api/account.ts index 7c02129..3473d77 100644 --- a/src/features/mypage/api/account.ts +++ b/src/features/mypage/api/account.ts @@ -1,6 +1,10 @@ import api from "@/shared/api/api"; import { API_ENDPOINTS } from "@/shared/consts/endpoints"; +import { USER_ERROR } from "@/shared/consts/errorCodes"; import { useMutation } from "@tanstack/react-query"; +import { toast } from "react-toastify"; +import type { AxiosError } from "axios"; +import useUserStore from "@/shared/model/useUserStore"; export const deleteAccount = async () => { const { data } = await api.patch(API_ENDPOINTS.users.me.withdrawal); @@ -8,8 +12,14 @@ export const deleteAccount = async () => { }; export const useDeleteAccount = (onSuccess: () => void) => { - return useMutation({ + return useMutation>({ mutationFn: deleteAccount, onSuccess: () => onSuccess?.(), + onError: e => { + if (e?.response?.data?.code === USER_ERROR.ALREADY_WITHDRAWN) { + toast.error(e.response.data.message); + useUserStore.getState().logout(); + } + }, }); }; From 363729dd07f07d9f581c381a8afac43398885b78 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Tue, 12 May 2026 14:53:52 +0900 Subject: [PATCH 05/12] =?UTF-8?q?design:=20=EC=84=9C=EB=B2=84=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=AC=B8=EA=B5=AC=20=EC=8C=8D=EB=94=B0=EC=98=B4?= =?UTF-8?q?=ED=91=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/ui/ErrorBoundary.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/ui/ErrorBoundary.tsx b/src/shared/ui/ErrorBoundary.tsx index ff301e3..2506cae 100644 --- a/src/shared/ui/ErrorBoundary.tsx +++ b/src/shared/ui/ErrorBoundary.tsx @@ -22,7 +22,7 @@ export const DefaultErrorFallback = ({
-

"서버에 문제가 발생했습니다."

+

서버에 문제가 발생했습니다.

잠시 후 다시 시도해주세요.