Pending course, rest ready for launch
This commit is contained in:
@@ -1,93 +1,35 @@
|
||||
import CourseCard from "@/components/CourseCard";
|
||||
import { db } from "@/lib/prisma";
|
||||
import { requireUser } from "@/lib/auth/requireUser";
|
||||
import CourseCatalogIntro from "@/components/courses/CourseCatalogIntro";
|
||||
import CourseLevelTabs from "@/components/courses/CourseLevelTabs";
|
||||
import ProgramSection from "@/components/courses/ProgramSection";
|
||||
import { getCourseCatalogViewModel } from "@/lib/courses/publicCourses";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function CoursesPage() {
|
||||
const courses = await db.course.findMany({
|
||||
where: {
|
||||
status: "PUBLISHED",
|
||||
},
|
||||
include: {
|
||||
author: {
|
||||
select: {
|
||||
fullName: true,
|
||||
},
|
||||
},
|
||||
modules: {
|
||||
select: {
|
||||
_count: {
|
||||
select: {
|
||||
lessons: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
enrollments: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
updatedAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
const totalLessons = courses.reduce(
|
||||
(total, course) => total + course.modules.reduce((courseTotal, module) => courseTotal + module._count.lessons, 0),
|
||||
0,
|
||||
);
|
||||
const user = await requireUser().catch(() => null);
|
||||
const catalog = await getCourseCatalogViewModel(user?.id ?? null);
|
||||
|
||||
return (
|
||||
<div className="acve-page">
|
||||
<section className="acve-panel overflow-hidden p-0">
|
||||
<div className="grid gap-0 lg:grid-cols-[1.45fr_0.95fr]">
|
||||
<div className="acve-section-base">
|
||||
<p className="acve-pill mb-4 w-fit">Course Catalog</p>
|
||||
<h1 className="text-3xl font-semibold leading-tight text-[#202a39] md:text-4xl">Build your legal English learning path</h1>
|
||||
<p className="mt-3 max-w-2xl text-base leading-relaxed text-slate-600 md:text-lg">
|
||||
Discover our published legal English courses and start with the path that matches your level.
|
||||
</p>
|
||||
<div className="mt-5 grid gap-3 sm:grid-cols-3">
|
||||
<div className="rounded-xl border border-slate-200 bg-white p-3">
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">Total Courses</p>
|
||||
<p className="mt-1 text-2xl font-semibold text-slate-900">{courses.length}</p>
|
||||
</div>
|
||||
<div className="rounded-xl border border-slate-200 bg-white p-3">
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">Published Lessons</p>
|
||||
<p className="mt-1 text-2xl font-semibold text-slate-900">{totalLessons}</p>
|
||||
</div>
|
||||
<div className="rounded-xl border border-slate-200 bg-white p-3">
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">Instructors</p>
|
||||
<p className="mt-1 text-2xl font-semibold text-slate-900">
|
||||
{new Set(courses.map((course) => course.author.fullName || "ACVE Team")).size}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CourseCatalogIntro
|
||||
instructorCount={catalog.totals.instructorCount}
|
||||
totalCourses={catalog.totals.totalCourses}
|
||||
totalLessons={catalog.totals.totalLessons}
|
||||
/>
|
||||
|
||||
<aside className="border-t border-slate-200 bg-slate-50/80 p-5 lg:border-l lg:border-t-0">
|
||||
<h2 className="text-base font-semibold text-slate-800">Open Access</h2>
|
||||
<p className="mt-2 text-sm text-slate-600">
|
||||
This catalog is public. Open any course card to visit the landing page and enroll.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
<CourseLevelTabs
|
||||
items={catalog.sections.map((section) => ({
|
||||
id: section.id,
|
||||
label: section.tabLabel,
|
||||
anchorId: section.anchorId,
|
||||
count: section.courses.length,
|
||||
}))}
|
||||
/>
|
||||
|
||||
{courses.length === 0 ? (
|
||||
<section className="acve-panel acve-section-base">
|
||||
<div className="rounded-xl border border-dashed border-slate-300 bg-slate-50 px-6 py-12 text-center">
|
||||
<h2 className="text-2xl font-semibold text-slate-900">Coming Soon</h2>
|
||||
<p className="mt-2 text-slate-600">We are preparing new courses. Please check back shortly.</p>
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{courses.map((course) => (
|
||||
<CourseCard key={course.slug} course={course} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{catalog.sections.map((section) => (
|
||||
<ProgramSection key={section.id} section={section} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user