emile 9 months ago
parent ed5ff67bab
commit 411b2e3cca

Binary file not shown.

@ -2,7 +2,14 @@ from osichat.models import *
from rest_framework import serializers
class VisitorSerializer(serializers.ModelSerializer):
class Meta:
model = Visitor
fields = '__all__'
class ChatRoomGuestSerializer(serializers.ModelSerializer):
visitor = VisitorSerializer()
class Meta:
model = ChatRoomGuest
fields = '__all__'

@ -49,10 +49,83 @@ class OsitcomVisitor(WebsocketConsumer):
class OsitcomChatRooms(WebsocketConsumer):
def connect(self):
async_to_sync(self.channel_layer.group_add)(
'ositcom_chats', self.channel_name
)
self.accept()
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
'ositcom_chats', self.channel_name
)
def receive(self, text_data):
data = json.loads(text_data)
event_type = data.get('event_type')
if event_type == 'set_client_type':
self.client_type = data.get('client_type')
self.user_id = data.get('user_id')
self.get_chats_handler()
def get_chats_handler(self):
chat_rooms = ChatRoom.objects.annotate(last_update=Max('chatmessage__date_sent')).order_by('-last_update', '-date_created')
user = get_object_or_404(User, id=self.user_id)
for room in chat_rooms:
room.number_of_unread = room.unread_messages(user)
context = {
'chat_rooms': chat_rooms,
}
if self.client_type == 'mobile_admin':
chat_rooms_data = [model_to_dict(chat_room) for chat_room in chat_rooms]
self.send(text_data=json.dumps({
'event_type': 'get_chats',
'chat_rooms_data': chat_rooms_data,
}, cls=DjangoJSONEncoder))
else:
html = render_to_string("chat_templates/partials/rooms.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'get_chats',
'html': html,
}))
def new_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()
context = {
'chat_room': chat_room,
'number_of_unread': number_of_unread
}
if self.client_type == 'mobile_admin':
chat_room_data = model_to_dict(chat_room)
self.send(text_data=json.dumps({
'event_type': 'new_update',
'chat_room_data': chat_room_data,
}, cls=DjangoJSONEncoder))
else:
html = render_to_string("chat_templates/partials/new-chat-room.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'new_update',
'chatroom_id': chat_room.id,
'html': html,
}))
class OsitcomChatRoom(WebsocketConsumer):
def connect(self):
self.domain = 'https://osina.ositcom.com'
self.domain = 'http://192.168.1.111:8000'
self.session_id = self.scope['url_route']['kwargs']['session_id']
self.visitor = Visitor.objects.filter(session_id=self.session_id).last()
@ -201,7 +274,7 @@ class OsitcomChatRoom(WebsocketConsumer):
)
number_of_unread = 0
else:
number_of_unread = ChatMessage.objects.filter(room=self.chat_room).exclude(member = member, chatmessageseen__member=member).count()
number_of_unread = ChatMessage.objects.filter(room=self.chat_room).exclude(member = member).exclude(hatmessageseen__member=member).count()
latest_unread_message = ChatMessage.objects.filter(room=self.chat_room).exclude(chatmessageseen__member=member).last()
else:
member = None
@ -334,6 +407,7 @@ class OsitcomChatRoom(WebsocketConsumer):
'html': html,
}))
def start_conversation_handler(self, event):
chat_room = get_object_or_404(ChatRoom, id=event['chat_room_id'])
context = {
@ -353,6 +427,7 @@ class OsitcomChatRoom(WebsocketConsumer):
'html': html,
}))
def typing_handler(self, event):
if event.get('typing_status') == 'typing':
if event.get('user_id'):
@ -362,19 +437,37 @@ class OsitcomChatRoom(WebsocketConsumer):
context = {
'member': member,
'chat_room': self.chat_room,
'domain': self.domain
}
html = render_to_string("partials/typing.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'typing',
'html': html,
}))
if self.client_type == 'mobile_admin':
member_data = None
if member:
member_data = model_to_dict(member)
self.send(text_data=json.dumps({
'event_type': 'typing',
'member_data': member_data,
}, cls=DjangoJSONEncoder))
elif self.client_type == 'website_admin':
html = render_to_string("chat_templates/partials/typing.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'typing',
'user': member.id if member else None,
'html': html,
}))
else:
html = render_to_string("partials/typing.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'typing',
'user': member.id if member else None,
'html': html,
}))
else:
self.send(text_data=json.dumps({
'event_type': 'stopped_typing',
}))
def send_message_handler(self, event):
chat_message = get_object_or_404(ChatMessage, id=event['chat_message_id'])
context = {
@ -391,6 +484,7 @@ class OsitcomChatRoom(WebsocketConsumer):
html = render_to_string("chat_templates/partials/message.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'send_message',
'user': chat_message.member.id if chat_message.member else None,
'html': html,
}))
else:
@ -401,6 +495,7 @@ class OsitcomChatRoom(WebsocketConsumer):
'html': html,
}))
def uploaded_file_handler(self, event):
message_attachment = get_object_or_404(ChatMessageAttachment, id=event['message_attachment_id'])
context = {
@ -425,6 +520,7 @@ class OsitcomChatRoom(WebsocketConsumer):
'html': html,
}))
def update_read_messages_handler(self, event):
latest_unread_message_id = event.get('latest_unread_message_id')
if latest_unread_message_id:
@ -434,14 +530,21 @@ class OsitcomChatRoom(WebsocketConsumer):
'latest_unread_message': latest_unread_message,
'domain': self.domain
}
html = render_to_string("partials/unread-messages.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'update_read_messages',
'html': html,
}))
if self.client_type == 'mobile_admin':
self.send(text_data=json.dumps({
'event_type': 'update_read_messages',
'number_of_unread': event['number_of_unread'],
},cls=DjangoJSONEncoder))
else:
html = render_to_string("partials/unread-messages.html", context=context)
self.send(text_data=json.dumps({
'event_type': 'update_read_messages',
'html': html,
}))
else:
latest_unread_message = None
def end_chat_handler(self, event):
if event['user_id']:
member = get_object_or_404(User, id=event['user_id'])

