From 197a011c4c41ce6926d73b95d93482e918d523ad Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:20:37 +0900 Subject: [PATCH] create folders table --- backend/index.js | 16 +++-- .../20240204090345-create-projects.js | 2 +- .../20240212022145-create-folders.js | 48 ++++++++++++++ backend/models/folders.js | 24 +++++++ backend/models/projects.js | 2 +- backend/routes/folders/index.js | 30 +++++++++ backend/routes/folders/new.js | 32 ++++++++++ backend/scripts/drop.sh | 2 +- backend/seeders/seed.js | 30 +++++++-- frontend/app/projects/[id]/page.tsx | 64 +++++++++++++++++++ frontend/app/projects/layout.tsx | 2 +- frontend/app/projects/page.tsx | 2 +- frontend/app/projects/project-card.tsx | 39 +++++------ 13 files changed, 261 insertions(+), 32 deletions(-) create mode 100644 backend/migrations/20240212022145-create-folders.js create mode 100644 backend/models/folders.js create mode 100644 backend/routes/folders/index.js create mode 100644 backend/routes/folders/new.js create mode 100644 frontend/app/projects/[id]/page.tsx diff --git a/backend/index.js b/backend/index.js index f4d2392..5bf8d6d 100644 --- a/backend/index.js +++ b/backend/index.js @@ -6,7 +6,7 @@ const app = express(); const cors = require("cors"); const corsOptions = { origin: "http://localhost:3000", - methods: "GET,HEAD,PUT,PATCH,POST,DELETE" + methods: "GET,HEAD,PUT,PATCH,POST,DELETE", }; app.use(cors(corsOptions)); @@ -15,13 +15,13 @@ app.use(express.json()); // init sequalize const sequelize = new Sequelize({ - dialect: 'sqlite', - storage: 'database.sqlite', + dialect: "sqlite", + storage: "database.sqlite", }); // "/" -const indexRoute = require('./routes/index'); -app.use('/', indexRoute); +const indexRoute = require("./routes/index"); +app.use("/", indexRoute); // "/projects" const projectsIndexRoute = require('./routes/projects/index')(sequelize); @@ -29,6 +29,12 @@ const projectsNewRoute = require('./routes/projects/new')(sequelize); app.use('/projects', projectsIndexRoute); app.use('/projects', projectsNewRoute); +// "/folders" +const foldersIndexRoute = require('./routes/folders/index')(sequelize); +const foldersNewRoute = require('./routes/folders/new')(sequelize); +app.use('/folders', foldersIndexRoute); +app.use('/folders', foldersNewRoute); + const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); diff --git a/backend/migrations/20240204090345-create-projects.js b/backend/migrations/20240204090345-create-projects.js index a52e7aa..bfc7e30 100644 --- a/backend/migrations/20240204090345-create-projects.js +++ b/backend/migrations/20240204090345-create-projects.js @@ -14,7 +14,7 @@ module.exports = { }, detail: { type: Sequelize.STRING, - allowNull: false, + allowNull: true, }, createdAt: { type: Sequelize.DATE, diff --git a/backend/migrations/20240212022145-create-folders.js b/backend/migrations/20240212022145-create-folders.js new file mode 100644 index 0000000..9a172b0 --- /dev/null +++ b/backend/migrations/20240212022145-create-folders.js @@ -0,0 +1,48 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('folders', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + name: { + type: Sequelize.STRING, + allowNull: false, + }, + detail: { + type: Sequelize.STRING, + allowNull: true, + }, + parentFolderId: { + type: Sequelize.INTEGER, + allowNull: true, + }, + projectId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'Projects', + key: 'id', + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }, + }, + createdAt: { + type: Sequelize.DATE, + allowNull: false, + }, + updatedAt: { + type: Sequelize.DATE, + allowNull: false, + }, + }); + }, + + async down (queryInterface, Sequelize) { + await queryInterface.dropTable('folders'); + } +}; diff --git a/backend/models/folders.js b/backend/models/folders.js new file mode 100644 index 0000000..ceb2f0c --- /dev/null +++ b/backend/models/folders.js @@ -0,0 +1,24 @@ +function defineFolder(sequelize, DataTypes) { + const Folder = sequelize.define("Folder", { + name: { + type: DataTypes.STRING, + allowNull: false, + }, + detail: { + type: DataTypes.STRING, + allowNull: true, + }, + parentFolderId: { + type: DataTypes.INTEGER, + allowNull: true, + }, + projectId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }); + + return Folder; +} + +module.exports = defineFolder; diff --git a/backend/models/projects.js b/backend/models/projects.js index 78259ce..c9dc6e4 100644 --- a/backend/models/projects.js +++ b/backend/models/projects.js @@ -6,7 +6,7 @@ function defineProject(sequelize, DataTypes) { }, detail: { type: DataTypes.STRING, - allowNull: false, + allowNull: true, }, }); diff --git a/backend/routes/folders/index.js b/backend/routes/folders/index.js new file mode 100644 index 0000000..ad13d3d --- /dev/null +++ b/backend/routes/folders/index.js @@ -0,0 +1,30 @@ +const express = require("express"); +const router = express.Router(); +const defineFolder = require('../../models/folders'); +const { DataTypes } = require('sequelize'); + +module.exports = function(sequelize) { + const Folder = defineFolder(sequelize, DataTypes) + + router.get("/", async (req, res) => { + const { projectId } = req.query; + + if (!projectId) { + return res.status(400).json({ error: 'projectId is required' }); + } + + try { + const folders = await Folder.findAll({ + where: { + projectId: projectId + } + }); + res.json(folders); + } catch (error) { + console.error(error); + res.status(500).send("Internal Server Error"); + } + }); + + return router; +}; \ No newline at end of file diff --git a/backend/routes/folders/new.js b/backend/routes/folders/new.js new file mode 100644 index 0000000..514e5ca --- /dev/null +++ b/backend/routes/folders/new.js @@ -0,0 +1,32 @@ +const express = require("express"); +const router = express.Router(); +const defineFolder = require("../../models/folders"); +const { DataTypes } = require("sequelize"); + +module.exports = function (sequelize) { + const Folder = defineFolder(sequelize, DataTypes); + + router.post("/", async (req, res) => { + try { + const { name, detail, projectId, parentFolderId } = req.body; + if (!name || !projectId) { + return res + .status(400) + .json({ error: "Name and projectId are required" }); + } + + const newFolder = await Folder.create({ + name, + detail, + projectId, + parentFolderId, + }); + + res.json(newFolder); + } catch (error) { + res.status(500).json({ error: "Internal server error" }); + } + }); + + return router; +}; diff --git a/backend/scripts/drop.sh b/backend/scripts/drop.sh index a1ca0eb..212267c 100644 --- a/backend/scripts/drop.sh +++ b/backend/scripts/drop.sh @@ -1,4 +1,4 @@ #!/bin/bash npx sequelize db:migrate:undo:all -echo "Dropped 'Project' table." +echo "Dropped all tables" diff --git a/backend/seeders/seed.js b/backend/seeders/seed.js index 66ac9bb..427bc5e 100644 --- a/backend/seeders/seed.js +++ b/backend/seeders/seed.js @@ -2,7 +2,8 @@ module.exports = { up: async (queryInterface, Sequelize) => { - return queryInterface.bulkInsert('Projects', [ + // Add projects table records + await queryInterface.bulkInsert('Projects', [ { name: 'Project 1', detail: 'Details of Project 1', @@ -11,13 +12,34 @@ module.exports = { }, { name: 'Project 2', - detail: 'Details of Project 2', createdAt: new Date(), updatedAt: new Date(), }, { name: 'Project 3', - detail: 'Details of Project 3', + createdAt: new Date(), + updatedAt: new Date(), + }, + ]); + + // Add folders table records + await queryInterface.bulkInsert('folders', [ + { + name: 'Folder 1', + detail: 'Details of Folder 1', + projectId: 1, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: 'Folder 2', + projectId: 1, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: 'Folder 3', + projectId: 1, createdAt: new Date(), updatedAt: new Date(), }, @@ -25,6 +47,6 @@ module.exports = { }, down: async (queryInterface, Sequelize) => { - // do nothing + // do nothingg }, }; diff --git a/frontend/app/projects/[id]/page.tsx b/frontend/app/projects/[id]/page.tsx new file mode 100644 index 0000000..bd07329 --- /dev/null +++ b/frontend/app/projects/[id]/page.tsx @@ -0,0 +1,64 @@ +"use client"; +import { useEffect, useState } from "react"; +import Config from "@/config/config"; +const apiServer = Config.apiServer; + +/** + * fetch folder records + * + * @param {string} url - API endpoint url + * @returns {Promise} - project record array + * @throws {Error} + */ +async function fetchFolders(url) { + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error("Error fetching data:", error.message); + } +} + +export default function Page({ params }: { params: { id: string } }) { + const [folders, setFolders] = useState([]); + const url = `${apiServer}/folders?projectId=${params.id}`; + + useEffect(() => { + async function fetchDataEffect() { + try { + const data = await fetchFolders(url); + setFolders(data); + } catch (error) { + console.error("Error in effect:", error.message); + } + } + + fetchDataEffect(); + }, []); + + return ( +
+
Project: {params.id}
+
+ {folders.map((folder, index) => ( +
+
{folder.name}
+
{folder.detail}
+
{folder.projectId}
+
+ ))} +
+
+ ); +} diff --git a/frontend/app/projects/layout.tsx b/frontend/app/projects/layout.tsx index c09e0c8..d956917 100644 --- a/frontend/app/projects/layout.tsx +++ b/frontend/app/projects/layout.tsx @@ -8,4 +8,4 @@ export default function ProjectsLayout({ {children} ); -} +} \ No newline at end of file diff --git a/frontend/app/projects/page.tsx b/frontend/app/projects/page.tsx index 6163a46..7e10c73 100644 --- a/frontend/app/projects/page.tsx +++ b/frontend/app/projects/page.tsx @@ -149,7 +149,7 @@ export default function ProjectsPage() { projectName.text, projectDetail.text ); - setProjects([...projects, newProject]) + setProjects([...projects, newProject]); closeModal(); } }; diff --git a/frontend/app/projects/project-card.tsx b/frontend/app/projects/project-card.tsx index 47cc9e3..ca784e7 100644 --- a/frontend/app/projects/project-card.tsx +++ b/frontend/app/projects/project-card.tsx @@ -6,26 +6,29 @@ import { Divider, Image, } from "@nextui-org/react"; +import NextLink from "next/link"; export function ProjectCard({ projectName, projectDetail }) { return ( - - - nextui logo -
-

{ projectName }

-
-
- - -

{projectDetail}

-
-
+ + + + nextui logo +
+

{projectName}

+
+
+ + +

{projectDetail}

+
+
+
); }