nie wiem co, cos zepsulem z nieprzeczytanymi wiadomosci i nie wiem jak naprawic
This commit is contained in:
@@ -27,7 +27,6 @@ function MessagesArea() {
|
|||||||
const previousMessagesLength = useRef(messages.length);
|
const previousMessagesLength = useRef(messages.length);
|
||||||
const isFocused = useWindowFocus();
|
const isFocused = useWindowFocus();
|
||||||
const previousTitle = useRef(document.title);
|
const previousTitle = useRef(document.title);
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
if (container && shouldScrollToBottom) {
|
if (container && shouldScrollToBottom) {
|
||||||
@@ -132,6 +131,7 @@ function MessagesArea() {
|
|||||||
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().toString(),
|
||||||
|
last_read_message_id: prevContacts[0]?.last_message_id || null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ function MessagesArea() {
|
|||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
setContactsList((prevContacts) => {
|
setContactsList((prevContacts) => {
|
||||||
return prevContacts.map((contact) =>
|
return prevContacts.map((contact) =>
|
||||||
contact.conversation_id === currentContact?.conversation_id
|
contact?.conversation_id === currentContact?.conversation_id
|
||||||
? {
|
? {
|
||||||
...contact,
|
...contact,
|
||||||
read: true,
|
read: true,
|
||||||
@@ -224,6 +224,19 @@ function MessagesArea() {
|
|||||||
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;
|
||||||
@@ -241,6 +254,8 @@ 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}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ function AddGroupMember() {
|
|||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<button className="p-2 hover:bg-zinc-800 rounded-lg">
|
<button className="p-2 hover:bg-zinc-800 rounded-lg" title="Add member">
|
||||||
<UserRoundPlus />
|
<UserRoundPlus />
|
||||||
</button>
|
</button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ function CreateGroupButton() {
|
|||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<button className="p-2 hover:bg-zinc-800 rounded-lg">
|
<button
|
||||||
|
className="p-2 hover:bg-zinc-800 rounded-lg"
|
||||||
|
title="Create group"
|
||||||
|
>
|
||||||
<Plus />
|
<Plus />
|
||||||
</button>
|
</button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|||||||
@@ -48,6 +48,22 @@ 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`);
|
||||||
|
|||||||
@@ -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);
|
setCurrentContact({ ...newContact, read: true });
|
||||||
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);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export type ContactsProps = {
|
|||||||
last_message_id: number | null;
|
last_message_id: number | 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ParticipantsProps = {
|
export type ParticipantsProps = {
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ async function createTables() {
|
|||||||
conversation_id UUID NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
conversation_id UUID NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||||
user_id UUID REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
user_id UUID REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||||
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
last_read_message_id INT REFERENCES Messages(message_id) ON DELETE SET NULL,
|
||||||
PRIMARY KEY (conversation_id, user_id)
|
PRIMARY KEY (conversation_id, user_id)
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS idx_memberships_conversation_id ON Memberships (conversation_id);
|
CREATE INDEX IF NOT EXISTS idx_memberships_conversation_id ON Memberships (conversation_id);
|
||||||
@@ -100,7 +101,6 @@ async function createTables() {
|
|||||||
contact_id SERIAL PRIMARY KEY,
|
contact_id SERIAL PRIMARY KEY,
|
||||||
user_id UUID REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
user_id UUID REFERENCES Accounts(user_id) ON DELETE CASCADE,
|
||||||
conversation_id UUID NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
conversation_id UUID NOT NULL REFERENCES Conversations(conversation_id) ON DELETE CASCADE,
|
||||||
read BOOLEAN NOT NULL DEFAULT FALSE,
|
|
||||||
last_active TIMESTAMPTZ DEFAULT NOW(),
|
last_active TIMESTAMPTZ DEFAULT NOW(),
|
||||||
CONSTRAINT unique_contact UNIQUE (user_id, conversation_id)
|
CONSTRAINT unique_contact UNIQUE (user_id, conversation_id)
|
||||||
);
|
);
|
||||||
@@ -237,6 +237,8 @@ async function insertMessage(
|
|||||||
attachmentUrls,
|
attachmentUrls,
|
||||||
]);
|
]);
|
||||||
updateConversationLastActive(conversation_id, senderId);
|
updateConversationLastActive(conversation_id, senderId);
|
||||||
|
updateContactStatus(senderId, conversation_id, result.rows[0].message_id);
|
||||||
|
|
||||||
return result.rows[0];
|
return result.rows[0];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to insert message ", e);
|
console.error("Failed to insert message ", e);
|
||||||
@@ -473,10 +475,10 @@ async function changePassword(username, newPasswordHash) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertContactById(senderId, conversation_id, read) {
|
async function insertContactById(senderId, conversation_id) {
|
||||||
// First check if contact already exists
|
// First check if contact already exists
|
||||||
const checkQuery = `
|
const checkQuery = `
|
||||||
SELECT contact_id, conversation_id, user_id, read, last_active
|
SELECT contact_id, conversation_id, user_id, last_active
|
||||||
FROM Contacts
|
FROM Contacts
|
||||||
WHERE user_id = $1 AND conversation_id = $2
|
WHERE user_id = $1 AND conversation_id = $2
|
||||||
`;
|
`;
|
||||||
@@ -494,16 +496,12 @@ async function insertContactById(senderId, conversation_id, read) {
|
|||||||
|
|
||||||
// If contact doesn't exist, create new one
|
// If contact doesn't exist, create new one
|
||||||
const insertQuery = `
|
const insertQuery = `
|
||||||
INSERT INTO Contacts (user_id, conversation_id, read)
|
INSERT INTO Contacts (user_id, conversation_id)
|
||||||
VALUES($1, $2, $3)
|
VALUES($1, $2)
|
||||||
RETURNING contact_id, conversation_id, user_id, read, last_active
|
RETURNING contact_id, conversation_id, user_id, last_active
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = await client.query(insertQuery, [
|
const result = await client.query(insertQuery, [senderId, conversation_id]);
|
||||||
senderId,
|
|
||||||
conversation_id,
|
|
||||||
read,
|
|
||||||
]);
|
|
||||||
console.log("Insert contact by id:", senderId, conversation_id);
|
console.log("Insert contact by id:", senderId, conversation_id);
|
||||||
return result.rows[0] || null;
|
return result.rows[0] || null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -512,7 +510,7 @@ async function insertContactById(senderId, conversation_id, read) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertContact(initiatorId, receiverId, contactUsername, read) {
|
async function insertContact(initiatorId, receiverId, contactUsername) {
|
||||||
try {
|
try {
|
||||||
let conversation_id;
|
let conversation_id;
|
||||||
|
|
||||||
@@ -625,7 +623,7 @@ async function insertContact(initiatorId, receiverId, contactUsername, read) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert the contact for the initiator
|
// Insert the contact for the initiator
|
||||||
const contact = await insertContactById(initiatorId, conversation_id, read);
|
const contact = await insertContactById(initiatorId, conversation_id);
|
||||||
if (!contact.contact_id) {
|
if (!contact.contact_id) {
|
||||||
console.error("Failed to insert contact by id");
|
console.error("Failed to insert contact by id");
|
||||||
return null;
|
return null;
|
||||||
@@ -642,7 +640,6 @@ async function insertContact(initiatorId, receiverId, contactUsername, read) {
|
|||||||
last_active: contact.last_active,
|
last_active: contact.last_active,
|
||||||
conversation_id: contact.conversation_id,
|
conversation_id: contact.conversation_id,
|
||||||
type: "direct",
|
type: "direct",
|
||||||
read: contact.read,
|
|
||||||
last_message_id: latestMessage.last_message_id,
|
last_message_id: latestMessage.last_message_id,
|
||||||
last_message: latestMessage.last_message,
|
last_message: latestMessage.last_message,
|
||||||
last_message_time: latestMessage.last_message_time,
|
last_message_time: latestMessage.last_message_time,
|
||||||
@@ -717,10 +714,10 @@ async function getContacts(user_id) {
|
|||||||
conv.last_active,
|
conv.last_active,
|
||||||
c.conversation_id,
|
c.conversation_id,
|
||||||
conv.conversation_type AS type,
|
conv.conversation_type AS type,
|
||||||
c.read
|
m.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 = c.conversation_id
|
JOIN Memberships m ON m.conversation_id = conv.conversation_id
|
||||||
JOIN Accounts a ON a.user_id = m.user_id
|
JOIN Accounts a ON a.user_id = m.user_id
|
||||||
WHERE c.user_id = $1
|
WHERE c.user_id = $1
|
||||||
AND conv.conversation_type = 'direct'
|
AND conv.conversation_type = 'direct'
|
||||||
@@ -735,9 +732,10 @@ async function getContacts(user_id) {
|
|||||||
conv.last_active,
|
conv.last_active,
|
||||||
c.conversation_id,
|
c.conversation_id,
|
||||||
conv.conversation_type AS type,
|
conv.conversation_type AS type,
|
||||||
c.read
|
m.last_read_message_id -- We need to add Memberships join here too
|
||||||
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 -- Added this JOIN
|
||||||
WHERE c.user_id = $1
|
WHERE c.user_id = $1
|
||||||
AND conv.conversation_type = 'group'
|
AND conv.conversation_type = 'group'
|
||||||
ORDER BY c.conversation_id, conv.last_active DESC
|
ORDER BY c.conversation_id, conv.last_active DESC
|
||||||
@@ -762,15 +760,14 @@ async function getContacts(user_id) {
|
|||||||
last_active: row.last_active,
|
last_active: row.last_active,
|
||||||
conversation_id: row.conversation_id,
|
conversation_id: row.conversation_id,
|
||||||
type: row.type,
|
type: row.type,
|
||||||
read: row.read,
|
last_read_message_id: row.last_read_message_id,
|
||||||
last_message_id: latestMessage.message_id,
|
last_message_id: latestMessage.last_message_id,
|
||||||
last_message: latestMessage.last_message,
|
last_message: latestMessage.last_message,
|
||||||
last_message_time: latestMessage.last_message_time,
|
last_message_time: latestMessage.last_message_time,
|
||||||
last_message_sender: latestMessage.last_message_sender,
|
last_message_sender: latestMessage.last_message_sender,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return contacts;
|
return contacts;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to get contacts:", error);
|
console.error("Failed to get contacts:", error);
|
||||||
@@ -864,23 +861,48 @@ async function deleteContact(user_id, conversation_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateContactStatus(user_id, conversation_id, read) {
|
async function updateContactStatus(
|
||||||
|
user_id,
|
||||||
|
conversation_id,
|
||||||
|
last_read_message_id,
|
||||||
|
) {
|
||||||
const query = `
|
const query = `
|
||||||
UPDATE Contacts SET read = $1
|
UPDATE Memberships
|
||||||
|
SET last_read_message_id = $1
|
||||||
WHERE user_id = $2
|
WHERE user_id = $2
|
||||||
AND conversation_id = $3;
|
AND conversation_id = $3;
|
||||||
`;
|
`;
|
||||||
try {
|
try {
|
||||||
await client.query(query, [read, user_id, conversation_id]);
|
await client.query(query, [last_read_message_id, user_id, conversation_id]);
|
||||||
// await updateContactLastActive(user_id, conversation_id);
|
|
||||||
console.log(
|
console.log(
|
||||||
`Successfully updated contact status, user_id: ${user_id}, conversation_id: ${conversation_id}, read: ${read}: `,
|
`Successfully updated contact status, user_id: ${user_id}, conversation_id: ${conversation_id}, last_read_message_id: ${last_read_message_id}`,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to update contact status ", e);
|
console.error("Failed to update contact status ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getLastReadMessageId(user_id, conversation_id) {
|
||||||
|
const query = `
|
||||||
|
SELECT last_read_message_id
|
||||||
|
FROM Memberships
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND conversation_id = $2;
|
||||||
|
`;
|
||||||
|
try {
|
||||||
|
const result = await client.query(query, [user_id, conversation_id]);
|
||||||
|
if (result.rows.length > 0) {
|
||||||
|
return result.rows[0].last_read_message_id;
|
||||||
|
} else {
|
||||||
|
console.log("No read message found for user in conversation");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to get last read message ID ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function updateContactLastActive(user_id, contact_id) {
|
async function updateContactLastActive(user_id, contact_id) {
|
||||||
const query = `
|
const query = `
|
||||||
UPDATE Contacts
|
UPDATE Contacts
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ app.put(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const read = req.body.status;
|
const read = req.body.status;
|
||||||
await updateContactStatus(req.user.user_id, conversation_id, read);
|
//await updateContactStatus(req.user.user_id, conversation_id, read);
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.status(200)
|
.status(200)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const {
|
|||||||
isAdmin,
|
isAdmin,
|
||||||
addAdministrator,
|
addAdministrator,
|
||||||
removeAdministrator,
|
removeAdministrator,
|
||||||
|
updateContactStatus,
|
||||||
} = require("../db/db");
|
} = require("../db/db");
|
||||||
const { isValidUsername } = require("../utils/filter");
|
const { isValidUsername } = require("../utils/filter");
|
||||||
const { verifyJwtToken } = require("../auth/jwt");
|
const { verifyJwtToken } = require("../auth/jwt");
|
||||||
@@ -342,6 +343,15 @@ function initializeSocket(io) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("message read", async (msg) => {
|
||||||
|
const { conversation_id, message_id } = msg;
|
||||||
|
if (!conversation_id || !message_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.error("MESSGE READ: ", conversation_id, message_id);
|
||||||
|
await updateContactStatus(socket.user_id, conversation_id, message_id);
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("disconnect", (reason) => {
|
socket.on("disconnect", (reason) => {
|
||||||
console.log("(socket)", socket.id, " disconnected due to: ", reason);
|
console.log("(socket)", socket.id, " disconnected due to: ", reason);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user