Export user data
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -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) => (
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user