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 {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
onStart: (modules: Module[]) => void;
|
onStart: (modules: Module[], avoidRepeated: boolean) => void;
|
||||||
disableSelection?: boolean;
|
disableSelection?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Selection({user, onStart, disableSelection = false}: Props) {
|
export default function Selection({user, onStart, disableSelection = false}: Props) {
|
||||||
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
||||||
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(true);
|
const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(false);
|
||||||
const {stats} = useStats(user?.id);
|
const {stats} = useStats(user?.id);
|
||||||
|
|
||||||
const toggleModule = (module: Module) => {
|
const toggleModule = (module: Module) => {
|
||||||
@@ -184,12 +184,13 @@ export default function Selection({user, onStart, disableSelection = false}: Pro
|
|||||||
</section>
|
</section>
|
||||||
<div className="flex w-full justify-between items-center">
|
<div className="flex w-full justify-between items-center">
|
||||||
<div
|
<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)}>
|
onClick={() => setAvoidRepeatedExams((prev) => !prev)}>
|
||||||
<input type="checkbox" className="hidden" />
|
<input type="checkbox" className="hidden" />
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
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",
|
"transition duration-300 ease-in-out",
|
||||||
avoidRepeatedExams && "!bg-mti-purple-light ",
|
avoidRepeatedExams && "!bg-mti-purple-light ",
|
||||||
)}>
|
)}>
|
||||||
@@ -199,7 +200,10 @@ export default function Selection({user, onStart, disableSelection = false}: Pro
|
|||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onStart(!disableSelection ? selectedModules.sort(sortByModuleName) : ["reading", "listening", "writing", "speaking"])
|
onStart(
|
||||||
|
!disableSelection ? selectedModules.sort(sortByModuleName) : ["reading", "listening", "writing", "speaking"],
|
||||||
|
avoidRepeatedExams,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
color="purple"
|
color="purple"
|
||||||
className="px-12 w-full max-w-xs self-end"
|
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 {withIronSessionApiRoute} from "iron-session/next";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import {sessionOptions} from "@/lib/session";
|
||||||
import {shuffle} from "lodash";
|
import {shuffle} from "lodash";
|
||||||
|
import {Exam} from "@/interfaces/exam";
|
||||||
|
import {Stat} from "@/interfaces/user";
|
||||||
|
|
||||||
const db = getFirestore(app);
|
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 {module, avoidRepeated} = req.query as {module: string; avoidRepeated: string};
|
||||||
const moduleRef = collection(db, module);
|
const moduleRef = collection(db, module);
|
||||||
const q = query(moduleRef, where("isDiagnostic", "==", false));
|
|
||||||
|
|
||||||
|
const q = query(moduleRef, where("isDiagnostic", "==", false));
|
||||||
const snapshot = await getDocs(q);
|
const snapshot = await getDocs(q);
|
||||||
|
|
||||||
res.status(200).json(
|
const exams: Exam[] = shuffle(
|
||||||
shuffle(
|
snapshot.docs.map((doc) => ({
|
||||||
snapshot.docs.map((doc) => ({
|
id: doc.id,
|
||||||
id: doc.id,
|
...doc.data(),
|
||||||
...doc.data(),
|
module,
|
||||||
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 [exam, setExam] = useState<Exam>();
|
||||||
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
||||||
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
||||||
|
const [avoidRepeated, setAvoidRepeated] = useState(false);
|
||||||
|
|
||||||
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
||||||
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
|
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]);
|
}, [selectedModules, setExams, exams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -113,7 +115,7 @@ export default function Page() {
|
|||||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||||
|
|
||||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
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) {
|
if (examRequest.status !== 200) {
|
||||||
toast.error("Something went wrong!");
|
toast.error("Something went wrong!");
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -215,7 +217,15 @@ export default function Page() {
|
|||||||
|
|
||||||
const renderScreen = () => {
|
const renderScreen = () => {
|
||||||
if (selectedModules.length === 0) {
|
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) {
|
if (moduleIndex >= selectedModules.length) {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export default function Page() {
|
|||||||
const [exam, setExam] = useState<Exam>();
|
const [exam, setExam] = useState<Exam>();
|
||||||
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
const [isEvaluationLoading, setIsEvaluationLoading] = useState(false);
|
||||||
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
const [showAbandonPopup, setShowAbandonPopup] = useState(false);
|
||||||
|
const [avoidRepeated, setAvoidRepeated] = useState(false);
|
||||||
|
|
||||||
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]);
|
||||||
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
|
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]);
|
}, [selectedModules, setExams, exams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -117,7 +119,7 @@ export default function Page() {
|
|||||||
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
}, [selectedModules, moduleIndex, hasBeenUploaded]);
|
||||||
|
|
||||||
const getExam = async (module: Module): Promise<Exam | undefined> => {
|
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) {
|
if (examRequest.status !== 200) {
|
||||||
toast.error("Something went wrong!");
|
toast.error("Something went wrong!");
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -217,7 +219,15 @@ export default function Page() {
|
|||||||
|
|
||||||
const renderScreen = () => {
|
const renderScreen = () => {
|
||||||
if (selectedModules.length === 0) {
|
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) {
|
if (moduleIndex >= selectedModules.length) {
|
||||||
|
|||||||
Reference in New Issue
Block a user