Bugfixes + Manuelle reports #127

Merged
PxlLoewe merged 5 commits from staging into release 2025-07-28 00:00:57 +00:00
6 changed files with 163 additions and 12 deletions
Showing only changes of commit 89a0eb7135 - Show all commits

View File

@@ -0,0 +1,111 @@
"use client";
import { createReport } from "(app)/admin/report/actions";
import { getUser } from "(app)/admin/user/action";
import { Prisma } from "@repo/db";
import { useQuery } from "@tanstack/react-query";
import { Select } from "_components/ui/Select";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { TriangleAlert } from "lucide-react";
import toast from "react-hot-toast";
import { Button } from "@repo/shared-components";
export const NewReportForm = ({
defaultValues,
}: {
defaultValues?: Partial<Prisma.XOR<Prisma.ReportCreateInput, Prisma.ReportUncheckedCreateInput>>;
}) => {
const session = useSession();
const [search, setSearch] = useState("");
const { data: user } = useQuery({
queryKey: ["newReport"],
queryFn: async () =>
getUser({
OR: [
{ firstname: { contains: search, mode: "insensitive" } },
{ lastname: { contains: search, mode: "insensitive" } },
{ publicId: { contains: search, mode: "insensitive" } },
{ id: defaultValues?.reportedUserId || "" },
],
}),
enabled: search.length > 0,
refetchOnWindowFocus: false,
});
const router = useRouter();
const form = useForm<Prisma.ReportUncheckedCreateInput>({
defaultValues: {
text: "",
reportedUserRole: "USER",
senderUserId: session.data?.user.id,
...defaultValues,
},
});
return (
<form
className="flex flex-wrap gap-3"
onSubmit={form.handleSubmit(async (values) => {
console.log("Form submitted with values:", values);
const newReport = await createReport(values);
toast.success("Report erfolgreich erstellt!");
router.push(`/admin/report/${newReport.id}`);
})}
>
<div className="card bg-base-200 flex-1 basis-[800px] shadow-xl">
<div className="card-body">
<h2 className="card-title">
<TriangleAlert /> Neuen Report erstellen
</h2>
<Select
form={form}
options={
user?.map((u) => ({
label: `${u.firstname} ${u.lastname} (${u.publicId})`,
value: u.id,
})) || [
{
label: "Kein Nutzer gefunden",
value: "",
disabled: true,
},
]
}
onInputChange={(v) => setSearch(v)}
name="reportedUserId"
label="Nutzer"
/>
<Select
form={form}
options={[
{ label: "Nutzer", value: "Nutzer" },
{ label: "Pilot", value: "Pilot" },
{ label: "Disponent", value: "Disponent" },
]}
name="reportedUserRole"
label="Rolle des Nutzers"
/>
<textarea
{...form.register("text")}
className="textarea w-full"
placeholder="Beschreibe den Vorfall"
/>
</div>
</div>
<div className="card bg-base-200 flex-1 basis-[800px] shadow-xl">
<div className="card-body">
<div className="flex w-full gap-4">
<Button
isLoading={form.formState.isSubmitting}
type="submit"
className="btn btn-primary flex-1"
>
Speichern
</Button>
</div>
</div>
</div>
</form>
);
};

View File

