import { useState, useEffect, useRef, useCallback } from 'react' import { MessageSquare, X, ChevronLeft, Send, Users, Loader2, Search, Bell, Settings, PenSquare, BellOff, Volume2, VolumeX, Paperclip, Pin, UserPlus, } from 'lucide-react' import { api, type ChatRoom, type ChatMessage, type ChatSearchResult, type ChatReaction } from '../../lib/api' import type { User } from '../../types' import { useAuth } from '../../contexts/AuthContext' import { cn } from '../../lib/utils' // ── Helpers ──────────────────────────────────────────────────────────────── function avatarColor(name: string) { const colors = ['#4F46E5','#059669','#2563EB','#7C3AED','#DC2626','#D97706','#DB2777','#0891B2'] let h = 0 for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) % colors.length return colors[h] } function initials(name: string) { return name.split(' ').map(p => p[0]).join('').toUpperCase().slice(0, 2) } function fmtTime(iso: string) { const d = new Date(iso), now = new Date() if (now.toDateString() === d.toDateString()) return d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }) return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' }) } function Avatar({ name, size = 28, online = false }: { name: string; size?: number; online?: boolean }) { return (
{view === 'rooms' && 'Чат сотрудников'} {view === 'messages' && (activeRoom ? roomDisplayName(activeRoom) : 'Чат')} {view === 'search' && 'Поиск'} {view === 'settings' && 'Настройки чата'} {view === 'create-group' && 'Новая группа'} {view === 'group-info' && 'Настройки группы'}
{/* Online dot in messages header */} {view === 'messages' && activeRoom && isOtherOnline(activeRoom) && ( )}{visibleRooms.length} чатов
} {view === 'messages' && activeRoom?.type === 'direct' && (() => { const roleLabels: Record{online && в сети} {online && roleLabel && ·} {roleLabel && {roleLabel}}
) })()} {view === 'messages' && activeRoom?.type === 'group' && activeRoom.memberCount && ({activeRoom.memberCount} участников
)} {view === 'messages' && activeRoom?.type === 'notifications' && (Только чтение
)}
Правый клик на сообщении — реакции, редактирование, удаление.
Кнопка ⋮ на чате — закрепить / открепить сверху.
Выбрано: {groupMemberIds.length} участника(-ов)
)}Enter — отправить · Shift+Enter — перенос · @ — упомянуть
{toast.roomName}
{showText ? ({toast.senderName ? `${toast.senderName.split(' ')[0]}: ` : ''}{toast.text || 'Новое сообщение'}
) : (Новое сообщение
)}0 ? 'text-slate-900 dark:text-slate-100' : 'text-slate-700 dark:text-slate-300')}> {room.type === 'general' ? 'Общий чат' : room.type === 'notifications' ? 'Уведомления' : room.type === 'group' ? (room.name ?? 'Группа') : room.otherUserName}
{!hovered && room.lastMessageAt && ( {fmtTime(room.lastMessageAt)} )}0 ? 'text-slate-600 dark:text-slate-300 font-medium' : 'text-slate-400 dark:text-slate-500')}> {room.lastSender && room.type === 'general' ? `${room.lastSender.split(' ')[0]}: ` : ''}{room.lastMessage}
)}{isSystem ? msg.systemName ?? 'Система' : msg.senderName.split(' ')[0]}
{roleLabel && ( {roleLabel} )}Сообщение удалено
) : isEditing ? ({fmtTime(msg.createdAt)}
{msg.editedAt &&· изм.
} {isOwn && ( {isRead ? '✓✓' : '✓'} )}{title}
Участники · {currentMemberIds.length}
{u.name} {u.id === currentUserId && (вы)}
{roleLabels[u.role] ?? u.role}
{label}