From 0d7f0ad2b8996e362d392da60b86f60611fb210a Mon Sep 17 00:00:00 2001 From: nocnico Date: Mon, 28 Apr 2025 22:59:46 +0200 Subject: [PATCH] Add Admin Reports page #2 --- apps/hub/app/(app)/admin/report/[id]/page.tsx | 82 ++++++++++++ apps/hub/app/(app)/admin/report/actions.ts | 36 ++++++ apps/hub/app/(app)/admin/report/layout.tsx | 24 ++++ apps/hub/app/(app)/admin/report/page.tsx | 122 ++++++++++++++++++ apps/hub/app/_components/Nav.tsx | 3 + .../prisma/schema/reportMessage.prisma | 13 +- 6 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 apps/hub/app/(app)/admin/report/[id]/page.tsx create mode 100644 apps/hub/app/(app)/admin/report/actions.ts create mode 100644 apps/hub/app/(app)/admin/report/layout.tsx create mode 100644 apps/hub/app/(app)/admin/report/page.tsx diff --git a/apps/hub/app/(app)/admin/report/[id]/page.tsx b/apps/hub/app/(app)/admin/report/[id]/page.tsx new file mode 100644 index 00000000..f16cb7aa --- /dev/null +++ b/apps/hub/app/(app)/admin/report/[id]/page.tsx @@ -0,0 +1,82 @@ +"use client"; +import { useEffect, useState } from "react"; +import { Eye } from "lucide-react"; +import { fetchReportDetails, handleMarkAsResolved } from "../actions"; + +export default function ReportDetailsPage({ + params: paramsPromise, +}: { + params: Promise<{ id: number }>; +}) { + const [params, setParams] = useState<{ id: number } | null>(null); + const [report, setReport] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function unwrapParams() { + const resolvedParams = await paramsPromise; + setParams(resolvedParams); + } + unwrapParams(); + }, [paramsPromise]); + + useEffect(() => { + if (!params) return; + + async function loadReport() { + if (!params) return; + const fetchedReport = await fetchReportDetails(parseInt(params.id)); + setReport(fetchedReport); + setLoading(false); + } + loadReport(); + }, [params]); + + if (!params || loading) return
Loading...
; + if (!report) return
Report not found
; + + return ( +
+

+ Report Details +

+
+
+

+ Sender: {report.sender.firstname} {report.sender.lastname} ( + {report.sender.publicId}) +

+

+ Reported: {report.reported.firstname}{" "} + {report.reported.lastname} ({report.reported.publicId}) +

+

+ Timestamp: {new Date(report.timestamp).toLocaleString()} +

+
+
+

+ Message: +

+

{report.text}

+
+
+
+ + +
+
+ ); +} diff --git a/apps/hub/app/(app)/admin/report/actions.ts b/apps/hub/app/(app)/admin/report/actions.ts new file mode 100644 index 00000000..e4fcc03c --- /dev/null +++ b/apps/hub/app/(app)/admin/report/actions.ts @@ -0,0 +1,36 @@ +"use server"; +import { prisma } from "@repo/db"; + +export const markAsResolved = async (id: number) => { + await prisma.reportMessage.update({ + where: { id: id }, + data: { erledigt: true }, + }); +}; + +// New function to handle marking a report as resolved +export const handleMarkAsResolved = async (id: number) => { + try { + await markAsResolved(id); + return { success: true }; + } catch (error) { + console.error("Error marking report as resolved:", error); + return { success: false, error: error }; + } +}; + +export const getReports = async () => { + return prisma.reportMessage.findMany({ + include: { + sender: true, + reported: true, + }, + }); +}; + +export const fetchReportDetails = async (id: number) => { + return prisma.reportMessage.findUnique({ + where: { id }, + include: { sender: true, reported: true }, + }); +}; diff --git a/apps/hub/app/(app)/admin/report/layout.tsx b/apps/hub/app/(app)/admin/report/layout.tsx new file mode 100644 index 00000000..7c1701a3 --- /dev/null +++ b/apps/hub/app/(app)/admin/report/layout.tsx @@ -0,0 +1,24 @@ +import { prisma } from "@repo/db"; +import { Error } from "_components/Error"; +import { getServerSession } from "api/auth/[...nextauth]/auth"; + +export default async function ReportLayout({ + children, +}: { + children: React.ReactNode; +}) { + const session = await getServerSession(); + + if (!session) return ; + + const user = await prisma.user.findUnique({ + where: { + id: session.user.id, + }, + }); + + if (!user?.permissions.includes("ADMIN_EVENT")) + return ; + + return <>{children}; +} diff --git a/apps/hub/app/(app)/admin/report/page.tsx b/apps/hub/app/(app)/admin/report/page.tsx new file mode 100644 index 00000000..73d0ad5a --- /dev/null +++ b/apps/hub/app/(app)/admin/report/page.tsx @@ -0,0 +1,122 @@ +"use client"; +import { useEffect, useState } from "react"; +import { Check, Eye, X } from "lucide-react"; +import Link from "next/link"; +import { getReports, handleMarkAsResolved } from "./actions"; + +export default function ReportPage() { + const [reports, setReports] = useState< + { + id: number; + timestamp: string; + erledigt: boolean; + sender: { + id: string; + firstname: string; + lastname: string; + publicId: string; + }; + reported: { + id: string; + firstname: string; + lastname: string; + publicId: string; + }; + }[] + >([]); + + useEffect(() => { + const fetchReports = async () => { + const reps = await getReports(); + const transformedReports = reps.map((report) => ({ + id: report.id, + timestamp: report.timestamp.toISOString(), + erledigt: report.erledigt, + sender: { + id: report.sender.id, + firstname: report.sender.firstname, + lastname: report.sender.lastname, + publicId: report.sender.publicId, + }, + reported: { + id: report.reported.id, + firstname: report.reported.firstname, + lastname: report.reported.lastname, + publicId: report.reported.publicId, + }, + })); + setReports(transformedReports); + }; + fetchReports(); + }, []); + + return ( + <> +
+ {" "} + Reports +
+
+ + + + + + + + + + + + + {reports.map((report) => ( + + + + + + + + + ))} + +
ErledigtSenderReportedTimeIDActions
+ {report.erledigt ? ( + + ) : ( + + )} + {`${report.sender.firstname} ${report.sender.lastname} (${report.sender.publicId})`}{`${report.reported.firstname} ${report.reported.lastname} (${report.reported.publicId})`}{new Date(report.timestamp).toLocaleString()}{report.id} +
+ + + + {!report.erledigt && ( + + )} +
+
+
+ + ); +} diff --git a/apps/hub/app/_components/Nav.tsx b/apps/hub/app/_components/Nav.tsx index 62085d15..e8f46bc6 100644 --- a/apps/hub/app/_components/Nav.tsx +++ b/apps/hub/app/_components/Nav.tsx @@ -57,6 +57,9 @@ export const VerticalNav = () => {
  • Service Nachrichten
  • +
  • + Reports +
  • diff --git a/packages/database/prisma/schema/reportMessage.prisma b/packages/database/prisma/schema/reportMessage.prisma index 6cf01427..4564b2e7 100644 --- a/packages/database/prisma/schema/reportMessage.prisma +++ b/packages/database/prisma/schema/reportMessage.prisma @@ -1,11 +1,10 @@ model ReportMessage { - id Int @id @default(autoincrement()) - text String - senderId String - reportedId String - timestamp DateTime @default(now()) - reportedName String - senderName String + id Int @id @default(autoincrement()) + text String + senderId String + reportedId String + timestamp DateTime @default(now()) + erledigt Boolean @default(false) // relations: sender User @relation("SentReports", fields: [senderId], references: [id])