diff --git a/app/error.tsx b/app/error.tsx new file mode 100644 index 00000000..0c788e08 --- /dev/null +++ b/app/error.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { useRouter } from 'next/navigation'; +import { startTransition } from 'react'; +import Button from '@/shared/ui/button'; + +export default function ErrorBoundary({ + error, + reset, +}: { + error: Error; + reset: () => void; +}) { + const router = useRouter(); + + return ( +
+
+

+ 서비스 이용에 불편드려 죄송합니다. +

+
+ + 에러가 발생하여 페이지를 표시할 수 없습니다. + + + 잠시 뒤에 다시 시도해주세요. + +
+
+ +
+ ); +} diff --git a/src/entities/review/model/use-review-query.ts b/src/entities/review/model/use-review-query.ts index 26d994a0..cbaf66a3 100644 --- a/src/entities/review/model/use-review-query.ts +++ b/src/entities/review/model/use-review-query.ts @@ -9,6 +9,7 @@ import { UserPositiveKeywordsRequest, } from '@/entities/review/api/review-types'; import { getKoreaDate } from '@/shared/lib/time'; +import { isApiError } from '@/shared/tanstack-query/api-error'; import { addStudyReview, getUserPositiveKeywords, @@ -32,6 +33,15 @@ export const useAddStudyReviewMutation = () => { // todo: 모달로 변경 alert('후기 작성이 완료되었습니다.'); }, + onError: (error) => { + if (isApiError(error)) { + if (error.errorCode === 'CMM001') { + alert('이미 후기를 작성했습니다.'); + } else if (error.errorCode === 'CMM003') { + alert('스터디 또는 스터디 멤버가 존재하지 않습니다.'); + } + } + }, }); }; diff --git a/src/entities/user/model/use-user-profile-query.ts b/src/entities/user/model/use-user-profile-query.ts index 38d00741..bbec6c9f 100644 --- a/src/entities/user/model/use-user-profile-query.ts +++ b/src/entities/user/model/use-user-profile-query.ts @@ -6,6 +6,7 @@ import { } from '@/entities/user/api/get-user-profile'; import type { GetUserProfileResponse } from '@/entities/user/api/types'; import { hashValue } from '@/shared/lib/hash'; +import { isApiError } from '@/shared/tanstack-query/api-error'; export const useUserProfileQuery = (memberId: number) => { return useQuery({ @@ -45,10 +46,18 @@ export const usePatchAutoMatchingMutation = () => { return { prev }; }, - onError: (_err, { memberId }, ctx) => { + onError: (error, { memberId }, ctx) => { if (ctx?.prev) { qc.setQueryData(['userProfile', memberId], ctx.prev); } + + if (isApiError(error)) { + if (error.errorCode === 'MEM004') { + alert('아직 스터디를 신청하지 않았습니다. 먼저 스터디 신청해주세요.'); + } else if (error.errorCode === 'MEM001') { + alert('회원 정보가 존재하지 않습니다.'); + } + } }, onSuccess: async (_data, { memberId, autoMatching }) => { diff --git a/src/features/auth/model/use-auth-mutation.ts b/src/features/auth/model/use-auth-mutation.ts index b81c0725..712e67ff 100644 --- a/src/features/auth/model/use-auth-mutation.ts +++ b/src/features/auth/model/use-auth-mutation.ts @@ -5,6 +5,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; import { logout, signUp, uploadProfileImage } from '@/features/auth/api/auth'; import { hashValue } from '@/shared/lib/hash'; +import { isApiError } from '@/shared/tanstack-query/api-error'; import { deleteCookie, getCookie } from '@/shared/tanstack-query/cookie'; import { SignUpResponse } from './types'; @@ -16,6 +17,13 @@ export const useSignUpMutation = () => { { name: string; imageExtension: string } >({ mutationFn: (data: any) => signUp(data), + onError: (error) => { + if (isApiError(error)) { + if (error.errorCode === 'DUPLICATE_MEMBER') { + alert('이미 가입된 회원입니다.'); + } + } + }, }); }; diff --git a/src/features/my-page/model/use-update-user-profile-mutation.ts b/src/features/my-page/model/use-update-user-profile-mutation.ts index d49cdaf7..5b34e273 100644 --- a/src/features/my-page/model/use-update-user-profile-mutation.ts +++ b/src/features/my-page/model/use-update-user-profile-mutation.ts @@ -1,5 +1,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; +import { isApiError } from '@/shared/tanstack-query/api-error'; import { UpdateUserProfileInfoRequest, UpdateUserProfileRequest, @@ -24,6 +25,15 @@ export const useUpdateUserProfileMutation = (memberId: number) => { onSuccess: () => { router.refresh(); }, + onError: (error) => { + if (isApiError(error)) { + if (error.errorCode === 'MPR001') { + alert('관심사가 중복됐습니다.'); + } else if (error.errorCode === 'MEM001') { + alert('회원 정보가 존재하지 않습니다.'); + } + } + }, }); };