SPB Git

Repository Public

page.tsx 2.8 KB 33 lines tsx

1import { Notice, PageHead, Status, when } from "@/components/studio/ui";2import { can, requireRole } from "@/lib/auth";3import { sql } from "@/lib/db";4import { filmStatus, resolveReport } from "../../actions";56export const metadata = { title: "Reports" };7export default async function Reports({ searchParams }: { searchParams: Promise<{ ok?: string; err?: string }> }) {8  const sp = await searchParams;9  const user = await requireRole("viewer");10  const editor = can(user, "editor");11  const rows = await sql<{ id: string; at: Date; reason: string; detail: string; contact: string; status: string; film_id: string | null; title_en: string | null; slug: string | null; film_status: string | null }[]>`12    SELECT r.*, f.title_en, f.slug, f.status AS film_status FROM reports r LEFT JOIN films f ON f.id = r.film_id ORDER BY (r.status = 'open') DESC, r.at DESC LIMIT 100`;13  return (14    <>15      <PageHead title="Reports" sub="Problem and takedown reports sent from the public site. Hold a film while you look into it: it disappears from the site immediately and can be restored." />16      <Notice ok={sp.ok} err={sp.err} />17      {rows.length ? <ul className="space-y-3">{rows.map((r) => (18        <li key={r.id} className="card p-4 text-sm">19          <div className="flex flex-wrap items-center justify-between gap-3"><p><Status value={r.status} /> <span className="ml-2 font-medium">{r.reason}</span> <span className="text-[var(--color-faint)]">· {when(r.at)}</span></p><p className="text-[var(--color-muted)]">{r.title_en ? <>{r.title_en} <Status value={r.film_status ?? "unpublished"} /></> : "film not identified"}</p></div>20          <p className="mt-2 whitespace-pre-wrap break-words text-[var(--color-muted)]">{r.detail}</p>21          {r.contact && <p className="mt-1 text-xs text-[var(--color-faint)]">Contact: {r.contact}</p>}22          {editor && r.status === "open" && (23            <div className="mt-3 flex flex-wrap gap-2">24              {r.film_id && r.film_status === "published" && <form action={filmStatus}><input type="hidden" name="film" value={r.film_id} /><input type="hidden" name="status" value="hold" /><input type="hidden" name="note" value={`report ${r.id}`} /><button className="btn btn-danger btn-sm">Hold the film now</button></form>}25              <form action={resolveReport}><input type="hidden" name="report" value={r.id} /><button className="btn btn-ghost btn-sm">Mark resolved</button></form>26              <form action={resolveReport}><input type="hidden" name="report" value={r.id} /><input type="hidden" name="status" value="dismissed" /><button className="btn btn-ghost btn-sm">Dismiss</button></form>27            </div>28          )}29        </li>))}</ul> : <div className="card p-10 text-center text-[var(--color-faint)]">No report has been filed.</div>}30    </>31  );32}33
Files main
Menu

Theme