Penalty Übersicht für Nutzer und Penalty-Log
This commit is contained in:
@@ -5,6 +5,8 @@ import {
|
||||
ConnectedAircraft,
|
||||
ConnectedDispatcher,
|
||||
DiscordAccount,
|
||||
Penalty,
|
||||
PenaltyType,
|
||||
PERMISSION,
|
||||
Report,
|
||||
Station,
|
||||
@@ -31,12 +33,23 @@ import { UserOptionalDefaults, UserOptionalDefaultsSchema } from "@repo/db/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
|
||||
import { cn } from "../../../../../../helper/cn";
|
||||
import { ChartBarBigIcon, Check, Eye, PlaneIcon, Timer, X } from "lucide-react";
|
||||
import {
|
||||
ChartBarBigIcon,
|
||||
Check,
|
||||
Eye,
|
||||
LockKeyhole,
|
||||
PlaneIcon,
|
||||
RedoDot,
|
||||
Timer,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Error } from "_components/Error";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { setStandardName } from "../../../../../../helper/discord";
|
||||
import { de } from "date-fns/locale";
|
||||
import { formatDistance } from "date-fns";
|
||||
|
||||
interface ProfileFormProps {
|
||||
user: User;
|
||||
@@ -300,11 +313,99 @@ export const ConnectionHistory: React.FC<{ user: User }> = ({ user }: { user: Us
|
||||
);
|
||||
};
|
||||
|
||||
export const UserPenalties = ({ user }: { user: User }) => {
|
||||
return (
|
||||
<div className="card-body">
|
||||
<h2 className="card-title">
|
||||
<ExclamationTriangleIcon className="w-5 h-5" /> Nutzer Strafen
|
||||
</h2>
|
||||
<PaginatedTable
|
||||
prismaModel="penalty"
|
||||
include={{
|
||||
CreatedUser: true,
|
||||
Report: true,
|
||||
}}
|
||||
filter={{
|
||||
userId: user.id,
|
||||
}}
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
export const UserReports = ({ user }: { user: User }) => {
|
||||
return (
|
||||
<div className="card-body">
|
||||
<h2 className="card-title">
|
||||
<ExclamationTriangleIcon className="w-5 h-5" /> User Reports
|
||||
<ExclamationTriangleIcon className="w-5 h-5" /> Nutzer Reports
|
||||
</h2>
|
||||
<PaginatedTable
|
||||
prismaModel="report"
|
||||
@@ -433,7 +534,7 @@ export const AdminForm = ({
|
||||
role="submit"
|
||||
className="btn-sm btn-wide btn-outline btn-error"
|
||||
>
|
||||
<HobbyKnifeIcon /> User Sperren
|
||||
<HobbyKnifeIcon /> HUB zugang sperren
|
||||
</Button>
|
||||
)}
|
||||
{user.isBanned && (
|
||||
@@ -451,7 +552,7 @@ export const AdminForm = ({
|
||||
role="submit"
|
||||
className="btn-sm btn-wide btn-outline btn-warning"
|
||||
>
|
||||
<HobbyKnifeIcon /> User Entperren
|
||||
<HobbyKnifeIcon /> HUB zugang entsperren
|
||||
</Button>
|
||||
)}
|
||||
{discordAccount && (
|
||||
@@ -509,8 +610,6 @@ export const AdminForm = ({
|
||||
<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">
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { PersonIcon } from "@radix-ui/react-icons";
|
||||
import { prisma } from "@repo/db";
|
||||
import { AdminForm, ConnectionHistory, ProfileForm, UserReports } from "./_components/forms";
|
||||
import {
|
||||
AdminForm,
|
||||
ConnectionHistory,
|
||||
ProfileForm,
|
||||
UserPenalties,
|
||||
UserReports,
|
||||
} from "./_components/forms";
|
||||
import { Error } from "../../../../_components/Error";
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
|
||||
@@ -115,6 +121,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-6">
|
||||
<UserReports user={user} />
|
||||
</div>
|
||||
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6">
|
||||
<UserPenalties user={user} />
|
||||
</div>
|
||||
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6">
|
||||
<ConnectionHistory user={user} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user