diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index 84b10091..5b5967cf 100644 Binary files a/osinaweb/db.sqlite3 and b/osinaweb/db.sqlite3 differ diff --git a/osinaweb/osinacore/__pycache__/consumers.cpython-310.pyc b/osinaweb/osinacore/__pycache__/consumers.cpython-310.pyc index 6ea27c69..499e4fc8 100644 Binary files a/osinaweb/osinacore/__pycache__/consumers.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/consumers.cpython-310.pyc differ diff --git a/osinaweb/osinacore/__pycache__/custom_context.cpython-310.pyc b/osinaweb/osinacore/__pycache__/custom_context.cpython-310.pyc index ad3e57a8..4460b9a9 100644 Binary files a/osinaweb/osinacore/__pycache__/custom_context.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/custom_context.cpython-310.pyc differ diff --git a/osinaweb/osinacore/__pycache__/routing.cpython-310.pyc b/osinaweb/osinacore/__pycache__/routing.cpython-310.pyc index f1d97082..f774f156 100644 Binary files a/osinaweb/osinacore/__pycache__/routing.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/routing.cpython-310.pyc differ diff --git a/osinaweb/osinacore/add/__pycache__/views.cpython-310.pyc b/osinaweb/osinacore/add/__pycache__/views.cpython-310.pyc index 3ea653a0..f94e8501 100644 Binary files a/osinaweb/osinacore/add/__pycache__/views.cpython-310.pyc and b/osinaweb/osinacore/add/__pycache__/views.cpython-310.pyc differ diff --git a/osinaweb/osinacore/add/views.py b/osinaweb/osinacore/add/views.py index 0b26831c..4d6eed31 100644 --- a/osinaweb/osinacore/add/views.py +++ b/osinaweb/osinacore/add/views.py @@ -498,7 +498,7 @@ def add_note_modal(request, project_id=None): def add_daily_report(request): user = request.user today = date.today() - statuses = Status.objects.filter(staff=user.staffprofile, date=today) + statuses = Status.objects.filter(staff=user.staffprofile, date_time__date=today) if request.method == 'POST': text = request.POST.get('text') current_datetime = datetime.now() diff --git a/osinaweb/osinacore/consumers.py b/osinaweb/osinacore/consumers.py index a3387881..d0c0850d 100644 --- a/osinaweb/osinacore/consumers.py +++ b/osinaweb/osinacore/consumers.py @@ -46,7 +46,6 @@ class OnlineUserConsumer(WebsocketConsumer): offline_connections = connections.filter(online=False, last_seen__isnull=False).order_by('-last_seen')[:5] sorted_connections = list(online_connections) + list(offline_connections) online_users_ids = [connection.user.id for connection in online_connections] - online_users_ids = [connection.user.id for connection in online_connections] customer_connections = [] staff_connections = [] for connection in sorted_connections: @@ -96,11 +95,51 @@ class NewStatusConsumer(WebsocketConsumer): ) def new_status_event(self, event): + is_online = Connection.objects.all().filter(user=self.user, online=True) status_id = event['status_id'] status = Status.objects.get(id=status_id) - context = {'status': status, 'new': True} + context = {'status': status, 'new': True, 'is_online': is_online,} html = render_to_string("details_templates/partials/new-status-activity.html", context) self.send(text_data=json.dumps({ 'event_type': 'new_status', 'html': html, })) + + + + +class UpdateStatusesTimeConsumer(WebsocketConsumer): + def connect(self): + self.user = self.scope['user'] + async_to_sync(self.channel_layer.group_add)( + "new_statuses_time_group", + self.channel_name + ) + self.accept() + def disconnect(self, close_code): + async_to_sync(self.channel_layer.group_discard)( + "new_statuses_time_group", + self.channel_name + ) + def receive(self, text_data): + data = json.loads(text_data) + connections = Connection.objects.filter(online=True) + online_users_ids = [connection.user.id for connection in connections] + if data.get('event_type') == 'update_statuses_time': + event = { + 'type': 'modify_status_time_handler', + 'online_users_ids': online_users_ids, + } + async_to_sync(self.channel_layer.group_send)( + "new_statuses_time_group", event + ) + def modify_status_time_handler(self, event): + today = datetime.now().date() + latest_statuses = Status.objects.filter(date_time__date=today).order_by('-id') + context = {'latest_statuses': latest_statuses} + html = render_to_string("details_templates/partials/recent-activities.html", context) + self.send(text_data=json.dumps({ + 'event_type': 'update_statuses_time', + 'html': html, + 'online_users_ids': event.get('online_users_ids', []) + })) diff --git a/osinaweb/osinacore/routing.py b/osinaweb/osinacore/routing.py index e28f87b4..efaa935c 100644 --- a/osinaweb/osinacore/routing.py +++ b/osinaweb/osinacore/routing.py @@ -4,6 +4,7 @@ from .consumers import * websocket_urlpatterns = [ path("ws/online-users/", OnlineUserConsumer.as_asgi()), path("ws/new-statuses/", NewStatusConsumer.as_asgi()), + path("ws/update-statuses-time/", UpdateStatusesTimeConsumer.as_asgi()), diff --git a/osinaweb/osinacore/templates/details_templates/partials/new-status-activity.html b/osinaweb/osinacore/templates/details_templates/partials/new-status-activity.html index 32a8f0c9..53e97501 100644 --- a/osinaweb/osinacore/templates/details_templates/partials/new-status-activity.html +++ b/osinaweb/osinacore/templates/details_templates/partials/new-status-activity.html @@ -124,8 +124,19 @@ -
-
+ + + +
+
@@ -136,10 +147,10 @@
+ class="w-[12px] h-[12px] absolute rounded-full bg-green-600 bottom-0 right-0 border-2 border-white {% if not is_online %} hidden {% endif %}">
+ class="w-[12px] h-[12px] absolute rounded-full bg-red-500 bottom-0 right-0 border-2 border-white {% if is_online %} hidden {% endif %}">
@@ -148,7 +159,7 @@ {{status.staff.user.last_name}} {% if status.time_ago == '0min ago' %}

Just Now

- {%else %} + {% else %}

{{ status.time_ago}}

{%endif%}
@@ -192,12 +203,3 @@
- diff --git a/osinaweb/osinacore/templates/index.html b/osinaweb/osinacore/templates/index.html index 0f416a5f..4e466990 100644 --- a/osinaweb/osinacore/templates/index.html +++ b/osinaweb/osinacore/templates/index.html @@ -339,7 +339,6 @@ const html = data.html; const ticketId = data.ticket_id; - console.log(ticketId); // Remove the existing ticket row if it exists const existingTicketRows = document.querySelectorAll(`.ticket-${ticketId}`); diff --git a/osinaweb/osinacore/templates/main.html b/osinaweb/osinacore/templates/main.html index 88ed6b3e..51d1bb16 100644 --- a/osinaweb/osinacore/templates/main.html +++ b/osinaweb/osinacore/templates/main.html @@ -1216,6 +1216,7 @@ + diff --git a/osinaweb/osinacore/templates/recent-activities-page.html b/osinaweb/osinacore/templates/recent-activities-page.html index 363fac26..0387dd4d 100644 --- a/osinaweb/osinacore/templates/recent-activities-page.html +++ b/osinaweb/osinacore/templates/recent-activities-page.html @@ -732,6 +732,10 @@ + + + + diff --git a/osinaweb/static/dist/output.css b/osinaweb/static/dist/output.css index 2893aa81..39d7f4b4 100644 --- a/osinaweb/static/dist/output.css +++ b/osinaweb/static/dist/output.css @@ -1221,10 +1221,6 @@ video { height: 16px; } -.h-\[180px\] { - height: 180px; -} - .h-\[18px\] { height: 18px; } @@ -2912,10 +2908,6 @@ video { line-height: 2.5rem; } -.text-\[10px\] { - font-size: 10px; -} - .text-\[12px\] { font-size: 12px; } diff --git a/osinaweb/static/js/online/online-consumer.js b/osinaweb/static/js/online/online-consumer.js index b0573cd7..71257c10 100644 --- a/osinaweb/static/js/online/online-consumer.js +++ b/osinaweb/static/js/online/online-consumer.js @@ -38,13 +38,11 @@ document.addEventListener("DOMContentLoaded", function () { }); const onlineUsersIds = data.online_users_ids || []; - console.log(onlineUsersIds); // Update user activity containers based on online status const userActivityContainers = document.querySelectorAll(".users-activities"); userActivityContainers.forEach(container => { const userId = container.getAttribute("data-userId"); - console.log(userId); if (onlineUsersIds.map(id => id.toString()).includes(userId)) { container.querySelector("#connected").classList.remove("hidden"); diff --git a/osinaweb/static/js/status/new-status-consumer.js b/osinaweb/static/js/status/new-status-consumer.js index 34d88ba7..415e14bd 100644 --- a/osinaweb/static/js/status/new-status-consumer.js +++ b/osinaweb/static/js/status/new-status-consumer.js @@ -10,8 +10,11 @@ const data = JSON.parse(e.data); if (data.event_type === 'new_status') { const activityDiv = document.getElementById('activitiesContainer'); - console.log(activityDiv); activityDiv.insertAdjacentHTML('afterbegin', data.html); + const audio = new Audio('/static/notifications/new-status.mp3'); + audio.play().catch(error => { + console.log('Error playing notification sound:', error); + }); } }; diff --git a/osinaweb/static/js/status/update-status-time-consumer.js b/osinaweb/static/js/status/update-status-time-consumer.js new file mode 100644 index 00000000..d363f254 --- /dev/null +++ b/osinaweb/static/js/status/update-status-time-consumer.js @@ -0,0 +1,50 @@ +// WebSocket connection for new statuses +const ws_protocol = window.location.protocol === "https:" ? "wss" : "ws"; +const newStatusesTimeSocketUrl = `${ws_protocol}://${window.location.host}/ws/update-statuses-time/`; +const newStatusesTimeSocket = new WebSocket(newStatusesTimeSocketUrl); + +newStatusesTimeSocket.onopen = () => { + console.log('WebSocket connection to new statuses time established'); + + function sendUpdate() { + newStatusesTimeSocket.send(JSON.stringify({ 'event_type': 'update_statuses_time' })); + } + + // Call sendUpdate every 1 minute (60000 milliseconds) + setInterval(sendUpdate, 60000); + // Call it immediately on load + sendUpdate(); +}; + +newStatusesTimeSocket.onmessage = function(e) { + const data = JSON.parse(e.data); + + if (data.event_type === 'update_statuses_time') { + const activityDiv = document.getElementById('activitiesContainer'); + activityDiv.innerHTML = data.html; + + // Update user activity containers based on online status + const onlineUsersIds = data.online_users_ids || []; + const userActivityContainers = document.querySelectorAll(".users-activities"); + + userActivityContainers.forEach(container => { + const userId = container.getAttribute("data-userId"); + + if (onlineUsersIds.map(id => id.toString()).includes(userId)) { + container.querySelector("#connected").classList.remove("hidden"); + container.querySelector("#not-connected").classList.add("hidden"); + } else { + container.querySelector("#connected").classList.add("hidden"); + container.querySelector("#not-connected").classList.remove("hidden"); + } + }); + } +}; + +newStatusesTimeSocket.onclose = () => { + console.log('WebSocket connection to new statuses time closed'); +}; + +newStatusesTimeSocket.onerror = (error) => { + console.log('WebSocket error:', error); +}; diff --git a/osinaweb/static/notifications/new-status.mp3 b/osinaweb/static/notifications/new-status.mp3 new file mode 100644 index 00000000..a1ad34ac Binary files /dev/null and b/osinaweb/static/notifications/new-status.mp3 differ