import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Alert, Box, Button, Card, CardActionArea, CardContent, Chip, CircularProgress, Container, Dialog, DialogActions, DialogContent, DialogTitle, Stack, TextField, Typography, } from '@mui/material'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import PlaylistAddCheckIcon from '@mui/icons-material/PlaylistAddCheck'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; import { examRepository } from '../../services/exam/examRepository'; import type { BankQuestion, BankResponse } from '../../types/exam.types'; const QuestionBankPage: React.FC = () => { const navigate = useNavigate(); const [bank, setBank] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [specRef, setSpecRef] = useState(null); const [subject, setSubject] = useState(null); const [selected, setSelected] = useState>(new Set()); const [dialogOpen, setDialogOpen] = useState(false); const [title, setTitle] = useState(''); const [creating, setCreating] = useState(false); const load = useCallback(async () => { setLoading(true); setError(null); try { setBank(await examRepository.getBank({ specRef: specRef ?? undefined, subject: subject ?? undefined })); } catch (e) { setError(e instanceof Error ? e.message : String(e)); } finally { setLoading(false); } }, [specRef, subject]); useEffect(() => { void load(); }, [load]); const toggle = (id: string) => setSelected((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); const selectedList = useMemo(() => Array.from(selected), [selected]); const selectedQuestions = useMemo( () => (bank?.questions ?? []).filter((q) => selected.has(q.id)), [bank, selected], ); const totalMarks = selectedQuestions.reduce((s, q) => s + (q.max_marks ?? 0), 0); // facet lists (sorted) with counts const specFacets = Object.entries(bank?.facets.spec_ref ?? {}).sort((a, b) => (a[0] < b[0] ? -1 : 1)); const subjectFacets = Object.entries(bank?.facets.subject ?? {}).sort((a, b) => (a[0] < b[0] ? -1 : 1)); const create = async () => { setCreating(true); setError(null); try { const subj = subject ?? selectedQuestions[0]?.paper.subject ?? undefined; const res = await examRepository.createCustomPaper({ title: title.trim() || `Custom paper — ${new Date().toISOString().slice(0, 10)}`, subject: subj ?? undefined, question_ids: selectedList, }); navigate(`/exam-marker/${res.id}/setup`); } catch (e) { setError(e instanceof Error ? e.message : String(e)); setCreating(false); setDialogOpen(false); } }; return ( Question bank Plan by spec point, then assemble a custom paper from questions across your papers. {error && setError(null)}>{error}} {/* Filters */} Spec point: setSpecRef(null)} variant={specRef ? 'outlined' : 'filled'} /> {specFacets.map(([ref, count]) => ( setSpecRef(ref)} /> ))} {subjectFacets.length > 1 && ( Subject: setSubject(null)} variant={subject ? 'outlined' : 'filled'} /> {subjectFacets.map(([s, count]) => ( setSubject(s)} sx={{ textTransform: 'capitalize' }} /> ))} )} {loading ? ( ) : (bank?.questions.length ?? 0) === 0 ? ( No questions match yet. Questions appear here once your templates have parts with spec points (set them in the mark-scheme editor). Auto-map + confirm on a paper to populate it. ) : ( <> {bank?.n} question{bank?.n === 1 ? '' : 's'} · click to add to your paper {(bank?.questions ?? []).map((q: BankQuestion) => { const on = selected.has(q.id); return ( toggle(q.id)}> Q{q.label ?? '?'} {on ? : } {q.answer_type && } {q.spec_ref && } {[q.paper.subject, q.paper.title].filter(Boolean).join(' · ') || 'Untitled paper'} ); })} )} !creating && setDialogOpen(false)} fullWidth maxWidth="sm"> Create custom paper {selected.size} question{selected.size === 1 ? '' : 's'} · {totalMarks} marks. This creates a new template you can open in setup and use for marking. setTitle(e.target.value)} placeholder={`Custom paper — ${new Date().toISOString().slice(0, 10)}`} /> ); }; export default QuestionBankPage;