// components/project/ProjectDashboard.tsx 'use client'; import React, { useState, useEffect } from 'react'; import { Crown, Users, Settings, FolderOpen, Shield, UserPlus, Trash2, BarChart3, Eye, Download, HardDrive, UserCog, Loader2 } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { useToast } from '@/hooks/use-toast'; import { useSession } from 'next-auth/react'; interface ProjectDashboardProps { projectId: string; } interface ProjectStats { files: { totalFiles: number; totalSize: number; publicFiles: number; restrictedFiles: number; confidentialFiles: number; }; members: { totalMembers: number; admins: number; editors: number; viewers: number; }; activity: { views: number; downloads: number; uploads: number; uniqueUsers: number; }; } export function ProjectDashboard({ projectId }: ProjectDashboardProps) { const { data: session } = useSession(); const [isOwner, setIsOwner] = useState(false); const [projectRole, setProjectRole] = useState('viewer'); const [stats, setStats] = useState(null); const [members, setMembers] = useState([]); const [loading, setLoading] = useState(true); console.log(stats) // 다이얼로그 상태 const [addMemberOpen, setAddMemberOpen] = useState(false); const [transferOwnershipOpen, setTransferOwnershipOpen] = useState(false); const [newMemberEmail, setNewMemberEmail] = useState(''); const [newMemberRole, setNewMemberRole] = useState('viewer'); const [newOwnerId, setNewOwnerId] = useState(''); const { toast } = useToast(); // 프로젝트 정보 및 권한 확인 useEffect(() => { const fetchProjectData = async () => { try { // 권한 확인 const accessRes = await fetch(`/api/projects/${projectId}/access`); const accessData = await accessRes.json(); setIsOwner(accessData.isOwner); setProjectRole(accessData.role); // Owner인 경우 통계 가져오기 if (accessData.isOwner) { const statsRes = await fetch(`/api/projects/${projectId}/stats`); const statsData = await statsRes.json(); setStats(statsData); } // 멤버 목록 가져오기 const membersRes = await fetch(`/api/projects/${projectId}/members`); const membersData = await membersRes.json(); setMembers(membersData.member); } catch (error) { console.error('프로젝트 데이터 로드 실패:', error); } finally { setLoading(false); } }; fetchProjectData(); }, [projectId]); // 멤버 추가 const handleAddMember = async () => { try { const response = await fetch(`/api/projects/${projectId}/members`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: newMemberEmail, role: newMemberRole, }), }); if (!response.ok) { throw new Error('멤버 추가 실패'); } toast({ title: '성공', description: '새 멤버가 추가되었습니다.', }); setAddMemberOpen(false); // 멤버 목록 새로고침 } catch (error) { toast({ title: '오류', description: '멤버 추가에 실패했습니다.', variant: 'destructive', }); } }; // 소유권 이전 const handleTransferOwnership = async () => { try { const response = await fetch(`/api/projects/${projectId}/transfer-ownership`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ newOwnerId: newOwnerId, }), }); if (!response.ok) { throw new Error('소유권 이전 실패'); } toast({ title: '성공', description: '프로젝트 소유권이 이전되었습니다.', }); setTransferOwnershipOpen(false); setIsOwner(false); } catch (error) { toast({ title: '오류', description: '소유권 이전에 실패했습니다.', variant: 'destructive', }); } }; const formatBytes = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const roleConfig = { owner: { label: 'Owner', icon: Crown, color: 'text-yellow-500' }, admin: { label: 'Admin', icon: Shield, color: 'text-blue-500' }, editor: { label: 'Editor', icon: FolderOpen, color: 'text-green-500' }, viewer: { label: 'Viewer', icon: Eye, color: 'text-gray-500' }, }; if (loading) { return (

프로젝트 정보를 불러오는 중...

); } return (
{/* 헤더 */}

프로젝트 대시보드

{roleConfig[projectRole as keyof typeof roleConfig].icon && React.createElement(roleConfig[projectRole as keyof typeof roleConfig].icon, { className: `h-3 w-3 ${roleConfig[projectRole as keyof typeof roleConfig].color}` }) } {roleConfig[projectRole as keyof typeof roleConfig].label}
{isOwner && (
)}
{/* Owner 전용 통계 */} {isOwner && stats && (
총 파일 수
{stats.storage.fileCount}

{formatBytes(stats.storage.used)}

멤버
{stats.users.total}
관리자 {stats.users.byRole.admins} 편집자 {stats.users.byRole.editors}
조회수 (30일)
{stats.activity.views}

활성 사용자 {stats.users.active}명

다운로드 (30일)
{stats.activity.downloads}

업로드 {stats.activity.uploads}개

)} {/* 탭 컨텐츠 */} 멤버 {isOwner && ( <> 권한 관리 위험 영역 )} 프로젝트 멤버 이 프로젝트에 접근할 수 있는 사용자 목록
{members.map((member) => (
{member.user.name?.charAt(0).toUpperCase()}

{member.user.name}

{member.user.email}

{roleConfig[member.role as keyof typeof roleConfig].icon && React.createElement(roleConfig[member.role as keyof typeof roleConfig].icon, { className: `h-3 w-3 mr-1 ${roleConfig[member.role as keyof typeof roleConfig].color}` }) } {roleConfig[member.role as keyof typeof roleConfig].label}
))}
{isOwner && ( 위험 영역 이 작업들은 되돌릴 수 없습니다. 신중하게 진행하세요.

소유권 이전

프로젝트 소유권을 다른 멤버에게 이전합니다

프로젝트 삭제

프로젝트와 모든 파일을 영구적으로 삭제합니다

)}
{/* 멤버 추가 다이얼로그 */} 멤버 추가 프로젝트에 새 멤버를 추가합니다
setNewMemberEmail(e.target.value)} placeholder="user@example.com" />
{/* 소유권 이전 다이얼로그 */} 소유권 이전 주의: 이 작업은 되돌릴 수 없습니다. 프로젝트의 모든 권한이 새 소유자에게 이전됩니다.
); }