Add quiz feature: student UI, admin editor, lesson page integration
- QuizSection component: shows questions as text inputs, read-only after submission - QuizEditor component: admin CRUD for quiz questions with type selector - saveQuiz/deleteQuiz server actions for admin - submitQuizAttempt server action: idempotent, auto-marks lesson complete - Student lesson page: renders QuizSection, updates complete button logic - Admin lesson page: renders QuizEditor below homework section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import { KinescopePlayer } from "@/components/player/kinescope-player";
|
||||
import { LessonContent } from "@/components/student/lesson-content";
|
||||
import { LessonCompleteButton } from "@/components/student/lesson-complete-button";
|
||||
import { HomeworkSection } from "@/components/student/homework-section";
|
||||
import { QuizSection } from "@/components/student/quiz-section";
|
||||
import { LessonComments } from "@/components/student/lesson-comments";
|
||||
import { FileFormatBadge } from "@/components/shared/file-format-badge";
|
||||
|
||||
@@ -26,6 +27,9 @@ export default async function LessonPage({ params }: Props) {
|
||||
include: {
|
||||
files: { orderBy: { createdAt: "asc" } },
|
||||
homework: true,
|
||||
quiz: {
|
||||
include: { questions: { orderBy: { order: "asc" } } },
|
||||
},
|
||||
module: {
|
||||
include: {
|
||||
course: {
|
||||
@@ -71,6 +75,12 @@ export default async function LessonPage({ params }: Props) {
|
||||
})
|
||||
: null;
|
||||
|
||||
const quizAttempt = lesson?.quiz && session && !isAdmin
|
||||
? await prisma.quizAttempt.findFirst({
|
||||
where: { quizId: lesson.quiz.id, userId: session.user.id },
|
||||
})
|
||||
: null;
|
||||
|
||||
if (!lesson || lesson.module.course.slug !== slug) notFound();
|
||||
|
||||
const isCompleted = !!progress;
|
||||
@@ -163,6 +173,21 @@ export default async function LessonPage({ params }: Props) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quiz */}
|
||||
{lesson.quiz && !isAdmin && (
|
||||
<div className="mb-8">
|
||||
<p className="text-xs font-bold uppercase tracking-widest mb-3" style={{ color: "var(--muted-foreground)" }}>
|
||||
Тест
|
||||
</p>
|
||||
<QuizSection
|
||||
quiz={lesson.quiz}
|
||||
attempt={quizAttempt ? { answers: quizAttempt.answers as Record<string, string> } : null}
|
||||
slug={slug}
|
||||
lessonId={lessonId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Complete button + Prev/Next navigation */}
|
||||
<div
|
||||
className="flex items-center justify-between pt-6 mt-6"
|
||||
@@ -179,10 +204,10 @@ export default async function LessonPage({ params }: Props) {
|
||||
<div />
|
||||
)}
|
||||
|
||||
{!isAdmin && !lesson.homework && (
|
||||
{!isAdmin && !lesson.homework && !lesson.quiz && (
|
||||
<LessonCompleteButton lessonId={lessonId} slug={slug} isCompleted={isCompleted} />
|
||||
)}
|
||||
{!isAdmin && lesson.homework && isCompleted && (
|
||||
{!isAdmin && (lesson.homework || lesson.quiz) && isCompleted && (
|
||||
<LessonCompleteButton lessonId={lessonId} slug={slug} isCompleted={true} readOnly={true} />
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user