# Веб-кабинет Ласточки ## Обзор Веб-кабинет мессенджера Ласточка предоставляет полный функционал для общения: - 💬 **Личные чаты** — общение один на один - 👥 **Группы** — групповые чаты с участниками - 📢 **Каналы** — публикация контента подписчикам - 🔍 **Поиск** — поиск пользователей и сообщений - ⚙️ **Настройки** — управление профилем и настройками ## Структура ``` src/ ├── components/ │ ├── layout/ │ │ └── Sidebar.tsx # Боковая панель с навигацией │ ├── chat/ │ │ ├── ChatHeader.tsx # Шапка чата │ │ ├── ChatWindow.tsx # Окно чата │ │ ├── MessagesList.tsx # Список сообщений │ │ └── MessageInput.tsx # Ввод сообщений │ ├── sidebar/ │ │ ├── ChatList.tsx # Список чатов │ │ └── ChatItem.tsx # Элемент чата │ └── ui/ │ ├── UserSearch.tsx # Поиск пользователей │ ├── CreateGroupModal.tsx # Создание группы/канала │ ├── MembersPanel.tsx # Панель участников │ └── Avatar.tsx # Аватар ├── store/ │ ├── auth.ts # Аутентификация │ ├── chat.ts # Чаты и сообщения │ └── groups.ts # Группы и каналы └── types/ └── index.ts # Типы данных ``` ## Компоненты ### Sidebar.tsx Боковая панель с переключением между чатами, группами и каналами. **Вкладки:** - **Чаты** — личные и групповые чаты - **Группы** — управление группами - **Каналы** — управление каналами **Функции:** - Поиск по чатам - Счётчики непрочитанных - Быстрое создание групп/каналов ### ChatHeader.tsx Шапка чата с информацией о собеседнике/группе. **Отображение:** - Аватар и имя - Статус (онлайн/был недавно) - Для групп: количество участников - Для каналов: количество подписчиков **Действия:** - Поиск по сообщениям - Показать/скрыть участников - Меню действий ### ChatWindow.tsx Основное окно чата. **Режимы:** - Пустое состояние (чат не выбран) - Активный чат с сообщениями ### UserSearch.tsx Поиск пользователей для добавления в чат или группу. **Props:** ```typescript interface UserSearchProps { onSelect?: (user: User) => void onClose?: () => void showStartChat?: boolean // Показать кнопку "Начать чат" showAddToGroup?: boolean // Показать кнопку "Добавить в группу" groupId?: string // ID группы для добавления } ``` **Функции:** - Debounced поиск (300ms) - Отображение статуса онлайн - Быстрое добавление в группу ### CreateGroupModal.tsx Модальное окно создания группы или канала. **Этапы:** 1. **Информация** — название, описание, тип доступа 2. **Участники** — выбор пользователей **Props:** ```typescript interface CreateGroupModalProps { isOpen: boolean onClose: () => void mode: 'group' | 'channel' } ``` **Параметры создания:** - Название (обязательно) - Описание (необязательно) - Тип доступа (приватный/публичный) - Участники (необязательно) ### MembersPanel.tsx Выезжающая панель участников группы/канала. **Props:** ```typescript interface MembersPanelProps { isOpen: boolean onClose: () => void groupId: string canAddMembers?: boolean canRemoveMembers?: boolean } ``` **Функции:** - Просмотр списка участников - Добавление участников (если разрешено) - Удаление участников (для владельца) - Выход из группы/канала ## Store ### groups.ts Управление группами и каналами. **Состояние:** ```typescript interface GroupsStore { groups: Group[] // Список групп channels: Group[] // Список каналов selectedGroup: Group | null // Выбранная группа isLoading: boolean error: string | null } ``` **Методы:** - `loadGroups()` — загрузка списка групп - `loadChannels()` — загрузка списка каналов - `createGroup(params)` — создание группы - `createChannel(params)` — создание канала - `selectGroup(groupId)` — выбор группы - `addMember(groupId, userId)` — добавление участника - `removeMember(groupId, userId)` — удаление участника - `leaveGroup(groupId)` — выход из группы - `deleteGroup(groupId)` — удаление группы - `updateGroupInfo(groupId, name, description)` — обновление информации - `searchUsersForInvite(query)` — поиск пользователей ## Типы данных ### Group ```typescript interface Group { id: string name: string description?: string avatar?: string owner: string members: GroupMember[] created: Date isChannel: boolean isPublic: boolean membersCount: number } ``` ### GroupMember ```typescript interface GroupMember { userId: string name: string avatar?: string role: 'owner' | 'admin' | 'member' joined: Date online?: boolean } ``` ### CreateGroupParams ```typescript interface CreateGroupParams { name: string description?: string isChannel: boolean isPublic: boolean members: string[] // user IDs avatar?: string } ``` ## Создание группы ```typescript import { useGroupsStore } from '@/store/groups' const { createGroup } = useGroupsStore() const group = await createGroup({ name: 'Моя группа', description: 'Описание группы', isChannel: false, isPublic: false, members: ['user1', 'user2'], }) ``` ## Создание канала ```typescript import { useGroupsStore } from '@/store/groups' const { createChannel } = useGroupsStore() const channel = await createChannel({ name: 'Мой канал', description: 'Описание канала', isPublic: true, members: [], // Можно без участников }) ``` ## Поиск пользователей ```typescript import { useGroupsStore } from '@/store/groups' const { searchUsersForInvite } = useGroupsStore() const users = await searchUsersForInvite('Иван') // [{ id: 'user1', name: 'Иван', online: true }, ...] ``` ## Добавление участника ```typescript import { useGroupsStore } from '@/store/groups' const { addMember } = useGroupsStore() await addMember('group-id', 'user-id') ``` ## Отличия групп и каналов | Параметр | Группа | Канал | |----------|--------|-------| | **Цель** | Общение | Публикация контента | | **Участники** | Могут писать | Только читают (обычно) | | **Создатель** | Владелец | Администратор | | **Доступ** | Приватный/Публичный | Приватный/Публичный | | **Уведомления** | Все сообщения | Только новые посты | ## Типы доступа ### Приватный - Вход только по приглашению - Не отображается в поиске - Участники видны друг другу ### Публичный - Любой может вступить - Отображается в поиске - Можно пригласить ссылку ## Интеграция с Tinode ### Группы Tinode использует topics с префиксом `grp`: ```typescript // Создание группы const groupTopic = tn.getTopic('new') await groupTopic.save({ desc: { public: { fn: 'Название', note: 'Описание', type: 'group', }, }, subs: members.map(userId => ({ user: userId, mode: 'RW', // Read-Write })), }) ``` ### Каналы ```typescript // Создание канала const channelTopic = tn.getTopic('new') await channelTopic.save({ desc: { public: { fn: 'Название', note: 'Описание', type: 'channel', }, }, subs: members.map(userId => ({ user: userId, mode: 'R', // Read-only })), }) ``` ## Роли участников ### Owner (Владелец) - Полный доступ - Может удалять группу - Назначать администраторов - Добавлять/удалять участников ### Admin (Администратор) - Может добавлять участников - Может удалять участников (не админов) - Может редактировать информацию ### Member (Участник) - Может писать сообщения - Может приглашать других (если разрешено) - Может покинуть группу ## Примеры использования ### Создание публичного канала ```typescript const { createChannel } = useGroupsStore() const channel = await createChannel({ name: 'Новости Ласточки', description: 'Официальные новости мессенджера', isPublic: true, members: [], }) // Переход в канал const { setActiveChat } = useChatStore.getState() await setActiveChat(channel.id) ``` ### Добавление участника из поиска ```typescript { console.log('Добавлен:', user) }} /> ``` ### Просмотр участников ```typescript const { selectGroup, selectedGroup } = useGroupsStore() await selectGroup('group-id') console.log(selectedGroup?.members) // [{ userId: 'user1', name: 'Иван', role: 'owner', ... }] ``` --- **Ласточка** — народный мессенджер с открытым кодом 🕊️