import { useEffect, useRef, useState } from 'react'; import { QuestionsProgress } from './QuestionsProgress'; import { CheckCircle, SkipForward, Sparkles } from 'lucide-react'; import { QuestionCard } from './QuestionCard'; import { QuestionLoader } from './QuestionLoader'; import { isLoggedIn } from '../../lib/jwt'; import type { QuestionType } from '../../lib/question-group'; import { Confetti } from '../Confetti'; import { httpGet, httpPut } from '../../lib/http'; import { useToast } from '../../hooks/use-toast'; type UserQuestionProgress = { know: string[]; didNotKnow: string[]; }; type QuestionsListProps = { groupId: string; questions: QuestionType[]; }; export function QuestionsList(props: QuestionsListProps) { const { questions: defaultQuestions, groupId } = props; const toast = useToast(); const [isLoading, setIsLoading] = useState(true); const [isUpdatingStatus, setIsUpdatingStatus] = useState(false); const [confettiEl, setConfettiEl] = useState(null); const [questions, setQuestions] = useState(); const [pendingQuestions, setPendingQuestions] = useState([]); const [userProgress, setUserProgress] = useState(); const alreadyKnowRef = useRef(null); const didNotKnowRef = useRef(null); function showConfetti(el: HTMLElement | null) { // If confetti is already showing, remove that first if (confettiEl) { setConfettiEl(null); } window.setTimeout(() => { setConfettiEl(el); }, 0); } async function fetchUserProgress(): Promise< UserQuestionProgress | undefined > { if (!isLoggedIn()) { return; } const { response, error } = await httpGet( `/v1-get-user-question-progress/${groupId}` ); if (error) { toast.error(error.message || 'Error fetching user progress'); return; } return response; } async function loadQuestions() { const userProgress = await fetchUserProgress(); setUserProgress(userProgress); const knownQuestions = userProgress?.know || []; const didNotKnowQuestions = userProgress?.didNotKnow || []; const pendingQuestions = defaultQuestions.filter((question) => { return ( !knownQuestions.includes(question.id) && !didNotKnowQuestions.includes(question.id) ); }); // Shuffle and set pending questions setPendingQuestions(pendingQuestions.sort(() => Math.random() - 0.5)); setQuestions(defaultQuestions); setIsLoading(false); } async function updateQuestionStatus( status: 'know' | 'dontKnow', questionId: string ) { setIsUpdatingStatus(true); let newProgress = userProgress || { know: [], didNotKnow: [] }; if (!isLoggedIn()) { if (status === 'know') { newProgress.know.push(questionId); } else { newProgress.didNotKnow.push(questionId); } } else { const { response, error } = await httpPut( `/v1-update-question-status/${groupId}`, { status, questionId, questionGroupId: groupId, } ); if (error || !response) { toast.error(error?.message || 'Error marking question status'); return; } newProgress = response; } setUserProgress(newProgress); setPendingQuestions(pendingQuestions.filter((q) => q.id !== questionId)); setIsUpdatingStatus(false); } useEffect(() => { loadQuestions().then(() => null); }, [defaultQuestions]); const knownCount = userProgress?.know.length || 0; const didNotKnowCount = userProgress?.didNotKnow.length || 0; const hasProgress = knownCount > 0 || didNotKnowCount > 0; const currQuestion = pendingQuestions[0]; return (
{ setConfettiEl(null); }} />
{!isLoading && } {isLoading && }
); }