@ -2,6 +2,9 @@ from django.db import models
from osinacore.models import *
import mimetypes
import os
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
import json
# Create your models here.
@ -46,6 +49,20 @@ class ChatRoom(models.Model):
return last_updated_time.strftime('%I:%M %p')
else:
return last_updated_time.strftime('%d-%m-%Y')
def unread_messages(self, user):
return ChatMessage.objects.filter(room=self).exclude(member=user).exclude(chatmessageseen__member=user).count()
def save(self, *args, **kwargs):
is_new = self.pk is None
super().save(*args, **kwargs)
channel_layer = get_channel_layer()
event = {
'type': 'new_update_handler',
'chatroom_id': self.id,
}
async_to_sync(channel_layer.group_send)("ositcom_chats", event)
class ChatRoomGuest(models.Model):
@ -80,6 +97,15 @@ class ChatMessage(models.Model):
member = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, blank=True)
content = models.TextField(null=True, blank=True)
date_sent = models.DateTimeField()
def save(self, *args, **kwargs):
is_new = self.pk is None
super().save(*args, **kwargs)
channel_layer = get_channel_layer()
event = {
'type': 'new_update_handler',
'chatroom_id': self.room.id,
}
async_to_sync(channel_layer.group_send)("ositcom_chats", event)
class ChatMessageAttachment(models.Model):

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

