Export user data

This commit is contained in:
2024-08-14 19:50:21 +08:00
parent c79bb5475d
commit be1c8de5bf
5 changed files with 125 additions and 25 deletions

View File

@@ -15,6 +15,7 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"chart.js": "^4.4.3", "chart.js": "^4.4.3",
"dayjs": "^1.11.12", "dayjs": "^1.11.12",
"export-from-json": "^1.7.4",
"formik": "^2.4.6", "formik": "^2.4.6",
"framer-motion": "^11.2.10", "framer-motion": "^11.2.10",
"openai": "^4.53.2", "openai": "^4.53.2",

View File

@@ -748,3 +748,22 @@ export const ArrowTrendingUpIcon = () => {
</svg> </svg>
); );
}; };
export const ArrowDownTrayIcon = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"
/>
</svg>
);
};

View File

@@ -9,18 +9,25 @@ import {
Button, Button,
Tooltip, Tooltip,
Input, Input,
Dropdown,
DropdownTrigger,
DropdownMenu,
DropdownItem,
DropdownSection,
} from "@nextui-org/react"; } from "@nextui-org/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import instance from "../security/http"; import instance from "../security/http";
import config from "../config"; import config from "../config";
import { popErrorToast, popToast } from "../utilities"; import { exportData, popErrorToast, popToast } from "../utilities";
import { import {
ArchiveBoxIcon, ArchiveBoxIcon,
ArrowDownTrayIcon,
ClipboardDocumentIcon, ClipboardDocumentIcon,
LifebuoyIcon, LifebuoyIcon,
MagnifyingGlassIcon, MagnifyingGlassIcon,
XMarkIcon, XMarkIcon,
} from "../icons"; } from "../icons";
import { ExportType } from "export-from-json";
export default function UsersManagement() { export default function UsersManagement() {
const [userInformationlist, setUserInformationList] = useState<any>([]); const [userInformationlist, setUserInformationList] = useState<any>([]);
@@ -110,12 +117,61 @@ export default function UsersManagement() {
}); });
}; };
const handleExport = (exportType: ExportType) => {
exportData(
userInformationlist,
`ecoconnect-user-data-${new Date().toUTCString()}`,
exportType
);
};
return ( return (
<div> <div>
{userInformationlist && ( {userInformationlist && (
<div className="flex flex-col gap-8 p-8"> <div className="flex flex-col gap-8 p-8">
<div className="flex flex-row justify-between *:my-auto"> <div className="flex flex-row justify-between *:my-auto">
<p className="text-4xl font-bold">Users Onboard</p> <p className="text-4xl font-bold">Users Onboard</p>
<div className="flex flex-row gap-2">
<Dropdown>
<DropdownTrigger>
<Button>
<div className="flex flex-row gap-2 *:my-auto px-4">
<div className="scale-80 origin-center">
<ArrowDownTrayIcon />
</div>
<p>Export</p>
</div>
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Export file type">
<DropdownSection title="SELECT A FILE TYPE">
<DropdownItem
key="json"
onPress={() => {
handleExport("json");
}}
>
JavaScript Object Notation (JSON)
</DropdownItem>
<DropdownItem
key="csv"
onPress={() => {
handleExport("csv");
}}
>
Comma-Separated Values (CSV)
</DropdownItem>
<DropdownItem
key="xls"
onPress={() => {
handleExport("xls");
}}
>
Excel Workbook (XLS)
</DropdownItem>
</DropdownSection>
</DropdownMenu>
</Dropdown>
<Input <Input
className="max-w-96" className="max-w-96"
placeholder="Search" placeholder="Search"
@@ -138,6 +194,7 @@ export default function UsersManagement() {
} }
/> />
</div> </div>
</div>
<Table aria-label="User Information Table"> <Table aria-label="User Information Table">
<TableHeader columns={columns}> <TableHeader columns={columns}>
{(column) => ( {(column) => (

View File

@@ -1,5 +1,6 @@
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import exportFromJSON, { ExportType } from "export-from-json";
export function getTimeOfDay(): number { export function getTimeOfDay(): number {
const currentHour = new Date().getHours(); const currentHour = new Date().getHours();
@@ -39,3 +40,11 @@ export const popErrorToast = (error: any) => {
popToast("An unexpected error occured!\nPlease try again later.", 2); popToast("An unexpected error occured!\nPlease try again later.", 2);
} }
}; };
export const exportData = (
data: any,
fileName: string,
exportType: ExportType
) => {
exportFromJSON({ data, fileName, exportType });
};

View File

@@ -90,14 +90,30 @@ router.get("/all", async (req, res) => {
let list = await User.findAll({ let list = await User.findAll({
where: condition, where: condition,
order: [["createdAt", "DESC"]], order: [["createdAt", "DESC"]],
attributes: { exclude: ["password", "profilePicture"] }, attributes: {
exclude: [
"password",
"profilePicture",
"resetPasswordToken",
"resetPasswordExpireTime",
],
},
}); });
res.json(list); res.json(list);
}); });
router.get("/individual/:id", validateToken, async (req, res) => { router.get("/individual/:id", validateToken, async (req, res) => {
let id = req.params.id; let id = req.params.id;
let user = await User.findByPk(id); let user = await User.findByPk(id, {
attributes: {
exclude: [
"password",
"profilePicture",
"resetPasswordToken",
"resetPasswordExpireTime",
],
},
});
if (!user) { if (!user) {
res.sendStatus(404); res.sendStatus(404);
@@ -109,8 +125,6 @@ router.get("/individual/:id", validateToken, async (req, res) => {
message: `ERR_ACC_IS_ARCHIVED`, message: `ERR_ACC_IS_ARCHIVED`,
}); });
} else { } else {
user.password = undefined;
user.profilePicture = undefined;
res.json(user); res.json(user);
} }
}); });