106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
import { useEffect, useRef } from "react";
|
||
import { enqueueSnackbar } from "notistack";
|
||
|
||
import { useQuizViewStore } from "@/stores/quizView";
|
||
import { sendQuestionAnswer } from "@/utils/sendQuestionAnswer";
|
||
|
||
type Params = {
|
||
enabled: boolean;
|
||
seconds: number;
|
||
quizId: string;
|
||
preview: boolean;
|
||
currentQuestion: any; // Using any to avoid tight coupling with question union types
|
||
onNext: () => void;
|
||
};
|
||
|
||
export function useQuestionTimer({ enabled, seconds, quizId, preview, currentQuestion, onNext }: Params) {
|
||
const ownVariants = useQuizViewStore((state) => state.ownVariants);
|
||
const currentQuizStep = useQuizViewStore((state) => state.currentQuizStep);
|
||
const timeoutRef = useRef<number | null>(null);
|
||
const isFirstQuestionRef = useRef<boolean>(true);
|
||
|
||
useEffect(() => {
|
||
console.log("🕐 useQuestionTimer useEffect triggered", {
|
||
enabled,
|
||
seconds,
|
||
quizId,
|
||
preview,
|
||
currentQuestionId: currentQuestion?.id,
|
||
currentQuestionType: currentQuestion?.type,
|
||
currentQuizStep,
|
||
hasCurrentQuestion: !!currentQuestion,
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
|
||
if (!enabled) {
|
||
console.log("❌ Timer disabled");
|
||
return;
|
||
}
|
||
if (!seconds || seconds <= 0) {
|
||
console.log("❌ Invalid seconds:", seconds);
|
||
return;
|
||
}
|
||
if (!currentQuestion) {
|
||
console.log("❌ No current question");
|
||
return;
|
||
}
|
||
if (currentQuizStep !== "question") {
|
||
console.log("❌ Not on question step:", currentQuizStep);
|
||
return;
|
||
}
|
||
if (currentQuestion.type === "result") {
|
||
console.log("❌ Question is result type");
|
||
return;
|
||
}
|
||
|
||
console.log("✅ Starting timer for", seconds, "seconds");
|
||
|
||
// Сбрасываем предыдущий таймер
|
||
if (timeoutRef.current) {
|
||
console.log("🔄 Clearing previous timer");
|
||
clearTimeout(timeoutRef.current);
|
||
timeoutRef.current = null;
|
||
}
|
||
|
||
// Для первого вопроса добавляем дополнительную задержку, чтобы избежать конфликтов с навигацией
|
||
const isFirstQuestion = isFirstQuestionRef.current;
|
||
const startDelay = isFirstQuestion ? 2000 : 100; // 2 секунды для первого вопроса, 100ms для остальных
|
||
|
||
if (isFirstQuestion) {
|
||
console.log("🔄 First question detected, adding 2s delay to prevent navigation conflicts");
|
||
isFirstQuestionRef.current = false;
|
||
}
|
||
|
||
timeoutRef.current = window.setTimeout(
|
||
async () => {
|
||
console.log("⏰ Timer expired! Auto-advancing to next question");
|
||
try {
|
||
if (!preview) {
|
||
console.log("📤 Sending empty answer for question:", currentQuestion.id);
|
||
// Отправляем пустую строку в ответе (questionAnswer === undefined)
|
||
await sendQuestionAnswer(quizId, currentQuestion, undefined, ownVariants);
|
||
console.log("✅ Empty answer sent successfully");
|
||
} else {
|
||
console.log("👀 Preview mode - skipping answer send");
|
||
}
|
||
} catch (e) {
|
||
console.error("❌ Error sending empty timed answer", e);
|
||
enqueueSnackbar("Ошибка при отправке ответа по таймеру");
|
||
} finally {
|
||
console.log("➡️ Calling onNext()");
|
||
onNext();
|
||
}
|
||
},
|
||
seconds * 1000 + startDelay
|
||
);
|
||
|
||
return () => {
|
||
console.log("🧹 Cleaning up timer");
|
||
if (timeoutRef.current) {
|
||
clearTimeout(timeoutRef.current);
|
||
timeoutRef.current = null;
|
||
}
|
||
};
|
||
}, [enabled, seconds, quizId, preview, currentQuestion?.id, currentQuizStep, onNext]);
|
||
}
|