diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx index a4476eb..694e5d6 100644 --- a/src/components/Modal/Modal.jsx +++ b/src/components/Modal/Modal.jsx @@ -1,8 +1,9 @@ -import { useState } from 'react'; +import { useRef, useState, useEffect, useCallback } from 'react'; import DOMPurify from 'dompurify'; import ReactDOM from 'react-dom'; import Badge from '../Badge/Badge'; import Button from '../common/Button'; +import useModalClose from '../../hooks/useModalClose'; // 경로에 맞게 수정 import styles from './Modal.module.scss'; export default function Modal({ @@ -14,19 +15,27 @@ export default function Modal({ createdAt, onClose, }) { + const modalRef = useRef(null); const [isClosing, setIsClosing] = useState(false); const sanitizedHTML = DOMPurify.sanitize(children); - const handleCloseModal = () => { + // 닫기 로직 (애니메이션 포함) + const handleCloseModal = useCallback(() => { setIsClosing(true); setTimeout(() => { onClose(); }, 300); - }; + }, [onClose]); + + // 외부 클릭 감지하여 닫기 + useModalClose(modalRef, handleCloseModal); return ReactDOM.createPortal(
-
+
프로필 이미지 diff --git a/src/hooks/useModalClose.jsx b/src/hooks/useModalClose.jsx new file mode 100644 index 0000000..c086fac --- /dev/null +++ b/src/hooks/useModalClose.jsx @@ -0,0 +1,15 @@ +import { useEffect } from 'react'; + +export default function useDetectClose(ref, onClose) { + useEffect(() => { + const handleClick = (e) => { + if (ref.current && !ref.current.contains(e.target)) { + onClose(); // 바로 닫기 말고 외부에서 애니메이션 포함한 onClose 실행 + } + }; + document.addEventListener('mousedown', handleClick); + return () => { + document.removeEventListener('mousedown', handleClick); + }; + }, [ref, onClose]); +} diff --git a/src/pages/Recipient/Recipient.jsx b/src/pages/Recipient/Recipient.jsx index cfef512..afac477 100644 --- a/src/pages/Recipient/Recipient.jsx +++ b/src/pages/Recipient/Recipient.jsx @@ -50,21 +50,21 @@ export default function Recipient({ showDelete }) { new Map(combined.map((message) => [message.id, message])).values(), ); - return uniqueMessages; - }); - - if (showDelete) { - setMessages(allMessages); - } else { - if ( - allMessages.length % 6 === 0 && - allMessages.length !== newMessages.count - ) { - setMessages(allMessages.slice(0, allMessages.length - 1)); + if (showDelete) { + setMessages(uniqueMessages); } else { - setMessages(allMessages); + if ( + uniqueMessages.length % 6 === 0 && + uniqueMessages.length !== newMessages.count + ) { + setMessages(uniqueMessages.slice(0, uniqueMessages.length - 1)); + } else { + setMessages(uniqueMessages); + } } - } + + return uniqueMessages; + }); if (!postData) return; setHasNextMessage(offset < postData.messageCount); setLoading(false); @@ -82,6 +82,7 @@ export default function Recipient({ showDelete }) { useEffect(() => { const observer = new IntersectionObserver((entries) => { const firstEntry = entries[0]; + if (firstEntry.isIntersecting && hasNextMessage && !loading) { loadMoreMessages(); } @@ -126,7 +127,7 @@ export default function Recipient({ showDelete }) { } function handleGoBack() { - navigate(-1); + showDelete ? navigate(`/post/${id}/`) : navigate('/list'); } function handleEditClick(id) {