@qor/chat-layer
Composables
Composables для работы с чатом — подключение, сообщения, списки, присутствие.
Все composables авто-импортируются в компоненты. Shared composables (отмечены) — синглтоны через createSharedComposable.
useChatSocket (shared)
Управление Socket.IO подключением. Центральный хаб для связи с сервером.
const {
status, // Ref<'disconnected' | 'connecting' | 'connected' | 'error'>
error, // Ref<string | null>
currentUserId, // Ref<string | null>
isConnected, // ComputedRef<boolean>
hasSocket, // ComputedRef<boolean>
socket, // ShallowRef<Socket | null>
connect, // (userId: string) => Promise<void>
disconnect, // () => Promise<void>
registerHandlers, // (socket: Socket) => void
setSocket, // (socket: Socket) => void
} = useChatSocket()
socket — это shallowRef. Socket.IO клиент не должен глубоко проксироваться Vue — это вызовет ошибки при внутренних мутациях SDK.Подключение к чату
// Обычно делается автоматически через chat-auth.client.ts плагин
await connect('user-uuid')
// Ручное отключение
await disconnect()
useChatList (shared)
Список диалогов, фильтрация и поиск.
const {
conversations, // Ref<ChatConversation[]> (readonly)
sortedConversations, // ComputedRef — отсортированные + отфильтрованные
totalUnread, // ComputedRef<number>
loading, // Ref<boolean>
filter, // Ref<'all' | 'single' | 'group' | 'unread'>
searchQuery, // Ref<string>
participantsMap, // ComputedRef<Map<userId, { name, avatar? }>>
loadConversations, // () => Promise<void>
getConversation, // (chatId: string) => ChatConversation | undefined
markAsRead, // (chatId: string) => void
updateConversation, // (chatId: string, updates: Partial<ChatConversation>) => void
leaveGroupChat, // (groupId: string) => void
} = useChatList()
Сортировка
Диалоги сортируются по:
- Закреплённые (
pinned) — наверху - Время последнего сообщения — по убыванию
Фильтрация
// Показать только непрочитанные
filter.value = 'unread'
// Поиск по имени или тексту
searchQuery.value = 'Иван'
useChatMessages (per-chat)
Сообщения конкретного диалога. Не shared — каждый экземпляр привязан к chatId.
const chatId = computed(() => route.params.id as string)
const {
messages, // Ref<ChatMessage[]> (readonly)
loading, // Ref<boolean>
hasMore, // Ref<boolean>
error, // Ref<string | null>
replyTo, // Ref<ChatMessage | null>
loadMessages, // () => Promise<void> — загрузить первую страницу
loadMore, // () => Promise<void> — подгрузить историю (cursor)
sendMessage, // (body, attachments?, files?) => ChatMessage | null
editMessage, // (messageId, newBody) => Promise<void>
deleteMessage, // (messageId) => Promise<void>
removeMessage, // (messageId) => void — полное удаление (retry)
editReactions, // (messageId, reactions, toggledEmoji?) => Promise<void>
isOwnMessage, // (msg) => boolean
reset, // () => void — очистка при смене чата
} = useChatMessages(chatId)
Отправка сообщения
// Текст
sendMessage('Привет!')
// Текст с вложениями
sendMessage('Смотри фото', attachments, files)
// Ответ на сообщение
replyTo.value = someMessage
sendMessage('Согласен')
Процесс отправки:
- Создаётся оптимистичное сообщение (status:
sending) - Файлы загружаются через REST (
/api/v1/chat/upload) - Сообщение отправляется через Socket.IO с ack
- При ack — оптимистичное сообщение заменяется серверным
Пагинация
// Infinite scroll
await loadMore() // Подгрузить старые сообщения по cursor
useChatMessageStore (shared)
Глобальный кеш сообщений. Хранит все загруженные сообщения, синхронизируется с useChatMessages.
const {
getMessages, // (chatId) => ChatMessage[]
setMessages, // (chatId, messages) => void
addMessage, // (chatId, message) => void
updateMessage, // (chatId, messageId, updates) => void
updateMessageStatus, // (chatId, messageId, status) => void
deleteMessage, // (chatId, messageId) => void
} = useChatMessageStore()
useChatPresence (shared)
Онлайн-статус и индикатор набора текста.
const {
getPresence, // (userId) => { online: boolean, lastSeen?: string }
setPresence, // (userId, data) => void
getTyping, // (chatId) => string[] — массив userId кто печатает
setTyping, // (chatId, userId, isTyping) => void
sendTyping, // (chatId) => void — отправить typing:start
stopTyping, // (chatId) => void — отправить typing:stop
} = useChatPresence()
useChatUserInfo (shared)
Кеш информации о пользователях из REST API.
const {
getUser, // (userId) => { nickname?, avatarurl? } | undefined
fetchUsers, // (userIds: string[]) => Promise<void>
} = useChatUserInfo()
useChatNotifications (shared)
Уведомления о новых сообщениях. Работает с useHead для обновления счётчика в заголовке.
const {
setActiveChat, // (chatId | null) => void
notifyNewMessage, // (chatId, message, senderName) => void
} = useChatNotifications()
useChatFetch (shared)
Обёртка над $fetch с учётом chatApiBase.
const {
chatUrl, // (path: string) => string — добавляет chatApiBase
chatFetch, // <T>(url, opts?) => Promise<T>
} = useChatFetch()
useChatPageActions (per-page)
Обработчики действий на странице чата — reply, edit, forward, react, pin, mute и т.д.
const {
replyTo, // Ref<ChatMessage | null>
editingMessage, // Ref<ChatMessage | null>
forwardOpen, // Ref<boolean>
forwardMessage, // Ref<ChatMessage | null>
handleSend, // (body, attachments?, files?) => void
handleReply, // (message) => void
handleEdit, // (message) => void
handleCopy, // (message) => void
handleForward, // (message) => void
handleForwardComplete, // ({ targetId, message }) => void
handleReact, // ({ messageId, emoji }) => void
handleRetry, // (message) => void
handlePin, // (message?) => void
handleMute, // () => void
handleClearChat, // () => void
handleLeaveGroup, // () => void
} = useChatPageActions(chatId, chatMessages)
Вспомогательные composables
| Composable | Тип | Описание |
|---|---|---|
useIsMobile() | shared | Определение мобильного viewport |
useChatScroll() | per-chat | Управление скроллом сообщений |
useChatMessageItems() | per-chat | Группировка сообщений + разделители дат |
useChatInputDraft() | per-chat | Автосохранение черновиков |
useChatInputFiles() | per-chat | Управление прикреплёнными файлами |
useChatKeyboard() | per-chat | Горячие клавиши (Esc, Ctrl+F) |
useDragDrop() | per-chat | Drag & drop файлов |
useSwipeReply() | per-chat | Свайп для ответа (мобильные) |