2026-03-29 00:32:24 -04:00

156 lines
4.1 KiB
TypeScript

import { NextResponse } from "next/server";
import { db } from "@/db";
import { quizSessions } from "@/db/schema";
import { eq, and, desc } from "drizzle-orm";
import { getSession } from "@/lib/auth";
import { WARMUP_PARAGRAPHS } from "@/lib/warmup-paragraphs";
interface WarmupProgress {
warmupCompleted: number;
}
function parseWarmupProgress(answersJson: string): WarmupProgress {
try {
const parsed = JSON.parse(answersJson);
if (parsed && typeof parsed === "object" && "warmupCompleted" in parsed) {
return { warmupCompleted: parsed.warmupCompleted ?? 0 };
}
// Legacy format: answers is an array, no warmup tracking yet
return { warmupCompleted: 0 };
} catch {
return { warmupCompleted: 0 };
}
}
async function getPassedQuizSession(annotatorId: string) {
const [session] = await db
.select()
.from(quizSessions)
.where(
and(
eq(quizSessions.annotatorId, annotatorId),
eq(quizSessions.passed, true),
),
)
.orderBy(desc(quizSessions.startedAt))
.limit(1);
return session ?? null;
}
export async function GET() {
const session = await getSession();
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const quizSession = await getPassedQuizSession(session.annotatorId);
if (!quizSession) {
return NextResponse.json(
{ error: "Quiz not passed" },
{ status: 403 },
);
}
const progress = parseWarmupProgress(quizSession.answers);
if (progress.warmupCompleted >= WARMUP_PARAGRAPHS.length) {
return NextResponse.json({ done: true, warmupCompleted: progress.warmupCompleted });
}
const next = WARMUP_PARAGRAPHS[progress.warmupCompleted];
return NextResponse.json({
done: false,
warmupCompleted: progress.warmupCompleted,
paragraph: {
id: next.id,
text: next.text,
index: progress.warmupCompleted,
total: WARMUP_PARAGRAPHS.length,
},
});
}
export async function POST(request: Request) {
const session = await getSession();
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const quizSession = await getPassedQuizSession(session.annotatorId);
if (!quizSession) {
return NextResponse.json(
{ error: "Quiz not passed" },
{ status: 403 },
);
}
const body = await request.json();
const { category, specificity, warmupIndex } = body as {
category?: string;
specificity?: number;
warmupIndex?: number;
};
if (!category || !specificity || warmupIndex === undefined) {
return NextResponse.json(
{ error: "Missing required fields: category, specificity, warmupIndex" },
{ status: 400 },
);
}
const progress = parseWarmupProgress(quizSession.answers);
if (warmupIndex !== progress.warmupCompleted) {
return NextResponse.json(
{ error: "Warmup index mismatch" },
{ status: 400 },
);
}
if (warmupIndex >= WARMUP_PARAGRAPHS.length) {
return NextResponse.json(
{ error: "Warmup already complete" },
{ status: 400 },
);
}
const gold = WARMUP_PARAGRAPHS[warmupIndex];
const newCompleted = warmupIndex + 1;
const categoryCorrect = category === gold.goldCategory;
const specificityCorrect = specificity === gold.goldSpecificity;
// Store warmup progress in the quiz session answers field
// Preserve existing quiz answers array if present, add warmup tracking
let existingData: Record<string, unknown>;
try {
const parsed = JSON.parse(quizSession.answers);
if (Array.isArray(parsed)) {
existingData = { quizAnswers: parsed };
} else {
existingData = parsed;
}
} catch {
existingData = {};
}
await db
.update(quizSessions)
.set({
answers: JSON.stringify({
...existingData,
warmupCompleted: newCompleted,
}),
})
.where(eq(quizSessions.id, quizSession.id));
return NextResponse.json({
categoryCorrect,
specificityCorrect,
goldCategory: gold.goldCategory,
goldSpecificity: gold.goldSpecificity,
explanation: gold.explanation,
warmupCompleted: newCompleted,
done: newCompleted >= WARMUP_PARAGRAPHS.length,
});
}