Skip to content

Commit

Permalink
Merge pull request #132 from softeerbootcamp4th/feat/#131-error-handling
Browse files Browse the repository at this point in the history
[Feat] 기존의 ErrorBoundary를 react-error-boundary으로 수정
  • Loading branch information
jhj2713 authored Aug 12, 2024
2 parents afd047c + b93bbbb commit bbb3ad0
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 176 deletions.
20 changes: 18 additions & 2 deletions admin/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2742,7 +2742,16 @@ source-map@^0.5.0:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==

"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -2814,7 +2823,14 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"react": "^18.3.1",
"react-cookie": "^7.2.0",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-router-dom": "^6.25.1",
"vite-plugin-svgr": "^4.2.0"
},
Expand Down
20 changes: 12 additions & 8 deletions client/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { CookiesProvider } from "react-cookie";
import { ErrorBoundary } from "react-error-boundary";
import { Outlet } from "react-router-dom";
import { PhoneNumberProvider } from "@/contexts/phoneNumberContext";
import { ScrollHeaderStyleProvider } from "@/contexts/scrollHeaderStyleContext.tsx";
import ErrorElement from "@/pages/ErrorElement";
import Header from "../Header";

export default function Layout() {
return (
<CookiesProvider>
<ScrollHeaderStyleProvider>
<PhoneNumberProvider>
<Header />
<Outlet />
</PhoneNumberProvider>
</ScrollHeaderStyleProvider>
</CookiesProvider>
<ErrorBoundary fallback={<ErrorElement />}>
<CookiesProvider>
<ScrollHeaderStyleProvider>
<PhoneNumberProvider>
<Header />
<Outlet />
</PhoneNumberProvider>
</ScrollHeaderStyleProvider>
</CookiesProvider>
</ErrorBoundary>
);
}
106 changes: 49 additions & 57 deletions client/src/features/CasperCustom/CasperCustomFinish.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DISSOLVE } from "@/constants/animation";
import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext";
import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext";
import useFetch from "@/hooks/useFetch";
import ErrorBoundary from "@/pages/ErrorBoundary";
import { CASPER_ACTION } from "@/types/casperCustom";
import { GetApplyCountResponse } from "@/types/lotteryApi";
import { saveDomImage } from "@/utils/saveDomImage";
Expand All @@ -30,11 +29,9 @@ export function CasperCustomFinish({
}: CasperCustomFinishProps) {
const [cookies] = useCookies([COOKIE_TOKEN_KEY]);

const {
data: applyCountData,
isError: isErrorgetApplyCount,
fetchData: getApplyCount,
} = useFetch<GetApplyCountResponse>(() => LotteryAPI.getApplyCount(cookies[COOKIE_TOKEN_KEY]));
const { data: applyCountData, fetchData: getApplyCount } = useFetch<GetApplyCountResponse>(() =>
LotteryAPI.getApplyCount(cookies[COOKIE_TOKEN_KEY])
);

const dispatch = useCasperCustomDispatchContext();
const { casperName } = useCasperCustomStateContext();
Expand Down Expand Up @@ -64,62 +61,57 @@ export function CasperCustomFinish({
};

return (
<ErrorBoundary isError={isErrorgetApplyCount}>
<motion.div
className="mt-[60px] flex flex-col items-center"
{...SCROLL_MOTION(DISSOLVE)}
>
<div className="flex items-center gap-[107px]">
<div>
<div ref={casperCustomRef}>
<MyCasperCardFront casperName={casperName} hasRandomButton={false} />
</div>
<motion.div className="mt-[60px] flex flex-col items-center" {...SCROLL_MOTION(DISSOLVE)}>
<div className="flex items-center gap-[107px]">
<div>
<div ref={casperCustomRef}>
<MyCasperCardFront casperName={casperName} hasRandomButton={false} />
</div>

<div className="flex gap-500 h-body-1-bold text-n-white mt-[30px]">
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleSaveImage}
>
이미지 저장
</button>
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleReset}
>
다시 만들기
</button>
</div>
<div className="flex gap-500 h-body-1-bold text-n-white mt-[30px]">
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleSaveImage}
>
이미지 저장
</button>
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleReset}
>
다시 만들기
</button>
</div>
</div>

<div className="flex flex-col items-center gap-[56px]">
{applyCountData && (
<div className="flex flex-col items-center gap-800">
<p className="text-n-neutral-500">응모한 횟수</p>

<Battery applyCount={applyCountData.appliedCount} />

<div className="flex items-center gap-300">
<h2 className="h-heading-2-bold text-n-white">
{applyCountData.appliedCount}
</h2>{" "}
<p className="h-body-2-regular text-n-neutral-300">
/{MAX_APPLY}
</p>
</div>
<div className="flex flex-col items-center gap-[56px]">
{applyCountData && (
<div className="flex flex-col items-center gap-800">
<p className="text-n-neutral-500">응모한 횟수</p>

<Battery applyCount={applyCountData.appliedCount} />

<div className="flex items-center gap-300">
<h2 className="h-heading-2-bold text-n-white">
{applyCountData.appliedCount}
</h2>{" "}
<p className="h-body-2-regular text-n-neutral-300">
/{MAX_APPLY}
</p>
</div>
)}
</div>
)}

<CTAButton label="이벤트 공유해서 추가 응모하기" />
</div>
<CTAButton label="이벤트 공유해서 추가 응모하기" />
</div>

