115 lines
3.3 KiB
TypeScript
115 lines
3.3 KiB
TypeScript
import { UserSolution } from "@/interfaces/exam";
|
|
import useExamStore from "@/stores/exam";
|
|
import axios from "axios";
|
|
import { useEffect, useRef } from "react";
|
|
import { useRouter } from "next/router";
|
|
|
|
const useEvaluationPolling = (sessionIds: string[], mode: "exam" | "records", userId: string) => {
|
|
const { setUserSolutions, userSolutions } = useExamStore();
|
|
const pollingTimeoutsRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
|
|
const router = useRouter();
|
|
|
|
const poll = async (sessionId: string) => {
|
|
try {
|
|
const { data: statusData } = await axios.get('/api/evaluate/status', {
|
|
params: { op: 'pending', userId, sessionId }
|
|
});
|
|
|
|
if (!statusData.hasPendingEvaluation) {
|
|
|
|
let solutionsOrStats = userSolutions;
|
|
|
|
if (mode === "records") {
|
|
const res = await axios.get(`/api/stats/session/${sessionId}`)
|
|
solutionsOrStats = res.data;
|
|
}
|
|
const { data: completedSolutions } = await axios.post('/api/evaluate/fetchSolutions?op=session', {
|
|
sessionId,
|
|
userId,
|
|
stats: solutionsOrStats,
|
|
});
|
|
|
|
await axios.post('/api/stats/disabled', {
|
|
sessionId,
|
|
userId,
|
|
solutions: completedSolutions,
|
|
});
|
|
|
|
const timeout = pollingTimeoutsRef.current.get(sessionId);
|
|
if (timeout) clearTimeout(timeout);
|
|
pollingTimeoutsRef.current.delete(sessionId);
|
|
|
|
if (mode === "exam") {
|
|
const updatedSolutions = userSolutions.map(solution => {
|
|
const completed = completedSolutions.find(
|
|
(c: UserSolution) => c.exercise === solution.exercise
|
|
);
|
|
return completed || solution;
|
|
});
|
|
|
|
setUserSolutions(updatedSolutions);
|
|
} else {
|
|
router.reload();
|
|
}
|
|
} else {
|
|
if (pollingTimeoutsRef.current.has(sessionId)) {
|
|
clearTimeout(pollingTimeoutsRef.current.get(sessionId));
|
|
}
|
|
pollingTimeoutsRef.current.set(
|
|
sessionId,
|
|
setTimeout(() => poll(sessionId), 5000)
|
|
);
|
|
}
|
|
} catch (error) {
|
|
if (pollingTimeoutsRef.current.has(sessionId)) {
|
|
clearTimeout(pollingTimeoutsRef.current.get(sessionId));
|
|
}
|
|
pollingTimeoutsRef.current.set(
|
|
sessionId,
|
|
setTimeout(() => poll(sessionId), 5000)
|
|
);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (mode === "exam") {
|
|
const hasDisabledSolutions = userSolutions.some(s => s.isDisabled);
|
|
|
|
if (hasDisabledSolutions && sessionIds.length > 0) {
|
|
poll(sessionIds[0]);
|
|
} else {
|
|
pollingTimeoutsRef.current.forEach((timeout) => {
|
|
clearTimeout(timeout);
|
|
});
|
|
pollingTimeoutsRef.current.clear();
|
|
}
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [mode, sessionIds, userSolutions]);
|
|
|
|
useEffect(() => {
|
|
if (mode === "records" && sessionIds.length > 0) {
|
|
sessionIds.forEach(sessionId => {
|
|
poll(sessionId);
|
|
});
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [mode, sessionIds]);
|
|
|
|
useEffect(() => {
|
|
const timeouts = pollingTimeoutsRef.current;
|
|
return () => {
|
|
timeouts.forEach((timeout) => {
|
|
clearTimeout(timeout);
|
|
});
|
|
timeouts.clear();
|
|
};
|
|
}, []);
|
|
|
|
return {
|
|
isPolling: pollingTimeoutsRef.current.size > 0
|
|
};
|
|
};
|
|
|
|
export default useEvaluationPolling;
|