diff --git a/src/components/LoginModal.tsx b/src/components/LoginModal.tsx index 052b1bb..9f13e34 100644 --- a/src/components/LoginModal.tsx +++ b/src/components/LoginModal.tsx @@ -1,4 +1,5 @@ import { css } from '@emotion/react'; +import { useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { KakaoTalkIcon, XMonoIcon } from '@/assets/icon'; @@ -14,6 +15,28 @@ interface LoginModalProps { */ const LoginModal = (props: LoginModalProps) => { const { onClick } = props; + const loginRef = useRef(null); + + useEffect(() => { + // 스크롤 방지 + document.body.style.overflow = 'hidden'; + + return () => { + document.body.style.overflow = 'auto'; + }; + }, []); + + useEffect(() => { + const handleFocus = (e: MouseEvent) => { + if (loginRef.current && !loginRef.current.contains(e.target as Node)) + onClick(); + }; + document.addEventListener('mouseup', handleFocus); + + return () => { + document.removeEventListener('mouseup', handleFocus); + }; + }, []); const handleLogin = () => { if (window.Kakao && window.Kakao.Auth) { @@ -28,7 +51,7 @@ const LoginModal = (props: LoginModalProps) => { const portalContent = (
-
+

카카오톡 로그인

서비스 이용을 위해 로그인이 필요해요.

); - return createPortal(portalContent, document.body); + return createPortal( + portalContent, + document.getElementById('root') as HTMLElement, + ); }; export default LoginModal; @@ -53,11 +79,10 @@ const backgroundCss = css` align-items: center; position: absolute; top: 0; - left: 0; z-index: 999; - width: 100vw; - height: 100vh; + width: 100dvw; + height: 100dvh; background-color: rgb(82 82 82 / 72%); `; diff --git a/src/components/MenuBar.tsx b/src/components/MenuBar.tsx index 6bff744..1132fb5 100644 --- a/src/components/MenuBar.tsx +++ b/src/components/MenuBar.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/react'; -import { Link, useLocation } from 'react-router-dom'; +import { useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; import { HomeMonoIcon, @@ -9,6 +10,8 @@ import { } from '@/assets/icon'; import { COLORS } from '@/styles/constants'; +import LoginModal from './LoginModal'; + // 각 페이지 url 변경시 이 부분을 수정해주세요. const PATH_MATCH = [ { url: '/', name: '홈', icon: }, @@ -20,24 +23,49 @@ const PATH_MATCH = [ const MenuBar = () => { const { pathname } = useLocation(); const firstPathname = `/${pathname.split('/')[1]}`; + const navigate = useNavigate(); + + const isLoggedIn = sessionStorage.getItem('kakao_id'); + + const [activateModal, setActivateModal] = useState(false); + + const handleNavigation = (url: string) => { + if (url === '/mypage') { + if (isLoggedIn) { + navigate(url); + } else { + setActivateModal(true); + } + } else { + navigate(url); + } + }; + + const closeModal = () => { + setActivateModal(false); + }; const menuList = PATH_MATCH.map(({ url, name, icon }) => { return ( - handleNavigation(url)} className={firstPathname === url ? 'selected' : ''} css={linkCss}> {icon} {name} - + ); }); return ( - + <> + + {activateModal && } + ); }; diff --git a/src/views/Detail/components/Header.tsx b/src/views/Detail/components/Header.tsx index 8673577..d900870 100644 --- a/src/views/Detail/components/Header.tsx +++ b/src/views/Detail/components/Header.tsx @@ -3,24 +3,39 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { ArrowLeftIcon, HeartFilledIcon, HeartGrayIcon } from '@/assets/icon'; +import LoginModal from '@/components/LoginModal'; const Header = () => { const [isFavorite, setIsFavorite] = useState(false); + const [activateModal, setActivateModal] = useState(false); + + const isLoggedIn = sessionStorage.getItem('kakao_id'); const navigate = useNavigate(); const favoriteOnClick = () => { - setIsFavorite(!isFavorite); + if (isLoggedIn) { + setIsFavorite(!isFavorite); + } else { + setActivateModal(true); + } + }; + + const closeModal = () => { + setActivateModal(false); }; return ( -
- - -
+ <> +
+ + +
+ {activateModal && } + ); }; diff --git a/src/views/Detail/components/review/TotalReview.tsx b/src/views/Detail/components/review/TotalReview.tsx index f766878..f3d91e4 100644 --- a/src/views/Detail/components/review/TotalReview.tsx +++ b/src/views/Detail/components/review/TotalReview.tsx @@ -1,7 +1,9 @@ import { css } from '@emotion/react'; -import { Link, useParams } from 'react-router-dom'; +import { useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; import { PencilMonoIcon } from '@/assets/icon'; +import LoginModal from '@/components/LoginModal'; import { COLORS, FONTS } from '@/styles/constants'; interface TotalReviewProps { @@ -11,17 +13,36 @@ interface TotalReviewProps { const TotalReview = (props: TotalReviewProps) => { const { reviewCount } = props; const { contentId } = useParams(); + const navigate = useNavigate(); + const [activateModal, setActivateModal] = useState(false); + + const isLoggedIn = sessionStorage.getItem('kakao_id'); + + const writeReviewFn = () => { + if (isLoggedIn) { + navigate(`/${contentId}/review/write`); + } else { + setActivateModal(true); + } + }; + + const closeModal = () => { + setActivateModal(false); + }; return ( -
-
- 리뷰 - {reviewCount} + <> +
+
+ 리뷰 + {reviewCount} +
+
- - - -
+ {activateModal && } + ); }; diff --git a/src/views/Map/pages/MapPage.tsx b/src/views/Map/pages/MapPage.tsx index 6288503..00bb3ea 100644 --- a/src/views/Map/pages/MapPage.tsx +++ b/src/views/Map/pages/MapPage.tsx @@ -8,6 +8,7 @@ import { MapSearchInactiveIcon, RefreshMonoIcon, } from '@/assets/icon'; +import LoginModal from '@/components/LoginModal'; import MenuBar from '@/components/MenuBar'; import { COLORS, FONTS } from '@/styles/constants'; import { locationBasedList1Res } from '@/types/locationBasedList1'; @@ -45,6 +46,9 @@ const MapPage = () => { const [defaultLoc, setDefaultLoc] = useState(); // 사용자 지정 지역 좌표 const [getLocActive, setGetLocActive] = useState(false); // 위치 허용에 따른 아이콘 변화 + const [activateModal, setActivateModal] = useState(false); + + const isLoggedIn = sessionStorage.getItem('kako_id'); // 바텀시트 내용 const [bottomSheetContent, setBottomSheetContent] = useState( @@ -82,22 +86,26 @@ const MapPage = () => { /** 저장한 여행지 목록 버튼 클릭 */ const onClickFavorite = async () => { - if (map) { - clearMarker(); - - const res = await createFavoritePin( - DUMMY, // 서버에서 받아온 contentId list로 대체 필요 - map, - setBottomSheetContent, - openPinBottomSheet, - ); - - if (res) { - favoriteList.current = res.favoriteList; - setFavMarkers(res.defaultMarker); + if (isLoggedIn) { + if (map) { + clearMarker(); + + const res = await createFavoritePin( + DUMMY, // 서버에서 받아온 contentId list로 대체 필요 + map, + setBottomSheetContent, + openPinBottomSheet, + ); + + if (res) { + favoriteList.current = res.favoriteList; + setFavMarkers(res.defaultMarker); + } + + openFavoriteBottomSheet(); } - - openFavoriteBottomSheet(); + } else { + setActivateModal(true); } }; @@ -186,67 +194,74 @@ const MapPage = () => { } }; + const closeModal = () => { + setActivateModal(false); + }; + return ( -
-
-
- {isFavClicked ? ( - - ) : ( - + <> +
+
+
+ {isFavClicked ? ( + + ) : ( + + )} +
+ {!isPinClicked && ( +
+ + +
+ )} +
+
+ {isPinClicked && ( + { + setIsPinClicked(false); + }} + /> + )} + + {isFavClicked && ( + + )} + + {isFavPinClicked && ( + setIsFavPinClicked(false)} + /> )} + +
- {!isPinClicked && ( -
- - -
- )} -
-
- {isPinClicked && ( - { - setIsPinClicked(false); - }} - /> - )} - - {isFavClicked && ( - - )} - - {isFavPinClicked && ( - setIsFavPinClicked(false)} - /> - )} - -
-
+ {activateModal && } + ); };