94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
import Link from "next/link";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { requireSession } from "@/lib/session-helpers";
|
|
import { firstLessonPath } from "@/lib/course-queries";
|
|
import { getUserCourseProgress } from "@/lib/course-progress";
|
|
import { RestartCourseButton } from "@/components/restart-course-button";
|
|
|
|
export default async function PortalHomePage() {
|
|
const session = await requireSession();
|
|
|
|
const enrollments = await prisma.enrollment.findMany({
|
|
where: { userId: session.user.id },
|
|
include: {
|
|
course: {
|
|
include: {
|
|
modules: {
|
|
orderBy: { sortOrder: "asc" },
|
|
include: {
|
|
lessons: {
|
|
where: { published: true },
|
|
orderBy: { sortOrder: "asc" },
|
|
select: { slug: true },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
|
|
const certs = await prisma.certificate.findMany({
|
|
where: { userId: session.user.id },
|
|
select: { courseId: true, code: true },
|
|
});
|
|
const certByCourse = new Map(certs.map((c) => [c.courseId, c.code]));
|
|
|
|
return (
|
|
<div>
|
|
<h1 className="page-title">Hallo{session.user.name ? `, ${session.user.name}` : ""}!</h1>
|
|
<p className="muted subtitle">Deine Kurse, Fortschritt und nächste Schritte.</p>
|
|
|
|
{enrollments.length === 0 ? (
|
|
<div className="panel">
|
|
<p>Du bist noch in keinem Kurs eingeschrieben.</p>
|
|
<Link href="/kurse" className="btn btn-primary">
|
|
Kurse entdecken
|
|
</Link>
|
|
</div>
|
|
) : (
|
|
<div className="course-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))" }}>
|
|
{await Promise.all(
|
|
enrollments.map(async (e) => {
|
|
const p = await getUserCourseProgress(session.user.id, e.course.id);
|
|
const start = firstLessonPath(e.course);
|
|
const cert = certByCourse.get(e.course.id);
|
|
|
|
return (
|
|
<div key={e.id} className="panel">
|
|
<h2 style={{ marginTop: 0, fontSize: "1.15rem" }}>{e.course.title}</h2>
|
|
<p className="muted" style={{ marginTop: 0 }}>
|
|
Fortschritt: {p.completed}/{p.total} Lektionen ({p.percent}%)
|
|
</p>
|
|
<div className="progress" aria-hidden="true">
|
|
<span style={{ width: `${p.percent}%` }} />
|
|
</div>
|
|
<div className="stack" style={{ marginTop: "1rem" }}>
|
|
{start ? (
|
|
<Link href={start} className="btn btn-primary">
|
|
{p.percent >= 100 ? "Kurs wiederholen" : "Weiterlernen"}
|
|
</Link>
|
|
) : (
|
|
<span className="muted">Keine Lektionen</span>
|
|
)}
|
|
<Link href={`/kurse/${e.course.slug}`} className="btn btn-ghost">
|
|
Kurrikulum
|
|
</Link>
|
|
{cert ? (
|
|
<Link href={`/zertifikat/${cert}`} className="btn btn-ghost">
|
|
Zertifikat
|
|
</Link>
|
|
) : null}
|
|
<RestartCourseButton courseId={e.course.id} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}),
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|