import { prisma } from "@/lib/prisma"; import Link from "next/link"; import { Suspense } from "react"; const PAGE_SIZE = 20; interface Props { searchParams: Promise<{ q?: string; status?: string; courseId?: string; page?: string; }>; } export default async function HomeworkListPage({ searchParams }: Props) { const sp = await searchParams; const q = sp.q ?? ""; const status = sp.status ?? ""; const courseId = sp.courseId ?? ""; const currentPage = Math.max(1, parseInt(sp.page ?? "1") || 1); const skip = (currentPage - 1) * PAGE_SIZE; // Build where clause const where = { ...(q ? { OR: [ { user: { name: { contains: q, mode: "insensitive" as const } } }, { user: { email: { contains: q, mode: "insensitive" as const } } }, { homework: { lesson: { title: { contains: q, mode: "insensitive" as const } } } }, ], } : {}), ...(courseId ? { homework: { lesson: { module: { courseId } }, }, } : {}), ...(status === "pending" ? { feedbacks: { none: {} } } : {}), ...(status === "reviewed" ? { feedbacks: { some: {} } } : {}), }; const [submissions, total, courses] = await Promise.all([ prisma.homeworkSubmission.findMany({ where, orderBy: { submittedAt: "desc" }, skip, take: PAGE_SIZE, include: { user: { select: { name: true, email: true } }, feedbacks: { select: { id: true }, take: 1 }, homework: { include: { lesson: { select: { title: true, module: { select: { title: true, course: { select: { id: true, title: true } } } }, }, }, }, }, }, }), prisma.homeworkSubmission.count({ where }), prisma.course.findMany({ orderBy: { title: "asc" }, select: { id: true, title: true } }), ]); const totalPages = Math.ceil(total / PAGE_SIZE); function pageUrl(p: number) { const params = new URLSearchParams(); if (q) params.set("q", q); if (status) params.set("status", status); if (courseId) params.set("courseId", courseId); params.set("page", String(p)); return `/curator/homework?${params.toString()}`; } const inputStyle: React.CSSProperties = { border: "2px solid var(--border)", background: "var(--background)", outline: "none", padding: "0.4rem 0.75rem", fontSize: "0.8rem", fontFamily: "inherit", color: "var(--foreground)", }; return (

Домашние задания

{total} {total === 1 ? "работа" : "работ"}

{/* Filters */}
{(q || status || courseId) && ( Сбросить )}
{submissions.length === 0 ? (

📭

Ничего не найдено

Попробуйте изменить фильтры

) : (
{submissions.map((s) => { const hasReview = s.feedbacks.length > 0; const reviewBadge = hasReview ? { label: "С отзывом", bg: "oklch(0.88 0.1 145)", color: "oklch(0.35 0.15 145)" } : { label: "Без ответа", bg: "var(--foreground)", color: "var(--background)" }; return (

{s.user.name}

{s.homework.lesson.module.course.title} · {s.homework.lesson.title}

{s.user.email}

{reviewBadge.label}

{new Date(s.submittedAt).toLocaleDateString("ru-RU")}

); })}
)} {/* Pagination */} {totalPages > 1 && (
{currentPage > 1 && ( ← )} {Array.from({ length: totalPages }, (_, i) => i + 1) .filter((p) => p === 1 || p === totalPages || Math.abs(p - currentPage) <= 2) .reduce<(number | "…")[]>((acc, p, i, arr) => { if (i > 0 && (p as number) - (arr[i - 1] as number) > 1) acc.push("…"); acc.push(p); return acc; }, []) .map((p, i) => p === "…" ? ( ) : ( {p} ) )} {currentPage < totalPages && ( → )} Страница {currentPage} из {totalPages} · Всего: {total}
)}
); }