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:
2026-04-25 13:42:05 +05:00
parent d8be6d6d95
commit 0bde11b86e
+17 -9
View File
@@ -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>