fixed fetching previous messages

This commit is contained in:
2025-01-16 16:36:40 +01:00
parent a2722deb76
commit 8f25f13838

View File

@@ -1,4 +1,4 @@
import { useContext, useEffect, useRef, useState } from 'react'; import { useContext, useEffect, useRef, useState, useCallback } from 'react';
import { socket } from '@/socket/socket.ts'; import { socket } from '@/socket/socket.ts';
import { sendContact } from '@/api/contactsApi.tsx'; import { sendContact } from '@/api/contactsApi.tsx';
import LoadingWheel from '../LoadingWheel.tsx'; import LoadingWheel from '../LoadingWheel.tsx';
@@ -20,13 +20,14 @@ function MessagesArea() {
contactsList, contactsList,
setCurrentContact, setCurrentContact,
} = useChat(); } = useChat();
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const { user } = useContext(AuthContext); const { user } = useContext(AuthContext);
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const [shouldScrollToBottom, setShouldScrollToBottom] = useState(true); const [shouldScrollToBottom, setShouldScrollToBottom] = useState(true);
const previousMessagesLength = useRef(messages.length); const previousMessagesLength = useRef<number>(messages.length);
const isFocused = useWindowFocus(); const isFocused = useWindowFocus();
const previousTitle = useRef(document.title); const previousTitle = useRef<string>(document.title);
const scrollToBottom = () => { const scrollToBottom = () => {
const container = containerRef.current; const container = containerRef.current;
if (container && shouldScrollToBottom) { if (container && shouldScrollToBottom) {
@@ -34,18 +35,16 @@ function MessagesArea() {
} }
}; };
const handleScroll = async () => { const handleScroll = useCallback(async () => {
const container = containerRef.current; const container = containerRef.current;
if (!container) return; if (!container || isLoading) return;
if (container.scrollTop === 0) { if (container.scrollTop === 0) {
setIsLoading(true); setIsLoading(true);
setShouldScrollToBottom(false);
const previousScrollHeight = container.scrollHeight;
try { try {
const previousScrollHeight = container.scrollHeight;
await fetchPreviousMessages(currentContact!.conversation_id); await fetchPreviousMessages(currentContact!.conversation_id);
// Adjust scroll position after fetching new messages
container.scrollTop = container.scrollHeight - previousScrollHeight; container.scrollTop = container.scrollHeight - previousScrollHeight;
} catch (e) { } catch (e) {
console.error('Error fetching previous messages:', e); console.error('Error fetching previous messages:', e);
@@ -58,39 +57,22 @@ function MessagesArea() {
container.scrollHeight - container.scrollTop <= container.scrollHeight - container.scrollTop <=
container.clientHeight + 200; container.clientHeight + 200;
setShouldScrollToBottom(isAtBottom); setShouldScrollToBottom(isAtBottom);
}; }, [isLoading, currentContact, fetchPreviousMessages]);
const deleteMessage = async (message_id: number) => { useEffect(() => {
try { const currentContainer = containerRef.current;
socket?.emit( if (!currentContainer) return;
'delete message',
{ currentContainer.addEventListener('scroll', handleScroll);
message_id,
conversation_id: currentContact?.conversation_id, return () => {
}, currentContainer.removeEventListener('scroll', handleScroll);
(response: { status: string; message: string }) => { };
if (response.status !== 'ok') { }, [handleScroll]);
console.error('Failed to delete message: ', response.message);
}
},
);
} catch (e) {
if (e instanceof Error) {
console.error('Failed to delete message');
}
}
};
useEffect(() => { useEffect(() => {
if (!socket) return; if (!socket) return;
const currentContainer = containerRef.current;
if (currentContainer) {
currentContainer.addEventListener('scroll', handleScroll);
}
socket.on('chat message', (msg: ChatMessagesProps) => { socket.on('chat message', (msg: ChatMessagesProps) => {
console.log('Received message: ', msg);
const isFromCurrentConversation = const isFromCurrentConversation =
msg.conversation_id === currentContact?.conversation_id; msg.conversation_id === currentContact?.conversation_id;
const isFromCurrentUser = msg.sender === user?.username; const isFromCurrentUser = msg.sender === user?.username;
@@ -98,58 +80,50 @@ function MessagesArea() {
if (isFromCurrentConversation) { if (isFromCurrentConversation) {
messageHandler(msg); messageHandler(msg);
if (!isFocused) { if (!isFocused) {
setContactsList((prevContacts) => { setContactsList((prevContacts) =>
return prevContacts.map((contact) => prevContacts.map((contact) =>
contact.conversation_id === currentContact?.conversation_id contact.conversation_id === currentContact?.conversation_id
? { ? { ...contact, read: false }
...contact,
read: false,
}
: contact, : contact,
); ),
}); );
document.title = 'New message ❗'; document.title = 'New message ❗';
} else { } else {
socket?.emit('read message', { socket?.emit('read message', {
conversation_id: msg.conversation_id, conversation_id: msg.conversation_id,
message_id: msg.conversation_id, message_id: msg.message_id,
}); });
} }
} }
// Handle contact list updates
setContactsList((prevContacts) => { setContactsList((prevContacts) => {
// If message is from another conversation const isFromAnotherConversation =
if (!isFromCurrentConversation && !isFromCurrentUser) { !isFromCurrentConversation && !isFromCurrentUser;
// Check if contact exists const existingContact = prevContacts.find(
const existingContact = prevContacts.find( (c) => c.conversation_id === msg.conversation_id,
(c) => c.conversation_id === msg.conversation_id, );
);
if (!existingContact) { if (isFromAnotherConversation && !existingContact) {
sendContact(msg.sender); sendContact(msg.sender);
return [ return [
...prevContacts, ...prevContacts,
{ {
read: false, read: false,
username: msg.sender, username: msg.sender,
id: msg.message_id, user_id: msg.sender_id,
user_id: msg.sender_id, conversation_id: msg.conversation_id,
conversation_id: msg.conversation_id, type: 'direct',
type: 'direct', id: msg.message_id,
last_active: new Date().toString(), last_active: new Date().toISOString(),
last_message: msg.message, last_message: msg.message,
last_message_id: msg.message_id, last_message_id: msg.message_id,
last_message_sender: msg.sender, last_message_sender: msg.sender,
last_message_time: new Date().toString(), last_message_time: new Date().toISOString(),
last_read_message_id: prevContacts[0]?.last_message_id || null, last_read_message_id: prevContacts[0]?.last_message_id || null,
}, },
]; ];
}
} }
// Update existing contact if found
return prevContacts.map((contact) => return prevContacts.map((contact) =>
contact.conversation_id === msg.conversation_id contact.conversation_id === msg.conversation_id
? { ? {
@@ -174,9 +148,8 @@ function MessagesArea() {
(message) => message.message_id !== msg.message_id, (message) => message.message_id !== msg.message_id,
), ),
); );
console.log('deleted message from state'); setContactsList((prevContacts) =>
setContactsList((prevContacts) => { prevContacts.map((contact) =>
return prevContacts.map((contact) =>
contact.last_message_id === msg.message_id contact.last_message_id === msg.message_id
? { ? {
...contact, ...contact,
@@ -185,20 +158,13 @@ function MessagesArea() {
last_message_time: new Date().toString(), last_message_time: new Date().toString(),
} }
: contact, : contact,
); ),
}); );
}, },
); );
return () => { return () => {
if (!socket) { if (!socket) return;
console.error('Socket not initialized');
return;
}
if (currentContainer) {
currentContainer.removeEventListener('scroll', handleScroll);
}
socket.off('chat message'); socket.off('chat message');
socket.off('delete message'); socket.off('delete message');
}; };
@@ -206,35 +172,22 @@ function MessagesArea() {
useEffect(() => { useEffect(() => {
if (!currentContact) return; if (!currentContact) return;
const currentContactOnList = contactsList.find((contact) => { const currentContactOnList = contactsList.find(
return contact.conversation_id == currentContact?.conversation_id; (contact) => contact.conversation_id === currentContact.conversation_id,
}); );
if (currentContactOnList && messages.length > 1) { if (currentContactOnList && messages.length > 1) {
socket?.emit('message read', { socket?.emit('message read', {
conversation_id: currentContact?.conversation_id, conversation_id: currentContact.conversation_id,
message_id: messages[messages.length - 1].message_id, message_id: messages[messages.length - 1].message_id,
}); });
setCurrentContact({ ...currentContact, read: currentContactOnList.read }); setCurrentContact({ ...currentContact, read: currentContactOnList.read });
} }
return () => {
if (!socket) return;
socket.off('message read');
};
}, [contactsList, currentContact?.conversation_id]); }, [contactsList, currentContact?.conversation_id]);
useEffect(() => { useEffect(() => {
if (currentContact?.read == true) { if (currentContact?.read) return;
return;
}
document.title = previousTitle.current; document.title = previousTitle.current;
if (messages.length > 1) { if (messages.length > 1) {
console.error(
'read !== true, emiting message read socket for: ',
currentContact?.username,
messages[messages.length - 1].message_id,
);
socket?.emit('message read', { socket?.emit('message read', {
conversation_id: currentContact?.conversation_id, conversation_id: currentContact?.conversation_id,
message_id: messages[messages.length - 1].message_id, message_id: messages[messages.length - 1].message_id,
@@ -242,16 +195,13 @@ function MessagesArea() {
} }
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
setContactsList((prevContacts) => { setContactsList((prevContacts) =>
return prevContacts.map((contact) => prevContacts.map((contact) =>
contact?.conversation_id === currentContact?.conversation_id contact.conversation_id === currentContact?.conversation_id
? { ? { ...contact, read: true }
...contact,
read: true,
}
: contact, : contact,
); ),
}); );
}, 800); }, 800);
return () => clearTimeout(timeout); return () => clearTimeout(timeout);
@@ -263,7 +213,6 @@ function MessagesArea() {
if (hasNewMessages && shouldScrollToBottom) { if (hasNewMessages && shouldScrollToBottom) {
scrollToBottom(); scrollToBottom();
setTimeout(scrollToBottom, 100); setTimeout(scrollToBottom, 100);
} }
}, [messages, shouldScrollToBottom]); }, [messages, shouldScrollToBottom]);
@@ -272,6 +221,27 @@ function MessagesArea() {
scrollToBottom(); scrollToBottom();
}, []); }, []);
const deleteMessage = async (message_id: number) => {
try {
socket?.emit(
'delete message',
{
message_id,
conversation_id: currentContact?.conversation_id,
},
(response: { status: string; message: string }) => {
if (response.status !== 'ok') {
console.error('Failed to delete message: ', response.message);
}
},
);
} catch (e) {
if (e instanceof Error) {
console.error('Failed to delete message:', e);
}
}
};
return ( return (
<div ref={containerRef} className="flex flex-col h-full overflow-y-auto"> <div ref={containerRef} className="flex flex-col h-full overflow-y-auto">
<p className="text-center text-gray-400">{errorMessage}</p> <p className="text-center text-gray-400">{errorMessage}</p>
@@ -281,7 +251,7 @@ function MessagesArea() {
<AnimatedMessage <AnimatedMessage
key={msg.message_id} key={msg.message_id}
message={msg} message={msg}
onDelete={deleteMessage} onDelete={() => deleteMessage(msg.message_id)}
/> />
))} ))}
</ul> </ul>