Serialize all Prisma data before passing to Client Components
Prisma 7 proxy objects (DateTime, _count, relations) cannot be serialized by React RSC. Convert all course page data to plain JSON objects with JSON.parse/stringify before passing as props. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,13 +50,21 @@ export default async function CourseDetailPage({ params }: Props) {
|
||||
|
||||
if (!course) notFound();
|
||||
|
||||
// Prisma 7 returns proxy objects for relations/aggregates that RSC cannot serialize.
|
||||
// Convert to plain JS before passing to Client Components.
|
||||
const plain = JSON.parse(JSON.stringify({ course, allStudents, categories })) as {
|
||||
course: typeof course;
|
||||
allStudents: typeof allStudents;
|
||||
categories: typeof categories;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="text-xs mb-6 uppercase tracking-widest" style={{ color: "var(--muted-foreground)" }}>
|
||||
<Link href="/admin/courses" className="hover:underline">Курсы</Link>
|
||||
<span className="mx-2">/</span>
|
||||
<span style={{ color: "var(--foreground)" }}>{course.title}</span>
|
||||
<span style={{ color: "var(--foreground)" }}>{plain.course.title}</span>
|
||||
</nav>
|
||||
|
||||
{/* Course metadata */}
|
||||
@@ -64,7 +72,7 @@ export default async function CourseDetailPage({ params }: Props) {
|
||||
<p className="text-xs font-bold uppercase tracking-widest mb-5" style={{ color: "var(--muted-foreground)" }}>
|
||||
Основная информация
|
||||
</p>
|
||||
<CourseEditForm course={course} categories={categories} />
|
||||
<CourseEditForm course={plain.course} categories={plain.categories} />
|
||||
</section>
|
||||
|
||||
{/* Modules */}
|
||||
@@ -74,19 +82,19 @@ export default async function CourseDetailPage({ params }: Props) {
|
||||
Модули
|
||||
</p>
|
||||
<span className="text-xs" style={{ color: "var(--muted-foreground)" }}>
|
||||
{course.modules.length} модулей
|
||||
{plain.course.modules.length} модулей
|
||||
</span>
|
||||
</div>
|
||||
<SortableModules courseId={courseId} modules={course.modules} />
|
||||
<SortableModules courseId={courseId} modules={plain.course.modules} />
|
||||
</section>
|
||||
|
||||
{/* Course tree overview */}
|
||||
{course.modules.length > 0 && (
|
||||
{plain.course.modules.length > 0 && (
|
||||
<section className="card-aubade p-6 mb-6">
|
||||
<p className="text-xs font-bold uppercase tracking-widest mb-5" style={{ color: "var(--muted-foreground)" }}>
|
||||
Структура курса
|
||||
</p>
|
||||
<CourseTree courseId={courseId} modules={course.modules} />
|
||||
<CourseTree courseId={courseId} modules={plain.course.modules} />
|
||||
</section>
|
||||
)}
|
||||
|
||||
@@ -97,9 +105,9 @@ export default async function CourseDetailPage({ params }: Props) {
|
||||
</p>
|
||||
<EnrollmentManager
|
||||
courseId={courseId}
|
||||
allStudents={allStudents}
|
||||
enrollments={course.enrollments}
|
||||
accessLogs={course.accessLogs}
|
||||
allStudents={plain.allStudents}
|
||||
enrollments={plain.course.enrollments}
|
||||
accessLogs={plain.course.accessLogs}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user