From 4614210aa9878922cfa1e424ce677ef893a1b6b2 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 29 Sep 2025 13:31:40 +0000
Subject: (대표님) 구매 권한설정, data room 등
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/project/ProjectList.tsx | 221 ++++++++++++++++++++++++-------------
 1 file changed, 147 insertions(+), 74 deletions(-)

(limited to 'components/project/ProjectList.tsx')

diff --git a/components/project/ProjectList.tsx b/components/project/ProjectList.tsx
index 4a4f7962..9dec7e77 100644
--- a/components/project/ProjectList.tsx
+++ b/components/project/ProjectList.tsx
@@ -2,13 +2,12 @@
 'use client';
 
 import { useState, useEffect } from 'react';
-import { useRouter } from 'next/navigation';
 import { useForm } from 'react-hook-form';
-import { 
-  Plus, 
-  Folder, 
-  Users, 
-  Globe, 
+import {
+  Plus,
+  Folder,
+  Users,
+  Globe,
   Lock,
   Crown,
   Calendar,
@@ -34,6 +33,7 @@ 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';
+import { useRouter, usePathname } from "next/navigation"
 
 interface Project {
   id: string;
@@ -65,11 +65,16 @@ export function ProjectList() {
   const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
   const [createDialogOpen, setCreateDialogOpen] = useState(false);
   const [isSubmitting, setIsSubmitting] = useState(false);
-  
+  const pathname = usePathname()
+
+  const internal = pathname?.includes('evcp')
+
+  console.log(projects)
+
   const router = useRouter();
   const { toast } = useToast();
 
-  // React Hook Form 설정
+  // React Hook Form setup
   const {
     register,
     handleSubmit,
@@ -100,8 +105,8 @@ export function ProjectList() {
       setProjects(data);
     } catch (error) {
       toast({
-        title: '오류',
-        description: '프로젝트 목록을 불러올 수 없습니다.',
+        title: 'Error',
+        description: 'Unable to load project list.',
         variant: 'destructive',
       });
     }
@@ -116,25 +121,25 @@ export function ProjectList() {
         body: JSON.stringify(data),
       });
 
-      if (!response.ok) throw new Error('프로젝트 생성 실패');
+      if (!response.ok) throw new Error('Failed to create project');
 
       const project = await response.json();
-      
+
       toast({
-        title: '성공',
-        description: '프로젝트가 생성되었습니다.',
+        title: 'Success',
+        description: 'Project has been created.',
       });
 
       setCreateDialogOpen(false);
       reset();
       fetchProjects();
-      
-      // 생성된 프로젝트로 이동
+
+      // Navigate to created project
       router.push(`/evcp/data-room/${project.id}`);
     } catch (error) {
       toast({
-        title: '오류',
-        description: '프로젝트 생성에 실패했습니다.',
+        title: 'Error',
+        description: 'Failed to create project.',
         variant: 'destructive',
       });
     } finally {
@@ -150,19 +155,20 @@ export function ProjectList() {
   };
 
   const filteredProjects = {
-    owned: projects.owned?.filter(p => 
+    owned: projects.owned?.filter(p =>
       p.name.toLowerCase().includes(searchQuery.toLowerCase())
-    ),
-    member: projects.member?.filter(p => 
+    ) || [],  // Return empty array instead of undefined
+    member: projects.member?.filter(p =>
       p.name.toLowerCase().includes(searchQuery.toLowerCase())
-    ),
-    public: projects.public?.filter(p => 
+    ) || [],
+    public: projects.public?.filter(p =>
       p.name.toLowerCase().includes(searchQuery.toLowerCase())
-    ),
+    ) || [],
   };
 
+
   const ProjectCard = ({ project, role }: { project: Project; role?: string }) => (
-    <Card 
+    <Card
       className="cursor-pointer hover:shadow-lg transition-shadow"
       onClick={() => router.push(`/evcp/data-room/${project.id}/files`)}
     >
@@ -182,7 +188,7 @@ export function ProjectList() {
           )}
         </div>
         <CardDescription className="line-clamp-2">
-          {project.description || '설명이 없습니다'}
+          {project.description || 'No description'}
         </CardDescription>
       </CardHeader>
       <CardContent>
@@ -217,26 +223,30 @@ export function ProjectList() {
 
   return (
     <>
-      {/* 헤더 */}
+      {/* Header */}
       <div className="flex items-center justify-between mb-6">
         <div>
-          <h1 className="text-3xl font-bold">프로젝트</h1>
+          <h1 className="text-3xl font-bold">Projects</h1>
           <p className="text-muted-foreground mt-1">
-            파일을 관리하고 팀과 협업하세요
+            Manage files and collaborate with your team
           </p>
         </div>
-        {/* <Button onClick={() => setCreateDialogOpen(true)}>
-          <Plus className="h-4 w-4 mr-2" />
-          새 프로젝트
-        </Button> */}
+        {internal &&
+          <Button onClick={() => setCreateDialogOpen(true)}>
+            <Plus className="h-4 w-4 mr-2" />
+            New Project
+          </Button>
+
+        }
+
       </div>
 
-      {/* 검색 및 필터 */}
+      {/* Search and Filter */}
       <div className="flex items-center gap-3 mb-6">
         <div className="relative flex-1 max-w-md">
           <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
           <Input
-            placeholder="프로젝트 검색..."
+            placeholder="Search projects..."
             className="pl-9"
             value={searchQuery}
             onChange={(e) => setSearchQuery(e.target.value)}
@@ -251,22 +261,85 @@ export function ProjectList() {
         </Button>
       </div>
 
-      {/* 프로젝트 목록 */}
+      {/* Project List */}
       <Tabs defaultValue="owned" className="space-y-6">
         <TabsList>
+          {internal &&
+            <TabsTrigger value="owned">
+              My Projects ({filteredProjects.owned?.length})
+            </TabsTrigger>
+          }
+
           <TabsTrigger value="member">
-            참여 프로젝트 ({filteredProjects.member?.length})
+            Joined Projects ({filteredProjects.member?.length})
           </TabsTrigger>
           <TabsTrigger value="public">
-            공개 프로젝트 ({filteredProjects.public?.length})
+            Public Projects ({filteredProjects.public?.length})
           </TabsTrigger>
         </TabsList>
 
+        {/* My Projects Tab */}
+        {internal &&
+          <TabsContent value="owned">
+            {filteredProjects.owned?.length === 0 ? (
+              <div className="text-center py-12">
+                <Crown className="h-12 w-12 text-muted-foreground mx-auto mb-3" />
+                <p className="text-muted-foreground">You don't own any projects</p>
+                <Button
+                  className="mt-4"
+                  onClick={() => setCreateDialogOpen(true)}
+                >
+                  <Plus className="h-4 w-4 mr-2" />
+                  Create your first project
+                </Button>
+              </div>
+            ) : viewMode === 'grid' ? (
+              <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
+                {filteredProjects.owned?.map(project => (
+                  <ProjectCard key={project.id} project={project} role="owner" />
+                ))}
+              </div>
+            ) : (
+              <div className="space-y-2">
+                {filteredProjects.owned?.map(project => (
+                  <Card
+                    key={project.id}
+                    className="cursor-pointer hover:shadow transition-shadow"
+                    onClick={() => router.push(`/evcp/data-room/${project.id}/files`)}
+                  >
+                    <CardContent className="flex items-center justify-between p-4">
+                      <div className="flex items-center gap-3">
+                        <Folder className="h-5 w-5 text-blue-500" />
+                        <div>
+                          <p className="font-medium">{project.code} {project.name}</p>
+                          <p className="text-sm text-muted-foreground">
+                            {project.description || 'No description'}
+                          </p>
+                        </div>
+                      </div>
+                      <div className="flex items-center gap-2">
+                        <Badge variant="secondary">Owner</Badge>
+                        {project.isPublic ? (
+                          <Globe className="h-4 w-4 text-green-500" />
+                        ) : (
+                          <Lock className="h-4 w-4 text-gray-500" />
+                        )}
+                      </div>
+                    </CardContent>
+                  </Card>
+                ))}
+              </div>
+            )}
+          </TabsContent>
+
+
+        }
+
         <TabsContent value="member">
           {filteredProjects.member?.length === 0 ? (
             <div className="text-center py-12">
               <Users className="h-12 w-12 text-muted-foreground mx-auto mb-3" />
-              <p className="text-muted-foreground">참여 중인 프로젝트가 없습니다</p>
+              <p className="text-muted-foreground">You are not a member of any projects</p>
             </div>
           ) : viewMode === 'grid' ? (
             <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
@@ -277,7 +350,7 @@ export function ProjectList() {
           ) : (
             <div className="space-y-2">
               {filteredProjects.member?.map(project => (
-                <Card 
+                <Card
                   key={project.id}
                   className="cursor-pointer hover:shadow transition-shadow"
                   onClick={() => router.push(`/evcp/data-room/${project.id}/files`)}
@@ -286,9 +359,9 @@ export function ProjectList() {
                     <div className="flex items-center gap-3">
                       <Folder className="h-5 w-5 text-blue-500" />
                       <div>
-                        <p className="font-medium">{project.name}</p>
+                        <p className="font-medium">{project.code} {project.name}</p>
                         <p className="text-sm text-muted-foreground">
-                          {project.description || '설명이 없습니다'}
+                          {project.description || 'No description'}
                         </p>
                       </div>
                     </div>
@@ -311,7 +384,7 @@ export function ProjectList() {
           {filteredProjects.public?.length === 0 ? (
             <div className="text-center py-12">
               <Globe className="h-12 w-12 text-muted-foreground mx-auto mb-3" />
-              <p className="text-muted-foreground">공개 프로젝트가 없습니다</p>
+              <p className="text-muted-foreground">No public projects</p>
             </div>
           ) : viewMode === 'grid' ? (
             <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
@@ -322,7 +395,7 @@ export function ProjectList() {
           ) : (
             <div className="space-y-2">
               {filteredProjects.public?.map(project => (
-                <Card 
+                <Card
                   key={project.id}
                   className="cursor-pointer hover:shadow transition-shadow"
                   onClick={() => router.push(`/evcp/data-room/${project.id}/files`)}
@@ -331,13 +404,13 @@ export function ProjectList() {
                     <div className="flex items-center gap-3">
                       <Globe className="h-5 w-5 text-green-500" />
                       <div>
-                        <p className="font-medium">{project.name}</p>
+                        <p className="font-medium">{project.code} {project.name}</p>
                         <p className="text-sm text-muted-foreground">
-                          {project.description || '설명이 없습니다'}
+                          {project.description || 'No description'}
                         </p>
                       </div>
                     </div>
-                    <Badge variant="outline">공개</Badge>
+                    <Badge variant="outline">Public</Badge>
                   </CardContent>
                 </Card>
               ))}
@@ -346,32 +419,32 @@ export function ProjectList() {
         </TabsContent>
       </Tabs>
 
-      {/* 프로젝트 생성 다이얼로그 */}
+      {/* Create Project Dialog */}
       <Dialog open={createDialogOpen} onOpenChange={handleDialogClose}>
         <DialogContent>
           <DialogHeader>
-            <DialogTitle>새 프로젝트 만들기</DialogTitle>
+            <DialogTitle>Create New Project</DialogTitle>
             <DialogDescription>
-              팀과 파일을 공유할 새 프로젝트를 생성합니다
+              Create a new project to share files with your team
             </DialogDescription>
           </DialogHeader>
-          
+
           <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
             <div>
               <Label htmlFor="code">
-                프로젝트 코드 <span className="text-red-500">*</span>
+                Project Code <span className="text-red-500">*</span>
               </Label>
               <Input
                 id="code"
                 {...register('code', {
-                  required: '프로젝트 코드는 필수입니다',
+                  required: 'Project code is required',
                   minLength: {
                     value: 2,
-                    message: '프로젝트 코드는 최소 2자 이상이어야 합니다',
+                    message: 'Project code must be at least 2 characters',
                   },
                   pattern: {
                     value: /^[A-Z0-9]+$/,
-                    message: '프로젝트 코드는 대문자와 숫자만 사용 가능합니다',
+                    message: 'Project code can only contain uppercase letters and numbers',
                   },
                 })}
                 placeholder="SN1001"
@@ -384,52 +457,52 @@ export function ProjectList() {
 
             <div>
               <Label htmlFor="name">
-                프로젝트 이름 <span className="text-red-500">*</span>
+                Project Name <span className="text-red-500">*</span>
               </Label>
               <Input
                 id="name"
                 {...register('name', {
-                  required: '프로젝트 이름은 필수입니다',
+                  required: 'Project name is required',
                   minLength: {
                     value: 2,
-                    message: '프로젝트 이름은 최소 2자 이상이어야 합니다',
+                    message: 'Project name must be at least 2 characters',
                   },
                   maxLength: {
                     value: 50,
-                    message: '프로젝트 이름은 50자를 초과할 수 없습니다',
+                    message: 'Project name cannot exceed 50 characters',
                   },
                 })}
-                placeholder="예: FNLG"
+                placeholder="e.g. FNLG"
                 className={errors.name ? 'border-red-500' : ''}
               />
               {errors.name && (
                 <p className="text-sm text-red-500 mt-1">{errors.name.message}</p>
               )}
             </div>
-            
+
             <div>
-              <Label htmlFor="description">설명 (선택)</Label>
+              <Label htmlFor="description">Description (Optional)</Label>
               <Input
                 id="description"
                 {...register('description', {
                   maxLength: {
                     value: 200,
-                    message: '설명은 200자를 초과할 수 없습니다',
+                    message: 'Description cannot exceed 200 characters',
                   },
                 })}
-                placeholder="프로젝트에 대한 간단한 설명"
+                placeholder="Brief description of the project"
                 className={errors.description ? 'border-red-500' : ''}
               />
               {errors.description && (
                 <p className="text-sm text-red-500 mt-1">{errors.description.message}</p>
               )}
             </div>
-            
+
             <div className="flex items-center justify-between">
               <div>
-                <Label htmlFor="public">공개 프로젝트</Label>
+                <Label htmlFor="public">Public Project</Label>
                 <p className="text-sm text-muted-foreground">
-                  모든 사용자가 이 프로젝트를 볼 수 있습니다
+                  All users can view this project
                 </p>
               </div>
               <Switch
@@ -438,21 +511,21 @@ export function ProjectList() {
                 onCheckedChange={(checked) => setValue('isPublic', checked)}
               />
             </div>
-            
+
             <DialogFooter>
-              <Button 
-                type="button" 
-                variant="outline" 
+              <Button
+                type="button"
+                variant="outline"
                 onClick={() => handleDialogClose(false)}
                 disabled={isSubmitting}
               >
-                취소
+                Cancel
               </Button>
-              <Button 
+              <Button
                 type="submit"
                 disabled={!isValid || isSubmitting}
               >
-                {isSubmitting ? '생성 중...' : '프로젝트 생성'}
+                {isSubmitting ? 'Creating...' : 'Create Project'}
               </Button>
             </DialogFooter>
           </form>
-- 
cgit v1.2.3