@ -4,6 +4,16 @@
<p id="chatRoomId" class="hidden">{{chat_room.id}}</p>
<div class="w-full h-full md:h-[450px] lg:h-[550px] bg-white rounded-b-none md:rounded-b-md flex flex-col justify-end">
<div class="absolute right-0 bottom-32 bg-secondosiblue px-2 py-3 bg-white border border-gray-100 rounded-l-md z-10 flex flex-col gap-2 shadow-md hidden" id="newMessagesPopMessage">
<div class="w-[22px] h-[22px] rounded-full border border-secondosiblue flex justify-center items-center text-secondosiblue text-xs text-secondosiblue">
<p id="newMessagesCounter">1</p>
</div>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</div>
<div class="overflow-y-auto flex flex-col gap-5 px-5 pt-3" id="conversation">
<!-- ROBOT -->
<div class="w-full flex items-end gap-2">
@ -126,8 +136,6 @@
</div>
<audio id="notification-sound" src="{{domain}}/static/notifications/osichat-notification.mp3" preload="auto"></audio>
<div id="typing" class="hidden"></div>
</div>
<form class="px-5 pt-3 bg-transparent relative" id="sendMessage">

@ -1,12 +1,7 @@
<div class="mb-2 flex justify-start items-center gap-2">
<div class="mb-2 flex justify-start items-center gap-2" id="typing">
<div
class="w-[30px] h-[30px] rounded-full shadow-md text-white flex justify-center items-center bg-osiblue uppercase text-xs">
{% if member.staffprofile.image %}
<img class="w-full h-full rounded-full"
src="{{domain}}{{member.staffprofile.image.url}}">
{% else %}
<p>{{member.first_name.0}}{{member.last_name.0}}</p>
{% endif %}
class="w-[25px] h-[25px] rounded-full shadow-md text-white flex justify-center items-center bg-osiblue uppercase text-xs">
<img class="w-full h-full rounded-full" src="{{domain}}{{member.staffprofile.image.url}}">
</div>
<div
class="w-fit rounded-r-3xl rounded-tl-3xl px-3 py-3 bg-gray-50 border border-gray-100 shadow-md flex space-x-1 justify-start items-center">

@ -9,8 +9,6 @@ from osichat.models import *
def utilities(request):
# Combine protocol and domain
current_url = 'https://osina.ositcom.com'
notes = None
recent_note = None
@ -123,5 +121,5 @@ def utilities(request):
'closed_tickets': closed_tickets,
'today': today,
'latest_chat_rooms': latest_chat_rooms,
'current_url': current_url
}

@ -89,22 +89,7 @@
<audio id="notification-sound" src="{{domain}}/static/notifications/osichat-notification.mp3" preload="auto"></audio>
<!-- INCLUDE TYPING HERE -->
<!-- <div class="mb-2 flex justify-start items-center gap-2">
<div
class="w-[30px] h-[30px] rounded-full shadow-md text-white flex justify-center items-center bg-osiblue uppercase text-xs">
<p>nn</p>
</div>
<div
class="w-fit rounded-r-3xl rounded-tl-3xl px-2 py-2 bg-gray-50 border border-gray-100 shadow-md flex space-x-1 justify-start items-center">
<div class="h-2 w-2 bg-secondosiblue rounded-full animate-typing"></div>
<div class="h-2 w-2 bg-osiblue rounded-full animate-typing" style="animation-delay: 0.2s;"></div>
<div class="h-2 w-2 bg-fifthosiblue rounded-full animate-typing" style="animation-delay: 0.4s;">
</div>
</div>
</div> -->
<!-- END TYPING -->
</div>
<!-- INPUT FORM -->

