feat(exam): add SAT style testing component

This commit is contained in:
shafin-r
2026-01-28 15:22:19 +06:00
parent 61b7c5220e
commit 355ca0c0c4
17 changed files with 1136 additions and 267 deletions

View File

@ -1,9 +1,16 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { Outlet, replace, useParams } from "react-router-dom";
import { api } from "../../../utils/api";
import { useAuthStore } from "../../../stores/authStore";
import type { PracticeSheet } from "../../../types/sheet";
import { CircleQuestionMark, Clock, Layers, Tag } from "lucide-react";
import {
CircleQuestionMark,
Clock,
Layers,
Loader,
Loader2,
Tag,
} from "lucide-react";
import {
Carousel,
CarouselContent,
@ -11,6 +18,7 @@ import {
type CarouselApi,
} from "../../../components/ui/carousel";
import { Button } from "../../../components/ui/button";
import { useNavigate } from "react-router-dom";
export const Pretest = () => {
const user = useAuthStore((state) => state.user);
@ -18,13 +26,18 @@ export const Pretest = () => {
const [carouselApi, setCarouselApi] = useState<CarouselApi>();
const [current, setCurrent] = useState(0);
const [count, setCount] = useState(0);
const navigate = useNavigate();
const [practiceSheet, setPracticeSheet] = useState<PracticeSheet | null>(
null,
);
function handleStartTest(sheetId: string) {
console.log("Starting test for Practice Sheet. ID: ", sheetId);
if (!sheetId) {
console.error("Sheet ID is required to start the test.");
return;
}
navigate(`/student/practice/${sheetId}/test`, { replace: true });
}
useEffect(() => {
@ -67,35 +80,43 @@ export const Pretest = () => {
{practiceSheet?.description}
</p>
</header>
<section className="flex flex-col gap-6 rounded-4xl bg-white border p-8">
<div className="flex items-center gap-4">
<Clock size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.time_limit}
</h3>
<p className="text-xl font-satoshi ">Minutes</p>
{practiceSheet ? (
<section className="flex flex-col gap-6 rounded-4xl bg-white border p-8">
<div className="flex items-center gap-4">
<Clock size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.time_limit}
</h3>
<p className="text-xl font-satoshi ">Minutes</p>
</div>
</div>
</div>
<div className="flex items-center gap-4">
<Layers size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.modules.length}
</h3>
<p className="text-xl font-satoshi">Modules</p>
<div className="flex items-center gap-4">
<Layers size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.modules.length}
</h3>
<p className="text-xl font-satoshi">Modules</p>
</div>
</div>
</div>
<div className="flex items-center gap-4">
<CircleQuestionMark size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.questions_count}
</h3>
<p className="text-xl font-satoshi ">Questions</p>
<div className="flex items-center gap-4">
<CircleQuestionMark size={65} color="black" />
<div>
<h3 className="text-3xl font-satoshi-bold ">
{practiceSheet?.questions_count}
</h3>
<p className="text-xl font-satoshi ">Questions</p>
</div>
</div>
</div>
</section>
</section>
) : (
<section className="flex flex-col items-center gap-6 rounded-4xl bg-white border p-8">
<div>
<Loader size={30} className="transition animate-spin" />
</div>
</section>
)}
<Carousel setApi={setCarouselApi}>
<CarouselContent className="">
{practiceSheet ? (
@ -161,7 +182,10 @@ export const Pretest = () => {
)
) : (
<CarouselItem>
<section className="flex flex-col w-full rounded-4xl p-8 bg-yellow-100 border">
<section className="flex flex-col w-full rounded-4xl p-8 bg-yellow-100 border items-center justify-between gap-4">
<div>
<Loader size={30} className="transition animate-spin" />
</div>
<h1 className="text-center text-xl font-satoshi-bold text-yellow-500">
Loading...
</h1>
@ -191,8 +215,15 @@ export const Pretest = () => {
onClick={() => handleStartTest(practiceSheet?.id!)}
variant="outline"
className="font-satoshi rounded-3xl w-full text-lg py-8 bg-linear-to-br from-purple-500 to-purple-600 text-white active:bg-linear-to-br active:from-purple-600 active:to-purple-700 active:translate-y-1"
disabled={!practiceSheet}
>
Start Test
{practiceSheet ? (
"Start Test"
) : (
<div>
<Loader size={60} className="transition animate-spin" />
</div>
)}
</Button>
</main>
);