Files
Kent-logistics-Laravel/resources/views/admin/chat_window.blade.php

269 lines
7.6 KiB
PHP
Raw Normal View History

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>
.chat-box {
height: 70vh;
overflow-y: auto;
background: #f5f6fa;
border-radius: 8px;
padding: 15px;
}
.message {
max-width: 65%;
padding: 10px 14px;
border-radius: 15px;
margin-bottom: 10px;
font-size: 0.9rem;
line-height: 1.4;
}
.message.admin {
background: #007bff;
color: white;
margin-left: auto;
border-bottom-right-radius: 0;
}
.message.user {
background: #ffffff;
border: 1px solid #ddd;
margin-right: auto;
border-bottom-left-radius: 0;
}
.chat-input {
position: fixed;
bottom: 15px;
left: 250px;
right: 20px;
}
</style>
<div class="container py-4">
<div class="d-flex align-items-center mb-3">
<h4 class="fw-bold mb-0">
Chat With: {{ $ticket->user->customer_name ?? $ticket->user->name }}
</h4>
<span class="badge ms-3 {{ $ticket->status === 'open' ? 'bg-success' : 'bg-danger' }}">
{{ ucfirst($ticket->status) }}
</span>
</div>
<div id="chatBox" class="chat-box border shadow-sm">
@foreach($messages as $msg)
<div class="message {{ $msg->sender_type === 'App\\Models\\Admin' ? 'admin' : 'user' }}">
{{-- TEXT --}}
@if($msg->message)
<div>{{ $msg->message }}</div>
@endif
{{-- FILE --}}
@if($msg->file_path)
2025-12-16 10:19:54 +05:30
@php
$isImage = Str::startsWith($msg->file_type, 'image');
$isVideo = Str::startsWith($msg->file_type, 'video');
@endphp
{{-- IMAGE --}}
@if($isImage)
<img
src="{{ asset('storage/'.$msg->file_path) }}"
style="max-width:150px;"
class="rounded"
>
{{-- VIDEO --}}
@elseif($isVideo)
<video
src="{{ asset('storage/'.$msg->file_path) }}"
controls
style="max-width:200px; border-radius:8px;"
>
Your browser does not support the video tag.
</video>
{{-- PDF / EXCEL / OTHER --}}
@else
<a href="{{ asset('storage/'.$msg->file_path) }}" target="_blank">
📎 View Attachment
</a>
@endif
2025-12-15 11:03:30 +05:30
@endif
2025-12-16 10:19:54 +05:30
2025-12-15 11:03:30 +05:30
<small class="text-muted d-block mt-1">
{{ $msg->created_at->format('d M h:i A') }}
</small>
</div>
@endforeach
</div>
<div class="chat-input">
<div class="card shadow-sm">
<div class="card-body d-flex align-items-center gap-2">
<input type="text" id="messageInput" class="form-control" placeholder="Type your message...">
<input type="file" id="fileInput" class="form-control" style="max-width:200px;">
<button class="btn btn-primary" id="sendBtn">Send</button>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
<script>
// ✅ Make current admin ID available to JS
const CURRENT_ADMIN_ID = {{ auth('admin')->id() }};
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();
// -------------------------------
// SEND MESSAGE (WORKING PART FROM SCRIPT #1)
// -------------------------------
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 = "";
})
.catch(err => console.error("[SEND] Error:", err));
});
// -------------------------------
// LISTEN FOR REALTIME MESSAGE (WORKING PART FROM SCRIPT #2)
// ----------------------------
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);
const msg = event; // ✅ flat payload
// ✅ CHECK IF THIS MESSAGE IS SENT BY CURRENT ADMIN
const isMine =
msg.sender_type === 'App\\Models\\Admin' &&
msg.sender_id === CURRENT_ADMIN_ID;
let html = `
<div class="message ${isMine ? 'admin' : 'user'}">
${msg.message ?? ''}
`;
2025-12-16 10:19:54 +05:30
if (msg.file_path) {
const fileUrl = `/storage/${msg.file_path}`;
2025-12-15 11:03:30 +05:30
if (msg.file_type?.startsWith("image")) {
2025-12-16 10:19:54 +05:30
html += `
<img
src="${fileUrl}"
class="rounded mt-2"
style="max-width:150px;"
>
`;
} else if (msg.file_type?.startsWith("video")) {
html += `
<video
src="${fileUrl}"
controls
class="mt-2"
style="max-width:200px; border-radius:8px;"
></video>
`;
2025-12-15 11:03:30 +05:30
} else {
2025-12-16 10:19:54 +05:30
html += `
<a href="${fileUrl}" target="_blank" class="mt-2 d-block">
📎 View Attachment
</a>
`;
2025-12-15 11:03:30 +05:30
}
}
2025-12-16 10:19:54 +05:30
2025-12-15 11:03:30 +05:30
html += `
<small class="text-muted d-block mt-1">Just now</small>
</div>
`;
document
.getElementById("chatBox")
.insertAdjacentHTML("beforeend", html);
scrollToBottom();
});
});
</script>
@endsection