@ -1,47 +1,14 @@
{% 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
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 -->
<div id="osichat-conversations" class="h-full overflow-y-auto border-r border-gray-200 bg-gray-50">
<!-- HEADER -->
<div class="grid grid-cols-2 sticky top-0 z-10">
<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>
<!-- CONVERSATIONS -->
{% include 'chat_templates/conversations.html' %}
<div id="widgetLeftSide" class="h-full overflow-y-auto border-r border-gray-200 bg-gray-50">
</div>
<!-- RIGHT SIDE - CONVERSATION -->
<div class="col-span-2 overflow-hidden" id="inner-conversation">
<!-- the messages are here -->
<!-- RIGHT SIDE -->
<div class="col-span-2 overflow-hidden" id="widgetRightSide">
</div>
</div>
@ -70,5 +37,5 @@
<!---------------------- JS SCRIPTS -------------------->
<script type="text/javascript" src='{% static "js/osichat-admin/conversation.js" %}'></script>
<script type="text/javascript" src='{% static "js/osichat-admin/inner-conversation.js" %}'></script>
<script type="text/javascript" src='{% static "js/osichat-admin/chat-toggle.js" %}'></script>

@ -1,20 +0,0 @@
<p id="userId" class="hidden">{{request.user.id}}</p>
<div class="h-full flex flex-col text-secondosiblue">
<!-- CHATS -->
{% for chat in latest_chat_rooms %}
<div class="chat-room w-full flex flex-col gap-1 py-3 px-3 border-b border-gray-100 text-sm cursor-pointer" data-chatid ="{{chat.id}}" data-session="{{chat.chatroomguest.visitor.session_id}}">
<div class="w-full flex justify-between items-center">
<p class="text-secondosiblue font-poppinsBold">{{chat.chatroomguest.visitor.session_id}}</p>
<div
class="w-[20px] h-[20px] bg-osiblue rounded-full shadow-md flex justify-center items-center text-white text-[10px]">
<p>22</p>
</div>
</div>
<p class="text-gray-500 text-xs">{{chat.chatmessage_set.all.last.content}}</p>
<p class="text-gray-500 opacity-70 text-xs">{{chat.last_updated}}</p>
</div>
{% endfor %}
</div>

@ -0,0 +1,14 @@
<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 class="w-full flex justify-between items-center">
<p class="text-secondosiblue font-poppinsBold">{{chat_room.chatroomguest.visitor.ip_address}}</p>
<div
class="w-[20px] h-[20px] bg-osiblue rounded-full shadow-md flex justify-center items-center text-white text-[10px]">
<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>

@ -0,0 +1,49 @@
<!-- HEADER -->
<div class="grid grid-cols-2 sticky top-0 z-10">
<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>
<div class="h-full flex flex-col text-secondosiblue" id="chatrooms">
<!-- CHATS -->
{% 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-3 px-3 border-b border-gray-100 text-sm cursor-pointer">
<div class="w-full flex justify-between items-center">
<p class="text-secondosiblue font-poppinsBold">{{chat_room.chatroomguest.visitor.ip_address}}</p>
<div
class="w-[20px] h-[20px] bg-osiblue rounded-full shadow-md flex justify-center items-center text-white text-[10px]">
<p>{{chat_room.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>
{% endfor %}
</div>

@ -0,0 +1,13 @@
<div class="mb-2 flex justify-start items-center gap-2" id="typing">
<div
class="w-[25px] h-[25px] rounded-full shadow-md text-white flex justify-center items-center bg-osiblue uppercase text-xs">
<img class="w-full h-full rounded-full object-cover" src="{{chat_room.chatroomguest.visitor.flag_image_url}}">
</div>
<div
class="w-fit rounded-r-3xl rounded-tl-3xl px-3 py-3 bg-gray-50 border border-gray-100 shadow-md flex space-x-1 justify-start items-center">
<div class="h-1.5 w-1.5 bg-secondosiblue rounded-full animate-typing"></div>
<div class="h-1.5 w-1.5 bg-osiblue rounded-full animate-typing" style="animation-delay: 0.2s;"></div>
<div class="h-1.5 w-1.5 bg-fifthosiblue rounded-full animate-typing" style="animation-delay: 0.4s;">
</div>
</div>
</div>

@ -1226,6 +1226,9 @@
<!-- ONLINE CONSUMER SCRIPT -->
<script type="text/javascript" src='{% static "js/online/online-consumer.js" %}'></script>
<!-- ROOMS -->
<script type="text/javascript" src='{% static "js/osichat-admin/rooms.js" %}'></script>
<!-- NEW STATUS CONSUMER -->
<script type="text/javascript" src='{% static "js/status/new-status-consumer.js" %}'></script>
<script type="text/javascript" src='{% static "js/status/update-status-time-consumer.js" %}'></script>

@ -842,6 +842,18 @@ video {
top: 14px;
}
.bottom-2 {
bottom: 0.5rem;
}
.bottom-28 {
bottom: 7rem;
}
.bottom-32 {
bottom: 8rem;
}
.z-10 {
z-index: 10;
}
@ -1039,10 +1051,6 @@ video {
height: 2rem;
}
.h-\[100\%\] {
height: 100%;
}
.h-\[1000px\] {
height: 1000px;
}
@ -1192,6 +1200,10 @@ video {
height: 100vh;
}
.h-\[22px\] {
height: 22px;
}
.max-h-\[200px\] {
max-height: 200px;
}
@ -1437,6 +1449,10 @@ video {
width: 100%;
}
.w-\[22px\] {
width: 22px;
}
.min-w-full {
min-width: 100%;
}
@ -1575,10 +1591,6 @@ video {
cursor: default;
}
.cursor-pointer {
cursor: pointer;
}
.cursor-none {
cursor: none;
}
@ -1587,6 +1599,10 @@ video {
cursor: not-allowed;
}
.cursor-pointer {
cursor: pointer;
}
.resize-none {
resize: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 KiB

@ -1,87 +0,0 @@
const admin_chat_ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
const protocol = window.location.protocol === "https:" ? "https" : "http";
const admin_chat_domain = "osina.ositcom.com";
let chatWebSocket;
const userId = document.getElementById('userId').textContent.trim();
function handleChatRoomClick(event) {
const sessionId = event.currentTarget.getAttribute('data-session');
const chatId = event.currentTarget.getAttribute('data-chatid');
if (sessionId && chatId) {
openConversation(sessionId, chatId);
} else {
console.error('Session ID not found for this chat room.');
}
}
document.querySelectorAll('.chat-room').forEach(div => {
div.addEventListener('click', handleChatRoomClick);
});
function appendTextAreaScript(domain, conversationContainer) {
if (!document.querySelector(`script[src="${protocol}://${admin_chat_domain}/static/js/osichat-admin/textarea.js"]`)) {
const textareaScript = document.createElement('script');
textareaScript.type = 'text/javascript';
textareaScript.src = `${protocol}://${admin_chat_domain}/static/js/osichat-admin/textarea.js`;
conversationContainer.appendChild(textareaScript);
}
}
function openConversation(sessionid, chatid) {
if (chatWebSocket && chatWebSocket.readyState !== WebSocket.CLOSED) { //Close previous sockets
chatWebSocket.close();
}
chatWebSocket = new WebSocket(`${admin_chat_ws_scheme}://${admin_chat_domain}/ws/osichat-admin/${sessionid}/${chatid}/`);
chatWebSocket.onopen = function () {
console.log('WebSocket connection to osichat established');
chatWebSocket.send(JSON.stringify({ 'event_type': 'load_chat', 'client_type': 'website_admin' }));
};
function handleLoadChatEvent(data, chatWebSocket) {
let chatDiv = document.getElementById('inner-conversation');
chatDiv.innerHTML = data.html;
appendTextAreaScript(admin_chat_domain, chatDiv);
const sendMessageForm = document.querySelector('#sendMessage');
sendMessageForm.addEventListener('submit', function (event) {
event.preventDefault();
const message = event.target.elements.message.value;
const eventMessage = {
'event_type': 'send_message',
'message': message,
'user_id': userId
};
chatWebSocket.send(JSON.stringify(eventMessage));
event.target.reset();
});
}
chatWebSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
switch (data.event_type) {
case 'load_chat':
handleLoadChatEvent(data, chatWebSocket);
break;
case 'send_message':
const messagesDiv = document.getElementById('messages_container');
messagesDiv.insertAdjacentHTML('beforeend', data.html);
if (!data.user) { // If it is sent by a guest play a notification sound for the guest
const notificationSound = document.getElementById('notification-sound');
notificationSound.play();
}
break;
default:
console.log('Unknown event type:', data.event_type);
}
};
chatWebSocket.onclose = function () {
console.log('WebSocket connection to osichat closed');
};
chatWebSocket.onerror = function (error) {
console.error('WebSocket error:', error);
};
}

@ -0,0 +1,100 @@
(function() {
function handleChatRoomClick(event) {
const sessionId = event.currentTarget.getAttribute('data-session');
const chatId = event.currentTarget.getAttribute('data-roomid');
if (sessionId && chatId) {
openConversation(sessionId, chatId);
} else {
console.error('Session ID not found for this chat room.');
}
}
document.querySelectorAll('.chat-room').forEach(div => {
div.addEventListener('click', handleChatRoomClick);
});
function appendTextAreaScript(domain, conversationContainer) {
if (!document.querySelector(`script[src="${protocol}://${admin_chat_domain}/static/js/osichat-admin/textarea.js"]`)) {
const textareaScript = document.createElement('script');
textareaScript.type = 'text/javascript';
textareaScript.src = `${protocol}://${admin_chat_domain}/static/js/osichat-admin/textarea.js`;
conversationContainer.appendChild(textareaScript);
}
}
function openConversation(sessionid, chatid) {
if (osichatadminroomSocket && osichatadminroomSocket.readyState !== WebSocket.CLOSED) { //Close previous sockets
osichatadminroomSocket.close();
}
osichatadminroomSocket = new WebSocket(`${admin_chat_ws_scheme}://${admin_chat_domain}/ws/osichat-admin/${sessionid}/${chatid}/`);
osichatadminroomSocket.onopen = function () {
console.log('WebSocket connection to osichat established');
osichatadminroomSocket.send(JSON.stringify({ 'event_type': 'load_chat', 'client_type': 'website_admin' }));
osichatadminroomSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'user_id': userId, 'chat_state': 'open' }));
};
function handleLoadChatEvent(data, osichatadminroomSocket) {
let chatDiv = document.getElementById('widgetRightSide');
chatDiv.innerHTML = data.html;
appendTextAreaScript(admin_chat_domain, chatDiv);
const sendMessageForm = document.querySelector('#sendMessage');
sendMessageForm.addEventListener('submit', function (event) {
event.preventDefault();
const message = event.target.elements.message.value;
const eventMessage = {
'event_type': 'send_message',
'message': message,
'user_id': userId
};
osichatadminroomSocket.send(JSON.stringify(eventMessage));
event.target.reset();
});
}
osichatadminroomSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
const typingDiv = document.getElementById('typing');
const messagesDiv = document.getElementById('messages_container');
switch (data.event_type) {
case 'load_chat':
handleLoadChatEvent(data, osichatadminroomSocket);
break;
case 'typing':
if(!typingDiv && data.user != userId){
messagesDiv.insertAdjacentHTML('beforeend', data.html);
}
break;
case 'stopped_typing':
if (typingDiv) {
typingDiv.remove();
}
break;
case 'send_message':
osichatadminroomSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'user_id': userId, 'chat_state': 'open' }));
messagesDiv.insertAdjacentHTML('beforeend', data.html);
if (!data.user) { // If it is sent by a guest play a notification sound for the guest
const notificationSound = document.getElementById('notification-sound');
notificationSound.play();
if (typingDiv) {
typingDiv.remove();
}
break;
}
break;
default:
console.log('Unknown event type:', data.event_type);
}
};
osichatadminroomSocket.onclose = function () {
console.log('WebSocket connection to osichat closed');
};
osichatadminroomSocket.onerror = function (error) {
console.error('WebSocket error:', error);
};
}
})();

