diff options
Diffstat (limited to 'components/project')
| -rw-r--r-- | components/project/ProjectDashboard.tsx | 103 | ||||
| -rw-r--r-- | components/project/ProjectList.tsx | 37 | ||||
| -rw-r--r-- | components/project/ProjectNav.tsx | 2 |
3 files changed, 128 insertions, 14 deletions
diff --git a/components/project/ProjectDashboard.tsx b/components/project/ProjectDashboard.tsx index 5f8afb75..581b7b95 100644 --- a/components/project/ProjectDashboard.tsx +++ b/components/project/ProjectDashboard.tsx @@ -103,7 +103,9 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) { // Dialog states const [addMemberOpen, setAddMemberOpen] = useState(false); const [transferOwnershipOpen, setTransferOwnershipOpen] = useState(false); + const [deleteProjectOpen, setDeleteProjectOpen] = useState(false); const [newOwnerId, setNewOwnerId] = useState(''); + const [deleteConfirmText, setDeleteConfirmText] = useState(''); // User selection related states const [availableUsers, setAvailableUsers] = useState<User[]>([]); @@ -256,6 +258,42 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) { } }; + // Delete project + const handleDeleteProject = async () => { + if (deleteConfirmText !== 'DELETE') { + toast({ + title: 'Error', + description: 'Please type DELETE to confirm.', + variant: 'destructive', + }); + return; + } + + try { + const response = await fetch(`/api/projects/${projectId}`, { + method: 'DELETE', + }); + + if (!response.ok) { + throw new Error('Failed to delete project'); + } + + toast({ + title: 'Success', + description: 'Project has been deleted.', + }); + + // 프로젝트 목록 페이지로 리다이렉트 + window.location.href = '/evcp/data-room'; + } catch (error) { + toast({ + title: 'Error', + description: 'Failed to delete project.', + variant: 'destructive', + }); + } + }; + const formatBytes = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const k = 1024; @@ -457,7 +495,10 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) { Permanently delete project and all files </p> </div> - <Button variant="destructive"> + <Button + variant="destructive" + onClick={() => setDeleteProjectOpen(true)} + > <Trash2 className="h-4 w-4 mr-2" /> Delete Project </Button> @@ -744,6 +785,66 @@ export function ProjectDashboard({ projectId }: ProjectDashboardProps) { </DialogFooter> </DialogContent> </Dialog> + + {/* Delete Project Dialog */} + <Dialog open={deleteProjectOpen} onOpenChange={(open) => { + setDeleteProjectOpen(open); + if (!open) setDeleteConfirmText(''); + }}> + <DialogContent> + <DialogHeader> + <DialogTitle className="text-red-600">Delete Project</DialogTitle> + <DialogDescription> + This action cannot be undone. This will permanently delete the project and all associated files. + </DialogDescription> + </DialogHeader> + + <div className="space-y-4"> + <div className="rounded-lg bg-red-50 border border-red-200 p-4"> + <h4 className="font-semibold text-red-800 mb-2">Warning</h4> + <ul className="text-sm text-red-700 space-y-1 list-disc list-inside"> + <li>All files will be permanently deleted</li> + <li>All project members will lose access</li> + <li>All sharing links will be invalidated</li> + <li>This action cannot be reversed</li> + </ul> + </div> + + <div className="space-y-2"> + <Label htmlFor="delete-confirm"> + Type <span className="font-mono font-bold">DELETE</span> to confirm + </Label> + <Input + id="delete-confirm" + placeholder="DELETE" + value={deleteConfirmText} + onChange={(e) => setDeleteConfirmText(e.target.value)} + className="font-mono" + /> + </div> + </div> + + <DialogFooter> + <Button + variant="outline" + onClick={() => { + setDeleteProjectOpen(false); + setDeleteConfirmText(''); + }} + > + Cancel + </Button> + <Button + variant="destructive" + onClick={handleDeleteProject} + disabled={deleteConfirmText !== 'DELETE'} + > + <Trash2 className="h-4 w-4 mr-2" /> + Delete Project + </Button> + </DialogFooter> + </DialogContent> + </Dialog> </div> ); }
\ No newline at end of file diff --git a/components/project/ProjectList.tsx b/components/project/ProjectList.tsx index 9dec7e77..e267b21c 100644 --- a/components/project/ProjectList.tsx +++ b/components/project/ProjectList.tsx @@ -98,20 +98,31 @@ export function ProjectList() { fetchProjects(); }, []); - const fetchProjects = async () => { - try { - const response = await fetch('/api/projects'); - const data = await response.json(); - setProjects(data); - } catch (error) { - toast({ - title: 'Error', - description: 'Unable to load project list.', - variant: 'destructive', - }); +// components/project/ProjectList.tsx 의 fetchProjects 함수 수정 + +const fetchProjects = async () => { + try { + const response = await fetch('/api/projects'); + const data = await response.json(); + setProjects(data); + + // 멤버인 프로젝트가 정확히 1개일 때 자동 리다이렉트 + const memberProjects = data.member || []; + const ownedProjects = data.owned || []; + const totalProjects = [...memberProjects, ...ownedProjects]; + + if (totalProjects.length === 1) { + const singleProject = totalProjects[0]; + router.push(`/evcp/data-room/${singleProject.id}/files`); } - }; - + } catch (error) { + toast({ + title: 'Error', + description: 'Unable to load project list.', + variant: 'destructive', + }); + } +}; const onSubmit = async (data: ProjectFormData) => { setIsSubmitting(true); try { diff --git a/components/project/ProjectNav.tsx b/components/project/ProjectNav.tsx index aac934ad..c62f760e 100644 --- a/components/project/ProjectNav.tsx +++ b/components/project/ProjectNav.tsx @@ -59,6 +59,7 @@ export function ProjectNav({ projectId }: ProjectNavProps) { }; console.log(pathname, projectId) + console.log(projectRole, "projectRole") const navItems = [ { @@ -66,6 +67,7 @@ export function ProjectNav({ projectId }: ProjectNavProps) { icon: Home, href: `/evcp/data-room/${projectId}`, active: pathname === `/${lng}/evcp/data-room/${projectId}`, + requireRole: ['owner', 'admin'], }, { label: 'Files', |
