import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { BrainCircuit, Loader2, Play, PenTool, BookOpen, Upload, X, FileText, Image, ScanText, Sparkles, Settings } from 'lucide-react'; import { useAuth } from 'react-oidc-context'; import { AuthButton } from './AuthButton'; import { QuizLibrary } from './QuizLibrary'; import { DefaultConfigModal } from './DefaultConfigModal'; import { useQuizLibrary } from '../hooks/useQuizLibrary'; import { useUserConfig } from '../hooks/useUserConfig'; import type { Quiz, GameConfig } from '../types'; type GenerateMode = 'topic' | 'document'; interface LandingProps { onGenerate: (options: { topic?: string; questionCount?: number; files?: File[]; useOcr?: boolean }) => void; onCreateManual: () => void; onLoadQuiz: (quiz: Quiz, quizId?: string) => void; onJoin: (pin: string, name: string) => void; isLoading: boolean; error: string | null; } export const Landing: React.FC = ({ onGenerate, onCreateManual, onLoadQuiz, onJoin, isLoading, error }) => { const auth = useAuth(); const [mode, setMode] = useState<'HOST' | 'JOIN'>('HOST'); const [generateMode, setGenerateMode] = useState('topic'); const [topic, setTopic] = useState(''); const [pin, setPin] = useState(''); const [name, setName] = useState(''); const [libraryOpen, setLibraryOpen] = useState(false); const [selectedFiles, setSelectedFiles] = useState([]); const [questionCount, setQuestionCount] = useState(10); const [isDragging, setIsDragging] = useState(false); const [useOcr, setUseOcr] = useState(false); const [defaultConfigOpen, setDefaultConfigOpen] = useState(false); const [editingDefaultConfig, setEditingDefaultConfig] = useState(null); const hasImageFile = selectedFiles.some(f => f.type.startsWith('image/')); const hasDocumentFile = selectedFiles.some(f => !f.type.startsWith('image/') && !['application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'text/html'].includes(f.type)); const showOcrOption = hasImageFile || hasDocumentFile; const { defaultConfig, saving: savingConfig, saveDefaultConfig } = useUserConfig(); const { quizzes, loading: libraryLoading, loadingQuizId, deletingQuizId, error: libraryError, fetchQuizzes, loadQuiz, deleteQuiz, retry: retryLibrary } = useQuizLibrary(); useEffect(() => { if (libraryOpen && auth.isAuthenticated) { fetchQuizzes(); } }, [libraryOpen, auth.isAuthenticated, fetchQuizzes]); const handleFileSelect = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { const newFiles = Array.from(e.target.files); setSelectedFiles(prev => [...prev, ...newFiles]); } }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { const acceptedTypes = ['.pdf', '.txt', '.md', '.docx', '.pptx', '.xlsx', '.odt', '.odp', '.ods', '.rtf', '.jpg', '.jpeg', '.png', '.gif', '.webp']; const newFiles = Array.from(e.dataTransfer.files).filter((file: File) => { const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase(); return acceptedTypes.includes(fileExtension) || file.type.startsWith('image/'); }); if (newFiles.length > 0) { setSelectedFiles(prev => [...prev, ...newFiles]); } } }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); }; const removeFile = (index: number) => { setSelectedFiles(prev => prev.filter((_, i) => i !== index)); if (selectedFiles.length <= 1) { setUseOcr(false); } }; const clearAllFiles = () => { setSelectedFiles([]); setUseOcr(false); }; const canGenerate = generateMode === 'topic' ? topic.trim() : selectedFiles.length > 0; const handleHostSubmit = (e: React.FormEvent) => { e.preventDefault(); if (canGenerate && !isLoading) { onGenerate({ topic: generateMode === 'topic' ? topic.trim() : undefined, questionCount, files: generateMode === 'document' ? selectedFiles : undefined, useOcr: generateMode === 'document' && showOcrOption ? useOcr : undefined }); } }; const handleJoinSubmit = (e: React.FormEvent) => { e.preventDefault(); if (pin.trim() && name.trim()) onJoin(pin, name); }; const handleLoadQuiz = async (id: string) => { try { const quiz = await loadQuiz(id); setLibraryOpen(false); onLoadQuiz(quiz, id); } catch (err) { if (err instanceof Error && err.message.includes('redirecting')) { return; } console.error('Failed to load quiz:', err); } }; return (
{auth.isAuthenticated && ( )}

Kaboot

The AI Quiz Party

{mode === 'HOST' ? (
{generateMode === 'topic' ? ( setTopic(e.target.value)} className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none transition-all placeholder:font-medium text-center" disabled={isLoading} /> ) : (
document.getElementById('file-upload')?.click()} className={`border-2 border-dashed rounded-2xl p-4 text-center cursor-pointer transition-all ${ isDragging ? 'border-theme-primary bg-theme-primary/5 scale-[1.02]' : selectedFiles.length > 0 ? 'border-theme-primary/50 bg-theme-primary/5' : 'border-gray-300 hover:border-gray-400 hover:bg-gray-50' }`} >

{isDragging ? 'Drop files here' : 'Drop files or click to browse'}

PDF, DOCX, PPTX, XLSX, TXT, Images

{selectedFiles.length > 0 && (
{selectedFiles.length} file{selectedFiles.length > 1 ? 's' : ''} selected
{selectedFiles.map((file, index) => (
{file.type.startsWith('image/') ? ( ) : ( )}
{file.name}
))}
)} {showOcrOption && ( )}
)}
Questions {questionCount}
setQuestionCount(Number(e.target.value))} className="w-full accent-theme-primary h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" />
OR
{auth.isAuthenticated && ( )}
) : (
setPin(e.target.value)} className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none text-center" /> setName(e.target.value)} className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none text-center" />
)} {error && (

{error}

)}
setLibraryOpen(false)} quizzes={quizzes} loading={libraryLoading} loadingQuizId={loadingQuizId} deletingQuizId={deletingQuizId} error={libraryError} onLoadQuiz={handleLoadQuiz} onDeleteQuiz={deleteQuiz} onRetry={retryLibrary} /> { setDefaultConfigOpen(false); setEditingDefaultConfig(null); }} config={editingDefaultConfig || defaultConfig} onChange={setEditingDefaultConfig} onSave={async () => { if (editingDefaultConfig) { await saveDefaultConfig(editingDefaultConfig); setDefaultConfigOpen(false); setEditingDefaultConfig(null); } }} saving={savingConfig} />
); };