/** * Chat Detail Page * Инициализация страницы детального просмотра чата */ let initChatMarkRead, initChatComposer, initChatHistoryLoader, initChatFormManager, MessageRenderer, InitialMessagesLoader; try { const modules = await Promise.all([ import('../components/chatMarkRead.js'), import('../components/chatComposer.js'), import('../components/chatHistoryLoader.js'), import('../components/chatFormManager.js'), import('../components/messageRenderer.js'), import('../components/initialMessagesLoader.js') ]); initChatMarkRead = modules[0].initChatMarkRead; initChatComposer = modules[1].initChatComposer; initChatHistoryLoader = modules[2].initChatHistoryLoader; initChatFormManager = modules[3].initChatFormManager; MessageRenderer = modules[4].MessageRenderer; InitialMessagesLoader = modules[5].InitialMessagesLoader; } catch (error) { console.error('[ChatDetail] Failed to load modules:', error); alert('Ошибка загрузки модулей чата: ' + error.message); throw error; } // Ждём DOM function initWhenReady() { // Получаем данные из data-атрибутов const appContainer = document.getElementById('chatDetailApp'); if (!appContainer) { console.warn('[ChatDetail] App container not found'); return; } // Читаем конфигурацию из data-атрибутов const config = { chatId: Number(appContainer.dataset.chatId), userId: Number(appContainer.dataset.userId), userName: appContainer.dataset.userName || 'Вы', userAvatar: appContainer.dataset.userAvatar || '', uploadUrl: appContainer.dataset.uploadUrl, messagesUrl: appContainer.dataset.messagesUrl, markReadUrl: appContainer.dataset.markReadUrl, editUrlTemplate: appContainer.dataset.editUrlTemplate, lastReadTimestamp: Number(appContainer.dataset.lastReadTimestamp) || null }; // Читаем дополнительные URL из chatScroll (для рендеринга сообщений) const chatScroll = document.getElementById('chatScroll'); if (chatScroll) { config.profileUrl = chatScroll.dataset.profileUrl; config.detailUrlTemplate = chatScroll.dataset.detailUrlTemplate; } console.log('[ChatDetail] Config:', config); if (!config.chatId) { console.error('[ChatDetail] chatId is required'); return; } // Ждём инициализации WebSocket waitForWebSocket().then((userWs) => { console.log('[ChatDetail] WebSocket ready, initializing components'); initializeComponents(config, userWs); }).catch((error) => { console.error('[ChatDetail] WebSocket initialization failed:', error); }); } // Запускаем инициализацию if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initWhenReady); } else { // DOM уже готов initWhenReady(); } /** * Ожидание готовности WebSocket */ function waitForWebSocket() { return new Promise((resolve, reject) => { // Если уже готов - используем сразу if (window.userWebSocket && window.userWebSocket.ws) { console.log('[ChatDetail] WebSocket already available'); resolve(window.userWebSocket); return; } // Ждём события с таймаутом console.log('[ChatDetail] Waiting for user:ws-ready event...'); let timeoutId; const handler = (e) => { console.log('[ChatDetail] user:ws-ready event received'); clearTimeout(timeoutId); resolve(e.detail.api); }; window.addEventListener('user:ws-ready', handler, { once: true }); timeoutId = setTimeout(() => { window.removeEventListener('user:ws-ready', handler); reject(new Error('WebSocket initialization timeout')); }, 10000); // 10 секунд }); } /** * Инициализация всех компонентов страницы */ function initializeComponents(config, userWs) { // ========== FORM MANAGER ========== console.log('[ChatDetail] Initializing FormManager...'); const formManager = initChatFormManager({ formId: 'chatForm', textareaId: 'id_content', chatId: config.chatId, uploadUrl: config.uploadUrl, editUrlTemplate: config.editUrlTemplate }); if (!formManager) { console.error('[ChatDetail] FormManager initialization failed'); return; } console.log('[ChatDetail] FormManager initialized'); // ========== MARK READ ========== console.log('[ChatDetail] Initializing MarkRead...'); const markReadApi = initChatMarkRead({ chatId: config.chatId, meId: config.userId, scrollContainerId: 'chatScroll', textareaId: 'id_content', formId: 'chatForm', scrollBtnId: 'scrollBtn', markReadUrl: config.markReadUrl, initialLastReadTs: config.lastReadTimestamp }); console.log('[ChatDetail] MarkRead initialized'); // ========== COMPOSER ========== console.log('[ChatDetail] Initializing Composer...'); const composer = initChatComposer({ chatId: config.chatId, formId: 'chatForm', textareaId: 'id_content', uploadUrl: config.uploadUrl, meId: config.userId, meName: config.userName, meAvatar: config.userAvatar }); if (!composer) { console.error('[ChatDetail] Composer initialization failed'); return; } console.log('[ChatDetail] Composer initialized:', composer); // ========== HISTORY LOADER ========== console.log('[ChatDetail] Initializing HistoryLoader...'); // Получаем avatarMap если доступен const avatarMap = window.chatAvatarMap?.getAll() || {}; const historyLoader = initChatHistoryLoader({ chatId: config.chatId, scrollContainerId: 'chatScroll', fetchUrl: config.messagesUrl, avatarMap: avatarMap, meId: config.userId }); console.log('[ChatDetail] HistoryLoader initialized'); // ========== MESSAGE RENDERER ========== console.log('[ChatDetail] Initializing MessageRenderer...'); const messageRenderer = new MessageRenderer({ containerId: 'chatScroll', currentUserId: config.userId, currentUserAvatar: config.userAvatar || '', profileUrl: config.profileUrl || '/employees/profile/', detailUrlTemplate: config.detailUrlTemplate || '/employees/detail/0/' }); console.log('[ChatDetail] MessageRenderer initialized'); // ========== CONTEXT MENU ========== // Инициализация контекстного меню перенесена в chat-detail-enhanced.js // для избежания конфликтов и дублирования // ========== INITIAL MESSAGES LOADER ========== // ОТКЛЮЧЕНО: Используем WebSocket для загрузки initial_messages // InitialMessagesLoader больше не нужен, так как WebSocket справляется с этой задачей /* console.log('[ChatDetail] Loading initial messages...'); const initialLoader = new InitialMessagesLoader({ chatId: config.chatId, fetchUrl: config.messagesUrl, limit: 30, messageRenderer: messageRenderer, onLoaded: (data) => { console.log('[ChatDetail] Initial messages loaded:', data.messages.length); // Скроллим вниз к последнему сообщению const container = document.getElementById('chatScroll'); if (container) { container.scrollTop = container.scrollHeight; } }, onError: (error) => { console.error('[ChatDetail] Failed to load initial messages:', error); alert('Ошибка загрузки сообщений: ' + error.message); } }); // Загружаем сообщения initialLoader.load().catch(err => { console.error('[ChatDetail] Initial load error:', err); }); */ console.log('[ChatDetail] Initial messages will be loaded via WebSocket'); // Убираем индикатор загрузки после подключения WebSocket const loader = document.getElementById('initialLoader'); if (loader) { // Скроем индикатор через WebSocket событие initial_messages window.addEventListener('chat:initial-messages-loaded', () => { loader.remove(); }, { once: true }); } // ========== CONFIGURE WEBSOCKET ========== console.log('[ChatDetail] Configuring WebSocket...'); if (userWs && userWs.configure) { userWs.configure({ scrollContainerId: 'chatScroll', formId: 'chatForm', textareaId: 'id_content', typingIndicatorId: 'typing', avatarMap: avatarMap, markReadApi: markReadApi, messageRenderer: messageRenderer // Добавляем MessageRenderer }); } // Открываем чат в WebSocket с загрузкой истории if (userWs && userWs.openChat) { console.log('[ChatDetail] Opening chat in WebSocket with history:', config.chatId); userWs.openChat(config.chatId, true); // true = загружаем initial_messages } // ========== EXPORT APIS ========== window.chatComposer = composer; window.chatHistoryLoader = historyLoader; window.markReadApi = markReadApi; window.chatFormManager = formManager; // Контекстное меню и выделение сообщений инициализируются в chat-detail-enhanced.js console.log('[ChatDetail] All components initialized successfully ✓'); }