delete project
This commit is contained in:
@@ -26,8 +26,10 @@ app.use("/", indexRoute);
|
||||
// "/projects"
|
||||
const projectsIndexRoute = require('./routes/projects/index')(sequelize);
|
||||
const projectsNewRoute = require('./routes/projects/new')(sequelize);
|
||||
const projectsDeleteRoute = require('./routes/projects/delete')(sequelize);
|
||||
app.use('/projects', projectsIndexRoute);
|
||||
app.use('/projects', projectsNewRoute);
|
||||
app.use('/projects', projectsDeleteRoute);
|
||||
|
||||
// "/folders"
|
||||
const foldersIndexRoute = require('./routes/folders/index')(sequelize);
|
||||
|
||||
29
backend/routes/projects/delete.js
Normal file
29
backend/routes/projects/delete.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const defineProject = require("../../models/projects");
|
||||
const { DataTypes } = require("sequelize");
|
||||
|
||||
module.exports = function (sequelize) {
|
||||
const Project = defineProject(sequelize, DataTypes);
|
||||
|
||||
router.delete("/:projectId", async (req, res) => {
|
||||
const projectId = req.params.projectId;
|
||||
try {
|
||||
const project = await Project.findOne({
|
||||
where: {
|
||||
id: projectId,
|
||||
},
|
||||
});
|
||||
if (!project) {
|
||||
return res.status(404).send("Project not found");
|
||||
}
|
||||
await project.destroy();
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send("Internal Server Error");
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
@@ -79,6 +79,27 @@ async function createProject(name, detail) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteProject(projectId: number) {
|
||||
const fetchOptions = {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
const url = `${apiServer}/projects/${projectId}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, fetchOptions);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting project:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export default function ProjectsPage() {
|
||||
// projects
|
||||
const [projects, setProjects] = useState([]);
|
||||
@@ -144,6 +165,15 @@ export default function ProjectsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const onDeleteClicked = async (projectId: number) => {
|
||||
try {
|
||||
await deleteProject(projectId);
|
||||
setProjects(projects.filter((project) => project.id !== projectId));
|
||||
} catch (error) {
|
||||
console.error("Error deleting project:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto max-w-7xl pt-16 px-6 flex-grow">
|
||||
<div className="flex h-full items-center">
|
||||
@@ -157,15 +187,20 @@ export default function ProjectsPage() {
|
||||
{projects.map((project, index) => (
|
||||
<ProjectCard
|
||||
key={index}
|
||||
projectName={project.name}
|
||||
projectDetail={project.detail}
|
||||
project={project}
|
||||
onDeleteClicked={onDeleteClicked}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Modal isOpen={isCreateDialogOpen}>
|
||||
<Modal
|
||||
isOpen={isCreateDialogOpen}
|
||||
onOpenChange={() => {
|
||||
setIsCreateDialogOpen(false);
|
||||
}}
|
||||
>
|
||||
<ModalContent>
|
||||
<ModalHeader className="flex flex-col gap-1">Modal Title</ModalHeader>
|
||||
<ModalHeader className="flex flex-col gap-1">Project</ModalHeader>
|
||||
<ModalBody>
|
||||
<Input
|
||||
type="text"
|
||||
@@ -194,7 +229,7 @@ export default function ProjectsPage() {
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onPress={closeModal}>
|
||||
<Button variant="light" onPress={closeModal}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onCreateClicked}>
|
||||
|
||||
@@ -1,34 +1,55 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Link,
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownTrigger,
|
||||
DropdownMenu,
|
||||
DropdownItem,
|
||||
Card,
|
||||
CardHeader,
|
||||
CardBody,
|
||||
Divider,
|
||||
Image,
|
||||
} from "@nextui-org/react";
|
||||
import NextLink from "next/link";
|
||||
import { DotsIcon } from "@/components/icons";
|
||||
|
||||
export function ProjectCard({ projectName, projectDetail }) {
|
||||
export function ProjectCard({ project, onDeleteClicked }) {
|
||||
return (
|
||||
<NextLink href={`/projects/${1}/home`}>
|
||||
<Card className="w-[250px] bg-white hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-800">
|
||||
<CardHeader className="flex gap-3">
|
||||
<Image
|
||||
alt="nextui logo"
|
||||
height={40}
|
||||
radius="sm"
|
||||
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
|
||||
width={40}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-md">{projectName}</p>
|
||||
<Card className="w-[250px]">
|
||||
<CardHeader className="flex gap-3 h-[50px] justify-between text-ellipsis overflow-hidden">
|
||||
<div className="flex gap-5">
|
||||
<div className="flex flex-col gap-1 items-start justify-center">
|
||||
<Link href={`/projects/${project.id}/home`}>{project.name}</Link>
|
||||
</div>
|
||||
</div>
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button
|
||||
isIconOnly
|
||||
variant="light"
|
||||
size="sm"
|
||||
className="text-transparent hover:text-inherit"
|
||||
>
|
||||
<DotsIcon size={16} />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Static Actions">
|
||||
<DropdownItem key="edit">Edit project</DropdownItem>
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
onClick={() => onDeleteClicked(project.id)}
|
||||
>
|
||||
Delete project
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</CardHeader>
|
||||
<Divider />
|
||||
<CardBody>
|
||||
<p>{projectDetail}</p>
|
||||
<CardBody className="h-[50px] text-ellipsis overflow-hidden">
|
||||
<p>{project.detail}</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</NextLink>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -284,3 +284,22 @@ export const FolderIcon: React.FC<IconSvgProps> = ({
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const DotsIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
height={size || height}
|
||||
width={size || height}
|
||||
{...props}
|
||||
>
|
||||
<path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 12c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user