@@ -16,6 +16,10 @@ const SENIOR_PRICE_PER_REVIEW = window.SENIOR_PRICE_PER_REVIEW ?? 0;
1616const chatContainer = document . getElementById ( 'messageList' ) ;
1717let stompClient = null ;
1818
19+ // 현재 방 마감 여부 (페이지 로드 시 초기값 + ROOM_CLOSE 이벤트 수신 시 true로 전환)
20+ // ROOM_STATUS 상수는 변경이 안 되므로 별도 변수로 관리
21+ let currentRoomClosed = ROOM_STATUS === 'CLOSED' ;
22+
1923// 결제 상세 모달에서 결제 진행 시 사용할 현재 주문 정보
2024// (GET /orders/{orderId}/prepare 응답으로 채워짐)
2125let paymentDetailOrderId = null ; // Toss orderId로 사용할 orderNumber(예: "ORD-...")
@@ -157,8 +161,8 @@ function renderUserMessage(msg, options = {}) {
157161}
158162
159163// 사이드바 미리보기 실시간 업데이트
160- function updateSidebarPreview ( content ) {
161- const roomItem = document . querySelector ( `.room-item[data-room-id="${ ROOM_ID } "]` ) ;
164+ function updateSidebarPreview ( content , roomId = ROOM_ID ) {
165+ const roomItem = document . querySelector ( `.room-item[data-room-id="${ roomId } "]` ) ;
162166 if ( ! roomItem ) return ;
163167 const preview = roomItem . querySelector ( '.room-preview' ) ;
164168 if ( preview ) preview . textContent = content ;
@@ -169,6 +173,34 @@ function updateSidebarPreview(content) {
169173 }
170174}
171175
176+ // 읽지 않은 메시지 점 표시 관리 (localStorage로 새로고침 후에도 유지)
177+ function updateUnreadBadge ( roomId ) {
178+ localStorage . setItem ( 'unread_' + roomId , 'true' ) ;
179+ showUnreadDot ( roomId ) ;
180+ }
181+
182+ function showUnreadDot ( roomId ) {
183+ const roomItem = document . querySelector ( `.room-item[data-room-id="${ roomId } "]` ) ;
184+ if ( ! roomItem ) return ;
185+ const dot = roomItem . querySelector ( '.unread-badge' ) ;
186+ if ( dot ) dot . style . display = 'block' ;
187+ }
188+
189+ // 페이지 로드 시: 현재 방은 읽음 처리, 나머지는 localStorage에서 복원
190+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
191+ // 현재 보고 있는 방은 읽음 처리
192+ if ( ROOM_ID ) localStorage . removeItem ( 'unread_' + ROOM_ID ) ;
193+
194+ // 다른 방들의 미확인 점 복원
195+ document . querySelectorAll ( '.room-item' ) . forEach ( function ( item ) {
196+ const roomId = item . getAttribute ( 'data-room-id' ) ;
197+ if ( roomId && localStorage . getItem ( 'unread_' + roomId ) ) {
198+ const dot = item . querySelector ( '.unread-badge' ) ;
199+ if ( dot ) dot . style . display = 'block' ;
200+ }
201+ } ) ;
202+ } ) ;
203+
172204// 사이드바 토글 (모바일 대응)
173205function toggleSidebar ( ) {
174206 const sidebar = document . getElementById ( 'chatSidebar' ) ;
@@ -193,7 +225,8 @@ function disableChatUI() {
193225// ==========================================
194226// 5. STOMP 연결 및 구독 로직 (1:1 Queue)
195227// ==========================================
196- if ( ROOM_ID && ROOM_STATUS !== 'CLOSED' ) {
228+ // CLOSED 방을 보고 있어도 다른 방의 메시지(배지/사이드바 업데이트)를 받기 위해 항상 연결한다.
229+ if ( ROOM_ID ) {
197230 const socket = new SockJS ( '/ws' ) ;
198231 stompClient = Stomp . over ( socket ) ;
199232 stompClient . debug = null ;
@@ -205,28 +238,43 @@ if (ROOM_ID && ROOM_STATUS !== 'CLOSED') {
205238 stompClient . connect ( connectHeaders , function ( ) {
206239 console . log ( '✅ STOMP 서버 연결 완료' ) ;
207240 const statusEl = document . getElementById ( 'connectionStatus' ) ;
208- if ( statusEl ) {
209- statusEl . textContent = '연결됨' ;
210- statusEl . className = 'connection-status status-connected' ;
241+ if ( statusEl ) {
242+ if ( currentRoomClosed ) {
243+ statusEl . textContent = '마감됨' ;
244+ statusEl . className = 'connection-status status-disconnected' ;
245+ } else {
246+ statusEl . textContent = '연결됨' ;
247+ statusEl . className = 'connection-status status-connected' ;
248+ }
211249 }
212250
213251 // 💡 1:1 큐 구독 방식으로 통신
214252 stompClient . subscribe ( '/user/queue/chat' , function ( message ) {
215253 const data = JSON . parse ( message . body ) ;
216254 const type = data . messageType || data . type ;
217255
256+ // 다른 방 메시지: 사이드바 미리보기 + 배지만 업데이트하고 렌더링은 스킵
257+ if ( data . roomId && data . roomId !== ROOM_ID ) {
258+ if ( type === 'USER' ) {
259+ updateSidebarPreview ( data . content , data . roomId ) ;
260+ updateUnreadBadge ( data . roomId ) ;
261+ }
262+ return ;
263+ }
264+
265+ // 현재 방이 마감 상태면 새 메시지 렌더링 스킵
266+ if ( currentRoomClosed ) return ;
267+
218268 // 실시간 마감 이벤트 감지
219269 if ( type === 'ROOM_CLOSE' ) {
270+ currentRoomClosed = true ; // 이후 이 방의 메시지는 렌더링하지 않음
220271 renderSystemMessage ( data ) ;
221272 disableChatUI ( ) ;
222-
223- stompClient . disconnect ( function ( ) {
224- console . log ( "🔒 채팅방 마감: 소켓 연결이 안전하게 종료되었습니다." ) ;
225- if ( statusEl ) {
226- statusEl . textContent = '마감됨' ;
227- statusEl . className = 'connection-status status-disconnected' ;
228- }
229- } ) ;
273+ // WebSocket은 끊지 않음 → 다른 방 메시지(배지/사이드바)를 계속 받기 위해
274+ if ( statusEl ) {
275+ statusEl . textContent = '마감됨' ;
276+ statusEl . className = 'connection-status status-disconnected' ;
277+ }
230278 return ;
231279 }
232280
@@ -256,9 +304,6 @@ if (ROOM_ID && ROOM_STATUS !== 'CLOSED') {
256304 statusEl . className = 'connection-status status-disconnected' ;
257305 }
258306 } ) ;
259- } else if ( ROOM_STATUS === 'CLOSED' ) {
260- console . warn ( "🔒 이미 마감된 채팅방입니다. 소켓 연결을 차단합니다." ) ;
261- setTimeout ( scrollToBottom , 100 ) ;
262307}
263308
264309// ==========================================
0 commit comments