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/ProjectDashboard.tsx | 465 +++++++++++++++++++++++++-------
 1 file changed, 369 insertions(+), 96 deletions(-)

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

diff --git a/components/project/ProjectDashboard.tsx b/components/project/ProjectDashboard.tsx
index d9ec2e0c..5f8afb75 100644
--- a/components/project/ProjectDashboard.tsx
+++ b/components/project/ProjectDashboard.tsx
@@ -15,7 +15,10 @@ import {
   Download,
   HardDrive,
   UserCog,
-  Loader2
+  Loader2,
+  Edit2,
+  Check,
+  ChevronsUpDown
 } from 'lucide-react';
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
 import { Button } from '@/components/ui/button';
@@ -36,10 +39,25 @@ import {
   SelectTrigger,
   SelectValue,
 } from '@/components/ui/select';
+import {
+  Popover,
+  PopoverContent,
+  PopoverTrigger,
+} from '@/components/ui/popover';
+import {
+  Command,
+  CommandEmpty,
+  CommandGroup,
+  CommandInput,
+  CommandItem,
+  CommandList,
+} from '@/components/ui/command';
 import { Input } from '@/components/ui/input';
 import { Label } from '@/components/ui/label';
 import { useToast } from '@/hooks/use-toast';
 import { useSession } from 'next-auth/react';
+import { getUsersForFilter } from '@/lib/gtc-contract/service';
+import { cn } from '@/lib/utils';
 
 interface ProjectDashboardProps {
   projectId: string;
@@ -67,6 +85,13 @@ interface ProjectStats {
   };
 }
 
+interface User {
+  id: number;
+  name: string;
+  email: string;
+  domain?: string; // 'partners' | 'internal' etc
+}
+
 export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
   const { data: session } = useSession();
   const [isOwner, setIsOwner] = useState(false);
@@ -75,41 +100,46 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
   const [members, setMembers] = useState<any[]>([]);
   const [loading, setLoading] = useState(true);
 
-  console.log(stats)
-  
-  // 다이얼로그 상태
+  // Dialog states
   const [addMemberOpen, setAddMemberOpen] = useState(false);
   const [transferOwnershipOpen, setTransferOwnershipOpen] = useState(false);
-  const [newMemberEmail, setNewMemberEmail] = useState('');
-  const [newMemberRole, setNewMemberRole] = useState('viewer');
   const [newOwnerId, setNewOwnerId] = useState('');
   
+  // User selection related states
+  const [availableUsers, setAvailableUsers] = useState<User[]>([]);
+  const [selectedUser, setSelectedUser] = useState<User | null>(null);
+  const [userSearchTerm, setUserSearchTerm] = useState('');
+  const [userPopoverOpen, setUserPopoverOpen] = useState(false);
+  const [loadingUsers, setLoadingUsers] = useState(false);
+  const [isExternalUser, setIsExternalUser] = useState(false);
+  const [newMemberRole, setNewMemberRole] = useState<string>('viewer');
+  
   const { toast } = useToast();
 
