diff --git a/components/Dropdown.tsx b/components/Dropdown.tsx index 615b8d4..440e3fc 100644 --- a/components/Dropdown.tsx +++ b/components/Dropdown.tsx @@ -1,4 +1,5 @@ -import { useEffect, useRef, useState } from 'react'; +import useOutsideClick from 'hooks/useOutsideClick'; +import { useRef, useState } from 'react'; import Menu from './Menu'; @@ -32,24 +33,10 @@ export default function Dropdown({ }; //외부 클릭시 드롭다운 닫기 - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsOpen(false); - } - }; - - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, []); + useOutsideClick(dropdownRef, () => setIsOpen(false)); return ( -
+
+ ); +} diff --git a/components/Headers/GNB.tsx b/components/Headers/GNB.tsx new file mode 100644 index 0000000..6204d36 --- /dev/null +++ b/components/Headers/GNB.tsx @@ -0,0 +1,14 @@ +import Link from 'next/link'; + +export default function GNB() { + return ( +
+ + 위키목록 + + + 자유게시판 + +
+ ); +} diff --git a/components/Headers/Headers.tsx b/components/Headers/Headers.tsx new file mode 100644 index 0000000..ba4e707 --- /dev/null +++ b/components/Headers/Headers.tsx @@ -0,0 +1,41 @@ +import useCheckMobile from 'hooks/useCheckMobile'; +import Link from 'next/link'; +import { useState } from 'react'; + +import Alarm from './Alarm'; +import GNB from './GNB'; +import Login from './Login'; + +export default function Headers() { + // TODO 임시 로그인 상태(추후 업데이트예정) + const [isLoggedIn, setIsLoggedIn] = useState(false); + const isMobile = useCheckMobile(); + const handleLogin = () => { + setIsLoggedIn(true); + }; + + const handleLogout = () => { + setIsLoggedIn(false); + }; + + return ( +
+
+ + 위키드 로고 + + +
+ {/* 로그인 여부에 따라 조건부로 노출 */} +
+ + +
+
+ ); +} diff --git a/components/Headers/Login.tsx b/components/Headers/Login.tsx new file mode 100644 index 0000000..a4c6bc0 --- /dev/null +++ b/components/Headers/Login.tsx @@ -0,0 +1,108 @@ +import useOutsideClick from 'hooks/useOutsideClick'; +import { useRouter } from 'next/router'; +import { useEffect, useRef, useState } from 'react'; + +import Menu from '../Menu'; + +interface LoginProps { + login: () => void; + logout: () => void; + isMobile: boolean; + isLoggedIn: boolean; +} + +/** + * 로그인 컴포넌트 + * @param login 로그인처리를 위한 함수 + * @param logout 로그아웃처리를 위한 함수 + * @param isMobile 화면 크기에 따라 모바일 여부 판별 + * @param isLoggedIn 로그인 여부 판별 + */ + +export default function Login({ + login, + logout, + isMobile, + isLoggedIn, +}: LoginProps) { + const [isOpen, setIsOpen] = useState(false); + const [profileMenu, setProfileMenu] = useState([]); + + //TODO 프로필 이미지 처리(추후 업데이트) + const profileImage = null; + const router = useRouter(); + const loginMenuRef = useRef(null); + + const updateProfileMenu = () => { + if (!isLoggedIn) { + if (isMobile) return ['로그인', '위키목록', '자유게시판']; + } else if (isMobile) { + return ['위키목록', '자유게시판', '알림', '마이페이지', '로그아웃']; + } else { + return ['마이페이지', '로그아웃']; + } + return []; + }; + + useEffect(() => { + setProfileMenu(updateProfileMenu()); + }, [isLoggedIn, isMobile]); + + const handleLoginMenu = (option: string) => { + if (option === '위키목록') { + router.push('/wikilist'); + } else if (option === '자유게시판') { + router.push('/boards'); + } else if (option === '마이페이지') { + router.push('/mypage'); + } + //TODO 로그인 처리 (추후 업데이트) + else if (option === '로그인') { + login(); + } else if (option === '로그아웃') { + logout(); + } + }; + + useOutsideClick(loginMenuRef, () => setIsOpen(false)); + + return isLoggedIn ? ( +
+ +
+ ) : isMobile ? ( +
+ +
+ ) : ( + + ); +} diff --git a/components/Menu.tsx b/components/Menu.tsx index d78e85a..e613681 100644 --- a/components/Menu.tsx +++ b/components/Menu.tsx @@ -14,7 +14,7 @@ interface MenuProps { export default function Menu({ options, onSelect, menuSize }: MenuProps) { return (
    {options.map((option, index) => (
  • { + const checkMobile = () => setIsMobile(window.innerWidth <= 767); + checkMobile(); + window.addEventListener('resize', checkMobile); + + return () => { + window.removeEventListener('resize', checkMobile); + }; + }, []); + + return isMobile; +} diff --git a/hooks/useOutsideClick.tsx b/hooks/useOutsideClick.tsx new file mode 100644 index 0000000..92098df --- /dev/null +++ b/hooks/useOutsideClick.tsx @@ -0,0 +1,20 @@ +import { useEffect } from 'react'; + +const useOutsideClick = ( + ref: React.RefObject, + callback: () => void +) => { + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (ref.current && !ref.current.contains(event.target as Node)) { + callback(); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [ref, callback]); +}; + +export default useOutsideClick; diff --git a/package.json b/package.json index 5c1ccdc..6dfacd1 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "eslint-config-next": "^15.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", - "eslint-plugin-next": "^0.0.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", "eslint-plugin-simple-import-sort": "^12.1.1", diff --git a/pages/test/Headers/index.tsx b/pages/test/Headers/index.tsx new file mode 100644 index 0000000..5e08fee --- /dev/null +++ b/pages/test/Headers/index.tsx @@ -0,0 +1,9 @@ +import Headers from '@/components/Headers/Headers'; + +export default function HeaderTest() { + return ( +
    + +
    + ); +} diff --git a/public/icon/icon-alarm.svg b/public/icon/icon-alarm.svg new file mode 100644 index 0000000..594a762 --- /dev/null +++ b/public/icon/icon-alarm.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/icon/icon-menu.svg b/public/icon/icon-menu.svg new file mode 100644 index 0000000..4e1644e --- /dev/null +++ b/public/icon/icon-menu.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icon/icon-profile.svg b/public/icon/icon-profile.svg new file mode 100644 index 0000000..5936df8 --- /dev/null +++ b/public/icon/icon-profile.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/logo.svg b/public/images/logo.svg new file mode 100644 index 0000000..30d3fcd --- /dev/null +++ b/public/images/logo.svg @@ -0,0 +1,7 @@ + + + + + + +