- {error instanceof CustomError && error.message}
+
+ {(error instanceof CustomError || error instanceof UnhandledError) && error.message}
+
diff --git a/frontend/src/components/layout/Header/Header.tsx b/frontend/src/components/layout/Header/Header.tsx
index 1653e10cd..4c9c2de79 100644
--- a/frontend/src/components/layout/Header/Header.tsx
+++ b/frontend/src/components/layout/Header/Header.tsx
@@ -65,7 +65,7 @@ export const TitleHeader = ({ title }: HeaderProps) => (
// 3. 가운데 제목, 우측 상단 차지하는 헤더 : 게임 대기 화면
export const RoomSettingHeader = ({ title }: HeaderProps) => {
- const { show } = useModal();
+ const { showModal } = useModal();
const {
member: { isMaster },
} = useGetUserInfo();
@@ -75,11 +75,11 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => {
const focusRef = useFocus();
const handleClickRoomSetting = () => {
- show(RoomSettingModal, { returnFocusRef });
+ showModal(RoomSettingModal, { returnFocusRef });
};
const handleClickExit = () => {
- show(AlertModal, { message: '정말로 나가시겠습니까?', onConfirm: handleExit });
+ showModal(AlertModal, { message: '정말로 나가시겠습니까?', onConfirm: handleExit });
};
return (
diff --git a/frontend/src/constants/errorStatus.ts b/frontend/src/constants/errorStatus.ts
new file mode 100644
index 000000000..1202f296b
--- /dev/null
+++ b/frontend/src/constants/errorStatus.ts
@@ -0,0 +1,3 @@
+export const SERVER_ERROR_STATUS = 500;
+export const NETWORK_ERROR_STATUS = 5001;
+export const UNHANDLED_ERROR_STATUS = 5002;
diff --git a/frontend/src/hooks/useDefaultMutationErrorHandler.ts b/frontend/src/hooks/useDefaultMutationErrorHandler.ts
index 4883fac4e..6933844f3 100644
--- a/frontend/src/hooks/useDefaultMutationErrorHandler.ts
+++ b/frontend/src/hooks/useDefaultMutationErrorHandler.ts
@@ -4,12 +4,12 @@ import useToast from '@/hooks/useToast';
import { CustomError, NetworkError } from '@/utils/error';
const useDefaultMutationErrorHandler = () => {
- const { show } = useToast();
- const { show: showModal } = useModal();
+ const { showToast } = useToast();
+ const { showModal } = useModal();
return (error: unknown) => {
if (error instanceof NetworkError) {
- show(error.message);
+ showToast(error.message);
return;
}
if (error instanceof CustomError) {
diff --git a/frontend/src/pages/ReadyPage/components/ReadyMembersContainer/ReadyMembersContainer.tsx b/frontend/src/pages/ReadyPage/components/ReadyMembersContainer/ReadyMembersContainer.tsx
index cc9f1db6d..8a5c72024 100644
--- a/frontend/src/pages/ReadyPage/components/ReadyMembersContainer/ReadyMembersContainer.tsx
+++ b/frontend/src/pages/ReadyPage/components/ReadyMembersContainer/ReadyMembersContainer.tsx
@@ -23,13 +23,13 @@ import useModal from '@/hooks/useModal';
const ReadyMembersContainer = () => {
const { members, master } = useGetRoomInfo();
- const { show } = useModal();
+ const { showModal } = useModal();
const queryClient = useQueryClient();
const returnFocusRef = useRef(null);
const memberCountMessage = `총 인원 ${members.length}명`;
const handleClickInvite = () => {
- show(InviteModal, { returnFocusRef });
+ showModal(InviteModal, { returnFocusRef });
};
useEffect(() => {
diff --git a/frontend/src/pages/ReadyPage/components/RoomSetting/RoomSetting.tsx b/frontend/src/pages/ReadyPage/components/RoomSetting/RoomSetting.tsx
index 387e710cb..0bcf1afff 100644
--- a/frontend/src/pages/ReadyPage/components/RoomSetting/RoomSetting.tsx
+++ b/frontend/src/pages/ReadyPage/components/RoomSetting/RoomSetting.tsx
@@ -21,7 +21,7 @@ const RoomSetting = () => {
const {
member: { isMaster },
} = useGetUserInfo();
- const { show } = useModal();
+ const { showModal } = useModal();
const screenReaderRoomSetting = `
방 정보.
@@ -30,7 +30,7 @@ const RoomSetting = () => {
제한시간 ${roomSetting.timeLimit / 1000}초.`;
const handleClickCategory = () => {
- show(RoomSettingModal, { returnFocusRef });
+ showModal(RoomSettingModal, { returnFocusRef });
};
return (
diff --git a/frontend/src/pages/RoundResultPage/components/NextRoundButton/NextRoundButton.tsx b/frontend/src/pages/RoundResultPage/components/NextRoundButton/NextRoundButton.tsx
index 5fd826254..f8af8d14e 100644
--- a/frontend/src/pages/RoundResultPage/components/NextRoundButton/NextRoundButton.tsx
+++ b/frontend/src/pages/RoundResultPage/components/NextRoundButton/NextRoundButton.tsx
@@ -18,15 +18,19 @@ const NextRoundButton = () => {
const {
member: { isMaster },
} = useGetUserInfo();
- const { show } = useModal();
+ const { showModal } = useModal();
const returnFocusRef = useRef(null);
const randomRoundNextMessage = createRandomNextRoundMessage();
const isLastRound = balanceContent?.currentRound === balanceContent?.totalRound;
- const showModal = () => {
- show(AlertModal, { message: randomRoundNextMessage, onConfirm: moveNextRound, returnFocusRef });
+ const handleNextRoundModal = () => {
+ showModal(AlertModal, {
+ message: randomRoundNextMessage,
+ onConfirm: moveNextRound,
+ returnFocusRef,
+ });
};
return (
@@ -35,7 +39,7 @@ const NextRoundButton = () => {
ref={returnFocusRef}
style={{ width: '100%' }}
text={getNextRoundButtonText(isMaster, isLastRound, isPending || isSuccess)}
- onClick={isLastRound ? moveNextRound : showModal}
+ onClick={isLastRound ? moveNextRound : handleNextRoundModal}
disabled={!isMaster || isPending || isSuccess}
/>
diff --git a/frontend/src/providers/ModalProvider/ModalProvider.tsx b/frontend/src/providers/ModalProvider/ModalProvider.tsx
index b7d4b1825..48d147fc6 100644
--- a/frontend/src/providers/ModalProvider/ModalProvider.tsx
+++ b/frontend/src/providers/ModalProvider/ModalProvider.tsx
@@ -18,7 +18,7 @@ interface Modal extends ModalProps {
}
interface ModalDispatchContextProps {
- show: (Component: React.FC | null, props?: ModalProps) => void;
+ showModal: (Component: React.FC | null, props?: ModalProps) => void;
close: () => void;
}
@@ -33,7 +33,7 @@ const ModalProvider = ({ children }: PropsWithChildren) => {
onConfirm: () => {},
});
- const show = (Component: React.FC | null, props?: ModalProps) => {
+ const showModal = (Component: React.FC | null, props?: ModalProps) => {
setModal({
Component,
title: props?.title,
@@ -52,7 +52,7 @@ const ModalProvider = ({ children }: PropsWithChildren) => {
}));
};
- const dispatch = useMemo(() => ({ show, close }), []);
+ const dispatch = useMemo(() => ({ showModal, close }), []);
return (
diff --git a/frontend/src/providers/QueryClientDefaultOptionProvider/QueryClientDefaultOptionProvider.tsx b/frontend/src/providers/QueryClientDefaultOptionProvider/QueryClientDefaultOptionProvider.tsx
index 8e60785f8..d95c2511b 100644
--- a/frontend/src/providers/QueryClientDefaultOptionProvider/QueryClientDefaultOptionProvider.tsx
+++ b/frontend/src/providers/QueryClientDefaultOptionProvider/QueryClientDefaultOptionProvider.tsx
@@ -1,10 +1,12 @@
import { useQueryClient } from '@tanstack/react-query';
import { PropsWithChildren } from 'react';
+import { NETWORK_ERROR_STATUS, SERVER_ERROR_STATUS } from '@/constants/errorStatus';
import useDefaultMutationErrorHandler from '@/hooks/useDefaultMutationErrorHandler';
import { CustomError } from '@/utils/error';
-const isServerError = (status: number) => status >= 500 && status !== 555;
+const isServerError = (status: number) =>
+ status >= SERVER_ERROR_STATUS && status !== NETWORK_ERROR_STATUS;
// QueryClient는 모든 Provider에 공유되면서 공통 에러 핸들링 로직에 Toast와 Modal을 넣기 위해 setDefaultOptions 사용
// 테스트 환경에서 retry 값이 있을 경우 에러 폴백 테스트가 돌지 않아 분기 처리
diff --git a/frontend/src/providers/ToastProvider/ToastProvider.tsx b/frontend/src/providers/ToastProvider/ToastProvider.tsx
index 04e65de59..c9a08965d 100644
--- a/frontend/src/providers/ToastProvider/ToastProvider.tsx
+++ b/frontend/src/providers/ToastProvider/ToastProvider.tsx
@@ -4,7 +4,7 @@ import { createPortal } from 'react-dom';
import { toastLayout } from './ToastProvider.styled';
interface ToastContext {
- show: (message: string) => void;
+ showToast: (message: string) => void;
}
export const ToastContext = createContext(null);
@@ -13,7 +13,7 @@ const ToastProvider = ({ children }: PropsWithChildren) => {
const [toastMessage, setToastMessage] = useState('');
const timerRef = useRef(null);
- const show = useCallback((message: string) => {
+ const showToast = useCallback((message: string) => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
@@ -34,7 +34,7 @@ const ToastProvider = ({ children }: PropsWithChildren) => {
}, []);
return (
-
+
{children}
{toastMessage &&
createPortal(
diff --git a/frontend/src/utils/error.ts b/frontend/src/utils/error.ts
index 87e649721..379882274 100644
--- a/frontend/src/utils/error.ts
+++ b/frontend/src/utils/error.ts
@@ -1,3 +1,4 @@
+import { NETWORK_ERROR_STATUS, UNHANDLED_ERROR_STATUS } from '@/constants/errorStatus';
import { ERROR_MESSAGE } from '@/constants/message';
import { ErrorCode } from '@/types/error';
@@ -20,6 +21,11 @@ export class CustomError extends Error {
}
export class NetworkError extends Error {
- status = 555;
+ status = NETWORK_ERROR_STATUS;
message = '네트워크가 불안정해요. 다시 시도해주세요!';
}
+
+export class UnhandledError extends Error {
+ status = UNHANDLED_ERROR_STATUS;
+ message = '예기치 못한 에러가 발생했어요. 관리자에게 문의 바랍니다.';
+}