@ -0,0 +1,64 @@
let admin_chat_ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
let protocol = window.location.protocol === "https:" ? "https" : "http";
let admin_chat_domain = "192.168.1.111:8000";
let userId = document.getElementById('userId').textContent.trim();
let osichatroomsSocket;
let osichatadminroomSocket;
function appendInnerConversationScript(div) {
const innerConversationScript = document.createElement('script');
innerConversationScript.type = 'text/javascript';
innerConversationScript.src = `${protocol}://${admin_chat_domain}/static/js/osichat-admin/inner-conversation.js`;
div.appendChild(innerConversationScript);
}
function getRooms(){
osichatroomsSocket = new WebSocket(`${admin_chat_ws_scheme}://${admin_chat_domain}/ws/osichat/rooms/`);
osichatroomsSocket.onopen = function () {
console.log('WebSocket connection to rooms established');
osichatroomsSocket.send(JSON.stringify({
'event_type': 'set_client_type',
'client_type': 'website_admin',
'user_id': userId
}));
};
osichatroomsSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
const leftDiv = document.getElementById('widgetLeftSide');
switch (data.event_type) {
case 'get_chats':
leftDiv.innerHTML = data.html;
appendInnerConversationScript(leftDiv);
break;
case 'new_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;
roomsContainer.insertAdjacentElement('afterbegin', newChatRoomDiv.firstElementChild);
appendInnerConversationScript(leftDiv);
break;
default:
console.log('Unknown event type:', data.event_type);
}
};
osichatroomsSocket.onclose = function () {
console.log('WebSocket connection to rooms closed');
};
osichatroomsSocket.onerror = function (error) {
console.error('WebSocket error:', error);
};
}
getRooms();

