Add /admin/comments page with delete and pagination

- Add admin auth guard (redirect to /dashboard if not admin)
- Add delete-action.ts with deleteComment(commentId) soft-delete action
- Fix pagination label to show "Страница X из Y · Всего: N"
- Existing actions.ts, comments-table.tsx, and admin-nav entry preserved

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 14:31:38 +05:00
parent 7084806aac
commit 751c012f3d
2 changed files with 26 additions and 1 deletions
+19
View File
@@ -0,0 +1,19 @@
"use server";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { revalidatePath } from "next/cache";
export async function deleteComment(commentId: string): Promise<{ ok: boolean }> {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") throw new Error("Нет доступа");
await prisma.lessonComment.update({
where: { id: commentId },
data: { deleted: true },
});
revalidatePath("/admin/comments");
return { ok: true };
}
+7 -1
View File
@@ -2,6 +2,9 @@ import { prisma } from "@/lib/prisma";
import Link from "next/link"; import Link from "next/link";
import { Suspense } from "react"; import { Suspense } from "react";
import { CommentsTable } from "@/components/admin/comments-table"; import { CommentsTable } from "@/components/admin/comments-table";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export const metadata = { title: "Комментарии" }; export const metadata = { title: "Комментарии" };
@@ -12,6 +15,9 @@ interface Props {
} }
export default async function AdminCommentsPage({ searchParams }: Props) { export default async function AdminCommentsPage({ searchParams }: Props) {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") redirect("/dashboard");
const { page = "1", search = "" } = await searchParams; const { page = "1", search = "" } = await searchParams;
const currentPage = Math.max(1, parseInt(page) || 1); const currentPage = Math.max(1, parseInt(page) || 1);
const skip = (currentPage - 1) * PAGE_SIZE; const skip = (currentPage - 1) * PAGE_SIZE;
@@ -106,7 +112,7 @@ export default async function AdminCommentsPage({ searchParams }: Props) {
{currentPage < totalPages && ( {currentPage < totalPages && (
<Link href={pageUrl(currentPage + 1)} className="btn-aubade px-3 py-1 text-xs"></Link> <Link href={pageUrl(currentPage + 1)} className="btn-aubade px-3 py-1 text-xs"></Link>
)} )}
<span className="ml-2 text-xs" style={{ color: "var(--muted-foreground)" }}>стр. {currentPage} из {totalPages}</span> <span className="ml-2 text-xs" style={{ color: "var(--muted-foreground)" }}>Страница {currentPage} из {totalPages} · Всего: {total}</span>
</div> </div>
)} )}
</div> </div>