Merged in ENCOA-131_MasterStatistical (pull request #91)

ENCOA-131 MasterStatistical

Approved-by: Tiago Ribeiro
This commit is contained in:
João Ramos
2024-09-06 08:53:07 +00:00
committed by Tiago Ribeiro
8 changed files with 405 additions and 100 deletions

View File

@@ -1,22 +1,24 @@
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";
import Button from "@/components/Low/Button";
interface Props {
corporateUsers: User[];
users: User[];
@@ -24,6 +26,7 @@ interface Props {
interface TableData {
user: string;
email: string;
correct: number;
corporate: string;
submitted: boolean;
@@ -37,6 +40,8 @@ interface UserCount {
maxUserCount: number;
}
const searchFilters = [["email"], ["user"], ["userId"]];
const MasterStatistical = (props: Props) => {
const { users, corporateUsers } = props;
@@ -66,16 +71,20 @@ 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 userName = users.find((u) => u.id === assignee)?.name || "";
const userData = users.find((u) => u.id === assignee);
const corporate = users.find((u) => u.id === a.assigner)?.name || "";
const commonData = {
user: userName,
user: userData?.name || "",
email: userData?.email || "",
userId: assignee,
corporateId: a.corporateId,
corporate,
assignment: a.name,
@@ -146,6 +155,13 @@ const MasterStatistical = (props: Props) => {
return <span>{info.getValue()}</span>;
},
}),
columnHelper.accessor("email", {
header: "Email",
id: "email",
cell: (info) => {
return <span>{info.getValue()}</span>;
},
}),
columnHelper.accessor("corporate", {
header: "Corporate",
id: "corporate",
@@ -192,8 +208,14 @@ const MasterStatistical = (props: Props) => {
}),
];
const {
rows: filteredRows,
renderSearch,
text: searchText,
} = useListSearch(searchFilters, tableResults);
const table = useReactTable({
data: tableResults,
data: filteredRows,
columns: defaultColumns,
getCoreRowModel: getCoreRowModel(),
});
@@ -220,6 +242,32 @@ 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 consolidateResults = getStudentsConsolidateScore();
return (
<>
@@ -261,28 +309,43 @@ const MasterStatistical = (props: Props) => {
);
})}
</div>
<div className="flex flex-col gap-3 w-full">
<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 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);
}}
/>
</div>
{renderSearch()}
<div className="flex flex-col gap-3 justify-end">
<Button
className="max-w-[200px] h-[70px]"
variant="outline"
onClick={triggerDownload}
>
Download
</Button>
</div>
</div>
<div>
<table className="rounded-xl h-full bg-mti-purple-ultralight/40 w-full">
<thead>