@@ -6,31 +6,74 @@ import { useRouter } from 'next/navigation';
66import tw from '@/shared/utills/tw' ;
77import { useAuthStore } from '@/domains/shared/store/auth' ;
88import { setPreLoginPath } from '@/domains/shared/auth/utils/setPreLoginPath' ;
9- import { useState } from 'react' ;
9+ import { useEffect , useState } from 'react' ;
1010import LogoutConfirm from '@/domains/login/components/LogoutConfirm' ;
11+ import { getApi } from '@/app/api/config/appConfig' ;
1112
1213
1314function HeaderBtn ( { pathname } : { pathname : string } ) {
1415 const { isLoggedIn } = useAuthStore ( ) ;
1516 const router = useRouter ( ) ;
1617 const [ logoutModalOpen , setLogoutModalOpen ] = useState ( false ) ;
18+ const [ hasNewNotification , setHasNotification ] = useState ( false )
1719
20+ useEffect ( ( ) => {
21+ if ( ! isLoggedIn ) return ;
22+
23+ console . log ( '🔌 SSE 연결 시작...' ) ;
24+ const eventSource = new EventSource ( `${ getApi } /me/subscribe` , { withCredentials : true } ) ;
25+
26+ eventSource . onopen = ( ) => {
27+ console . log ( '✅ SSE 연결 성공!' ) ;
28+ } ;
29+
30+ eventSource . onmessage = ( event ) => {
31+ console . log ( '📢 새 알림 도착:' , event . data ) ;
32+ setHasNotification ( true ) ;
33+ } ;
34+
35+ eventSource . onerror = ( error ) => {
36+ console . error ( '❌ SSE 에러:' , error ) ;
37+ console . log ( '연결 상태:' , eventSource . readyState ) ; // 0: CONNECTING, 1: OPEN, 2: CLOSED
38+ eventSource . close ( ) ;
39+ } ;
40+
41+ return ( ) => {
42+ console . log ( '🔌 SSE 연결 종료' ) ;
43+ eventSource . close ( ) ;
44+ } ;
45+ } , [ isLoggedIn ] ) ;
46+
47+ useEffect ( ( ) => {
48+ const timer = setTimeout ( ( ) => {
49+ console . log ( '🧪 테스트 알림 발생' ) ;
50+ setHasNotification ( true ) ;
51+ } , 5000 ) ;
52+
53+ return ( ) => clearTimeout ( timer ) ;
54+ } , [ ] ) ;
1855
1956 const navButtons = [
2057 {
2158 icon : Bell ,
2259 label : '알림' ,
2360 className : pathname === '/mypage/my-alarm' ? 'text-tertiary' : 'text-current' ,
2461 hiddenMobile : true ,
25- onClick : ( ) => router . push ( '/mypage/my-alarm' ) ,
62+ onClick : ( ) => {
63+ setHasNotification ( false )
64+ router . push ( '/mypage/my-alarm' )
65+ } ,
66+ showBadge :true
2667 } ,
2768 {
2869 icon : User ,
2970 label : '마이 페이지' ,
3071 className : pathname === '/mypage' ? 'text-tertiary' : 'text-current' ,
3172 hiddenMobile : true ,
3273 onClick : ( ) => router . push ( '/mypage' ) ,
74+ showBadge :false
3375 } ,
76+
3477 ] ;
3578
3679 const authButton = isLoggedIn
@@ -52,18 +95,24 @@ function HeaderBtn({ pathname }: { pathname: string }) {
5295 { /* 아이콘 버튼들 */ }
5396 < div className = "flex gap-2" >
5497 { isLoggedIn &&
55- navButtons . map ( ( { icon : Icon , label, onClick, className, hiddenMobile } ) => (
98+ navButtons . map ( ( { icon : Icon , label, onClick, className, hiddenMobile, showBadge } ) => (
5699 < button
57100 key = { label }
58101 aria-label = { label }
59102 onClick = { onClick }
60103 className = { tw (
61104 className ,
62105 hiddenMobile ? 'hidden sm:flex' : '' ,
63- 'items-center justify-center rounded-full w-7 h-7 hover:bg-secondary/10 transition-colors duration-200'
106+ 'relative items-center justify-center rounded-full w-7 h-7 hover:bg-secondary/10 transition-colors duration-200'
64107 ) }
65108 >
66109 < Icon width = { 24 } height = { 24 } className = "text-current" />
110+ { showBadge && hasNewNotification && (
111+ < span
112+ className = " absolute items-center justify-center top-1 right-1 w-2 h-2 bg-red-500
113+ rounded-full"
114+ > </ span >
115+ ) }
67116 </ button >
68117 ) ) }
69118 </ div >
0 commit comments