new
							parent
							
								
									ccbec47cab
								
							
						
					
					
						commit
						988ac3a2d7
					
				
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,99 @@ | ||||
| from channels.generic.websocket import WebsocketConsumer  | ||||
| from django.shortcuts import get_object_or_404 | ||||
| from customercore.models import *  | ||||
| import json | ||||
| from django.template.loader import render_to_string | ||||
| from asgiref.sync import async_to_sync | ||||
| from channels.generic.websocket import WebsocketConsumer  | ||||
| from django.shortcuts import get_object_or_404 | ||||
| from customercore.models import *  | ||||
| import json | ||||
| from django.template.loader import render_to_string | ||||
| from asgiref.sync import async_to_sync | ||||
| 
 | ||||
| 
 | ||||
| class TicketRoomConsumer(WebsocketConsumer): | ||||
|     def connect(self):  | ||||
|         self.user = self.scope['user'] | ||||
|         self.ticket_id = self.scope['url_route']['kwargs']['ticket_id'] | ||||
|         self.ticket = get_object_or_404(Ticket, id=self.ticket_id) | ||||
|         self.ticket_number = self.ticket.ticket_number | ||||
|         async_to_sync(self.channel_layer.group_add)( | ||||
|             self.ticket_number, self.channel_name  | ||||
|         ) | ||||
|         self.accept() | ||||
| 
 | ||||
|     def disconnect(self, close_code): | ||||
|         async_to_sync(self.channel_layer.group_discard)( | ||||
|            self.ticket_number, self.channel_name  | ||||
|         ) | ||||
| 
 | ||||
|     def receive(self, text_data):  | ||||
|         text_data_json = json.loads(text_data) | ||||
|         event_type = text_data_json.get('event_type') | ||||
|          | ||||
|         if event_type == 'typing': | ||||
|             event = { | ||||
|                 'type': 'typing_handler', | ||||
|                 'user': self.scope['user'] | ||||
|             } | ||||
|             async_to_sync(self.channel_layer.group_send)( | ||||
|                 self.ticket_number, event | ||||
|             ) | ||||
|         elif event_type == 'stop_typing': | ||||
|             event = { | ||||
|                 'type': 'stop_typing_handler', | ||||
|             } | ||||
|             async_to_sync(self.channel_layer.group_send)( | ||||
|                 self.ticket_number, event | ||||
|             ) | ||||
|         else: | ||||
|             body = text_data_json['description'] | ||||
|             file_paths = text_data_json['filePath'] | ||||
|             ticketupdate = TicketUpdate.objects.create( | ||||
|                 added_by=self.user, | ||||
|                 description=body, | ||||
|                 ticket=self.ticket, | ||||
|                 date_added=datetime.now() | ||||
|             ) | ||||
|             for file_path in file_paths: | ||||
|                 ticket_attachment = TicketAttachment( | ||||
|                     ticket_update=ticketupdate, | ||||
|                     file_path=file_path   | ||||
|                 ) | ||||
|                 ticket_attachment.save() | ||||
|             event = { | ||||
|                 'type': 'update_handler', | ||||
|                 'update_id': ticketupdate.id | ||||
|             } | ||||
|             async_to_sync(self.channel_layer.group_send)( | ||||
|                 self.ticket_number, event | ||||
|             ) | ||||
| 
 | ||||
|     def update_handler(self, event): | ||||
|         update_id = event['update_id'] | ||||
|         update = TicketUpdate.objects.get(id=update_id) | ||||
|         context = {  | ||||
|             'update': update, | ||||
|             'user': self.user | ||||
|         } | ||||
|         html = render_to_string("details_templates/new-ticket-message.html", context=context) | ||||
|         self.send(text_data=json.dumps({ | ||||
|             'event_type': 'update', | ||||
|             'html': html | ||||
|         })) | ||||
| 
 | ||||
|     def typing_handler(self, event): | ||||
|         context = { | ||||
|             'user': event['user'] | ||||
|         } | ||||
|         html = render_to_string("details_templates/typing-message.html", context=context) | ||||
|         self.send(text_data=json.dumps({ | ||||
|             'event_type': 'typing', | ||||
|             'html': html | ||||
|         })) | ||||
| 
 | ||||
|     def stop_typing_handler(self, event): | ||||
|         self.send(text_data=json.dumps({ | ||||
|             'event_type': 'stop_typing' | ||||
|         })) | ||||
| @ -0,0 +1,8 @@ | ||||
| from django.urls import path  | ||||
| from .consumers import * | ||||
| 
 | ||||
| websocket_urlpatterns = [ | ||||
|     path("ws/ticketroom/<int:ticket_id>/", TicketRoomConsumer.as_asgi()), | ||||
| 
 | ||||
| 
 | ||||
| ] | ||||
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,19 @@ | ||||
| <div id="messages" hx-swap-oob="beforeend">  | ||||
| 
 | ||||
|     <div class="fade-in-up"> | ||||
|         {% include 'details_templates/ticket-message.html' %} | ||||
|     </div> | ||||
|      | ||||
|     <style> | ||||
|         @keyframes fadeInAndUp { | ||||
|             from { opacity: 0; transform: translateY(12px); } | ||||
|             to { opacity: 1; transform: translateY(0px); } | ||||
|         } | ||||
|         .fade-in-up { | ||||
|             animation: fadeInAndUp 0.6s ease; | ||||
|         } | ||||
|     </style> | ||||
|      | ||||
| 
 | ||||
