Files
web-chat/frontend/js/chat.js

239 lines
8.6 KiB
JavaScript

const form = document.getElementById('form');
const input = document.getElementById('input');
const recipientForm = document.getElementById('recipientForm');
const recipientInput = document.getElementById('recipient');
const messages = document.getElementById('messages');
const messageBox = document.getElementById('messageBox');
const contacts = document.getElementById('contacts');
let currentRecipient = null;
window.onload = () => {
initializeRecipient();
if(!recipientInput.value){
recipientInput.focus();
}
}
function initializeRecipient() {
const savedRecipient = localStorage.getItem('currentRecipient');
if (savedRecipient) {
currentRecipient = savedRecipient;
recipientInput.value = savedRecipient;
input.focus();
return currentRecipient;
}
}
async function getToken() {
try {
const response = await fetch('/auth/token');
if (!response.ok) {
console.log('Network response was not ok');
return null;
}
return await response.text();
} catch (error) {
console.error('There was a problem with token fetching', error);
return null;
}
}
async function initializeSocket() {
const token = await getToken();
if (!token) {
console.error('Not logged in');
return;
}
const socket = io({
auth: {
token: token,
serverOffset: 0
}
});
socket.on('connect', () => {
console.log('Connected to server');
const initialRecipient = initializeRecipient();
socket.emit('get contacts')
socket.emit('get messages', initialRecipient);
});
// Socket for displaying current username
let currentUsername = null;
socket.on('username', (username) => {
currentUsername = username;
document.getElementById('input').placeholder = `Send message as: ${username}`;
})
// Set for not displaying same contact multiple times
const addedContacts = new Set();
// Main socket connection, it is displaying all messages in real time
socket.on('chat message', async (msg) => {
console.log('Received message:', msg);
const { username, content, recipient } = msg;
// username is sender username!!!
// Display messages
if (recipient === currentRecipient || username === currentRecipient) {
const item = document.createElement('li');
item.textContent = `${username}: ${content}`;
messages.appendChild(item);
messages.scrollTop = messages.scrollHeight;
}
// 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, "recipient: ", recipient, 'currentRecipient: ', currentRecipient );
// Notify about unread message
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';
}
// Avoid duplicating contacts
if (!addedContacts.has(username)) {
socket.emit('contacts', { contact: username, status: "unread" });
console.log('added contact')
// Add the username to the Set of contacts
addedContacts.add(username);
}
}
});
// Contacts handler
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, contact.status, socket)
}
})
// If not previous messages found on backend
socket.on('no messages', () => {
console.log('No previous messages found');
messages.innerHTML = '<p>No messages found</p>';
});
// Error messages from backend
socket.on('socket error', (msg) => {
console.log('There was an error: ', msg)
messageBox.innerHTML = msg;
})
// Recipient form, it request previous messages after submitting
recipientForm.addEventListener('submit', (e) => {
e.preventDefault();
if (recipientInput.value) {
currentRecipient = recipientInput.value;
localStorage.setItem('currentRecipient', currentRecipient);
messages.innerHTML = '';
console.log('Requesting messages for recipient:', currentRecipient);
socket.emit('contacts', { contact: currentRecipient, status: "read"});
// Request previous messages after form submit
socket.emit('get messages', currentRecipient);
}
});
// Form for sending messages
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value && currentRecipient) {
console.log('Sending message:', input.value, 'to', currentRecipient);
socket.emit('chat message', { content: input.value, recipient: currentRecipient });
messages.scrollTop = messages.scrollHeight;
input.value = '';
}
});
// Socket connection for getting previous messages
socket.on('messages history', (messagesHistory) => {
console.log('Received messages history:', messagesHistory);
messages.innerHTML = ''; // Clear previous messages
for (const message of messagesHistory) {
const item = document.createElement('li');
item.textContent = `${message.username}: ${message.content}`;
messages.appendChild(item);
}
messages.scrollTop = messages.scrollHeight;
});
// Create contact li and create remove contact button
function addContact(contactUsername, status, socket) {
const contact = document.createElement('li');
contact.className = 'contact-item';
contact.dataset.username = contactUsername;
contact.dataset.unread = status === "unread" ? "true" : "false";
const leftWrapper = document.createElement('div');
leftWrapper.className = 'left-wrapper';
const unreadIndicator = document.createElement('span');
unreadIndicator.className = 'unread-indicator';
unreadIndicator.textContent = '•';
const usernameSpan = document.createElement('span');
usernameSpan.textContent = contactUsername;
usernameSpan.className = 'contact-username';
const removeButton = document.createElement('button');
removeButton.textContent = 'X';
removeButton.className = 'remove-contact';
if(status === "unread") {
unreadIndicator.style.display = 'inline';
} else {
unreadIndicator.style.display = 'none';
}
removeButton.addEventListener('click', (e) => {
e.stopPropagation();
socket.emit('delete contact', contactUsername);
socket.emit('read', contactUsername);
contacts.removeChild(contact);
addedContacts.delete(contactUsername);
});
leftWrapper.appendChild(unreadIndicator);
contact.appendChild(usernameSpan);
contact.appendChild(leftWrapper);
contact.appendChild(removeButton);
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';
contact.dataset.unread = "false";
sortContacts();
input.focus();
});
contacts.appendChild(contact);
sortContacts();
}
function sortContacts() {
const contactsList = Array.from(contacts.children);
contactsList.sort((a, b) => {
if (a.dataset.unread === "true" && b.dataset.unread === "false") return -1;
if (a.dataset.unread === "false" && b.dataset.unread === "true") return 1;
return a.dataset.username.localeCompare(b.dataset.username);
});
contactsList.forEach(contact => contacts.appendChild(contact));
}
}
initializeSocket();