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