fix: smart CBT result/back routing for DPPs and add Test Type selector in Admin panel

This commit is contained in:
2026-07-27 15:55:54 +05:30
parent 053b727725
commit 62d15c85f6
5 changed files with 40 additions and 7 deletions

View File

@@ -646,6 +646,7 @@ class ManualQuestionInput(BaseModel):
class ManualTestCreate(BaseModel):
title: str
type: str = "CBT"
exam_pattern: str
time_limit: int
scheduled_date: Optional[datetime] = None
@@ -707,7 +708,7 @@ def create_manual_test(
# 1. Create the test object
test_obj = models.Test(
title=data.title,
type="Mock",
type=data.type,
exam_pattern=models.ExamEnum(data.exam_pattern),
sections={},
total_time=data.time_limit,

View File

@@ -41,6 +41,7 @@ export default function AdminTestsPage() {
// Upload Form State
const [title, setTitle] = useState("")
const [testType, setTestType] = useState("CBT")
const [examPattern, setExamPattern] = useState("JEE_Main")
const [timeLimit, setTimeLimit] = useState("180")
const [scheduledDate, setScheduledDate] = useState<Date | null>(null)
@@ -180,6 +181,7 @@ export default function AdminTestsPage() {
const payload = {
title,
type: testType,
exam_pattern: examPattern,
time_limit: parseInt(timeLimit),
admin_id: userId,
@@ -237,6 +239,27 @@ export default function AdminTestsPage() {
<Input required value={title} onChange={e => setTitle(e.target.value)} placeholder="e.g. JEE Main Mock Test 1" />
</div>
{/* TEST TYPE — KEY DIFFERENTIATOR */}
<div className="space-y-2">
<label className="text-sm font-medium flex items-center gap-2">
Test Type
<span className="text-[10px] text-muted-foreground font-normal">(determines which section it appears in)</span>
</label>
<select
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
value={testType}
onChange={(e) => setTestType(e.target.value)}
>
<option value="CBT">🎯 CBT Mock Test — appears in Mock Tests section</option>
<option value="DPS">📋 DPP (Daily Practice) — appears in PrepPilot AI section</option>
</select>
<p className="text-[11px] text-muted-foreground">
{testType === 'CBT'
? '✅ This will appear under Dashboard → Mock Tests (CBT) for students to attempt.'
: '✅ This will appear under AI Coach → PrepPilot AI as a DPP with full CBT interface.'}
</p>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Exam Pattern</label>
<select

View File

@@ -316,6 +316,7 @@ export default function CBTExamPage({ params }: { params: Promise<{ examId: stri
<ExamResult
payload={payload}
attemptId={attemptId}
examType={examType}
onRetake={examType === 'DPS' ? () => {
resetExamState();
window.location.reload();

View File

@@ -62,6 +62,10 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
fetchHistoryData();
}, [attemptId, userId]);
// Smart back route based on test type
const backRoute = test?.type === 'DPS' ? '/dashboard/ai-coach/cbt-dpp' : '/dashboard/cbt';
const backLabel = test?.type === 'DPS' ? '← Back to PrepPilot AI' : '← Back to Tests';
if (loading) {
return (
<div className="flex h-screen items-center justify-center">
@@ -83,8 +87,8 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
return (
<div className="max-w-6xl mx-auto p-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
<Link href="/dashboard/cbt" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-6 transition-colors">
<ArrowLeft size={16} className="mr-2" /> Back to Tests
<Link href={backRoute} className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-6 transition-colors">
<ArrowLeft size={16} className="mr-2" /> {test?.type === 'DPS' ? 'Back to PrepPilot AI' : 'Back to Tests'}
</Link>
<div className="flex flex-col md:flex-row gap-8 mb-10">

View File

@@ -19,11 +19,15 @@ interface ExamAttemptPayload {
interface ExamResultProps {
payload: ExamAttemptPayload;
attemptId: string | null;
examType?: string; // 'CBT' or 'DPS'
onRetake: () => void;
}
export function ExamResult({ payload, attemptId, onRetake }: ExamResultProps) {
export function ExamResult({ payload, attemptId, examType, onRetake }: ExamResultProps) {
const router = useRouter();
const isDPP = examType === 'DPS';
const backRoute = isDPP ? '/dashboard/ai-coach/cbt-dpp' : '/dashboard/cbt';
const backLabel = isDPP ? 'Back to PrepPilot AI' : 'Back to Mock Tests';
const answered = payload.answers.filter(a => a.selected_answer !== null).length;
const unanswered = payload.total_questions - answered;
@@ -114,7 +118,7 @@ export function ExamResult({ payload, attemptId, onRetake }: ExamResultProps) {
<div className="flex flex-col sm:flex-row gap-4 justify-center pt-8">
<Button variant="outline" size="lg" className="rounded-xl h-14 px-8 font-bold text-lg gap-2" onClick={onRetake}>
<RotateCcw className="size-5" /> Retake Mock Test
<RotateCcw className="size-5" /> {isDPP ? 'Retake DPP' : 'Retake Mock Test'}
</Button>
{attemptId && (
<Button
@@ -146,10 +150,10 @@ export function ExamResult({ payload, attemptId, onRetake }: ExamResultProps) {
} catch (err) {
console.error("Error exiting fullscreen", err);
}
router.push("/dashboard/cbt");
router.push(backRoute);
}}
>
Dashboard <ArrowRight className="size-5" />
{backLabel} <ArrowRight className="size-5" />
</Button>
</div>