Merged develop into feature/ExamGenRework

This commit is contained in:
Tiago Ribeiro
2024-11-06 14:53:02 +00:00
7 changed files with 318 additions and 26 deletions

View File

@@ -0,0 +1,99 @@
import { Session } from "@/hooks/useSessions";
import { Assignment } from "@/interfaces/results";
import { User } from "@/interfaces/user";
import { sortByModuleName } from "@/utils/moduleUtils";
import clsx from "clsx";
import moment from "moment";
import { useRouter } from "next/router";
import Button from "../Low/Button";
import ModuleBadge from "../ModuleBadge";
interface Props {
assignment: Assignment
user: User
session?: Session
startAssignment: (assignment: Assignment) => void
resumeAssignment: (session: Session) => void
}
export default function AssignmentCard({ user, assignment, session, startAssignment, resumeAssignment }: Props) {
const router = useRouter()
return (
<div
className={clsx(
"border-mti-gray-anti-flash flex min-w-[350px] flex-col gap-6 rounded-xl border p-4",
assignment.results.map((r) => r.user).includes(user.id) && "border-mti-green-light",
)}
key={assignment.id}>
<div className="flex flex-col gap-1">
<h3 className="text-mti-black/90 text-xl font-semibold">{assignment.name}</h3>
<span className="flex justify-between gap-1 text-lg">
<span>{moment(assignment.startDate).format("DD/MM/YY, HH:mm")}</span>
<span>-</span>
<span>{moment(assignment.endDate).format("DD/MM/YY, HH:mm")}</span>
</span>
</div>
<div className="flex w-full items-center justify-between">
<div className="-md:mt-2 grid w-fit min-w-[140px] grid-cols-2 grid-rows-2 place-items-center justify-between gap-4">
{assignment.exams
.filter((e) => e.assignee === user.id)
.map((e) => e.module)
.sort(sortByModuleName)
.map((module) => (
<ModuleBadge className="scale-110 w-full" key={module} module={module} />
))}
</div>
{!assignment.results.map((r) => r.user).includes(user.id) && (
<>
<div
className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
data-tip="Your screen size is too small to perform an assignment">
<Button className="h-full w-full !rounded-xl" variant="outline">
Start
</Button>
</div>
{!session && (
<div
data-tip="You have already started this assignment!"
className={clsx(
"-md:hidden h-full w-full max-w-[50%] cursor-pointer",
!!session && "tooltip",
)}>
<Button
className={clsx("w-full h-full !rounded-xl")}
onClick={() => startAssignment(assignment)}
variant="outline">
Start
</Button>
</div>
)}
{!!session && (
<div
className={clsx(
"-md:hidden h-full w-full max-w-[50%] cursor-pointer"
)}>
<Button
className={clsx("w-full h-full !rounded-xl")}
onClick={() => resumeAssignment(session)}
color="green"
variant="outline">
Resume
</Button>
</div>
)}
</>
)}
{assignment.results.map((r) => r.user).includes(user.id) && (
<Button
onClick={() => router.push("/record")}
color="green"
className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
variant="outline">
Submitted
</Button>
)}
</div>
</div>
)
}

View File

@@ -13,10 +13,12 @@ export default function SessionCard({
session,
reload,
loadSession,
disableDelete = false
}: {
session: Session;
reload: () => void;
loadSession: (session: Session) => Promise<void>;
disableDelete?: boolean
}) {
const [isLoading, setIsLoading] = useState(false);
@@ -95,7 +97,7 @@ export default function SessionCard({
</button>
<button
onClick={deleteSession}
disabled={isLoading}
disabled={isLoading || disableDelete}
className="bg-mti-red-ultralight w-full hover:bg-mti-red-light rounded-lg p-2 px-4 transition duration-300 ease-in-out hover:text-white disabled:cursor-not-allowed">
{!isLoading && "Delete"}
{isLoading && (

View File

@@ -189,10 +189,7 @@ const StatsGridItem: React.FC<StatsGridItemProps> = ({
};
const shouldRenderPDFIcon = () => {
if (assignment) {
return assignment.released;
}
if (assignment) return assignment.released;
return true;
};

View File

@@ -14,10 +14,11 @@ interface Props {
label: string;
tooltip?: string;
}[];
removeLevel?: boolean
children?: ReactElement;
}
export default function ProfileSummary({user, items}: Props) {
export default function ProfileSummary({user, items, removeLevel = false}: Props) {
return (
<section className="w-full flex -md:flex-col gap-4 md:gap-8">
<img
@@ -30,21 +31,29 @@ export default function ProfileSummary({user, items}: Props) {
<div className="flex -md:flex-col justify-between w-full gap-8">
<div className="flex flex-col gap-2 py-2">
<h1 className="font-bold text-2xl md:text-4xl">{user.name}</h1>
<h6 className="font-normal text-base text-mti-gray-taupe">{USER_TYPE_LABELS[user.type]}</h6>
<div className="flex items-center gap-2">
<h6 className="font-normal text-base text-mti-gray-taupe">{user.email}</h6>
<span> - </span>
<h6 className="font-normal text-base text-mti-gray-taupe">{USER_TYPE_LABELS[user.type]}</h6>
</div>
</div>
<ProgressBar
label={`Level ${calculateAverageLevel(user.levels).toFixed(1)}`}
percentage={100}
color="purple"
className="max-w-xs w-32 md:self-end h-10 -md:hidden"
/>
{!removeLevel && (
<ProgressBar
label={`Level ${calculateAverageLevel(user.levels).toFixed(1)}`}
percentage={100}
color="purple"
className="max-w-xs w-32 md:self-end h-10 -md:hidden"
/>
)}
</div>
<ProgressBar
label=""
percentage={Math.round((calculateAverageLevel(user.levels) * 100) / calculateAverageLevel(user.desiredLevels))}
color="red"
className="w-full h-3 drop-shadow-lg -md:hidden"
/>
{!removeLevel && (
<ProgressBar
label=""
percentage={Math.round((calculateAverageLevel(user.levels) * 100) / calculateAverageLevel(user.desiredLevels))}
color="red"
className="w-full h-3 drop-shadow-lg -md:hidden"
/>
)}
<div className="flex justify-between w-full mt-8 -md:hidden">
{items.map((item) => (