summaryrefslogtreecommitdiff
path: root/components/project
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-13 08:56:27 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-13 08:56:27 +0000
commitb9a2081a76e669688d5884f20482b37cc8acca22 (patch)
tree385e78c05d193a54daaced836f1e1152696153a8 /components/project
parente84cf02a1cb4959a9d3bb5bbf37885c13a447f78 (diff)
(최겸, 임수민) 구매 입찰, 견적(그룹코드, tbe에러) 수정, data-room 수정
Diffstat (limited to 'components/project')
-rw-r--r--components/project/ProjectDashboard.tsx103
-rw-r--r--components/project/ProjectList.tsx37
-rw-r--r--components/project/ProjectNav.tsx2
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',