Grapevine_Disease_Detection/vineye-admin/app/(admin)/dashboard/page.tsx
Yanis fe70005a86 add vineye-admin dashboard (Next.js)
Admin panel for VinEye with dashboard, users, diseases, guides, alerts management.
Stack: Next.js App Router + Prisma + PostgreSQL + better-auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:22:01 +02:00

75 lines
2.1 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import { formatDate } from "@/lib/utils";
import DashboardClient from "./dashboard-client";
export const dynamic = "force-dynamic";
export default async function DashboardPage() {
const [totalUsers, totalDiseases, activeAlerts, scansThisMonth, recentScans, topDiseases] =
await Promise.all([
prisma.user.count(),
prisma.disease.count(),
prisma.seasonAlert.count({ where: { active: true } }),
prisma.scan.count({
where: {
createdAt: {
gte: new Date(new Date().getFullYear(), new Date().getMonth(), 1),
},
},
}),
prisma.scan.findMany({
select: {
id: true,
confidence: true,
createdAt: true,
user: { select: { name: true } },
disease: { select: { name: true } },
},
orderBy: { createdAt: "desc" },
take: 8,
}),
prisma.scan
.groupBy({
by: ["diseaseId"],
_count: { id: true },
where: { diseaseId: { not: null } },
orderBy: { _count: { id: "desc" } },
take: 5,
})
.then(async (stats) => {
const ids = stats
.map((s) => s.diseaseId)
.filter((id): id is string => id !== null);
const diseases = await prisma.disease.findMany({
where: { id: { in: ids } },
select: { id: true, name: true },
});
return stats.map((stat) => ({
name: diseases.find((d) => d.id === stat.diseaseId)?.name || "Inconnu",
count: stat._count.id,
}));
}),
]);
const formattedScans = recentScans.map((scan) => ({
id: scan.id,
userName: scan.user.name,
diseaseName: scan.disease?.name || "Non identifie",
confidence: Math.round(scan.confidence * 100),
date: formatDate(scan.createdAt),
}));
return (
<DashboardClient
stats={{
totalUsers,
scansThisMonth,
totalDiseases,
activeAlerts,
}}
recentScans={formattedScans}
topDiseases={topDiseases}
/>
);
}