| </div> | ||||
|      | ||||
| @ -0,0 +1,69 @@ | ||||
| <div class="flex gap-3 mb-10"> | ||||
|     <div> | ||||
|         <div class="w-[45px] s:w-[60px] h-[45px] s:h-[60px] rounded-full shadow-md border border-gray-100"> | ||||
|             {% if update.added_by.customerprofile %} | ||||
|             {% if update.added_by.customerprofile.image %} | ||||
|             <img src="{{update.added_by.customerprofile.image.url}}" | ||||
|                 class="w-full h-full rounded-full object-cover"> | ||||
|             {% else %} | ||||
|             <div | ||||
|                 class="w-full h-full border border-secondosiblue bg-secondosiblue text-white uppercase rounded-full flex justify-center items-center p-1 shadow-md"> | ||||
|                 {{ update.added_by.first_name.0 }}{{ update.added_by.last_name.0 }} | ||||
|             </div> | ||||
|             {% endif %} | ||||
|             {% elif update.added_by.staffprofile %} | ||||
|             {% if update.added_by.staffprofile.image %} | ||||
|             <img src="{{update.added_by.staffprofile.image.url}}" | ||||
|                 class="w-full h-full rounded-full object-cover"> | ||||
|             {% else %} | ||||
|             <div | ||||
|                 class="w-full h-full border border-osiblue bg-osiblue text-white uppercase rounded-full flex justify-center items-center p-1 shadow-md"> | ||||
|                 {{ update.added_by.first_name.0 }}{{ update.added_by.last_name.0 }} | ||||
|             </div> | ||||
|             {% endif %} | ||||
|             {% endif %} | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| 
 | ||||
|     <div class="w-full replyContainer shadow-md"> | ||||
|         <div | ||||
|             class="w-full bg-gray-100 flex justify-between items-center gap-3 px-3 py-3 cursor-pointer rounded-t-md toggleReply"> | ||||
|             <p class="text-secondosiblue font-light text-sm s:text-base"><span | ||||
|                     class="font-semibold">{{update.added_by.first_name}}</span> | ||||
|                 replied {{update.date_added}}</p> | ||||
| 
 | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" | ||||
|                 stroke="currentColor" class="w-4 h-4 text-secondosiblue arrowUp"> | ||||
|                 <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 15.75 7.5-7.5 7.5 7.5" /> | ||||
|             </svg> | ||||
| 
 | ||||
| 
 | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" | ||||
|                 stroke="currentColor" class="w-4 h-4 text-secondosiblue arrowDown hidden"> | ||||
|                 <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /> | ||||
|             </svg> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="w-full bg-white p-5 flex flex-col gap-3 reply default-css"> | ||||
|             {{update.description | safe }} | ||||
| 
 | ||||
|             {% if update.ticketattachment_set.all %} | ||||
|             <div class="w-full flex flex-wrap justify-end items-center gap-3"> | ||||
|                 {% for file in update.ticketattachment_set.all %} | ||||
|                     <div | ||||
|                         class="flex items-center gap-1 text-secondosiblue hover:text-gray-500 duration-300 cursor-pointer text-sm"> | ||||
|                         <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" | ||||
|                             stroke-width="1.5" stroke="currentColor" class="w-4 h-4 text-secondosiblue"> | ||||
|                             <path stroke-linecap="round" stroke-linejoin="round" | ||||
|                                 d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" /> | ||||
|                         </svg> | ||||
|                         <a href="https://osina.ositcom.com/{{file.file_path}}" target="_blank">{{ file.file_path | cut:"static/images/uploaded_ticket_files/" }}{% if not forloop.last %}, {% endif %}</a> | ||||
|                     </div> | ||||
|                 {% endfor %} | ||||
|             </div> | ||||
|             {% endif %} | ||||
|          | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| @ -0,0 +1,36 @@ | ||||
| <div id="typing-notification" class="flex gap-3 mb-10"> | ||||
|     <div> | ||||
|         <div class="w-[45px] s:w-[60px] h-[45px] s:h-[60px] rounded-full shadow-md border border-gray-100"> | ||||
|             {% if user.customerprofile %} | ||||
|             {% if user.customerprofile.image %} | ||||
|             <img src="{{user.customerprofile.image.url}}" | ||||
|                 class="w-full h-full rounded-full object-cover"> | ||||
|             {% else %} | ||||
|             <div | ||||
|                 class="w-full h-full border border-secondosiblue bg-secondosiblue text-white uppercase rounded-full flex justify-center items-center p-1 shadow-md"> | ||||
|                 {{ user.first_name.0 }}{{ user.last_name.0 }} | ||||
|             </div> | ||||
|             {% endif %} | ||||
|             {% elif user.staffprofile %} | ||||
|             {% if user.staffprofile.image %} | ||||
|             <img src="{{user.staffprofile.image.url}}" | ||||
|                 class="w-full h-full rounded-full object-cover"> | ||||
|             {% else %} | ||||
|             <div | ||||
|                 class="w-full h-full border border-osiblue bg-osiblue text-white uppercase rounded-full flex justify-center items-center p-1 shadow-md"> | ||||
|                 {{ user.first_name.0 }}{{ user.last_name.0 }} | ||||
|             </div> | ||||
|             {% endif %} | ||||
|             {% endif %} | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| 
 | ||||
|     <div class="w-full replyContainer shadow-md"> | ||||
|         <div | ||||
|             class="w-full bg-gray-100 flex justify-between items-center gap-3 px-3 py-3 cursor-pointer rounded-t-md toggleReply"> | ||||
|             <p class="text-secondosiblue font-light text-sm s:text-base"><span | ||||
|                     class="font-semibold">{{user.first_name}}</span> is typing... </p> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								| After Width: | Height: | Size: 3.7 MiB | 
											
												Binary file not shown.
											
										
									
								| After Width: | Height: | Size: 854 KiB | 
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
					Loading…
					
					
				
		Reference in New Issue