This commit is contained in:
Utkarsh Khedkar
2025-12-19 17:27:54 +05:30
parent 80c6e42e0c
commit 3941b06355

View File

@@ -4,6 +4,7 @@
@section('content')
<style>
/* ... तुझा existing complete CSS जसाच्या तसा ठेव ... */
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--primary-soft: rgba(102, 126, 234, 0.12);
@@ -643,6 +644,32 @@ body {
max-width: 100px;
}
}
.header-notify {
position: relative;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: #cbd5f5;
}
.header-notify-badge {
min-width: 18px;
height: 18px;
border-radius: 999px;
background: #ef4444;
color: #fff;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
box-shadow: 0 0 0 2px rgba(15,23,42,0.8);
}
.header-notify.d-none {
display: none;
}
</style>
<div class="chat-container">
@@ -662,6 +689,12 @@ body {
</div>
</div>
<div class="header-actions">
{{-- perticket new message notification --}}
<div id="ticketNotifyBox" class="header-notify d-none">
New messages:
<span id="ticketNotifyCount" class="header-notify-badge">0</span>
</div>
<span class="status-badge {{ $ticket->status === 'open' ? 'open' : 'closed' }}">
{{ ucfirst($ticket->status) }}
</span>
@@ -692,8 +725,7 @@ body {
$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);
@@ -710,8 +742,7 @@ body {
} catch (Exception $e) {
$fileSize = 'Unknown';
}
// Determine file class
if ($isImage) {
$fileClass = 'image-file';
$fileIcon = '🖼️';
@@ -744,9 +775,9 @@ body {
Your browser does not support the video tag.
</video>
@endif
<a href="{{ asset('storage/'.$msg->file_path) }}"
target="_blank"
<a href="{{ asset('storage/'.$msg->file_path) }}"
target="_blank"
class="file-item {{ $fileClass }}"
title="{{ $fileName }}">
<div class="file-icon">
@@ -758,7 +789,7 @@ body {
</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"
<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>
@@ -789,10 +820,11 @@ body {
<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"/>
<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">
@@ -823,8 +855,6 @@ body {
@section('scripts')
<script>
const CURRENT_ADMIN_ID = {{ auth('admin')->id() }};
// ✅ Make current admin ID available to JS
console.log("CHAT WINDOW: script loaded");
// -------------------------------
@@ -859,13 +889,12 @@ const fileInput = document.getElementById('fileInput');
const fileNameDisplay = document.getElementById('fileNameDisplay');
const clearFileBtn = document.getElementById('clearFileBtn');
fileInput.addEventListener('change', function(e) {
fileInput.addEventListener('change', function() {
if (this.files.length > 0) {
const file = this.files[0];
const fileName = file.name;
const fileSize = formatFileSize(file.size);
fileNameDisplay.textContent = `${fileName} (${fileSize})`;
const name = file.name;
const size = formatFileSize(file.size);
fileNameDisplay.textContent = `${name} (${size})`;
fileNameDisplay.style.display = 'block';
clearFileBtn.style.display = 'block';
}
@@ -886,40 +915,26 @@ function formatFileSize(bytes) {
}
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 '📎';
}
if (fileType.startsWith('image/')) return '🖼️';
if (fileType.startsWith('video/')) return '🎬';
if (fileName.endsWith('.pdf')) return '📄';
if (fileName.match(/\.(doc|docx|txt)$/i)) return '📝';
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';
}
if (fileType.startsWith('image/')) return 'image-file';
if (fileType.startsWith('video/')) return 'video-file';
if (fileName.endsWith('.pdf')) return 'pdf-file';
if (fileName.match(/\.(doc|docx|txt)$/i)) return 'document-file';
return 'other-file';
}
// -------------------------------
// SEND MESSAGE
// -------------------------------
document.getElementById("sendBtn").addEventListener("click", function () {
console.log("[SEND] Attempting to send message...");
let msg = document.getElementById("messageInput").value;
let msg = document.getElementById("messageInput").value;
let file = document.getElementById("fileInput").files[0];
if (!msg.trim() && !file) {
@@ -937,8 +952,7 @@ document.getElementById("sendBtn").addEventListener("click", function () {
body: formData
})
.then(res => res.json())
.then((response) => {
console.log("[SEND] Message sent:", response);
.then(() => {
document.getElementById("messageInput").value = "";
document.getElementById("fileInput").value = "";
fileNameDisplay.style.display = 'none';
@@ -957,15 +971,18 @@ document.getElementById("messageInput").addEventListener("keypress", function(e)
// -------------------------------
// LISTEN FOR REALTIME MESSAGE
// ----------------------------
// -------------------------------
waitForEcho(() => {
const ticketId = "{{ $ticket->id }}";
const notifyBox = document.getElementById('ticketNotifyBox');
const notifyCount = document.getElementById('ticketNotifyCount');
let ticketNewCount = 0;
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);
const msg = event;
@@ -973,67 +990,69 @@ waitForEcho(() => {
msg.sender_type === 'App\\Models\\Admin' &&
msg.sender_id === CURRENT_ADMIN_ID;
// जर message admin ने पाठवला असेल तर त्या साठी notification वाढवायची गरज नाही
if (!isMine) {
ticketNewCount++;
if (notifyBox && notifyCount) {
notifyBox.classList.remove('d-none');
notifyCount.textContent = ticketNewCount;
}
}
let html = `
<div class="message ${isMine ? 'admin' : 'user'}">
${msg.message ? `<div>${msg.message}</div>` : ''}
`;
if (msg.file_path) {
const fileUrl = `/storage/${msg.file_path}`;
const fileUrl = `/storage/${msg.file_path}`;
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);
// Check if it's image or video for preview
const isImage = (msg.file_type || '').startsWith('image');
const isVideo = (msg.file_type || '').startsWith('video');
const fileClass= getFileClass(msg.file_type || '', fileName);
const isImage = (msg.file_type || '').startsWith('image');
const isVideo = (msg.file_type || '').startsWith('video');
html += `<div class="file-preview">`;
if (isImage) {
html += `
<img src="${fileUrl}"
class="rounded mt-2"
<img src="${fileUrl}"
class="rounded mt-2"
style="max-width:210px;"
alt="${fileName}">
`;
} else if (isVideo) {
html += `
<video src="${fileUrl}"
controls
class="mt-2 rounded"
<video src="${fileUrl}"
controls
class="mt-2 rounded"
style="max-width:200px;">
</video>
`;
}
html += `
<a href="${fileUrl}"
target="_blank"
<a href="${fileUrl}"
target="_blank"
class="file-item ${fileClass}"
title="${fileName}">
<div class="file-icon">
${fileIcon}
</div>
<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" />
<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>`;
}
html += `
<small class="mt-2">Just now</small>
</div>
`;
html += `<small class="mt-2">Just now</small></div>`;
document
.querySelector("#chatBox .chat-box-inner")
@@ -1043,4 +1062,4 @@ waitForEcho(() => {
});
});
</script>
@endsection
@endsection