Added dynamic generation of exams as an option

This commit is contained in:
Joao Ramos
2023-12-07 23:07:35 +00:00
parent f48885bba6
commit 0049ab272b
3 changed files with 82 additions and 31 deletions

View File

@@ -18,6 +18,7 @@ import {getExam} from "@/utils/exams";
import {toast} from "react-toastify"; import {toast} from "react-toastify";
import {uuidv4} from "@firebase/util"; import {uuidv4} from "@firebase/util";
import {Assignment} from "@/interfaces/results"; import {Assignment} from "@/interfaces/results";
import Checkbox from "@/components/Low/Checkbox";
interface Props { interface Props {
isCreating: boolean; isCreating: boolean;
@@ -35,6 +36,8 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [startDate, setStartDate] = useState<Date | null>(assignment ? moment(assignment.startDate).toDate() : moment().add(1, "day").toDate()); const [startDate, setStartDate] = useState<Date | null>(assignment ? moment(assignment.startDate).toDate() : moment().add(1, "day").toDate());
const [endDate, setEndDate] = useState<Date | null>(assignment ? moment(assignment.endDate).toDate() : moment().add(8, "day").toDate()); const [endDate, setEndDate] = useState<Date | null>(assignment ? moment(assignment.endDate).toDate() : moment().add(8, "day").toDate());
// creates a new exam for each assignee or just one exam for all assignees
const [generateMultiple, setGenerateMultiple] = useState<boolean>(false);
const toggleModule = (module: Module) => { const toggleModule = (module: Module) => {
const modules = selectedModules.filter((x) => x !== module); const modules = selectedModules.filter((x) => x !== module);
@@ -55,7 +58,8 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro
name, name,
startDate, startDate,
endDate, endDate,
selectedModules selectedModules,
generateMultiple,
} }
) )
.then(() => { .then(() => {
@@ -280,6 +284,11 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro
))} ))}
</div> </div>
</section> </section>
<div className="flex gap-4 w-full justify-end">
<Checkbox isChecked={generateMultiple} onChange={() => setGenerateMultiple(d => !d)}>
Generate an unique exam for each student
</Checkbox>
</div>
<div className="flex gap-4 w-full justify-end"> <div className="flex gap-4 w-full justify-end">
<Button className="w-full max-w-[200px]" variant="outline" onClick={cancelCreation} disabled={isLoading} isLoading={isLoading}> <Button className="w-full max-w-[200px]" variant="outline" onClick={cancelCreation} disabled={isLoading} isLoading={isLoading}>
Cancel Cancel

View File

@@ -49,12 +49,12 @@ function getRandomIndex(arr: any[]): number {
return randomIndex; return randomIndex;
} }
async function POST(req: NextApiRequest, res: NextApiResponse) { const generateExams = async (
const { selectedModules, assignees, ...body } = req.body as { generateMultiple: Boolean,
selectedModules: Module[]; selectedModules: Module[],
assignees: string[]; assignees: string[]
}; ): Promise<ExamWithUser[]> => {
if (generateMultiple) {
// for optimization purposes, it would be better to create a new endpoint that returned the answers for all users at once // for optimization purposes, it would be better to create a new endpoint that returned the answers for all users at once
const allExams = await assignees.map(async (assignee) => { const allExams = await assignees.map(async (assignee) => {
const selectedModulePromises = await selectedModules.map( const selectedModulePromises = await selectedModules.map(
@@ -82,7 +82,49 @@ async function POST(req: NextApiRequest, res: NextApiResponse) {
const exams = flatten(await Promise.all(allExams)).filter( const exams = flatten(await Promise.all(allExams)).filter(
(x) => x !== null (x) => x !== null
) as ExamWithUser[]; ) as ExamWithUser[];
return exams;
}
const selectedModulePromises = await selectedModules.map(
async (module: Module) => {
const exams: Exam[] = await getExams(db, module, "false", undefined);
const exam = exams[getRandomIndex(exams)];
if (exam) {
return { module: exam.module, id: exam.id };
}
return null;
}
);
const exams = await Promise.all(selectedModulePromises);
const examesFiltered = exams.filter((x) => x !== null) as ExamWithUser[];
return flatten(
assignees.map((assignee) =>
examesFiltered.map((exam) => ({ ...exam, assignee }))
)
);
};
async function POST(req: NextApiRequest, res: NextApiResponse) {
const {
selectedModules,
assignees,
// Generarte multiple true would generate an unique exam for eacah user
// false would generate the same exam for all usersa
generateMultiple = false,
...body
} = req.body as {
selectedModules: Module[];
assignees: string[];
generateMultiple: Boolean;
};
const exams: ExamWithUser[] = await generateExams(
generateMultiple,
selectedModules,
assignees
);
if (exams.length === 0) { if (exams.length === 0) {
res res
.status(400) .status(400)

View File

@@ -18,7 +18,7 @@ export const getExams = async (
// added userId as due to assignments being set from the teacher to the student // added userId as due to assignments being set from the teacher to the student
// we need to make sure we are serving exams not executed by the user and not // we need to make sure we are serving exams not executed by the user and not
// by the teacher that performed the request // by the teacher that performed the request
userId: string userId: string | undefined
): Promise<Exam[]> => { ): Promise<Exam[]> => {
const moduleRef = collection(db, module); const moduleRef = collection(db, module);