// islands/Quizzing.tsx import { useCallback, useEffect, useRef, useState } from "preact/hooks"; //import { QuizData } from "../utils/database.ts"; import { QuizConfig } from "../utils/types.ts"; import { Signal, signal } from "@preact/signals"; import Card from "./Card.tsx"; import { stringify } from "node:querystring"; interface QuizzingIProps { initialQuizData: QuizConfig; runData: string; } export const STORAGE_KEY = "QUIZ_STATE"; const useAudio1 = signal(true); const useAudio2 = signal(true); const useInputHint = signal(false); export default function Quizzing({ initialQuizData, runData }: QuizzingIProps) { const hideText = initialQuizData && (initialQuizData.quiz_mode === "photo-hide-english" || initialQuizData.quiz_mode === "photo-hide-bisaya"); const [quizData, setQuizData] = useState(initialQuizData); const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); const [questionText, setQuextionText] = useState( quizData ? quizData.questions[0].text_1 : "", ); const [meaningText, setMeaningText] = useState(""); const [backgroundUrl, setCurrentBackgroundUrl] = useState(""); const [quizCompleted, setQuizCompleted] = useState(false); const [runFullAuto, setRunFullAuto] = useState(false); const [isPausedDisplay, setIsPausedDisplay] = useState(false); const togglePauseRef = useRef<() => void>(() => {}); const [countdown, setCountdown] = useState(3); const postButtonRef = useRef(null); const [count, setCount] = useState(0); const [cardKey, setCardKey] = useState(0); const runFullAutoRef = useRef(runFullAuto); const meaningTextRef = useRef(meaningText); const quizDataRef = useRef(quizData); useEffect(() => { runFullAutoRef.current = runFullAuto; }, [runFullAuto]); useEffect(() => { meaningTextRef.current = meaningText; }, [meaningText]); useEffect(() => { quizDataRef.current = quizData; }, [quizData]); const [cardInputParams, seCardInputParams] = useState({ setFullAuto: setRunFullAuto, runFullAuto: false, setTogglePause: (fn: () => void) => { togglePauseRef.current = fn; }, setIsPausedDisplay: setIsPausedDisplay, questionPhrase: quizData ? quizData.questions[0].text_1 : "", answerPhrase: "", nextButton: () => {}, audio1: "", audio2: "", onHelpUsed: () => {}, flipped: false, }); const handleClick = () => { setCount((prev) => { const newCount = prev + 1; //eventEmitter.emit("countUpdated", newCount); return newCount; }); }; // Ref to track current index synchronously (state updates are async) const currentIndexRef = useRef(0); const incTheIndex = (auto: boolean): number => { let nextIndex = currentIndexRef.current + 1; if (auto && nextIndex >= initialQuizData.questions.length) { nextIndex = 0; } currentIndexRef.current = nextIndex; setCurrentQuestionIndex(nextIndex); return nextIndex; }; useEffect(() => { if (quizCompleted && countdown > 0) { const timer = setTimeout(() => { setCountdown(countdown - 1); }, 1000); return () => clearTimeout(timer); } else if (quizCompleted && countdown === 0) { if (postButtonRef.current) { //console.log(runData); postButtonRef.current.click(); } //wind ow.location.href = "/language/dashboard"; } }, [quizCompleted, countdown]); const handleNextQuestionInternal = useCallback((forceAuto?: boolean) => { if (forceAuto === true && !runFullAutoRef.current) { runFullAutoRef.current = true; setRunFullAuto(true); } const thisAuto = typeof forceAuto === "boolean" ? forceAuto : runFullAutoRef.current; const quizDataNow = quizDataRef.current; const meaningTextNow = meaningTextRef.current; // Determine the next index synchronously // On first call (meaningText === ""), stay at index 0 // On subsequent calls, increment const isFirstCall = meaningTextNow === ""; const thisIndex = isFirstCall ? 0 : incTheIndex(thisAuto); if (thisIndex < quizDataNow.questions.length) { // Get ALL data from the SAME question object const thisQuestion = quizDataNow.questions[thisIndex]; const text_1 = thisQuestion.text_1; const text_2 = thisQuestion.text_2; const audio1 = useAudio1.value ? thisQuestion.audio_file_1 : ""; const audio2 = useAudio2.value ? thisQuestion.audio_file_2 : ""; const thisDataUrl = thisQuestion.background_image_data || ""; // Update all state together setQuextionText(text_1); setMeaningText(text_2); meaningTextRef.current = text_2; setCurrentBackgroundUrl(thisDataUrl); const cardParams = { setFullAuto: setRunFullAuto, runFullAuto: thisAuto, setTogglePause: (fn: () => void) => { togglePauseRef.current = fn; }, setIsPausedDisplay: setIsPausedDisplay, questionPhrase: text_1, answerPhrase: text_2, nextButton: handleNextQuestion, audio1: audio1, audio2: audio2, onHelpUsed: () => {}, flipped: initialQuizData.quiz_mode === "photo-hide-english" || initialQuizData.quiz_mode === "photo-see-english" || initialQuizData.quiz_mode === "blank-see-english", }; seCardInputParams(cardParams); setCardKey((prev) => prev + 1); // Force Card remount handleClick(); } else { //localStorage.removeItem("QUIZ_STATE"); setQuizCompleted(true); } }, [initialQuizData]); const handleNextQuestion = useCallback(() => { handleNextQuestionInternal(); }, [handleNextQuestionInternal]); if (!initialQuizData || !runData) { return
Unable to load quiz
; } if (!quizData) { return
Loading...
; } if (quizCompleted) { return (

Quiz Completed!

{countdown}

Redirecting ...

); } //const currentQuestion = quizData.questions[currentQuestionIndex]; //if (quizStarted){ return (
{meaningText !== "" ? ( ) : (

Ready to start quiz

Questions: {quizData.questions.length}

)} {meaningText === "" ? (
Keyboard: shift + return = help
) : runFullAuto ? ( ) : ( )}
); // } // else{ // return ( //
// //
// ); // } // Placeholder function for fetching quiz data // async function fetchQuizData(quiz_id: number): Promise<{}> { // // Implement the actual data fetching logic here // // This is just a placeholder // return { quiz_id: quiz_id, questions: [] }; // } }