emile 9 months ago
parent 103f2c96bf
commit d3df878d0e

Binary file not shown.

@ -29,13 +29,6 @@ class OsitcomVisitor(WebsocketConsumer):
def receive(self, text_data):
text_data_json = json.loads(text_data)
event_type = text_data_json.get('event_type')
if event_type == 'set_client_type':
self.client_type = text_data_json.get('client_type')
self.user_id = text_data_json.get('user_id')
self.get_vistors_handler()
if event_type == 'visitor_ping':
session_id = text_data_json.get('session_id')
if Visitor.objects.filter(session_id=session_id).last():
@ -54,42 +47,22 @@ class OsitcomVisitor(WebsocketConsumer):
visit_date = datetime.now()
)
def get_vistors_handler(self):
visitors = Visitor.objects.all().order_by('-id')
context = {
'visitors': visitors,
}
if self.client_type == 'mobile_admin':
visitors_data = []
for visitor in visitors:
visitor_dict = model_to_dict(visitor)
visitor_logs = VisitorLog.objects.filter(visitor=visitor)
visitor_logs_data = [model_to_dict(log) for log in visitor_logs]
visitor_dict['visitor_logs'] = visitor_logs_data
visitors_data.append(visitor_dict)
self.send(text_data=json.dumps({
'event_type': 'get_visitors',
'visitors_data': visitors_data,
}, cls=DjangoJSONEncoder))
class OsitcomChatRooms(WebsocketConsumer):
class Osichat(WebsocketConsumer):
def connect(self):
async_to_sync(self.channel_layer.group_add)(
'ositcom_chats', self.channel_name
'osichat', self.channel_name
)
self.accept()
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
'ositcom_chats', self.channel_name
'osichat', self.channel_name
)
def receive(self, text_data):
@ -99,11 +72,30 @@ class OsitcomChatRooms(WebsocketConsumer):
if event_type == 'set_client_type':
self.client_type = data.get('client_type')
self.user_id = data.get('user_id')
self.get_chats_handler()
event = {
'type': 'get_chats_handler',
}
self.get_chats_handler(event)
if event_type == 'get_chats':
event = {
'type': 'get_chats_handler',
}
async_to_sync(self.channel_layer.group_send)(
'osichat', event
)
if event_type == 'get_visitors':
print('eeewew')
event = {
'type': 'get_visitors_handler',
}
async_to_sync(self.channel_layer.group_send)(
'osichat', event
)
def get_chats_handler(self):
def get_chats_handler(self, event):
chat_rooms = ChatRoom.objects.annotate(last_update=Max('chatmessage__date_sent'),
order_key=Case(
When(last_update__isnull=True, then=F('date_created')),
@ -149,7 +141,7 @@ class OsitcomChatRooms(WebsocketConsumer):
}))
def new_update_handler(self, event):
def new_chat_update_handler(self, event):
chat_room = get_object_or_404(ChatRoom, id=event['chatroom_id'])
user = get_object_or_404(User, id=self.user_id)
number_of_unread = ChatMessage.objects.filter(room=chat_room).exclude(member=user).exclude(chatmessageseen__member=user).count()
@ -168,13 +160,43 @@ class OsitcomChatRooms(WebsocketConsumer):
else:
html = render_to_string("chat_templates/partials/new-chat-room.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'new_update',
'event_type': 'new_chat_update',
'chatroom_id': chat_room.id,
'user': last_message.member.id if last_message and last_message.member else None,
'html': html,
}))
def get_visitors_handler(self, event):
visitors = Visitor.objects.all().order_by('-id')
context = {
'visitors': visitors,
}
if self.client_type == 'mobile_admin':
visitors_data = []
for visitor in visitors:
visitor_dict = model_to_dict(visitor)
visitor_logs = VisitorLog.objects.filter(visitor=visitor)
visitor_logs_data = [model_to_dict(log) for log in visitor_logs]
visitor_dict['visitor_logs'] = visitor_logs_data
visitors_data.append(visitor_dict)
self.send(text_data=json.dumps({
'event_type': 'get_visitors',
'visitors_data': visitors_data,
}, cls=DjangoJSONEncoder))
else:
html = render_to_string("chat_templates/partials/visitors.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'get_visitors',
'html': html,
}))
@ -244,21 +266,20 @@ class OsitcomChatRoom(WebsocketConsumer):
visitor=self.visitor
)
self.chat_room = chat_room
self.group = f"{self.session_id}_{self.chat_room.id}"
async_to_sync(self.channel_layer.group_discard)(
self.group, self.channel_name
)
self.group = f"{self.session_id}_{self.chat_room.id}"
async_to_sync(self.channel_layer.group_add)(
self.group, self.channel_name
)
async_to_sync(self.channel_layer.group_send)(
self.group, event
)
event = {
'type': 'start_conversation_handler',
'chat_room_id': chat_room.id
}
async_to_sync(self.channel_layer.group_send)(
self.group, event
)
if event_type == 'typing':
event = {

@ -58,10 +58,10 @@ class ChatRoom(models.Model):
super().save(*args, **kwargs)
channel_layer = get_channel_layer()
event = {
'type': 'new_update_handler',
'type': 'new_chat_update_handler',
'chatroom_id': self.id,
}
async_to_sync(channel_layer.group_send)("ositcom_chats", event)
async_to_sync(channel_layer.group_send)("osichat", event)
@ -102,10 +102,10 @@ class ChatMessage(models.Model):
super().save(*args, **kwargs)
channel_layer = get_channel_layer()
event = {
'type': 'new_update_handler',
'type': 'new_chat_update_handler',
'chatroom_id': self.room.id,
}
async_to_sync(channel_layer.group_send)("ositcom_chats", event)
async_to_sync(channel_layer.group_send)("osichat", event)
class ChatMessageAttachment(models.Model):

@ -2,8 +2,7 @@ from django.urls import path
from .consumers import *
websocket_urlpatterns = [
path("ws/osichat/visitors/", OsitcomVisitor.as_asgi()),
path("ws/osichat/rooms/", OsitcomChatRooms.as_asgi()),
path("ws/osichat/", Osichat.as_asgi()),
path("ws/osichat/<str:session_id>/", OsitcomChatRoom.as_asgi()),
path("ws/osichat-admin/<str:session_id>/<int:chat_id>/", OsitcomChatRoom.as_asgi()),

@ -1,10 +1,57 @@
{% load static %}
<p id="userId" class="hidden">{{request.user.id}}</p>
<div id="chatWidget" class="hidden fixed bg-black bg-opacity-50 inset-0 z-50 h-[100vh]">
<div id="osichatWidget" class="hidden fixed bg-black bg-opacity-50 inset-0 z-50 h-[100vh]">
<div
class="w-[950px] min-h-[500px] h-[80%] bg-white rounded-md border border-gray-200 shadow-xl z-20 right-9 bottom-24 grid grid-cols-3 fixed">
<!-- LEFT SIDE - CHATS -->
<!-- LEFT SIDE - CONTENT -->
<div id="widgetLeftSide" class="h-full overflow-y-auto border-r border-gray-200 bg-gray-50 relative rounded-l-md">
<!-- RECONNECTING LOADER -->
<div id="roomsLoader"
class="w-full h-full absolute flex justify-center items-center bg-black bg-opacity-60 z-20 inset-0 rounded-l-md hidden">
<div class="flex flex-col justify-center items-center gap-2">
<p class="text-white">Reconneting</p>
<div class="w-fit flex gap-1 justify-start items-center">
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md"></div>
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md" style="animation-delay: 0.2s;"></div>
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md" style="animation-delay: 0.4s;">
</div>
</div>
</div>
</div>
<!-- HEADER -->
<div class="grid grid-cols-2 sticky top-0 z-10 rounded-l-md">
<div id="chatsTab"
class="w-full flex items-center justify-center gap-1 py-3 px-3 border-b border-gray-100 bg-white rounded-md shadow-md cursor-pointer text-secondosiblue">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-5">
<path stroke-linecap="round" stroke-linejoin="round"
d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
</svg>
<p>Chats</p>
</div>
<div id="visitorsTab"
class=" w-full flex items-center justify-center gap-1 py-3 px-3 border-b border-gray-100 bg-gray-100 text-gray-400 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-5" fill="none">
<path
d="M2.5 8.18677C2.60406 6.08705 2.91537 4.77792 3.84664 3.84664C4.77792 2.91537 6.08705 2.60406 8.18677 2.5M21.5 8.18677C21.3959 6.08705 21.0846 4.77792 20.1534 3.84664C19.2221 2.91537 17.9129 2.60406 15.8132 2.5M15.8132 21.5C17.9129 21.3959 19.2221 21.0846 20.1534 20.1534C21.0846 19.2221 21.3959 17.9129 21.5 15.8132M8.18676 21.5C6.08705 21.3959 4.77792 21.0846 3.84664 20.1534C2.91537 19.2221 2.60406 17.9129 2.5 15.8132"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M19.6352 11.3178C19.8784 11.6224 20 11.7746 20 12C20 12.2254 19.8784 12.3776 19.6352 12.6822C18.5423 14.0504 15.7514 17 12 17C8.24862 17 5.45768 14.0504 4.36483 12.6822C4.12161 12.3776 4 12.2254 4 12C4 11.7746 4.12161 11.6224 4.36483 11.3178C5.45768 9.9496 8.24862 7 12 7C15.7514 7 18.5423 9.9496 19.6352 11.3178Z"
stroke="currentColor" stroke-width="1.5" />
<path
d="M14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z"
stroke="currentColor" stroke-width="1.5" />
</svg>
<p>Visitors</p>
</div>
</div>
<div id="leftDynamic"></div>
</div>
<!-- RIGHT SIDE -->

@ -1,14 +1,21 @@
<div data-roomid = {{chat_room.id}} data-session="{{chat_room.chatroomguest.visitor.session_id}}" class="chat-room w-full flex flex-col gap-1 py-3 px-3 border-b border-gray-100 text-sm cursor-pointer">
<div data-roomid={{chat_room.id}} data-session="{{chat_room.chatroomguest.visitor.session_id}}"
class="chat-room w-full flex flex-col gap-1 py-4 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
<div class="w-full flex justify-between items-center">
<div class="w-full flex items-center gap-2">
<div class="w-[40px] h-[40px] rounded-full">
<img src="{{chat_room.chatroomguest.visitor.flag_image_url}}">
</div>
<div class="flex flex-col">
<p class="text-secondosiblue font-poppinsBold">{{chat_room.chatroomguest.visitor.ip_address}}</p>
<p class="text-gray-500 text-xs">{{chat_room.chatmessage_set.all.last.content}}</p>
<p class="text-gray-500 opacity-70 text-xs">{{chat_room.last_updated}}</p>
</div>
</div>
<div data-roomid={{chat_room.id}}
class="unread w-[20px] h-[20px] bg-osiblue rounded-full shadow-md flex justify-center items-center text-white text-[10px] {% if chat_room.number_of_unread == 0 %} hidden {% endif %}">
<p>{{number_of_unread}}</p>
</div>
</div>
<p class="text-gray-500 text-xs">{{chat_room.chatmessage_set.all.last.content}}</p>
<p class="text-gray-500 opacity-70 text-xs">{{chat_room.last_updated}}</p>
</div>

@ -1,50 +1,5 @@
<!-- RECONNECTING LOADER -->
<div id="roomsLoader"
class="w-full h-full absolute flex justify-center items-center bg-black bg-opacity-60 z-20 inset-0 rounded-l-md hidden">
<div class="flex flex-col justify-center items-center gap-2">
<p class="text-white">Reconneting</p>
<div class="w-fit flex gap-1 justify-start items-center">
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md"></div>
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md" style="animation-delay: 0.2s;"></div>
<div class="h-2 w-2 bg-white rounded-full animate-typing shadow-md" style="animation-delay: 0.4s;">
</div>
</div>
</div>
</div>
<!-- HEADER -->
<div class="grid grid-cols-2 sticky top-0 z-10 rounded-l-md">
<div
class="w-full flex items-center justify-center gap-1 py-3 px-3 border-b border-gray-100 bg-white rounded-md shadow-md cursor-pointer text-secondosiblue">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-5">
<path stroke-linecap="round" stroke-linejoin="round"
d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
</svg>
<p>Chats</p>
</div>
<div
class="w-full flex items-center justify-center gap-1 py-3 px-3 border-b border-gray-100 bg-gray-100 text-gray-400 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-5" fill="none">
<path
d="M2.5 8.18677C2.60406 6.08705 2.91537 4.77792 3.84664 3.84664C4.77792 2.91537 6.08705 2.60406 8.18677 2.5M21.5 8.18677C21.3959 6.08705 21.0846 4.77792 20.1534 3.84664C19.2221 2.91537 17.9129 2.60406 15.8132 2.5M15.8132 21.5C17.9129 21.3959 19.2221 21.0846 20.1534 20.1534C21.0846 19.2221 21.3959 17.9129 21.5 15.8132M8.18676 21.5C6.08705 21.3959 4.77792 21.0846 3.84664 20.1534C2.91537 19.2221 2.60406 17.9129 2.5 15.8132"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M19.6352 11.3178C19.8784 11.6224 20 11.7746 20 12C20 12.2254 19.8784 12.3776 19.6352 12.6822C18.5423 14.0504 15.7514 17 12 17C8.24862 17 5.45768 14.0504 4.36483 12.6822C4.12161 12.3776 4 12.2254 4 12C4 11.7746 4.12161 11.6224 4.36483 11.3178C5.45768 9.9496 8.24862 7 12 7C15.7514 7 18.5423 9.9496 19.6352 11.3178Z"
stroke="currentColor" stroke-width="1.5" />
<path
d="M14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z"
stroke="currentColor" stroke-width="1.5" />
</svg>
<p>Visitors</p>
</div>
</div>
<!-- CHATS -->
<div class="h-full flex flex-col text-secondosiblue" id="chatrooms">
<div class="h-full flex flex-col" id="chatrooms">
{% for chat_room in chat_rooms %}
<div data-roomid={{chat_room.id}} data-session="{{chat_room.chatroomguest.visitor.session_id}}"
class="chat-room w-full flex flex-col gap-1 py-4 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
@ -71,31 +26,6 @@
</div>
<!-- VISITORS -->
<!-- <div class="h-full flex flex-col">
<div class="w-full py-3 px-3 border-b border-gray-200 flex items-center gap-2">
<div class="w-[20px] h-[20px] bg-green-600 rounded-full onlineDot">
<div class="wave"></div>
</div>
<p class="text-secondosiblue">Active</p>
</div>
<div class="w-full flex justify-between gap-2 items-center py-3 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
<div class="w-full flex gap-2 items-center">
<div class="w-[40px] h-[40px] rounded-full bg-red-500"></div>
<div class="flex flex-col">
<p class="text-secondosiblue font-poppinsBold">192.168.1.1092</p>
<p class="text-fifthosiblue text-xs">Web development</p>
</div>
</div>
<p class="text-gray-500 text-sm">00:00</p>
</div>
</div> -->
<audio id="notification-sound" src="{{domain}}/static/notifications/osichat-notification.mp3" preload="auto"></audio>
<audio id="out-notification-sound" src="{{domain}}/static/notifications/out-osichat-notification.wav"

@ -0,0 +1,30 @@
<!-- VISITORS -->
<div class="h-full flex flex-col" id="visitors">
<div class="w-full py-3 px-3 border-b border-gray-200 flex items-center gap-2">
<div class="w-[20px] h-[20px] bg-green-600 rounded-full onlineDot">
<div class="wave"></div>
</div>
<p class="text-secondosiblue">Active</p>
</div>
{% for visitor in visitors %}
<div class="w-full flex justify-between gap-2 items-center py-3 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
<div class="w-full flex gap-2 items-center">
<div class="w-[40px] h-[40px] rounded-full">
<img src="{{visitor.flag_image_url}}">
</div>
<div class="flex flex-col">
<p class="text-secondosiblue font-poppinsBold">{{visitor.ip_address}}</p>
<p class="text-fifthosiblue text-xs">{{visitor.visitorlog_set.all.last.url}}</p>
</div>
</div>
<p class="text-gray-500 text-sm">00:00</p>
</div>
{% endfor %}
</div>

@ -1,5 +1,5 @@
const openChatButton = document.getElementById('openChatContainer');
const chatWidget = document.getElementById('chatWidget');
const osichatWidget = document.getElementById('osichatWidget');
const closeChatButton = document.getElementById('closeChatContainer');
const conversation = document.getElementById('conversation');
@ -8,14 +8,14 @@ function scrollToBottom() {
}
openChatButton.addEventListener('click', function () {
chatWidget.classList.remove('hidden');
osichatWidget.classList.remove('hidden');
openChatButton.classList.add('hidden');
closeChatButton.classList.remove('hidden');
scrollToBottom();
});
function closeChat() {
chatWidget.classList.add('hidden');
osichatWidget.classList.add('hidden');
openChatButton.classList.remove('hidden');
closeChatButton.classList.add('hidden');
}

@ -30,10 +30,8 @@ function appendInnerConversationScript(div) {
function getRooms(){
osichatroomsSocket = new WebSocket(`${admin_chat_ws_scheme}://${admin_chat_domain}/ws/osichat/rooms/`);
function initializeOsichat(){
osichatroomsSocket = new WebSocket(`${admin_chat_ws_scheme}://${admin_chat_domain}/ws/osichat/`);
osichatroomsSocket.onopen = function () {
console.log('WebSocket connection to rooms established');
@ -48,19 +46,24 @@ function getRooms(){
osichatroomsSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
const leftDiv = document.getElementById('widgetLeftSide');
const leftDynamicDiv = document.getElementById('leftDynamic');
switch (data.event_type) {
case 'get_chats':
leftDiv.innerHTML = data.html;
leftDynamicDiv.innerHTML = data.html;
appendInnerConversationScript(leftDiv);
break;
case 'new_update':
case 'get_visitors':
leftDynamicDiv.innerHTML = data.html;
break;
case 'new_chat_update':
const roomsContainer = document.getElementById('chatrooms');
const chatRoomDiv = roomsContainer.querySelector(`.chat-room[data-roomid='${data.chatroom_id}']`);
if (chatRoomDiv) {
chatRoomDiv.remove(); // Remove the existing chat room div
}
// Insert the new chat room HTML at the top of the container
const newChatRoomDiv = document.createElement('div');
newChatRoomDiv.innerHTML = data.html;
@ -100,7 +103,7 @@ function getRooms(){
showLoader();
setTimeout(() => {
console.log('Attempting to reconnect to WebSocket...');
getRooms();
initializeOsichat();
}, 2000);
};
@ -118,4 +121,33 @@ function getRooms(){
}
getRooms();
const chatsTab = document.getElementById('chatsTab');
const visitorsTab = document.getElementById('visitorsTab');
function switchToChats() {
chatsTab.classList.add('bg-white', 'text-secondosiblue', 'shadow-md');
chatsTab.classList.remove('bg-gray-100', 'text-gray-400');
visitorsTab.classList.add('bg-gray-100', 'text-gray-400');
visitorsTab.classList.remove('bg-white', 'text-secondosiblue', 'shadow-md');
osichatroomsSocket.send(JSON.stringify({
event_type: 'get_chats'
}));
}
function switchToVisitors() {
visitorsTab.classList.add('bg-white', 'text-secondosiblue', 'shadow-md');
visitorsTab.classList.remove('bg-gray-100', 'text-gray-400');
chatsTab.classList.add('bg-gray-100', 'text-gray-400');
chatsTab.classList.remove('bg-white', 'text-secondosiblue', 'shadow-md');
osichatroomsSocket.send(JSON.stringify({
event_type: 'get_visitors'
}));
}
chatsTab.addEventListener('click', switchToChats);
visitorsTab.addEventListener('click', switchToVisitors);
initializeOsichat();
Loading…
Cancel
Save