View file assets/script.js

File size: 36.33Kb
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">&times;</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);
                    }
                });
        }
    }

});