2025-12-15 11:03:30 +05:30
|
|
|
@extends('admin.layouts.app')
|
|
|
|
|
|
|
|
|
|
@section('page-title', 'Chat With ' . ($ticket->user->customer_name ?? $ticket->user->name))
|
|
|
|
|
|
|
|
|
|
@section('content')
|
|
|
|
|
<style>
|
2025-12-19 11:00:34 +05:30
|
|
|
:root {
|
|
|
|
|
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
--primary-soft: rgba(102, 126, 234, 0.12);
|
|
|
|
|
--message-admin: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
--message-user: #ffffff;
|
|
|
|
|
--bg-pattern: #0f172a;
|
|
|
|
|
--border-radius-lg: 18px;
|
|
|
|
|
--border-radius-sm: 12px;
|
|
|
|
|
--shadow-soft: 0 18px 45px rgba(15, 23, 42, 0.4);
|
|
|
|
|
--shadow-chip: 0 4px 12px rgba(15, 23, 42, 0.35);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
background: radial-gradient(circle at top, #1f2937 0, #020617 55%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-container {
|
|
|
|
|
max-width: 1180px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* glass card wrapper */
|
|
|
|
|
.chat-shell {
|
|
|
|
|
border-radius: 26px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
background: radial-gradient(circle at top left, rgba(148, 163, 184, 0.15), rgba(15, 23, 42, 0.95));
|
|
|
|
|
box-shadow: var(--shadow-soft);
|
|
|
|
|
border: 1px solid rgba(148, 163, 184, 0.35);
|
|
|
|
|
backdrop-filter: blur(22px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-header {
|
|
|
|
|
background: radial-gradient(circle at top left, #4f46e5 0%, #4338ca 35%, #0f172a 100%);
|
|
|
|
|
padding: 18px 26px;
|
|
|
|
|
color: #e5e7eb;
|
|
|
|
|
position: relative;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-header::before {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: -40%;
|
|
|
|
|
background:
|
|
|
|
|
radial-gradient(circle at 0% 0%, rgba(248, 250, 252, 0.15), transparent 55%),
|
|
|
|
|
radial-gradient(circle at 80% 0%, rgba(248, 250, 252, 0.12), transparent 55%);
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-header-content {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-avatar {
|
|
|
|
|
width: 50px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
background: radial-gradient(circle at 0 0, #f97316 0, #ec4899 50%, #6366f1 100%);
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
color: #f9fafb;
|
|
|
|
|
border: 2px solid rgba(248, 250, 252, 0.3);
|
|
|
|
|
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-details h4 {
|
|
|
|
|
margin: 0;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
color: #f9fafb;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-details h4 span {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
padding: 2px 8px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
background: rgba(15, 23, 42, 0.55);
|
|
|
|
|
color: #e5e7eb;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.06em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-details p {
|
|
|
|
|
margin: 4px 0 0;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
color: #c7d2fe;
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.status-badge {
|
|
|
|
|
padding: 6px 14px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
|
border: 1px solid rgba(15, 23, 42, 0.5);
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 6px;
|
|
|
|
|
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.status-badge.open {
|
|
|
|
|
background: radial-gradient(circle at 0 0, #22c55e 0, #16a34a 60%, #15803d 100%);
|
|
|
|
|
color: #ecfdf3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.status-badge.closed {
|
|
|
|
|
background: radial-gradient(circle at 0 0, #fb7185 0, #ef4444 60%, #b91c1c 100%);
|
|
|
|
|
color: #fef2f2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.back-btn {
|
|
|
|
|
background: rgba(15, 23, 42, 0.6);
|
|
|
|
|
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
|
|
|
color: #e5e7eb;
|
|
|
|
|
padding: 7px 18px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
letter-spacing: 0.06em;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 6px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.7);
|
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.back-btn svg {
|
|
|
|
|
width: 16px;
|
|
|
|
|
height: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.back-btn:hover {
|
|
|
|
|
background: rgba(15, 23, 42, 0.9);
|
|
|
|
|
transform: translateX(-3px);
|
|
|
|
|
border-color: #e5e7eb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box {
|
|
|
|
|
height: calc(100vh - 320px);
|
|
|
|
|
min-height: 420px;
|
|
|
|
|
max-height: 620px;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
background: radial-gradient(circle at top left, rgba(15, 23, 42, 0.9), rgba(15, 23, 42, 1));
|
|
|
|
|
padding: 20px 22px;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box::before {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
|
|
|
|
background:
|
|
|
|
|
radial-gradient(circle at 15% 25%, rgba(56, 189, 248, 0.12) 0, transparent 55%),
|
|
|
|
|
radial-gradient(circle at 80% 80%, rgba(129, 140, 248, 0.1) 0, transparent 50%);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box-inner {
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box::-webkit-scrollbar {
|
|
|
|
|
width: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box::-webkit-scrollbar-track {
|
|
|
|
|
background: rgba(15, 23, 42, 0.9);
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-box::-webkit-scrollbar-thumb {
|
|
|
|
|
background: linear-gradient(180deg, #4f46e5, #22d3ee);
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message {
|
|
|
|
|
max-width: 68%;
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
margin-bottom: 14px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
line-height: 1.55;
|
|
|
|
|
position: relative;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
border-radius: 14px;
|
|
|
|
|
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.7);
|
|
|
|
|
animation: messageSlideIn 0.22s ease-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes messageSlideIn {
|
|
|
|
|
from { opacity: 0; transform: translateY(6px); }
|
|
|
|
|
to { opacity: 1; transform: translateY(0); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.admin {
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
background: radial-gradient(circle at 0 0, #4f46e5 0, #6366f1 40%, #22d3ee 100%);
|
|
|
|
|
color: #eef2ff;
|
|
|
|
|
border-radius: 14px 14px 4px 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.user {
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
background: rgba(15, 23, 42, 0.9);
|
|
|
|
|
border-radius: 14px 14px 14px 4px;
|
|
|
|
|
border: 1px solid rgba(148, 163, 184, 0.8);
|
|
|
|
|
color: #e5e7eb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message img {
|
|
|
|
|
max-width: 210px;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
display: block;
|
|
|
|
|
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.8);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message img:hover {
|
|
|
|
|
transform: translateY(-2px) scale(1.01);
|
|
|
|
|
box-shadow: 0 16px 40px rgba(15, 23, 42, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* File preview container */
|
|
|
|
|
.file-preview {
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
background: rgba(15, 23, 42, 0.55);
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
color: inherit;
|
|
|
|
|
max-width: 250px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.admin .file-item {
|
|
|
|
|
background: rgba(15, 23, 42, 0.5);
|
|
|
|
|
border-color: rgba(226, 232, 240, 0.7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.user .file-item {
|
|
|
|
|
background: rgba(15, 23, 42, 0.7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-item:hover {
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
background: rgba(15, 23, 42, 0.8);
|
|
|
|
|
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-icon {
|
|
|
|
|
width: 32px;
|
|
|
|
|
height: 32px;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.image-file .file-icon {
|
|
|
|
|
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pdf-file .file-icon {
|
|
|
|
|
background: linear-gradient(135deg, #ef4444, #dc2626);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.video-file .file-icon {
|
|
|
|
|
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.document-file .file-icon {
|
|
|
|
|
background: linear-gradient(135deg, #10b981, #059669);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.other-file .file-icon {
|
|
|
|
|
background: linear-gradient(135deg, #6b7280, #4b5563);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-info {
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-width: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-name {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
margin-bottom: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-size {
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-download-btn {
|
|
|
|
|
background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
border: none;
|
|
|
|
|
width: 24px;
|
|
|
|
|
height: 24px;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-download-btn svg {
|
|
|
|
|
width: 12px;
|
|
|
|
|
height: 12px;
|
|
|
|
|
color: #cbd5e1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-download-btn:hover {
|
|
|
|
|
background: rgba(255, 255, 255, 0.2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message small {
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
display: block;
|
|
|
|
|
text-align: right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.user small {
|
|
|
|
|
text-align: left;
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message.admin small {
|
|
|
|
|
color: #e0f2fe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.date-divider {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin: 18px 0;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.date-divider::before,
|
|
|
|
|
.date-divider::after {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 50%;
|
|
|
|
|
width: 40%;
|
|
|
|
|
height: 1px;
|
|
|
|
|
background: radial-gradient(circle, rgba(148, 163, 184, 0.6), transparent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.date-divider::before {
|
|
|
|
|
left: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.date-divider::after {
|
|
|
|
|
right: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.date-divider span {
|
|
|
|
|
background: rgba(15, 23, 42, 0.95);
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
border: 1px solid rgba(55, 65, 81, 0.8);
|
|
|
|
|
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-input-container {
|
|
|
|
|
background: radial-gradient(circle at top, rgba(15, 23, 42, 0.95), #020617);
|
|
|
|
|
padding: 14px 18px 18px;
|
|
|
|
|
border-top: 1px solid rgba(31, 41, 55, 0.9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-input-wrapper {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
background: rgba(15, 23, 42, 0.95);
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
padding: 4px 4px 4px 18px;
|
|
|
|
|
border: 1px solid rgba(55, 65, 81, 0.9);
|
|
|
|
|
transition: all 0.18s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-input-wrapper:focus-within {
|
|
|
|
|
border-color: #6366f1;
|
|
|
|
|
box-shadow: 0 0 0 1px rgba(129, 140, 248, 0.9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-input-wrapper input[type="text"] {
|
|
|
|
|
flex: 1;
|
|
|
|
|
border: none;
|
|
|
|
|
background: transparent;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
outline: none;
|
|
|
|
|
color: #e5e7eb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chat-input-wrapper input[type="text"]::placeholder {
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-container {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-btn {
|
|
|
|
|
position: relative;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-btn input[type="file"] {
|
|
|
|
|
position: absolute;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
inset: 0;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-btn label {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
width: 40px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
background: radial-gradient(circle at 0 0, #22c55e 0, #22c55e 40%, #16a34a 100%);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
box-shadow: 0 10px 25px rgba(22, 163, 74, 0.7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-btn label svg {
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
color: #ecfdf5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload-btn label:hover {
|
|
|
|
|
transform: translateY(-1px) scale(1.03);
|
|
|
|
|
filter: brightness(1.05);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-name-display {
|
|
|
|
|
background: rgba(15, 23, 42, 0.7);
|
|
|
|
|
border: 1px solid rgba(55, 65, 81, 0.8);
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
padding: 6px 10px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
max-width: 150px;
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.clear-file-btn {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: #ef4444;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
padding: 4px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
display: none;
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.clear-file-btn:hover {
|
|
|
|
|
background: rgba(239, 68, 68, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.clear-file-btn svg {
|
|
|
|
|
width: 14px;
|
|
|
|
|
height: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.send-btn {
|
|
|
|
|
background: radial-gradient(circle at 0 0, #38bdf8 0, #6366f1 50%, #4f46e5 100%);
|
|
|
|
|
border: none;
|
|
|
|
|
width: 44px;
|
|
|
|
|
height: 44px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
box-shadow: 0 12px 28px rgba(37, 99, 235, 0.85);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.send-btn svg {
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
color: #eff6ff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.send-btn:hover {
|
|
|
|
|
transform: translateY(-1px) scale(1.04);
|
|
|
|
|
box-shadow: 0 18px 40px rgba(37, 99, 235, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.send-btn:active {
|
|
|
|
|
transform: scale(0.96);
|
|
|
|
|
box-shadow: 0 8px 22px rgba(30, 64, 175, 0.9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.typing-indicator {
|
|
|
|
|
display: none;
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
background: rgba(15, 23, 42, 0.95);
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
max-width: 70px;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
box-shadow: 0 10px 25px rgba(15, 23, 42, 0.9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.typing-indicator span {
|
|
|
|
|
height: 6px;
|
|
|
|
|
width: 6px;
|
|
|
|
|
background: #a5b4fc;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
margin: 0 2px;
|
|
|
|
|
animation: typing 1.2s infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.typing-indicator span:nth-child(2) {
|
|
|
|
|
animation-delay: 0.15s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.typing-indicator span:nth-child(3) {
|
|
|
|
|
animation-delay: 0.3s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes typing {
|
|
|
|
|
0%, 60%, 100% {
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
opacity: 0.5;
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
2025-12-19 11:00:34 +05:30
|
|
|
30% {
|
|
|
|
|
transform: translateY(-6px);
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
.chat-container {
|
|
|
|
|
padding: 10px;
|
|
|
|
|
}
|
|
|
|
|
.chat-shell {
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
}
|
|
|
|
|
.chat-header-content {
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.user-info {
|
|
|
|
|
width: 100%;
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
2025-12-19 11:00:34 +05:30
|
|
|
.header-actions {
|
|
|
|
|
width: 100%;
|
|
|
|
|
justify-content: space-between;
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
2025-12-19 11:00:34 +05:30
|
|
|
.back-btn {
|
|
|
|
|
padding-inline: 12px;
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
2025-12-19 11:00:34 +05:30
|
|
|
.message {
|
|
|
|
|
max-width: 85%;
|
|
|
|
|
}
|
|
|
|
|
.chat-box {
|
|
|
|
|
height: calc(100vh - 360px);
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
2025-12-19 11:00:34 +05:30
|
|
|
.file-name-display {
|
|
|
|
|
max-width: 100px;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-15 11:03:30 +05:30
|
|
|
</style>
|
|
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<div class="chat-container">
|
|
|
|
|
<div class="chat-shell">
|
|
|
|
|
<div class="chat-header">
|
|
|
|
|
<div class="chat-header-content">
|
|
|
|
|
<div class="user-info">
|
|
|
|
|
<div class="user-avatar">
|
|
|
|
|
{{ strtoupper(substr(($ticket->user->customer_name ?? $ticket->user->name), 0, 1)) }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="user-details">
|
|
|
|
|
<h4>
|
|
|
|
|
{{ $ticket->user->customer_name ?? $ticket->user->name }}
|
|
|
|
|
<span>Online</span>
|
|
|
|
|
</h4>
|
|
|
|
|
<p>Ticket #{{ $ticket->id }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
<span class="status-badge {{ $ticket->status === 'open' ? 'open' : 'closed' }}">
|
|
|
|
|
{{ ucfirst($ticket->status) }}
|
|
|
|
|
</span>
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<a href="{{ route('admin.chat_support') }}" class="back-btn">
|
|
|
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Back
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
{{-- Messages --}}
|
|
|
|
|
<div id="chatBox" class="chat-box">
|
|
|
|
|
<div class="chat-box-inner">
|
|
|
|
|
@foreach($messages as $msg)
|
|
|
|
|
<div class="message {{ $msg->sender_type === 'App\\Models\\Admin' ? 'admin' : 'user' }}">
|
|
|
|
|
@if($msg->message)
|
|
|
|
|
<div>{{ $msg->message }}</div>
|
|
|
|
|
@endif
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
@if($msg->file_path)
|
|
|
|
|
@php
|
|
|
|
|
$isImage = Str::startsWith($msg->file_type, 'image');
|
|
|
|
|
$isVideo = Str::startsWith($msg->file_type, 'video');
|
|
|
|
|
$isPdf = Str::endsWith($msg->file_path, '.pdf');
|
|
|
|
|
$isDocument = in_array(Str::lower(Str::afterLast($msg->file_path, '.')), ['doc', 'docx', 'txt']);
|
|
|
|
|
$fileName = basename($msg->file_path);
|
|
|
|
|
|
|
|
|
|
// Get file size from storage if possible
|
|
|
|
|
$fileSize = 'N/A';
|
|
|
|
|
try {
|
|
|
|
|
$fullPath = storage_path('app/public/' . $msg->file_path);
|
|
|
|
|
if (file_exists($fullPath)) {
|
|
|
|
|
$size = filesize($fullPath);
|
|
|
|
|
if ($size < 1024) {
|
|
|
|
|
$fileSize = $size . ' B';
|
|
|
|
|
} elseif ($size < 1048576) {
|
|
|
|
|
$fileSize = round($size / 1024, 1) . ' KB';
|
|
|
|
|
} else {
|
|
|
|
|
$fileSize = round($size / 1048576, 1) . ' MB';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
$fileSize = 'Unknown';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine file class
|
|
|
|
|
if ($isImage) {
|
|
|
|
|
$fileClass = 'image-file';
|
|
|
|
|
$fileIcon = '🖼️';
|
|
|
|
|
} elseif ($isVideo) {
|
|
|
|
|
$fileClass = 'video-file';
|
|
|
|
|
$fileIcon = '🎬';
|
|
|
|
|
} elseif ($isPdf) {
|
|
|
|
|
$fileClass = 'pdf-file';
|
|
|
|
|
$fileIcon = '📄';
|
|
|
|
|
} elseif ($isDocument) {
|
|
|
|
|
$fileClass = 'document-file';
|
|
|
|
|
$fileIcon = '📝';
|
|
|
|
|
} else {
|
|
|
|
|
$fileClass = 'other-file';
|
|
|
|
|
$fileIcon = '📎';
|
|
|
|
|
}
|
|
|
|
|
@endphp
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<div class="file-preview">
|
|
|
|
|
@if($isImage)
|
|
|
|
|
<img src="{{ asset('storage/'.$msg->file_path) }}"
|
|
|
|
|
style="max-width:210px;"
|
|
|
|
|
class="rounded mt-2"
|
|
|
|
|
alt="{{ $fileName }}">
|
|
|
|
|
@elseif($isVideo)
|
|
|
|
|
<video src="{{ asset('storage/'.$msg->file_path) }}"
|
|
|
|
|
controls
|
|
|
|
|
class="mt-2 rounded"
|
|
|
|
|
style="max-width:200px;">
|
|
|
|
|
Your browser does not support the video tag.
|
|
|
|
|
</video>
|
|
|
|
|
@endif
|
|
|
|
|
|
|
|
|
|
<a href="{{ asset('storage/'.$msg->file_path) }}"
|
|
|
|
|
target="_blank"
|
|
|
|
|
class="file-item {{ $fileClass }}"
|
|
|
|
|
title="{{ $fileName }}">
|
|
|
|
|
<div class="file-icon">
|
|
|
|
|
{{ $fileIcon }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="file-info">
|
|
|
|
|
<div class="file-name">{{ $fileName }}</div>
|
|
|
|
|
<div class="file-size">{{ $fileSize }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="file-download-btn">
|
|
|
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
|
|
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
@endif
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<small class="mt-2">
|
|
|
|
|
{{ $msg->created_at->format('d M h:i A') }}
|
|
|
|
|
</small>
|
|
|
|
|
</div>
|
|
|
|
|
@endforeach
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<div class="typing-indicator" id="typingIndicator">
|
|
|
|
|
<span></span>
|
|
|
|
|
<span></span>
|
|
|
|
|
<span></span>
|
|
|
|
|
</div>
|
2025-12-15 11:03:30 +05:30
|
|
|
</div>
|
2025-12-19 11:00:34 +05:30
|
|
|
</div>
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
{{-- Input --}}
|
|
|
|
|
<div class="chat-input-container">
|
|
|
|
|
<div class="chat-input-wrapper">
|
|
|
|
|
<input type="text" id="messageInput" placeholder="Type a reply…" autocomplete="off">
|
|
|
|
|
|
|
|
|
|
<div class="file-upload-container">
|
|
|
|
|
<div class="file-name-display" id="fileNameDisplay"></div>
|
|
|
|
|
<button class="clear-file-btn" id="clearFileBtn" title="Remove file">
|
|
|
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<div class="file-upload-btn">
|
|
|
|
|
<input type="file" id="fileInput">
|
|
|
|
|
<label for="fileInput" title="Attach file">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
|
|
|
viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round"
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" />
|
|
|
|
|
</svg>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
<button class="send-btn" id="sendBtn">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
|
|
|
viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round"
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
2025-12-15 11:03:30 +05:30
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@endsection
|
|
|
|
|
|
|
|
|
|
@section('scripts')
|
|
|
|
|
<script>
|
2025-12-19 11:00:34 +05:30
|
|
|
const CURRENT_ADMIN_ID = {{ auth('admin')->id() }};
|
2025-12-15 11:03:30 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
// ✅ Make current admin ID available to JS
|
2025-12-15 11:03:30 +05:30
|
|
|
console.log("CHAT WINDOW: script loaded");
|
|
|
|
|
|
|
|
|
|
// -------------------------------
|
|
|
|
|
// WAIT FOR ECHO READY
|
|
|
|
|
// -------------------------------
|
|
|
|
|
function waitForEcho(callback, retries = 40) {
|
|
|
|
|
if (window.Echo) {
|
|
|
|
|
console.log("%c[ECHO] Ready!", "color: green; font-weight: bold;", window.Echo);
|
|
|
|
|
return callback();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.warn("[ECHO] Not ready. Retrying...");
|
|
|
|
|
if (retries <= 0) {
|
|
|
|
|
console.error("[ECHO] FAILED to initialize after retry limit");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setTimeout(() => waitForEcho(callback, retries - 1), 200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scroll chat down
|
|
|
|
|
function scrollToBottom() {
|
|
|
|
|
const el = document.getElementById("chatBox");
|
|
|
|
|
if (el) el.scrollTop = el.scrollHeight;
|
|
|
|
|
}
|
|
|
|
|
scrollToBottom();
|
|
|
|
|
|
|
|
|
|
// -------------------------------
|
2025-12-19 11:00:34 +05:30
|
|
|
// FILE UPLOAD HANDLING
|
|
|
|
|
// -------------------------------
|
|
|
|
|
const fileInput = document.getElementById('fileInput');
|
|
|
|
|
const fileNameDisplay = document.getElementById('fileNameDisplay');
|
|
|
|
|
const clearFileBtn = document.getElementById('clearFileBtn');
|
|
|
|
|
|
|
|
|
|
fileInput.addEventListener('change', function(e) {
|
|
|
|
|
if (this.files.length > 0) {
|
|
|
|
|
const file = this.files[0];
|
|
|
|
|
const fileName = file.name;
|
|
|
|
|
const fileSize = formatFileSize(file.size);
|
|
|
|
|
|
|
|
|
|
fileNameDisplay.textContent = `${fileName} (${fileSize})`;
|
|
|
|
|
fileNameDisplay.style.display = 'block';
|
|
|
|
|
clearFileBtn.style.display = 'block';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
clearFileBtn.addEventListener('click', function() {
|
|
|
|
|
fileInput.value = '';
|
|
|
|
|
fileNameDisplay.style.display = 'none';
|
|
|
|
|
clearFileBtn.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function formatFileSize(bytes) {
|
|
|
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
|
const k = 1024;
|
|
|
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getFileIcon(fileType, fileName) {
|
|
|
|
|
if (fileType.startsWith('image/')) {
|
|
|
|
|
return '🖼️';
|
|
|
|
|
} else if (fileType.startsWith('video/')) {
|
|
|
|
|
return '🎬';
|
|
|
|
|
} else if (fileName.endsWith('.pdf')) {
|
|
|
|
|
return '📄';
|
|
|
|
|
} else if (fileName.match(/\.(doc|docx|txt)$/i)) {
|
|
|
|
|
return '📝';
|
|
|
|
|
} else {
|
|
|
|
|
return '📎';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getFileClass(fileType, fileName) {
|
|
|
|
|
if (fileType.startsWith('image/')) {
|
|
|
|
|
return 'image-file';
|
|
|
|
|
} else if (fileType.startsWith('video/')) {
|
|
|
|
|
return 'video-file';
|
|
|
|
|
} else if (fileName.endsWith('.pdf')) {
|
|
|
|
|
return 'pdf-file';
|
|
|
|
|
} else if (fileName.match(/\.(doc|docx|txt)$/i)) {
|
|
|
|
|
return 'document-file';
|
|
|
|
|
} else {
|
|
|
|
|
return 'other-file';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -------------------------------
|
|
|
|
|
// SEND MESSAGE
|
2025-12-15 11:03:30 +05:30
|
|
|
// -------------------------------
|
|
|
|
|
document.getElementById("sendBtn").addEventListener("click", function () {
|
|
|
|
|
console.log("[SEND] Attempting to send message...");
|
|
|
|
|
|
|
|
|
|
let msg = document.getElementById("messageInput").value;
|
|
|
|
|
let file = document.getElementById("fileInput").files[0];
|
|
|
|
|
|
|
|
|
|
if (!msg.trim() && !file) {
|
|
|
|
|
alert("Please type something or upload a file.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let formData = new FormData();
|
|
|
|
|
formData.append("message", msg);
|
|
|
|
|
if (file) formData.append("file", file);
|
|
|
|
|
|
|
|
|
|
fetch("{{ route('admin.chat.send', $ticket->id) }}", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: { "X-CSRF-TOKEN": "{{ csrf_token() }}" },
|
|
|
|
|
body: formData
|
|
|
|
|
})
|
|
|
|
|
.then(res => res.json())
|
|
|
|
|
.then((response) => {
|
|
|
|
|
console.log("[SEND] Message sent:", response);
|
|
|
|
|
document.getElementById("messageInput").value = "";
|
|
|
|
|
document.getElementById("fileInput").value = "";
|
2025-12-19 11:00:34 +05:30
|
|
|
fileNameDisplay.style.display = 'none';
|
|
|
|
|
clearFileBtn.style.display = 'none';
|
|
|
|
|
scrollToBottom();
|
2025-12-15 11:03:30 +05:30
|
|
|
})
|
|
|
|
|
.catch(err => console.error("[SEND] Error:", err));
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
// Enter key support
|
|
|
|
|
document.getElementById("messageInput").addEventListener("keypress", function(e) {
|
|
|
|
|
if (e.key === "Enter") {
|
|
|
|
|
document.getElementById("sendBtn").click();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-15 11:03:30 +05:30
|
|
|
// -------------------------------
|
2025-12-19 11:00:34 +05:30
|
|
|
// LISTEN FOR REALTIME MESSAGE
|
2025-12-15 11:03:30 +05:30
|
|
|
// ----------------------------
|
|
|
|
|
waitForEcho(() => {
|
|
|
|
|
const ticketId = "{{ $ticket->id }}";
|
|
|
|
|
|
|
|
|
|
console.log("[ECHO] Subscribing to PRIVATE channel:", `ticket.${ticketId}`);
|
|
|
|
|
|
|
|
|
|
window.Echo.private(`ticket.${ticketId}`)
|
|
|
|
|
.listen(".NewChatMessage", (event) => {
|
|
|
|
|
|
|
|
|
|
console.log("%c[REALTIME RECEIVED]", "color: blue; font-weight: bold;", event);
|
|
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
const msg = event;
|
2025-12-15 11:03:30 +05:30
|
|
|
const isMine =
|
|
|
|
|
msg.sender_type === 'App\\Models\\Admin' &&
|
|
|
|
|
msg.sender_id === CURRENT_ADMIN_ID;
|
|
|
|
|
|
|
|
|
|
let html = `
|
|
|
|
|
<div class="message ${isMine ? 'admin' : 'user'}">
|
2025-12-19 11:00:34 +05:30
|
|
|
${msg.message ? `<div>${msg.message}</div>` : ''}
|
2025-12-15 11:03:30 +05:30
|
|
|
`;
|
|
|
|
|
|
2025-12-16 10:19:54 +05:30
|
|
|
if (msg.file_path) {
|
|
|
|
|
const fileUrl = `/storage/${msg.file_path}`;
|
2025-12-19 11:00:34 +05:30
|
|
|
const fileName = msg.file_path.split('/').pop();
|
|
|
|
|
const fileSize = msg.file_size ? formatFileSize(msg.file_size) : 'Unknown';
|
|
|
|
|
const fileIcon = getFileIcon(msg.file_type || '', fileName);
|
|
|
|
|
const fileClass = getFileClass(msg.file_type || '', fileName);
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
// Check if it's image or video for preview
|
|
|
|
|
const isImage = (msg.file_type || '').startsWith('image');
|
|
|
|
|
const isVideo = (msg.file_type || '').startsWith('video');
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
html += `<div class="file-preview">`;
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
if (isImage) {
|
2025-12-16 10:19:54 +05:30
|
|
|
html += `
|
2025-12-19 11:00:34 +05:30
|
|
|
<img src="${fileUrl}"
|
|
|
|
|
class="rounded mt-2"
|
|
|
|
|
style="max-width:210px;"
|
|
|
|
|
alt="${fileName}">
|
2025-12-16 10:19:54 +05:30
|
|
|
`;
|
2025-12-19 11:00:34 +05:30
|
|
|
} else if (isVideo) {
|
2025-12-16 10:19:54 +05:30
|
|
|
html += `
|
2025-12-19 11:00:34 +05:30
|
|
|
<video src="${fileUrl}"
|
|
|
|
|
controls
|
|
|
|
|
class="mt-2 rounded"
|
|
|
|
|
style="max-width:200px;">
|
|
|
|
|
</video>
|
2025-12-16 10:19:54 +05:30
|
|
|
`;
|
2025-12-15 11:03:30 +05:30
|
|
|
}
|
|
|
|
|
|
2025-12-19 11:00:34 +05:30
|
|
|
html += `
|
|
|
|
|
<a href="${fileUrl}"
|
|
|
|
|
target="_blank"
|
|
|
|
|
class="file-item ${fileClass}"
|
|
|
|
|
title="${fileName}">
|
|
|
|
|
<div class="file-icon">
|
|
|
|
|
${fileIcon}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="file-info">
|
|
|
|
|
<div class="file-name">${fileName}</div>
|
|
|
|
|
<div class="file-size">${fileSize}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="file-download-btn">
|
|
|
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
|
|
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
</a>
|
|
|
|
|
</div>`;
|
|
|
|
|
}
|
2025-12-16 10:19:54 +05:30
|
|
|
|
2025-12-15 11:03:30 +05:30
|
|
|
html += `
|
2025-12-19 11:00:34 +05:30
|
|
|
<small class="mt-2">Just now</small>
|
2025-12-15 11:03:30 +05:30
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
document
|
2025-12-19 11:00:34 +05:30
|
|
|
.querySelector("#chatBox .chat-box-inner")
|
2025-12-15 11:03:30 +05:30
|
|
|
.insertAdjacentHTML("beforeend", html);
|
|
|
|
|
|
|
|
|
|
scrollToBottom();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
</script>
|
2025-12-19 11:00:34 +05:30
|
|
|
@endsection
|