From f04b4e0c4350a5acc539a8f15bc9df4bfd10a537 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 28 Sep 2026 22:06:07 +0200 Subject: feat(hub): reports from public-group members, decided by an administrator A report needs a person's account at least a day old, membership of the public group, and fits a daily allowance per account. Past the threshold a hash is queued and administrators are notified; blocking without review is an instance setting, off by default. Report menu item in public groups, Reports tab and settings in the admin panel. Co-Authored-By: Claude Opus 5.5 --- .../meshbay-hub/src/meshbay_hub/static/report.js | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 packages/meshbay-hub/src/meshbay_hub/static/report.js (limited to 'packages/meshbay-hub/src/meshbay_hub/static/report.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/report.js b/packages/meshbay-hub/src/meshbay_hub/static/report.js new file mode 100644 index 0000000..f433780 --- /dev/null +++ b/packages/meshbay-hub/src/meshbay_hub/static/report.js @@ -0,0 +1,70 @@ +import { html, render, useEffect, useRef, useState } from './vendor/htm-preact.js'; +import { t } from './i18n.js'; + +/** + * Ask why a file is being reported, drawn by the page like `ask.js`. + * + * Resolves `{ reason, detail }`, or null when cancelled. The reasons are the + * hub's own closed list (api/moderation.py `ReportRequest`), and the detail is + * bounded to what the hub keeps (256 characters). + */ + +const REASONS = ['illegal', 'spam', 'copyright', 'other']; + +function ReportDialog({ name, onDone }) { + const [reason, setReason] = useState('illegal'); + const [detail, setDetail] = useState(''); + const firstRef = useRef(null); + useEffect(() => { if (firstRef.current) firstRef.current.focus(); }, []); + + return html` +
{ + if (e.target.classList.contains('video-overlay')) onDone(null); + }}> +