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:
@@ -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 };
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user