diff --git a/client/src/components/AdministratorNavigationPanel.tsx b/client/src/components/AdministratorNavigationPanel.tsx
index 08c5511..e6dfd87 100644
--- a/client/src/components/AdministratorNavigationPanel.tsx
+++ b/client/src/components/AdministratorNavigationPanel.tsx
@@ -19,6 +19,7 @@ import {
ChatBubbleOvalLeftIcon,
ChevronLeftIcon,
ArrowRightStartOnRectangleIcon,
+ UsersIcon,
} from "../icons";
import EcoconnectFullLogo from "./EcoconnectFullLogo";
import { retrieveUserInformation } from "../security/users";
@@ -192,7 +193,12 @@ export default function AdministratorNavigationPanel() {
Users
}
+ onClickRef="users-management"
+ />
+
}
onClickRef="#"
/>
diff --git a/client/src/icons.tsx b/client/src/icons.tsx
index 47dd10c..f40819b 100644
--- a/client/src/icons.tsx
+++ b/client/src/icons.tsx
@@ -443,4 +443,80 @@ export const TrashIcon = () => {
/>
);
-};
\ No newline at end of file
+};
+
+export const UsersIcon = () => {
+ return (
+
+ );
+};
+
+export const ClipboardDocumentIcon = () => {
+ return (
+
+ );
+};
+
+export const ArchiveBoxIcon = () => {
+ return (
+
+ );
+};
+
+export const LifebuoyIcon = () => {
+ return (
+
+ );
+};
diff --git a/client/src/pages/UsersManagement.tsx b/client/src/pages/UsersManagement.tsx
new file mode 100644
index 0000000..144e44e
--- /dev/null
+++ b/client/src/pages/UsersManagement.tsx
@@ -0,0 +1,185 @@
+import {
+ getKeyValue,
+ Table,
+ TableBody,
+ TableCell,
+ TableColumn,
+ TableHeader,
+ TableRow,
+ Button,
+ Tooltip,
+} from "@nextui-org/react";
+import { useEffect, useState } from "react";
+import instance from "../security/http";
+import config from "../config";
+import { popErrorToast, popToast } from "../utilities";
+import { ArchiveBoxIcon, ClipboardDocumentIcon, LifebuoyIcon } from "../icons";
+
+export default function UsersManagement() {
+ const [userInformationlist, setUserInformationList] = useState
([]);
+ const columns = [
+ {
+ key: "firstName",
+ label: "FISRT NAME",
+ },
+ {
+ key: "lastName",
+ label: "LAST NAME",
+ },
+ {
+ key: "email",
+ label: "EMAIL ADDRESS",
+ },
+ {
+ key: "phoneNumber",
+ label: "TELEPHONE",
+ },
+ {
+ key: "accountType",
+ label: "ACCOUNT TYPE",
+ },
+ {
+ key: "isArchived",
+ label: "STATUS",
+ },
+ {
+ key: "actions",
+ label: "ACTIONS",
+ },
+ ];
+
+ const populateUserInformationList = () => {
+ instance
+ .get(`${config.serverAddress}/users/all`)
+ .then((response) => {
+ setUserInformationList(response.data);
+ console.log(userInformationlist);
+ })
+ .catch((error) => {
+ popErrorToast(error);
+ });
+ };
+
+ useEffect(() => {
+ populateUserInformationList();
+ }, []);
+
+ const handleCopyID = (userId: string, firstName: string) => {
+ navigator.clipboard.writeText(userId);
+ popToast(firstName + "'s User ID has been copied!", 1);
+ };
+
+ const handleArchiveToggle = (userId: string, isArchived: boolean) => {
+ instance
+ .put(
+ `${config.serverAddress}/users/${
+ isArchived ? "unarchive" : "archive"
+ }/${userId}`
+ )
+ .then(() => {
+ window.location.reload();
+ })
+ .catch((error) => {
+ popErrorToast(error);
+ });
+ };
+
+ return (
+
+ {userInformationlist && (
+
+
Users Onboard
+
+
+ {(column) => (
+ {column.label}
+ )}
+
+
+ {(userEntry: any) => (
+
+ {(columnKey) => (
+
+ {columnKey === "accountType" ? (
+ (() => {
+ const accountType = getKeyValue(userEntry, columnKey);
+ switch (accountType) {
+ case 0:
+ return "User";
+ case 1:
+ return "Karang Guni";
+ case 2:
+ return "Admin";
+ default:
+ return "";
+ }
+ })()
+ ) : columnKey === "actions" ? (
+
+
+
+
+
+
+
+
+ ) : columnKey == "isArchived" ? (
+ getKeyValue(userEntry, columnKey) ? (
+ "Archived"
+ ) : (
+ "Active"
+ )
+ ) : (
+
+ {getKeyValue(userEntry, columnKey)}
+
+ )}
+
+ )}
+
+ )}
+
+
+
+ )}
+
+ );
+}
diff --git a/server/routes/users.js b/server/routes/users.js
index edeb1df..349aa17 100644
--- a/server/routes/users.js
+++ b/server/routes/users.js
@@ -79,6 +79,7 @@ router.get("/all", async (req, res) => {
let list = await User.findAll({
where: condition,
order: [["createdAt", "DESC"]],
+ attributes: { exclude: ["password", "profilePicture"] },
});
res.json(list);
});
@@ -97,6 +98,8 @@ router.get("/individual/:id", validateToken, async (req, res) => {
message: `ERR_ACC_IS_ARCHIVED`,
});
} else {
+ user.password = undefined;
+ user.profilePicture = undefined;
res.json(user);
}
});
@@ -223,6 +226,30 @@ router.put("/archive/:id", validateToken, async (req, res) => {
}
});
+router.put("/unarchive/:id", validateToken, async (req, res) => {
+ let id = req.params.id;
+ let user = await User.findByPk(id);
+
+ if (!user) {
+ res.sendStatus(404);
+ return;
+ }
+
+ try {
+ await User.update(
+ { isArchived: false },
+ {
+ where: { id: id },
+ }
+ );
+ res.json({
+ message: "User archived successfully.",
+ });
+ } catch (err) {
+ res.status(400).json({ errors: err.errors });
+ }
+});
+
router.get("/profile-image/:id", async (req, res) => {
let id = req.params.id;
let user = await User.findByPk(id);