completed Account Log

This commit is contained in:
PxlLoewe
2026-01-30 16:19:00 +01:00
parent ea8d63ce0b
commit 2154684223
8 changed files with 215 additions and 64 deletions

View File

@@ -0,0 +1,137 @@
"use client";
import { Log, Prisma, User } from "@repo/db";
import { cn } from "@repo/shared-components";
import { ColumnDef } from "@tanstack/react-table";
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
import { Printer } from "lucide-react";
import Link from "next/link";
import { useRef, useState } from "react";
export const AccountLog = ({ sameIPLogs, userId }: { sameIPLogs: Log[]; userId: string }) => {
const [onlyImportant, setOnlyImportant] = useState(true);
const tableRef = useRef<PaginatedTableRef>(null);
return (
<div className="card-body">
<div className="card-title flex justify-between">
<h2 className="flex items-center gap-2">
<Printer className="h-5 w-5" /> Account Log
</h2>
<p className="text-end text-sm text-gray-500">
Hier werden Logs angezeigt, die dem Nutzer zugeordnet sind oder von der selben IP stammen.
</p>
</div>
<PaginatedTable
ref={tableRef}
rightOfPagination={
<div className="ml-4 flex items-center gap-2">
<input
type="checkbox"
id="ImportantOnly"
checked={onlyImportant}
onChange={() => {
setOnlyImportant(!onlyImportant);
tableRef.current?.refresh();
}}
className="checkbox checkbox-sm"
/>
<label
htmlFor="ImportantOnly"
className="min-w-[210px] cursor-pointer select-none text-sm"
>
Unauffällige Einträge ausblenden
</label>
</div>
}
getFilter={(searchTerm) => {
return {
AND: [
{
OR: [
{ ip: { contains: searchTerm } },
{ browser: { contains: searchTerm } },
{
id: {
in: sameIPLogs
.filter((log) => log.id.toString().includes(searchTerm))
.map((log) => log.id),
},
},
],
},
onlyImportant
? {
OR: [
{
id: {
in: sameIPLogs
.filter((log) => log.id.toString().includes(searchTerm))
.map((log) => log.id),
},
},
{
type: {
in: ["REGISTER", "PROFILE_CHANGE"],
},
},
],
}
: {},
],
} as Prisma.LogWhereInput;
}}
include={{
User: true,
}}
prismaModel={"log"}
columns={
[
{
header: "Zeitstempel",
accessorKey: "timestamp",
cell: (info) => new Date(info.getValue<string>()).toLocaleString("de-DE"),
},
{
header: "Aktion",
accessorKey: "action",
cell: ({ row }) => {
const action = row.original.type;
if (action !== "PROFILE_CHANGE") {
return <span className="text-blue-500">{action}</span>;
} else {
return (
<span className="text-yellow-500">{`${row.original.field} von "${row.original.oldValue}" zu "${row.original.newValue}"`}</span>
);
}
},
},
{
header: "IP-Adresse",
accessorKey: "ip",
},
{
header: "Browser",
accessorKey: "browser",
},
{
header: "Benutzer",
accessorKey: "userId",
cell: ({ row }) => {
return (
<Link
href={`/admin/user/${row.original.userId}`}
className={cn("link", userId !== row.original.userId && "text-red-400")}
>
{row.original.User
? `${row.original.User.firstname} ${row.original.User.lastname} - ${row.original.User.publicId}`
: "Unbekannt"}
</Link>
);
},
},
] as ColumnDef<Log & { User: User }>[]
}
/>
</div>
);
};

View File

@@ -11,6 +11,7 @@ import { Error } from "../../../../_components/Error";
import { getUserPenaltys } from "@repo/shared-components";
import { PaginatedTable } from "_components/PaginatedTable";
import { ColumnDef } from "@tanstack/react-table";
import { AccountLog } from "./_components/AccountLog";
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
@@ -175,44 +176,12 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
/>
</div>
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-6">
<PaginatedTable
prismaModel={"log"}
columns={
[
{
header: "Zeitstempel",
accessorKey: "timestamp",
cell: (info) => new Date(info.getValue<string>()).toLocaleString("de-DE"),
},
{
header: "Aktion",
accessorKey: "action",
cell: ({ row }) => {
const action = row.original.type;
if (action !== "PROFILE_CHANGE") {
return action;
} else {
return `${row.original.field} von "${row.original.oldValue}" zu "${row.original.newValue}"`;
}
},
},
{
header: "IP-Adresse",
accessorKey: "ip",
},
{
header: "Gerät",
accessorKey: "browser",
},
] as ColumnDef<Log>[]
}
/>
<AccountLog sameIPLogs={sameIpLogs} userId={user.id} />
</div>
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-6">
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-3">
<UserReports user={user} />
</div>
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-6">
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-3">
<UserPenalties user={user} />
</div>
<div className="card bg-base-200 col-span-6 mb-4 shadow-xl xl:col-span-6">