// components/project/ProjectList.tsx 'use client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { Plus, Folder, Users, Globe, Lock, Crown, Calendar, Search, Filter, Grid3x3, List } 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 { Input } from '@/components/ui/input'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useToast } from '@/hooks/use-toast'; import { cn } from '@/lib/utils'; interface Project { id: string; code: string; name: string; description?: string; isPublic: boolean; createdAt: string; updatedAt: string; role?: string; memberCount?: number; fileCount?: number; } interface ProjectFormData { code: string; name: string; description?: string; isPublic: boolean; } export function ProjectList() { const [projects, setProjects] = useState<{ owned: Project[]; member: Project[]; public: Project[]; }>({ owned: [], member: [], public: [] }); const [searchQuery, setSearchQuery] = useState(''); const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); const [createDialogOpen, setCreateDialogOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const router = useRouter(); const { toast } = useToast(); // React Hook Form 설정 const { register, handleSubmit, reset, formState: { errors, isValid }, watch, setValue, } = useForm({ mode: 'onChange', defaultValues: { code: '', name: '', description: '', isPublic: false, }, }); const watchIsPublic = watch('isPublic'); useEffect(() => { fetchProjects(); }, []); const fetchProjects = async () => { try { const response = await fetch('/api/projects'); const data = await response.json(); setProjects(data); } catch (error) { toast({ title: '오류', description: '프로젝트 목록을 불러올 수 없습니다.', variant: 'destructive', }); } }; const onSubmit = async (data: ProjectFormData) => { setIsSubmitting(true); try { const response = await fetch('/api/projects', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('프로젝트 생성 실패'); const project = await response.json(); toast({ title: '성공', description: '프로젝트가 생성되었습니다.', }); setCreateDialogOpen(false); reset(); fetchProjects(); // 생성된 프로젝트로 이동 router.push(`/evcp/data-room/${project.id}`); } catch (error) { toast({ title: '오류', description: '프로젝트 생성에 실패했습니다.', variant: 'destructive', }); } finally { setIsSubmitting(false); } }; const handleDialogClose = (open: boolean) => { setCreateDialogOpen(open); if (!open) { reset(); } }; const filteredProjects = { owned: projects.owned?.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase()) ), member: projects.member?.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase()) ), public: projects.public?.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase()) ), }; const ProjectCard = ({ project, role }: { project: Project; role?: string }) => ( router.push(`/evcp/data-room/${project.id}/files`)} >
{project.code} {project.name}
{role === 'owner' && ( )} {project.isPublic ? ( ) : ( )}
{project.description || '설명이 없습니다'}
{project.memberCount && ( {project.memberCount} )} {project.fileCount !== undefined && ( {project.fileCount} )}
{new Date(project.updatedAt).toLocaleDateString()}
{role && ( {role} )}
); return ( <> {/* 헤더 */}

프로젝트

파일을 관리하고 팀과 협업하세요

{/* */}
{/* 검색 및 필터 */}
setSearchQuery(e.target.value)} />
{/* 프로젝트 목록 */} 참여 프로젝트 ({filteredProjects.member?.length}) 공개 프로젝트 ({filteredProjects.public?.length}) {filteredProjects.member?.length === 0 ? (

참여 중인 프로젝트가 없습니다

) : viewMode === 'grid' ? (
{filteredProjects.member?.map(project => ( ))}
) : (
{filteredProjects.member?.map(project => ( router.push(`/evcp/data-room/${project.id}/files`)} >

{project.name}

{project.description || '설명이 없습니다'}

{project.role} {project.isPublic ? ( ) : ( )}
))}
)}
{filteredProjects.public?.length === 0 ? (

공개 프로젝트가 없습니다

) : viewMode === 'grid' ? (
{filteredProjects.public?.map(project => ( ))}
) : (
{filteredProjects.public?.map(project => ( router.push(`/evcp/data-room/${project.id}/files`)} >

{project.name}

{project.description || '설명이 없습니다'}

공개
))}
)}
{/* 프로젝트 생성 다이얼로그 */} 새 프로젝트 만들기 팀과 파일을 공유할 새 프로젝트를 생성합니다
{errors.code && (

{errors.code.message}

)}
{errors.name && (

{errors.name.message}

)}
{errors.description && (

{errors.description.message}

)}

모든 사용자가 이 프로젝트를 볼 수 있습니다

setValue('isPublic', checked)} />
); }