added reports stats for admins

This commit is contained in:
PxlLoewe
2025-05-16 23:07:51 -07:00
parent 40ca6b1bd9
commit 16e05a08a6
3 changed files with 157 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { BADGES, PERMISSION, User } from "@repo/db";
import { BADGES, PERMISSION, Report, User } from "@repo/db";
import { useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { deleteDispoHistory, editUser, resetPassword } from "../../action";
@@ -20,10 +20,10 @@ import { Select } from "../../../../../_components/ui/Select";
import { UserSchema } from "@repo/db/zod";
import { useRouter } from "next/navigation";
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
import { min } from "date-fns";
import { cn } from "../../../../../../helper/cn";
import { ChartBarBigIcon, PlaneIcon } from "lucide-react";
import { ChartBarBigIcon, Check, Eye, PlaneIcon, Timer, X } from "lucide-react";
import Link from "next/link";
import { ColumnDef } from "@tanstack/react-table";
interface ProfileFormProps {
user: User;
@@ -305,6 +305,79 @@ export const ConnectionHistory: React.FC<{ user: User }> = ({
);
};
export const UserReports = ({ user }: { user: User }) => {
return (
<div className="card-body">
<h2 className="card-title">
<ExclamationTriangleIcon className="w-5 h-5" /> User Reports
</h2>
<PaginatedTable
prismaModel="report"
filter={{
reportedUserId: user.id,
}}
include={{
Sender: true,
Reported: true,
}}
columns={
[
{
accessorKey: "reviewed",
header: "Erledigt",
cell: ({ row }) => {
return (
<div className="text-center">
{row.getValue("reviewed") ? (
<Check className="text-green-500 w-5 h-5" />
) : (
<X className="text-red-500 w-5 h-5" />
)}
</div>
);
},
},
{
accessorKey: "Sender",
header: "Sender",
cell: ({ row }) => {
const user = row.getValue("Sender") as User;
return `${user.firstname} ${user.lastname} (${user.publicId})`;
},
},
{
accessorKey: "Reported",
header: "Reported",
cell: ({ row }) => {
const user = row.getValue("Reported") as User;
return `${user.firstname} ${user.lastname} (${user.publicId})`;
},
},
{
accessorKey: "timestamp",
header: "Time",
cell: ({ row }) =>
new Date(row.getValue("timestamp")).toLocaleString(),
},
{
accessorKey: "actions",
header: "Actions",
cell: ({ row }) => (
<Link href={`/admin/report/${row.original.id}`}>
<button className="btn btn-sm btn-outline btn-info flex items-center gap-2">
<Eye className="w-4 h-4" /> Anzeigen
</button>
</Link>
),
},
] as ColumnDef<Report>[]
}
/>
</div>
);
};
interface AdminFormProps {
user: User;
dispoTime: {
@@ -317,9 +390,19 @@ interface AdminFormProps {
minutes: number;
lastLogin?: Date;
};
reports: {
total: number;
open: number;
total60Days: number;
};
}
export const AdminForm = ({ user, dispoTime, pilotTime }: AdminFormProps) => {
export const AdminForm = ({
user,
dispoTime,
pilotTime,
reports,
}: AdminFormProps) => {
const router = useRouter();
return (
@@ -388,7 +471,7 @@ export const AdminForm = ({ user, dispoTime, pilotTime }: AdminFormProps) => {
<h2 className="card-title">
<ChartBarBigIcon className="w-5 h-5" /> Aktivität
</h2>
<div className="stats shadow">
<div className="stats flex">
<div className="stat">
<div className="stat-figure text-primary">
<LightningBoltIcon className="w-8 h-8" />
@@ -419,7 +502,34 @@ export const AdminForm = ({ user, dispoTime, pilotTime }: AdminFormProps) => {
<h2 className="card-title">
<ExclamationTriangleIcon className="w-5 h-5" /> Reports
</h2>
{/* TODO: Report summary Here */}
<div className="stats flex">
<div className="stat">
<div className="stat-figure text-primary">
<ExclamationTriangleIcon className="w-8 h-8" />
</div>
<div
className={cn(
"stat-value text-primary",
reports.open && "text-warning",
)}
>
{reports.open}
</div>
<div className="stat-title">Offen</div>
</div>
<div className="stat">
<div className="stat-figure text-primary">
<Timer className="w-8 h-8" />
</div>
<div className="stat-value text-primary">{reports.total60Days}</div>
<div className="stat-title">in den letzten 60 Tagen</div>
<div className="stat-desc text-secondary">
{reports.total} insgesammt
</div>
</div>
</div>
</div>
);
};

View File

@@ -1,6 +1,11 @@
import { PersonIcon } from "@radix-ui/react-icons";
import { prisma, User } from "@repo/db";
import { AdminForm, ConnectionHistory, ProfileForm } from "./_components/forms";
import {
AdminForm,
ConnectionHistory,
ProfileForm,
UserReports,
} from "./_components/forms";
import { Error } from "../../../../_components/Error";
const Page = async ({ params }: { params: { id: string } }) => {
@@ -62,6 +67,33 @@ const Page = async ({ params }: { params: { id: string } }) => {
lastLogin: pilotSessions[pilotSessions.length - 1]?.loginTime,
};
const totalReportsReports = await prisma.report.count({
where: {
reportedUserId: user?.id,
},
});
const totalReports60Days = await prisma.report.count({
where: {
reportedUserId: user?.id,
timestamp: {
gte: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000),
},
},
});
const totalReportsOpen = await prisma.report.count({
where: {
reportedUserId: user?.id,
reviewed: false,
},
});
const reports = {
total: totalReportsReports,
open: totalReportsOpen,
total60Days: totalReports60Days,
};
if (!user) return <Error statusCode={404} title="User not found" />;
return (
<div className="grid grid-cols-6 gap-4">
@@ -75,7 +107,15 @@ const Page = async ({ params }: { params: { id: string } }) => {
<ProfileForm user={user} />
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<AdminForm user={user} dispoTime={dispoTime} pilotTime={pilotTime} />
<AdminForm
user={user}
dispoTime={dispoTime}
pilotTime={pilotTime}
reports={reports}
/>
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6">
<UserReports user={user} />
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6">
<ConnectionHistory user={user} />