{
onClick={(e) => {
if (e.target === e.currentTarget) {
e.stopPropagation();
- onClose();
- }
- }}
- onKeyDown={(e) => {
- if (e.key === 'Escape') {
- e.preventDefault();
- e.stopPropagation();
- onClose();
+ closeLastModal();
}
}}
className={layoutStyle}>
diff --git a/src/common/components/Modal/ModalProvider.tsx b/src/common/components/Modal/ModalProvider.tsx
index 41fc1c7f..acf63604 100644
--- a/src/common/components/Modal/ModalProvider.tsx
+++ b/src/common/components/Modal/ModalProvider.tsx
@@ -1,14 +1,22 @@
-import { Fragment, useEffect } from 'react';
+import { useEffect } from 'react';
+import { useLocation } from 'react-router-dom';
+import ModalLayout from '@/common/components/Modal/ModalLayout';
import { useModalStore } from '@/common/stores/modal';
const ModalProvider = () => {
const { modalStore, resetStore, closeModal } = useModalStore();
+ const location = useLocation();
// 언마운트시 모달 리셋
useEffect(() => {
return () => resetStore();
}, [resetStore]);
+ // 라우팅 변경시 모달 리셋
+ useEffect(() => {
+ resetStore();
+ }, [location.pathname, resetStore]);
+
// 모달 오버레이시 배경 스크롤 방지
useEffect(() => {
if (modalStore.length > 0) {
@@ -18,14 +26,14 @@ const ModalProvider = () => {
}
}, [modalStore]);
+ if (modalStore.length === 0) return null;
+
return (
- <>
- {modalStore.map(({ id, render }) => (
-
- {render({ isOpen: modalStore.some((modal) => modal.id === id), close: () => closeModal(id) })}
-
- ))}
- >
+
+ {modalStore.map(({ id, render }) =>
+ render({ isOpen: modalStore.some((modal) => modal.id === id), close: () => closeModal(id) })
+ )}
+
);
};
diff --git a/src/common/stores/modal.ts b/src/common/stores/modal.ts
index e7864884..353871cb 100644
--- a/src/common/stores/modal.ts
+++ b/src/common/stores/modal.ts
@@ -9,6 +9,7 @@ interface ModalStore {
openModal: (render: RenderProps) => void;
closeModal: (id: string) => void;
+ closeLastModal: () => void;
resetStore: () => void;
}
@@ -22,5 +23,12 @@ export const useModalStore = create
((set) => ({
closeModal: (id) => set((state) => ({ modalStore: state.modalStore.filter((modal) => modal.id !== id) })),
+ closeLastModal: () => set((state) => ({ modalStore: state.modalStore.slice(0, -1) })),
+
resetStore: () => set(() => ({ modalStore: [] })),
}));
+
+export const useOpenModal = () => useModalStore((state) => state.openModal);
+export const useCloseModal = () => useModalStore((state) => state.closeModal);
+export const useCloseLastModal = () => useModalStore((state) => state.closeLastModal);
+export const useResetModalStore = () => useModalStore((state) => state.resetStore);
diff --git a/src/layout/Layout.tsx b/src/layout/Layout.tsx
index d0d0f4e9..7f3357de 100644
--- a/src/layout/Layout.tsx
+++ b/src/layout/Layout.tsx
@@ -1,6 +1,7 @@
import { Outlet, ScrollRestoration, useLocation } from 'react-router-dom';
import { ROUTES_CONFIG } from '@/routes/routesConfig';
import Header from '@/common/components/Header/Header';
+import ModalProvider from '@/common/components/Modal/ModalProvider';
import { ApiErrorBoundary } from '@/shared/components/ErrorBoundary/ApiErrorBoundary/ApiErrorBoundary';
import GlobalErrorBoundary from '@/shared/components/ErrorBoundary/GlobalErrorBoundary/GlobalErrorBoundary';
@@ -19,6 +20,7 @@ const Layout = () => {
{shouldShowHeader && }
+
diff --git a/src/pages/instructor/classDetail/components/StudentCard/StudentCard.tsx b/src/pages/instructor/classDetail/components/StudentCard/StudentCard.tsx
index 462c35be..c843f48c 100644
--- a/src/pages/instructor/classDetail/components/StudentCard/StudentCard.tsx
+++ b/src/pages/instructor/classDetail/components/StudentCard/StudentCard.tsx
@@ -11,7 +11,7 @@ import Head from '@/common/components/Head/Head';
import Modal from '@/common/components/Modal/Modal';
import Text from '@/common/components/Text/Text';
import { notify } from '@/common/components/Toast/Toast';
-import { useModalStore } from '@/common/stores/modal';
+import { useOpenModal } from '@/common/stores/modal';
import ApplyTag from '@/shared/components/ApplyTag/ApplyTag';
import { teacherKeys } from '@/shared/constants/queryKey';
import { WITHDRAW_USER_NAME } from '@/shared/constants/withdrawUser';
@@ -36,7 +36,7 @@ interface StudentCardPropTypes {
}
const StudentCard = ({ studentData, index, lessonId, selectedTab }: StudentCardPropTypes) => {
- const { openModal } = useModalStore();
+ const openModal = useOpenModal();
const { text: buttonText, variant: buttonVariant } = STATUS_BUTTON_MAP[studentData.reservationStatus];
diff --git a/src/pages/mypage/components/CancelConfirmPage/CancelConfirmPage.tsx b/src/pages/mypage/components/CancelConfirmPage/CancelConfirmPage.tsx
index d6667afd..0d637c70 100644
--- a/src/pages/mypage/components/CancelConfirmPage/CancelConfirmPage.tsx
+++ b/src/pages/mypage/components/CancelConfirmPage/CancelConfirmPage.tsx
@@ -21,7 +21,7 @@ import ApplicantInfo from '@/pages/reservation/components/ApplicantInfo/Applican
import ClassInfo from '@/pages/reservation/components/ClassInfo/ClassInfo';
import BlurBotton from '@/common/components/BlurButton/BlurButton';
import Modal from '@/common/components/Modal/Modal';
-import { useModalStore } from '@/common/stores/modal';
+import { useOpenModal } from '@/common/stores/modal';
import { useGetBankList } from '@/shared/apis/queries';
import BankBottomSheet from '@/shared/components/BankBottomSheet/BankBottomSheet';
import BoxButton from '@/common/components/BoxButton/BoxButton';
@@ -48,7 +48,7 @@ const CancelConfirmPage = () => {
const { data: myPageData } = useGetMyPage();
const { data: bankList } = useGetBankList();
- const { openModal } = useModalStore();
+ const openModal = useOpenModal();
const { mutate: cancelReservation, isPending } = useCancelReservation();
const navigationState = location.state as NavigationState | null;
diff --git a/src/pages/mypage/components/Withdraw/components/NoticeStep/NoticeStep.tsx b/src/pages/mypage/components/Withdraw/components/NoticeStep/NoticeStep.tsx
index 1aca053e..13d7bf65 100644
--- a/src/pages/mypage/components/Withdraw/components/NoticeStep/NoticeStep.tsx
+++ b/src/pages/mypage/components/Withdraw/components/NoticeStep/NoticeStep.tsx
@@ -15,16 +15,16 @@ import {
} from '@/pages/mypage/components/Withdraw/components/NoticeStep/noticeStep.css';
import { NOTICE_CONTENTS } from '@/pages/mypage/components/Withdraw/constants';
import BlurButton from '@/common/components/BlurButton/BlurButton';
-import Modal from '@/common/components/Modal/Modal';
-import { useModalStore } from '@/common/stores/modal';
-import { useWithdrawStore } from '@/common/stores/withdraw';
-import IcCheckcircleGray0524 from '@/shared/assets/svg/IcCheckcircleGray0524';
-import IcCheckcircleMain0324 from '@/shared/assets/svg/IcCheckcircleMain0324';
import BoxButton from '@/common/components/BoxButton/BoxButton';
import Divider from '@/common/components/Divider/Divider';
import Head from '@/common/components/Head/Head';
+import Modal from '@/common/components/Modal/Modal';
import Text from '@/common/components/Text/Text';
import { notify } from '@/common/components/Toast/Toast';
+import { useOpenModal } from '@/common/stores/modal';
+import { useWithdrawStore } from '@/common/stores/withdraw';
+import IcCheckcircleGray0524 from '@/shared/assets/svg/IcCheckcircleGray0524';
+import IcCheckcircleMain0324 from '@/shared/assets/svg/IcCheckcircleMain0324';
import { vars } from '@/shared/styles/theme.css';
import { clearStorage } from '@/shared/utils/handleToken';
@@ -34,7 +34,9 @@ interface NoticeStepPropTypes {
const NoticeStep = ({ onNext }: NoticeStepPropTypes) => {
const [isAgreed, setIsAgreed] = useState(false);
- const { openModal } = useModalStore();
+
+ const openModal = useOpenModal();
+
const titleId = useId();
const handleAgreeToggle = () => setIsAgreed((prev) => !prev);
diff --git a/src/shared/styles/reset.css.ts b/src/shared/styles/reset.css.ts
index c6704685..8a0e3ba4 100644
--- a/src/shared/styles/reset.css.ts
+++ b/src/shared/styles/reset.css.ts
@@ -84,3 +84,7 @@ globalStyle('button', {
globalStyle('input, textarea', {
outline: 'none',
});
+
+globalStyle('dialog', {
+ border: 'none',
+});