import { useState, useEffect, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Camera, Edit3, Check, Loader2, UserPlus, Trash2, Search, Crown, Users, } from 'lucide-react'; import { api } from '../lib/api'; import { useAuthStore } from '../stores/authStore'; import { useChatStore } from '../stores/chatStore'; import { useLang } from '../lib/i18n'; import { Chat, UserPresence } from '../lib/types'; import ConfirmModal from './ConfirmModal'; interface GroupSettingsProps { chat: Chat; onClose: () => void; } export default function GroupSettings({ chat, onClose }: GroupSettingsProps) { const { user } = useAuthStore(); const { updateChat } = useChatStore(); const { t } = useLang(); const currentMember = chat.members.find((m) => m.user.id === user?.id); const [removeTargetId, setRemoveTargetId] = useState(null); const isAdmin = currentMember?.role === 'admin'; const [isEditingName, setIsEditingName] = useState(false); const [groupName, setGroupName] = useState(chat.name || ''); const [isSaving, setIsSaving] = useState(false); const [avatarUploading, setAvatarUploading] = useState(false); const [showAddMember, setShowAddMember] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [isSearching, setIsSearching] = useState(false); const fileInputRef = useRef(null); const searchInputRef = useRef(null); // Keep local state in sync with chat prop useEffect(() => { setGroupName(chat.name || ''); }, [chat.name]); // Search users to add useEffect(() => { if (!searchQuery.trim()) { setSearchResults([]); return; } const timer = setTimeout(async () => { try { setIsSearching(true); const results = await api.searchUsers(searchQuery); // Filter out users already in the group const memberIds = new Set(chat.members.map((m) => m.user.id)); setSearchResults(results.filter((u) => !memberIds.has(u.id))); } catch (e) { console.error(e); } finally { setIsSearching(false); } }, 300); return () => clearTimeout(timer); }, [searchQuery, chat.members]); const handleSaveName = async () => { if (!groupName.trim()) return; try { setIsSaving(true); const updatedChat = await api.updateGroup(chat.id, { name: groupName.trim() }); updateChat(updatedChat); setIsEditingName(false); } catch (e) { console.error(e); } finally { setIsSaving(false); } }; const handleAvatarUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; try { setAvatarUploading(true); const updatedChat = await api.uploadGroupAvatar(chat.id, file); updateChat(updatedChat); } catch (e) { console.error(e); } finally { setAvatarUploading(false); e.target.value = ''; } }; const handleRemoveAvatar = async () => { try { setAvatarUploading(true); const updatedChat = await api.removeGroupAvatar(chat.id); updateChat(updatedChat); } catch (e) { console.error(e); } finally { setAvatarUploading(false); } }; const handleAddMember = async (userId: string) => { try { const updatedChat = await api.addGroupMembers(chat.id, [userId]); updateChat(updatedChat); setSearchQuery(''); setSearchResults([]); } catch (e) { console.error(e); } }; const handleRemoveMember = async (userId: string) => { setRemoveTargetId(userId); }; const confirmRemoveMember = async () => { if (!removeTargetId) return; try { const updatedChat = await api.removeGroupMember(chat.id, removeTargetId); updateChat(updatedChat); } catch (e) { console.error(e); } setRemoveTargetId(null); }; const initials = (chat.name || 'G') .split(' ') .map((w: string) => w[0]) .join('') .slice(0, 2) .toUpperCase(); return ( <> {/* Header */}

{t('groupSettings')}

{/* Avatar */}
{chat.avatar ? ( ) : (
{initials}
)}
{isAdmin && ( <> {chat.avatar && ( )} )}
{/* Group name */} {isEditingName ? (
setGroupName(e.target.value)} className="flex-1 text-lg font-bold text-center text-white bg-transparent border-b border-vortex-500 outline-none px-2 py-1" autoFocus onKeyDown={(e) => { if (e.key === 'Enter') handleSaveName(); if (e.key === 'Escape') { setIsEditingName(false); setGroupName(chat.name || ''); } }} />
) : (

{chat.name}

{isAdmin && ( )}
)}

{chat.members.length} {t('members')}

{/* Members */}

{t('membersCount')}

{isAdmin && ( )}
{/* Add member search */} {showAddMember && (
setSearchQuery(e.target.value)} placeholder={t('findUser')} className="w-full pl-8 pr-3 py-2 rounded-xl bg-surface-tertiary text-sm text-white placeholder-zinc-500 border border-border focus:border-accent transition-colors" />
{isSearching && (
)} {searchResults.map((u) => ( ))} {searchQuery.trim() && !isSearching && searchResults.length === 0 && (

{t('usersNotFound')}

)}
)}
{/* Member list */}
{chat.members .sort((a, b) => { if (a.role === 'admin' && b.role !== 'admin') return -1; if (b.role === 'admin' && a.role !== 'admin') return 1; return 0; }) .map((member) => (
{member.user.avatar ? ( ) : (
{(member.user.displayName || member.user.username || '?')[0].toUpperCase()}
)} {member.user.isOnline && ( )}

{member.user.displayName || member.user.username} {member.user.id === user?.id && ( ({t('you') || 'вы'}) )}

{member.role === 'admin' && ( {t('adminBadge')} )}

@{member.user.username}

{isAdmin && member.user.id !== user?.id && member.role !== 'admin' && ( )}
))}
setRemoveTargetId(null)} /> ); }