From 672eca530b902d6d108a26c849c65e98c224be75 Mon Sep 17 00:00:00 2001
From: Rykkel <220993G@mymail.nyp.edu.sg>
Date: Mon, 12 Aug 2024 00:32:10 +0800
Subject: [PATCH] Tag management function
---
client/src/App.tsx | 3 +
.../AdministratorNavigationPanel.tsx | 2 +-
client/src/pages/CommunityPostManagement.tsx | 2 +-
client/src/pages/TagManagement.tsx | 157 ++++++++++++++++++
server/routes/post.js | 37 ++++-
5 files changed, 198 insertions(+), 3 deletions(-)
create mode 100644 client/src/pages/TagManagement.tsx
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 35d4de9..6f1fa97 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -35,6 +35,8 @@ import CreateVoucherPage from "./pages/CreateVoucherPage";
import EditVoucherPage from "./pages/EditVoucherPage";
import FeedbackPage from "./pages/FeedbackPage";
import ManageFeedbacksPage from "./pages/ManageFeedbacksPage";
+import TagManagement from "./pages/TagManagement";
+
function App() {
return (
@@ -122,6 +124,7 @@ function App() {
} />
+ } />
diff --git a/client/src/components/AdministratorNavigationPanel.tsx b/client/src/components/AdministratorNavigationPanel.tsx
index 140e166..2c5b724 100644
--- a/client/src/components/AdministratorNavigationPanel.tsx
+++ b/client/src/components/AdministratorNavigationPanel.tsx
@@ -157,7 +157,7 @@ export default function AdministratorNavigationPanel() {
}
- onClickRef="#"
+ onClickRef="community-posts/manage-tag"
/>
diff --git a/client/src/pages/CommunityPostManagement.tsx b/client/src/pages/CommunityPostManagement.tsx
index a960cd9..df0c7b1 100644
--- a/client/src/pages/CommunityPostManagement.tsx
+++ b/client/src/pages/CommunityPostManagement.tsx
@@ -181,7 +181,7 @@ export default function CommunityPostManagement() {
onClick={() =>
handleCopyID(item.postId, item.title)
}
- aria-label="Copy postId, title"
+ aria-label="Copy postId"
>
diff --git a/client/src/pages/TagManagement.tsx b/client/src/pages/TagManagement.tsx
new file mode 100644
index 0000000..f961baf
--- /dev/null
+++ b/client/src/pages/TagManagement.tsx
@@ -0,0 +1,157 @@
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableColumn,
+ TableHeader,
+ TableRow,
+ Button,
+ Tooltip,
+ Modal,
+ ModalContent,
+ ModalHeader,
+ ModalBody,
+ ModalFooter,
+} from "@nextui-org/react";
+import { useEffect, useState } from "react";
+import instance from "../security/http";
+import config from "../config";
+import { popErrorToast, popToast } from "../utilities";
+import { ClipboardDocumentIcon, TrashDeleteIcon } from "../icons";
+
+export default function TagManagement() {
+ const [tagList, setTagList] = useState
([]);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [tagToDelete, setTagToDelete] = useState(null);
+
+ const columns = [
+ { key: "tag", label: "TAG" },
+ { key: "actions", label: "ACTIONS" },
+ ];
+
+ const populateTagList = () => {
+ instance
+ .get(`${config.serverAddress}/post/tags/all`)
+ .then((response) => {
+ setTagList(response.data);
+ console.log(response.data);
+ })
+ .catch((error) => {
+ popErrorToast(error);
+ });
+ };
+ useEffect(() => {
+ populateTagList();
+ }, []);
+
+ const handleCopyID = (id: string, tag: string) => {
+ navigator.clipboard.writeText(id);
+ popToast(tag + "'s Tag ID has been copied!", 1);
+ };
+
+ const handleDeleteClick = (item: any) => {
+ setTagToDelete(item);
+ setIsModalOpen(true);
+ };
+
+ const handleDeleteConfirm = async () => {
+ if (tagToDelete) {
+ try {
+ await instance.delete(
+ `${config.serverAddress}/post/tags/${tagToDelete.id}`
+ );
+ populateTagList();
+ setIsModalOpen(false);
+ } catch (error) {
+ console.error("Error deleting post:", error);
+ }
+ }
+ };
+
+ return (
+
+ {!tagList && (
There are currently no tags!
)}
+ {tagList && (
+
+
Tag Management
+
+
+ {(column) => (
+
+ {column.label}
+
+ )}
+
+
+ {(tagEntry: any) => (
+
+ {(columnKey) => (
+
+ {columnKey === "actions" ? (
+
+
+
+
+
+
+
+
+ ) : (
+ {tagEntry.tag}
+ )}
+
+ )}
+
+ )}
+
+
+
+
setIsModalOpen(false)}
+ isDismissable={false}
+ isKeyboardDismissDisabled={true}
+ >
+
+ <>
+
+ {tagToDelete?.tag
+ ? `DELETING TAG: ${tagToDelete.tag}`
+ : "Delete tag"}
+
+
+ Are you sure you want to delete this tag?
+
+
+
+
+
+ >
+
+
+
+ )}
+
+ )
+}
diff --git a/server/routes/post.js b/server/routes/post.js
index 645dd6c..3f2f6bb 100644
--- a/server/routes/post.js
+++ b/server/routes/post.js
@@ -258,7 +258,7 @@ router.delete("/:id", async (req, res) => {
where: { id: id },
});
if (num == 1) {
- // destry() returns no. of rows affected, that's why if num == 1
+ // destroy() returns no. of rows affected, that's why if num == 1
res.json({
message: "Post was deleted successfully.",
});
@@ -317,4 +317,39 @@ router.get("/:id/getComments", async (req, res) => {
res.json(comments);
});
+router.get("/tags/all", async (req, res) => {
+ // Check id not found
+ let tags = await Tag.findAll();
+ if (!tags) {
+ res.sendStatus(404);
+ return;
+ }
+ res.json(tags);
+})
+
+router.delete("/tags/:id", async (req, res) => {
+ let id = req.params.id;
+ // Check id not found
+ let tag = await Tag.findByPk(id);
+ if (!tag) {
+ res.sendStatus(404);
+ return;
+ }
+ let num = await Tag.destroy({
+ // destroy() deletes data based on the where condition, and returns the number of rows affected
+ where: { id: id },
+ });
+
+ if (num == 1) {
+ // destroy() returns no. of rows affected, that's why if num == 1
+ res.json({
+ message: "Tag was deleted successfully.",
+ });
+ } else {
+ res.status(400).json({
+ message: `Cannot delete tag with id ${id}.`,
+ });
+ }
+})
+
module.exports = router;