148 lines · 5.4 KB
import { createFileRoute, notFound } from "@tanstack/react-router";
import { z } from "zod";
import { actOnAbuse, getAbuseQueue } from "~/fns/abuse";
import { useAction } from "~/hooks/use-action";
import { ABUSE_CATEGORY_LABELS } from "~/lib/abuse";
import type { AbuseAction, AbuseCategory, AbuseStatus } from "~/lib/abuse";
import { Badge } from "~/ui/Badge";
import { Button } from "~/ui/Button";
import { ErrorBanner } from "~/ui/Callout";
import { EmptyState } from "~/ui/EmptyState";
import { Heading } from "~/ui/Heading";
import { PageContainer } from "~/ui/PageContainer";
import { Panel } from "~/ui/Panel";
import { RelativeTime } from "~/ui/RelativeTime";
import { ExternalLink, TextLink } from "~/ui/TextLink";

const STATUSES: { value: AbuseStatus; label: string }[] = [
  { value: "open", label: "Open" },
  { value: "actioned", label: "Actioned" },
  { value: "dismissed", label: "Dismissed" },
];

export const Route = createFileRoute("/admin/abuse")({
  head: () => ({ meta: [{ title: "Abuse queue · gitfor" }] }),
  validateSearch: z.object({ status: z.enum(["open", "actioned", "dismissed"]).optional() }),
  beforeLoad: ({ context }) => {
    if (!context.viewer?.isAdmin) throw notFound();
  },
  loaderDeps: ({ search }) => ({ status: search.status ?? "open" }),
  loader: ({ deps }) => getAbuseQueue({ data: { status: deps.status } }),
  component: AbuseQueuePage,
});

type Report = Awaited<ReturnType<typeof getAbuseQueue>>["reports"][number];

function siteState(report: Report) {
  if (!report.site_id) return <Badge>Not a hosted site</Badge>;
  if (report.site_paused_at) return <Badge tone="warning">Paused</Badge>;
  if (report.site_disabled_reason) return <Badge tone="danger">Disabled</Badge>;
  return <Badge tone="success">Live</Badge>;