Manuelle reports
This commit is contained in:
111
apps/hub/app/(app)/admin/report/_components/NewReport.tsx
Normal file
111
apps/hub/app/(app)/admin/report/_components/NewReport.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
21
apps/hub/app/(app)/admin/report/new/page.tsx
Normal file
21
apps/hub/app/(app)/admin/report/new/page.tsx
Normal 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;
|
||||||
@@ -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={{
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
Reference in New Issue
Block a user