Melden-Button: Beiträge mit optionalem Grund melden

- report-Tabelle wieder im Schema (kompatibel zur bestehenden auf PROD)
- POST /api/entry/{pid}/report, nur angemeldet, speichert Melder-uid;
  erneutes Melden legt keine zweite offene Meldung an
- "Melden" auf der Beitragsseite für fremde, nicht gelöschte Beiträge
- Test und API-Doku

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
This commit is contained in:
irrlicht
2026-09-29 17:53:10 +02:00
co-authored by Claude Opus 5.5
parent 2bae608d76
commit 80c333cd58
6 changed files with 123 additions and 2 deletions
+37 -2
View File
@@ -38,7 +38,8 @@ function ThreadView({ pid }: { pid: string }) {
);
}
const data = thread.data;
const isOwner = !!me && !!data && me.uid === data.entry.uid && !data.entry.deleted;
const live = !!me && !!data && !data.entry.deleted;
const isOwner = live && me.uid === data.entry.uid;
return (
<>
@@ -47,7 +48,9 @@ function ThreadView({ pid }: { pid: string }) {
</section>
<div id="focus">
{data && <EntryCard entry={data.entry} />}
{data && isOwner && <OwnerActions entry={data.entry} onChange={refresh} />}
{live && (isOwner
? <OwnerActions entry={data.entry} onChange={refresh} />
: <ReportAction pid={data.entry.pid} />)}
</div>
<section id="reply-box" hidden={!me}>
@@ -116,3 +119,35 @@ function OwnerActions({ entry, onChange }: { entry: Entry; onChange: () => void
</>
);
}
// ReportAction: fremden Beitrag melden, der Grund ist optional.
function ReportAction({ pid }: { pid: number }) {
const [open, setOpen] = useState(false);
const report = useMutation({
mutationFn: (fd: FormData) => api.post(`/entry/${pid}/report`, fd),
});
const onSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
report.mutate(new FormData(e.currentTarget));
};
const cancel = () => {
report.reset();
setOpen(false);
};
if (report.isSuccess) return <p className="muted">Danke, der Beitrag wurde gemeldet.</p>;
return (
<>
<button disabled={open} onClick={() => setOpen(true)}>Melden</button>
{open && (
<form onSubmit={onSubmit}>
<textarea name="reason" rows={2} maxLength={500} placeholder="Grund (optional)"></textarea>{" "}
<button type="submit" disabled={report.isPending}>Melden</button>{" "}
<button type="button" onClick={cancel}>Abbrechen</button>{" "}
<p className="msg">{report.isError ? errMsg(report.error, "Melden fehlgeschlagen.") : ""}</p>
</form>
)}
</>
);
}