frontAnswerer/lib/utils/hooks/FlowControlLogic/useQuestionTimer.ts

106 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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]);
}