@ -21,17 +21,20 @@
const submitButton = document.getElementById('submitMessageButton');
const typingUserId = document.getElementById('userId').textContent.trim();
let typingTimeout;
let isTyping = false;
// EVENT LISTENERS
textarea.addEventListener('input', function () {
// Adjust textarea and button
adjustTextAreaAndButton(dynamicTextarea, submitButton);
console.log(chatWebSocket);
chatWebSocket.send(JSON.stringify({
'event_type': 'typing',
'user_id': typingUserId,
'typing_status': 'typing'
}));
if (!isTyping){
chatWebSocket.send(JSON.stringify({
'event_type': 'typing',
'user_id': typingUserId,
'typing_status': 'typing'
}));
isTyping = true;
}
clearTimeout(typingTimeout);
typingTimeout = setTimeout(function() {
@ -40,6 +43,7 @@
'user_id': typingUserId,
'typing_status': 'stopped_typing'
}));
isTyping = false;
}, 3000);
});

@ -1,9 +1,10 @@
const chat_ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
const protocol = window.location.protocol === "https:" ? "https" : "http";
const domain = "osina.ositcom.com";
const domain = "192.168.1.111:8000";
let osichatSocket;
let isOpen = false;
let chatLoaded = false;
let newMessageCount = 0;
function scrollBottom() {
@ -13,13 +14,31 @@ function scrollBottom() {
}
}
function showNewMessageNotification(count) {
const newMessagesPopMessage = document.getElementById('newMessagesPopMessage');
const newMessagesCounter = document.getElementById('newMessagesCounter');
if (newMessagesPopMessage && newMessagesCounter) {
newMessagesCounter.textContent = count;
newMessagesPopMessage.classList.remove('hidden');
console.log('popup displayed')
}
}
function hideNewMessageNotification() {
const newMessagesPopMessage = document.getElementById('newMessagesPopMessage');
if (newMessagesPopMessage) {
newMessagesPopMessage.classList.add('hidden');
}
}
// FUNCTION TO FETCH THE SESSION ID
async function fetchSessionID() {
let session_id = 'Unknown';
while (session_id === 'Unknown') {
try {
const response = await fetch('https://ositcom.com/get-client-session/');
const response = await fetch('http://192.168.1.111:3000/get-client-session/');
const data = await response.json();
if (data.session_id) {
session_id = data.session_id;
@ -46,6 +65,8 @@ function hideLoader() {
}
}
// FUNCTION TO APPEND THE TEXTAREA SCRIPT
function appendTextAreaScript(domain, chatDiv) {
const textareaScript = document.createElement('script');
@ -150,6 +171,7 @@ async function initializeChatWebSocket() {
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);
@ -158,11 +180,14 @@ async function initializeChatWebSocket() {
handleLoadChatEvent(data, osichatSocket);
break;
case 'typing':
typingDiv.classList.remove('hidden');
typingDiv.innerHTML = data.html;
if(!typingDiv && data.user){
messagesDiv.insertAdjacentHTML('beforeend', data.html);
}
break;
case 'stopped_typing':
typingDiv.classList.add('hidden');
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
@ -170,11 +195,17 @@ async function initializeChatWebSocket() {
} else {
osichatSocket.send(JSON.stringify({ 'event_type': 'update_read_messages', 'chat_state': 'closed' }));
}
const messagesDiv = document.getElementById('messages');
messagesDiv.insertAdjacentHTML('beforeend', data.html);
if (data.user) { // If it is sent by an Osina user play a notification sound for the guest
const notificationSound = document.getElementById('notification-sound');
notificationSound.play();
if (typingDiv) {
typingDiv.remove();
}
let count = newMessageCount + 1;
newMessageCount = count;
showNewMessageNotification(count);
}
break;
case 'uploaded_file':

@ -28,10 +28,33 @@
const textarea = document.querySelector('#dynamicTextarea');
const conversationContainer = document.getElementById('conversation');
const submitButton = document.getElementById('submitMessageButton');
let typingTimeout;
let isTyping = false;
// EVENT LISTENERS
textarea.addEventListener('input', () => adjustTextAreaAndButton(textarea, submitButton));
textarea.addEventListener('input', function () {
// Adjust textarea and button
adjustTextAreaAndButton(dynamicTextarea, submitButton);
if (!isTyping) {
osichatSocket.send(JSON.stringify({
'event_type': 'typing',
'typing_status': 'typing'
}));
isTyping = true;
}
clearTimeout(typingTimeout);
typingTimeout = setTimeout(function() {
osichatSocket.send(JSON.stringify({
'event_type': 'typing',
'typing_status': 'stopped_typing'
}));
isTyping = false;
}, 3000);
});
form.addEventListener('submit', (event) => {
textarea.style.height = '50px';

@ -1,5 +1,5 @@
(function () {
const imageDomain = "https://osina.ositcom.com";
const imageDomain = "http://192.168.1.111:8000";
// TO TRIGGER TEH FILE UPLOADER WHEN CLICKING ON THE UPLOAD FILE SVG
document.getElementById('svgFileUpload').addEventListener('click', function () {

@ -1,11 +1,11 @@
const visitors_ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
const my_domain = "osina.ositcom.com";
const my_domain = "192.168.1.111:8000";
async function fetchClientData() {
let clientData = { client_ip: 'Unknown', client_country: 'Unknown' };
while (clientData.client_ip === 'Unknown') {
try {
const response = await fetch('https://osina.ositcom.com/get-client-ip/');
const response = await fetch('http://192.168.1.111:8000/get-client-ip/');
const data = await response.json();
if (data.ip) {
clientData = {
@ -25,7 +25,7 @@ async function fetchVisitorsSession() {
let session_id = 'Unknown';
while (session_id === 'Unknown') {
try {
const response = await fetch('https://ositcom.com/get-client-session/');
const response = await fetch('http://192.168.1.111:3000/get-client-session/');
const data = await response.json();
if (data.session_id) {
session_id = data.session_id;

Loading…
Cancel
Save