diff --git a/frontend/src/features/comments/components/CommentForm.tsx b/frontend/src/features/comments/components/CommentForm.tsx index 56eb9aba..3fda9f16 100644 --- a/frontend/src/features/comments/components/CommentForm.tsx +++ b/frontend/src/features/comments/components/CommentForm.tsx @@ -5,8 +5,8 @@ import shookshook from '@/assets/icon/shookshook.svg'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import LoginModal from '@/features/auth/components/LoginModal'; import Avatar from '@/shared/components/Avatar'; -import useModal from '@/shared/components/Modal/hooks/useModal'; import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; +import { useOverlay } from '@/shared/hooks/useOverlay'; import { usePostCommentMutation } from '../queries'; interface CommentFormProps { @@ -16,7 +16,24 @@ interface CommentFormProps { const CommentForm = ({ songId, partId }: CommentFormProps) => { const [newComment, setNewComment] = useState(''); - const { isOpen, closeModal: closeLoginModal, openModal: openLoginModal } = useModal(); + const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); + const overlay = useOverlay(); + + const openLoginModal = () => { + setIsLoginModalOpen(true); + + overlay.open(({ isOpen, close }) => ( + <LoginModal + isOpen={isOpen} + closeModal={() => { + setIsLoginModalOpen(false); + close(); + }} + message={'로그인하고 댓글을 작성해 보세요!'} + /> + )); + }; + const { user } = useAuthContext(); const isLoggedIn = !!user; @@ -70,12 +87,7 @@ const CommentForm = ({ songId, partId }: CommentFormProps) => { type="text" onFocus={openLoginModal} placeholder="댓글 추가..." - disabled={isOpen} - /> - <LoginModal - isOpen={isOpen} - message={'로그인하고 댓글을 작성해 보세요!'} - closeModal={closeLoginModal} + disabled={isLoginModalOpen} /> </> )} diff --git a/frontend/src/features/comments/components/CommentList.tsx b/frontend/src/features/comments/components/CommentList.tsx index 1595853a..741ac7b8 100644 --- a/frontend/src/features/comments/components/CommentList.tsx +++ b/frontend/src/features/comments/components/CommentList.tsx @@ -1,12 +1,13 @@ import { styled } from 'styled-components'; import cancelIcon from '@/assets/icon/cancel.svg'; import BottomSheet from '@/shared/components/BottomSheet/BottomSheet'; -import useModal from '@/shared/components/Modal/hooks/useModal'; import Spacing from '@/shared/components/Spacing'; import SRHeading from '@/shared/components/SRHeading'; +import { useOverlay } from '@/shared/hooks/useOverlay'; import { useCommentsQuery } from '../queries'; import Comment from './Comment'; import CommentForm from './CommentForm'; +import type { Comment as CommentType } from '../types/comment.type'; interface CommentListProps { songId: number; @@ -14,7 +15,32 @@ interface CommentListProps { } const CommentList = ({ songId, partId }: CommentListProps) => { - const { isOpen, openModal, closeModal } = useModal(false); + const overlay = useOverlay(); + + const openBottomSheet = ({ comments }: { comments: CommentType[] }) => + overlay.open(({ isOpen, close }) => ( + <BottomSheet isOpen={isOpen} closeModal={close}> + <Spacing direction="vertical" size={16} /> + <div style={{ display: 'flex', justifyContent: 'space-between' }}> + <CommentsTitle>댓글 {comments.length}개</CommentsTitle> + <CloseImg src={cancelIcon} onClick={close} /> + </div> + <Spacing direction="vertical" size={20} /> + <Comments> + {comments.map(({ id, content, createdAt, writerNickname }) => ( + <Comment + key={id} + content={content} + createdAt={createdAt} + writerNickname={writerNickname} + /> + ))} + </Comments> + <Spacing direction="vertical" size={8} /> + <CommentForm songId={songId} partId={partId} /> + </BottomSheet> + )); + const { comments } = useCommentsQuery(songId, partId); if (!comments) { @@ -29,7 +55,7 @@ const CommentList = ({ songId, partId }: CommentListProps) => { <SRHeading as="h3">댓글 목록</SRHeading> <CommentTitle>댓글 {comments.length}개</CommentTitle> <Spacing direction="vertical" size={12} /> - <CommentWrapper onClick={openModal}> + <CommentWrapper onClick={() => openBottomSheet({ comments })}> {isEmptyComment ? ( <Comment.DefaultComment /> ) : ( @@ -40,26 +66,6 @@ const CommentList = ({ songId, partId }: CommentListProps) => { /> )} </CommentWrapper> - <BottomSheet isOpen={isOpen} closeModal={closeModal}> - <Spacing direction="vertical" size={16} /> - <div style={{ display: 'flex', justifyContent: 'space-between' }}> - <CommentsTitle>댓글 {comments.length}개</CommentsTitle> - <CloseImg src={cancelIcon} onClick={closeModal} /> - </div> - <Spacing direction="vertical" size={20} /> - <Comments> - {comments.map(({ id, content, createdAt, writerNickname }) => ( - <Comment - key={id} - content={content} - createdAt={createdAt} - writerNickname={writerNickname} - /> - ))} - </Comments> - <Spacing direction="vertical" size={8} /> - <CommentForm songId={songId} partId={partId} /> - </BottomSheet> </> ); }; diff --git a/frontend/src/features/songs/components/KillingPartTrack.tsx b/frontend/src/features/songs/components/KillingPartTrack.tsx index a1b79a5d..de30e1be 100644 --- a/frontend/src/features/songs/components/KillingPartTrack.tsx +++ b/frontend/src/features/songs/components/KillingPartTrack.tsx @@ -9,12 +9,12 @@ import LoginModal from '@/features/auth/components/LoginModal'; import { deleteMemberParts } from '@/features/member/remotes/memberParts'; import useVideoPlayerContext from '@/features/youtube/hooks/useVideoPlayerContext'; import { useConfirmContext } from '@/shared/components/ConfirmModal/hooks/useConfirmContext'; -import useModal from '@/shared/components/Modal/hooks/useModal'; import useTimerContext from '@/shared/components/Timer/hooks/useTimerContext'; import useToastContext from '@/shared/components/Toast/hooks/useToastContext'; import { GA_ACTIONS, GA_CATEGORIES } from '@/shared/constants/GAEventName'; import sendGAEvent from '@/shared/googleAnalytics/sendGAEvent'; import { useMutation } from '@/shared/hooks/useMutation'; +import { useOverlay } from '@/shared/hooks/useOverlay'; import { toPlayingTimeText } from '@/shared/utils/convertTime'; import copyClipboard from '@/shared/utils/copyClipBoard'; import formatOrdinals from '@/shared/utils/formatOrdinals'; @@ -53,11 +53,8 @@ const KillingPartTrack = ({ partId, }); const { countedTime: currentPlayTime } = useTimerContext(); - const { - isOpen: isLoginModalOpen, - closeModal: closeLoginModal, - openModal: openLoginModal, - } = useModal(); + const overlay = useOverlay(); + const { user } = useAuthContext(); const isLoggedIn = user !== null; @@ -65,6 +62,18 @@ const KillingPartTrack = ({ const playingTime = toPlayingTimeText(start, end); const partLength = end - start; + const openLoginModal = () => { + overlay.open(({ isOpen, close }) => ( + <LoginModal + isOpen={isOpen} + message={ + '로그인하여 킬링파트에 "좋아요!"를 눌러주세요!\n"좋아요!"한 노래는 마이페이지에 저장됩니다!' + } + closeModal={close} + /> + )); + }; + const copyKillingPartUrl = async () => { sendGAEvent({ action: GA_ACTIONS.COPY_URL, @@ -218,14 +227,6 @@ const KillingPartTrack = ({ {isNowPlayingTrack && ( <ProgressBar value={currentPlayTime} max={partLength} aria-hidden="true" /> )} - - <LoginModal - isOpen={isLoginModalOpen} - message={ - '로그인하여 킬링파트에 "좋아요!"를 눌러주세요!\n"좋아요!"한 노래는 마이페이지에 저장됩니다!' - } - closeModal={closeLoginModal} - /> </Container> ); }; diff --git a/frontend/src/features/songs/components/KillingPartTrackList.tsx b/frontend/src/features/songs/components/KillingPartTrackList.tsx index 3c35874d..4cb8a4ea 100644 --- a/frontend/src/features/songs/components/KillingPartTrackList.tsx +++ b/frontend/src/features/songs/components/KillingPartTrackList.tsx @@ -3,8 +3,8 @@ import { useNavigate } from 'react-router-dom'; import { styled } from 'styled-components'; import { useAuthContext } from '@/features/auth/components/AuthProvider'; import LoginModal from '@/features/auth/components/LoginModal'; -import useModal from '@/shared/components/Modal/hooks/useModal'; import ROUTE_PATH from '@/shared/constants/path'; +import { useOverlay } from '@/shared/hooks/useOverlay'; import KillingPartTrack from './KillingPartTrack'; import type { KillingPart, SongDetail } from '@/shared/types/song'; @@ -26,15 +26,23 @@ const KillingPartTrackList = ({ setCommentsPartId, }: KillingPartTrackListProps) => { const [myPartDetail, setMyPartDetail] = useState<SongDetail['memberPart'] | null>(memberPart); - const { user } = useAuthContext(); const navigate = useNavigate(); + const overlay = useOverlay(); + + const openLoginModal = () => { + overlay.open(({ isOpen, close }) => ( + <LoginModal + isOpen={isOpen} + closeModal={close} + message={'로그인하여 나의 킬링파트를 등록하세요!\n등록한 노래는 마이페이지에 저장됩니다!'} + /> + )); + }; const isLoggedIn = !!user; const goToPartCollectingPage = () => navigate(`/${ROUTE_PATH.COLLECT}/${songId}`); - const { isOpen, openModal, closeModal } = useModal(); - const hideMyPart = () => setMyPartDetail(null); return ( @@ -63,16 +71,13 @@ const KillingPartTrackList = ({ hideMyPart={hideMyPart} /> ) : ( - <PartRegisterButton type="button" onClick={isLoggedIn ? goToPartCollectingPage : openModal}> + <PartRegisterButton + type="button" + onClick={isLoggedIn ? goToPartCollectingPage : openLoginModal} + > + My Part </PartRegisterButton> )} - - <LoginModal - isOpen={isOpen} - closeModal={closeModal} - message={'로그인하여 나의 킬링파트를 등록하세요!\n등록한 노래는 마이페이지에 저장됩니다!'} - /> </TrackList> ); };