Files
NextEdu/src/app/(dashboard)/student/learning/courses/page.tsx
SpecialX 37d2688a28 feat(app): add lesson-plans, practice, and grade dashboard routes
- Add admin/lesson-plans, parent/lesson-plans, student/lesson-plans routes

- Add student/practice and teacher/practice routes for adaptive practice

- Add management/grade/dashboard and management/grade/practice routes

- Add teacher/lesson-plans error and loading boundaries

- Update existing admin, parent, student, teacher pages with new features

- Update globals.css and proxy middleware
2026-06-24 12:03:47 +08:00

64 lines
2.0 KiB
TypeScript

import { UserX } from "lucide-react"
import { getTranslations } from "next-intl/server"
import { getStudentClasses } from "@/modules/classes/data-access"
import { getCurrentStudentUser } from "@/modules/users/data-access"
import { StudentCoursesView } from "@/modules/student/components/student-courses-view"
import { CourseFilters } from "@/modules/student/components/course-filters"
import { EmptyState } from "@/shared/components/ui/empty-state"
import { getParam, type SearchParams } from "@/shared/lib/search-params"
export const dynamic = "force-dynamic"
export default async function StudentCoursesPage({
searchParams,
}: {
searchParams: Promise<SearchParams>
}) {
const t = await getTranslations("student")
const student = await getCurrentStudentUser()
if (!student) {
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold tracking-tight">{t("courses.title")}</h2>
<p className="text-muted-foreground">{t("courses.description")}</p>
</div>
<EmptyState
title={t("courses.noUser")}
description={t("courses.noUserDesc")}
icon={UserX}
/>
</div>
)
}
const [sp, classes] = await Promise.all([
searchParams,
getStudentClasses(student.id),
])
const q = (getParam(sp, "q") || "").toLowerCase().trim()
const filteredClasses = q
? classes.filter((c) => {
return (
c.name.toLowerCase().includes(q) ||
(c.teacherName?.toLowerCase().includes(q) ?? false) ||
(c.schoolName?.toLowerCase().includes(q) ?? false) ||
(c.homeroom?.toLowerCase().includes(q) ?? false)
)
})
: classes
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold tracking-tight">{t("courses.title")}</h2>
<p className="text-muted-foreground">{t("courses.description")}</p>
</div>
{classes.length > 0 && <CourseFilters />}
<StudentCoursesView classes={filteredClasses} />
</div>
)
}