let osichatSocket; let isOpen = false; let chatLoaded = false; let newMessageCount = 0; let atBottom = true; function scrollBottom() { const conversationContainer = document.getElementById('conversation'); if (conversationContainer) { conversationContainer.scrollTo({ top: conversationContainer.scrollHeight, behavior: 'smooth' }); } } function isScrolledToBottom(element) { return element && (element.scrollHeight - element.scrollTop <= element.clientHeight + 200); } function setupScrollEventListener() { const conversationContainer = document.getElementById('conversation'); if (conversationContainer) { conversationContainer.addEventListener('scroll', () => { if (isScrolledToBottom(conversationContainer)) { if (!atBottom) { hideNewMessageNotification(); atBottom = true; // Update flag when user scrolls to the bottom } } else { atBottom = false; // Update flag if user is not at the bottom } }); } } function showNewMessageNotification(count) { const newMessagesPopMessage = document.getElementById('newMessagesPopMessage'); const newMessagesCounter = document.getElementById('newMessagesCounter'); if (newMessagesPopMessage && newMessagesCounter) { newMessagesCounter.textContent = count; newMessagesPopMessage.classList.remove('hidden'); } } function hideNewMessageNotification() { const newMessagesPopMessage = document.getElementById('newMessagesPopMessage'); if (newMessagesPopMessage) { newMessagesPopMessage.classList.add('hidden'); newMessageCount = 0; const newMessagesCounter = document.getElementById('newMessagesCounter'); if (newMessagesCounter) { newMessagesCounter.textContent = newMessageCount; } scrollBottom() } } function newMessageNotification() { const notificationSound = document.getElementById('notification-sound'); notificationSound.play(); const conversationContainer = document.getElementById('conversation'); if (!isScrolledToBottom(conversationContainer)) { let count = newMessageCount + 1; newMessageCount = count; showNewMessageNotification(count); } else { scrollBottom(); } } // FUNCTION TO FETCH THE SESSION ID async function fetchSessionID() { let session_id = 'Unknown'; while (session_id === 'Unknown') { try { const response = await fetch(`${protocol}://${ositcomDomain}/get-client-session/`); const data = await response.json(); if (data.session_id) { session_id = data.session_id; } } catch (error) { console.error('Error fetching session ID:', error); } } return session_id; } // FUNCTIONS TO SHOW & HIDE THE LOADER function showLoader() { const osichatLoader = document.getElementById('osichatLoader'); if (osichatLoader) { osichatLoader.classList.remove('hidden'); } } function hideLoader() { const osichatLoader = document.getElementById('osichatLoader'); if (osichatLoader) { osichatLoader.classList.add('hidden'); } } // FUNCTION TO APPEND THE TEXTAREA SCRIPT function appendTextAreaScript(domain, chatDiv) { const textareaScript = document.createElement('script'); textareaScript.type = 'text/javascript'; textareaScript.src = `${protocol}://${domain}/static/js/osichat/textarea.js`; chatDiv.appendChild(textareaScript); } // FUNCTION TO HANDLE FORM SUBMISSION function handleFormSubmission(form, eventType, osichatSocket) { form.addEventListener('submit', function (event) { event.preventDefault(); const formData = new FormData(form); const eventMessage = { 'event_type': eventType }; formData.forEach((value, key) => { eventMessage[key] = value; }); if (eventType === 'start_conversation') { showLoader(); } osichatSocket.send(JSON.stringify(eventMessage)); form.reset(); }); } // FUNCTION TO HANDLE LOAD CHAT EVENT function handleLoadChatEvent(data, osichatSocket) { chatLoaded = true; hideLoader(); let chatDiv = document.getElementById('roomContainer'); // CASE WHERE WIDGET IS ALREADY LOADED, DISPLAY THE CHAT PAGES(START/CONVERSATION) IN ROOM CONTAINER if (!chatDiv) { chatDiv = document.getElementById('osichat'); // CASE WHERE WIDGET IS NOT LOADED, DISPLAY THE WHOLE CHATWIDGET IN OSICHAT } chatDiv.innerHTML = data.html; scrollBottom(); if (isOpen) { // If chat widget isOpen mark all messages as read by guest else just return number of unread messages osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'open' })); } else { osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'closed' })); } if (!document.querySelector(`script[src="${protocol}://${osinaDomain}/static/js/osichat/chat-toggle.js"]`)) { const script = document.createElement('script'); script.type = 'text/javascript'; script.src = `${protocol}://${osinaDomain}/static/js/osichat/chat-toggle.js`; chatDiv.appendChild(script); } const startChatContainer = document.getElementById('startChat'); //Case where returned is start-conversation.html if (startChatContainer) { handleFormSubmission(startChatContainer, 'start_conversation', osichatSocket); } const sendMessageContainer = document.getElementById('sendMessage'); //Case where returned is chat-room.html if (sendMessageContainer) { appendTextAreaScript(osinaDomain, chatDiv); handleFormSubmission(sendMessageContainer, 'send_message', osichatSocket); const uploadScript = document.createElement('script'); uploadScript.type = 'text/javascript'; uploadScript.src = `${protocol}://${osinaDomain}/static/js/osichat/upload-file.js`; chatDiv.appendChild(uploadScript); const endChatScript = document.createElement('script'); endChatScript.type = 'text/javascript'; endChatScript.src = `${protocol}://${osinaDomain}/static/js/osichat/end-chat.js`; chatDiv.appendChild(endChatScript); const endChatButton = document.getElementById('endChat'); endChatButton.classList.remove('hidden') } const sendReviewContainer = document.getElementById('reviewContainer'); //Case where returned is ended-chat.html if (sendReviewContainer) { const sendReviewScript = document.createElement('script'); sendReviewScript.type = 'text/javascript'; sendReviewScript.src = `${protocol}://${osinaDomain}/static/js/osichat/send-review.js`; chatDiv.appendChild(sendReviewScript); } } // FUNCTION TO INITIALIZE WEB SOCKET CONNECTION async function initializeChatWebSocket() { const session_id = await fetchSessionID(); let osichatSocketUrl = `${wsScheme}://${osinaDomain}/ws/osichat/${session_id}/`; osichatSocket = new WebSocket(osichatSocketUrl); osichatSocket.onopen = () => { if(!chatLoaded){ osichatSocket.send(JSON.stringify({ 'event_type': 'load_chat', 'client_type': 'website_guest', 'reconnecting': 'False'})); }else{ osichatSocket.send(JSON.stringify({ 'event_type': 'load_chat', 'client_type': 'website_guest', 'reconnecting': 'True'})); } }; osichatSocket.onmessage = function (e) { const data = JSON.parse(e.data); const typingDiv = document.getElementById('typing'); const messagesDiv = document.getElementById('messages'); switch (data.event_type) { case 'load_chat': handleLoadChatEvent(data, osichatSocket); break; case 'start_conversation': handleLoadChatEvent(data, osichatSocket); break; case 'typing': if(!typingDiv && data.user){ messagesDiv.insertAdjacentHTML('beforeend', data.html); } break; case 'stopped_typing': if (typingDiv) { typingDiv.remove(); } break; case 'send_message': if (isOpen) { // If chat widget isOpen (declared in chat-toggle.js) mark all messages as read by guest else just return number of unread messages osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'open' })); } else { osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'closed' })); } messagesDiv.insertAdjacentHTML('beforeend', data.html); const newMessagesPopMessage = document.getElementById('newMessagesPopMessage'); newMessagesPopMessage.addEventListener('click', hideNewMessageNotification); if (data.user) { // If it is sent by an Osina user play a notification sound for the guest if (typingDiv) { typingDiv.remove(); } newMessageNotification(); setupScrollEventListener(); } break; case 'uploaded_file': if (isOpen) { osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'open' })); } else { osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'closed' })); } const uploadingDiv = document.getElementById(`uploading-${data.file_name}`); if (uploadingDiv) { uploadingDiv.outerHTML = data.html; if (!data.user) { scrollBottom(); } else { newMessageNotification(); } } else{ document.getElementById('messages').insertAdjacentHTML('beforeend', data.html); if (!data.user) { scrollBottom(); } else { newMessageNotification(); } } break; case 'update_read_messages': const unreadMessages = document.getElementById(`unreadMessages`); if (!isOpen) { unreadMessages.classList.remove('hidden'); unreadMessages.innerHTML = data.html; const script = document.createElement('script'); script.src = `${protocol}://${osinaDomain}/static/js/osichat/chat-toggle.js`; document.body.appendChild(script); } else { unreadMessages.classList.add('hidden'); } break; case 'ended_chat': const currentChat = document.getElementById(`roomContainer`); if (currentChat) { currentChat.innerHTML = data.html; scrollBottom(); } document.getElementById(`endChatConfirmationContainer`).classList.add('hidden'); document.getElementById(`endChat`).classList.add('hidden'); const sendReviewScript = document.createElement('script'); sendReviewScript.type = 'text/javascript'; sendReviewScript.src = `${protocol}://${osinaDomain}/static/js/osichat/send-review.js`; currentChat.appendChild(sendReviewScript); break; case 'submit_review': const submitReview = document.getElementById(`reviewContainer`); if (submitReview) { submitReview.innerHTML = data.html; } const reviewScript = document.createElement('script'); reviewScript.type = 'text/javascript'; reviewScript.src = `${protocol}://${osinaDomain}/static/js/osichat/send-review.js`; submitReview.appendChild(reviewScript); break; default: console.log('Unknown event type:', data.event_type); } }; osichatSocket.onclose = () => { showLoader(); setTimeout(() => { console.log('Attempting to reconnect to WebSocket...'); initializeChatWebSocket(); }, 2000); }; osichatSocket.onerror = (error) => { console.log('WebSocket error:', error); showLoader(); }; } window.addEventListener('offline', () => { showLoader(); if (osichatSocket) { osichatSocket.close(); } }); // INITIALIZE CHAT WEB SOCKET initializeChatWebSocket();