Updated Master Statistical

This commit is contained in:
Joao Ramos
2024-08-23 00:56:18 +01:00
parent 4379716e9b
commit 44adc142f6
6 changed files with 175 additions and 45 deletions

View File

@@ -625,7 +625,8 @@ export default function MasterCorporateDashboard({user}: Props) {
<h2 className="text-2xl font-semibold">Master Statistical</h2>
</div>
<MasterStatistical
users={masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => {
users={users}
corporateUsers={masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => {
const user = users.find((u) => u.id === id) as CorporateUser;
if (user) return [...accm, user];
return accm;
@@ -694,13 +695,13 @@ export default function MasterCorporateDashboard({user}: Props) {
color="purple"
onClick={() => setPage("studentsPerformance")}
/>
{/* <IconCard
<IconCard
Icon={BsDatabase}
label="Master Statistical"
// value={masterCorporateUserGroups.length}
color="purple"
onClick={() => setPage("statistical")}
/> */}
/>
<button
disabled={isAssignmentsLoading}
onClick={() => setPage("assignments")}

View File

@@ -1,34 +1,108 @@
import React from "react";
import {CorporateUser} from "@/interfaces/user";
import {BsBank, BsPersonFill} from "react-icons/bs";
import { CorporateUser, User } from "@/interfaces/user";
import { 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 { groupBySession } from "@/utils/stats";
import { Assignment, AssignmentResult } from "@/interfaces/results";
interface Props {
users: CorporateUser[];
corporateUsers: CorporateUser[];
users: User[];
}
interface TableData {
user: string;
correct: number;
corporate: string;
submitted: boolean;
date: moment.Moment;
assignment: string;
}
const MasterStatistical = (props: Props) => {
const {users} = props;
const { users, corporateUsers } = props;
const usersList = React.useMemo(() => users.map((x) => x.id), [users]);
const corporates = React.useMemo(() => corporateUsers.map((x) => x.id), [corporateUsers]);
const [startDate, setStartDate] = React.useState<Date | null>(
moment("01/01/2023").toDate()
);
const [endDate, setEndDate] = React.useState<Date | null>(
moment().endOf("year").toDate()
);
const {assignments} = useAssignmentsCorporates({corporates: usersList});
const { assignments } = useAssignmentsCorporates({
corporates,
startDate,
endDate,
});
return (
<div className="flex flex-wrap gap-2 items-center text-center">
<IconCard Icon={BsBank} label="Consolidate" value={0} color="purple" onClick={() => console.log("clicked")} />
{users.map((group) => (
<IconCard
key={group.id}
Icon={BsBank}
label={group.corporateInformation?.companyInformation?.name}
value={0}
color="purple"
onClick={() => console.log("clicked", group)}
/>
))}
<IconCard onClick={() => console.log("clicked")} Icon={BsPersonFill} label="Consolidate Highest Student" color="purple" />
</div>
);
const x = assignments.reduce((accmA: TableData[], a: Assignment) => {
const userResults = a.results.reduce((accmB: TableData[], r: AssignmentResult) => {
const userStats = groupBySession(r.stats);
const data = Object.keys(userStats).map((key) => ({
user: users.find((u) => u.id === r.user)?.name || "",
correct: userStats[key].reduce((n, e) => n + e.score.correct, 0),
corporate: users.find((u) => u.id === a.assigner)?.name || "",
submitted: false,
date: moment.max(userStats[key].map((e) => moment(e.date))),
assignment: a.name,
}));
return [...accmB, ...data];
}, []);
return [...accmA, ...userResults];
}, []);
return (
<div className="flex flex-wrap gap-2 items-center text-center">
<IconCard
Icon={BsBank}
label="Consolidate"
value={0}
color="purple"
onClick={() => console.log("clicked")}
/>
{corporateUsers.map((group) => (
<IconCard
key={group.id}
Icon={BsBank}
label={group.corporateInformation?.companyInformation?.name}
value={0}
color="purple"
onClick={() => console.log("clicked", group)}
/>
))}
<ReactDatePicker
dateFormat="dd/MM/yyyy"
className="px-4 py-6 w-full 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);
}}
/>
<IconCard
onClick={() => console.log("clicked")}
Icon={BsPersonFill}
label="Consolidate Highest Student"
color="purple"
/>
</div>
);
};
export default MasterStatistical;

View File

@@ -1,11 +1,16 @@
import { Assignment } from "@/interfaces/results";
import axios from "axios";
import moment from "moment";
import { useEffect, useState } from "react";
export default function useAssignmentsCorporates({
corporates,
startDate,
endDate,
}: {
corporates: string[];
startDate: Date | null;
endDate: Date | null;
}) {
const [assignments, setAssignments] = useState<Assignment[]>([]);
const [isLoading, setIsLoading] = useState(false);
@@ -18,9 +23,15 @@ export default function useAssignmentsCorporates({
}
setIsLoading(true);
const urlSearchParams = new URLSearchParams({
ids: corporates.join(","),
...(startDate ? { startDate: startDate.toISOString() } : {}),
...(endDate ? { endDate: endDate.toISOString() } : {}),
});
axios
.get<Assignment[]>(
`/api/assignments/corporate?ids=${corporates.join(",")}`
`/api/assignments/corporate?${urlSearchParams.toString()}`
)
.then(async (response) => {
setAssignments(response.data);
@@ -28,7 +39,7 @@ export default function useAssignmentsCorporates({
.finally(() => setIsLoading(false));
};
useEffect(getData, [corporates]);
useEffect(getData, [corporates, startDate, endDate]);
return { assignments, isLoading, isError, reload: getData };
}

View File

@@ -10,16 +10,18 @@ interface ModuleResult {
total: number;
}
export interface AssignmentResult {
user: string;
type: "academic" | "general";
stats: Stat[];
}
export interface Assignment {
id: string;
name: string;
assigner: string;
assignees: string[];
results: {
user: string;
type: "academic" | "general";
stats: Stat[];
}[];
results: AssignmentResult[];
exams: {id: string; module: Module; assignee: string}[];
instructorGender?: InstructorGender;
startDate: Date;

View File

@@ -20,13 +20,16 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}
async function GET(req: NextApiRequest, res: NextApiResponse) {
const { ids } = req.query as { ids: string };
const { ids, startDate, endDate } = req.query as { ids: string, startDate?: string, endDate?: string };
const startDateParsed = startDate ? new Date(startDate) : undefined;
const endDateParsed = endDate ? new Date(endDate) : undefined;
try {
const idsList = ids.split(",");
const assigners = await Promise.all(idsList.map(getAllAssignersByCorporate));
const assignmentList = [...assigners.flat(), ...idsList];
const assignments = await getAssignmentsByAssigners(assignmentList);
const assignments = await getAssignmentsByAssigners(assignmentList, startDateParsed, endDateParsed);
res.status(200).json(assignments);
} catch (err: any) {
res.status(500).json({ error: err.message });

View File

@@ -1,19 +1,58 @@
import {app} from "@/firebase";
import {Assignment} from "@/interfaces/results";
import {collection, getDocs, getFirestore, query, where} from "firebase/firestore";
import { app } from "@/firebase";
import { Assignment } from "@/interfaces/results";
import {
collection,
getDocs,
getFirestore,
query,
where,
} from "firebase/firestore";
const db = getFirestore(app);
export const getAssignmentsByAssigner = async (id: string) => {
const {docs} = await getDocs(query(collection(db, "assignments"), where("assigner", "==", id)));
return docs.map((x) => ({...x.data(), id: x.id})) as Assignment[];
export const getAssignmentsByAssigner = async (
id: string,
startDate?: Date,
endDate?: Date
) => {
const { docs } = await getDocs(
query(
collection(db, "assignments"),
...[
where("assigner", "==", id),
...(startDate ? [where("startDate", ">=", startDate.toISOString())] : []),
// firebase doesnt accept compound queries so we have to filter on the server
// ...endDate ? [where("endDate", "<=", endDate)] : [],
]
)
);
if (endDate) {
return docs
.map((x) => ({ ...(x.data() as Assignment), id: x.id }))
.filter((x) => new Date(x.endDate) <= endDate) as Assignment[];
}
return docs.map((x) => ({ ...x.data(), id: x.id })) as Assignment[];
};
export const getAssignmentsByAssignerBetweenDates = async (id: string, startDate: Date, endDate: Date) => {
const {docs} = await getDocs(query(collection(db, "assignments"), where("assigner", "==", id), ));
return docs.map((x) => ({...x.data(), id: x.id})) as Assignment[];
export const getAssignmentsByAssignerBetweenDates = async (
id: string,
startDate: Date,
endDate: Date
) => {
const { docs } = await getDocs(
query(collection(db, "assignments"), where("assigner", "==", id))
);
return docs.map((x) => ({ ...x.data(), id: x.id })) as Assignment[];
};
export const getAssignmentsByAssigners = async (ids: string[]) => {
return (await Promise.all(ids.map(getAssignmentsByAssigner))).flat();
export const getAssignmentsByAssigners = async (
ids: string[],
startDate?: Date,
endDate?: Date
) => {
return (
await Promise.all(
ids.map((id) => getAssignmentsByAssigner(id, startDate, endDate))
)
).flat();
};