'use client'; import { useState, useEffect, useCallback } from 'react'; import { useParams, useRouter } from 'next/navigation'; import Link from 'next/link'; import { motion, AnimatePresence } from 'framer-motion'; import { ArrowLeft, FolderOpen, Plus, Users, MessageSquare, Settings, UserPlus, Loader2, Clock, MoreHorizontal, Trash2, Crown, Shield, User, Copy, Check, X, Send, } from 'lucide-react'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import * as Dialog from '@radix-ui/react-dialog'; import { fetchSpace, fetchSpaceMembers, fetchSpaceThreads, inviteToSpace, removeSpaceMember } from '@/lib/api'; import type { Space, SpaceMember, Thread } from '@/lib/types'; import { useAuth } from '@/lib/contexts/AuthContext'; function formatDate(dateStr: string): string { const date = new Date(dateStr); const now = new Date(); const diff = now.getTime() - date.getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) return 'Сегодня'; if (days === 1) return 'Вчера'; if (days < 7) return `${days} дн. назад`; return date.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' }); } function getRoleIcon(role: string) { switch (role) { case 'owner': return Crown; case 'admin': return Shield; default: return User; } } function getRoleLabel(role: string) { switch (role) { case 'owner': return 'Владелец'; case 'admin': return 'Админ'; default: return 'Участник'; } } export default function SpaceDetailPage() { const params = useParams(); const router = useRouter(); const { user } = useAuth(); const spaceId = params.id as string; const [space, setSpace] = useState(null); const [members, setMembers] = useState([]); const [threads, setThreads] = useState([]); const [isLoading, setIsLoading] = useState(true); const [activeTab, setActiveTab] = useState<'threads' | 'members'>('threads'); const [showInviteModal, setShowInviteModal] = useState(false); const [inviteEmail, setInviteEmail] = useState(''); const [inviteLoading, setInviteLoading] = useState(false); const [inviteError, setInviteError] = useState(''); const [inviteSuccess, setInviteSuccess] = useState(''); const isOwner = space?.userId === user?.id; const currentMember = members.find(m => m.userId === user?.id); const isAdmin = isOwner || currentMember?.role === 'admin'; const loadData = useCallback(async () => { setIsLoading(true); try { const [spaceData, membersData, threadsData] = await Promise.all([ fetchSpace(spaceId), fetchSpaceMembers(spaceId), fetchSpaceThreads(spaceId), ]); setSpace(spaceData); setMembers(membersData); setThreads(threadsData); } catch (err) { console.error('Failed to load space:', err); } finally { setIsLoading(false); } }, [spaceId]); useEffect(() => { loadData(); }, [loadData]); const handleInvite = async (e: React.FormEvent) => { e.preventDefault(); if (!inviteEmail.trim() || inviteLoading) return; setInviteLoading(true); setInviteError(''); setInviteSuccess(''); try { await inviteToSpace(spaceId, inviteEmail.trim()); setInviteSuccess(`Приглашение отправлено на ${inviteEmail}`); setInviteEmail(''); setTimeout(() => setShowInviteModal(false), 2000); } catch (err) { setInviteError(err instanceof Error ? err.message : 'Не удалось отправить приглашение'); } finally { setInviteLoading(false); } }; const handleRemoveMember = async (memberId: string, userId: string) => { if (!confirm('Удалить участника из пространства?')) return; try { await removeSpaceMember(spaceId, userId); setMembers(prev => prev.filter(m => m.id !== memberId)); } catch (err) { console.error('Failed to remove member:', err); } }; const startNewThread = () => { router.push(`/?space=${spaceId}`); }; if (isLoading) { return (

Загрузка пространства...

); } if (!space) { return (

Пространство не найдено

Возможно, оно было удалено или у вас нет доступа

К списку пространств
); } return (
{/* Header */}

{space.name}

{space.description && (

{space.description}

)}
{isAdmin && ( )}
{/* Stats */}
{members.length} участник{members.length === 1 ? '' : members.length < 5 ? 'а' : 'ов'}
{threads.length} тред{threads.length === 1 ? '' : threads.length < 5 ? 'а' : 'ов'}
{/* Tabs */}
{/* Content */} {activeTab === 'threads' ? ( {/* New Thread Button */} {/* Threads List */} {threads.length > 0 ? (
{threads.map((thread, i) => (

{thread.title || 'Без названия'}

{formatDate(thread.updatedAt)} {thread.messages?.length || 0} сообщений
))}
) : (

Пока нет тредов

Начните новый тред для обсуждения

)}
) : ( {/* Members List */}
{members.map((member, i) => { const RoleIcon = getRoleIcon(member.role); const canRemove = isAdmin && member.userId !== user?.id && member.role !== 'owner'; return (
{member.avatar ? ( ) : ( {(member.name || member.email || '?').charAt(0).toUpperCase()} )}
{member.name || member.email} {getRoleLabel(member.role)}
{member.email && member.name && (

{member.email}

)}
{canRemove && ( handleRemoveMember(member.id, member.userId)} className="flex items-center gap-2 px-3 py-2.5 text-sm text-error rounded-lg cursor-pointer hover:bg-error/10 outline-none transition-colors" > Удалить )}
); })}
{/* Invite Button */} {isAdmin && ( )}
)}
{/* Invite Modal */}
Пригласить участника

Введите email пользователя, которого хотите пригласить в пространство

{inviteError && (
{inviteError}
)} {inviteSuccess && (
{inviteSuccess}
)}
setInviteEmail(e.target.value)} placeholder="email@example.com" className="w-full px-4 py-3 bg-surface/50 border border-border rounded-xl text-primary placeholder:text-muted focus:outline-none input-gradient transition-colors" autoFocus />
); }