Files
edbridge-scholars/src/pages/student/practice/Pretest.tsx
2026-01-28 15:22:19 +06:00

231 lines
8.6 KiB
TypeScript

import { useEffect, useState } from "react";
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,
Loader,
Loader2,
Tag,
} from "lucide-react";
import {
Carousel,
CarouselContent,
CarouselItem,
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);
const { sheetId } = useParams<{ sheetId: string }>();
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) {
if (!sheetId) {
console.error("Sheet ID is required to start the test.");
return;
}
navigate(`/student/practice/${sheetId}/test`, { replace: true });
}
useEffect(() => {
if (!user) return;
async function fetchPracticeSheet(sheetId: string) {
const authStorage = localStorage.getItem("auth-storage");
if (!authStorage) {
console.error("authStorage not found in local storage");
return;
}
const {
state: { token },
} = JSON.parse(authStorage);
if (!token) {
console.error("Token not found in authStorage");
return;
}
const data = await api.getPracticeSheetById(token, sheetId);
setPracticeSheet(data);
}
fetchPracticeSheet(sheetId!);
}, [sheetId]);
useEffect(() => {
if (!carouselApi) {
return;
}
setCount(carouselApi.scrollSnapList().length);
setCurrent(carouselApi.selectedScrollSnap() + 1);
carouselApi.on("select", () => {
setCurrent(carouselApi.selectedScrollSnap() + 1);
});
}, [carouselApi]);
return (
<main className="max-w-full mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-6">
<header className="space-y-2">
<h1 className="text-4xl font-satoshi-bold">{practiceSheet?.title}</h1>
<p className="text-lg font-satoshi text-gray-700">
{practiceSheet?.description}
</p>
</header>
{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 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 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>
</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 ? (
practiceSheet.modules.length > 0 ? (
practiceSheet.modules.map((module, index) => (
<CarouselItem key={index} className="">
<section className="flex flex-col gap-6 rounded-4xl p-8 bg-white border">
<h1 className="text-2xl font-satoshi-bold">
Section {Math.floor(index / 2) + 1}
</h1>
<p className="text-lg font-satoshi text-gray-700">
{module.title}
</p>
<section className="flex justify-between">
<div className="flex flex-col justify-center items-center gap-4">
<div className="w-fit bg-cyan-100 p-2 rounded-full">
<Clock size={30} color="oklch(60.9% 0.126 221.723)" />
</div>
<div className="flex flex-col justify-center items-center">
<h3 className="text-xl font-satoshi-bold ">
{module.duration}
</h3>
<p className="text-md font-satoshi ">Minutes</p>
</div>
</div>
<div className="flex flex-col justify-center items-center gap-4">
<div className="w-fit bg-lime-100 p-2 rounded-full">
<CircleQuestionMark
size={30}
color="oklch(64.8% 0.2 131.684)"
/>
</div>
<div className="flex flex-col justify-center items-center">
<h3 className="text-xl font-satoshi-bold ">
{module.questions.length}
</h3>
<p className="text-md font-satoshi">Questions</p>
</div>
</div>
<div className="flex flex-col justify-center items-center gap-4">
<div className="w-fit bg-amber-100 p-2 rounded-full">
<Tag size={30} color="oklch(66.6% 0.179 58.318)" />
</div>
<div className="flex flex-col justify-center items-center">
<h3 className="text-xl font-satoshi-bold ">
{module.section}
</h3>
<p className="text-md font-satoshi">Type</p>
</div>
</div>
</section>
</section>
</CarouselItem>
))
) : (
<CarouselItem>
<section className="w-full rounded-4xl p-8 bg-red-100 border border-red-300">
<h1 className="text-lg text-center font-satoshi-bold text-red-500">
No modules available.
</h1>
</section>
</CarouselItem>
)
) : (
<CarouselItem>
<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>
</section>
</CarouselItem>
)}
</CarouselContent>
<div className="flex justify-center mt-4">
{practiceSheet?.modules.map((_, index) => (
<div
key={index}
className={`w-2 h-2 mx-1 rounded-full ${
index + 1 === current ? "bg-purple-500" : "bg-gray-300"
}`}
></div>
))}
</div>
</Carousel>
<section className="w-full rounded-4xl p-8 bg-white border flex flex-col justify-between gap-4">
<h1 className="text-lg font-satoshi-bold ">
This practice sheet will help you prepare for the SAT. Take your time
and do your best!
</h1>
</section>
<Button
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}
>
{practiceSheet ? (
"Start Test"
) : (
<div>
<Loader size={60} className="transition animate-spin" />
</div>
)}
</Button>
</main>
);
};