diff --git a/backend/db.js b/backend/db.js index 8c71563..1273a32 100644 --- a/backend/db.js +++ b/backend/db.js @@ -70,10 +70,9 @@ async function insertUser(username, password){ VALUES ($1, $2) RETURNING *; `; - const values = [username, password]; try { - const signupData = await db.query(query, values); + const signupData = await db.query(query, [username, password]); console.log('Account created:', signupData.rows[0].username); } catch (err) { console.error('Error inserting data:', err.stack); @@ -91,6 +90,7 @@ async function changePassword(username, password) { console.error('Failed to update password') throw err; } + } module.exports = { db , diff --git a/backend/socket.js b/backend/socket.js index aa0d236..0818876 100644 --- a/backend/socket.js +++ b/backend/socket.js @@ -2,6 +2,7 @@ const { Server } = require('socket.io'); const jwt = require('jsonwebtoken'); const jwtSecret = process.env.JWT_SECRET; const { db } = require('./db.js'); +const {json} = require("express"); function initializeSocket(server) { const io = new Server(server, { @@ -70,6 +71,7 @@ function initializeSocket(server) { } } catch (err) { console.error('Error fetching inserted message:', err); + socket.emit('socket error', 'Failed to send message') } }); @@ -94,9 +96,48 @@ function initializeSocket(server) { } } catch (e) { console.error('Error retrieving messages:', e); - socket.emit('socket error', "Error retrieving messages, refresh the page") + socket.emit('socket error', 'Error retrieving messages, refresh the page (server error)') } }); + + // Contacts socket + socket.on('contacts', async (contactUsername) => { + const username = socket.user.username; + // Update contact list in db + try { + const query = ('INSERT INTO contacts (username, contact) VALUES ($1, $2)'); + await db.query(query, [username, contactUsername]); + } catch (err) { + console.error('Failed to update contacts') + socket.emit('socket error', 'Failed to update contacts (server error)') + } + // Get contact list from db + try { + const query = (` + SELECT contact, username + FROM contacts + WHERE username = $1 + `); + const result = await db.query(query, [username]); + console.log(result.rows) + socket.emit('contacts', result.rows); + } catch(err) { + console.error('Failed to get contacts from db'); + socket.emit('socket error', 'Failed to get contacts (server error)'); + } + }) + + socket.on('delete contacts', async (contactUsername) => { + const username = socket.user.username; + try { + 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'); + socket.emit('socket error', 'Failed to remove contact (server error)'); + } + }) // disconnect event socket.on('disconnect', () => { return "Disconnected"; diff --git a/frontend/icons/icon.png b/frontend/icons/icon.png new file mode 100644 index 0000000..d2d02d2 Binary files /dev/null and b/frontend/icons/icon.png differ diff --git a/frontend/js/chat.js b/frontend/js/chat.js index fca671f..9eb86ce 100644 --- a/frontend/js/chat.js +++ b/frontend/js/chat.js @@ -58,6 +58,8 @@ async function initializeSocket() { const initialRecipient = initializeRecipient(); socket.emit('get messages', initialRecipient); }); + + // Socket for displaying current username let currentUsername = null; socket.on('username', (username) => { currentUsername = username; @@ -65,10 +67,10 @@ async function initializeSocket() { }) // Set for not displaying same contact multiple times - const addedContacts = new Set(); + const addedContacts = new Set(); // Main socket connection, it is displaying all messages in real time - socket.on('chat message', (msg) => { + socket.on('chat message', async (msg) => { console.log('Received message:', msg); const { username, content, recipient } = msg; @@ -82,50 +84,30 @@ async function initializeSocket() { messages.scrollTop = messages.scrollHeight; } - // Add and display contact/incoming messages + // Add and display contact if (recipient !== currentRecipient && username !== currentUsername) { // Check if the contact has already been added if (!addedContacts.has(username)) { - addContact(username, socket); - // Add the username to the Set of added contacts + try{ + socket.emit('contacts', username); + } catch (err) { + messageBox.innerHTML = 'Failed to fetch contact api'; + console.log('Failed to add contact', err); + } + // Add the username to the Set of contacts addedContacts.add(username); } } - - function addContact(username, socket) { - const contact = document.createElement('li'); - contact.className = 'contact-item'; - - const usernameSpan = document.createElement('span'); - usernameSpan.textContent = username; - usernameSpan.className = 'contact-username'; - - const removeButton = document.createElement('button'); - removeButton.textContent = 'X'; - removeButton.className = 'remove-contact'; - - contact.appendChild(usernameSpan); - contact.appendChild(removeButton); - - usernameSpan.addEventListener('click', () => { - currentRecipient = username; - recipientInput.value = username; - localStorage.setItem('currentRecipient', currentRecipient); - socket.emit('get messages', username); - }); - - removeButton.addEventListener('click', (e) => { - e.stopPropagation(); - contacts.removeChild(contact); - addedContacts.delete(username); - }); - - contacts.appendChild(contact); - console.log('Created contact:', username); - } - }); + // Contacts handler + socket.on('contacts', (contacts) => { + console.log('contactArray: ', contacts); + for(const contact in contacts) { + addContact(contact, socket); + } + }) + // If not previous messages found on backend socket.on('no messages', () => { console.log('No previous messages found'); @@ -174,7 +156,48 @@ async function initializeSocket() { } messages.scrollTop = messages.scrollHeight; }); + + function addContact(username, socket) { + const contact = document.createElement('li'); + contact.className = 'contact-item'; + + const usernameSpan = document.createElement('span'); + usernameSpan.textContent = username; + usernameSpan.className = 'contact-username'; + + const removeButton = document.createElement('button'); + removeButton.textContent = 'X'; + removeButton.className = 'remove-contact'; + + contact.appendChild(usernameSpan); + contact.appendChild(removeButton); + + usernameSpan.addEventListener('click', () => { + currentRecipient = username; + recipientInput.value = username; + localStorage.setItem('currentRecipient', currentRecipient); + socket.emit('get messages', username); + }); + + removeButton.addEventListener('click', (e) => { + e.stopPropagation(); + socket.emit('delete contact', username); + socket.on('delete contact', (res) => { + if(res === 'ok') { + contacts.removeChild(contact); + addedContacts.delete(username); + } else { + messageBox.innerHTML = 'Failed to remove contact (server error)' + } + }) + + }); + + contacts.appendChild(contact); + console.log('Created contact:', username); + } } + initializeSocket(); diff --git a/frontend/js/settings.js b/frontend/js/settings.js index ffb81cc..73e6bfc 100644 --- a/frontend/js/settings.js +++ b/frontend/js/settings.js @@ -29,7 +29,7 @@ document.getElementById('changePasswordForm').addEventListener('submit', async ( const nPassword = document.getElementById('nPassword').value.trim(); const messageBox = document.getElementById('messageBox'); const jsonData = JSON.stringify({ cPassword, nPassword }); - const response = await fetch('/auth/changepassword', { + const response = await fetch('/auth/changePassword', { method: 'POST', headers: { 'Content-Type': 'application/json' diff --git a/frontend/routes/chat.html b/frontend/routes/chat.html index d1f222e..084a9de 100644 --- a/frontend/routes/chat.html +++ b/frontend/routes/chat.html @@ -6,6 +6,7 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">