diff --git a/public/error.png b/public/error.png new file mode 100644 index 0000000..8aa59c2 Binary files /dev/null and b/public/error.png differ diff --git a/src/components/community/shared/PostDetail.tsx b/src/components/community/shared/PostDetail.tsx index 6c2abe0..11bd4ff 100644 --- a/src/components/community/shared/PostDetail.tsx +++ b/src/components/community/shared/PostDetail.tsx @@ -6,6 +6,7 @@ import { cancelLike, registerLike } from '../remote/post'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { usePostDetail } from '../factory/postDetailFactory'; +import ErrorBoundary from '@/components/shared/ErrorBoundary'; const PostDetail = () => { const router = useRouter(); @@ -53,7 +54,7 @@ const PostDetail = () => { {/* 유저 사진 */}
image {
{/* 유저 이름 */}
-
{postData.writer.nickname}
- {postData.isWriter && ( +
{postData?.writer?.nickname}
+ {postData?.isWriter && (
{ setOpen(true); - setDeleteId(String(postData.postId)); + setDeleteId(String(postData?.postId)); setCategory('post'); }} className="text-gray-500 text-sm font-normal underline cursor-pointer"> @@ -87,13 +88,13 @@ const PostDetail = () => {
{/* 제목자리 */} -
{postData.title}
+
{postData?.title}
{/* 컨텐츠 내용자리 */} -
{postData.content}
+
{postData?.content}
{/* 사진자리 */} - {(postData.images?.length as number) > 0 ? ( + {(postData?.images?.length as number) > 0 ? (
{postData.images?.map((image: string, i: number) => (
@@ -117,10 +118,10 @@ const PostDetail = () => {
{/* 일자 */}
- {formatDate(postData.createdDate)} + {formatDate(postData?.createdDate)}
{/* 시간 */} -
{formatTime(postData.createdDate)}
+
{formatTime(postData?.createdDate)}
{/* 좋아요 조회수 자리 */} @@ -128,10 +129,10 @@ const PostDetail = () => { {/* 좋아요 */}
{ - if (postData.isLiked) { - cancelLikeMutate(postData.postId); + if (postData?.isLiked) { + cancelLikeMutate(postData?.postId); } else { - registerLikeMutate(postData.postId); + registerLikeMutate(postData?.postId); } }} className="flex items-center justify-center gap-1 cursor-pointer"> @@ -139,7 +140,7 @@ const PostDetail = () => {
좋아요
-
{postData.likeCount}
+
{postData?.likeCount}
@@ -151,7 +152,7 @@ const PostDetail = () => {
조회수
-
{postData.viewCount}
+
{postData?.viewCount}
@@ -159,4 +160,25 @@ const PostDetail = () => { ); }; -export default PostDetail; +export default WrapErrorBoundary; + +function WrapErrorBoundary() { + return ( + +
+ error +
+ 글을 가져오는 중 일시적인 오류가 발생했습니다. +
+
+ 잠시 후 다시 시도해주세요 +
+
+
+ }> + + + ); +} diff --git a/src/components/shared/ErrorBoundary.tsx b/src/components/shared/ErrorBoundary.tsx new file mode 100644 index 0000000..75263ef --- /dev/null +++ b/src/components/shared/ErrorBoundary.tsx @@ -0,0 +1,35 @@ +import React, { ErrorInfo } from 'react'; + +interface Props { + children: React.ReactNode; + fallbackComponent?: React.ReactNode; +} + +interface State { + hasError: boolean; +} + +class ErrorBoundary extends React.Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false }; + } + static getDerivedStateFromError() { + return { hasError: true }; + } + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.log({ error, errorInfo }); + } + render() { + if (this.state.hasError) { + if (this.props.fallbackComponent != null) { + return <>{this.props.fallbackComponent}; + } + + return
문제가 발생했어요.
; + } + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 6272d2d..f2a4a41 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -2,10 +2,12 @@ import { authHandlers } from './authHandler'; import { questionHandlers } from './questionHandler'; import { notificationHandler } from './notificationHandler'; import { postHandlers } from './postHandler'; +import { mainErrorHandlers } from './mainPageHandler'; export const handlers = [ ...authHandlers, ...questionHandlers, ...notificationHandler, - ...postHandlers + ...postHandlers, + ...mainErrorHandlers ]; diff --git a/src/mocks/mainPageHandler/index.ts b/src/mocks/mainPageHandler/index.ts new file mode 100644 index 0000000..f575f77 --- /dev/null +++ b/src/mocks/mainPageHandler/index.ts @@ -0,0 +1,12 @@ +import { http, HttpResponse } from 'msw'; + +export const mainErrorHandlers = [ + http.get(`https://joo-api.store/branches/27/available-count`, () => { + return new HttpResponse('Not found', { + status: 400, + headers: { + 'Content-Type': 'text/plain' + } + }); + }) +]; diff --git a/src/mocks/mainPageHandler/mocks.ts b/src/mocks/mainPageHandler/mocks.ts new file mode 100644 index 0000000..98eb2a8 --- /dev/null +++ b/src/mocks/mainPageHandler/mocks.ts @@ -0,0 +1,6 @@ +export const MOCK_MAIN_DATA = { + status: 400, + errorCode: null, + data: null, + message: '오늘의 일정을 가져오는 중 에러 발생' +}; diff --git a/src/mocks/postHandler/index.ts b/src/mocks/postHandler/index.ts index 3436ed8..468922e 100644 --- a/src/mocks/postHandler/index.ts +++ b/src/mocks/postHandler/index.ts @@ -3,7 +3,9 @@ import { MOCK_POSTDETAIL_DATA } from './mocks'; export const postHandlers = [ /* ----- 글 상세 데이터 가져오기 api ----- */ - http.get(`https://joo-api.store/posts/39`, () => { - return HttpResponse.json(MOCK_POSTDETAIL_DATA); + http.get(`https://joo-api.store/posts/25`, () => { + return HttpResponse.json('Not found', { + status: 404 + }); }) ]; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 2f7ffa6..ed03455 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,3 +1,4 @@ +import ErrorBoundary from '@/components/shared/ErrorBoundary'; import Layout from '@/components/shared/Layout'; import LoadingSpinner from '@/components/shared/LoadingSpinner'; import { AuthorizationProvider } from '@/providers/Authentication'; @@ -42,8 +43,10 @@ export default function App({ Component, pageProps }: AppProps) { - {loading && } - + + {loading && } + +