-  // 프로젝트 정보 및 권한 확인
+  // Fetch project info and permissions
   useEffect(() => {
     const fetchProjectData = async () => {
       try {
-        // 권한 확인
+        // Check permissions
         const accessRes = await fetch(`/api/projects/${projectId}/access`);
         const accessData = await accessRes.json();
         setIsOwner(accessData.isOwner);
         setProjectRole(accessData.role);
 
-        // Owner인 경우 통계 가져오기
+        // Get stats if owner
         if (accessData.isOwner) {
           const statsRes = await fetch(`/api/projects/${projectId}/stats`);
           const statsData = await statsRes.json();
           setStats(statsData);
         }
 
-        // 멤버 목록 가져오기
+        // Get member list
         const membersRes = await fetch(`/api/projects/${projectId}/members`);
         const membersData = await membersRes.json();
         setMembers(membersData.member);
 
       } catch (error) {
-        console.error('프로젝트 데이터 로드 실패:', error);
+        console.error('Failed to load project data:', error);
       } finally {
         setLoading(false);
       }
@@ -118,39 +148,84 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
     fetchProjectData();
   }, [projectId]);
 
-  // 멤버 추가
+  // Fetch user list when dialog opens
+  useEffect(() => {
+    if (addMemberOpen) {
+      fetchAvailableUsers();
+    } else {
+      // Reset when dialog closes
+      setSelectedUser(null);
+      setUserSearchTerm('');
+      setNewMemberRole('viewer');
+      setIsExternalUser(false);
+    }
+  }, [addMemberOpen]);
+
+  const fetchAvailableUsers = async () => {
+    try {
+      setLoadingUsers(true);
+      const users = await getUsersForFilter();
+      // Exclude members already in project
+      const memberUserIds = members.map(m => m.userId);
+      const filteredUsers = users.filter(u => !memberUserIds.includes(u.id));
+      setAvailableUsers(filteredUsers);
+    } catch (error) {
+      console.error('Failed to load user list:', error);
+      toast({
+        title: 'Error',
+        description: 'Unable to load user list.',
+        variant: 'destructive',
+      });
+    } finally {
+      setLoadingUsers(false);
+    }
+  };
+
+  // Add member
   const handleAddMember = async () => {
+    if (!selectedUser) {
+      toast({
+        title: 'Error',
+        description: 'Please select a user.',
+        variant: 'destructive',
+      });
+      return;
+    }
+
     try {
       const response = await fetch(`/api/projects/${projectId}/members`, {
         method: 'POST',
         headers: { 'Content-Type': 'application/json' },
         body: JSON.stringify({
-          email: newMemberEmail,
+          userId: selectedUser.id,
           role: newMemberRole,
         }),
       });
 
       if (!response.ok) {
-        throw new Error('멤버 추가 실패');
+        throw new Error('Failed to add member');
       }
 
       toast({
-        title: '성공',
-        description: '새 멤버가 추가되었습니다.',
+        title: 'Success',
+        description: 'New member has been added.',
       });
 
       setAddMemberOpen(false);
-      // 멤버 목록 새로고침
+      // Refresh member list
+      const membersRes = await fetch(`/api/projects/${projectId}/members`);
+      const membersData = await membersRes.json();
+      setMembers(membersData.member);
     } catch (error) {
       toast({
-        title: '오류',
-        description: '멤버 추가에 실패했습니다.',
+        title: 'Error',
+        description: 'Failed to add member.',
         variant: 'destructive',
       });
     }
   };
 
-  // 소유권 이전
+  // Transfer ownership
   const handleTransferOwnership = async () => {
     try {
       const response = await fetch(`/api/projects/${projectId}/transfer-ownership`, {
@@ -162,20 +237,20 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
       });
 
       if (!response.ok) {
-        throw new Error('소유권 이전 실패');
+        throw new Error('Failed to transfer ownership');
       }
 
       toast({
-        title: '성공',
-        description: '프로젝트 소유권이 이전되었습니다.',
+        title: 'Success',
+        description: 'Project ownership has been transferred.',
       });
 
       setTransferOwnershipOpen(false);
       setIsOwner(false);
     } catch (error) {
       toast({
-        title: '오류',
-        description: '소유권 이전에 실패했습니다.',
+        title: 'Error',
+        description: 'Failed to transfer ownership.',
         variant: 'destructive',
       });
     }
@@ -192,16 +267,22 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
   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' },
+    editor: { label: 'Editor', icon: Edit2, color: 'text-green-500' },
     viewer: { label: 'Viewer', icon: Eye, color: 'text-gray-500' },
   };
 
+  // User search filtering
+  const filteredUsers = availableUsers.filter(user =>
+    user.name.toLowerCase().includes(userSearchTerm.toLowerCase()) ||
+    user.email.toLowerCase().includes(userSearchTerm.toLowerCase())
+  );
+
   if (loading) {
     return (
       <div className="flex items-center justify-center min-h-[400px]">
         <div className="text-center space-y-3">
           <Loader2 className="h-8 w-8 animate-spin text-primary mx-auto" />
-          <p className="text-sm text-muted-foreground">프로젝트 정보를 불러오는 중...</p>
+          <p className="text-sm text-muted-foreground">Loading project information...</p>
         </div>
       </div>
     );
@@ -209,10 +290,10 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
 
   return (
     <div className="p-6 space-y-6">
-      {/* 헤더 */}
+      {/* Header */}
       <div className="flex items-center justify-between">
         <div className="flex items-center gap-3">
-          <h1 className="text-2xl font-bold">프로젝트 대시보드</h1>
+          <h1 className="text-2xl font-bold">Project Dashboard</h1>
           <Badge variant="outline" className="flex items-center gap-1">
             {roleConfig[projectRole as keyof typeof roleConfig].icon && 
               React.createElement(roleConfig[projectRole as keyof typeof roleConfig].icon, {
@@ -227,22 +308,22 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
           <div className="flex gap-2">
             <Button onClick={() => setAddMemberOpen(true)}>
               <UserPlus className="h-4 w-4 mr-2" />
-              멤버 추가
+              Add Member
             </Button>
             <Button variant="outline">
               <Settings className="h-4 w-4 mr-2" />
-              설정
+              Settings
             </Button>
           </div>
         )}
       </div>
 
-      {/* Owner 전용 통계 */}
+      {/* Owner-only statistics */}
       {isOwner && stats && (
         <div className="grid grid-cols-4 gap-4">
           <Card>
             <CardHeader className="pb-2">
-              <CardTitle className="text-sm font-medium">총 파일 수</CardTitle>
+              <CardTitle className="text-sm font-medium">Total Files</CardTitle>
             </CardHeader>
             <CardContent>
               <div className="text-2xl font-bold">{stats.storage.fileCount}</div>
@@ -254,16 +335,16 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
 
           <Card>
             <CardHeader className="pb-2">
-              <CardTitle className="text-sm font-medium">멤버</CardTitle>
+              <CardTitle className="text-sm font-medium">Members</CardTitle>
             </CardHeader>
             <CardContent>
               <div className="text-2xl font-bold">{stats.users.total}</div>
               <div className="flex gap-2 mt-1">
                 <span className="text-xs text-muted-foreground">
-                  관리자 {stats.users.byRole.admins}
+                  Admins {stats.users.byRole.admins}
                 </span>
                 <span className="text-xs text-muted-foreground">
-                  편집자 {stats.users.byRole.editors}
+                  Editors {stats.users.byRole.editors}
                 </span>
               </div>
             </CardContent>
@@ -271,38 +352,38 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
 
           <Card>
             <CardHeader className="pb-2">
-              <CardTitle className="text-sm font-medium">조회수 (30일)</CardTitle>
+              <CardTitle className="text-sm font-medium">Views (30 days)</CardTitle>
             </CardHeader>
             <CardContent>
               <div className="text-2xl font-bold">{stats.activity.views}</div>
               <p className="text-xs text-muted-foreground mt-1">
-                활성 사용자 {stats.users.active}명
+                {stats.users.active} active users
               </p>
             </CardContent>
           </Card>
 
           <Card>
             <CardHeader className="pb-2">
-              <CardTitle className="text-sm font-medium">다운로드 (30일)</CardTitle>
+              <CardTitle className="text-sm font-medium">Downloads (30 days)</CardTitle>
             </CardHeader>
             <CardContent>
               <div className="text-2xl font-bold">{stats.activity.downloads}</div>
               <p className="text-xs text-muted-foreground mt-1">
-                업로드 {stats.activity.uploads}개
+                {stats.activity.uploads} uploads
               </p>
             </CardContent>
           </Card>
         </div>
       )}
 
-      {/* 탭 컨텐츠 */}
+      {/* Tab content */}
       <Tabs defaultValue="members">
         <TabsList>
-          <TabsTrigger value="members">멤버</TabsTrigger>
+          <TabsTrigger value="members">Members</TabsTrigger>
           {isOwner && (
             <>
-              <TabsTrigger value="permissions">권한 관리</TabsTrigger>
-              <TabsTrigger value="danger">위험 영역</TabsTrigger>
+              <TabsTrigger value="permissions">Permission Management</TabsTrigger>
+              <TabsTrigger value="danger">Danger Zone</TabsTrigger>
             </>
           )}
         </TabsList>
@@ -310,9 +391,9 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
         <TabsContent value="members" className="mt-6">
           <Card>
             <CardHeader>
-              <CardTitle>프로젝트 멤버</CardTitle>
+              <CardTitle>Project Members</CardTitle>
               <CardDescription>
-                이 프로젝트에 접근할 수 있는 사용자 목록
+                List of users who can access this project
               </CardDescription>
             </CardHeader>
             <CardContent>
@@ -347,17 +428,17 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
           <TabsContent value="danger" className="mt-6">
             <Card className="border-red-200">
               <CardHeader>
-                <CardTitle className="text-red-600">위험 영역</CardTitle>
+                <CardTitle className="text-red-600">Danger Zone</CardTitle>
                 <CardDescription>
-                  이 작업들은 되돌릴 수 없습니다. 신중하게 진행하세요.
+                  These actions cannot be undone. Please proceed with caution.
                 </CardDescription>
               </CardHeader>
               <CardContent className="space-y-4">
                 <div className="flex items-center justify-between p-4 border rounded-lg">
                   <div>
-                    <h3 className="font-medium">소유권 이전</h3>
+                    <h3 className="font-medium">Transfer Ownership</h3>
                     <p className="text-sm text-muted-foreground">
-                      프로젝트 소유권을 다른 멤버에게 이전합니다
+                      Transfer project ownership to another member
                     </p>
                   </div>
                   <Button 
@@ -365,20 +446,20 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
                     onClick={() => setTransferOwnershipOpen(true)}
                   >
                     <UserCog className="h-4 w-4 mr-2" />
-                    소유권 이전
+                    Transfer Ownership
                   </Button>
                 </div>
 
                 <div className="flex items-center justify-between p-4 border rounded-lg border-red-200">
                   <div>
-                    <h3 className="font-medium text-red-600">프로젝트 삭제</h3>
+                    <h3 className="font-medium text-red-600">Delete Project</h3>
                     <p className="text-sm text-muted-foreground">
-                      프로젝트와 모든 파일을 영구적으로 삭제합니다
+                      Permanently delete project and all files
                     </p>
                   </div>
                   <Button variant="destructive">
                     <Trash2 className="h-4 w-4 mr-2" />
-                    프로젝트 삭제
+                    Delete Project
                   </Button>
                 </div>
               </CardContent>
@@ -387,67 +468,259 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
         )}
       </Tabs>
 
-      {/* 멤버 추가 다이얼로그 */}
+      {/* Add Member Dialog */}
       <Dialog open={addMemberOpen} onOpenChange={setAddMemberOpen}>
-        <DialogContent>
+        <DialogContent className="max-w-lg">
           <DialogHeader>
-            <DialogTitle>멤버 추가</DialogTitle>
+            <DialogTitle>Add Member</DialogTitle>
             <DialogDescription>
-              프로젝트에 새 멤버를 추가합니다
+              Add a member to the project
             </DialogDescription>
           </DialogHeader>
-          
-          <div className="space-y-4">
-            <div>
-              <Label htmlFor="email">이메일</Label>
-              <Input
-                id="email"
-                type="email"
-                value={newMemberEmail}
-                onChange={(e) => setNewMemberEmail(e.target.value)}
-                placeholder="user@example.com"
-              />
-            </div>
-            
-            <div>
-              <Label htmlFor="role">역할</Label>
-              <Select value={newMemberRole} onValueChange={setNewMemberRole}>
-                <SelectTrigger>
-                  <SelectValue />
-                </SelectTrigger>
-                <SelectContent>
-                  <SelectItem value="viewer">Viewer - 읽기 전용</SelectItem>
-                  <SelectItem value="editor">Editor - 파일 편집 가능</SelectItem>
-                  <SelectItem value="admin">Admin - 프로젝트 관리</SelectItem>
-                </SelectContent>
-              </Select>
-            </div>
-          </div>
-          
+
+          <Tabs defaultValue="internal" className="w-full">
+            <TabsList className="grid w-full grid-cols-2">
+              <TabsTrigger value="internal">Internal Users</TabsTrigger>
+              <TabsTrigger value="external" className="flex items-center gap-2">
+                External Users
+                <Badge variant="outline" className="ml-1 text-xs">Viewer Only</Badge>
+              </TabsTrigger>
+            </TabsList>
+
+            <TabsContent value="internal" className="space-y-4 mt-4">
+              <div className="space-y-2">
+                <Label htmlFor="internal-user">Select User</Label>
+                
+                {loadingUsers ? (
+                  <div className="flex items-center justify-center py-4">
+                    <Loader2 className="h-4 w-4 animate-spin" />
+                    <span className="ml-2 text-sm text-muted-foreground">Loading user list...</span>
+                  </div>
+                ) : (
+                  <>
+                    <Popover open={userPopoverOpen} onOpenChange={setUserPopoverOpen}>
+                      <PopoverTrigger asChild>
+                        <Button
+                          variant="outline"
+                          role="combobox"
+                          aria-expanded={userPopoverOpen}
+                          className="w-full justify-between"
+                        >
+                          <span className="truncate">
+                            {selectedUser && selectedUser.domain !== 'partners' ? (
+                              <div className="text-left">
+                                <div className="font-medium">{selectedUser.name}</div>
+                                <div className="text-xs text-muted-foreground">{selectedUser.email}</div>
+                              </div>
+                            ) : (
+                              "Select internal user..."
+                            )}
+                          </span>
+                          <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                        </Button>
+                      </PopoverTrigger>
+                      <PopoverContent className="w-[460px] p-0">
+                        <Command>
+                          <CommandInput
+                            placeholder="Search by name or email..."
+                            value={userSearchTerm}
+                            onValueChange={setUserSearchTerm}
+                          />
+                          <CommandList className="max-h-[300px]">
+                            <CommandEmpty>No user found.</CommandEmpty>
+                            <CommandGroup heading="Internal User List">
+                              {filteredUsers
+                                .filter(u => u.domain !== 'partners')
+                                .map((user) => (
+                                  <CommandItem
+                                    key={user.id}
+                                    onSelect={() => {
+                                      setSelectedUser(user);
+                                      setUserPopoverOpen(false);
+                                      setIsExternalUser(false);
+                                      setNewMemberRole('viewer');
+                                    }}
+                                    value={`${user.name} ${user.email}`}
+                                    className="truncate"
+                                  >
+                                    <Users className="mr-2 h-4 w-4 text-blue-500 flex-shrink-0" />
+                                    <div className="flex-1 truncate">
+                                      <div className="font-medium truncate">{user.name}</div>
+                                      <div className="text-xs text-muted-foreground truncate">{user.email}</div>
+                                    </div>
+                                    <Check
+                                      className={cn(
+                                        "ml-2 h-4 w-4 flex-shrink-0",
+                                        selectedUser?.id === user.id && !isExternalUser ? "opacity-100" : "opacity-0"
+                                      )}
+                                    />
+                                  </CommandItem>
+                                ))}
+                            </CommandGroup>
+                          </CommandList>
+                        </Command>
+                      </PopoverContent>
+                    </Popover>
+
+                    <p className="text-xs text-muted-foreground">
+                      Internal users can be assigned any role.
+                    </p>
+                  </>
+                )}
+              </div>
+
+              <div className="space-y-2">
+                <Label htmlFor="internal-role">Role</Label>
+                <Select 
+                  value={newMemberRole} 
+                  onValueChange={setNewMemberRole}
+                  disabled={!selectedUser || isExternalUser}
+                >
+                  <SelectTrigger id="internal-role">
+                    <SelectValue />
+                  </SelectTrigger>
+                  <SelectContent>
+                    <SelectItem value="viewer">Viewer - Read only</SelectItem>
+                    <SelectItem value="editor">Editor - Can edit files</SelectItem>
+                    <SelectItem value="admin">Admin - Project management</SelectItem>
+                  </SelectContent>
+                </Select>
+              </div>
+            </TabsContent>
+
+            <TabsContent value="external" className="space-y-4 mt-4">
+              <div className="rounded-lg bg-amber-50 border border-amber-200 p-3 mb-4">
+                <p className="text-sm text-amber-800">
+                  <strong>Security Policy Notice</strong><br/>
+                  External users (partners) can only be granted Viewer permissions due to security policy.
+                </p>
+              </div>
+
+              <div className="space-y-2">
+                <Label htmlFor="external-user">Select Partner</Label>
+                
+                {loadingUsers ? (
+                  <div className="flex items-center justify-center py-4">
+                    <Loader2 className="h-4 w-4 animate-spin" />
+                    <span className="ml-2 text-sm text-muted-foreground">Loading user list...</span>
+                  </div>
+                ) : (
+                  <Popover open={userPopoverOpen} onOpenChange={setUserPopoverOpen}>
+                    <PopoverTrigger asChild>
+                      <Button
+                        variant="outline"
+                        role="combobox"
+                        aria-expanded={userPopoverOpen}
+                        className="w-full justify-between"
+                      >
+                        <span className="truncate">
+                          {selectedUser && selectedUser.domain === 'partners' ? (
+                            <span className="flex items-center gap-2">
+                              {selectedUser.name}
+                              <Badge variant="outline" className="ml-1 text-xs">External</Badge>
+                            </span>
+                          ) : (
+                            "Select external user..."
+                          )}
+                        </span>
+                        <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                      </Button>
+                    </PopoverTrigger>
+                    <PopoverContent className="w-[460px] p-0">
+                      <Command>
+                        <CommandInput
+                          placeholder="Search by name..."
+                          value={userSearchTerm}
+                          onValueChange={setUserSearchTerm}
+                        />
+                        <CommandList className="max-h-[300px]">
+                          <CommandEmpty>No external users found.</CommandEmpty>
+                          <CommandGroup heading="Partner List">
+                            {filteredUsers
+                              .filter(u => u.domain === 'partners')
+                              .map((user) => (
+                                <CommandItem
+                                  key={user.id}
+                                  onSelect={() => {
+                                    setSelectedUser(user);
+                                    setUserPopoverOpen(false);
+                                    setIsExternalUser(true);
+                                    setNewMemberRole('viewer');
+                                  }}
+                                  value={user.name}
+                                  className="truncate"
+                                >
+                                  <Users className="mr-2 h-4 w-4 text-amber-600" />
+                                  <span className="truncate flex-1">{user.name}</span>
+                                  <Badge variant="outline" className="text-xs mx-2">External</Badge>
+                                  <Check
+                                    className={cn(
+                                      "ml-auto h-4 w-4 flex-shrink-0",
+                                      selectedUser?.id === user.id && isExternalUser ? "opacity-100" : "opacity-0"
+                                    )}
+                                  />
+                                </CommandItem>
+                              ))}
+                          </CommandGroup>
+                        </CommandList>
+                      </Command>
+                    </PopoverContent>
+                  </Popover>
+                )}
+              </div>
+
+              <div className="space-y-2">
+                <Label htmlFor="external-role">Role</Label>
+                <Select value="viewer" disabled>
+                  <SelectTrigger id="external-role" className="opacity-60">
+                    <SelectValue />
+                  </SelectTrigger>
+                  <SelectContent>
+                    <SelectItem value="viewer">Viewer - Read Only (Fixed)</SelectItem>
+                  </SelectContent>
+                </Select>
+              </div>
+            </TabsContent>
+          </Tabs>
+
           <DialogFooter>
-            <Button variant="outline" onClick={() => setAddMemberOpen(false)}>
-              취소
+            <Button 
+              variant="outline" 
+              onClick={() => {
+                setAddMemberOpen(false);
+                setSelectedUser(null);
+                setUserSearchTerm('');
+                setNewMemberRole('viewer');
+                setIsExternalUser(false);
+              }}
+            >
+              Cancel
+            </Button>
+            <Button 
+              onClick={handleAddMember} 
+              disabled={!selectedUser}
+            >
+              Add
             </Button>
-            <Button onClick={handleAddMember}>추가</Button>
           </DialogFooter>
         </DialogContent>
       </Dialog>
 
-      {/* 소유권 이전 다이얼로그 */}
+      {/* Transfer Ownership Dialog */}
       <Dialog open={transferOwnershipOpen} onOpenChange={setTransferOwnershipOpen}>
         <DialogContent>
           <DialogHeader>
-            <DialogTitle>소유권 이전</DialogTitle>
+            <DialogTitle>Transfer Ownership</DialogTitle>
             <DialogDescription className="text-red-600">
-              주의: 이 작업은 되돌릴 수 없습니다. 프로젝트의 모든 권한이 새 소유자에게 이전됩니다.
+              Warning: This action is irreversible. All permissions will be transferred to the new owner.
             </DialogDescription>
           </DialogHeader>
           
           <div>
-            <Label htmlFor="new-owner">새 소유자 선택</Label>
+            <Label htmlFor="new-owner">Select New Owner</Label>
             <Select value={newOwnerId} onValueChange={setNewOwnerId}>
               <SelectTrigger>
-                <SelectValue placeholder="멤버 선택" />
+                <SelectValue placeholder="Choose member" />
               </SelectTrigger>
               <SelectContent>
                 {members
@@ -463,10 +736,10 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) {
           
           <DialogFooter>
             <Button variant="outline" onClick={() => setTransferOwnershipOpen(false)}>
-              취소
+              Cancel
             </Button>
             <Button variant="destructive" onClick={handleTransferOwnership}>
-              소유권 이전
+              Transfer
             </Button>
           </DialogFooter>
         </DialogContent>
-- 
cgit v1.2.3

