diff --git a/src/components/Modal/ColumnDeleteModal.tsx b/src/components/Modal/ColumnDeleteModal.tsx index 5c0287c3..20183361 100644 --- a/src/components/Modal/ColumnDeleteModal.tsx +++ b/src/components/Modal/ColumnDeleteModal.tsx @@ -1,18 +1,10 @@ -import { MouseEventHandler } from 'react'; - import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; import useModal from '@/hooks/useModal'; import { deleteColumn } from '@/services/deleteService'; import { ColumnDeleteModalProps } from '@/types/Modal.interface'; -export default function ColumnDeleteModal({ - handleCloseModal, - modalProps, -}: { - handleCloseModal: MouseEventHandler; - modalProps: ColumnDeleteModalProps; -}) { +export default function ColumnDeleteModal({ modalProps }: { modalProps: ColumnDeleteModalProps }) { const { closeModal } = useModal(); const handleDeleteButton = async () => { try { @@ -31,7 +23,7 @@ export default function ColumnDeleteModal({
- 취소 + 취소 삭제 diff --git a/src/components/Modal/ColumnModifyModal.tsx b/src/components/Modal/ColumnModifyModal.tsx index 839039e5..51c33691 100644 --- a/src/components/Modal/ColumnModifyModal.tsx +++ b/src/components/Modal/ColumnModifyModal.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler, useState } from 'react'; +import { useState } from 'react'; import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; @@ -6,23 +6,17 @@ import useModal from '@/hooks/useModal'; import { putColumn } from '@/services/putService'; import { ColumnModifyModalProps } from '@/types/Modal.interface'; -export default function ColumnModifyModal({ - handleCloseModal, - modalProps, -}: { - handleCloseModal: MouseEventHandler; - modalProps: ColumnModifyModalProps; -}) { +export default function ColumnModifyModal({ modalProps }: { modalProps: ColumnModifyModalProps }) { const id = modalProps?.columnId; const [title, setTitle] = useState(modalProps?.columnTitle || ''); - const { openModal } = useModal(); + const { openModal, closeModal } = useModal(); const handleModifyButton = async () => { try { await putColumn(id, { title }); - openModal({ type: 'columnModifySuccess' }); + openModal({ type: 'textModal', modalProps: { text: '컬럼이 성공적으로 변경되었습니다.' } }); } catch { - openModal({ type: 'columnModifyFailed' }); + openModal({ type: 'textModal', modalProps: { text: '컬럼이 변경되지 않았습니다.' } }); } }; @@ -54,7 +48,7 @@ export default function ColumnModifyModal({
- 취소 + 취소 0)} onClick={handleModifyButton}> 변경 diff --git a/src/components/Modal/DefaultModal.tsx b/src/components/Modal/DefaultModal.tsx index 387bfd9a..990d6181 100644 --- a/src/components/Modal/DefaultModal.tsx +++ b/src/components/Modal/DefaultModal.tsx @@ -1,12 +1,13 @@ -import { MouseEventHandler } from 'react'; - import ModalCancelButton from '@/components/Button/ModalCancelButton'; +import useModal from '@/hooks/useModal'; + +export default function DefaultModal() { + const { closeModal } = useModal(); -export default function DefaultModal({ handleCloseModal }: { handleCloseModal: MouseEventHandler }) { return (

DEFAULT MODAL

- 취소 + 취소
); } diff --git a/src/components/Modal/DeleteDashboardModal.tsx b/src/components/Modal/DeleteDashboardModal.tsx index 6204b7aa..9b649afe 100644 --- a/src/components/Modal/DeleteDashboardModal.tsx +++ b/src/components/Modal/DeleteDashboardModal.tsx @@ -1,18 +1,10 @@ -import { MouseEventHandler } from 'react'; - import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; import useModal from '@/hooks/useModal'; import { deleteDashboard } from '@/services/deleteService'; import { DeleteDashboardModalProps } from '@/types/Modal.interface'; -export default function DeleteDashboardModal({ - handleCloseModal, - modalProps, -}: { - handleCloseModal: MouseEventHandler; - modalProps: DeleteDashboardModalProps; -}) { +export default function DeleteDashboardModal({ modalProps }: { modalProps: DeleteDashboardModalProps }) { const { closeModal } = useModal(); const handleDeleteButton = async () => { try { @@ -31,7 +23,7 @@ export default function DeleteDashboardModal({
- 취소 + 취소 삭제 diff --git a/src/components/Modal/InviteMemberModal.tsx b/src/components/Modal/InviteMemberModal.tsx index 381b24ca..48cbf8e6 100644 --- a/src/components/Modal/InviteMemberModal.tsx +++ b/src/components/Modal/InviteMemberModal.tsx @@ -1,5 +1,5 @@ import { AxiosError } from 'axios'; -import { MouseEventHandler, useState, ChangeEvent } from 'react'; +import { useState, ChangeEvent } from 'react'; import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; @@ -7,14 +7,8 @@ import useModal from '@/hooks/useModal'; import { postMemberInvite } from '@/services/postService'; import { InviteMemberModalProps } from '@/types/Modal.interface'; -export default function InviteMemberModal({ - handleCloseModal, - modalProps, -}: { - handleCloseModal: MouseEventHandler; - modalProps: InviteMemberModalProps; -}) { - const { openModal } = useModal(); +export default function InviteMemberModal({ modalProps }: { modalProps: InviteMemberModalProps }) { + const { openModal, closeModal } = useModal(); const [email, setEmail] = useState(''); const [isValid, setIsValid] = useState(true); const [errorMessage, setErrorMessage] = useState(''); @@ -35,7 +29,7 @@ export default function InviteMemberModal({ const handleMemberInviteButton = async () => { try { await postMemberInvite(modalProps.dashboardId, { email }); - openModal({ type: 'inviteMemberSuccess' }); + openModal({ type: 'textModal', modalProps: { text: '해당 멤버를 초대하였습니다!' } }); } catch (error) { if (error instanceof AxiosError) { setErrorMessage(error.response?.data.message || '초대 중 에러가 발생했습니다.'); @@ -60,7 +54,7 @@ export default function InviteMemberModal({ {errorMessage &&

{errorMessage}

}
- 취소 + 취소 초대 diff --git a/src/components/Modal/NewColumnModal.tsx b/src/components/Modal/NewColumnModal.tsx index 869912fb..0dd32dc5 100644 --- a/src/components/Modal/NewColumnModal.tsx +++ b/src/components/Modal/NewColumnModal.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler, useState } from 'react'; +import { useState } from 'react'; import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; @@ -6,12 +6,11 @@ import useModal from '@/hooks/useModal'; import { postNewColumn } from '@/services/postService'; interface NewColumnModalProps { - handleCloseModal: MouseEventHandler; modalProps: { dashboardId: number }; } -export default function NewColumnModal({ handleCloseModal, modalProps }: NewColumnModalProps) { - const { openModal } = useModal(); +export default function NewColumnModal({ modalProps }: NewColumnModalProps) { + const { openModal, closeModal } = useModal(); const [column, setColumn] = useState(''); @@ -19,9 +18,9 @@ export default function NewColumnModal({ handleCloseModal, modalProps }: NewColu const handlePostNewColumn = async () => { try { await postNewColumn({ title: column, dashboardId: dashboardId }); - openModal({ type: 'newColumnSuccess' }); + openModal({ type: 'textModal', modalProps: { text: '새로운 컬럼이 생성되었습니다!' } }); } catch (error) { - openModal({ type: 'newColumnFailed' }); + openModal({ type: 'textModal', modalProps: { text: '컬럼 생성을 실패하였습니다.' } }); } }; @@ -40,7 +39,7 @@ export default function NewColumnModal({ handleCloseModal, modalProps }: NewColu />
- 취소 + 취소 생성 diff --git a/src/components/Modal/NewDashboardModal.tsx b/src/components/Modal/NewDashboardModal.tsx index 0917c31f..3524a282 100644 --- a/src/components/Modal/NewDashboardModal.tsx +++ b/src/components/Modal/NewDashboardModal.tsx @@ -1,5 +1,5 @@ import Image from 'next/image'; -import { MouseEventHandler, useState } from 'react'; +import { useState } from 'react'; import ModalActionButton from '@/components/Button/ModalActionButton'; import ModalCancelButton from '@/components/Button/ModalCancelButton'; @@ -14,11 +14,7 @@ interface DashboardState { color: string; } -export default function NewDashboardModal({ - handleCloseModal, -}: { - handleCloseModal: MouseEventHandler; -}) { +export default function NewDashboardModal() { const [value, setValue] = useState({ title: '', color: DASHBOARD_COLOR_OBJ['green'], @@ -26,7 +22,7 @@ export default function NewDashboardModal({ const [selectedColor, setSelectedColor] = useState('green'); - const { openModal } = useModal(); + const { openModal, closeModal } = useModal(); const handleColorSelect = (color: DashboardColor) => { setSelectedColor(color); @@ -39,9 +35,9 @@ export default function NewDashboardModal({ const handlePostDashboard = async () => { try { await postNewDashboard(value); - openModal({ type: 'newDashboardSuccess' }); + openModal({ type: 'textModal', modalProps: { text: '새로운 대시보드가 생성되었습니다!' } }); } catch { - openModal({ type: 'newDashboardFailed' }); + openModal({ type: 'textModal', modalProps: { text: '대시보드 생성을 실패하였습니다.' } }); } }; @@ -76,7 +72,7 @@ export default function NewDashboardModal({ ))}
- 취소 + 취소 생성 diff --git a/src/components/Modal/NotificationModal.tsx b/src/components/Modal/NotificationModal.tsx deleted file mode 100644 index e5be9bb3..00000000 --- a/src/components/Modal/NotificationModal.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { MouseEventHandler } from 'react'; - -import ModalActionButton from '@/components/Button/ModalActionButton'; - -export default function NotificationModal({ - handleCloseModal, - notificationText, -}: { - handleCloseModal: MouseEventHandler; - notificationText: string; -}) { - return ( -
-
-

{notificationText}

- - 확인 - -
-
- ); -} diff --git a/src/components/Modal/TextModal.tsx b/src/components/Modal/TextModal.tsx index d14c923e..2e486148 100644 --- a/src/components/Modal/TextModal.tsx +++ b/src/components/Modal/TextModal.tsx @@ -1,22 +1,17 @@ -import { MouseEventHandler } from 'react'; - import ModalActionButton from '@/components/Button/ModalActionButton'; +import useModal from '@/hooks/useModal'; import { TextModalProps } from '@/types/Modal.interface'; -export default function TextModal({ - handleCloseModal, - modalProps, -}: { - handleCloseModal: MouseEventHandler; - modalProps: TextModalProps; -}) { +export default function TextModal({ modalProps }: { modalProps: TextModalProps }) { + const { closeModal } = useModal(); + return (

{modalProps.text}

확인 diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index ee689777..c55ae2ba 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import { useSelector } from 'react-redux'; import ColumnDeleteModal from './ColumnDeleteModal'; import ColumnModifyModal from './ColumnModifyModal'; @@ -9,12 +9,11 @@ import EmailExistModal from './EmailExistModal'; import InviteMemberModal from './InviteMemberModal'; import NewColumnModal from './NewColumnModal'; import NewDashboardModal from './NewDashboardModal'; -import NotificationModal from './NotificationModal'; -import SignUpSuccessModal from './signupSuccessModal'; +import SignUpSuccessModal from './SignupSuccessModal'; import TextModal from './TextModal'; -import { NOTIFICATION_TEXT_OBJ } from '@/constants'; -import { modalSelector, closeModal } from '@/store/reducers/modalSlice'; +import useModal from '@/hooks/useModal'; +import { modalSelector } from '@/store/reducers/modalSlice'; import { ColumnDeleteModalProps, ColumnModifyModalProps, @@ -26,86 +25,66 @@ import { } from '@/types/Modal.interface'; export default function Modal() { - const dispatch = useDispatch(); + const { closeModal } = useModal(); const { type, modalProps } = useSelector(modalSelector); + // 모달이 열릴 때, overflow-hidden으로 스크롤 동작 방지 useEffect(() => { if (type) { - // 모달이 열렸을 때 body의 overflow를 hidden으로 설정 document.body.style.overflow = 'hidden'; } else { - // 모달이 닫힐 때 body의 overflow를 auto로 설정 document.body.style.overflow = 'auto'; } - - // cleanup 함수로 모달이 닫힐 때 overflow를 auto로 설정 return () => { document.body.style.overflow = 'auto'; }; }, [type]); - const handleCloseModal = () => { - dispatch(closeModal()); - }; - + // 바깥을 눌렀을 때 모달이 닫힘 const handleOutsideClick = (e: React.MouseEvent) => { if (e.target === e.currentTarget) { - handleCloseModal(); + closeModal(); } }; + + // 전달받은 type에 따라 모달의 내부 컨텐트를 다르게 렌더 const renderModalContent = () => { switch (type) { - case 'pwdNotEqual': - case 'curPwdNotEqual': - case 'newDashboardSuccess': - case 'newDashboardFailed': - case 'newColumnSuccess': - case 'newColumnFailed': - case 'inviteMemberSuccess': - case 'inviteMemberFailed': - case 'columnModifySuccess': - case 'columnModifyFailed': - return ; - case 'textModal': - return modalProps ? ( - - ) : null; case 'newDashboard': - return ; + return ; + + case 'signupSuccess': + return ; + + case 'textModal': + return modalProps ? : null; + case 'deleteDashboard': - return ( - - ); + return modalProps ? : null; + case 'columnDeleteConfirm': - return modalProps ? ( - - ) : null; + return modalProps ? : null; + case 'newColumn': - return modalProps ? ( - - ) : null; + return modalProps ? : null; + case 'inviteMember': - return modalProps ? ( - - ) : null; + return modalProps ? : null; + case 'columnModify': - return modalProps ? ( - - ) : null; + return modalProps ? : null; + case 'emailExists': return modalProps ? : null; - case 'signupSuccess': - return ; + default: - return ; + return ; } }; return ( <> + {/* 타입이 존재할 때만 모달이 열림 */} {type && (
state.user); + const { openModal } = useModal(); const onSubmit = (data: TSignInInputs) => { mutation.mutate(data, { onSuccess: () => { router.push('/mydashboard'); // 로그인 성공 시 리다이렉트 }, + onError: (error) => { + if (error instanceof AxiosError) { + dispatch(setError(error.response?.data.message)); + openModal({ type: 'textModal', modalProps: { text: error.response?.data.message } }); + } else { + const unknownError = '알 수 없는 오류가 발생했습니다.'; + dispatch(setError(unknownError)); + openModal({ type: 'textModal', modalProps: { text: unknownError } }); + } + }, }); }; @@ -62,15 +74,6 @@ export default function SignInForm() { - {mutation.isError && ( -

Error: {mutation.error instanceof Error ? mutation.error.message : '알 수 없는 오류가 발생했습니다.'}

- )} - {user && ( -

- 로그인 성공: {user.nickname} ({user.id}) -

- )} - {error &&

오류: {error}

} ); } diff --git a/src/hooks/useSignIn.ts b/src/hooks/useSignIn.ts index 2fa44638..66f9cfe1 100644 --- a/src/hooks/useSignIn.ts +++ b/src/hooks/useSignIn.ts @@ -1,4 +1,5 @@ import { useMutation } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; import { useDispatch } from 'react-redux'; import { postSignIn } from '@/services/postService'; @@ -11,8 +12,8 @@ export const useSignIn = () => { return useMutation({ mutationFn: postSignIn, onError: (error: unknown) => { - if (error instanceof Error) { - dispatch(setError(error.message)); + if (error instanceof AxiosError) { + dispatch(setError(error.response?.data.message)); } else { dispatch(setError('알 수 없는 오류가 발생했습니다.')); } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 8a9f8ec2..f262dbdf 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -37,7 +37,7 @@ const Home: React.FC = () => {