fixed fetching previous messages
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user