Add questions nav links and admin unread badge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,9 @@ export default async function StudentLayout({ children }: { children: React.Reac
|
|||||||
{schoolName}
|
{schoolName}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
<Link href="/questions" className="text-sm hover:underline" style={{ color: "var(--muted-foreground)" }}>
|
||||||
|
Вопросы
|
||||||
|
</Link>
|
||||||
<Link href="/profile" className="text-sm hover:underline" style={{ color: "var(--muted-foreground)" }}>
|
<Link href="/profile" className="text-sm hover:underline" style={{ color: "var(--muted-foreground)" }}>
|
||||||
{session.user.name}
|
{session.user.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -2,11 +2,23 @@ import { headers } from "next/headers";
|
|||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { AdminShell } from "@/components/admin/admin-shell";
|
import { AdminShell } from "@/components/admin/admin-shell";
|
||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
|
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||||
const session = await auth.api.getSession({ headers: await headers() });
|
const session = await auth.api.getSession({ headers: await headers() });
|
||||||
if (!session) redirect("/login");
|
if (!session) redirect("/login");
|
||||||
if (session.user.role !== "admin") redirect("/dashboard");
|
if (session.user.role !== "admin") redirect("/dashboard");
|
||||||
|
|
||||||
return <AdminShell userName={session.user.name}>{children}</AdminShell>;
|
const questionsBadge = await prisma.studentQuestion.count({
|
||||||
|
where: {
|
||||||
|
messages: {
|
||||||
|
some: {
|
||||||
|
isRead: false,
|
||||||
|
author: { role: "student" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return <AdminShell userName={session.user.name} questionsBadge={questionsBadge}>{children}</AdminShell>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export default async function CuratorLayout({ children }: { children: React.Reac
|
|||||||
<nav className="flex-1 py-3 space-y-0.5 px-2">
|
<nav className="flex-1 py-3 space-y-0.5 px-2">
|
||||||
<NavLink href="/curator/dashboard">Обзор</NavLink>
|
<NavLink href="/curator/dashboard">Обзор</NavLink>
|
||||||
<NavLink href="/curator/homework">ДЗ на проверку</NavLink>
|
<NavLink href="/curator/homework">ДЗ на проверку</NavLink>
|
||||||
|
<NavLink href="/curator/questions">Вопросы</NavLink>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="px-4 py-4" style={{ borderTop: "1px solid rgba(255,255,255,0.08)" }}>
|
<div className="px-4 py-4" style={{ borderTop: "1px solid rgba(255,255,255,0.08)" }}>
|
||||||
<p className="text-xs mb-2 truncate" style={{ color: "#888" }}>{session.user.name}</p>
|
<p className="text-xs mb-2 truncate" style={{ color: "#888" }}>{session.user.name}</p>
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ const links = [
|
|||||||
{ href: "/admin/categories", label: "Категории" },
|
{ href: "/admin/categories", label: "Категории" },
|
||||||
{ href: "/admin/users", label: "Пользователи" },
|
{ href: "/admin/users", label: "Пользователи" },
|
||||||
{ href: "/curator/homework", label: "ДЗ на проверку" },
|
{ href: "/curator/homework", label: "ДЗ на проверку" },
|
||||||
|
{ href: "/admin/questions", label: "Вопросы" },
|
||||||
{ href: "/admin/quizzes", label: "Тесты" },
|
{ href: "/admin/quizzes", label: "Тесты" },
|
||||||
{ href: "/admin/comments", label: "Комментарии" },
|
{ href: "/admin/comments", label: "Комментарии" },
|
||||||
{ href: "/admin/import-export", label: "Импорт / Экспорт" },
|
{ href: "/admin/import-export", label: "Импорт / Экспорт" },
|
||||||
{ href: "/admin/settings", label: "Настройки" },
|
{ href: "/admin/settings", label: "Настройки" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function AdminNav() {
|
export function AdminNav({ questionsBadge = 0 }: { questionsBadge?: number }) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -24,7 +25,7 @@ export function AdminNav() {
|
|||||||
const active =
|
const active =
|
||||||
pathname === href ||
|
pathname === href ||
|
||||||
(href !== "/admin/dashboard" && href !== "/curator/homework" && pathname.startsWith(href)) ||
|
(href !== "/admin/dashboard" && href !== "/curator/homework" && pathname.startsWith(href)) ||
|
||||||
(href === "/curator/homework" && pathname.startsWith("/curator"));
|
(href === "/curator/homework" && pathname.startsWith("/curator/homework"));
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={href}
|
key={href}
|
||||||
@@ -40,7 +41,23 @@ export function AdminNav() {
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{label}
|
<span className="flex items-center justify-between w-full">
|
||||||
|
{label}
|
||||||
|
{href === "/admin/questions" && questionsBadge > 0 && (
|
||||||
|
<span
|
||||||
|
className="ml-2 inline-flex items-center justify-center rounded-full text-xs font-bold leading-none"
|
||||||
|
style={{
|
||||||
|
minWidth: "1.25rem",
|
||||||
|
height: "1.25rem",
|
||||||
|
padding: "0 0.3rem",
|
||||||
|
backgroundColor: "var(--destructive)",
|
||||||
|
color: "#fff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{questionsBadge}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { LogoutButton } from "@/components/layout/logout-button";
|
|||||||
export function AdminShell({
|
export function AdminShell({
|
||||||
children,
|
children,
|
||||||
userName,
|
userName,
|
||||||
|
questionsBadge = 0,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
userName: string;
|
userName: string;
|
||||||
|
questionsBadge?: number;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex">
|
<div className="min-h-screen flex">
|
||||||
@@ -23,7 +25,7 @@ export function AdminShell({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<nav className="flex-1 px-2 py-4 space-y-0.5 overflow-y-auto">
|
<nav className="flex-1 px-2 py-4 space-y-0.5 overflow-y-auto">
|
||||||
<AdminNav />
|
<AdminNav questionsBadge={questionsBadge} />
|
||||||
</nav>
|
</nav>
|
||||||
<div className="px-4 py-4" style={{ borderTop: "2px solid var(--sidebar-border)" }}>
|
<div className="px-4 py-4" style={{ borderTop: "2px solid var(--sidebar-border)" }}>
|
||||||
<p className="text-xs mb-3 truncate" style={{ color: "var(--sidebar-text)" }}>
|
<p className="text-xs mb-3 truncate" style={{ color: "var(--sidebar-text)" }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user