From 7f943509523061ed39877e520931d10530cda43f Mon Sep 17 00:00:00 2001 From: Wind-Explorer <66894537+Wind-Explorer@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:19:08 +0800 Subject: [PATCH] Feedbacks management go brr --- client/src/App.tsx | 2 + .../AdministratorNavigationPanel.tsx | 24 +- client/src/icons.tsx | 80 ++++-- client/src/pages/FeedbackPage.tsx | 2 +- client/src/pages/ManageFeedbacksPage.tsx | 246 ++++++++++++++++++ server/models/Feedback.js | 2 +- server/routes/feedback.js | 21 +- 7 files changed, 343 insertions(+), 34 deletions(-) create mode 100644 client/src/pages/ManageFeedbacksPage.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 03e0e21..35d4de9 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -34,6 +34,7 @@ import ManageVoucherPage from "./pages/ManageVoucherPage"; import CreateVoucherPage from "./pages/CreateVoucherPage"; import EditVoucherPage from "./pages/EditVoucherPage"; import FeedbackPage from "./pages/FeedbackPage"; +import ManageFeedbacksPage from "./pages/ManageFeedbacksPage"; function App() { return ( @@ -91,6 +92,7 @@ function App() { }> } /> } /> + } /> } /> diff --git a/client/src/components/AdministratorNavigationPanel.tsx b/client/src/components/AdministratorNavigationPanel.tsx index 3ed5a48..140e166 100644 --- a/client/src/components/AdministratorNavigationPanel.tsx +++ b/client/src/components/AdministratorNavigationPanel.tsx @@ -63,8 +63,9 @@ export default function AdministratorNavigationPanel() { return (
@@ -196,7 +200,7 @@ export default function AdministratorNavigationPanel() { } - onClickRef="#" + onClickRef="manage-feedbacks" />
diff --git a/client/src/icons.tsx b/client/src/icons.tsx index 08aa11c..3397ad6 100644 --- a/client/src/icons.tsx +++ b/client/src/icons.tsx @@ -542,17 +542,19 @@ export const ArrowTopRightOnSquare = () => { export const TrashDeleteIcon = () => { return ( - - - + + ); }; @@ -563,13 +565,13 @@ export const EmailIcon = () => { xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" className="size-6" > @@ -582,13 +584,13 @@ export const InfoIcon = () => { xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" className="size-6" > @@ -601,13 +603,13 @@ export const TrophyIcon = () => { xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" className="size-6" > @@ -651,3 +653,41 @@ export const ChevronDoubleDownIcon = () => { ); }; + +export const CheckmarkIcon = () => { + return ( + + + + ); +}; + +export const BookOpenIcon = () => { + return ( + + + + ); +}; diff --git a/client/src/pages/FeedbackPage.tsx b/client/src/pages/FeedbackPage.tsx index 7f15ddb..472adc5 100644 --- a/client/src/pages/FeedbackPage.tsx +++ b/client/src/pages/FeedbackPage.tsx @@ -30,7 +30,7 @@ export default function FeedbackPage() { comment: Yup.string() .trim() .min(1) - .max(1024) + .max(2048) .required("Enter your comments."), allowContact: Yup.boolean().oneOf([true, false], "please decide"), }); diff --git a/client/src/pages/ManageFeedbacksPage.tsx b/client/src/pages/ManageFeedbacksPage.tsx new file mode 100644 index 0000000..71109b6 --- /dev/null +++ b/client/src/pages/ManageFeedbacksPage.tsx @@ -0,0 +1,246 @@ +import { useEffect, useState } from "react"; +import instance from "../security/http"; +import config from "../config"; +import { popErrorToast } from "../utilities"; +import { + Button, + Chip, + getKeyValue, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + Table, + TableBody, + TableCell, + TableColumn, + TableHeader, + TableRow, + Textarea, +} from "@nextui-org/react"; +import { BookOpenIcon, CheckmarkIcon, EmailIcon } from "../icons"; +import { retrieveUserInformationById } from "../security/usersbyid"; + +export default function ManageFeedbacksPage() { + const [feedbacksList, setFeedbacksList] = useState([]); + const [viewFeedbackModalOpened, setViewFeedbackModalOpened] = useState(false); + const [viewingFeedback, setViewingFeedback] = useState(); + const columns = [ + { + key: "feedbackCategory", + label: "CATEGORY", + }, + { + key: "subject", + label: "SUBJECT", + }, + { + key: "comment", + label: "COMMENT", + }, + { + key: "createdAt", + label: "SUBMITTED", + }, + { + key: "actions", + label: "ACTIONS", + }, + ]; + + const populateFeedbacksList = () => { + instance + .get(`${config.serverAddress}/feedback/all`) + .then((response) => { + setFeedbacksList(response.data); + console.log(feedbacksList); + }) + .catch((error) => { + popErrorToast(error); + }); + }; + + useEffect(() => { + populateFeedbacksList(); + }, []); + + const viewFeedback = (feedbackId: string) => { + instance + .get(`${config.serverAddress}/feedback/${feedbackId}`) + .then((feedbackObject) => { + setViewingFeedback(feedbackObject.data); + setViewFeedbackModalOpened(true); + }); + }; + + return ( +
+

Manage Feedbacks

+ + + {(column) => ( + {column.label} + )} + + + {(feedbackEntry: any) => ( + + {(columnKey) => ( + + {(() => { + switch (columnKey) { + case "feedbackCategory": + let result = ""; + switch (getKeyValue(feedbackEntry, columnKey)) { + case 0: + result = "Feature request"; + break; + case 1: + result = "Bug report"; + break; + case 2: + result = "Get in touch"; + break; + default: + result = "Unknown"; + break; + } + return {result}; + case "subject": + return ( +

+ {getKeyValue(feedbackEntry, columnKey)} +

+ ); + case "comment": + return ( +
+

+ {getKeyValue(feedbackEntry, columnKey)} +

+
+ ); + case "createdAt": + let creationDate = Date.parse( + getKeyValue(feedbackEntry, columnKey) + ); + let timing = Math.floor( + (Date.now() - creationDate) / (1000 * 60 * 60 * 24) + ); + return ( +

+ {timing <= 0 + ? "Today" + : `${timing} day${timing == 1 ? "" : "s"} ago`} +

+ ); + case "actions": + return ( +
+
+ } + onPress={() => { + viewFeedback(getKeyValue(feedbackEntry, "id")); + }} + > + View + + + + ); + default: + return

{getKeyValue(feedbackEntry, columnKey)}

; + } + })()} +
+ )} +
+ )} +
+
+ + + {(onClose) => { + return ( + viewingFeedback && ( + <> + +
+

"{viewingFeedback.subject}"

+

+ Submitted on{" "} + {new Date(viewingFeedback.createdAt).toLocaleString()} +

+
+
+ +
+