unread messages handling works
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/turtle.svg"/>
|
<link rel="icon" type="image/svg+xml" href="/turtle.svg"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Turtel chat 🐢</title>
|
<title>Turtel chat</title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body{
|
body{
|
||||||
|
|||||||
@@ -12,21 +12,6 @@ export async function getContactsList(): Promise<ContactsProps[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setContactStatus(conversation_id: string, read: boolean) {
|
|
||||||
try {
|
|
||||||
const response = await axiosClient.put(
|
|
||||||
`/api/chat/contacts/${conversation_id}`,
|
|
||||||
{ status: read },
|
|
||||||
{ withCredentials: true },
|
|
||||||
);
|
|
||||||
console.log(response.data);
|
|
||||||
return response.data;
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to set contact status: ', e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function sendContact(contact: string) {
|
export async function sendContact(contact: string) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosClient.post(`/api/chat/contact/${contact}`);
|
const response = await axiosClient.post(`/api/chat/contact/${contact}`);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useContext, useEffect, useRef, useState } from 'react';
|
import { useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { socket } from '@/socket/socket.ts';
|
import { socket } from '@/socket/socket.ts';
|
||||||
import { sendContact, setContactStatus } from '@/api/contactsApi.tsx';
|
import { sendContact } from '@/api/contactsApi.tsx';
|
||||||
import LoadingWheel from '../LoadingWheel.tsx';
|
import LoadingWheel from '../LoadingWheel.tsx';
|
||||||
import AnimatedMessage from '@/components/chat/chatArea/AnimatedMessage.tsx';
|
import AnimatedMessage from '@/components/chat/chatArea/AnimatedMessage.tsx';
|
||||||
import { ChatMessagesProps } from '@/types/types.ts';
|
import { ChatMessagesProps } from '@/types/types.ts';
|
||||||
@@ -13,11 +13,11 @@ function MessagesArea() {
|
|||||||
messages,
|
messages,
|
||||||
setMessages,
|
setMessages,
|
||||||
currentContact,
|
currentContact,
|
||||||
updateContactStatus,
|
|
||||||
messageHandler,
|
messageHandler,
|
||||||
setContactsList,
|
setContactsList,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
fetchPreviousMessages,
|
fetchPreviousMessages,
|
||||||
|
contactsList,
|
||||||
setCurrentContact,
|
setCurrentContact,
|
||||||
} = useChat();
|
} = useChat();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -98,9 +98,23 @@ function MessagesArea() {
|
|||||||
if (isFromCurrentConversation) {
|
if (isFromCurrentConversation) {
|
||||||
messageHandler(msg);
|
messageHandler(msg);
|
||||||
if (!isFocused) {
|
if (!isFocused) {
|
||||||
updateContactStatus(msg.conversation_id, false);
|
setContactsList((prevContacts) => {
|
||||||
setCurrentContact({ ...currentContact, read: false });
|
return prevContacts.map((contact) =>
|
||||||
|
contact.conversation_id === currentContact?.conversation_id
|
||||||
|
? {
|
||||||
|
...contact,
|
||||||
|
read: false,
|
||||||
|
}
|
||||||
|
: contact,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
document.title = 'New message ❗';
|
document.title = 'New message ❗';
|
||||||
|
} else {
|
||||||
|
socket?.emit('read message', {
|
||||||
|
conversation_id: msg.conversation_id,
|
||||||
|
message_id: msg.conversation_id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,8 +122,6 @@ function MessagesArea() {
|
|||||||
setContactsList((prevContacts) => {
|
setContactsList((prevContacts) => {
|
||||||
// If message is from another conversation
|
// If message is from another conversation
|
||||||
if (!isFromCurrentConversation && !isFromCurrentUser) {
|
if (!isFromCurrentConversation && !isFromCurrentUser) {
|
||||||
setContactStatus(msg.conversation_id, false);
|
|
||||||
|
|
||||||
// Check if contact exists
|
// 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,
|
||||||
@@ -120,8 +132,8 @@ function MessagesArea() {
|
|||||||
return [
|
return [
|
||||||
...prevContacts,
|
...prevContacts,
|
||||||
{
|
{
|
||||||
username: msg.sender,
|
|
||||||
read: false,
|
read: false,
|
||||||
|
username: msg.sender,
|
||||||
id: msg.message_id,
|
id: msg.message_id,
|
||||||
user_id: msg.sender_id,
|
user_id: msg.sender_id,
|
||||||
conversation_id: msg.conversation_id,
|
conversation_id: msg.conversation_id,
|
||||||
@@ -189,23 +201,43 @@ function MessagesArea() {
|
|||||||
socket.off('chat message');
|
socket.off('chat message');
|
||||||
socket.off('delete message');
|
socket.off('delete message');
|
||||||
};
|
};
|
||||||
}, [
|
}, [currentContact, user?.username, setContactsList, isFocused]);
|
||||||
currentContact,
|
|
||||||
user?.username,
|
|
||||||
setContactsList,
|
|
||||||
updateContactStatus,
|
|
||||||
isFocused,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFocused && currentContact?.read == true) {
|
if (!currentContact) return;
|
||||||
|
const currentContactOnList = contactsList.find((contact) => {
|
||||||
|
return contact.conversation_id == currentContact?.conversation_id;
|
||||||
|
});
|
||||||
|
if (currentContactOnList && messages.length > 1) {
|
||||||
|
socket?.emit('message read', {
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
document.title = previousTitle.current;
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
if (currentContact?.conversation_id && currentContact?.read !== true) {
|
socket?.emit('message read', {
|
||||||
updateContactStatus(currentContact.conversation_id, true);
|
conversation_id: currentContact?.conversation_id,
|
||||||
setCurrentContact({ ...currentContact, read: true });
|
message_id: messages[messages.length - 1].message_id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
@@ -219,24 +251,11 @@ function MessagesArea() {
|
|||||||
: contact,
|
: contact,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 800);
|
||||||
|
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}, [isFocused]);
|
}, [isFocused]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!socket) return;
|
|
||||||
if (currentContact?.read == true) return;
|
|
||||||
socket.emit('message read', {
|
|
||||||
conversation_id: currentContact?.conversation_id,
|
|
||||||
message_id: messages[messages?.length - 1].message_id,
|
|
||||||
});
|
|
||||||
console.info('MESSAGE READ: ', {
|
|
||||||
conversation_id: currentContact?.conversation_id,
|
|
||||||
message_id: messages[messages?.length - 1].message_id,
|
|
||||||
});
|
|
||||||
}, [isFocused]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hasNewMessages = messages.length > previousMessagesLength.current;
|
const hasNewMessages = messages.length > previousMessagesLength.current;
|
||||||
previousMessagesLength.current = messages.length;
|
previousMessagesLength.current = messages.length;
|
||||||
@@ -254,8 +273,6 @@ function MessagesArea() {
|
|||||||
|
|
||||||
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>READ STATUS: {currentContact?.read ? <p>true</p> : <p>false</p>}</p>
|
|
||||||
<p>ISFOCUSED: {isFocused ? <p>tak</p> : <p>nie</p>}</p>
|
|
||||||
<p className="text-center text-gray-400">{errorMessage}</p>
|
<p className="text-center text-gray-400">{errorMessage}</p>
|
||||||
<ul className="flex-grow list-none">
|
<ul className="flex-grow list-none">
|
||||||
{isLoading ? <LoadingWheel /> : null}
|
{isLoading ? <LoadingWheel /> : null}
|
||||||
@@ -267,6 +284,8 @@ function MessagesArea() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
<p>READ STATUS: {currentContact?.read ? 'tak' : 'nie'}</p>
|
||||||
|
<p>ISFOCUSED: {isFocused ? 'tak' : 'nie'}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ function ContactsList() {
|
|||||||
contactsList,
|
contactsList,
|
||||||
setContactsList,
|
setContactsList,
|
||||||
setCurrentContact,
|
setCurrentContact,
|
||||||
updateContactStatus,
|
|
||||||
setMessages,
|
setMessages,
|
||||||
setErrorMessage,
|
setErrorMessage,
|
||||||
} = useChat();
|
} = useChat();
|
||||||
@@ -48,28 +47,25 @@ function ContactsList() {
|
|||||||
};
|
};
|
||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
contactsList.forEach((contact) => {
|
|
||||||
if (contact.last_message_id && contact.last_read_message_id) {
|
|
||||||
if (contact.last_message_id > contact.last_read_message_id) {
|
|
||||||
setContactsList((prevContacts) =>
|
|
||||||
prevContacts.map((prevContact) =>
|
|
||||||
prevContact.id === contact.id
|
|
||||||
? { ...prevContact, read: false }
|
|
||||||
: prevContact,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [contactsList]);
|
|
||||||
|
|
||||||
const fetchContacts = async () => {
|
const fetchContacts = async () => {
|
||||||
console.log('Fetching contacts list');
|
console.log('Fetching contacts list');
|
||||||
const response = await axiosClient.get(`/api/chat/contacts`);
|
const response = await axiosClient.get(`/api/chat/contacts`);
|
||||||
console.log('Get contacts list response: ', response.data);
|
console.log('Get contacts list response: ', response.data);
|
||||||
|
const fetchedContacts: ContactsProps[] = response.data;
|
||||||
|
|
||||||
setContactsList(response.data);
|
const updatedContacts = fetchedContacts.map((contact) => {
|
||||||
|
if (
|
||||||
|
contact.last_message_id &&
|
||||||
|
contact.last_read_message_id &&
|
||||||
|
contact.last_message_id !== contact.last_read_message_id
|
||||||
|
) {
|
||||||
|
return { ...contact, read: false };
|
||||||
|
} else {
|
||||||
|
return { ...contact, read: true };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setContactsList(updatedContacts);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function removeContact(contactId: number, conversation_id: string) {
|
async function removeContact(contactId: number, conversation_id: string) {
|
||||||
@@ -100,13 +96,22 @@ function ContactsList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sortedContacts = [...contactsList].sort((a, b) => {
|
const sortedContacts = [...contactsList].sort((a, b) => {
|
||||||
// First, sort by read status
|
// First, sort by read status (unread first)
|
||||||
if (a.read !== b.read) {
|
if (a.read !== b.read) {
|
||||||
return a.read ? 1 : -1;
|
return a.read ? 1 : -1;
|
||||||
}
|
}
|
||||||
if (a.read && b.read) {
|
|
||||||
return -a.last_active?.localeCompare(b.last_active);
|
// If both are read or both are unread, sort by last_message_time (if available)
|
||||||
|
if (a.last_message_time !== null && b.last_message_time !== null) {
|
||||||
|
return -a.last_message_time.localeCompare(b.last_message_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If one or both last_message_time are null, sort by last_active_time
|
||||||
|
if (a.last_message_time === null || b.last_message_time === null) {
|
||||||
|
return -a.last_active.localeCompare(b.last_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default case (should not be reached)
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,7 +120,6 @@ function ContactsList() {
|
|||||||
className="m-1 flex p-2 hover:bg-zinc-900 cursor-pointer transition-colors rounded-lg justify-between items-start min-h-[40px]"
|
className="m-1 flex p-2 hover:bg-zinc-900 cursor-pointer transition-colors rounded-lg justify-between items-start min-h-[40px]"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
initializeContact(contact);
|
initializeContact(contact);
|
||||||
updateContactStatus(contact.conversation_id, true);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex flex-col w-full">
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const LastActiveTime = ({ contact }: LastActiveTimeProps) => {
|
|||||||
const intervalId = setInterval(updateTime, 60000);
|
const intervalId = setInterval(updateTime, 60000);
|
||||||
|
|
||||||
return () => clearInterval(intervalId);
|
return () => clearInterval(intervalId);
|
||||||
}, [contact?.last_message]);
|
}, [contact?.last_message_time]);
|
||||||
|
|
||||||
return <span className="text-xs font-bold text-gray-500">{timeAgo}</span>;
|
return <span className="text-xs font-bold text-gray-500">{timeAgo}</span>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ function ParticipantsBar() {
|
|||||||
last_message: string | null;
|
last_message: string | null;
|
||||||
last_message_time: string | null;
|
last_message_time: string | null;
|
||||||
last_message_sender: string | null;
|
last_message_sender: string | null;
|
||||||
|
last_read_message_id: number | null;
|
||||||
}) => {
|
}) => {
|
||||||
const { group_id } = msg;
|
const { group_id } = msg;
|
||||||
if (
|
if (
|
||||||
@@ -157,6 +158,7 @@ function ParticipantsBar() {
|
|||||||
last_message_id: msg.last_message_id,
|
last_message_id: msg.last_message_id,
|
||||||
last_message_sender: msg.last_message_sender,
|
last_message_sender: msg.last_message_sender,
|
||||||
last_message_time: msg.last_message_time,
|
last_message_time: msg.last_message_time,
|
||||||
|
last_read_message_id: msg.last_read_message_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ChatContext } from '@/context/chat/ChatContext.tsx';
|
|||||||
import { ReactNode, useState } from 'react';
|
import { ReactNode, useState } from 'react';
|
||||||
import { ChatMessagesProps, ContactsProps, MeProps } from '@/types/types.ts';
|
import { ChatMessagesProps, ContactsProps, MeProps } from '@/types/types.ts';
|
||||||
import { joinRoom } from '@/socket/socket.ts';
|
import { joinRoom } from '@/socket/socket.ts';
|
||||||
import { getMessages, setContactStatus } from '@/api/contactsApi.tsx';
|
import { getMessages } from '@/api/contactsApi.tsx';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
||||||
@@ -23,7 +23,7 @@ export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
async function initializeContact(newContact: ContactsProps) {
|
async function initializeContact(newContact: ContactsProps) {
|
||||||
setMessages([]); // Clear messages from previous contact
|
setMessages([]); // Clear messages from previous contact
|
||||||
localStorage.setItem('contact', JSON.stringify(newContact)); // Set current contact in localstorage
|
localStorage.setItem('contact', JSON.stringify(newContact)); // Set current contact in localstorage
|
||||||
setCurrentContact({ ...newContact, read: true });
|
setCurrentContact({ ...newContact });
|
||||||
console.log('Initialized contact: ', newContact);
|
console.log('Initialized contact: ', newContact);
|
||||||
try {
|
try {
|
||||||
const joinResult = await joinRoom(newContact.conversation_id);
|
const joinResult = await joinRoom(newContact.conversation_id);
|
||||||
@@ -53,19 +53,19 @@ export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
const fetchMessages = async (conversation_id: string) => {
|
const fetchMessages = async (conversation_id: string) => {
|
||||||
console.log('Fetching messages for: ', conversation_id);
|
console.log('Fetching messages for: ', conversation_id);
|
||||||
try {
|
try {
|
||||||
const messages = await getMessages(conversation_id);
|
const fetchedMessages = await getMessages(conversation_id);
|
||||||
if (messages.messages.length < 50) {
|
if (fetchedMessages.messages.length < 50) {
|
||||||
setHasMoreMessages(false);
|
setHasMoreMessages(false);
|
||||||
setErrorMessage('No more messages found');
|
setErrorMessage('No more messages found');
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor(() => {
|
setCursor(() => {
|
||||||
return Math.min(
|
return Math.min(
|
||||||
...messages.messages.map((message) => message.message_id),
|
...fetchedMessages.messages.map((message) => message.message_id),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
messages.messages.forEach(messageHandler);
|
fetchedMessages.messages.forEach(messageHandler);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (axios.isAxiosError(e)) {
|
if (axios.isAxiosError(e)) {
|
||||||
setErrorMessage(e.message);
|
setErrorMessage(e.message);
|
||||||
@@ -94,8 +94,6 @@ export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
setContactsList((prevContacts) =>
|
setContactsList((prevContacts) =>
|
||||||
prevContacts.map((contact) => {
|
prevContacts.map((contact) => {
|
||||||
if (contact.conversation_id === conversation_id) {
|
if (contact.conversation_id === conversation_id) {
|
||||||
setContactStatus(conversation_id, read);
|
|
||||||
|
|
||||||
return { ...contact, read: read };
|
return { ...contact, read: read };
|
||||||
} else {
|
} else {
|
||||||
return contact;
|
return contact;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export default function Login() {
|
|||||||
<div className="text-red-400 text-sm">{message}</div>
|
<div className="text-red-400 text-sm">{message}</div>
|
||||||
</form>
|
</form>
|
||||||
<p className="text-gray-300 mt-10 text-center text-sm">
|
<p className="text-gray-300 mt-10 text-center text-sm">
|
||||||
Don't have account?{' '}
|
or{' '}
|
||||||
<Link
|
<Link
|
||||||
to="/signup"
|
to="/signup"
|
||||||
className="text-green-400 leading-6 hover:text-green-600"
|
className="text-green-400 leading-6 hover:text-green-600"
|
||||||
|
|||||||
@@ -707,49 +707,56 @@ async function checkMembership(user_id, conversation_id) {
|
|||||||
async function getContacts(user_id) {
|
async function getContacts(user_id) {
|
||||||
const contactsQuery = `
|
const contactsQuery = `
|
||||||
WITH DirectContacts AS (
|
WITH DirectContacts AS (
|
||||||
SELECT
|
SELECT DISTINCT ON (c.conversation_id)
|
||||||
c.contact_id AS id,
|
c.contact_id AS id,
|
||||||
a.user_id AS user_id,
|
a.user_id AS user_id,
|
||||||
a.username AS username,
|
a.username AS username,
|
||||||
conv.last_active,
|
conv.last_active,
|
||||||
c.conversation_id,
|
c.conversation_id,
|
||||||
conv.conversation_type AS type,
|
conv.conversation_type AS type,
|
||||||
m.last_read_message_id
|
requesting_member.last_read_message_id
|
||||||
FROM Contacts c
|
FROM Contacts c
|
||||||
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
|
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
|
||||||
JOIN Memberships m ON m.conversation_id = conv.conversation_id
|
JOIN Memberships requesting_member
|
||||||
JOIN Accounts a ON a.user_id = m.user_id
|
ON requesting_member.conversation_id = conv.conversation_id
|
||||||
WHERE c.user_id = $1
|
AND requesting_member.user_id = $1
|
||||||
AND conv.conversation_type = 'direct'
|
JOIN Memberships other_member
|
||||||
AND (a.user_id != $1 OR (SELECT COUNT(*) FROM Memberships WHERE conversation_id = c.conversation_id) = 1)
|
ON other_member.conversation_id = conv.conversation_id
|
||||||
ORDER BY c.conversation_id, conv.last_active DESC
|
JOIN Accounts a ON a.user_id = other_member.user_id
|
||||||
),
|
WHERE c.user_id = $1
|
||||||
GroupContacts AS (
|
AND conv.conversation_type = 'direct'
|
||||||
SELECT
|
AND (
|
||||||
c.contact_id AS id,
|
a.user_id != $1
|
||||||
NULL::uuid AS user_id,
|
OR (SELECT COUNT(*) FROM Memberships WHERE conversation_id = c.conversation_id) = 1
|
||||||
conv.name AS username,
|
)
|
||||||
conv.last_active,
|
),
|
||||||
c.conversation_id,
|
GroupContacts AS (
|
||||||
conv.conversation_type AS type,
|
SELECT DISTINCT ON (c.conversation_id)
|
||||||
m.last_read_message_id -- We need to add Memberships join here too
|
c.contact_id AS id,
|
||||||
FROM Contacts c
|
NULL::uuid AS user_id,
|
||||||
|
conv.name AS username,
|
||||||
|
conv.last_active,
|
||||||
|
c.conversation_id,
|
||||||
|
conv.conversation_type AS type,
|
||||||
|
m.last_read_message_id
|
||||||
|
FROM Contacts c
|
||||||
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
|
JOIN Conversations conv ON c.conversation_id = conv.conversation_id
|
||||||
JOIN Memberships m ON m.conversation_id = conv.conversation_id -- Added this JOIN
|
JOIN Memberships m
|
||||||
WHERE c.user_id = $1
|
ON m.conversation_id = conv.conversation_id
|
||||||
AND conv.conversation_type = 'group'
|
AND m.user_id = $1
|
||||||
ORDER BY c.conversation_id, conv.last_active DESC
|
WHERE c.user_id = $1
|
||||||
)
|
AND conv.conversation_type = 'group'
|
||||||
|
)
|
||||||
SELECT * FROM DirectContacts
|
SELECT * FROM DirectContacts
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT * FROM GroupContacts
|
SELECT * FROM GroupContacts
|
||||||
ORDER BY last_active DESC;
|
ORDER BY last_active DESC NULLS LAST;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const contactsResult = await client.query(contactsQuery, [user_id]);
|
const contactsResult = await client.query(contactsQuery, [user_id]);
|
||||||
|
|
||||||
// Map the results to include the latest message and message_id
|
// Map the results to include the latest message info
|
||||||
const contacts = await Promise.all(
|
const contacts = await Promise.all(
|
||||||
contactsResult.rows.map(async (row) => {
|
contactsResult.rows.map(async (row) => {
|
||||||
const latestMessage = await getLatestMessage(row.conversation_id);
|
const latestMessage = await getLatestMessage(row.conversation_id);
|
||||||
|
|||||||
Reference in New Issue
Block a user