ENCOA-86: Added an option to release exam results

This commit is contained in:
Joao Ramos
2024-08-21 22:19:15 +01:00
parent 22611121c6
commit 556f642112
4 changed files with 83 additions and 2 deletions

View File

@@ -10,6 +10,7 @@ import {usePDFDownload} from "@/hooks/usePDFDownload";
import {useAssignmentArchive} from "@/hooks/useAssignmentArchive";
import {uniqBy} from "lodash";
import {useAssignmentUnarchive} from "@/hooks/useAssignmentUnarchive";
import {useAssignmentRelease} from "@/hooks/useAssignmentRelease";
import {getUserName} from "@/utils/users";
import {User} from "@/interfaces/user";
@@ -40,11 +41,14 @@ export default function AssignmentCard({
allowUnarchive,
allowExcelDownload,
users,
released,
}: Assignment & Props) {
const renderPdfIcon = usePDFDownload("assignments");
const renderExcelIcon = usePDFDownload("assignments", "excel");
const renderArchiveIcon = useAssignmentArchive(id, reload);
const renderUnarchiveIcon = useAssignmentUnarchive(id, reload);
const renderReleaseIcon = useAssignmentRelease(id, reload);
const calculateAverageModuleScore = (module: Module) => {
const resultModuleBandScores = results.map((r) => {
@@ -66,10 +70,11 @@ export default function AssignmentCard({
<div className="flex flex-row justify-between">
<h3 className="text-xl font-semibold">{name}</h3>
<div className="flex gap-2">
{allowDownload && renderPdfIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")}
{allowExcelDownload && renderExcelIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")}
{allowDownload && released && renderPdfIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")}
{allowExcelDownload && released && renderExcelIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")}
{allowArchive && !archived && renderArchiveIcon("text-mti-gray-dim", "text-mti-gray-dim")}
{allowUnarchive && archived && renderUnarchiveIcon("text-mti-gray-dim", "text-mti-gray-dim")}
{!released && renderReleaseIcon("text-mti-gray-dim", "text-mti-gray-dim")}
</div>
</div>
<ProgressBar

View File

@@ -0,0 +1,42 @@
import React from "react";
import axios from "axios";
import {toast} from "react-toastify";
import {BsDoorOpen} from "react-icons/bs";
export const useAssignmentRelease = (assignmentId: string, reload?: Function) => {
const [loading, setLoading] = React.useState(false);
const archive = () => {
// archive assignment
setLoading(true);
axios
.post(`/api/assignments/${assignmentId}/release`)
.then((res) => {
toast.success("Assignment archived!");
if (reload) reload();
setLoading(false);
})
.catch((err) => {
toast.error("Failed to archive the assignment!");
setLoading(false);
});
};
const renderIcon = (downloadClasses: string, loadingClasses: string) => {
if (loading) {
return <span className={`${loadingClasses} loading loading-infinity w-6`} />;
}
return (
<div
className="tooltip flex items-center justify-center w-fit h-fit"
data-tip="Release assignment"
onClick={(e) => {
e.stopPropagation();
archive();
}}>
<BsDoorOpen className={`${downloadClasses} text-2xl cursor-pointer tooltip`} />
</div>
);
};
return renderIcon;
};

View File

@@ -25,4 +25,5 @@ export interface Assignment {
startDate: Date;
endDate: Date;
archived?: boolean;
released?: boolean;
}

View File

@@ -0,0 +1,33 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { app } from "@/firebase";
import { getFirestore, doc, getDoc, setDoc } from "firebase/firestore";
import { withIronSessionApiRoute } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
const db = getFirestore(app);
export default withIronSessionApiRoute(handler, sessionOptions);
async function post(req: NextApiRequest, res: NextApiResponse) {
// verify if it's a logged user that is trying to archive
if (req.session.user) {
const { id } = req.query as { id: string };
const docSnap = await getDoc(doc(db, "assignments", id));
if (!docSnap.exists()) {
res.status(404).json({ ok: false });
return;
}
await setDoc(docSnap.ref, { released: true }, { merge: true });
res.status(200).json({ ok: true });
return;
}
res.status(401).json({ ok: false });
}
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") return post(req, res);
res.status(404).json({ ok: false });
}