diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 5c6374c..57942c7 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,5 @@ import '@/shared/styles/global.css'; import type { Metadata } from 'next'; -import '@/shared/styles/global.css'; import { Toaster } from 'react-hot-toast'; import ScrollTopBtnWrapper from '@/shared/components/scroll-top/ScrollTopBtnWrapper'; import KaKaoScript from './api/kakao/KaKaoScript'; diff --git a/src/domains/main/api/useSSENotification.ts b/src/domains/main/api/useSSENotification.ts new file mode 100644 index 0000000..6cd2adf --- /dev/null +++ b/src/domains/main/api/useSSENotification.ts @@ -0,0 +1,64 @@ +import { useEffect, useRef, useState } from 'react'; +import { getApi } from '@/app/api/config/appConfig'; + +export function useSSENotification(isLoggedIn: boolean) { + const [hasNewNotification, setHasNewNotification] = useState(false); + const eventSourceRef = useRef(null); + const isConnectingRef = useRef(false); + + useEffect(() => { + // 로그인 안 했으면 연결 안 함 + if (!isLoggedIn) { + if (eventSourceRef.current) { + eventSourceRef.current.close(); + eventSourceRef.current = null; + isConnectingRef.current = false; + } + return; + } + + // 이미 연결 중이거나 연결되어 있으면 중복 방지 + if (isConnectingRef.current || eventSourceRef.current) { + return; + } + + isConnectingRef.current = true; + + const eventSource = new EventSource(`${getApi}/me/subscribe`, { + withCredentials: true, + }); + + eventSourceRef.current = eventSource; + + eventSource.onopen = () => { + isConnectingRef.current = false; + }; + + eventSource.onmessage = () => { + setHasNewNotification(true); + }; + + eventSource.onerror = () => { + isConnectingRef.current = false; + + if (eventSource.readyState === EventSource.CLOSED) { + eventSourceRef.current = null; + } + }; + + // cleanup 함수 + return () => { + if (eventSourceRef.current) { + eventSourceRef.current.close(); + eventSourceRef.current = null; + } + isConnectingRef.current = false; + }; + }, [isLoggedIn]); // isLoggedIn만 의존성으로 + + const clearNotification = () => { + setHasNewNotification(false); + }; + + return { hasNewNotification, clearNotification }; +} diff --git a/src/domains/main/components/mainSlide/components/mobile/MobileAbv.tsx b/src/domains/main/components/mainSlide/components/mobile/MobileAbv.tsx index f532493..f9a4ba0 100644 --- a/src/domains/main/components/mainSlide/components/mobile/MobileAbv.tsx +++ b/src/domains/main/components/mainSlide/components/mobile/MobileAbv.tsx @@ -53,7 +53,10 @@ function MobileAbv() {

내 알콜도수 UP

{ - console.log(myLike); - }, [myLike]); - - return ( -
- {myLike.length > 0 ? ( - - ) : ( -
아직 좋아요를 누른 글이 없습니다
- )} -
- ); + return ; } export default MyLike; diff --git a/src/shared/components/header/HeaderBtn.tsx b/src/shared/components/header/HeaderBtn.tsx index e86cb7e..d0eb284 100644 --- a/src/shared/components/header/HeaderBtn.tsx +++ b/src/shared/components/header/HeaderBtn.tsx @@ -8,19 +8,26 @@ import { useAuthStore } from '@/domains/shared/store/auth'; import { setPreLoginPath } from '@/domains/shared/auth/utils/setPreLoginPath'; import { useState } from 'react'; import LogoutConfirm from '@/domains/login/components/LogoutConfirm'; +import { useSSENotification } from '@/domains/main/api/useSSENotification'; function HeaderBtn({ pathname }: { pathname: string }) { const { isLoggedIn } = useAuthStore(); const router = useRouter(); const [logoutModalOpen, setLogoutModalOpen] = useState(false); + const { hasNewNotification, clearNotification } = useSSENotification(isLoggedIn); + const navButtons = [ { icon: Bell, label: '알림', className: pathname === '/mypage/my-alarm' ? 'text-tertiary' : 'text-current', hiddenMobile: true, - onClick: () => router.push('/mypage/my-alarm'), + onClick: () => { + clearNotification(); + router.push('/mypage/my-alarm'); + }, + showBadge: true, }, { icon: User, @@ -28,6 +35,7 @@ function HeaderBtn({ pathname }: { pathname: string }) { className: pathname === '/mypage' ? 'text-tertiary' : 'text-current', hiddenMobile: true, onClick: () => router.push('/mypage'), + showBadge: false, }, ]; @@ -50,7 +58,7 @@ function HeaderBtn({ pathname }: { pathname: string }) { {/* 아이콘 버튼들 */}
{isLoggedIn && - navButtons.map(({ icon: Icon, label, onClick, className, hiddenMobile }) => ( + navButtons.map(({ icon: Icon, label, onClick, className, hiddenMobile, showBadge }) => ( ))}