Penalty Übersicht für Nutzer und Penalty-Log

This commit is contained in:
PxlLoewe
2025-06-21 22:05:16 -07:00
parent 4732ecb770
commit 93962a9ce4
15 changed files with 402 additions and 25 deletions

View File

@@ -1,7 +1,11 @@
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { prisma } from "@repo/db";
import { Error } from "_components/Error";
import { ReportAdmin, ReportSenderInfo } from "(app)/admin/report/_components/form";
import {
ReportAdmin,
ReportPenalties,
ReportSenderInfo,
} from "(app)/admin/report/_components/form";
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
@@ -33,6 +37,9 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<ReportAdmin report={report} />
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6">
<ReportPenalties report={report} />
</div>
</div>
);
}

View File

@@ -1,11 +1,15 @@
"use client";
import { editReport } from "(app)/admin/report/actions";
import { zodResolver } from "@hookform/resolvers/zod";
import { Report as IReport, User } from "@repo/db";
import { Report as IReport, Penalty, PenaltyType, Report, User } from "@repo/db";
import { ReportSchema, Report as IReportZod } from "@repo/db/zod";
import { ColumnDef } from "@tanstack/react-table";
import { PaginatedTable } from "_components/PaginatedTable";
import { Button } from "_components/ui/Button";
import { Switch } from "_components/ui/Switch";
import { Trash } from "lucide-react";
import { formatDistance } from "date-fns";
import { de } from "date-fns/locale";
import { Eye, LockKeyhole, RedoDot, Shield, Timer, Trash } from "lucide-react";
import { useSession } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/navigation";
@@ -24,10 +28,12 @@ export const ReportSenderInfo = ({
const { Reported, Sender } = report;
return (
<div className="card-body">
<Link href={`/admin/user/${Reported?.id}`} className="card-title link link-hover">
{Reported?.firstname} {Reported?.lastname} ({Reported?.publicId}) als{" "}
<h2 className="card-title">
<Link href={`/admin/user/${Reported?.id}`} className=" link link-hover">
{Reported?.firstname} {Reported?.lastname} ({Reported?.publicId}) als{" "}
</Link>
<span className="text-primary">{report.reportedUserRole}</span>
</Link>
</h2>
<div className="textarea w-full text-left">{report.text}</div>
<Link
href={`/admin/user/${Reported?.id}`}
@@ -85,7 +91,7 @@ export const ReportAdmin = ({
{report.Reviewer &&
`Kommentar von ${Reviewer?.firstname} ${Reviewer?.lastname} (${Reviewer?.publicId})`}
</p>
<Switch form={form} name="reviewed" label="Report als geklärt markieren" />
<Switch form={form} name="reviewed" label="Report als erledigt markieren" />
<div className="card-actions flex justify-between">
<Button
role="submit"
@@ -126,3 +132,109 @@ export const ReportAdmin = ({
</form>
);
};
export const ReportPenalties = ({
report,
}: {
report: IReport & {
Reported?: User;
Sender?: User;
Reviewer?: User | null;
};
}) => {
if (!report.penaltyId)
return (
<div className="card-body">
<h2 className="card-title">
<Shield className="w-5 h-5" /> Strafen zu diesem Report
</h2>
<p className="text-sm text-gray-600">Es wurden keine Strafen zu diesem Report erfasst.</p>
</div>
);
return (
<div className="card-body">
<h2 className="card-title">
<Shield className="w-5 h-5" /> Strafen zu diesem Report
</h2>
<PaginatedTable
prismaModel="penalty"
include={{
CreatedUser: true,
Report: true,
}}
filter={{
id: report.penaltyId,
}}
columns={
[
{
accessorKey: "type",
header: "Typ",
cell: ({ row }) => {
switch (row.getValue("type") as PenaltyType) {
case "KICK":
return (
<div className="text-warning flex gap-3">
<RedoDot />
Kick
</div>
);
case "TIME_BAN": {
const length = formatDistance(
new Date(row.original.timestamp),
new Date(row.original.until || Date.now()),
{ locale: de },
);
return (
<div className="text-warning flex gap-3">
<Timer />
Zeit Sperre ({length})
</div>
);
}
case "BAN":
return (
<div className="text-error flex gap-3">
<LockKeyhole /> Bann
</div>
);
}
},
},
{
accessorKey: "CreatedUser",
header: "Bestraft durch",
cell: ({ row }) => {
const user = row.getValue("CreatedUser") 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 }) => {
const report = row.original.Report;
if (!report[0]) return null;
return (
<Link href={`/admin/report/${report[0].id}`}>
<button className="btn btn-sm btn-outline btn-info flex items-center gap-2">
<Eye className="w-4 h-4" />
Report Anzeigen
</button>
</Link>
);
},
},
] as ColumnDef<Penalty & { Report: Report[] }>[]
}
/>
</div>
);
};