Skip to content

Commit

Permalink
Feat: 로그인 모달창 추가 (#66)
Browse files Browse the repository at this point in the history
* feat:네비게이션 모달창 추가

* feat: 지도에 로그인 모달창 추가

* feat: 리뷰 페이지에 로그인 모달창 추가

* feat: 즐찾 버튼 로그인 모달 추가

* feat: 로그인 모달 ux 개선

* fix: 모달창 렌더링 위치 수정
  • Loading branch information
aazkgh authored Oct 1, 2024
1 parent 54587af commit f58c4bc
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 102 deletions.
35 changes: 30 additions & 5 deletions src/components/LoginModal.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -14,6 +15,28 @@ interface LoginModalProps {
*/
const LoginModal = (props: LoginModalProps) => {
const { onClick } = props;
const loginRef = useRef<HTMLDivElement>(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) {
Expand All @@ -28,7 +51,7 @@ const LoginModal = (props: LoginModalProps) => {

const portalContent = (
<div css={backgroundCss}>
<div css={container}>
<div css={container} ref={loginRef}>
<p css={titleCss}>카카오톡 로그인</p>
<p css={descriptionCss}>서비스 이용을 위해 로그인이 필요해요.</p>
<button type="button" css={linkCss} onClick={handleLogin}>
Expand All @@ -42,7 +65,10 @@ const LoginModal = (props: LoginModalProps) => {
</div>
);

return createPortal(portalContent, document.body);
return createPortal(
portalContent,
document.getElementById('root') as HTMLElement,
);
};

export default LoginModal;
Expand All @@ -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%);
`;
Expand Down
42 changes: 35 additions & 7 deletions src/components/MenuBar.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -9,6 +10,8 @@ import {
} from '@/assets/icon';
import { COLORS } from '@/styles/constants';

import LoginModal from './LoginModal';

// 각 페이지 url 변경시 이 부분을 수정해주세요.
const PATH_MATCH = [
{ url: '/', name: '홈', icon: <HomeMonoIcon /> },
Expand All @@ -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 (
<Link
<button
type="button"
key={url}
to={url}
onClick={() => handleNavigation(url)}
className={firstPathname === url ? 'selected' : ''}
css={linkCss}>
{icon}
<span css={spanCss}>{name}</span>
</Link>
</button>
);
});

return (
<nav css={navCss}>
<div css={container}>{menuList}</div>
</nav>
<>
<nav css={navCss}>
<div css={container}>{menuList}</div>
</nav>
{activateModal && <LoginModal onClick={closeModal} />}
</>
);
};

Expand Down
33 changes: 24 additions & 9 deletions src/views/Detail/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<boolean>(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 (
<header css={headerContainer}>
<button type="button" onClick={() => navigate('/')}>
<ArrowLeftIcon />
</button>
<button type="button" onClick={favoriteOnClick}>
{isFavorite ? <HeartFilledIcon /> : <HeartGrayIcon />}
</button>
</header>
<>
<header css={headerContainer}>
<button type="button" onClick={() => navigate('/')}>
<ArrowLeftIcon />
</button>
<button type="button" onClick={favoriteOnClick}>
{isFavorite ? <HeartFilledIcon /> : <HeartGrayIcon />}
</button>
</header>
{activateModal && <LoginModal onClick={closeModal} />}
</>
);
};

Expand Down
39 changes: 30 additions & 9 deletions src/views/Detail/components/review/TotalReview.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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 (
<div css={containerCss}>
<div css={reviewCountCss}>
<span>리뷰</span>
<span>{reviewCount}</span>
<>
<div css={containerCss}>
<div css={reviewCountCss}>
<span>리뷰</span>
<span>{reviewCount}</span>
</div>
<button type="button" onClick={writeReviewFn}>
<PencilMonoIcon />
</button>
</div>
<Link to={`/${contentId}/review/write`}>
<PencilMonoIcon />
</Link>
</div>
{activateModal && <LoginModal onClick={closeModal} />}
</>
);
};

Expand Down
Loading

0 comments on commit f58c4bc

Please sign in to comment.