import { useState } from 'react';
import './App.css';
import { parseDocument, generateQuiz, submitQuiz } from './api';
import DropZone from './components/DropZone';
import StepHeader from './components/StepHeader';
import QuestionCard from './components/QuestionCard';
import ResultsView from './components/ResultsView';
import Alert from './components/Alert';
// ── small helpers ──────────────────────────────────────────────
function NumberInput({ label, value, onChange, min = 1, max = 20 }) {
return (
);
}
function SelectInput({ label, id, value, onChange, options }) {
return (
);
}
function LoadingBlock({ text }) {
return (
);
}
// ── progress strip ────────────────────────────────────────────
function QuizProgress({ answered, total }) {
const pct = total ? (answered / total) * 100 : 0;
return (
Progress
{answered}/{total} answered
);
}
// ── main app ──────────────────────────────────────────────────
export default function App() {
// wizard state
const [file, setFile] = useState(null);
const [docReady, setDocReady] = useState(false);
const [quiz, setQuiz] = useState(null); // { quiz_id, questions }
const [answers, setAnswers] = useState({}); // { [i]: string }
const [result, setResult] = useState(null);
// settings
const [numQ, setNumQ] = useState(5);
const [difficulty, setDifficulty] = useState('Medium');
const [qType, setQType] = useState('MCQ');
// async state
const [parsing, setParsing] = useState(false);
const [generating, setGenerating] = useState(false);
const [submitting, setSubmitting] = useState(false);
// errors
const [parseErr, setParseErr] = useState('');
const [genErr, setGenErr] = useState('');
const [submitErr, setSubmitErr] = useState('');
const [warnMsg, setWarnMsg] = useState('');
// ── handlers ──
const handleParse = async () => {
if (!file) return;
setParseErr('');
setParsing(true);
try {
await parseDocument(file);
setDocReady(true);
} catch {
setParseErr('Failed to connect to backend. Is the server running?');
} finally {
setParsing(false);
}
};
const handleGenerate = async () => {
setGenErr('');
setGenerating(true);
setAnswers({});
setResult(null);
try {
const data = await generateQuiz({
topic: 'full document',
num_questions: numQ,
difficulty,
question_type: qType,
});
setQuiz(data);
} catch {
setGenErr('Quiz generation failed. Please try again.');
} finally {
setGenerating(false);
}
};
const handleAnswer = (idx, val) => {
setAnswers((prev) => ({ ...prev, [idx]: val }));
setWarnMsg('');
};
const handleSubmit = async () => {
if (!quiz) return;
setWarnMsg('');
setSubmitErr('');
// validation
const unanswered = quiz.questions.reduce((acc, _, i) => {
if (!answers[i]?.trim()) acc.push(i + 1);
return acc;
}, []);
if (unanswered.length) {
setWarnMsg(
`Please answer all questions before submitting. (${unanswered.length} remaining: Q${unanswered.join(', Q')})`
);
return;
}
const payload = quiz.questions.map((_, i) => ({
question_index: i,
user_answer: answers[i] || '',
}));
setSubmitting(true);
try {
const res = await submitQuiz(quiz.quiz_id, payload);
setResult(res);
} catch (e) {
if (e.message === 'Quiz expired') {
setSubmitErr('Quiz session expired. Please generate a new quiz.');
} else {
setSubmitErr('Submission failed. Please try again.');
}
} finally {
setSubmitting(false);
}
};
const handleReset = () => {
setQuiz(null);
setAnswers({});
setResult(null);
setGenErr('');
setSubmitErr('');
setWarnMsg('');
};
const handleFullReset = () => {
handleReset();
setDocReady(false);
setFile(null);
setParseErr('');
};
const answeredCount = quiz
? quiz.questions.filter((_, i) => answers[i]?.trim()).length
: 0;
// ── render ──
return (
{/* HERO */}
{/* ══ LEFT PANEL ══ */}
{/* ══ RIGHT PANEL ══ */}
{/* Loading states */}
{generating && }
{submitting && }
{/* QUIZ QUESTIONS */}
{!generating && !submitting && quiz && !result && (
{quiz.questions.map((q, i) => (
handleAnswer(i, val)}
/>
))}
{warnMsg && {warnMsg}}
{submitErr && {submitErr}}
)}
{/* RESULTS */}
{!submitting && result && (
)}
{/* EMPTY — no document */}
{!quiz && !result && !generating && !docReady && (
📄
Upload a document to begin your session
Supports PDF · DOCX · PPTX · TXT · MD
)}
{/* EMPTY — document ready, not generated */}
{!quiz && !result && !generating && docReady && (
✦
Configure your quiz settings and generate
Choose difficulty, type & question count
)}
);
}