Compare commits
2 Commits
9d2ffb5183
...
62238cbf8f
| Author | SHA1 | Date | |
|---|---|---|---|
| 62238cbf8f | |||
| 60e858c931 |
16
src/App.tsx
16
src/App.tsx
@ -16,6 +16,9 @@ import { Test } from "./pages/student/practice/Test";
|
|||||||
import { Profile } from "./pages/student/Profile";
|
import { Profile } from "./pages/student/Profile";
|
||||||
import { Rewards } from "./pages/student/Rewards";
|
import { Rewards } from "./pages/student/Rewards";
|
||||||
import { StudentLayout } from "./pages/student/StudentLayout";
|
import { StudentLayout } from "./pages/student/StudentLayout";
|
||||||
|
import { TargetedPractice } from "./pages/student/targeted-practice/page";
|
||||||
|
import { Drills } from "./pages/student/drills/page";
|
||||||
|
import { HardTestModules } from "./pages/student/hard-test-modules/page";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
@ -54,9 +57,20 @@ function App() {
|
|||||||
path: "practice/:sheetId",
|
path: "practice/:sheetId",
|
||||||
element: <Pretest />,
|
element: <Pretest />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "practice/targeted-practice",
|
||||||
|
element: <TargetedPractice />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "practice/drills",
|
||||||
|
element: <Drills />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "practice/hard-test-modules",
|
||||||
|
element: <HardTestModules />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: "practice/:sheetId/test",
|
path: "practice/:sheetId/test",
|
||||||
element: <Test />,
|
element: <Test />,
|
||||||
|
|||||||
@ -17,8 +17,10 @@ import {
|
|||||||
CardTitle,
|
CardTitle,
|
||||||
} from "../../components/ui/card";
|
} from "../../components/ui/card";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
export const Practice = () => {
|
export const Practice = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen max-w-7xl mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-4">
|
<main className="min-h-screen max-w-7xl mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-4">
|
||||||
<header className="flex justify-between items-center">
|
<header className="flex justify-between items-center">
|
||||||
@ -61,7 +63,10 @@ export const Practice = () => {
|
|||||||
<section className="flex flex-col gap-6">
|
<section className="flex flex-col gap-6">
|
||||||
<h1 className="font-satoshi-black text-2xl">Practice your way</h1>
|
<h1 className="font-satoshi-black text-2xl">Practice your way</h1>
|
||||||
<div className="md:grid md:grid-cols-2 md:gap-6 space-y-6 md:space-y-0">
|
<div className="md:grid md:grid-cols-2 md:gap-6 space-y-6 md:space-y-0">
|
||||||
<Card className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1">
|
<Card
|
||||||
|
onClick={() => navigate("/student/practice/targeted-practice")}
|
||||||
|
className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1"
|
||||||
|
>
|
||||||
<CardHeader className="space-y-3">
|
<CardHeader className="space-y-3">
|
||||||
<div className="w-fit bg-linear-to-br from-red-400 to-red-500 p-3 rounded-2xl">
|
<div className="w-fit bg-linear-to-br from-red-400 to-red-500 p-3 rounded-2xl">
|
||||||
<Target size={20} color="white" />
|
<Target size={20} color="white" />
|
||||||
@ -81,7 +86,10 @@ export const Practice = () => {
|
|||||||
</CardAction>
|
</CardAction>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1">
|
<Card
|
||||||
|
onClick={() => navigate("/student/practice/drills")}
|
||||||
|
className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1"
|
||||||
|
>
|
||||||
<CardHeader className="space-y-3">
|
<CardHeader className="space-y-3">
|
||||||
<div className="w-fit bg-linear-to-br from-cyan-400 to-cyan-500 p-3 rounded-2xl">
|
<div className="w-fit bg-linear-to-br from-cyan-400 to-cyan-500 p-3 rounded-2xl">
|
||||||
<Zap size={20} color="white" />
|
<Zap size={20} color="white" />
|
||||||
@ -99,7 +107,10 @@ export const Practice = () => {
|
|||||||
</CardAction>
|
</CardAction>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1">
|
<Card
|
||||||
|
onClick={() => navigate("/student/practice/hard-test-modules")}
|
||||||
|
className="rounded-4xl cursor-pointer hover:bg-gray-50 active:bg-gray-50 active:translate-y-1"
|
||||||
|
>
|
||||||
<CardHeader className="space-y-3">
|
<CardHeader className="space-y-3">
|
||||||
<div className="w-fit bg-linear-to-br from-lime-400 to-lime-500 p-3 rounded-2xl">
|
<div className="w-fit bg-linear-to-br from-lime-400 to-lime-500 p-3 rounded-2xl">
|
||||||
<Trophy size={20} color="white" />
|
<Trophy size={20} color="white" />
|
||||||
|
|||||||
7
src/pages/student/drills/page.tsx
Normal file
7
src/pages/student/drills/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const Drills = () => {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen max-w-7xl mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-4">
|
||||||
|
Drills
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
7
src/pages/student/hard-test-modules/page.tsx
Normal file
7
src/pages/student/hard-test-modules/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const HardTestModules = () => {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen max-w-7xl mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-4">
|
||||||
|
HardTestModules
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -41,6 +41,7 @@ import { useExamNavigationGuard } from "../../../hooks/useExamNavGuard";
|
|||||||
|
|
||||||
export const Test = () => {
|
export const Test = () => {
|
||||||
const blocker = useExamNavigationGuard();
|
const blocker = useExamNavigationGuard();
|
||||||
|
const [eliminated, setEliminated] = useState<Record<string, Set<string>>>({});
|
||||||
|
|
||||||
const [showExitDialog, setShowExitDialog] = useState(false);
|
const [showExitDialog, setShowExitDialog] = useState(false);
|
||||||
|
|
||||||
@ -223,37 +224,61 @@ export const Test = () => {
|
|||||||
|
|
||||||
// ✅ MCQ
|
// ✅ MCQ
|
||||||
if (question.options && question.options.length > 0) {
|
if (question.options && question.options.length > 0) {
|
||||||
|
const eliminatedSet = eliminated[question.id] ?? new Set();
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{question.options.map((option, index) => {
|
{question.options.map((option, index) => {
|
||||||
const isSelected = currentAnswer === option.id;
|
const isSelected = currentAnswer === option.id;
|
||||||
|
const isEliminated = eliminatedSet.has(option.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<div
|
||||||
key={option.id}
|
key={option.id}
|
||||||
className={`text-start font-satoshi-medium text-lg space-x-2 px-4 py-4 border rounded-4xl transition duration-200 ${
|
className={`flex flex-row-reverse items-center gap-4 transition
|
||||||
isSelected
|
|
||||||
? "bg-linear-to-br from-purple-400 to-purple-500 text-white"
|
`}
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
onClick={() =>
|
|
||||||
setAnswers((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[question.id]: option.id,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<span
|
<button
|
||||||
className={`px-2 py-1 rounded-full ${
|
type="button"
|
||||||
isSelected
|
onClick={(e) => {
|
||||||
? "bg-white text-purple-500"
|
e.stopPropagation();
|
||||||
: "bg-purple-500 text-white"
|
toggleEliminate(question.id, option.id);
|
||||||
}`}
|
}}
|
||||||
|
className={`w-8 h-8 rounded-full text-sm flex items-center justify-center
|
||||||
|
${
|
||||||
|
isEliminated
|
||||||
|
? "bg-red-500 text-white"
|
||||||
|
: "bg-gray-200 text-gray-600 hover:bg-gray-300"
|
||||||
|
}
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
{"ABCD"[index]}
|
✕
|
||||||
</span>{" "}
|
</button>
|
||||||
<span>{renderQuestionText(option.text)}</span>
|
<button
|
||||||
</button>
|
className={`w-full text-start font-satoshi-medium text-lg space-x-2 px-4 py-4 border rounded-4xl transition duration-200 ${
|
||||||
|
isSelected
|
||||||
|
? "bg-linear-to-br from-purple-400 to-purple-500 text-white"
|
||||||
|
: ""
|
||||||
|
} ${isEliminated ? "line-through opacity-70" : ""}`}
|
||||||
|
onClick={() =>
|
||||||
|
setAnswers((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[question.id]: option.id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`text-inherit px-2 py-1 rounded-full ${
|
||||||
|
isSelected
|
||||||
|
? "bg-white text-purple-500"
|
||||||
|
: "bg-purple-500 text-white"
|
||||||
|
} `}
|
||||||
|
>
|
||||||
|
{"ABCD"[index]}
|
||||||
|
</span>{" "}
|
||||||
|
<span>{renderQuestionText(option.text)}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -278,6 +303,14 @@ export const Test = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleEliminate = (questionId: string, optionId: string) => {
|
||||||
|
setEliminated((prev) => {
|
||||||
|
const current = new Set(prev[questionId] ?? []);
|
||||||
|
current.has(optionId) ? current.delete(optionId) : current.add(optionId);
|
||||||
|
return { ...prev, [questionId]: current };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case "IDLE":
|
case "IDLE":
|
||||||
return (
|
return (
|
||||||
|
|||||||
7
src/pages/student/targeted-practice/page.tsx
Normal file
7
src/pages/student/targeted-practice/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const TargetedPractice = () => {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen max-w-7xl mx-auto px-8 sm:px-6 lg:px-8 py-8 space-y-4">
|
||||||
|
Targeted Practice
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user