Added the ability for a user to select to avoid repeated exams
This commit is contained in:
@@ -13,13 +13,13 @@ import {sortByModuleName} from "@/utils/moduleUtils";
|
||||
|
||||
interface Props {
|
||||
user: User;
|
||||
onStart: (modules: Module[]) => void;
|
||||
onStart: (modules: Module[], avoidRepeated: boolean) => void;
|
||||
disableSelection?: boolean;
|
||||
}
|
||||
|
||||
export default function Selection({user, onStart, disableSelection = false}: Props) {
|
||||
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
||||
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(true);
|
||||
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(false);
|
||||
const {stats} = useStats(user?.id);
|
||||
|
||||
const toggleModule = (module: Module) => {
|
||||
@@ -184,12 +184,13 @@ export default function Selection({user, onStart, disableSelection = false}: Pro
|
||||
</section>
|
||||
<div className="flex w-full justify-between items-center">
|
||||
<div
|
||||
className="flex gap-3 items-center text-mti-gray-dim text-sm cursor-pointer"
|
||||
className="flex gap-3 items-center text-mti-gray-dim text-sm cursor-pointer tooltip"
|
||||
data-tip="If possible, the platform will choose exams not yet done"
|
||||
onClick={() => setAvoidRepeatedExams((prev) => !prev)}>
|
||||
<input type="checkbox" className="hidden" />
|
||||
<div
|
||||
className={clsx(
|
||||
"w-6 h-6 rounded-sm flex items-center justify-center border border-mti-purple-light bg-white",
|
||||
"w-6 h-6 rounded-md flex items-center justify-center border border-mti-purple-light bg-white",
|
||||
"transition duration-300 ease-in-out",
|
||||
avoidRepeatedExams && "!bg-mti-purple-light ",
|
||||
)}>
|
||||
@@ -199,7 +200,10 @@ export default function Selection({user, onStart, disableSelection = false}: Pro
|
||||
</div>
|
||||
<Button
|
||||
onClick={() =>
|
||||
onStart(!disableSelection ? selectedModules.sort(sortByModuleName) : ["reading", "listening", "writing", "speaking"])
|
||||
onStart(
|
||||
!disableSelection ? selectedModules.sort(sortByModuleName) : ["reading", "listening", "writing", "speaking"],
|
||||
avoidRepeatedExams,
|
||||
)
|
||||
}
|
||||
color="purple"
|
||||
className="px-12 w-full max-w-xs self-end"
|
||||
|
||||
@@ -5,6 +5,8 @@ import {getFirestore, collection, getDocs, query, where} from "firebase/firestor
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {shuffle} from "lodash";
|
||||
import {Exam} from "@/interfaces/exam";
|
||||
import {Stat} from "@/interfaces/user";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
@@ -18,17 +20,28 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
const {module, avoidRepeated} = req.query as {module: string; avoidRepeated: string};
|
||||
const moduleRef = collection(db, module);
|
||||
const q = query(moduleRef, where("isDiagnostic", "==", false));
|
||||
|
||||
const q = query(moduleRef, where("isDiagnostic", "==", false));
|
||||
const snapshot = await getDocs(q);
|
||||
|
||||
res.status(200).json(
|
||||
shuffle(
|
||||
snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...doc.data(),
|
||||
module,
|
||||
})),
|
||||
),
|
||||
);
|
||||
const exams: Exam[] = shuffle(
|
||||
snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...doc.data(),
|
||||
module,
|
||||
})),
|
||||
) as Exam[];
|
||||
|
||||
if (avoidRepeated === "true") {
|
||||
const statsQ = query(collection(db, "stats"), where("user", "==", req.session.user.id));
|
||||
const statsSnapshot = await getDocs(statsQ);
|
||||
|
||||
const stats: Stat[] = statsSnapshot.docs.map((doc) => ({id: doc.id, ...doc.data()})) as unknown as Stat[];
|
||||
const filteredExams = exams.filter((x) => stats.map((s) => s.exam).includes(x.id));
|
||||
|
||||
res.status(200).json(filteredExams.length > 0 ? filteredExams : exams);
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json(exams);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ export default function Page() {
|
||||
const [exam, setExam] = useState<Exam>();
|
||||
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
||||
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
||||
const [avoidRepeated, setAvoidRepeated] = useState(false);
|
||||
|
||||
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
||||
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
|
||||
@@ -91,6 +92,7 @@ export default function Page() {
|
||||
});
|
||||
}
|
||||
})();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedModules, setExams, exams]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -113,7 +115,7 @@ export default function Page() {
|
||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||
|
||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}`);
|
||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}?avoidRepeated=${avoidRepeated}`);
|
||||
if (examRequest.status !== 200) {
|
||||
toast.error("Something went wrong!");
|
||||
return undefined;
|
||||
@@ -215,7 +217,15 @@ export default function Page() {
|
||||
|
||||
const renderScreen = () => {
|
||||
if (selectedModules.length === 0) {
|
||||
return <Selection user={user!} onStart={setSelectedModules} disableSelection />;
|
||||
return (
|
||||
<Selection
|
||||
user={user!}
|
||||
onStart={(modules, avoid) => {
|
||||
setSelectedModules(modules);
|
||||
setAvoidRepeated(avoid);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (moduleIndex >= selectedModules.length) {
|
||||
|
||||
@@ -62,6 +62,7 @@ export default function Page() {
|
||||
const [exam, setExam] = useState<Exam>();
|
||||
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
||||
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
||||
const [avoidRepeated, setAvoidRepeated] = useState(false);
|
||||
|
||||
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
||||
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
|
||||
@@ -95,6 +96,7 @@ export default function Page() {
|
||||
});
|
||||
}
|
||||
})();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedModules, setExams, exams]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -117,7 +119,7 @@ export default function Page() {
|
||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||
|
||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}`);
|
||||
const examRequest = await axios<Exam[]>(`/api/exam/${module}?avoidRepeated=${avoidRepeated}`);
|
||||
if (examRequest.status !== 200) {
|
||||
toast.error("Something went wrong!");
|
||||
return undefined;
|
||||
@@ -217,7 +219,15 @@ export default function Page() {
|
||||
|
||||
const renderScreen = () => {
|
||||
if (selectedModules.length === 0) {
|
||||
return <Selection user={user!} onStart={setSelectedModules} />;
|
||||
return (
|
||||
<Selection
|
||||
user={user!}
|
||||
onStart={(modules, avoid) => {
|
||||
setSelectedModules(modules);
|
||||
setAvoidRepeated(avoid);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (moduleIndex >= selectedModules.length) {
|
||||
|
||||
Reference in New Issue
Block a user