@@ -26,15 +26,15 @@ export const ReportSenderInfo = ({
return ( return (
<div className="card-body"> <div className="card-body">
<h2 className="card-title"> <h2 className="card-title">
<Link href={`/admin/user/${Reported?.id}`} className=" link link-hover"> <Link href={`/admin/user/${Reported?.id}`} className="link link-hover">
{Reported?.firstname} {Reported?.lastname} ({Reported?.publicId}) als{" "} {Reported?.firstname} {Reported?.lastname} ({Reported?.publicId}) als{" "}
</Link> </Link>
<span className="text-primary">{report.reportedUserRole}</span> <span className="text-primary">{report.reportedUserRole}</span>
</h2> </h2>
<div className="textarea w-full text-left">{report.text}</div> <div className="textarea w-full text-left">{report.text}</div>
<Link <Link
href={`/admin/user/${Reported?.id}`} href={`/admin/user/${Sender?.id}`}
className="text-sm text-gray-600 text-right link link-hover" className="link link-hover text-right text-sm text-gray-600"
> >
gemeldet von Nutzer {Sender?.firstname} {Sender?.lastname} ({Sender?.publicId}) am{" "} gemeldet von Nutzer {Sender?.firstname} {Sender?.lastname} ({Sender?.publicId}) am{" "}
{new Date(report.timestamp).toLocaleString()} {new Date(report.timestamp).toLocaleString()}
@@ -82,7 +82,7 @@ export const ReportAdmin = ({
> >
<h2 className="card-title">Staff Kommentar</h2> <h2 className="card-title">Staff Kommentar</h2>
<textarea {...form.register("reviewerComment")} className="textarea w-full" placeholder="" /> <textarea {...form.register("reviewerComment")} className="textarea w-full" placeholder="" />
<p className="text-sm text-gray-600 text-right"> <p className="text-right text-sm text-gray-600">
{report.Reviewer && {report.Reviewer &&
`Kommentar von ${Reviewer?.firstname} ${Reviewer?.lastname} (${Reviewer?.publicId})`} `Kommentar von ${Reviewer?.firstname} ${Reviewer?.lastname} (${Reviewer?.publicId})`}
</p> </p>
@@ -141,7 +141,7 @@ export const ReportPenalties = ({
return ( return (
<div className="card-body"> <div className="card-body">
<h2 className="card-title"> <h2 className="card-title">
<Shield className="w-5 h-5" /> Strafen zu diesem Report <Shield className="h-5 w-5" /> Strafen zu diesem Report
</h2> </h2>
<PaginatedTable <PaginatedTable
prismaModel="penalty" prismaModel="penalty"

View File

@@ -1,10 +1,7 @@
"use server"; "use server";
import { Prisma, prisma } from "@repo/db"; import { Prisma, prisma } from "@repo/db";
export const editReport = async ( export const editReport = async (id: number, data: Prisma.ReportUncheckedUpdateInput) => {
id: number,
data: Prisma.ReportUncheckedUpdateInput,
) => {
return await prisma.report.update({ return await prisma.report.update({
where: { where: {
id: id, id: id,
@@ -12,3 +9,11 @@ export const editReport = async (
data, data,
}); });
}; };
export const createReport = async (
data: Prisma.XOR<Prisma.ReportCreateInput, Prisma.ReportUncheckedCreateInput>,
) => {
return await prisma.report.create({
data,
});
};

View File

@@ -0,0 +1,21 @@
import { NewReportForm } from "(app)/admin/report/_components/NewReport";
const Page = async ({
searchParams,
}: {
searchParams?: {
[key: string]: string | undefined;
};
}) => {
const params = await searchParams;
console.log("searchParams", params);
return (
<NewReportForm
defaultValues={{
reportedUserId: params?.reportedUserId || "",
}}
/>
);
};
export default Page;

View File

@@ -42,6 +42,7 @@ import {
Eye, Eye,
LockKeyhole, LockKeyhole,
PlaneIcon, PlaneIcon,
Plus,
ShieldUser, ShieldUser,
Timer, Timer,
Trash2, Trash2,
@@ -484,9 +485,16 @@ export const UserPenalties = ({ user }: { user: User }) => {
export const UserReports = ({ user }: { user: User }) => { export const UserReports = ({ user }: { user: User }) => {
return ( return (
<div className="card-body"> <div className="card-body">
<h2 className="card-title"> <div className="card-title flex justify-between">
<ExclamationTriangleIcon className="h-5 w-5" /> Nutzer Reports <h2 className="flex items-center gap-2">
</h2> <ExclamationTriangleIcon className="h-5 w-5" /> Nutzer Reports
</h2>
<Link href={`/admin/report/new?reportedUserId=${user.id}`}>
<button className={"btn btn-xs btn-square btn-soft cursor-pointer"}>
<Plus />
</button>
</Link>
</div>
<PaginatedTable <PaginatedTable
prismaModel="report" prismaModel="report"
filter={{ filter={{

View File

@@ -3,6 +3,12 @@ import { prisma, Prisma } from "@repo/db";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import { sendMailByTemplate } from "../../../../helper/mail"; import { sendMailByTemplate } from "../../../../helper/mail";
export const getUser = async (where: Prisma.UserWhereInput) => {
return await prisma.user.findMany({
where,
});
};
export const editUser = async (id: string, data: Prisma.UserUpdateInput) => { export const editUser = async (id: string, data: Prisma.UserUpdateInput) => {
return await prisma.user.update({ return await prisma.user.update({
where: { where: {