Skip to content

Commit

Permalink
Merge pull request #145 from Selody-project/144-front-task-알림탭-위치-변경
Browse files Browse the repository at this point in the history
issue #144 design: move notification button to Header
  • Loading branch information
sikkzz authored Nov 25, 2023
2 parents d534872 + 5104a00 commit 3da8fad
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 133 deletions.
3 changes: 3 additions & 0 deletions src/assets/icon/ic-notification.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 39 additions & 10 deletions src/components/Header/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { NavLink, useLocation } from "react-router-dom";

import NotificationIcon from "@/assets/icon/ic-notification.svg";
import Logo from "@/assets/img/img-selody-logo/1x.png";
import NotificationDropdown from "@/components/Notification/NotificationDropdown/NotificationDropdown";
import { openModal } from "@/features/ui/ui-slice";

import {
Expand All @@ -16,6 +18,8 @@ import {
TabButton,
ContainerHeader,
WrapDiv,
NotificationButton,
NotificationDiv,
} from "./Header.styles";
import GroupCreateModal from "../GroupCreateModal/GroupCreateModal";
import ProfileDropdown from "../ProfileDropdown/ProfileDropdown";
Expand All @@ -26,28 +30,39 @@ const Header = () => {
const dispatch = useDispatch();

const profileRef = useRef();
const dropdownRef = useRef();
const notiRef = useRef();

const isSchedule = path === "/" || path === "/share";
const isFeed = path === "/community" || path === "mypage";

const { openedModal } = useSelector((state) => state.ui);

const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isProfileDropdownOpen, setIsProfileDropdownOpen] = useState(false);
const [isNotiDropdownOpen, setIsNotiDropdownOpen] = useState(false);

const handleDropdown = (e) => {
if (isDropdownOpen && !dropdownRef.current.contains(e.target)) {
setIsDropdownOpen(false);
} else if (profileRef.current.contains(e.target)) {
setIsDropdownOpen(true);
const handleProfileDropdown = (e) => {
const { target } = e;

if (isProfileDropdownOpen && !profileRef.current.contains(target)) {
setIsProfileDropdownOpen(false);
}
};

const handleNotiDropdown = (e) => {
const { target } = e;

if (isNotiDropdownOpen && !notiRef.current.contains(target)) {
setIsNotiDropdownOpen(false);
}
};

useEffect(() => {
window.addEventListener("click", handleDropdown);
window.addEventListener("click", handleProfileDropdown);
window.addEventListener("click", handleNotiDropdown);

return () => {
window.removeEventListener("click", handleDropdown);
window.removeEventListener("click", handleProfileDropdown);
window.removeEventListener("click", handleNotiDropdown);
};
});

Expand Down Expand Up @@ -86,13 +101,27 @@ const Header = () => {
>
그룹 만들기
</GroupCreateButton>
<NotificationDiv>
<NotificationButton
ref={notiRef}
onClick={() => {
setIsNotiDropdownOpen(!isNotiDropdownOpen);
}}
>
<NotificationIcon />
</NotificationButton>
{isNotiDropdownOpen && <NotificationDropdown />}
</NotificationDiv>
<ProfileDiv>
<ProfileImg
ref={profileRef}
src="https://yt3.ggpht.com/ytc/AOPolaSlb8-cH_rN_lZDD1phXr7aHFpoOqMVoepaGuTm=s48-c-k-c0x00ffffff-no-rj"
alt="user-profile"
onClick={() => {
setIsProfileDropdownOpen(!isProfileDropdownOpen);
}}
/>
{isDropdownOpen && <ProfileDropdown ref={dropdownRef} />}
{isProfileDropdownOpen && <ProfileDropdown />}
</ProfileDiv>
</RightDiv>
{openedModal === "CREATE_GROUP" && <GroupCreateModal />}
Expand Down
32 changes: 25 additions & 7 deletions src/components/Header/Header/Header.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const TabButton = styled.button`
font-weight: ${({ isActive }) => (isActive ? "600" : "500")};
border-bottom: ${({ isActive, theme: { colors } }) =>
isActive ? `2px solid ${colors.primary}` : 0};
padding: 10px 8px 8px;
padding: 10px 0;
&:hover {
color: ${({ theme }) => theme.colors.primary};
Expand All @@ -90,26 +90,24 @@ export const GroupCreateButton = styled.button`
border: 1px solid ${({ theme }) => theme.colors.primary};
border-radius: 100px;
padding: 12px 36px;
background-color: white;
background-color: ${({ theme }) => theme.colors.white};
color: ${({ theme }) => theme.colors.primary};
font-size: 13px;
font-family: Inter;
font-weight: 700;
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
box-shadow: 0px 4px 2px 0px rgba(0, 0, 0, 0.25);
&:hover {
box-shadow: 0px 4px 2px 0px rgba(0, 0, 0, 0.25);
background-color: ${({ theme }) => theme.colors.bg_02};
}
&:active {
box-shadow: 0px 4px 2px 0px rgba(0, 0, 0, 0.25);
background-color: #ccc4ff;
background-color: ${({ theme }) => `${theme.colors.bg_03}30`};
}
`;

export const ProfileDiv = styled.div`
position: relative;
margin-left: 28px;
`;

export const ProfileImg = styled.img`
Expand All @@ -119,3 +117,23 @@ export const ProfileImg = styled.img`
border-radius: 50%;
object-fit: contain;
`;

export const NotificationDiv = styled.div`
position: relative;
`;

export const NotificationButton = styled.button`
margin: 0 16px;
cursor: pointer;
border-radius: 50%;
width: 40px;
height: 40px;
text-align: center;
&:hover {
background-color: ${({ theme }) => theme.colors.bg_02};
}
&:active {
background-color: ${({ theme }) => `${theme.colors.btn_01}30`};
}
`;
47 changes: 20 additions & 27 deletions src/components/Header/ProfileDropdown/ProfileDropdown.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
import React, { forwardRef } from "react";
import React from "react";
import { useDispatch } from "react-redux";
import { Link, useNavigate } from "react-router-dom";

import DropdownBubble from "@/assets/icon/ic-profile-dropdown.svg";
import { logout } from "@/features/auth/auth-service";

import {
ContainerDiv,
ItemButton,
MenuUl,
MenuWrapDiv,
} from "./ProfileDropdown.style";
import { ItemButton, MenuUl, MenuWrapDiv } from "./ProfileDropdown.style";

const ProfileDropdown = forwardRef((_, dropdownRef) => {
const ProfileDropdown = () => {
const dispatch = useDispatch();
const navigate = useNavigate();

return (
<ContainerDiv>
<MenuWrapDiv ref={dropdownRef}>
<DropdownBubble />
<MenuUl>
<li>
<Link to="/setting">
<ItemButton>설정</ItemButton>
</Link>
</li>
<hr />
<li>
<ItemButton onClick={() => dispatch(logout(navigate))}>
로그아웃
</ItemButton>
</li>
</MenuUl>
</MenuWrapDiv>
</ContainerDiv>
<MenuWrapDiv>
<DropdownBubble />
<MenuUl>
<li>
<Link to="/setting">
<ItemButton>설정</ItemButton>
</Link>
</li>
<hr />
<li>
<ItemButton onClick={() => dispatch(logout(navigate))}>
로그아웃
</ItemButton>
</li>
</MenuUl>
</MenuWrapDiv>
);
});
};

export default ProfileDropdown;
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import styled from "styled-components";

export const ContainerDiv = styled.div``;

export const MenuWrapDiv = styled.div`
position: absolute;
top: calc(100% + 24px);
Expand Down
70 changes: 16 additions & 54 deletions src/components/Header/SubHeader/SubHeader.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import React, { useEffect, useRef, useState } from "react";
import React from "react";
import { NavLink } from "react-router-dom";

import { NotificationButton, SubHeaderDiv, SubTabUl } from "./SubHeader.style";
import NotificationDropdown from "../../Notification/NotificationDropdown/NotificationDropdown";
import { SubHeaderDiv, SubTabUl } from "./SubHeader.style";

const SubHeader = ({ tab }) => {
const buttonRef = useRef();
const dropdownRef = useRef();

const [isNotiTabOpen, setIsNotiTabOpen] = useState(false);

const listItems =
tab === "schedule"
? [
Expand All @@ -18,56 +12,24 @@ const SubHeader = ({ tab }) => {
]
: [
{ path: "/community", title: "홈" },
{ path: null, title: "알림" },
{ path: "/mypage", title: "마이페이지" },
];

const closeDropdown = (e) => {
if (
!buttonRef.current.contains(e.target) &&
!dropdownRef.current.contains(e.target)
) {
setIsNotiTabOpen(false);
}
};

useEffect(() => {
if (isNotiTabOpen) {
window.addEventListener("click", closeDropdown);
}

return () => {
window.removeEventListener("click", closeDropdown);
};
});

return (
<>
<SubHeaderDiv isNotiTabOpen={isNotiTabOpen}>
<SubTabUl>
{listItems.map(({ path, title }) => (
<li key={title}>
{path === null ? (
<NotificationButton
ref={buttonRef}
onClick={() => setIsNotiTabOpen(true)}
>
{title}
</NotificationButton>
) : (
<NavLink
to={path}
className={({ isActive }) => (isActive ? "isActive" : "")}
>
{title}
</NavLink>
)}
</li>
))}
</SubTabUl>
</SubHeaderDiv>
{isNotiTabOpen && <NotificationDropdown ref={dropdownRef} />}
</>
<SubHeaderDiv>
<SubTabUl>
{listItems.map(({ path, title }) => (
<li key={title}>
<NavLink
to={path}
className={({ isActive }) => (isActive ? "isActive" : "")}
>
{title}
</NavLink>
</li>
))}
</SubTabUl>
</SubHeaderDiv>
);
};

Expand Down
6 changes: 1 addition & 5 deletions src/components/Header/SubHeader/SubHeader.style.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styled from "styled-components";

export const SubHeaderDiv = styled.div`
display: ${({ isNotiTabOpen }) => (isNotiTabOpen ? "block" : "none")};
display: none;
position: absolute;
top: 100%;
z-index: 2;
Expand Down Expand Up @@ -32,7 +32,3 @@ export const SubTabUl = styled.ul`
font-weight: 600;
}
`;

export const NotificationButton = styled.button`
cursor: pointer;
`;
Loading

0 comments on commit 3da8fad

Please sign in to comment.