From 399ce726501dba32e18d75ed0f8357e77b5c4476 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Tue, 1 Jul 2025 04:58:59 +0600 Subject: [PATCH] wip --- src/components/AIQuiz/AIQuiz.tsx | 12 + src/components/AIQuiz/AIQuizGenerator.tsx | 227 ++++++++++++++++++ .../ContentGenerator/ContentGenerator.tsx | 2 +- src/pages/ai/quiz/index.astro | 15 ++ 4 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 src/components/AIQuiz/AIQuiz.tsx create mode 100644 src/components/AIQuiz/AIQuizGenerator.tsx create mode 100644 src/pages/ai/quiz/index.astro diff --git a/src/components/AIQuiz/AIQuiz.tsx b/src/components/AIQuiz/AIQuiz.tsx new file mode 100644 index 000000000..c137cc8ff --- /dev/null +++ b/src/components/AIQuiz/AIQuiz.tsx @@ -0,0 +1,12 @@ +import { AITutorLayout } from '../AITutor/AITutorLayout'; + +export function AIQuiz() { + return ( + +

AI Quiz

+
+ ); +} diff --git a/src/components/AIQuiz/AIQuizGenerator.tsx b/src/components/AIQuiz/AIQuizGenerator.tsx new file mode 100644 index 000000000..de87ab051 --- /dev/null +++ b/src/components/AIQuiz/AIQuizGenerator.tsx @@ -0,0 +1,227 @@ +import { + BookOpenIcon, + FileTextIcon, + ListCheckIcon, + ListTodoIcon, + MapIcon, + SparklesIcon, + type LucideIcon, +} from 'lucide-react'; +import { useEffect, useId, useState } from 'react'; +import { isLoggedIn } from '../../lib/jwt'; +import { showLoginPopup } from '../../lib/popup'; +import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal'; +import { useIsPaidUser } from '../../queries/billing'; +import { + clearQuestionAnswerChatMessages, + storeQuestionAnswerChatMessages, +} from '../../lib/ai-questions'; +import { + QuestionAnswerChat, + type QuestionAnswerChatMessage, +} from '../ContentGenerator/QuestionAnswerChat'; +import { useToast } from '../../hooks/use-toast'; +import { cn } from '../../lib/classname'; +import { getUrlParams } from '../../lib/browser'; +import { useParams } from '../../hooks/use-params'; +import { FormatItem } from '../ContentGenerator/FormatItem'; + +const allowedFormats = ['mcq', 'open-ended', 'mixed'] as const; +export type AllowedFormat = (typeof allowedFormats)[number]; + +export function AIQuizGenerator() { + const [isUpgradeModalOpen, setIsUpgradeModalOpen] = useState(false); + const { isPaidUser, isLoading: isPaidUserLoading } = useIsPaidUser(); + + const toast = useToast(); + const [title, setTitle] = useState(''); + const [selectedFormat, setSelectedFormat] = useState('mcq'); + + // question answer chat options + const [showFineTuneOptions, setShowFineTuneOptions] = useState(false); + const [questionAnswerChatMessages, setQuestionAnswerChatMessages] = useState< + QuestionAnswerChatMessage[] + >([]); + + const titleFieldId = useId(); + const fineTuneOptionsId = useId(); + + useEffect(() => { + const params = getUrlParams(); + const format = params.format as AllowedFormat; + if (format && allowedFormats.find((f) => f.value === format)) { + setSelectedFormat(format); + } + }, []); + + const allowedFormats: { + label: string; + icon: LucideIcon; + value: AllowedFormat; + }[] = [ + { + label: 'MCQ', + icon: ListTodoIcon, + value: 'mcq', + }, + { + label: 'Open-Ended', + icon: FileTextIcon, + value: 'open-ended', + }, + { + label: 'Mixed', + icon: MapIcon, + value: 'mixed', + }, + ]; + + const handleSubmit = () => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + let sessionId = ''; + if (showFineTuneOptions) { + clearQuestionAnswerChatMessages(); + sessionId = storeQuestionAnswerChatMessages(questionAnswerChatMessages); + } + }; + + useEffect(() => { + window?.fireEvent({ + action: 'tutor_user', + category: 'ai_tutor', + label: 'Visited AI Quiz Generator Page', + }); + }, []); + + const trimmedTitle = title.trim(); + const canGenerate = trimmedTitle && trimmedTitle.length >= 3; + + return ( +
+
+ {isUpgradeModalOpen && ( + setIsUpgradeModalOpen(false)} /> + )} + {!isPaidUser && !isPaidUserLoading && isLoggedIn() && ( +
+ You are on the free plan + +
+ )} +

+ What can I help you learn? +

+

+ Enter a topic below to generate a personalized course for it +

+
+ +
{ + e.preventDefault(); + handleSubmit(); + }} + > +
+ + { + setTitle(e.target.value); + setShowFineTuneOptions(false); + }} + className="block w-full rounded-xl border border-gray-200 bg-white p-4 outline-none placeholder:text-gray-500 focus:border-gray-500" + required + minLength={3} + /> +
+
+ +
+ {allowedFormats.map((format) => { + const isSelected = format.value === selectedFormat; + + return ( + setSelectedFormat(format.value)} + icon={format.icon} + isSelected={isSelected} + /> + ); + })} +
+
+ + + + {/* {showFineTuneOptions && ( + { + handleSubmit(); + }} + /> + )} */} + + + +
+ ); +} diff --git a/src/components/ContentGenerator/ContentGenerator.tsx b/src/components/ContentGenerator/ContentGenerator.tsx index 85da2d70d..1abde5c5e 100644 --- a/src/components/ContentGenerator/ContentGenerator.tsx +++ b/src/components/ContentGenerator/ContentGenerator.tsx @@ -60,7 +60,7 @@ export function ContentGenerator() { useEffect(() => { const params = getUrlParams(); const format = params.format as AllowedFormat; - if (format && allowedFormats.includes(format)) { + if (format && allowedFormats.find((f) => f.value === format)) { setSelectedFormat(format); } }, []); diff --git a/src/pages/ai/quiz/index.astro b/src/pages/ai/quiz/index.astro new file mode 100644 index 000000000..6cab838d6 --- /dev/null +++ b/src/pages/ai/quiz/index.astro @@ -0,0 +1,15 @@ +--- +import { AIQuiz } from '../../../components/AIQuiz/AIQuiz'; +import SkeletonLayout from '../../../layouts/SkeletonLayout.astro'; +--- + + + +