document.addEventListener('DOMContentLoaded', () => {
const messagesArea = document.getElementById('messagesArea');
const messageInput = document.getElementById('messageInput');
const sendBtn = document.getElementById('sendBtn');
const recordBtn = document.getElementById('recordBtn');
const photoBtn = document.getElementById('photoBtn');
const imageInput = document.getElementById('imageInput');
// Отключение голосовой функции, если указано в настройках
if (typeof FEATURES !== 'undefined' && !FEATURES.voice && recordBtn) {
recordBtn.style.display = 'none';
}
let currentOnlineUsernames = [];
// Создание элемента индикатора набора текста
const typingIndicator = document.createElement('div');
typingIndicator.className = 'typing-indicator hidden';
typingIndicator.innerText = '';
document.querySelector('.chat-container').insertBefore(typingIndicator, document.querySelector('.input-area'));
// Создание элемента наложения записи
const recordingOverlay = document.createElement('div');
recordingOverlay.className = 'recording-overlay';
// Использовать LANG.recording, если доступно, иначе английский
// Use LANG.recording if available, fallback to English
const recText = (typeof LANG !== 'undefined') ? LANG.recording : 'Recording...';
const cancelText = (typeof LANG !== 'undefined' && LANG.cancel) ? LANG.cancel : 'Cancel';
recordingOverlay.innerHTML = '<span class="rec-dot"></span> ' + recText + ' <span id="recTimer" style="margin-left:8px; width:40px; display:inline-block;">0:00</span><span id="cancelRec" style="margin-left:15px; cursor:pointer; font-size:0.8rem; color:#fff; text-decoration:underline;">' + cancelText + '</span>';
// Вставка наложения записи
const inputArea = document.querySelector('.input-area');
inputArea.insertBefore(recordingOverlay, messageInput);
recordingOverlay.querySelector('#cancelRec').addEventListener('click', cancelRecording);
// Элемент предпросмотра ответа
const replyPreview = document.createElement('div');
replyPreview.className = 'reply-preview-bar';
replyPreview.innerHTML = '<div class="reply-info"><strong></strong><span></span></div><div class="close-reply">×</div>';
inputArea.insertBefore(replyPreview, recordingOverlay);
// Actually parent is .input-area. absolute bottom: 100%. correct.
replyPreview.querySelector('.close-reply').addEventListener('click', cancelReply);
let replyToId = null;
function initiateReply(msg) {
replyToId = msg.id;
const name = msg.username;
const tVoice = (typeof LANG !== 'undefined') ? LANG.voice_message : 'Voice Message';
const text = msg.type === 'voice' ? tVoice : msg.content;
const tReplyingTo = (typeof LANG !== 'undefined' && LANG.replying_to) ? LANG.replying_to : 'Replying to';
replyPreview.querySelector('strong').innerText = tReplyingTo + ' ' + name;
replyPreview.querySelector('span').innerText = text;
replyPreview.classList.add('visible');
messageInput.focus();
// Логика подсветки
document.querySelectorAll('.message').forEach(m => m.classList.remove('replying'));
const el = document.querySelector(`.message[data-id="${msg.id}"]`);
if (el) el.classList.add('replying');
}
function cancelReply() {
replyToId = null;
replyPreview.classList.remove('visible');
document.querySelectorAll('.message').forEach(m => m.classList.remove('replying'));
}
window.scrollToMessage = function (id) {
const el = document.querySelector(`.message[data-id="${id}"]`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('replying');
setTimeout(() => el.classList.remove('replying'), 1000);
}
};
let mediaRecorder;
let audioChunks = [];
let isRecording = false;
let lastTypingTime = 0;
let recStartTime = 0;
let recInterval;
// Использовать глобальный currentRoomId, определенный в index.php
currentRoomId = parseInt(localStorage.getItem('lastRoomId')) || 1;
window.currentRoomName = 'General'; // Сохранить оригинальное имя комнаты (глобально для доступа из index.php)
let lastId = 0;
// Загрузка комнат и сообщений
fetchRooms();
fetchMessages();
// Опрос каждые 2 секунды для получения новых сообщений
setInterval(fetchMessages, 2000);
// Немедленное обновление, когда пользователь возвращается на вкладку
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
fetchMessages();
}
});
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
handleTyping();
});
function handleTyping() {
const now = Date.now();
if (now - lastTypingTime > 1000) { // Ограничение до одного раза в секунду
fetch('api/typing.php'); // Отправить и забыть
lastTypingTime = now;
}
}
// Голосовая запись
// Инициализация микрофона перенесена в startRecording
function initMicrophone() {
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
console.error('getUserMedia not supported on your browser!');
return Promise.reject('Not supported');
}
return navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = event => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
if (shouldSend) {
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
sendVoiceMessage(audioBlob);
}
audioChunks = [];
};
return true;
})
.catch(err => {
console.error('Error accessing microphone:', err);
recordBtn.disabled = true;
recordBtn.title = "Microphone access denied";
throw err;
});
}
// Переключение записи по клику
recordBtn.addEventListener('click', () => {
if (!isRecording) {
startRecording();
} else {
stopRecording();
}
});
// Иконки
const micIcon = '<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.66 9 5v6c0 1.66 1.34 3 3 3z"/><path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/></svg>';
const stopIcon = '<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M6 6h12v12H6z"/></svg>';
let shouldSend = false;
async function startRecording() {
if (!mediaRecorder) {
try {
await initMicrophone();
} catch (e) {
alert("Ошибка доступа к микрофону. Пожалуйста, разрешите доступ в настройках браузера.");
return;
}
}
if (mediaRecorder && mediaRecorder.state === "inactive") {
// Скрыть кнопки, чтобы предотвратить перекрытие
if (photoBtn) photoBtn.style.display = 'none';
if (sendBtn) sendBtn.style.display = 'none';
isRecording = true;
shouldSend = true; // По умолчанию true для режима клика
mediaRecorder.start();
recordBtn.classList.add('recording');
recordBtn.innerHTML = stopIcon; // Изменить на иконку остановки
recordBtn.title = "Stop & Send";
// UI Updates
messageInput.classList.add('recording');
messageInput.disabled = true;
recordingOverlay.classList.add('visible');
// Таймер
recStartTime = Date.now();
updateTimer();
recInterval = setInterval(updateTimer, 1000);
}
}
function cancelRecording() {
shouldSend = false;
stopRecording();
}
function updateTimer() {
if (!isRecording) return;
const elapsed = Math.floor((Date.now() - recStartTime) / 1000);
const mins = Math.floor(elapsed / 60);
const secs = elapsed % 60;
const timerEl = document.getElementById('recTimer');
if (timerEl) timerEl.innerText = `${mins}:${secs.toString().padStart(2, '0')}`;
}
function stopRecording() {
if (mediaRecorder && mediaRecorder.state === "recording") {
// Восстановить кнопки
if (photoBtn) photoBtn.style.display = '';
if (sendBtn) sendBtn.style.display = '';
isRecording = false;
mediaRecorder.stop();
recordBtn.classList.remove('recording');
recordBtn.innerHTML = micIcon; // Сброс на микрофон
recordBtn.title = "Record voice message";
// UI Updates
messageInput.classList.remove('recording');
messageInput.disabled = false;
recordingOverlay.classList.remove('visible');
clearInterval(recInterval);
messageInput.focus();
}
}
function sendMessage() {
const text = messageInput.value.trim();
if (!text) return;
const formData = new FormData();
formData.append('message', text);
if (replyToId) formData.append('reply_to', replyToId);
formData.append('room_id', currentRoomId);
fetch('api/send.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
messageInput.value = '';
cancelReply();
fetchMessages();
} else {
alert('Error sending message');
}
})
.catch(console.error);
}
function sendVoiceMessage(blob) {
const formData = new FormData();
formData.append('audio_data', blob);
if (replyToId) formData.append('reply_to', replyToId);
formData.append('room_id', currentRoomId);
fetch('api/send.php', {
method: 'POST',
body: formData,
credentials: 'include'
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
cancelReply();
fetchMessages();
fetch('api/bot.php', { credentials: 'include' });
} else {
console.error('Error sending voice:', data);
}
})
.catch(console.error);
}
const playIcon = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
const pauseIcon = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
function fetchMessages() {
const url = (!lastId || lastId === 0)
? `api/fetch.php?room_id=${currentRoomId}`
: `api/fetch.php?last_id=${lastId}&room_id=${currentRoomId}`;
fetch(url)
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Статус онлайн
const onlineUsers = data.online_users || [];
currentOnlineUsernames = onlineUsers;
const statusDiv = document.getElementById('onlineStatus');
if (statusDiv) {
const tOnline = (typeof LANG !== 'undefined') ? LANG.online : 'Online';
const tNoOnline = (typeof LANG !== 'undefined') ? LANG.no_online : 'No one else online';
if (onlineUsers.length > 0) {
const names = onlineUsers.map(u => u.username).join(', ');
statusDiv.innerHTML = `<div class="status-dot online"></div> ${names} (${tOnline})`;
} else {
statusDiv.innerHTML = `<div class="status-dot"></div> ${tNoOnline}`;
}
}
// Обновление индикатора набора текста
if (data.typing_users && data.typing_users.length > 0) {
let text;
const isBot = data.typing_users.includes('ChatBot');
const tTyping = (typeof LANG !== 'undefined') ? LANG.typing : 'is typing...';
const tBotTyping = (typeof LANG !== 'undefined') ? LANG.bot_typing : 'is typing...';
if (isBot && data.typing_users.length === 1) {
text = 'ChatBot ' + tBotTyping;
} else {
text = data.typing_users.join(', ') + ' ' + tTyping;
}
typingIndicator.innerText = text;
typingIndicator.classList.remove('hidden');
} else {
typingIndicator.classList.add('hidden');
}
// Сообщения
const newMessages = data.messages;
if (newMessages.length > 0) {
lastId = newMessages[newMessages.length - 1].id;
renderMessages(newMessages);
scrollToBottom();
}
}
})
.catch(console.error);
}
function renderMessages(messages) {
messages.forEach(msg => {
const wrapper = document.createElement('div');
wrapper.className = 'message-row ' + (msg.is_me ? 'sent' : 'received');
wrapper.dataset.id = msg.id;
const isActive = currentOnlineUsernames.includes(msg.username) || msg.username === 'ChatBot' || msg.is_me;
const avatarCont = document.createElement('div');
avatarCont.className = 'avatar-container';
const avatarImg = document.createElement('img');
avatarImg.className = 'msg-avatar';
avatarImg.src = msg.avatar || 'assets/default_avatar.png';
avatarImg.title = msg.username;
avatarImg.style.cursor = 'pointer';
avatarImg.onclick = () => showOtherUserProfile(msg.username, msg.avatar, msg.role, msg.user_id == 1, msg.user_id_real, msg.email);
avatarCont.appendChild(avatarImg);
if (isActive) {
const dot = document.createElement('div');
dot.className = 'status-dot online';
avatarCont.appendChild(dot);
}
wrapper.appendChild(avatarCont);
const div = document.createElement('div');
div.classList.add('message');
div.classList.add(msg.is_me ? 'sent' : 'received');
if (msg.type === 'deleted') {
const tDeleted = (typeof LANG !== 'undefined' && LANG.msg_deleted) ? LANG.msg_deleted : 'Message deleted';
div.innerHTML = `<em style="opacity:0.6;">${tDeleted}</em>`;
div.style.padding = '8px 12px';
wrapper.appendChild(div);
messagesArea.appendChild(wrapper);
return;
}
wrapper.appendChild(div);
messagesArea.appendChild(wrapper);
// Триггеры ответа
// Десктоп: Двойной клик (LKM x2) для ответа
div.addEventListener('dblclick', () => initiateReply(msg));
// Мобильные: Долгое нажатие (Удержание)
let pressTimer;
div.addEventListener('touchstart', () => {
pressTimer = setTimeout(() => initiateReply(msg), 800);
}, { passive: true });
div.addEventListener('touchend', () => clearTimeout(pressTimer));
div.addEventListener('touchmove', () => clearTimeout(pressTimer));
// Контекстное меню удаления (Правый клик)
div.addEventListener('contextmenu', e => {
if (msg.is_me) {
e.preventDefault();
const tConfirm = (typeof LANG !== 'undefined' && LANG.confirm_delete) ? LANG.confirm_delete : 'Delete this message?';
if (confirm(tConfirm)) {
deleteMessage(msg.id);
}
}
});
// Блок цитирования
if (msg.reply_to && msg.reply_content) {
const quote = document.createElement('div');
quote.className = 'quote-block';
const rType = msg.reply_type === 'voice' ? (typeof LANG !== 'undefined' ? LANG.voice_message || 'Voice Message' : 'Voice Message') : msg.reply_content;
quote.innerHTML = ''; // Clear
const strong = document.createElement('strong');
strong.textContent = msg.reply_username;
const span = document.createElement('span');
span.textContent = rType;
quote.appendChild(strong);
quote.appendChild(span);
quote.onclick = (e) => { e.stopPropagation(); window.scrollToMessage(msg.reply_to); };
div.appendChild(quote);
}
// Всегда показывать имя пользователя + значок админа, если применимо
const nameDiv = document.createElement('div');
nameDiv.className = 'user-name';
nameDiv.style.fontWeight = 'bold';
nameDiv.style.fontSize = '0.75rem';
nameDiv.style.marginBottom = '6px';
nameDiv.style.color = msg.is_me ? 'rgba(255,255,255,0.7)' : 'rgba(255,255,255,0.5)';
nameDiv.style.display = 'flex';
nameDiv.style.alignItems = 'center';
nameDiv.style.gap = '6px';
let adminBadge = '';
if (msg.role === 'admin' || msg.user_id == 1) {
adminBadge = `<span style="background:rgba(255,183,3,0.15); color:#ffb703; padding:1px 6px; border-radius:6px; font-weight:800; font-size:0.6rem; border:1px solid rgba(255,183,3,0.3); text-transform:uppercase;">АДМІН</span>`;
}
nameDiv.innerHTML = `${msg.username} ${adminBadge}`;
nameDiv.style.cursor = 'pointer';
nameDiv.onclick = () => showOtherUserProfile(msg.username, msg.avatar, msg.role, msg.user_id == 1, msg.user_id_real, msg.email);
div.appendChild(nameDiv);
if (msg.type === 'voice') {
const playerDiv = document.createElement('div');
playerDiv.className = 'custom-audio-player';
playerDiv.innerHTML = `
<button class="audio-btn">${playIcon}</button>
<div class="audio-track">
<div class="audio-progress"></div>
</div>
<span class="audio-time">...</span>
`;
const audio = document.createElement('audio');
audio.src = msg.content;
audio.preload = 'metadata';
const btn = playerDiv.querySelector('.audio-btn');
const track = playerDiv.querySelector('.audio-track');
const progress = playerDiv.querySelector('.audio-progress');
const timeDisplay = playerDiv.querySelector('.audio-time');
btn.addEventListener('click', () => {
if (audio.paused) {
document.querySelectorAll('audio').forEach(a => {
if (a !== audio) {
a.pause();
a.currentTime = 0;
}
});
audio.play();
} else {
audio.pause();
}
});
track.addEventListener('click', (e) => {
if (audio.duration) {
const rect = track.getBoundingClientRect();
const percent = Math.min(Math.max((e.clientX - rect.left) / rect.width, 0), 1);
audio.currentTime = percent * audio.duration;
}
});
audio.addEventListener('play', () => {
btn.innerHTML = pauseIcon;
btn.classList.add('playing');
});
audio.addEventListener('pause', () => {
btn.innerHTML = playIcon;
btn.classList.remove('playing');
});
audio.addEventListener('ended', () => {
btn.innerHTML = playIcon;
btn.classList.remove('playing');
progress.style.width = '0%';
});
audio.addEventListener('timeupdate', () => {
if (audio.duration) {
const percent = (audio.currentTime / audio.duration) * 100;
progress.style.width = `${percent}%`;
timeDisplay.innerText = formatTime(audio.currentTime);
}
});
audio.addEventListener('loadedmetadata', () => {
timeDisplay.innerText = formatTime(audio.duration);
});
audio.addEventListener('error', () => {
timeDisplay.innerText = "Err";
});
div.appendChild(playerDiv);
} else if (msg.type === 'image') {
const img = document.createElement('img');
img.src = msg.content;
img.style.maxWidth = '200px';
img.style.maxHeight = '300px';
img.style.borderRadius = '8px';
img.style.cursor = 'pointer';
img.style.marginTop = '5px';
img.onclick = () => window.open(msg.content, '_blank');
div.appendChild(img);
} else if (msg.type === 'system') {
const p = document.createElement('p');
p.innerText = msg.content;
p.style.fontStyle = 'italic';
p.style.color = 'rgba(255,255,255,0.6)';
div.style.border = '1px dashed rgba(255,255,255,0.15)';
div.style.background = 'rgba(0,0,0,0.2)';
div.appendChild(p);
} else {
const p = document.createElement('p');
p.innerText = msg.content;
div.appendChild(p);
}
const metaDiv = document.createElement('div');
metaDiv.className = 'meta';
metaDiv.innerText = new Date(msg.created_at).toLocaleTimeString();
div.appendChild(metaDiv);
});
}
function formatTime(seconds) {
if (!seconds || isNaN(seconds)) return "0:00";
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m}:${s.toString().padStart(2, '0')}`;
}
function scrollToBottom() {
messagesArea.scrollTop = messagesArea.scrollHeight;
}
function deleteMessage(id) {
const formData = new FormData();
formData.append('message_id', id);
fetch('api/delete.php', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
fetchMessages(); // Обновить, чтобы показать состояние "удалено"
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
})
.catch(err => console.error(err));
}
// --- ЛОГИКА КОМНАТ ---
function fetchRooms() {
fetch('api/rooms.php')
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
renderRooms(data.rooms);
} else {
console.error('Rooms Error:', data);
}
})
.catch(err => console.error('Rooms Net Error:', err));
}
function renderRooms(rooms) {
const list = document.getElementById('roomsList');
if (!list) return;
list.innerHTML = '';
if (!rooms || rooms.length === 0) {
list.innerHTML = '<div style="padding:10px; opacity:0.5; font-size:0.9rem;">No rooms available</div>';
return;
}
let activeName = 'ChatApp';
rooms.forEach(room => {
let displayName = room.name;
if (room.id == 1 && room.name === 'General' && typeof LANG !== 'undefined' && LANG.room_general) {
displayName = LANG.room_general;
}
const isActive = (room.id == currentRoomId);
if (isActive) {
activeName = displayName;
window.currentRoomName = room.name; // Сохранить оригинальное имя (глобально)
}
const div = document.createElement('div');
div.className = 'room-item ' + (isActive ? 'active' : '');
const nameSpan = document.createElement('span');
nameSpan.innerText = displayName;
div.appendChild(nameSpan);
// Действия владельца
// Общую комнату (ID=1) никто не может редактировать
const isGeneralRoom = room.id == 1;
const canEditRoom = !isGeneralRoom && (room.is_owner || USER.role === 'admin' || USER.id == 1);
if (canEditRoom) {
const actions = document.createElement('div');
actions.className = 'room-actions';
actions.style.display = 'flex';
actions.style.gap = '5px';
// Edit
const editBtn = document.createElement('button');
editBtn.className = 'room-action-btn';
editBtn.innerHTML = '✎';
editBtn.title = 'Rename';
editBtn.onclick = (e) => {
e.stopPropagation();
renameRoom(room.id, room.name);
};
actions.appendChild(editBtn);
// Удалить (Нельзя удалить Общую комнату)
if (room.id != 1) {
const delBtn = document.createElement('button');
delBtn.className = 'room-action-btn';
delBtn.innerHTML = '🗑';
delBtn.title = 'Delete';
delBtn.onclick = (e) => {
e.stopPropagation();
deleteRoom(room.id);
};
actions.appendChild(delBtn);
}
div.appendChild(actions);
}
div.onclick = () => joinRoom(room.id);
list.appendChild(div);
});
const titleEl = document.getElementById('chatRoomTitle');
if (titleEl) titleEl.innerText = activeName;
// Обновить кнопку переключения бота и кнопку редактирования комнаты
const toggleBotBtn = document.getElementById('toggleBotBtn');
const editRoomBtn = document.getElementById('editRoomBtn');
const currentRoom = rooms.find(r => r.id == currentRoomId);
// General room (ID=1) cannot be edited by anyone
const isGeneralRoom = currentRoomId == 1;
const isOwnerOrAdmin = currentRoom && (currentRoom.is_owner || USER.role === 'admin' || USER.id == 1);
// Логика кнопки редактирования: Общую комнату нельзя редактировать вообще
const canEdit = !isGeneralRoom && isOwnerOrAdmin;
if (toggleBotBtn) {
if (canEdit) {
toggleBotBtn.style.display = 'block';
const isBotActive = parseInt(currentRoom.bot_active);
toggleBotBtn.innerText = isBotActive ? '🤖 ' + LANG.remove_bot : '🤖 ' + LANG.add_bot;
toggleBotBtn.style.background = isBotActive ? 'rgba(255, 183, 3, 0.1)' : 'rgba(0, 180, 216, 0.1)';
toggleBotBtn.style.color = isBotActive ? '#ffb703' : '#00b4d8';
toggleBotBtn.style.borderColor = isBotActive ? 'rgba(255, 183, 3, 0.2)' : 'rgba(0, 180, 216, 0.2)';
toggleBotBtn.onclick = () => {
const fd = new FormData();
fd.append('action', 'toggle_bot');
fd.append('room_id', currentRoomId);
fd.append('active', isBotActive ? 0 : 1);
fetch('api/rooms.php', { method: 'POST', body: fd })
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
fetchRooms();
}
});
};
} else {
toggleBotBtn.style.display = 'none';
}
}
if (editRoomBtn) {
editRoomBtn.style.display = canEdit ? 'block' : 'none';
}
}
// Логика мобильного меню
const menuBtn = document.getElementById('menuBtn');
const sidebar = document.querySelector('.sidebar');
const mobileOverlay = document.getElementById('mobileOverlay');
if (menuBtn && sidebar) {
menuBtn.addEventListener('click', () => {
sidebar.classList.add('active');
if (mobileOverlay) mobileOverlay.classList.add('active');
});
}
if (mobileOverlay) {
mobileOverlay.addEventListener('click', () => {
if (sidebar) sidebar.classList.remove('active');
mobileOverlay.classList.remove('active');
});
}
if (photoBtn && imageInput) {
photoBtn.addEventListener('click', () => imageInput.click());
imageInput.addEventListener('change', (e) => {
if (e.target.files && e.target.files[0]) {
sendImage(e.target.files[0]);
}
});
}
function sendImage(file) {
const formData = new FormData();
formData.append('image_data', file);
formData.append('room_id', currentRoomId);
if (replyToId) formData.append('reply_to', replyToId);
fetch('api/send.php', { method: 'POST', body: formData })
.then(res => res.json())
.then(data => {
if (data.status === 'success') {
cancelReply();
fetchMessages();
imageInput.value = '';
} else {
alert('Error: ' + (data.message || 'Image upload failed'));
}
})
.catch(console.error);
}
function joinRoom(id) {
// Закрыть боковую панель на мобильных
if (sidebar && sidebar.classList.contains('active')) {
sidebar.classList.remove('active');
if (mobileOverlay) mobileOverlay.classList.remove('active');
}
if (currentRoomId === id && messagesArea.innerHTML !== '') return;
currentRoomId = id;
localStorage.setItem('lastRoomId', id);
lastId = 0; // Сброс для новой комнаты
messagesArea.innerHTML = '';
fetchRooms(); // Обновить активное состояние
fetchMessages(); // Загрузить новые сообщения
}
// Создать комнату
const createRoomBtn = document.getElementById('createRoomBtn');
const newRoomNameInput = document.getElementById('newRoomName');
window.handleCreateRoom = () => {
const name = newRoomNameInput ? newRoomNameInput.value.trim() : '';
if (!name) {
alert("Пожалуйста, введите название комнаты");
return;
}
console.log("Attempting to create room:", name);
const formData = new FormData();
formData.append('action', 'create');
formData.append('name', name);
fetch('api/rooms.php', { method: 'POST', body: formData })
.then(res => {
console.log("Server response raw:", res);
if (!res.ok) throw new Error("HTTP error " + res.status);
return res.json();
})
.then(data => {
console.log("Server response JSON:", data);
if (data.status === 'success') {
if (newRoomNameInput) newRoomNameInput.value = '';
fetchRooms();
joinRoom(data.id); // Автоматическое присоединение
} else {
alert("Ошибка: " + (data.message || 'Error creating room'));
}
})
.catch(err => {
alert('Ошибка сети/сервера: ' + err.message);
console.error("Room creation error:", err);
});
};
if (createRoomBtn) {
createRoomBtn.onclick = window.handleCreateRoom;
}
if (newRoomNameInput) {
newRoomNameInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') window.handleCreateRoom();
});
}
// Помощник для Переименования/Удаления
function renameRoom(id, oldName) {
const tPrompt = (typeof LANG !== 'undefined' && LANG.rename_room_prompt) ? LANG.rename_room_prompt : 'New name:';
const newName = prompt(tPrompt, oldName);
if (newName && newName !== oldName) {
fetch('api/rooms.php', {
method: 'PUT',
body: JSON.stringify({ id: id, name: newName })
}).then(() => fetchRooms());
}
}
function deleteRoom(id) {
const tConfirm = (typeof LANG !== 'undefined' && LANG.delete_room_confirm) ? LANG.delete_room_confirm : 'Delete this room and its messages?';
if (confirm(tConfirm)) {
fetch('api/rooms.php', {
method: 'DELETE',
body: JSON.stringify({ id: id })
}).then(res => res.json())
.then(data => {
if (data.status === 'success') {
if (currentRoomId == id) joinRoom(1); // Fallback to General
fetchRooms();
} else {
alert(data.message);
}
});
}
}
});