diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index e9d3b13..bf7b986 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -10,7 +10,7 @@ import './profile.css'; import '../modals/NotificationModal.css'; import axios from "axios"; import NotiService from '../services/NotiService'; -import webSocketService from '../services/WebSocketService'; +import webSocketNotificationService from '../services/WebSocketNotificationService'; const Home = () => { // 알림 모달 @@ -21,6 +21,19 @@ const Home = () => { const [userInfo, setUserInfo] = useState({}); const [userLoading, setUserLoading] = useState(true); const [userError, setUserError] = useState(null); + + const [loading, setLoading] = useState(true); + const [user, setUser] = useState(null); + const [error, setError] = useState(null); + const [totalCommitData, setTotalCommitData] = useState(null); + const [seasonData, setSeasonData] = useState({ + spring: null, + summer: null, + fall: null, + winter: null + }); + const [connected, setConnected] = useState(false); // 웹소켓 연결 상태 + const navigate = useNavigate(); // 사용자 정보 불러오기 @@ -40,50 +53,29 @@ const Home = () => { fetchUserInfo(); }, []); - const toggleModal = () => { + const toggleModal = async () => { setIsModalOpen(!isModalOpen); - if (isModalOpen) { - setHasNewNotification(false); // 모달을 열면 새로운 알림 표시 제거 - } - }; - - // 알림 불러오기 - useEffect(() => { - const fetchNotifications = async () => { - try { - const response = await fetch('/api/notifications', { credentials: 'include' }); - if (!response.ok) { - throw new Error('알림 데이터를 가져오는데 실패했습니다'); - } - - const data = await response.json(); - console.log(data.data); - setNotifications(data.data); - - // 새로운 알림이 있는지 확인 - if (data.length > 0) { - setHasNewNotification(true); + if (!isModalOpen) { // 모달이 열릴 때 (false -> true) + try { + // 읽지 않은 알림만 필터링 + const unreadNotifications = notifications.filter(noti => !noti.read); + if (unreadNotifications.length > 0) { + const unreadIds = unreadNotifications.map(noti => noti.id); + await NotiService.markAsRead(unreadIds); + + // 상태 업데이트: 알림을 읽음으로 표시 + setNotifications(prev => prev.map(noti => + unreadIds.includes(noti.id) + ? { ...noti, read: true } + : noti + )); + setHasNewNotification(false); // 모든 알림을 읽음으로 표시했으므로 빨간 점 제거 + } + } catch (error) { + console.error('Failed to mark notifications as read:', error); } - } catch (error) { - console.error('알림 데이터 가져오기 오류:', error); - } - }; - - fetchNotifications(); - }, []); - - const [loading, setLoading] = useState(true); - const [user, setUser] = useState(null); - const [error, setError] = useState(null); - const [totalCommitData, setTotalCommitData] = useState(null); - const [seasonData, setSeasonData] = useState({ - spring: null, - summer: null, - fall: null, - winter: null - }); - const [connected, setConnected] = useState(false); // 웹소켓 연결 상태 - const navigate = useNavigate(); + } +}; // 메시지 목록을 로드하는 함수 const loadNotis = async () => { @@ -92,6 +84,11 @@ const Home = () => { const response = await NotiService.getNotis(); console.log('Noti response:', response); setNotifications(response.data); + + // 읽지 않은 알림이 있는지 확인 + const hasUnread = response.data.some(noti => !noti.read); + setHasNewNotification(hasUnread); + setLoading(false); } catch (err) { console.error('Error loading Noti:', err); @@ -101,26 +98,51 @@ const Home = () => { }; useEffect(() => { - loadNotis(); - - // 웹소켓 연결 - webSocketService.connect(); - - // 연결 상태 변경 이벤트 리스너 등록 - const unsubscribeFromConnection = webSocketService.onConnectionChange(setConnected); - - // 채팅방 구독 시도 - setTimeout(() => { - const success = webSocketService.subscribeToNotificationChannel(); - console.log('Notis subscription success:', success); - }, 1000); // 약간의 지연을 두어 연결이 설정될 시간을 줌 - - // 컴포넌트 언마운트 시 이벤트 리스너 제거 및 구독 해제 - return () => { - if (unsubscribeFromConnection) { - unsubscribeFromConnection(); + const setupWebSocket = async () => { + try { + await webSocketNotificationService.connect(); + + // 연결 상태 변경 이벤트 리스너 등록 + const unsubscribeFromConnection = webSocketNotificationService.onConnectionChange((isConnected) => { + console.log('WebSocket connection status:', isConnected); + setConnected(isConnected); + + // 연결되면 바로 구독 시도 + if (isConnected) { + const success = webSocketNotificationService.subscribeToNotificationChannel(); + console.log('Notification subscription success:', success); + } + }); + + // 새로운 알림 메시지 핸들러 등록 + const unsubscribeFromMessages = webSocketNotificationService.onMessage((newNotification) => { + console.log('New notification received:', newNotification); + + // 새로운 알림을 상태에 추가 + setNotifications(prev => [{ + ...newNotification, + read: false + }, ...prev]); + + // 새 알림 표시 + setHasNewNotification(true); + }); + + // 초기 알림 데이터 로드 + await loadNotis(); + + // 컴포넌트 언마운트 시 정리 + return () => { + unsubscribeFromConnection(); + unsubscribeFromMessages(); + webSocketNotificationService.disconnect(); + }; + } catch (error) { + console.error('Error setting up WebSocket:', error); } }; + + setupWebSocket(); }, []); useEffect(() => { @@ -246,16 +268,43 @@ useEffect(() => { } }; + const notificationBtnStyle = { + position: 'relative', + backgroundColor: 'transparent', + border: 'none', + cursor: 'pointer', + alignItems: 'center', + }; + + const notificationIconStyle = { + fontSize: '20px', + }; + + const notificationBadgeStyle = { + position: 'absolute', + top: '4px', + right: '12px', + width: '8px', + height: '8px', + backgroundColor: '#ef4444', + borderRadius: '50%', + display: hasNewNotification ? 'block' : 'none', + }; + return (
CommitField
- + {/* 채팅 버튼 추가 */}