document.addEventListener('DOMContentLoaded', function () {
let currentRoomId = null;
let lastMessageId = 0;
let messagePollInterval = null;
let roomPollInterval = null;
let isFetchingMessages = false;
const UI = {
roomList: document.getElementById('room-list'),
noChatSelected: document.getElementById('no-chat-selected'),
chatHeader: document.getElementById('active-chat-header'),
chatTitle: document.getElementById('active-chat-title'),
chatHeaderInfo: document.getElementById('chat-header-info'),
messages: document.getElementById('chat-messages'),
inputArea: document.getElementById('chat-input-area'),
form: document.getElementById('chat-form'),
input: document.getElementById('chat-input'),
indicator: document.getElementById('polling-indicator'),
// 🟢 متغیرهای جدید برای Modal کاربران
newChatBtn: document.getElementById('new-chat-btn'),
usersModal: document.getElementById('users-modal'),
closeModalBtn: document.getElementById('close-users-modal'),
usersList: document.getElementById('users-list'),
searchInput: document.getElementById('user-search-input')
};
// ── منطق مودال کاربران ──
if (UI.newChatBtn) {
UI.newChatBtn.addEventListener('click', () => {
UI.usersModal.style.transform = 'translateY(0)'; // نمایش مودال (بالا آمدن)
fetchUsers(''); // لود اولیه لیست کاربران
});
}
if (UI.closeModalBtn) {
UI.closeModalBtn.addEventListener('click', () => {
UI.usersModal.style.transform = 'translateY(100%)'; // مخفی کردن مودال (پایین رفتن)
});
}
if (UI.searchInput) {
let timeout = null;
UI.searchInput.addEventListener('input', (e) => {
clearTimeout(timeout);
// دیباونس (Debounce) برای جلوگیری از ریکوئستهای تکراری
timeout = setTimeout(() => {
fetchUsers(e.target.value);
}, 300);
});
}
async function fetchUsers(query) {
UI.usersList.innerHTML = '
autorenew
';
try {
const res = await fetch(`${window.CHAT_CONFIG.apiUrlUsers}?q=${encodeURIComponent(query)}`);
const data = await res.json();
renderUsers(data.users);
} catch (e) {
console.error("Failed to fetch users:", e);
UI.usersList.innerHTML = `${window.CHAT_CONFIG.trans.failedToLoadUsers}
`;
}
}
function renderUsers(users) {
if (users.length === 0) {
UI.usersList.innerHTML = `${window.CHAT_CONFIG.trans.noUsersFound}
`;
return;
}
UI.usersList.innerHTML = users.map(user => {
const initial = user.name ? user.name.charAt(0).toUpperCase() : 'U';
// استفاده از کلاسهای room-item و room-avatar برای هماهنگی 100 درصدی
return `
${initial}
${user.name}
${user.role}
`;
}).join('');
}
window.startChatWithUser = async function (userId) {
// بستن مودال بلافاصله بعد از کلیک
UI.usersModal.style.transform = 'translateY(100%)';
try {
const res = await fetch(window.CHAT_CONFIG.apiUrlCreateRoom, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': window.CHAT_CONFIG.csrfToken
},
body: JSON.stringify({ user_id: userId })
});
const data = await res.json();
if (data.success) {
// اگر با موفقیت ساخته یا پیدا شد، مستقیماً وارد چت میشویم
selectRoom(data.room_id, data.title);
}
} catch (e) {
console.error("Failed to start chat:", e);
}
};
// ── پایان منطق مودال کاربران ──
// ── بقیه کدهای قبلی (fetchRooms, renderRooms, fetchMessages و...) بدون تغییر در اینجا قرار دارند ──
async function fetchRooms() {
try {
const res = await fetch(window.CHAT_CONFIG.apiUrlRooms);
const data = await res.json();
renderRooms(data.rooms);
} catch (e) { console.error("Failed to fetch rooms:", e); }
}
function renderRooms(rooms) {
if (rooms.length === 0) {
UI.roomList.innerHTML = `${window.CHAT_CONFIG.trans.noActiveChatsFound}
`;
return;
}
UI.roomList.innerHTML = rooms.map(room => {
const isActive = currentRoomId === room.id;
const safeTitle = room.title.replace(/'/g, "\\'");
const initial = room.title ? room.title.charAt(0).toUpperCase() : 'G';
return `
${initial}
${room.title}
${room.time}
${room.type === 'group' ? '👥 ' + window.CHAT_CONFIG.trans.groupChat : '👤 ' + window.CHAT_CONFIG.trans.privateChat}
${room.unread > 0 ? `${room.unread}` : ''}
`;
}).join('');
}
window.selectRoom = function (id, title) {
currentRoomId = id;
lastMessageId = 0;
isFetchingMessages = false;
// 🟢 Optimistic UI: Update active state and remove unread badge immediately
document.querySelectorAll('.room-item').forEach(el => el.classList.remove('room-item-active'));
const clickedRoom = document.querySelector(`.room-item[onclick*="selectRoom(${id}"]`);
if (clickedRoom) {
clickedRoom.classList.add('room-item-active');
const badge = clickedRoom.querySelector('.unread-badge');
if (badge) badge.remove(); // Hide badge instantly
}
// 🟢 تغییر invisible به hidden برای کارکرد درست بلوکها
UI.noChatSelected.classList.add('hidden');
UI.chatHeaderInfo.classList.remove('hidden'); // 🟢 تغییر یافته
UI.messages.classList.remove('hidden');
UI.inputArea.classList.remove('hidden');
UI.chatTitle.textContent = title;
UI.messages.innerHTML = 'autorenew
';
stopPolling();
fetchMessages().then(() => {
startPolling();
scrollToBottom();
fetchRooms(); // Sync with backend to ensure exact unread counts
});
UI.input.focus();
};
async function fetchMessages() {
if (!currentRoomId || isFetchingMessages) return;
isFetchingMessages = true;
try {
UI.indicator.classList.remove('hidden');
setTimeout(() => UI.indicator.classList.add('hidden'), 500);
const res = await fetch(`${window.CHAT_CONFIG.apiUrlMessagesBase}${currentRoomId}/?last_id=${lastMessageId}`);
const data = await res.json();
if (data.messages && data.messages.length > 0) {
if (lastMessageId === 0) UI.messages.innerHTML = '';
renderMessages(data.messages);
lastMessageId = data.messages[data.messages.length - 1].id;
scrollToBottom();
} else if (lastMessageId === 0) {
UI.messages.innerHTML = `chat${window.CHAT_CONFIG.trans.noMessagesYet}
`;
}
} catch (e) {
console.error("Failed to fetch messages:", e);
} finally {
isFetchingMessages = false;
}
}
function renderMessages(messages) {
const html = messages.map(m => {
const isMe = m.is_me;
const alignClass = isMe ? 'message-sent' : 'message-received';
const bubbleClass = isMe ? 'message-bubble-sent' : 'message-bubble-received';
const senderName = !isMe ? `${m.sender_name}
` : '';
const safeContent = m.content.replace(//g, ">");
const timeColor = isMe ? 'text-blue-100' : 'text-gray-400';
const tickIcon = isMe ? `done_all` : '';
return `
${senderName}
${safeContent}
${m.sent_at} ${tickIcon}
`;
}).join('');
UI.messages.insertAdjacentHTML('beforeend', html);
}
function scrollToBottom() {
UI.messages.scrollTo({ top: UI.messages.scrollHeight, behavior: 'smooth' });
}
// ── Textarea Auto-resize & Key Handling ──
UI.input.addEventListener('input', function () {
this.style.height = 'auto';
this.style.height = (this.scrollHeight) + 'px';
});
UI.input.addEventListener('keydown', function (e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
// Trigger form submit
UI.form.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));
}
});
UI.form.addEventListener('submit', async (e) => {
e.preventDefault();
const text = UI.input.value.trim();
if (!text || !currentRoomId) return;
UI.input.value = '';
UI.input.style.height = 'auto'; // Reset height
try {
await fetch(`${window.CHAT_CONFIG.apiUrlSendBase}${currentRoomId}/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': window.CHAT_CONFIG.csrfToken
},
body: JSON.stringify({ content: text })
});
await fetchMessages();
fetchRooms();
} catch (e) { console.error("Failed to send message:", e); }
});
function startPolling() {
messagePollInterval = setInterval(fetchMessages, 3000);
}
function stopPolling() {
if (messagePollInterval) clearInterval(messagePollInterval);
}
fetchRooms();
roomPollInterval = setInterval(fetchRooms, 10000);
});