import React, { useState, useEffect } from "react"; import { Conversation, Message, User } from "../types"; import { messageAPI } from "../services/api"; import { useAuth } from "../contexts/AuthContext"; import { useSocket } from "../contexts/SocketContext"; import ChatWindow from "../components/ChatWindow"; const Messages: React.FC = () => { const { user } = useAuth(); const { isConnected, onNewMessage, onMessageRead } = useSocket(); const [conversations, setConversations] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedRecipient, setSelectedRecipient] = useState(null); const [showChat, setShowChat] = useState(false); useEffect(() => { fetchConversations(); }, []); // Listen for new messages and update conversations in real-time useEffect(() => { if (!isConnected) return; const cleanup = onNewMessage((newMessage: Message) => { setConversations((prevConversations) => { // Determine conversation partner const partnerId = newMessage.senderId === user?.id ? newMessage.receiverId : newMessage.senderId; // Find existing conversation const existingIndex = prevConversations.findIndex( (c) => c.partnerId === partnerId ); if (existingIndex !== -1) { // Update existing conversation const updated = [...prevConversations]; const conv = { ...updated[existingIndex] }; conv.lastMessage = { id: newMessage.id, content: newMessage.content, senderId: newMessage.senderId, createdAt: newMessage.createdAt, isRead: newMessage.isRead, }; conv.lastMessageAt = newMessage.createdAt; // Increment unread count if user received the message if (newMessage.receiverId === user?.id && !newMessage.isRead) { conv.unreadCount++; } updated[existingIndex] = conv; // Re-sort by most recent updated.sort( (a, b) => new Date(b.lastMessageAt).getTime() - new Date(a.lastMessageAt).getTime() ); return updated; } else { // New conversation - add to top const partner = newMessage.senderId === user?.id ? newMessage.receiver! : newMessage.sender!; if (!partner) { return prevConversations; } const newConv: Conversation = { partnerId, partner, lastMessage: { id: newMessage.id, content: newMessage.content, senderId: newMessage.senderId, createdAt: newMessage.createdAt, isRead: newMessage.isRead, }, unreadCount: newMessage.receiverId === user?.id && !newMessage.isRead ? 1 : 0, lastMessageAt: newMessage.createdAt, }; return [newConv, ...prevConversations]; } }); }); return cleanup; }, [isConnected, user?.id, onNewMessage]); // Listen for read receipts and update unread counts useEffect(() => { if (!isConnected) return; const cleanup = onMessageRead((data: any) => { setConversations((prevConversations) => { return prevConversations.map((conv) => { // If this is the conversation and the last message was marked as read if ( conv.lastMessage.id === data.messageId && !conv.lastMessage.isRead ) { return { ...conv, lastMessage: { ...conv.lastMessage, isRead: true }, unreadCount: Math.max(0, conv.unreadCount - 1), }; } return conv; }); }); }); return cleanup; }, [isConnected, onMessageRead]); const fetchConversations = async () => { try { const response = await messageAPI.getConversations(); setConversations(response.data); } catch (err: any) { setError(err.response?.data?.error || "Failed to fetch conversations"); } finally { setLoading(false); } }; const formatDate = (dateString: string) => { const date = new Date(dateString); const now = new Date(); const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60); if (diffInHours < 24) { return date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", }); } else if (diffInHours < 48) { return "Yesterday"; } else { return date.toLocaleDateString("en-US", { month: "short", day: "numeric", }); } }; const handleConversationClick = (conversation: Conversation) => { setSelectedRecipient(conversation.partner); setShowChat(true); }; const handleMessagesRead = (partnerId: string, count: number) => { // Update the conversation's unread count setConversations((prevConversations) => prevConversations.map((conv) => conv.partnerId === partnerId ? { ...conv, unreadCount: 0 } : conv ) ); }; const handleChatClose = () => { setShowChat(false); setSelectedRecipient(null); // Refresh conversations to get updated unread counts fetchConversations(); }; if (loading) { return (
Loading...
); } return (

Messages

{error && (
{error}
)} {conversations.length === 0 ? (

No conversations yet

) : (
{conversations.map((conversation) => { const isUnread = conversation.unreadCount > 0; const isLastMessageFromPartner = conversation.lastMessage.senderId === conversation.partnerId; return (
handleConversationClick(conversation)} style={{ cursor: "pointer", backgroundColor: isUnread ? "#f0f7ff" : "white", }} >
{/* Profile Picture */} {conversation.partner.profileImage ? ( {`${conversation.partner.firstName} ) : (
)}
{/* User Name and Unread Badge */}
{conversation.partner.firstName}{" "} {conversation.partner.lastName}
{isUnread && ( {conversation.unreadCount} )}
{/* Last Message Preview */}

{conversation.lastMessage.senderId === user?.id && ( You: )} {conversation.lastMessage.content}

{/* Timestamp */}
{formatDate(conversation.lastMessageAt)}
); })}
)}
{selectedRecipient && ( )}
); }; export default Messages;