Added an export feature for the master statisticl screen
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user