@@ -31,7 +31,8 @@ import {
3131 ChatMessage ,
3232 ChatRoom ,
3333 getAvailableRooms ,
34- getRoomMessages ,
34+ getRoomMessages ,
35+ fetchRoomMessages ,
3536 sendMessage ,
3637 addReaction ,
3738 removeReaction ,
@@ -54,6 +55,7 @@ const Community: React.FC = () => {
5455 const [ replyingTo , setReplyingTo ] = useState < ChatMessage | null > ( null ) ;
5556 const [ newRoomName , setNewRoomName ] = useState ( '' ) ;
5657 const messagesEndRef = useRef < HTMLDivElement > ( null ) ;
58+ const messageListenerRef = useRef < ( ) => void > ( ( ) => { } ) ;
5759 const { currentUser, userProfile } = useAuth ( ) ;
5860
5961 // Initialize default chat rooms and fetch available rooms
@@ -62,7 +64,6 @@ const Community: React.FC = () => {
6264 if ( ! currentUser ) return ;
6365
6466 try {
65- // await initializeDefaultChatRooms();
6667 const rooms = await getAvailableRooms ( currentUser . uid , userProfile ?. gender ) ;
6768 setChatRooms ( rooms ) ;
6869
@@ -108,30 +109,70 @@ const Community: React.FC = () => {
108109 fetchUsers ( ) ;
109110 } , [ ] ) ;
110111
111- // Fetch messages for selected room
112+ // Set up real-time message listener when room changes
112113 useEffect ( ( ) => {
114+ // Clean up previous listener if it exists
115+ if ( messageListenerRef . current ) {
116+ messageListenerRef . current ( ) ;
117+ messageListenerRef . current = ( ) => { } ;
118+ }
119+
113120 if ( ! selectedRoom ) return ;
114121
115122 setMessagesLoading ( true ) ;
116123
117- const fetchMessages = async ( ) => {
124+ // Initial fetch of messages
125+ const fetchInitialMessages = async ( ) => {
118126 try {
119- await getRoomMessages ( selectedRoom . id )
120- . then ( ( fetchedMessages ) => {
121- setMessages ( fetchedMessages ) ;
122- setMessagesLoading ( false ) ;
123- } )
124- . catch ( ( error ) => {
125- console . error ( `Error fetching messages for room ${ selectedRoom . id } :` , error ) ;
126- setMessagesLoading ( false ) ;
127- } ) ;
127+ const initialMessages = await fetchRoomMessages ( selectedRoom . id ) ;
128+ setMessages ( initialMessages ) ;
129+ setMessagesLoading ( false ) ;
128130 } catch ( error ) {
129- console . error ( " Error in fetchMessages:" , error ) ;
131+ console . error ( ` Error fetching initial messages for room ${ selectedRoom . id } :` , error ) ;
130132 setMessagesLoading ( false ) ;
131133 }
132134 } ;
133135
134- fetchMessages ( ) ;
136+ fetchInitialMessages ( ) ;
137+
138+ // Set up real-time listener for messages
139+ const unsubscribe = getRoomMessages ( selectedRoom . id ) ;
140+
141+ // Store the unsubscribe function in a ref to clean up later
142+ messageListenerRef . current = unsubscribe ;
143+
144+ // Add a custom listener to the messages collection
145+ const messagesQuery = collection ( db , 'rooms' , selectedRoom . id , 'messages' ) ;
146+ const realTimeListener = onSnapshot ( messagesQuery , ( snapshot ) => {
147+ const updatedMessages : ChatMessage [ ] = [ ] ;
148+
149+ snapshot . forEach ( ( doc ) => {
150+ const messageData = doc . data ( ) as Omit < ChatMessage , 'id' > ;
151+ updatedMessages . push ( {
152+ id : doc . id ,
153+ ...messageData ,
154+ timestamp : messageData . timestamp as Timestamp
155+ } ) ;
156+ } ) ;
157+
158+ // Sort messages by timestamp
159+ updatedMessages . sort ( ( a , b ) => {
160+ const aTime = a . timestamp instanceof Timestamp ? a . timestamp . toMillis ( ) : 0 ;
161+ const bTime = b . timestamp instanceof Timestamp ? b . timestamp . toMillis ( ) : 0 ;
162+ return aTime - bTime ;
163+ } ) ;
164+
165+ setMessages ( updatedMessages ) ;
166+ setMessagesLoading ( false ) ;
167+ } ) ;
168+
169+ // Updated cleanup function
170+ return ( ) => {
171+ if ( messageListenerRef . current ) {
172+ messageListenerRef . current ( ) ;
173+ }
174+ realTimeListener ( ) ;
175+ } ;
135176 } , [ selectedRoom ] ) ;
136177
137178 // Scroll to bottom when messages change
@@ -241,6 +282,17 @@ const Community: React.FC = () => {
241282 }
242283 } ;
243284
285+ // Get online count (this is a placeholder - in a real app you'd implement presence tracking)
286+ const getOnlineCount = ( room : ChatRoom ) => {
287+ // For demonstration, we'll assume 1-3 random participants are online
288+ const participantCount = room . participants . length ;
289+ const onlineCount = participantCount > 0
290+ ? Math . min ( Math . ceil ( Math . random ( ) * participantCount ) , 3 )
291+ : 0 ;
292+
293+ return onlineCount ;
294+ } ;
295+
244296 // Render message reactions
245297 const renderReactions = ( message : ChatMessage ) => {
246298 if ( ! message . reactions || Object . keys ( message . reactions ) . length === 0 ) {
@@ -348,28 +400,44 @@ const Community: React.FC = () => {
348400 </ div >
349401 ) : (
350402 < div className = "space-y-2 max-h-[50vh] overflow-y-auto pr-2" >
351- { chatRooms . map ( ( room ) => (
352- < div
353- key = { room . id }
354- className = { `flex items-center gap-2 p-2 rounded-md cursor-pointer transition-colors ${
355- selectedRoom ?. id === room . id
356- ? 'bg-primary text-primary-foreground'
357- : 'hover:bg-muted'
358- } `}
359- onClick = { ( ) => setSelectedRoom ( room ) }
360- >
361- < div className = "flex-1 truncate" >
362- < div className = "font-medium" > { room . name } </ div >
363- { room . lastMessage && (
364- < div className = "text-xs truncate opacity-80" >
365- { getUserDisplayName ( room . lastMessage . senderId ) } : { room . lastMessage . text }
403+ { chatRooms . map ( ( room ) => {
404+ // Calculate online count for display
405+ const onlineCount = getOnlineCount ( room ) ;
406+
407+ return (
408+ < div
409+ key = { room . id }
410+ className = { `flex items-center gap-2 p-2 rounded-md cursor-pointer transition-colors ${
411+ selectedRoom ?. id === room . id
412+ ? 'bg-primary text-primary-foreground'
413+ : 'hover:bg-muted'
414+ } `}
415+ onClick = { ( ) => setSelectedRoom ( room ) }
416+ >
417+ < div className = "flex-1 truncate" >
418+ < div className = "font-medium" > { room . name } </ div >
419+ { room . lastMessage && (
420+ < div className = "text-xs truncate opacity-80" >
421+ { getUserDisplayName ( room . lastMessage . senderId ) } : { room . lastMessage . text }
422+ </ div >
423+ ) }
424+ < div className = "text-xs mt-1" >
425+ < span className = "font-medium" >
426+ { room . participants . length } members
427+ </ span >
428+ { onlineCount > 0 && (
429+ < span className = "ml-2" >
430+ < span className = "inline-block h-2 w-2 rounded-full bg-green-500 mr-1" > </ span >
431+ { onlineCount } online
432+ </ span >
433+ ) }
366434 </ div >
367- ) }
435+ </ div >
436+ { room . type === 'men' && < Badge variant = "outline" > 👨 Men</ Badge > }
437+ { room . type === 'women' && < Badge variant = "outline" > 👩 Women</ Badge > }
368438 </ div >
369- { room . type === 'men' && < Badge variant = "outline" > 👨 Men</ Badge > }
370- { room . type === 'women' && < Badge variant = "outline" > 👩 Women</ Badge > }
371- </ div >
372- ) ) }
439+ ) ;
440+ } ) }
373441 </ div >
374442 ) }
375443 </ CardContent >
@@ -380,10 +448,23 @@ const Community: React.FC = () => {
380448 < div className = "md:col-span-3" >
381449 < Card className = "mb-6" >
382450 < CardHeader className = "pb-3" >
383- < CardTitle > { selectedRoom ?. name || 'Select a chat room' } </ CardTitle >
384- < CardDescription >
385- A safe space to share experiences and support each other
386- </ CardDescription >
451+ < div className = "flex justify-between items-center" >
452+ < div >
453+ < CardTitle > { selectedRoom ?. name || 'Select a chat room' } </ CardTitle >
454+ < CardDescription >
455+ A safe space to share experiences and support each other
456+ </ CardDescription >
457+ </ div >
458+
459+ { selectedRoom && (
460+ < div className = "text-sm text-muted-foreground" >
461+ < div className = "flex items-center" >
462+ < Users className = "h-4 w-4 mr-1" />
463+ < span > { selectedRoom . participants . length } members</ span >
464+ </ div >
465+ </ div >
466+ ) }
467+ </ div >
387468 </ CardHeader >
388469
389470 < CardContent className = "space-y-4" >
@@ -423,7 +504,7 @@ const Community: React.FC = () => {
423504 < div className = "flex items-baseline gap-2" >
424505 < span className = "text-sm font-medium" > { getUserDisplayName ( msg . senderId ) } </ span >
425506 < span className = "text-xs text-muted-foreground" >
426- { formatTimeAgo ( msg . timestamp . toDate ( ) ) }
507+ { msg . timestamp && msg . timestamp . toDate ? formatTimeAgo ( msg . timestamp . toDate ( ) ) : 'Just now' }
427508 </ span >
428509 </ div >
429510
0 commit comments