![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/php-migration/ |
<?php
/**
* Chat Page
* Real-time messaging interface
*/
require_once 'config/config.php';
require_once 'auth/Auth.php';
require_once 'models/ChatRoom.php';
require_once 'models/Message.php';
require_once 'config/database.php';
$auth = new Auth();
// Check if user is logged in
if (!$auth->isLoggedIn()) {
header('Location: /login.php');
exit;
}
$user = $auth->getCurrentUser();
$database = new Database();
$db = $database->getConnection();
// Get user's chat rooms
$chatRoomModel = new ChatRoom($db);
$userChatRooms = $chatRoomModel->getByUserId($user['id']);
// Get current room
$currentRoomId = $_GET['room'] ?? ($userChatRooms[0]['id'] ?? null);
$currentRoom = null;
$messages = [];
if ($currentRoomId) {
$chatRoomModel->findById($currentRoomId);
$currentRoom = $chatRoomModel;
$messageModel = new Message($db);
$messages = $messageModel->getRecentByChatRoomId($currentRoomId, 50);
}
// Get language from user preference
$language = $user['language'] ?? DEFAULT_LANGUAGE;
// Bilingual content
$content = [
'fr' => [
'title' => 'Chat - avocat.quebec',
'heading' => 'Messages',
'selectRoom' => 'Sélectionner une conversation',
'typeMessage' => 'Tapez votre message...',
'send' => 'Envoyer',
'noMessages' => 'Aucun message dans cette conversation',
'noRooms' => 'Aucune conversation disponible',
'online' => 'En ligne',
'typing' => 'en train d\'écrire...',
'attachFile' => 'Joindre un fichier',
'reply' => 'Répondre',
'edit' => 'Modifier',
'delete' => 'Supprimer'
],
'en' => [
'title' => 'Chat - avocat.quebec',
'heading' => 'Messages',
'selectRoom' => 'Select a conversation',
'typeMessage' => 'Type your message...',
'send' => 'Send',
'noMessages' => 'No messages in this conversation',
'noRooms' => 'No conversations available',
'online' => 'Online',
'typing' => 'typing...',
'attachFile' => 'Attach file',
'reply' => 'Reply',
'edit' => 'Edit',
'delete' => 'Delete'
]
];
$currentContent = $content[$language];
?>
<!DOCTYPE html>
<html lang="<?php echo $language; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $currentContent['title']; ?></title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
.message-bubble {
max-width: 70%;
word-wrap: break-word;
}
.message-bubble.own {
background-color: #3b82f6;
color: white;
margin-left: auto;
}
.message-bubble.other {
background-color: #f3f4f6;
color: #374151;
}
.typing-indicator {
display: none;
}
.typing-indicator.show {
display: block;
}
</style>
</head>
<body class="bg-gray-100 h-screen">
<!-- Navigation -->
<nav class="bg-white shadow-sm border-b">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<a href="/dashboard.php" class="text-2xl font-bold text-blue-600">avocat.quebec</a>
<span class="ml-4 text-gray-600"><?php echo $currentContent['heading']; ?></span>
</div>
<div class="flex items-center space-x-4">
<span class="text-sm text-gray-700"><?php echo htmlspecialchars($user['name']); ?></span>
<a href="/dashboard.php" class="text-blue-600 hover:text-blue-800">Dashboard</a>
</div>
</div>
</div>
</nav>
<div class="flex h-screen">
<!-- Sidebar - Chat Rooms -->
<div class="w-1/3 bg-white border-r">
<div class="p-4 border-b">
<h2 class="text-lg font-semibold text-gray-900"><?php echo $currentContent['selectRoom']; ?></h2>
</div>
<div class="overflow-y-auto h-full">
<?php if (empty($userChatRooms)): ?>
<div class="p-4 text-center text-gray-500">
<?php echo $currentContent['noRooms']; ?>
</div>
<?php else: ?>
<?php foreach ($userChatRooms as $room): ?>
<a href="?room=<?php echo $room['id']; ?>"
class="block p-4 border-b hover:bg-gray-50 <?php echo $room['id'] === $currentRoomId ? 'bg-blue-50 border-blue-200' : ''; ?>">
<div class="flex items-center">
<div class="w-10 h-10 bg-blue-500 rounded-full flex items-center justify-center text-white font-semibold">
<?php echo strtoupper(substr($room['name'], 0, 2)); ?>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-gray-900"><?php echo htmlspecialchars($room['name']); ?></h3>
<p class="text-xs text-gray-500"><?php echo ucfirst($room['type']); ?></p>
</div>
</div>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Main Chat Area -->
<div class="flex-1 flex flex-col">
<?php if ($currentRoom): ?>
<!-- Chat Header -->
<div class="bg-white border-b p-4">
<div class="flex items-center justify-between">
<div>
<h3 class="text-lg font-semibold text-gray-900"><?php echo htmlspecialchars($currentRoom->name); ?></h3>
<p class="text-sm text-gray-500"><?php echo ucfirst($currentRoom->type); ?> • <span id="online-count">0</span> <?php echo $currentContent['online']; ?></p>
</div>
<div class="flex items-center space-x-2">
<span class="text-sm text-gray-500" id="typing-indicator" style="display: none;">
<span id="typing-users"></span> <?php echo $currentContent['typing']; ?>
</span>
</div>
</div>
</div>
<!-- Messages Area -->
<div class="flex-1 overflow-y-auto p-4 space-y-4" id="messages-container">
<?php if (empty($messages)): ?>
<div class="text-center text-gray-500 py-8">
<?php echo $currentContent['noMessages']; ?>
</div>
<?php else: ?>
<?php foreach ($messages as $message): ?>
<div class="flex <?php echo $message['userId'] === $user['id'] ? 'justify-end' : 'justify-start'; ?>">
<div class="message-bubble <?php echo $message['userId'] === $user['id'] ? 'own' : 'other'; ?> p-3 rounded-lg">
<?php if ($message['userId'] !== $user['id']): ?>
<div class="text-xs font-semibold mb-1"><?php echo htmlspecialchars($message['userName']); ?></div>
<?php endif; ?>
<div class="text-sm"><?php echo htmlspecialchars($message['content']); ?></div>
<div class="text-xs opacity-75 mt-1">
<?php echo date('H:i', strtotime($message['createdAt'])); ?>
<?php if ($message['isEdited']): ?>
<span class="italic">(edited)</span>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- Message Input -->
<div class="bg-white border-t p-4">
<form id="message-form" class="flex space-x-2">
<input type="hidden" id="room-id" value="<?php echo $currentRoomId; ?>">
<input type="text"
id="message-input"
placeholder="<?php echo $currentContent['typeMessage']; ?>"
class="flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<button type="submit"
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
<?php echo $currentContent['send']; ?>
</button>
</form>
</div>
<?php else: ?>
<!-- No Room Selected -->
<div class="flex-1 flex items-center justify-center">
<div class="text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
<h3 class="mt-2 text-sm font-medium text-gray-900"><?php echo $currentContent['selectRoom']; ?></h3>
</div>
</div>
<?php endif; ?>
</div>
</div>
<!-- WebSocket Script -->
<script>
let ws;
let currentRoomId = '<?php echo $currentRoomId; ?>';
let userId = '<?php echo $user['id']; ?>';
let typingTimeout;
// Initialize WebSocket connection
function initWebSocket() {
ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
console.log('WebSocket connected');
// Authenticate with user ID
ws.send(JSON.stringify({
type: 'auth',
token: userId
}));
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
handleWebSocketMessage(data);
};
ws.onclose = function() {
console.log('WebSocket disconnected');
// Reconnect after 3 seconds
setTimeout(initWebSocket, 3000);
};
}
// Handle WebSocket messages
function handleWebSocketMessage(data) {
switch (data.type) {
case 'auth_success':
console.log('Authenticated successfully');
if (currentRoomId) {
joinRoom(currentRoomId);
}
break;
case 'room_joined':
loadMessages(data.messages);
break;
case 'new_message':
addMessage(data.message);
break;
case 'user_typing':
showTypingIndicator(data.userName);
break;
case 'user_stop_typing':
hideTypingIndicator(data.userName);
break;
}
}
// Join a chat room
function joinRoom(roomId) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'join_room',
roomId: roomId
}));
}
}
// Load messages
function loadMessages(messages) {
const container = document.getElementById('messages-container');
container.innerHTML = '';
if (messages.length === 0) {
container.innerHTML = '<div class="text-center text-gray-500 py-8"><?php echo $currentContent['noMessages']; ?></div>';
return;
}
messages.forEach(message => {
addMessage(message);
});
scrollToBottom();
}
// Add a message to the chat
function addMessage(message) {
const container = document.getElementById('messages-container');
const isOwn = message.userId === userId;
const messageDiv = document.createElement('div');
messageDiv.className = `flex ${isOwn ? 'justify-end' : 'justify-start'}`;
messageDiv.innerHTML = `
<div class="message-bubble ${isOwn ? 'own' : 'other'} p-3 rounded-lg">
${!isOwn ? `<div class="text-xs font-semibold mb-1">${message.userName}</div>` : ''}
<div class="text-sm">${message.content}</div>
<div class="text-xs opacity-75 mt-1">
${new Date(message.createdAt).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}
${message.isEdited ? '<span class="italic">(edited)</span>' : ''}
</div>
</div>
`;
container.appendChild(messageDiv);
scrollToBottom();
}
// Show typing indicator
function showTypingIndicator(userName) {
const indicator = document.getElementById('typing-indicator');
const users = document.getElementById('typing-users');
users.textContent = userName;
indicator.style.display = 'block';
}
// Hide typing indicator
function hideTypingIndicator(userName) {
const indicator = document.getElementById('typing-indicator');
indicator.style.display = 'none';
}
// Scroll to bottom of messages
function scrollToBottom() {
const container = document.getElementById('messages-container');
container.scrollTop = container.scrollHeight;
}
// Handle message form submission
document.getElementById('message-form').addEventListener('submit', function(e) {
e.preventDefault();
const input = document.getElementById('message-input');
const message = input.value.trim();
if (message && ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'message',
content: message,
messageType: 'TEXT',
roomId: currentRoomId
}));
input.value = '';
}
});
// Handle typing indicator
document.getElementById('message-input').addEventListener('input', function() {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'typing',
roomId: currentRoomId
}));
clearTimeout(typingTimeout);
typingTimeout = setTimeout(() => {
ws.send(JSON.stringify({
type: 'stop_typing',
roomId: currentRoomId
}));
}, 1000);
}
});
// Initialize WebSocket when page loads
document.addEventListener('DOMContentLoaded', function() {
initWebSocket();
});
</script>
</body>
</html>