This commit is contained in:
2026-01-10 17:22:49 +01:00
parent edcc1b5403
commit 674fabb715
21 changed files with 2135 additions and 489 deletions

293
public/js/messaging.js Normal file
View File

@@ -0,0 +1,293 @@
// Messaging JavaScript functionality
class MessagingSystem {
constructor() {
this.currentUserId = null;
this.currentConversationUserId = null;
this.pollingInterval = null;
this.init();
}
init() {
// Get current user ID from the page
this.currentUserId = document.querySelector('meta[name="user-id"]')?.content;
if (this.currentUserId) {
this.setupEventListeners();
this.startPolling();
}
}
setupEventListeners() {
// Handle message form submissions
document.querySelectorAll('form[id$="-form"], form[action*="message/send"]').forEach(form => {
form.addEventListener('submit', (e) => {
e.preventDefault();
this.sendMessage(form);
});
});
// Handle conversation switching
document.querySelectorAll('a[href*="message/conversation/"]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const userId = link.href.split('/').pop();
this.loadConversation(userId);
});
});
}
async sendMessage(form) {
try {
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
// Show loading state
const submitButton = form.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
submitButton.textContent = 'Sending...';
submitButton.disabled = true;
const response = await fetch('index.php/message/send', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: new URLSearchParams(data)
});
const result = await response.json();
if (result.success) {
// Clear form
form.reset();
// Reload messages or show success
if (this.currentConversationUserId) {
await this.loadMessages(this.currentConversationUserId);
} else {
this.showFeedback('Message sent successfully!', 'success');
}
} else {
this.showFeedback(result.message || 'Failed to send message', 'error');
}
} catch (error) {
console.error('Error sending message:', error);
this.showFeedback('Network error. Please try again.', 'error');
} finally {
// Restore button state
const submitButton = form.querySelector('button[type="submit"]');
submitButton.textContent = originalText;
submitButton.disabled = false;
}
}
async loadConversation(userId) {
this.currentConversationUserId = userId;
try {
const response = await fetch(`index.php/message/conversation/${userId}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const html = await response.text();
const conversationContainer = document.querySelector('.conversation-container') ||
document.querySelector('.panel-default');
if (conversationContainer) {
conversationContainer.innerHTML = html;
this.setupEventListeners(); // Re-setup event listeners for new content
}
}
} catch (error) {
console.error('Error loading conversation:', error);
this.showFeedback('Failed to load conversation', 'error');
}
}
async loadMessages(userId) {
try {
const response = await fetch(`index.php/message/getConversationMessages/${userId}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const messages = await response.json();
this.displayMessages(messages);
}
} catch (error) {
console.error('Error loading messages:', error);
}
}
async loadGlobalMessages() {
try {
const response = await fetch('index.php/message/getGlobalMessages', {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const messages = await response.json();
this.displayGlobalMessages(messages);
}
} catch (error) {
console.error('Error loading global messages:', error);
}
}
displayMessages(messages) {
const messageContainer = document.querySelector('.message-container');
if (!messageContainer) return;
messageContainer.innerHTML = '';
messages.forEach(message => {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${message.sender_id == this.currentUserId ? 'sent' : 'received'}`;
messageDiv.innerHTML = `
<div class="message-bubble">
${this.escapeHtml(message.message)}
</div>
<div class="message-time">
${this.formatDate(message.created_at)}
</div>
`;
messageContainer.appendChild(messageDiv);
});
// Scroll to bottom
messageContainer.scrollTop = messageContainer.scrollHeight;
}
displayGlobalMessages(messages) {
const globalContainer = document.querySelector('.global-messages-container');
if (!globalContainer) return;
globalContainer.innerHTML = '';
messages.forEach(message => {
const messageDiv = document.createElement('div');
messageDiv.className = 'global-message';
messageDiv.innerHTML = `
<div class="message-header">
<strong>${this.escapeHtml(message.sender_name)}</strong>
<span class="message-time">${this.formatDate(message.created_at)}</span>
</div>
<div class="message-bubble">
${this.escapeHtml(message.message)}
</div>
`;
globalContainer.appendChild(messageDiv);
});
// Scroll to bottom
globalContainer.scrollTop = globalContainer.scrollHeight;
}
startPolling() {
// Poll for new messages every 5 seconds
this.pollingInterval = setInterval(() => {
this.checkForNewMessages();
}, 5000);
// Also check for unread count
setInterval(() => {
this.updateUnreadCount();
}, 10000);
}
async checkForNewMessages() {
if (this.currentConversationUserId) {
await this.loadMessages(this.currentConversationUserId);
}
}
async updateUnreadCount() {
try {
const response = await fetch('index.php/message/unreadcount', {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
this.updateUnreadCountDisplay(data.count);
}
} catch (error) {
console.error('Error updating unread count:', error);
}
}
updateUnreadCountDisplay(count) {
const unreadElements = document.querySelectorAll('.unread-count');
unreadElements.forEach(element => {
if (count > 0) {
element.textContent = count;
element.style.display = 'inline-block';
} else {
element.style.display = 'none';
}
});
}
showFeedback(message, type) {
// Create feedback element
const feedback = document.createElement('div');
feedback.className = `feedback-${type}`;
feedback.textContent = message;
feedback.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 15px 20px;
background: ${type === 'success' ? '#4caf50' : '#f44336'};
color: white;
border-radius: 4px;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
`;
document.body.appendChild(feedback);
// Remove after 3 seconds
setTimeout(() => {
feedback.remove();
}, 3000);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleString('en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
}
// Initialize the messaging system when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.messagingSystem = new MessagingSystem();
});
// Make it available globally for any other scripts that might need it
window.MessagingSystem = MessagingSystem;