Added an export feature for the master statisticl screen

This commit is contained in:
Joao Ramos
2024-09-05 22:42:46 +01:00
parent 70de97766e
commit a61ad2cc7e
6 changed files with 309 additions and 89 deletions

View File

@@ -1,23 +1,23 @@
import React from "react";
import { CorporateUser, User } from "@/interfaces/user";
import { BsBank, BsPersonFill } from "react-icons/bs";
import { BsFileExcel, BsBank, BsPersonFill } from "react-icons/bs";
import IconCard from "./IconCard";
import useAssignmentsCorporates from "@/hooks/useAssignmentCorporates";
import ReactDatePicker from "react-datepicker";
import moment from "moment";
import { Assignment, AssignmentWithCorporateId } from "@/interfaces/results";
import { AssignmentWithCorporateId } from "@/interfaces/results";
import {
CellContext,
createColumnHelper,
flexRender,
createColumnHelper,
getCoreRowModel,
HeaderGroup,
Table,
useReactTable,
} from "@tanstack/react-table";
import Checkbox from "@/components/Low/Checkbox";
import { useListSearch } from "@/hooks/useListSearch";
import axios from "axios";
import { toast } from "react-toastify";
interface Props {
corporateUsers: User[];
users: User[];
@@ -39,7 +39,7 @@ interface UserCount {
maxUserCount: number;
}
const searchFilters = [["email"], ["user"], ["userId"], ];
const searchFilters = [["email"], ["user"], ["userId"]];
const MasterStatistical = (props: Props) => {
const { users, corporateUsers } = props;
@@ -70,13 +70,15 @@ const MasterStatistical = (props: Props) => {
endDate,
});
const [downloading, setDownloading] = React.useState<boolean>(false);
const tableResults = React.useMemo(
() =>
assignments.reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
const userResults = a.assignees.map((assignee) => {
const userStats =
a.results.find((r) => r.user === assignee)?.stats || [];
const userData = users.find((u) => u.id === assignee)
const userData = users.find((u) => u.id === assignee);
const corporate = users.find((u) => u.id === a.assigner)?.name || "";
const commonData = {
user: userData?.name || "",
@@ -205,9 +207,9 @@ const MasterStatistical = (props: Props) => {
}),
];
const { rows: filteredRows, renderSearch } = useListSearch(
const { rows: filteredRows, renderSearch, text: searchText } = useListSearch(
searchFilters,
tableResults,
tableResults
);
const table = useReactTable({
@@ -216,8 +218,6 @@ const MasterStatistical = (props: Props) => {
getCoreRowModel: getCoreRowModel(),
});
const areAllSelected = selectedCorporates.length === corporates.length;
const getStudentsConsolidateScore = () => {
@@ -240,9 +240,55 @@ const MasterStatistical = (props: Props) => {
);
};
const triggerDownload = async () => {
try {
setDownloading(true);
const res = await axios.post("/api/assignments/statistical/excel", {
ids: selectedCorporates,
...(startDate ? { startDate: startDate.toISOString() } : {}),
...(endDate ? { endDate: endDate.toISOString() } : {}),
searchText,
});
toast.success("Report ready!");
const link = document.createElement("a");
link.href = res.data;
// download should have worked but there are some CORS issues
// https://firebase.google.com/docs/storage/web/download-files#cors_configuration
// link.download="report.pdf";
link.target = "_blank";
link.rel = "noreferrer";
link.click();
setDownloading(false);
} catch (err) {
toast.error("Failed to display the report!");
console.error(err);
setDownloading(false);
}
};
const renderIcon = () => {
if (downloading) {
return (
<span className={`text-mti-gray-dim loading loading-infinity w-6`} />
);
}
return (
<BsFileExcel
className={`text-mti-gray-dim text-2xl cursor-pointer`}
onClick={(e) => {
e.stopPropagation();
triggerDownload();
}}
/>
);
};
const consolidateResults = getStudentsConsolidateScore();
return (
<>
{renderIcon()}
<div className="flex flex-wrap gap-2 items-center text-center">
<IconCard
Icon={BsBank}
@@ -283,26 +329,28 @@ const MasterStatistical = (props: Props) => {
</div>
<div className="flex gap-3 w-full">
<div className="flex flex-col gap-3">
<label className="font-normal text-base text-mti-gray-dim">Date</label>
<ReactDatePicker
dateFormat="dd/MM/yyyy"
className="px-4 py-6 w-52 text-sm text-center font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed rounded-full border border-mti-gray-platinum focus:outline-none"
selected={startDate}
startDate={startDate}
endDate={endDate}
selectsRange
showMonthDropdown
onChange={([initialDate, finalDate]: [Date, Date]) => {
setStartDate(initialDate ?? moment("01/01/2023").toDate());
if (finalDate) {
// basicly selecting a final day works as if I'm selecting the first
// minute of that day. this way it covers the whole day
setEndDate(moment(finalDate).endOf("day").toDate());
return;
}
setEndDate(null);
}}
/>
<label className="font-normal text-base text-mti-gray-dim">
Date
</label>
<ReactDatePicker
dateFormat="dd/MM/yyyy"
className="px-4 py-6 w-52 text-sm text-center font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed rounded-full border border-mti-gray-platinum focus:outline-none"
selected={startDate}
startDate={startDate}
endDate={endDate}
selectsRange
showMonthDropdown
onChange={([initialDate, finalDate]: [Date, Date]) => {
setStartDate(initialDate ?? moment("01/01/2023").toDate());
if (finalDate) {
// basicly selecting a final day works as if I'm selecting the first
// minute of that day. this way it covers the whole day
setEndDate(moment(finalDate).endOf("day").toDate());
return;
}
setEndDate(null);
}}
/>
</div>
{renderSearch()}
</div>