| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- 'use client';
- import { useState, useCallback, useEffect } from 'react';
- import Link from 'next/link';
- import { usePathname } from 'next/navigation';
- import Styles from '../styles/common.module.scss';
- import useAuth from '@/hooks/useAuth';
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
- import { faBars, faXmark, faCoins, faComments, faNewspaper, faHeadset, faUser, faRightToBracket } from '@fortawesome/free-solid-svg-icons';
- import { faCommentDots, faClock } from '@fortawesome/free-regular-svg-icons';
- import ChatSidebar from '@/app/component/chat/ChatSidebar';
- type Props = {
- children: React.ReactNode;
- };
- export default function Layout({ children }: Props) {
- const { isAuthenticated, isLoading, logout } = useAuth();
- const [sidebarOpen, setSidebarOpen] = useState(false);
- const [chatOpen, setChatOpen] = useState(false);
- const pathname = usePathname();
- const toggleSidebar = useCallback(() => {
- setSidebarOpen((prev) => !prev);
- }, []);
- const toggleChat = useCallback(() => {
- setChatOpen((prev) => !prev);
- }, []);
- const closeOverlay = useCallback(() => {
- setSidebarOpen(false);
- setChatOpen(false);
- }, []);
- const [currentTime, setCurrentTime] = useState('');
- useEffect(() => {
- const updateTime = () => {
- const now = new Date();
- setCurrentTime(
- `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
- );
- };
- updateTime();
- const timer = setInterval(updateTime, 1000);
- return () => clearInterval(timer);
- }, []);
- if (isLoading) {
- return <></>;
- }
- return (
- <>
- <div id='container' className={`${Styles.container}${sidebarOpen ? ` ${Styles.sidebarOpen}` : ''}${chatOpen ? ` ${Styles.chatOpen}` : ''}`}>
- {/* 상단 내용 */}
- <header id='header' className={`${Styles.header} flex items-center w-full px-4`}>
- <button type='button' className={Styles.hamburger} onClick={toggleSidebar} aria-label='메뉴'>
- <FontAwesomeIcon icon={sidebarOpen ? faXmark : faBars} />
- </button>
- <Link href='/' className={Styles.logo}>
- <picture>
- <source src="image.webp" type="image/webp" />
- <img src="/resources/logo.svg" alt="bitforum logo" />
- </picture>
- </Link>
- <nav className={Styles.pcNav}>
- <ul className='flex gap-4'>
- <li>
- <Link href='/'>
- 코인
- </Link>
- </li>
- {/*
- <li>
- <Link href='/latest'>
- 토론
- </Link>
- </li>
- */}
- <li>
- <Link href='/news'>
- 뉴스
- </Link>
- </li>
- <li>
- <Link href='/board/notice'>
- 고객지원
- </Link>
- </li>
- </ul>
- {!isAuthenticated ? (
- <ul className='flex gap-4 items-center'>
- <li className={`${Styles.clock} text-sm opacity-70`} style={{ fontVariantNumeric: 'tabular-nums' }}>
- <FontAwesomeIcon icon={faClock} className='mr-1' />{currentTime}
- </li>
- <li>
- <a href='/login'>
- 로그인
- </a>
- </li>
- <li>
- <a href='/register'>
- 회원가입
- </a>
- </li>
- </ul>
- ) : (
- <ul className='flex gap-4 items-center'>
- <li className={`${Styles.clock} text-sm opacity-70`} style={{ fontVariantNumeric: 'tabular-nums' }}>
- <FontAwesomeIcon icon={faClock} className='mr-1' />{currentTime}
- </li>
- <li>
- <Link href='/profile'>
- 내 정보
- </Link>
- </li>
- <li>
- <button type='button' onClick={logout}>
- 로그아웃
- </button>
- </li>
- </ul>
- )}
- </nav>
- <button type='button' className={Styles.chatToggle} onClick={toggleChat} aria-label='채팅'>
- <FontAwesomeIcon icon={faCommentDots} />
- </button>
- </header>
- {/* 모바일 오버레이 */}
- <div className={Styles.overlay} onClick={closeOverlay} />
- {/* 메인 내용 */}
- <main id='main' className={`${Styles.main} relative`}>
- {children}
- </main>
- {/* 우측 채팅 사이드바 */}
- <aside id='chatAside' className={Styles.chatAside}>
- <ChatSidebar />
- </aside>
- {/* 하단 내용 */}
- <footer id='footer' className={`${Styles.footer} px-4`}>
- <ol>
- <li>
- <Link href='/docs/teams'>이용약관</Link>
- </li>
- <li>
- <Link href='/docs/privacy'>개인정보처리방침</Link>
- </li>
- {/* 저작권 표시 */}
- <li>© 2025 PLAYR. All rights reserved.</li>
- </ol>
- </footer>
- {/* 모바일 하단 탭바 */}
- <nav className={Styles.bottomTab}>
- <Link href='/' className={pathname === '/' ? Styles.active : ''}>
- <FontAwesomeIcon icon={faCoins} />
- <span>코인</span>
- </Link>
- <Link href='/latest' className={pathname.startsWith('/latest') || (pathname.startsWith('/board') && !pathname.startsWith('/board/notice')) || pathname.startsWith('/post') ? Styles.active : ''}>
- <FontAwesomeIcon icon={faComments} />
- <span>토론</span>
- </Link>
- <Link href='/news' className={pathname.startsWith('/news') ? Styles.active : ''}>
- <FontAwesomeIcon icon={faNewspaper} />
- <span>뉴스</span>
- </Link>
- <Link href='/board/notice' className={pathname.startsWith('/board/notice') || pathname.startsWith('/support') ? Styles.active : ''}>
- <FontAwesomeIcon icon={faHeadset} />
- <span>고객지원</span>
- </Link>
- {isAuthenticated ? (
- <Link href='/profile' className={pathname.startsWith('/profile') ? Styles.active : ''}>
- <FontAwesomeIcon icon={faUser} />
- <span>내 정보</span>
- </Link>
- ) : (
- <a href='/login'>
- <FontAwesomeIcon icon={faRightToBracket} />
- <span>로그인</span>
- </a>
- )}
- </nav>
- </div>
- </>
- );
- }
|