1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-06-21 09:18:23 +02:00

Store what messages are read

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello
2024-04-28 23:25:15 +02:00
parent 8f3929875f
commit 1a641cb2d7
6 changed files with 213 additions and 58 deletions

View File

@ -70,29 +70,8 @@ function setChannels(new_channels) {
categoryLists[category].parentElement.classList.add('d-none')
}
for (let channel of new_channels) {
channels[channel['id']] = channel
if (!messages[channel['id']])
messages[channel['id']] = new Map()
let categoryList = categoryLists[channel['category']]
categoryList.parentElement.classList.remove('d-none')
let navItem = document.createElement('li')
navItem.classList.add('list-group-item')
navItem.id = `tab-channel-${channel['id']}`
navItem.setAttribute('data-bs-dismiss', 'offcanvas')
navItem.onclick = () => selectChannel(channel['id'])
categoryList.appendChild(navItem)
let channelButton = document.createElement('button')
channelButton.classList.add('nav-link')
channelButton.type = 'button'
channelButton.innerText = channel['name']
navItem.appendChild(channelButton)
fetchMessages(channel['id'])
}
for (let channel of new_channels)
addChannel(channel, categoryLists)
if (new_channels && (!selected_channel_id || !channels[selected_channel_id])) {
if (window.location.hash) {
@ -107,6 +86,38 @@ function setChannels(new_channels) {
}
}
async function addChannel(channel, categoryLists) {
channels[channel['id']] = channel
if (!messages[channel['id']])
messages[channel['id']] = new Map()
let categoryList = categoryLists[channel['category']]
categoryList.parentElement.classList.remove('d-none')
let navItem = document.createElement('li')
navItem.classList.add('list-group-item')
navItem.id = `tab-channel-${channel['id']}`
navItem.setAttribute('data-bs-dismiss', 'offcanvas')
navItem.onclick = () => selectChannel(channel['id'])
categoryList.appendChild(navItem)
let channelButton = document.createElement('button')
channelButton.classList.add('nav-link')
channelButton.type = 'button'
channelButton.innerText = channel['name']
navItem.appendChild(channelButton)
let unreadBadge = document.createElement('span')
unreadBadge.classList.add('badge', 'rounded-pill', 'text-bg-light', 'ms-2')
unreadBadge.id = `unread-messages-${channel['id']}`
unreadBadge.innerText = channel.unread_messages || 0
if (!channel.unread_messages)
unreadBadge.classList.add('d-none')
channelButton.appendChild(unreadBadge)
fetchMessages(channel['id'])
}
function receiveMessage(message) {
let scrollableContent = document.getElementById('chat-messages')
let isScrolledToBottom = scrollableContent.scrollHeight - scrollableContent.clientHeight <= scrollableContent.scrollTop + 1
@ -165,6 +176,32 @@ function receiveFetchedMessages(data) {
redrawMessages()
}
function markMessageAsRead(data) {
for (let message of data['messages']) {
let stored_message = messages[message['channel_id']].get(message['id'])
if (stored_message)
stored_message['read'] = true
}
redrawMessages()
updateUnreadBadges(data['unread_messages'])
}
function updateUnreadBadges(unreadMessages) {
console.log(unreadMessages)
for (let channel of Object.values(channels)) {
let unreadMessagesChannel = unreadMessages[channel['id']] || 0
console.log(channel, unreadMessagesChannel)
channel.unread_messages = unreadMessagesChannel
let unreadBadge = document.getElementById(`unread-messages-${channel['id']}`)
unreadBadge.innerText = unreadMessagesChannel
if (unreadMessagesChannel)
unreadBadge.classList.remove('d-none')
else
unreadBadge.classList.add('d-none')
}
}
function startPrivateChat(data) {
let channel = data['channel']
if (!channel) {
@ -194,6 +231,8 @@ function redrawMessages() {
let newTimestamp = new Date(message['timestamp'])
if ((newTimestamp - lastTimestamp) / 1000 < 60 * 10) {
let messageContentDiv = document.createElement('div')
messageContentDiv.classList.add('message')
messageContentDiv.setAttribute('data-message-id', message['id'])
lastContentDiv.appendChild(messageContentDiv)
let messageContentSpan = document.createElement('span')
messageContentSpan.innerText = message['content']
@ -227,6 +266,8 @@ function redrawMessages() {
messageElement.appendChild(contentDiv)
let messageContentDiv = document.createElement('div')
messageContentDiv.classList.add('message')
messageContentDiv.setAttribute('data-message-id', message['id'])
contentDiv.appendChild(messageContentDiv)
let messageContentSpan = document.createElement('span')
messageContentSpan.innerText = message['content']
@ -243,6 +284,8 @@ function redrawMessages() {
fetchMoreButton.classList.add('d-none')
else
fetchMoreButton.classList.remove('d-none')
messageList.dispatchEvent(new CustomEvent('updatemessages'))
}
function removeAllPopovers() {
@ -370,6 +413,9 @@ document.addEventListener('DOMContentLoaded', () => {
case 'fetch_messages':
receiveFetchedMessages(data)
break
case 'mark_read':
markMessageAsRead(data)
break
case 'start_private_chat':
startPrivateChat(data)
break
@ -435,6 +481,51 @@ document.addEventListener('DOMContentLoaded', () => {
})
}
function setupReadTracker() {
const scrollableContent = document.getElementById('chat-messages')
const messagesList = document.getElementById('message-list')
let markReadBuffer = []
let markReadTimeout = null
scrollableContent.addEventListener('scroll', () => {
if (scrollableContent.clientHeight - scrollableContent.scrollTop === scrollableContent.scrollHeight
&& !document.getElementById('fetch-previous-messages').classList.contains('d-none')) {
// If the user is at the top of the chat, fetch previous messages
fetchPreviousMessages()}
markVisibleMessagesAsRead()
})
messagesList.addEventListener('updatemessages', () => markVisibleMessagesAsRead())
function markVisibleMessagesAsRead() {
let viewport = scrollableContent.getBoundingClientRect()
for (let item of messagesList.querySelectorAll('.message')) {
let message = messages[selected_channel_id].get(parseInt(item.getAttribute('data-message-id')))
if (!message.read) {
let rect = item.getBoundingClientRect()
if (rect.top >= viewport.top && rect.bottom <= viewport.bottom) {
message.read = true
markReadBuffer.push(message['id'])
if (markReadTimeout)
clearTimeout(markReadTimeout)
markReadTimeout = setTimeout(() => {
socket.send(JSON.stringify({
'type': 'mark_read',
'message_ids': markReadBuffer,
}))
markReadBuffer = []
markReadTimeout = null
}, 3000)
}
}
}
}
markVisibleMessagesAsRead()
}
function setupPWAPrompt() {
let deferredPrompt = null
@ -460,5 +551,6 @@ document.addEventListener('DOMContentLoaded', () => {
setupSocket()
setupSwipeOffscreen()
setupReadTracker()
setupPWAPrompt()
})