diff --git a/backend/socket.js b/backend/socket.js index 2d576ca..045d7b0 100644 --- a/backend/socket.js +++ b/backend/socket.js @@ -102,17 +102,17 @@ function initializeSocket(server) { // Contacts socket socket.on('contacts', async (contactUsername) => { const username = socket.user.username; - + const status = 'unread'; // Update contact list in db try { const query = ` - INSERT INTO contacts (username, contact) - SELECT $1, $2 + INSERT INTO contacts (username, contact, status) + SELECT $1, $2, $3 WHERE NOT EXISTS ( SELECT 1 FROM contacts WHERE username = $1 AND contact = $2 ) - `; - await db.query(query, [username, contactUsername]); + `; + await db.query(query, [username, contactUsername, status]); } catch (err) { console.error('Failed to update contacts ', err) socket.emit('socket error', 'Failed to update contacts (server error)') @@ -120,10 +120,10 @@ function initializeSocket(server) { // Get contact list from db try { const query = (` - SELECT contact, username + SELECT contact, username, status FROM contacts WHERE username = $1 - `); + `); const result = await db.query(query, [username]); io.to(username).emit('contacts', result.rows); @@ -137,7 +137,7 @@ function initializeSocket(server) { const username = socket.user.username; try { const query = (` - SELECT contact, username + SELECT contact, username, status FROM contacts WHERE username = $1 `); @@ -152,14 +152,40 @@ function initializeSocket(server) { socket.on('delete contact', async (contactUsername) => { const username = socket.user.username; try { - const query = (' DELETE FROM contacts WHERE (username = $1 AND contact = $2)'); + const query = ('DELETE FROM contacts WHERE (username = $1 AND contact = $2)'); await db.query(query, [username, contactUsername]); - socket.emit('delete contacts', 'ok'); + } catch(err) { console.error('Failed to remove contact from db'); io.to(username).emit('socket error', 'Failed to remove contact (server error)'); } }) + + socket.on('status', async (username) => { + const userUsername = socket.user.username; + const status = 'unread'; + try { + const query = ( + 'UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3' + ); + await db.query(query, [status, userUsername, username]); + io.to(userUsername).emit('status', username); + } catch(err) { + console.error('Failed to update unread status:', err); + } + }) + + socket.on('read', async(contactUsername) => { + const userUsername = socket.user.username; + const status = 'read'; + try { + const query = ('UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3'); + await db.query(query, [status, userUsername, contactUsername]); + io.to(userUsername).emit('status', contactUsername); + } catch(err) { + console.error('Failed to update unread status:', err) + } + }) // disconnect event socket.on('disconnect', () => { return "Disconnected"; diff --git a/frontend/js/chat.js b/frontend/js/chat.js index e619e17..5c50557 100644 --- a/frontend/js/chat.js +++ b/frontend/js/chat.js @@ -74,6 +74,13 @@ async function initializeSocket() { console.log('Received message:', msg); const { username, content, recipient } = msg; + // if(username !== currentRecipient && username !== currentUsername) { + // socket.emit('status', username); + // console.log('new message from ', username); + // const unreadIndicator = document.querySelector('.unread-indicator'); + // unreadIndicator.style.display = 'inline'; + // } + // username is sender username!!! // Display messages @@ -87,13 +94,22 @@ async function initializeSocket() { // Add and display contact if (recipient !== currentRecipient && username !== currentUsername) { // Check if the contact has already been added + socket.emit('status', username); + console.log('new message from ', username); + // const unreadIndicator = document.querySelector('.unread-indicator'); + // unreadIndicator.style.display = 'inline'; + const contactItem = Array.from(contacts.children).find( + item => item.querySelector('.contact-username').textContent === username + ); + if (contactItem) { + const unreadIndicator = contactItem.querySelector('.unread-indicator'); + unreadIndicator.style.display = 'inline'; + unreadIndicator.textContent = '•'; // or any other indicator you prefer + } if (!addedContacts.has(username)) { - try{ - socket.emit('contacts', username); - } catch (err) { - messageBox.innerHTML = 'Failed to fetch contact api'; - console.log('Failed to add contact', err); - } + socket.emit('contacts', username); + console.log('added contact') + // Add the username to the Set of contacts addedContacts.add(username); } @@ -104,12 +120,12 @@ async function initializeSocket() { socket.on('contacts', (contacts) => { console.log('Received contacts: ', contacts); // Clear contact to avoid duplicates because backend send all user contacts and add to existing so it just clear previous and display data from db + document.getElementById('contacts').innerHTML = ""; for(const contact of contacts) { - addContact(contact.contact, socket) + addContact(contact.contact, contact.status, socket) } }) - // If not previous messages found on backend socket.on('no messages', () => { console.log('No previous messages found'); @@ -130,7 +146,7 @@ async function initializeSocket() { localStorage.setItem('currentRecipient', currentRecipient); messages.innerHTML = ''; console.log('Requesting messages for recipient:', currentRecipient); - + socket.emit('contacts', currentRecipient); // Request previous messages after form submit socket.emit('get messages', currentRecipient); } @@ -160,9 +176,10 @@ async function initializeSocket() { }); // Create contact li and create remove contact button - function addContact(contactUsername, socket) { + function addContact(contactUsername, status, socket) { const contact = document.createElement('li'); contact.className = 'contact-item'; + const usernameSpan = document.createElement('span'); usernameSpan.textContent = contactUsername; usernameSpan.className = 'contact-username'; @@ -170,21 +187,37 @@ async function initializeSocket() { const removeButton = document.createElement('button'); removeButton.textContent = 'X'; removeButton.className = 'remove-contact'; + + const unreadIndicator = document.createElement('span'); + unreadIndicator.className = 'unread-indicator'; + + if(status === "unread") { + unreadIndicator.style.display = 'inline'; + } else { + unreadIndicator.style.display = 'none'; + } + unreadIndicator.textContent = '•'; + removeButton.addEventListener('click', (e) => { e.stopPropagation(); socket.emit('delete contact', contactUsername); + socket.emit('read', contactUsername); contacts.removeChild(contact); addedContacts.delete(contactUsername); }); contact.appendChild(usernameSpan); contact.appendChild(removeButton); + contact.appendChild(unreadIndicator); contact.addEventListener('click', () => { currentRecipient = contactUsername; recipientInput.value = contactUsername; localStorage.setItem('currentRecipient', currentRecipient); socket.emit('get messages', contactUsername); + socket.emit('read', contactUsername); + unreadIndicator.style.display = 'none'; + input.focus(); }); contacts.appendChild(contact); diff --git a/frontend/routes/chat.html b/frontend/routes/chat.html index 1006355..8e499db 100644 --- a/frontend/routes/chat.html +++ b/frontend/routes/chat.html @@ -20,7 +20,7 @@