<Link className="flex gap-300 mt-[60px] group" to="/lottery/show-case">
<p className="h-body-1-regular text-n-white group-hover:underline">
다른 사람들의 스마일 로봇 뱃지 보러가기
</p>
<ArrowIcon stroke="#ffffff" />
</Link>
</motion.div>
</ErrorBoundary>
</div>

<Link className="flex gap-300 mt-[60px] group" to="/lottery/show-case">
<p className="h-body-1-regular text-n-white group-hover:underline">
다른 사람들의 스마일 로봇 뱃지 보러가기
</p>
<ArrowIcon stroke="#ffffff" />
</Link>
</motion.div>
);
}
60 changes: 28 additions & 32 deletions client/src/features/CasperCustom/CasperCustomForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DISSOLVE } from "@/constants/animation";
import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext";
import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext";
import useFetch from "@/hooks/useFetch";
import ErrorBoundary from "@/pages/ErrorBoundary";
import { CASPER_ACTION } from "@/types/casperCustom";
import { CasperInformationType, PostCasperResponse } from "@/types/lotteryApi";
import { SCROLL_MOTION } from "../../constants/animation";
Expand All @@ -26,7 +25,6 @@ export function CasperCustomForm({ navigateNextStep }: CasperCustomFormProps) {
const {
data: casper,
isSuccess: isSuccessPostCasper,
isError: isErrorPostCasper,
fetchData: postCasper,
} = useFetch<PostCasperResponse, { token: string; casper: CasperInformationType }>(
({ token, casper }) => LotteryAPI.postCasper(token, casper)
Expand Down Expand Up @@ -86,37 +84,35 @@ export function CasperCustomForm({ navigateNextStep }: CasperCustomFormProps) {
};

return (
<ErrorBoundary isError={isErrorPostCasper}>
<motion.div className="flex flex-col items-center" {...SCROLL_MOTION(DISSOLVE)}>
<div className="flex items-center mt-[68px] gap-1000">
<MyCasperCardFront hasRandomButton={false} />
<div>
<TextField
label="캐스퍼 일렉트릭 봇의 이름을 지어주세요!"
isRequired
size="sm"
placeholder="김캐스퍼"
limit={10}
value={casperName}
handleValueChange={handleSetCasperName}
/>
<div className="mt-[42px]" />
<TextField
label="캐스퍼 일렉트릭과 함께 하고 싶은 일이 있나요?"
isRequired={false}
size="lg"
placeholder="캐스퍼와 함께 혼자 차박하고 싶어요!"
limit={60}
value={expectations}
handleValueChange={handleSetExpectations}
/>
</div>
<motion.div className="flex flex-col items-center" {...SCROLL_MOTION(DISSOLVE)}>
<div className="flex items-center mt-[68px] gap-1000">
<MyCasperCardFront hasRandomButton={false} />
<div>
<TextField
label="캐스퍼 일렉트릭 봇의 이름을 지어주세요!"
isRequired
size="sm"
placeholder="김캐스퍼"
limit={10}
value={casperName}
handleValueChange={handleSetCasperName}
/>
<div className="mt-[42px]" />
<TextField
label="캐스퍼 일렉트릭과 함께 하고 싶은 일이 있나요?"
isRequired={false}
size="lg"
placeholder="캐스퍼와 함께 혼자 차박하고 싶어요!"
limit={60}
value={expectations}
handleValueChange={handleSetExpectations}
/>
</div>
</div>

<div className="mt-1000">
<CTAButton label="완료" disabled={!canSubmit} onClick={handleSubmitCasper} />
</div>
</motion.div>
</ErrorBoundary>
<div className="mt-1000">
<CTAButton label="완료" disabled={!canSubmit} onClick={handleSubmitCasper} />
</div>
</motion.div>
);
}
4 changes: 4 additions & 0 deletions client/src/hooks/useFetch.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { useState } from "react";
import { useErrorBoundary } from "react-error-boundary";

export default function useFetch<T, P = void>(fetch: (params: P) => Promise<T>) {
const [data, setData] = useState<T | null>(null);
const [isSuccess, setIsSuccess] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);

const { showBoundary } = useErrorBoundary();

const fetchData = async (params?: P) => {
try {
const data = await fetch(params as P);
setData(data);
setIsSuccess(!!data);
} catch (error) {
showBoundary(error);
setIsError(true);
console.error(error);
}
Expand Down
30 changes: 0 additions & 30 deletions client/src/pages/ErrorBoundary/index.tsx

This file was deleted.

19 changes: 19 additions & 0 deletions client/src/pages/ErrorElement/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import CTAButton from "@/components/CTAButton";

interface ErrorElementProps {
fallbackUrl?: string;
}

export default function ErrorElement({ fallbackUrl = "/" }: ErrorElementProps) {
return (
<div className="fixed z-10 h-screen w-full bg-n-neutral-950 flex flex-col justify-center items-center">
<img alt="오류 아이콘" src="/assets/icons/casper-error.svg" />
<div className="mt-4" />
<h3 className="h-heading-3-bold text-n-white">
문제가 발생했습니다. 잠시 후 다시 시도해 보세요.
</h3>
<div className="mt-12" />
<CTAButton label="돌아가기" url={fallbackUrl} hasArrowIcon />
</div>
);
}
Loading

0 comments on commit bbb3ad0

Please sign in to comment.