diff --git a/src/components/AIQuiz/AIQuizContent.tsx b/src/components/AIQuiz/AIQuizContent.tsx index 30c00f029..2fff2825a 100644 --- a/src/components/AIQuiz/AIQuizContent.tsx +++ b/src/components/AIQuiz/AIQuizContent.tsx @@ -23,6 +23,8 @@ const DEFAULT_QUESTION_STATE: QuestionState = { status: 'pending', }; +type QuizStatus = 'answering' | 'submitted' | 'reviewing'; + type AIQuizContentProps = { quizSlug?: string; questions: QuizQuestion[]; @@ -38,7 +40,7 @@ export function AIQuizContent(props: AIQuizContentProps) { const [questionStates, setQuestionStates] = useState< Record >({}); - const [isAllQuestionsSubmitted, setIsAllQuestionsSubmitted] = useState(false); + const [quizStatus, setQuizStatus] = useState('answering'); const activeQuestionState = questionStates[activeQuestionIndex] ?? DEFAULT_QUESTION_STATE; @@ -59,7 +61,9 @@ export function AIQuizContent(props: AIQuizContentProps) { return newSelectedOptions; }); - setIsAllQuestionsSubmitted(activeQuestionIndex === questions.length - 1); + setQuizStatus( + activeQuestionIndex === questions.length - 1 ? 'submitted' : 'answering', + ); }; const handleSetUserAnswer = (userAnswer: string) => { @@ -112,34 +116,54 @@ export function AIQuizContent(props: AIQuizContentProps) { }); }; - const handleNext = () => { - setActiveQuestionIndex(activeQuestionIndex + 1); - }; - const handleRetry = () => { setActiveQuestionIndex(0); setQuestionStates({}); - setIsAllQuestionsSubmitted(false); + setQuizStatus('answering'); }; + const hasNextQuestion = activeQuestionIndex < questions.length - 1; + const hasPreviousQuestion = activeQuestionIndex > 0; const totalQuestions = questions?.length ?? 0; + const isAllQuestionsSubmitted = + Object.values(questionStates).filter((state) => state.status !== 'pending') + .length === totalQuestions; + const progressPercentage = isLoading ? 0 : getPercentage(activeQuestionIndex + 1, totalQuestions); + const shouldShowQuestions = + quizStatus === 'answering' || quizStatus === 'reviewing'; + + const handleNextQuestion = () => { + if (!hasNextQuestion) { + setQuizStatus(isAllQuestionsSubmitted ? 'submitted' : 'reviewing'); + return; + } + + setActiveQuestionIndex(activeQuestionIndex + 1); + }; + return (
- {!isAllQuestionsSubmitted && ( + {shouldShowQuestions && ( setActiveQuestionIndex(activeQuestionIndex - 1)} - onNext={() => setActiveQuestionIndex(activeQuestionIndex + 1)} + onPrevious={() => { + if (!hasPreviousQuestion) { + return; + } + + setActiveQuestionIndex(activeQuestionIndex - 1); + }} + onNext={handleNextQuestion} /> )} - {isAllQuestionsSubmitted && ( + {quizStatus === 'submitted' && ( { window.location.href = '/ai/quiz'; }} + onReview={(questionIndex) => { + setActiveQuestionIndex(questionIndex); + setQuizStatus('reviewing'); + }} /> )} - {!isAllQuestionsSubmitted && ( + {shouldShowQuestions && ( <> {activeQuestion && activeQuestion.type === 'mcq' && ( )} @@ -168,7 +196,7 @@ export function AIQuizContent(props: AIQuizContentProps) { question={activeQuestion} questionState={activeQuestionState} onSubmit={handleSubmit} - onNext={handleNext} + onNext={handleNextQuestion} setUserAnswer={handleSetUserAnswer} setCorrectAnswer={handleSetCorrectAnswer} /> diff --git a/src/components/AIQuiz/AIQuizGenerator.tsx b/src/components/AIQuiz/AIQuizGenerator.tsx index bd613bd0c..aad27a16f 100644 --- a/src/components/AIQuiz/AIQuizGenerator.tsx +++ b/src/components/AIQuiz/AIQuizGenerator.tsx @@ -218,9 +218,7 @@ export function AIQuizGenerator() { format={selectedFormatTitle || selectedFormat} questionAnswerChatMessages={questionAnswerChatMessages} setQuestionAnswerChatMessages={setQuestionAnswerChatMessages} - onGenerateNow={() => { - handleSubmit(); - }} + from="quiz" /> )} diff --git a/src/components/AIQuiz/AIQuizResults.tsx b/src/components/AIQuiz/AIQuizResults.tsx index dca072113..d16e3c474 100644 --- a/src/components/AIQuiz/AIQuizResults.tsx +++ b/src/components/AIQuiz/AIQuizResults.tsx @@ -22,10 +22,12 @@ type AIQuizResultsProps = { totalQuestions: number; onRetry: () => void; onNewQuiz: () => void; + onReview?: (questionIndex: number) => void; }; export function AIQuizResults(props: AIQuizResultsProps) { - const { questionStates, totalQuestions, onRetry, onNewQuiz } = props; + const { questionStates, totalQuestions, onRetry, onNewQuiz, onReview } = + props; const states = Object.values(questionStates); const correctCount = states.filter( @@ -66,10 +68,11 @@ export function AIQuizResults(props: AIQuizResultsProps) { const isSkipped = status === 'skipped'; return ( -
onReview?.(quizIndex)} className={cn( - 'flex aspect-square flex-col items-center justify-center rounded-xl border border-gray-200 p-2', + 'flex aspect-square flex-col items-center justify-center rounded-xl border border-gray-200 p-2 hover:opacity-80', isCorrect && 'bg-green-700 text-white', isIncorrect && 'bg-red-700 text-white', isSkipped && 'bg-gray-700 text-white', @@ -78,7 +81,7 @@ export function AIQuizResults(props: AIQuizResultsProps) { {isCorrect && } {isIncorrect && } {isSkipped && } -
+ ); })}
diff --git a/src/components/ContentGenerator/ContentGenerator.tsx b/src/components/ContentGenerator/ContentGenerator.tsx index 1abde5c5e..10dbbda30 100644 --- a/src/components/ContentGenerator/ContentGenerator.tsx +++ b/src/components/ContentGenerator/ContentGenerator.tsx @@ -227,9 +227,6 @@ export function ContentGenerator() { format={selectedFormat} questionAnswerChatMessages={questionAnswerChatMessages} setQuestionAnswerChatMessages={setQuestionAnswerChatMessages} - onGenerateNow={() => { - handleSubmit(); - }} /> )} diff --git a/src/components/ContentGenerator/QuestionAnswerChat.tsx b/src/components/ContentGenerator/QuestionAnswerChat.tsx index 134b0bde7..840699497 100644 --- a/src/components/ContentGenerator/QuestionAnswerChat.tsx +++ b/src/components/ContentGenerator/QuestionAnswerChat.tsx @@ -27,9 +27,11 @@ type QuestionAnswerChatProps = { setQuestionAnswerChatMessages: ( messages: QuestionAnswerChatMessage[], ) => void; - onGenerateNow: () => void; defaultQuestions?: AIQuestionSuggestionsResponse['questions']; type?: 'create' | 'update'; + + from?: 'content' | 'quiz'; + className?: string; }; @@ -40,9 +42,9 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) { defaultQuestions, questionAnswerChatMessages, setQuestionAnswerChatMessages, - onGenerateNow, type = 'create', className = '', + from = 'content', } = props; const [activeMessageIndex, setActiveMessageIndex] = useState( @@ -58,7 +60,7 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) { data: aiQuestionSuggestions, isLoading: isLoadingAiQuestionSuggestions, } = useQuery( - aiQuestionSuggestionsOptions({ term, format }, defaultQuestions), + aiQuestionSuggestionsOptions({ term, format, from }, defaultQuestions), queryClient, ); @@ -113,11 +115,6 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) { scrollToBottom(); }; - const canGenerateNow = - // user can generate after answering 5 questions -> 5 * 2 messages (user and assistant) - !isLoadingAiQuestionSuggestions && questionAnswerChatMessages.length >= 10; - - const canReset = questionAnswerChatMessages.length >= 2; const handleReset = () => { setQuestionAnswerChatMessages([]); setActiveMessageIndex(0); diff --git a/src/queries/user-ai-session.ts b/src/queries/user-ai-session.ts index 0164d16fc..aa4966872 100644 --- a/src/queries/user-ai-session.ts +++ b/src/queries/user-ai-session.ts @@ -4,6 +4,7 @@ import { httpGet } from '../lib/query-http'; type AIQuestionSuggestionsQuery = { term: string; format: string; + from?: 'content' | 'quiz'; }; export type AIQuestionSuggestionsResponse = { @@ -31,7 +32,7 @@ export function aiQuestionSuggestionsOptions( query, ); }, - enabled: !!query.term && !!query.format, + enabled: !!query.term && !!query.format && !!query.from, refetchOnMount: false, }); }