- Восстановлен мягкий цвет пузырей: color-mix(92%) вместо жесткого var(--bs-primary) - Аватары: border-radius 9999px + grid layout для идеальных кругов - Разделители: правильный spacing, font-weight 700, pointer-events, color-mix прозрачность - Добавлены оптимизации скролла: rootMargin 300px, limit 50 сообщений (Telegram-стиль) - Добавлены новые модули: messageLoader, scrollManager, chatUtils - Рефакторинг логики загрузки сообщений для предотвращения дубликатов - Создана документация по архитектуре и тестированию
6.9 KiB
6.9 KiB
WebSocket Integration с ChatController
Дата: 12.01.2026
Статус: ✅ Интеграция завершена
Архитектура событий
Новая система событий
UserWebSocket теперь dispatch'ит глобальные события вместо прямого вызова компонентов:
WebSocket Server
↓
userWebSocket.js (получает JSON)
↓
window.dispatchEvent('ws:*') ← НОВОЕ
↓
ChatController (слушает события)
↓
MessageLoader → MessageStore
↓
Store событие → MessageRenderer
События WebSocket
1. ws:initial-messages
Когда: После открытия чата и получения истории
Данные:
{
detail: {
messages: Array, // Массив сообщений
chatId: number // ID чата
}
}
Обработка:
window.addEventListener('ws:initial-messages', (event) => {
const { messages, chatId } = event.detail;
// ChatController автоматически рендерит и скроллит
});
2. ws:new-message
Когда: Получено новое сообщение в реальном времени
Данные:
{
detail: {
message: Object, // Полный объект сообщения
chatId: number, // ID чата
isOwnMessage: boolean // true если отправитель - мы
}
}
Обработка:
window.addEventListener('ws:new-message', (event) => {
const { message, isOwnMessage } = event.detail;
// MessageLoader добавит в Store
// Renderer сделает incremental update
// Autoscroll если isOwnMessage или nearBottom
});
3. ws:message-edited
Когда: Сообщение отредактировано
Данные:
{
detail: {
message: Object, // Обновленное сообщение
chatId: number
}
}
Обработка:
window.addEventListener('ws:message-edited', (event) => {
const { message } = event.detail;
// Store обновит сообщение
// Renderer сделает DOM patching
});
4. ws:message-removed
Когда: Сообщение удалено
Данные:
{
detail: {
messageId: number, // ID удаленного сообщения
chatId: number
}
}
Обработка:
window.addEventListener('ws:message-removed', (event) => {
const { messageId } = event.detail;
// Store удалит сообщение
// Renderer удалит из DOM с анимацией
});
5. ws:reaction-added
Когда: Добавлена реакция к сообщению
Данные:
{
detail: {
messageId: number,
emoji: string,
userId: number,
userName: string,
reactionsSummary: Object, // Полная сводка реакций
chatId: number
}
}
6. ws:reaction-removed
Когда: Удалена реакция
Данные:
{
detail: {
messageId: number,
emoji: string,
userId: number,
reactionsSummary: Object,
chatId: number
}
}
Backward Compatibility
Старые события сохранены
Для совместимости со старым кодом, userWebSocket продолжает dispatch'ить старые события:
chat:initial-messages-loadedchat:message-addedchat:message-editedchat:reaction-addedchat:reaction-removed
Старый messageRenderer работает
Если options.messageRenderer передан в initUserWebSocket(), старая логика рендеринга продолжает работать параллельно с новой:
// В userWebSocket.js
if (options.messageRenderer && messages?.length) {
console.log('[UserWS] [DEPRECATED] Using old messageRenderer');
options.messageRenderer.renderMessages(messages);
}
Это временная мера - удалится после полной миграции на ChatController.
Миграция на ChatController
До (старый способ):
// chatDetail.js - СТАРОЕ
const messageRenderer = new MessageRenderer({...});
userWs.configure({ messageRenderer });
// Прямой вызов методов
messageRenderer.renderMessages(messages);
messageRenderer.renderMessage(message);
После (новый способ):
// chatDetail.js - НОВОЕ
import { ChatController } from '../controllers/chatController.js';
const chatController = new ChatController({
chatId: currentChatId,
currentUserId: currentUserId,
scrollElement: document.getElementById('chatScroll'),
wsConnection: window.userWebSocket
});
await chatController.init();
// Всё автоматически!
// - WebSocket dispatch'ит события
// - ChatController слушает
// - MessageLoader обновляет Store
// - Store dispatch'ит события
// - Renderer обновляет DOM
Debugging
Проверка событий
В консоли браузера:
// Слушаем все WS события
['ws:initial-messages', 'ws:new-message', 'ws:message-edited',
'ws:message-removed', 'ws:reaction-added', 'ws:reaction-removed']
.forEach(eventName => {
window.addEventListener(eventName, (e) => {
console.log(`🔔 ${eventName}:`, e.detail);
});
});
Проверка ChatController
// Получить статус контроллера
window.chatController?.getStatus();
// Вернет:
// {
// initialized: true,
// chatId: 123,
// messageCount: 45,
// loadingState: {...},
// scrollPosition: {...}
// }
Следующие шаги
- ✅ userWebSocket интегрирован (DONE)
- ⏳ Обновить chatDetail.js для использования ChatController
- ⏳ Удалить старый messageRenderer после миграции
- ⏳ Удалить старый chatHistoryLoader
- ⏳ Удалить backward compatibility код из userWebSocket
Преимущества новой архитектуры
До:
- ❌ userWebSocket напрямую вызывал messageRenderer
- ❌ Tight coupling между модулями
- ❌ Сложно тестировать
- ❌ Нельзя заменить компоненты
После:
- ✅ Событийная архитектура (Event-Driven)
- ✅ Loose coupling - модули независимы
- ✅ Легко тестировать (mock события)
- ✅ Можно заменить любой компонент
- ✅ Единая точка входа (ChatController)
- ✅ Single Source of Truth (MessageStore)