diff --git a/src/api/register/post-register-wine.ts b/src/api/register/post-register-wine.ts index 89cb1bbd..c0729342 100644 --- a/src/api/register/post-register-wine.ts +++ b/src/api/register/post-register-wine.ts @@ -1,10 +1,6 @@ import instance from "@/lib/axios"; import { WineFormData } from "@/types/wine"; -interface ImageData { - url: File; -} - const postRegisterWine = async (wineFormData: WineFormData) => { try { const response = await instance.post("/wines", wineFormData); diff --git a/src/app/(auth)/login/layout.tsx b/src/app/(auth)/login/layout.tsx index 93a63080..12ac91b8 100644 --- a/src/app/(auth)/login/layout.tsx +++ b/src/app/(auth)/login/layout.tsx @@ -1,5 +1,6 @@ import { ReactNode } from "react"; import { METADATA } from "@/constants/metadata"; +import ErrorBoundary from "@/error/error-boundary"; export function generateMetadata() { const TITLE = "로그인"; @@ -22,5 +23,9 @@ export function generateMetadata() { } export default function LoginLayout({ children }: { children: ReactNode }) { - return <>{children}; + return ( + <> + {children} + + ); } diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 9cad3d57..ce905a70 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -35,7 +35,6 @@ const Page = () => { const { loginError } = useToast(); const [loginType, setLoginType] = useState(null); const [state, formAction, isPending] = useActionState(login, null); - const { checked, setChecked, initialId, opts } = useRememberId(); const email = watch("email"); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 94e10642..a93c92e3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,6 +6,7 @@ import QueryProvider from "@/providers/query-provider"; import getMe from "@/api/user/get-me"; import KaKaoInitializer from "@/lib/kakao-initializer"; import ToastProvider from "@/providers/toast/toast-provider"; +import { ToastContainer } from "react-toastify"; export function generateMetadata() { return METADATA; @@ -31,6 +32,7 @@ export default async function RootLayout({ + ); diff --git a/src/components/modal/page-modal.tsx b/src/components/modal/page-modal.tsx index 47950f5f..70b8c3df 100644 --- a/src/components/modal/page-modal.tsx +++ b/src/components/modal/page-modal.tsx @@ -24,6 +24,13 @@ const PageModal = ({ e.preventDefault(); }; + const handleCancelEsc = (e: KeyboardEvent) => { + if (e.key === "Escape") { + router.back(); + e.preventDefault(); + } + }; + useLayoutEffect(() => { const currentScrollY = window.scrollY; lockingScroll(currentScrollY); @@ -38,11 +45,12 @@ const PageModal = ({ if (modalRef.current) { modalRef.current.addEventListener("cancel", handleCancel); + modalRef.current.addEventListener("keydown", handleCancelEsc); } return () => { - // eslint-disable-next-line react-hooks/exhaustive-deps modalRef.current?.removeEventListener("cancel", handleCancel); + modalRef.current?.removeEventListener("keydown", handleCancelEsc); }; }, [modalRef]); @@ -50,7 +58,7 @@ const PageModal = ({ ; + +class ErrorBoundary extends Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false }; + } + + /** + * 오류가 발생한 후 대체 UI를 렌더링하기 위해 state를 업데이트 합니다. + */ + static getDerivedStateFromError(error: Error) { + return { hasError: true }; + } + + /** + * 오류 정보를 기록하는 데 사용합니다. side effect를 수행할 수 있습니다. + * @param error + * @param errorInfo + */ + componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { + toast.error(error.message, { icon: ALERT_ERROR_ICON }); + } + + /** + * @returns props로 받은 대체 UI 또는 자식 컴포넌트를 렌더링합니다. + */ + render(): React.ReactNode { + return this.props.children; + } +} + +export default ErrorBoundary;