ENCOA-315
This commit is contained in:
@@ -1,95 +1,114 @@
|
||||
import { UserSolution } from '@/interfaces/exam';
|
||||
import useExamStore from '@/stores/exam';
|
||||
import { StateFlags } from '@/stores/exam/types';
|
||||
import axios from 'axios';
|
||||
import { SetStateAction, useEffect, useRef } from 'react';
|
||||
import { UserSolution } from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/exam";
|
||||
import axios from "axios";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
type UseEvaluationPolling = (props: {
|
||||
pendingExercises: string[],
|
||||
setPendingExercises: React.Dispatch<SetStateAction<string[]>>,
|
||||
}) => void;
|
||||
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 useEvaluationPolling: UseEvaluationPolling = ({
|
||||
pendingExercises,
|
||||
setPendingExercises,
|
||||
}) => {
|
||||
const {
|
||||
flags, sessionId, user,
|
||||
userSolutions, evaluated,
|
||||
setEvaluated, setFlags
|
||||
} = useExamStore();
|
||||
const poll = async (sessionId: string) => {
|
||||
try {
|
||||
const { data: statusData } = await axios.get('/api/evaluate/status', {
|
||||
params: { op: 'pending', userId, sessionId }
|
||||
});
|
||||
|
||||
const pollingTimeoutRef = useRef<NodeJS.Timeout>();
|
||||
if (!statusData.hasPendingEvaluation) {
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (pollingTimeoutRef.current) {
|
||||
clearTimeout(pollingTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
let solutionsOrStats = userSolutions;
|
||||
|
||||
useEffect(() => {
|
||||
if (!flags.pendingEvaluation || pendingExercises.length === 0) {
|
||||
|
||||
if (pollingTimeoutRef.current) {
|
||||
clearTimeout(pollingTimeoutRef.current);
|
||||
}
|
||||
return;
|
||||
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,
|
||||
});
|
||||
|
||||
const pollStatus = async () => {
|
||||
try {
|
||||
const { data } = await axios.get('/api/evaluate/status', {
|
||||
params: {
|
||||
sessionId,
|
||||
userId: user,
|
||||
exerciseIds: pendingExercises.join(',')
|
||||
}
|
||||
});
|
||||
await axios.post('/api/stats/disabled', {
|
||||
sessionId,
|
||||
userId,
|
||||
solutions: completedSolutions,
|
||||
});
|
||||
|
||||
if (data.finishedExerciseIds.length > 0) {
|
||||
const remainingExercises = pendingExercises.filter(
|
||||
id => !data.finishedExerciseIds.includes(id)
|
||||
);
|
||||
const timeout = pollingTimeoutsRef.current.get(sessionId);
|
||||
if (timeout) clearTimeout(timeout);
|
||||
pollingTimeoutsRef.current.delete(sessionId);
|
||||
|
||||
setPendingExercises(remainingExercises);
|
||||
if (mode === "exam") {
|
||||
const updatedSolutions = userSolutions.map(solution => {
|
||||
const completed = completedSolutions.find(
|
||||
(c: UserSolution) => c.exercise === solution.exercise
|
||||
);
|
||||
return completed || solution;
|
||||
});
|
||||
|
||||
if (remainingExercises.length === 0) {
|
||||
const evaluatedData = await axios.post('/api/evaluate/fetchSolutions', {
|
||||
sessionId,
|
||||
userId: user,
|
||||
userSolutions
|
||||
});
|
||||
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)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const newEvaluations = evaluatedData.data.filter(
|
||||
(newEval: UserSolution) =>
|
||||
!evaluated.some(existingEval => existingEval.exercise === newEval.exercise)
|
||||
);
|
||||
useEffect(() => {
|
||||
if (mode === "exam") {
|
||||
const hasDisabledSolutions = userSolutions.some(s => s.isDisabled);
|
||||
|
||||
setEvaluated([...evaluated, ...newEvaluations]);
|
||||
setFlags({ pendingEvaluation: false });
|
||||
return;
|
||||
}
|
||||
}
|
||||
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]);
|
||||
|
||||
if (pendingExercises.length > 0) {
|
||||
pollingTimeoutRef.current = setTimeout(pollStatus, 5000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Evaluation polling error:', error);
|
||||
pollingTimeoutRef.current = setTimeout(pollStatus, 5000);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (mode === "records" && sessionIds.length > 0) {
|
||||
sessionIds.forEach(sessionId => {
|
||||
poll(sessionId);
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [mode, sessionIds]);
|
||||
|
||||
pollStatus();
|
||||
useEffect(() => {
|
||||
const timeouts = pollingTimeoutsRef.current;
|
||||
return () => {
|
||||
timeouts.forEach((timeout) => {
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
timeouts.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return () => {
|
||||
if (pollingTimeoutRef.current) {
|
||||
clearTimeout(pollingTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
});
|
||||
return {
|
||||
isPolling: pollingTimeoutsRef.current.size > 0
|
||||
};
|
||||
};
|
||||
|
||||
export default useEvaluationPolling;
|
||||
|
||||
Reference in New Issue
Block a user